2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.bgpcep.pcep.topology.provider;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static com.google.common.base.Preconditions.checkState;
12 import static java.util.Objects.requireNonNull;
14 import com.google.common.util.concurrent.AsyncFunction;
15 import com.google.common.util.concurrent.FluentFuture;
16 import com.google.common.util.concurrent.Futures;
17 import com.google.common.util.concurrent.ListenableFuture;
18 import com.google.common.util.concurrent.MoreExecutors;
19 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
20 import java.net.InetAddress;
21 import java.nio.ByteBuffer;
22 import java.nio.charset.StandardCharsets;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.List;
27 import java.util.Optional;
28 import java.util.concurrent.atomic.AtomicBoolean;
29 import java.util.concurrent.atomic.AtomicLong;
30 import org.checkerframework.checker.lock.qual.GuardedBy;
31 import org.checkerframework.checker.lock.qual.Holding;
32 import org.eclipse.jdt.annotation.NonNull;
33 import org.opendaylight.bgpcep.pcep.server.PathComputation;
34 import org.opendaylight.bgpcep.pcep.server.PceServerProvider;
35 import org.opendaylight.protocol.pcep.PCEPSession;
36 import org.opendaylight.protocol.pcep.spi.PCEPErrors;
37 import org.opendaylight.protocol.pcep.spi.PSTUtil;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev200720.PathComputationClient1Builder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev200720.lsp.db.version.tlv.LspDbVersion;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.Lsp1;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.PcinitiateBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.Srp1;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.Srp1Builder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.Stateful1;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.pcinitiate.message.PcinitiateMessageBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.pcinitiate.message.pcinitiate.message.Requests;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.pcinitiate.message.pcinitiate.message.RequestsBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Arguments1;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Arguments2;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Arguments3;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.OperationalStatus;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Path1;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Path1Builder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.PcrptMessage;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.PcupdBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.PlspId;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.SrpIdNumber;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.StatefulTlv1Builder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.SymbolicPathName;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Tlvs1;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object.Lsp;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object.LspBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object.lsp.TlvsBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.pcerr.pcerr.message.error.type.StatefulCase;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.pcerr.pcerr.message.error.type.stateful._case.stateful.Srps;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.pcrpt.message.pcrpt.message.Reports;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.pcupd.message.PcupdMessageBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.pcupd.message.pcupd.message.UpdatesBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.pcupd.message.pcupd.message.updates.PathBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.srp.object.Srp;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.srp.object.SrpBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.stateful.capability.tlv.Stateful;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.symbolic.path.name.tlv.SymbolicPathNameBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.Pcerr;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.PcerrBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.Pcreq;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Message;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.PcerrMessage;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.RequestId;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.explicit.route.object.EroBuilder;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.open.object.open.Tlvs;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.path.setup.type.tlv.PathSetupType;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcep.error.object.ErrorObjectBuilder;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.PcerrMessageBuilder;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.ErrorsBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.error.type.RequestCaseBuilder;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.error.type.request._case.RequestBuilder;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.error.type.request._case.request.RpsBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.PcreqMessage;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.rp.object.RpBuilder;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.AddLspArgs;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.EnsureLspOperationalInput;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.LspId;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.Node1;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.OperationResult;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.PccSyncState;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.RemoveLspArgs;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.TriggerSyncArgs;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.UpdateLspArgs;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.ensure.lsp.operational.args.Arguments;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.PathComputationClient;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.PathComputationClientBuilder;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.ReportedLsp;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.ReportedLspBuilder;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.StatefulTlvBuilder;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.reported.lsp.Path;
107 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
108 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
109 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
110 import org.opendaylight.yangtools.yang.common.Uint32;
111 import org.slf4j.Logger;
112 import org.slf4j.LoggerFactory;
114 // Non-final for testing
115 class PCEPTopologySessionListener extends AbstractTopologySessionListener<SrpIdNumber, PlspId> {
116 private static final Logger LOG = LoggerFactory.getLogger(PCEPTopologySessionListener.class);
117 private static final PlspId PLSPID_ZERO = new PlspId(Uint32.ZERO);
119 private final AtomicLong requestId = new AtomicLong(1L);
122 private final List<PlspId> staleLsps = new ArrayList<>();
124 private final AtomicBoolean statefulCapability = new AtomicBoolean(false);
125 private final AtomicBoolean lspUpdateCapability = new AtomicBoolean(false);
126 private final AtomicBoolean initiationCapability = new AtomicBoolean(false);
128 private final PceServerProvider pceServerProvider;
131 * Creates a new stateful topology session listener for given server session manager.
133 PCEPTopologySessionListener(final ServerSessionManager serverSessionManager) {
134 super(serverSessionManager);
135 pceServerProvider = serverSessionManager.getPCEPTopologyProviderDependencies().getPceServerProvider();
138 private static LspDbVersion geLspDbVersionTlv(final Lsp lsp) {
139 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object
140 .lsp.Tlvs tlvs = lsp.getTlvs();
141 if (tlvs != null && tlvs.augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang
142 .controller.pcep.sync.optimizations.rev200720.Tlvs1.class) != null) {
143 return tlvs.augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller
144 .pcep.sync.optimizations.rev200720.Tlvs1.class).getLspDbVersion();
150 protected void onSessionUp(final PCEPSession session, final PathComputationClientBuilder pccBuilder) {
151 final InetAddress peerAddress = session.getRemoteAddress();
153 final Tlvs tlvs = session.getRemoteTlvs();
154 if (tlvs != null && tlvs.augmentation(Tlvs1.class) != null) {
155 final Stateful stateful = tlvs.augmentation(Tlvs1.class).getStateful();
156 if (stateful != null) {
157 setStatefulCapabilities(stateful);
158 pccBuilder.setReportedLsp(Collections.emptyMap());
159 if (isSynchronized()) {
160 pccBuilder.setStateSync(PccSyncState.Synchronized);
161 } else if (isTriggeredInitialSynchro()) {
162 pccBuilder.setStateSync(PccSyncState.TriggeredInitialSync);
163 } else if (isIncrementalSynchro()) {
164 pccBuilder.setStateSync(PccSyncState.IncrementalSync);
166 pccBuilder.setStateSync(PccSyncState.InitialResync);
168 pccBuilder.setStatefulTlv(new StatefulTlvBuilder().addAugmentation(
169 new StatefulTlv1Builder(tlvs.augmentation(Tlvs1.class)).build()).build());
171 LOG.debug("Peer {} does not advertise stateful TLV", peerAddress);
174 LOG.debug("Peer {} does not advertise stateful TLV", peerAddress);
179 public synchronized ListenableFuture<OperationResult> triggerSync(final TriggerSyncArgs input) {
180 if (isTriggeredInitialSynchro() && !isSynchronized()) {
181 return triggerSynchronization(input);
182 } else if (isSessionSynchronized() && isTriggeredReSyncEnabled()) {
183 checkArgument(input != null && input.getNode() != null, MISSING_XML_TAG);
184 return input.getName() == null ? triggerResyncronization(input) : triggerLspSyncronization(input);
186 return OperationResults.UNSENT.future();
189 private ListenableFuture<OperationResult> triggerLspSyncronization(final TriggerSyncArgs input) {
190 LOG.trace("Trigger Lsp Resynchronization {}", input);
192 // Make sure the LSP exists
193 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
194 final FluentFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
196 return OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future();
198 return Futures.transformAsync(f, new ResyncLspFunction(input), MoreExecutors.directExecutor());
201 private ListenableFuture<OperationResult> triggerResyncronization(final TriggerSyncArgs input) {
202 LOG.trace("Trigger Resynchronization {}", input);
204 updatePccState(PccSyncState.PcepTriggeredResync);
205 final PcupdMessageBuilder pcupdMessageBuilder = new PcupdMessageBuilder(MESSAGE_HEADER);
206 final SrpIdNumber srpIdNumber = createUpdateMessageSync(pcupdMessageBuilder);
207 final Message msg = new PcupdBuilder().setPcupdMessage(pcupdMessageBuilder.build()).build();
208 return sendMessage(msg, srpIdNumber, null);
211 private ListenableFuture<OperationResult> triggerSynchronization(final TriggerSyncArgs input) {
212 LOG.trace("Trigger Initial Synchronization {}", input);
213 final PcupdMessageBuilder pcupdMessageBuilder = new PcupdMessageBuilder(MESSAGE_HEADER);
214 final SrpIdNumber srpIdNumber = createUpdateMessageSync(pcupdMessageBuilder);
215 final Message msg = new PcupdBuilder().setPcupdMessage(pcupdMessageBuilder.build()).build();
216 return sendMessage(msg, srpIdNumber, null);
219 private SrpIdNumber createUpdateMessageSync(final PcupdMessageBuilder pcupdMessageBuilder) {
220 final UpdatesBuilder updBuilder = new UpdatesBuilder();
221 // LSP mandatory in Upd
222 final Lsp lsp = new LspBuilder().setPlspId(PLSPID_ZERO).setSync(Boolean.TRUE).build();
223 // SRP Mandatory in Upd
224 final SrpBuilder srpBuilder = new SrpBuilder();
225 // not sue whether use 0 instead of nextRequest() or do not insert srp == SRP-ID-number = 0
226 srpBuilder.setOperationId(nextRequest());
227 final Srp srp = srpBuilder.build();
228 //ERO Mandatory in Upd
229 final PathBuilder pb = new PathBuilder();
230 pb.setEro(new EroBuilder().build());
232 updBuilder.setPath(pb.build());
233 updBuilder.setLsp(lsp).setSrp(srp).setPath(pb.build());
235 pcupdMessageBuilder.setUpdates(Collections.singletonList(updBuilder.build()));
236 return srp.getOperationId();
240 private void markAllLspAsStale() {
241 staleLsps.addAll(lsps.keySet());
244 private boolean handleErrorMessage(final PcerrMessage message) {
245 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message
246 .PcerrMessage errMsg = message.getPcerrMessage();
247 if (errMsg.getErrorType() instanceof StatefulCase) {
248 final StatefulCase stat = (StatefulCase) errMsg.getErrorType();
249 for (final Srps srps : stat.getStateful().getSrps()) {
250 final SrpIdNumber id = srps.getSrp().getOperationId();
251 if (id.getValue().toJava() != 0) {
252 final PCEPRequest req = removeRequest(id);
254 req.done(OperationResults.createFailed(errMsg.getErrors()));
256 LOG.warn("Request ID {} not found in outstanding DB", id);
261 LOG.warn("Unhandled PCErr message {}.", errMsg);
267 private boolean isSolicited(final Srp srp, final Lsp lsp, final MessageContext ctx, final ReportedLspBuilder rlb) {
271 final SrpIdNumber id = srp.getOperationId();
272 if (id.getValue().toJava() == 0) {
275 switch (lsp.getOperational()) {
279 if (!isTriggeredSyncInProcess()) {
280 final PCEPRequest req = removeRequest(id);
282 LOG.debug("Request {} resulted in LSP operational state {}", id, lsp.getOperational());
283 rlb.setMetadata(req.getMetadata());
284 ctx.resolveRequest(req);
286 LOG.warn("Request ID {} not found in outstanding DB", id);
292 // These are transitive states, so we don't have to do anything, as they will be followed
302 private boolean manageNextReport(final Reports report, final MessageContext ctx) {
303 final Lsp lsp = report.getLsp();
304 final PlspId plspid = lsp.getPlspId();
305 final Srp srp = report.getSrp();
307 if (!lsp.getSync() && (plspid == null || plspid.getValue().toJava() == 0)) {
309 if (isTriggeredSyncInProcess()) {
313 final SrpIdNumber id = srp.getOperationId();
314 if (id.getValue().toJava() == 0) {
317 final PCEPRequest req = removeRequest(id);
318 ctx.resolveRequest(req);
320 stateSynchronizationAchieved(ctx);
323 final ReportedLspBuilder rlb = new ReportedLspBuilder();
324 boolean solicited = false;
325 solicited = isSolicited(srp, lsp, ctx, rlb);
327 // if remove flag is set in SRP object, remove the tunnel immediately
329 final Srp1 initiatedSrp = srp.augmentation(Srp1.class);
330 if (initiatedSrp != null && initiatedSrp.getRemove()) {
331 super.removeLsp(ctx, plspid);
335 rlb.setPath(BindingMap.of(buildPath(report, srp, lsp)));
337 String name = lookupLspName(plspid);
338 if (lsp.getTlvs() != null && lsp.getTlvs().getSymbolicPathName() != null) {
339 name = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(lsp.getTlvs().getSymbolicPathName().getPathName()
340 .getValue())).toString();
342 //get LspDB from LSP and write it to pcc's node
343 final LspDbVersion lspDbVersion = geLspDbVersionTlv(lsp);
344 if (lspDbVersion != null) {
345 updatePccNode(ctx, new PathComputationClientBuilder()
346 .addAugmentation(new PathComputationClient1Builder().setLspDbVersion(lspDbVersion).build()).build());
348 updateLsp(ctx, plspid, name, rlb, solicited, lsp.getRemove());
349 unmarkStaleLsp(plspid);
351 LOG.debug("LSP {} updated", lsp);
355 private static Path buildPath(final Reports report, final Srp srp, final Lsp lsp) {
356 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client
357 .attributes.path.computation.client.reported.lsp.PathBuilder pb = new org.opendaylight.yang.gen.v1
358 .urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation
359 .client.reported.lsp.PathBuilder();
360 if (report.getPath() != null) {
361 pb.fieldsFrom(report.getPath());
363 // LSP is mandatory (if there is none, parser will throw an exception)
364 // this is to ensure a path will be created at any rate
365 final Path1Builder p1Builder = new Path1Builder();
366 p1Builder.setLsp(report.getLsp());
367 final PathSetupType pst;
368 if (srp != null && srp.getTlvs() != null && srp.getTlvs().getPathSetupType() != null) {
369 pst = srp.getTlvs().getPathSetupType();
370 p1Builder.setPathSetupType(pst);
374 pb.addAugmentation(p1Builder.build());
375 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp
376 .object.lsp.Tlvs tlvs = report.getLsp().getTlvs();
378 if (tlvs.getLspIdentifiers() != null) {
379 pb.setLspId(tlvs.getLspIdentifiers().getLspId());
380 } else if (!PSTUtil.isDefaultPST(pst)) {
381 pb.setLspId(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820
382 .LspId(lsp.getPlspId().getValue()));
388 private boolean handlePcreqMessage(final PcreqMessage message) {
390 LOG.info("Start PcRequest Message handler");
392 /* Get a Path Computation to compute the Path from the Request */
393 PathComputation pathComputation = pceServerProvider.getPathComputation();
395 /* Reply with Error Message if no valid Path Computation is available */
396 if (pathComputation == null) {
397 rep = createErrorMsg(PCEPErrors.RESOURCE_LIMIT_EXCEEDED, Uint32.ZERO);
398 sendMessage(rep, new SrpIdNumber(Uint32.ZERO), null);
401 for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq
402 .message.Requests req : message.getRequests()) {
403 LOG.debug("Process request {}", req);
404 rep = pathComputation.computePath(req);
405 SrpIdNumber repId = null;
406 if (req.getRp() != null) {
407 repId = new SrpIdNumber(req.getRp().getRequestId().getValue());
409 repId = new SrpIdNumber(Uint32.ZERO);
411 sendMessage(rep, repId, null);
417 protected synchronized boolean onMessage(final MessageContext ctx, final Message message) {
418 if (message instanceof PcerrMessage) {
419 return handleErrorMessage((PcerrMessage) message);
421 if (message instanceof Pcreq) {
422 LOG.info("PcReq detected. Start Request Message handler");
423 return handlePcreqMessage(((Pcreq) message).getPcreqMessage());
425 if (!(message instanceof PcrptMessage)) {
428 listenerState.updateLastReceivedRptMsg();
429 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.pcrpt
430 .message.PcrptMessage rpt = ((PcrptMessage) message).getPcrptMessage();
431 for (final Reports report : rpt.getReports()) {
432 if (!manageNextReport(report, ctx)) {
439 private SrpIdNumber nextRequest() {
440 return new SrpIdNumber(Uint32.valueOf(requestId.getAndIncrement()));
444 @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
445 public synchronized ListenableFuture<OperationResult> addLsp(final AddLspArgs input) {
446 checkArgument(input != null && input.getName() != null && input.getNode() != null
447 && input.getArguments() != null, MISSING_XML_TAG);
448 LOG.trace("AddLspArgs {}", input);
449 // Make sure there is no such LSP
450 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
451 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
452 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
453 : Futures.transformAsync(f, new AddFunction(input, lsp), MoreExecutors.directExecutor());
457 @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
458 public synchronized ListenableFuture<OperationResult> removeLsp(final RemoveLspArgs input) {
459 checkArgument(input != null && input.getName() != null && input.getNode() != null, MISSING_XML_TAG);
460 LOG.trace("RemoveLspArgs {}", input);
461 // Make sure the LSP exists, we need it for PLSP-ID
462 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
463 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
464 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
465 : Futures.transformAsync(f, rep -> {
466 final Lsp reportedLsp = validateReportedLsp(rep, input);
467 if (reportedLsp == null) {
468 return OperationResults.createUnsent(PCEPErrors.UNKNOWN_PLSP_ID).future();
470 final PcinitiateMessageBuilder ib = new PcinitiateMessageBuilder(MESSAGE_HEADER);
471 final Requests rb = buildRequest(rep, reportedLsp);
472 ib.setRequests(Collections.singletonList(rb));
473 return sendMessage(new PcinitiateBuilder().setPcinitiateMessage(ib.build()).build(),
474 rb.getSrp().getOperationId(), null);
475 }, MoreExecutors.directExecutor());
478 private Requests buildRequest(final Optional<ReportedLsp> rep, final Lsp reportedLsp) {
479 // Build the request and send it
480 final RequestsBuilder rb = new RequestsBuilder();
481 final SrpBuilder srpBuilder = new SrpBuilder().addAugmentation(new Srp1Builder()
482 .setRemove(Boolean.TRUE).build()).setOperationId(nextRequest()).setProcessingRule(Boolean.TRUE);
483 final Optional<PathSetupType> maybePST = getPST(rep);
484 if (maybePST.isPresent()) {
485 srpBuilder.setTlvs(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
486 .rev200720.srp.object.srp.TlvsBuilder().setPathSetupType(maybePST.get()).build());
488 rb.setSrp(srpBuilder.build());
489 rb.setLsp(new LspBuilder().setRemove(Boolean.FALSE).setPlspId(reportedLsp.getPlspId())
490 .setDelegate(reportedLsp.getDelegate()).build());
494 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
495 justification = "https://github.com/spotbugs/spotbugs/issues/811")
496 private ListenableFuture<OperationResult> redelegate(final Lsp reportedLsp, final Srp srp, final Lsp lsp,
497 final UpdateLspArgs input) {
498 // the D bit that was reported decides the type of PCE message sent
499 final boolean isDelegate = requireNonNull(reportedLsp.getDelegate());
502 // we already have delegation, send update
503 final UpdatesBuilder rb = new UpdatesBuilder();
506 final PathBuilder pb = new PathBuilder();
507 pb.fieldsFrom(input.getArguments());
508 rb.setPath(pb.build());
509 final PcupdMessageBuilder ub = new PcupdMessageBuilder(MESSAGE_HEADER);
510 ub.setUpdates(Collections.singletonList(rb.build()));
511 msg = new PcupdBuilder().setPcupdMessage(ub.build()).build();
513 final Lsp1 lspCreateFlag = reportedLsp.augmentation(Lsp1.class);
514 // we only retake delegation for PCE initiated tunnels
515 if (lspCreateFlag != null && !lspCreateFlag.getCreate()) {
516 LOG.warn("Unable to retake delegation of PCC-initiated tunnel: {}", reportedLsp);
517 return OperationResults.createUnsent(PCEPErrors.UPDATE_REQ_FOR_NON_LSP).future();
519 // we want to revoke delegation, different type of message
520 // is sent because of specification by Siva
521 // this message is also sent, when input delegate bit is set to 0
522 // generating an error in PCC
523 final List<Requests> reqs = new ArrayList<>();
524 reqs.add(new RequestsBuilder().setSrp(srp).setLsp(lsp).build());
525 final PcinitiateMessageBuilder ib = new PcinitiateMessageBuilder();
526 ib.setRequests(reqs);
527 msg = new PcinitiateBuilder().setPcinitiateMessage(ib.build()).build();
529 return sendMessage(msg, srp.getOperationId(), input.getArguments().getMetadata());
533 @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
535 public synchronized ListenableFuture<OperationResult> updateLsp(final UpdateLspArgs input) {
536 checkArgument(input != null && input.getName() != null && input.getNode() != null
537 && input.getArguments() != null, MISSING_XML_TAG);
538 LOG.trace("UpdateLspArgs {}", input);
539 // Make sure the LSP exists
540 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
541 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
542 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
543 : Futures.transformAsync(f, new UpdateFunction(input), MoreExecutors.directExecutor());
547 public synchronized ListenableFuture<OperationResult> ensureLspOperational(final EnsureLspOperationalInput input) {
548 checkArgument(input != null && input.getName() != null && input.getNode() != null, MISSING_XML_TAG);
549 final Arguments args = input.getArguments();
550 checkArgument(args != null, MISSING_XML_TAG);
552 final OperationalStatus op;
553 final Arguments1 aa = args.augmentation(Arguments1.class);
555 op = aa.getOperational();
560 // Make sure the LSP exists
561 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
562 LOG.debug("Checking if LSP {} has operational state {}", lsp, op);
563 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
564 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
565 : listenableFuture(f, input, op);
568 private static ListenableFuture<OperationResult> listenableFuture(
569 final ListenableFuture<Optional<ReportedLsp>> future, final EnsureLspOperationalInput input,
570 final OperationalStatus op) {
571 return Futures.transform(future, rep -> {
572 if (!rep.isPresent()) {
573 LOG.debug("Node {} does not contain LSP {}", input.getNode(), input.getName());
574 return OperationResults.UNSENT;
576 // check if at least one of the paths has the same status as requested
577 for (final Path p : rep.get().nonnullPath().values()) {
578 final Path1 p1 = p.augmentation(Path1.class);
580 LOG.warn("Node {} LSP {} does not contain data", input.getNode(), input.getName());
581 return OperationResults.UNSENT;
583 if (op.equals(p1.getLsp().getOperational())) {
584 return OperationResults.SUCCESS;
587 return OperationResults.UNSENT;
588 }, MoreExecutors.directExecutor());
592 protected Lsp validateReportedLsp(final Optional<ReportedLsp> rep, final LspId input) {
593 if (!rep.isPresent()) {
594 LOG.debug("Node {} does not contain LSP {}", input.getNode(), input.getName());
597 // it doesn't matter how many lsps there are in the path list, we only need data that is the same in each path
598 final Path1 ra = rep.get().getPath().values().iterator().next().augmentation(Path1.class);
599 checkState(ra != null, "Reported LSP reported null from data-store.");
600 final Lsp reportedLsp = ra.getLsp();
601 checkState(reportedLsp != null, "Reported LSP does not contain LSP object.");
605 private static Optional<PathSetupType> getPST(final Optional<ReportedLsp> rep) {
606 if (rep.isPresent()) {
607 final Path1 path1 = rep.get().getPath().values().iterator().next().augmentation(Path1.class);
609 final PathSetupType pst = path1.getPathSetupType();
610 if (!PSTUtil.isDefaultPST(pst)) {
611 return Optional.of(pst);
615 return Optional.empty();
619 * Recover lspData and mark any LSPs in the LSP database that were previously reported by the PCC as stale.
622 protected synchronized void loadLspData(final Node node, final Map<String, ReportedLsp> lspData,
623 final Map<PlspId, String> lsps, final boolean incrementalSynchro) {
624 //load node's lsps from DS
625 final PathComputationClient pcc = node.augmentation(Node1.class).getPathComputationClient();
626 for (final ReportedLsp reportedLsp : pcc.nonnullReportedLsp().values()) {
627 final String lspName = reportedLsp.getName();
628 lspData.put(lspName, reportedLsp);
629 if (!reportedLsp.getPath().isEmpty()) {
630 final Path1 path1 = reportedLsp.getPath().values().iterator().next().augmentation(Path1.class);
632 final PlspId plspId = path1.getLsp().getPlspId();
633 if (!incrementalSynchro) {
634 staleLsps.add(plspId);
636 lsps.put(plspId, lspName);
643 * When the PCC reports an LSP during state synchronization, if the LSP already
644 * exists in the LSP database, the PCE MUST update the LSP database and
645 * clear the stale marker from the LSP.
649 private synchronized void unmarkStaleLsp(final PlspId plspId) {
650 staleLsps.remove(plspId);
654 * Purge any LSPs from the LSP database that are still marked as stale.
656 * @param ctx message context
658 private synchronized void purgeStaleLsps(final MessageContext ctx) {
659 for (final PlspId plspId : staleLsps) {
660 removeLsp(ctx, plspId);
666 public boolean isInitiationCapability() {
667 return initiationCapability.get();
671 public boolean isStatefulCapability() {
672 return statefulCapability.get();
676 public boolean isLspUpdateCapability() {
677 return lspUpdateCapability.get();
680 private synchronized void setStatefulCapabilities(final Stateful stateful) {
681 statefulCapability.set(true);
682 if (stateful.getLspUpdateCapability() != null) {
683 lspUpdateCapability.set(stateful.getLspUpdateCapability());
685 final Stateful1 stateful1 = stateful.augmentation(Stateful1.class);
686 if (stateful1 != null && stateful1.getInitiation() != null) {
687 initiationCapability.set(stateful1.getInitiation());
691 private class ResyncLspFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
693 private final TriggerSyncArgs input;
695 ResyncLspFunction(final TriggerSyncArgs input) {
700 public ListenableFuture<OperationResult> apply(final Optional<ReportedLsp> rep) {
701 final Lsp reportedLsp = validateReportedLsp(rep, input);
702 if (reportedLsp == null || !rep.isPresent()) {
703 return OperationResults.createUnsent(PCEPErrors.UNKNOWN_PLSP_ID).future();
706 final ReportedLsp staleLsp = rep.get();
707 if (!staleLsp.getPath().isEmpty()) {
708 final Path1 path1 = staleLsp.getPath().values().iterator().next().augmentation(Path1.class);
710 staleLsps.add(path1.getLsp().getPlspId());
713 updatePccState(PccSyncState.PcepTriggeredResync);
714 // create PCUpd with mandatory objects and LSP object set to 1
715 final SrpBuilder srpBuilder = new SrpBuilder();
716 srpBuilder.setOperationId(nextRequest());
717 srpBuilder.setProcessingRule(Boolean.TRUE);
719 final Optional<PathSetupType> maybePST = getPST(rep);
720 if (maybePST.isPresent()) {
722 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
723 .rev200720.srp.object.srp.TlvsBuilder()
724 .setPathSetupType(maybePST.get()).build());
727 final Srp srp = srpBuilder.build();
728 final Lsp lsp = new LspBuilder().setPlspId(reportedLsp.getPlspId()).setSync(Boolean.TRUE).build();
730 final Message msg = createPcepUpd(srp, lsp);
731 return sendMessage(msg, srp.getOperationId(), null);
734 private Message createPcepUpd(final Srp srp, final Lsp lsp) {
735 final UpdatesBuilder rb = new UpdatesBuilder();
738 final PathBuilder pb = new PathBuilder();
739 rb.setPath(pb.build());
740 final PcupdMessageBuilder ub = new PcupdMessageBuilder(MESSAGE_HEADER);
741 ub.setUpdates(Collections.singletonList(rb.build()));
742 return new PcupdBuilder().setPcupdMessage(ub.build()).build();
746 private class AddFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
748 private final AddLspArgs input;
749 private final InstanceIdentifier<ReportedLsp> lsp;
751 AddFunction(final AddLspArgs input, final InstanceIdentifier<ReportedLsp> lsp) {
757 public ListenableFuture<OperationResult> apply(final Optional<ReportedLsp> rep) {
758 if (rep.isPresent()) {
759 LOG.debug("Node {} already contains lsp {} at {}", input.getNode(), input.getName(), lsp);
760 return OperationResults.createUnsent(PCEPErrors.USED_SYMBOLIC_PATH_NAME).future();
762 if (!initiationCapability.get()) {
763 return OperationResults.createUnsent(PCEPErrors.CAPABILITY_NOT_SUPPORTED).future();
767 final RequestsBuilder rb = new RequestsBuilder();
768 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120
769 .add.lsp.args.Arguments args = input.getArguments();
770 final Arguments2 args2 = args.augmentation(Arguments2.class);
771 final Lsp inputLsp = args2 != null ? args2.getLsp() : null;
772 if (inputLsp == null) {
773 return OperationResults.createUnsent(PCEPErrors.LSP_MISSING).future();
776 rb.fieldsFrom(input.getArguments());
778 /* Call Path Computation if an ERO was not provided */
779 boolean segmentRouting = !PSTUtil.isDefaultPST(args2.getPathSetupType());
780 if (rb.getEro() == null
781 || rb.getEro().getSubobject() == null
782 || rb.getEro().getSubobject().size() == 0) {
784 /* Get a Path Computation to compute the Path from the Arguments */
785 PathComputation pathComputation = pceServerProvider.getPathComputation();
786 if (pathComputation == null) {
787 return OperationResults.createUnsent(PCEPErrors.ERO_MISSING).future();
789 rb.setEro(pathComputation.computeEro(args.getEndpointsObj(), args.getBandwidth(), args.getClassType(),
790 args.getMetrics(), segmentRouting));
793 final TlvsBuilder tlvsBuilder;
794 if (inputLsp.getTlvs() != null) {
795 tlvsBuilder = new TlvsBuilder(inputLsp.getTlvs());
797 tlvsBuilder = new TlvsBuilder();
799 tlvsBuilder.setSymbolicPathName(
800 new SymbolicPathNameBuilder().setPathName(new SymbolicPathName(input.getName()
801 .getBytes(StandardCharsets.UTF_8))).build());
803 final SrpBuilder srpBuilder = new SrpBuilder()
804 .setOperationId(nextRequest())
805 .setProcessingRule(Boolean.TRUE);
806 if (segmentRouting) {
808 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf
809 .stateful.rev200720.srp.object.srp.TlvsBuilder()
810 .setPathSetupType(args2.getPathSetupType()).build());
812 rb.setSrp(srpBuilder.build());
814 rb.setLsp(new LspBuilder()
815 .setAdministrative(inputLsp.getAdministrative())
816 .setDelegate(inputLsp.getDelegate())
817 .setPlspId(PLSPID_ZERO)
818 .setTlvs(tlvsBuilder.build())
822 return sendMessage(new PcinitiateBuilder()
823 .setPcinitiateMessage(new PcinitiateMessageBuilder(MESSAGE_HEADER)
824 .setRequests(Collections.singletonList(rb.build()))
827 rb.getSrp().getOperationId(), input.getArguments().getMetadata());
831 private class UpdateFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
833 private final UpdateLspArgs input;
835 UpdateFunction(final UpdateLspArgs input) {
840 public ListenableFuture<OperationResult> apply(final Optional<ReportedLsp> rep) {
841 final Lsp reportedLsp = validateReportedLsp(rep, input);
842 if (reportedLsp == null) {
843 return OperationResults.createUnsent(PCEPErrors.UNKNOWN_PLSP_ID).future();
845 // create mandatory objects
846 final Arguments3 args = input.getArguments().augmentation(Arguments3.class);
847 final SrpBuilder srpBuilder = new SrpBuilder();
848 srpBuilder.setOperationId(nextRequest());
849 srpBuilder.setProcessingRule(Boolean.TRUE);
850 if (args != null && args.getPathSetupType() != null) {
851 if (!PSTUtil.isDefaultPST(args.getPathSetupType())) {
853 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
854 .rev200720.srp.object.srp.TlvsBuilder()
855 .setPathSetupType(args.getPathSetupType()).build());
858 final Optional<PathSetupType> maybePST = getPST(rep);
859 if (maybePST.isPresent()) {
861 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
862 .rev200720.srp.object.srp.TlvsBuilder()
863 .setPathSetupType(maybePST.get()).build());
866 final Srp srp = srpBuilder.build();
867 final Lsp inputLsp = args != null ? args.getLsp() : null;
868 final LspBuilder lspBuilder = new LspBuilder().setPlspId(reportedLsp.getPlspId());
869 if (inputLsp != null) {
870 lspBuilder.setDelegate(Boolean.TRUE.equals(inputLsp.getDelegate()))
871 .setTlvs(inputLsp.getTlvs())
872 .setAdministrative(Boolean.TRUE.equals(inputLsp.getAdministrative()));
874 return redelegate(reportedLsp, srp, lspBuilder.build(), input);
878 private static Pcerr createErrorMsg(@NonNull final PCEPErrors pcepErrors, final Uint32 reqID) {
879 return new PcerrBuilder()
880 .setPcerrMessage(new PcerrMessageBuilder()
881 .setErrorType(new RequestCaseBuilder()
882 .setRequest(new RequestBuilder()
883 .setRps(Collections.singletonList(new RpsBuilder()
884 .setRp(new RpBuilder()
885 .setProcessingRule(false)
887 .setRequestId(new RequestId(reqID))
892 .setErrors(Collections.singletonList(new ErrorsBuilder()
893 .setErrorObject(new ErrorObjectBuilder()
894 .setType(pcepErrors.getErrorType())
895 .setValue(pcepErrors.getErrorValue())