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.nio.ByteBuffer;
21 import java.nio.charset.StandardCharsets;
22 import java.util.ArrayList;
23 import java.util.List;
25 import java.util.Optional;
26 import java.util.concurrent.atomic.AtomicLong;
27 import org.checkerframework.checker.lock.qual.GuardedBy;
28 import org.checkerframework.checker.lock.qual.Holding;
29 import org.eclipse.jdt.annotation.NonNull;
30 import org.opendaylight.bgpcep.pcep.server.PathComputation;
31 import org.opendaylight.bgpcep.pcep.server.PceServerProvider;
32 import org.opendaylight.protocol.pcep.spi.PCEPErrors;
33 import org.opendaylight.protocol.pcep.spi.PSTUtil;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev200720.PathComputationClient1Builder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev200720.lsp.db.version.tlv.LspDbVersion;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.Lsp1;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.PcinitiateBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.Srp1;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.Srp1Builder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.pcinitiate.message.PcinitiateMessageBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.pcinitiate.message.pcinitiate.message.Requests;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.pcinitiate.message.pcinitiate.message.RequestsBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Arguments1;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Arguments2;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Arguments3;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.OperationalStatus;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Path1;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Path1Builder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.PcrptMessage;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.PcupdBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.PlspId;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.SrpIdNumber;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.SymbolicPathName;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object.Lsp;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object.LspBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object.lsp.TlvsBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.pcerr.pcerr.message.error.type.StatefulCase;
58 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;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.pcrpt.message.pcrpt.message.Reports;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.pcupd.message.PcupdMessageBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.pcupd.message.pcupd.message.UpdatesBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.pcupd.message.pcupd.message.updates.PathBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.srp.object.Srp;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.srp.object.SrpBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.symbolic.path.name.tlv.SymbolicPathNameBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.Pcerr;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.PcerrBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.Pcreq;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Message;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.MessageHeader;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.PcerrMessage;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.ProtocolVersion;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.RequestId;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.explicit.route.object.EroBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.path.setup.type.tlv.PathSetupType;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcep.error.object.ErrorObjectBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.PcerrMessageBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.ErrorsBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.error.type.RequestCaseBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.error.type.request._case.RequestBuilder;
81 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;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.PcreqMessage;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.rp.object.RpBuilder;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.AddLspArgs;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.EnsureLspOperationalInput;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.LspId;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.Node1;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.OperationResult;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.PccSyncState;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.RemoveLspArgs;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.TriggerSyncArgs;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.UpdateLspArgs;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.ensure.lsp.operational.args.Arguments;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client.attributes.PathComputationClient;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client.attributes.PathComputationClientBuilder;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client.attributes.path.computation.client.ReportedLsp;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client.attributes.path.computation.client.ReportedLspBuilder;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client.attributes.path.computation.client.reported.lsp.Path;
99 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
100 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
101 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
102 import org.opendaylight.yangtools.yang.common.Uint32;
103 import org.opendaylight.yangtools.yang.common.Uint8;
104 import org.slf4j.Logger;
105 import org.slf4j.LoggerFactory;
107 // Non-final for testing
108 class PCEPTopologySessionListener extends AbstractTopologySessionListener {
109 private static final Logger LOG = LoggerFactory.getLogger(PCEPTopologySessionListener.class);
110 private static final PlspId PLSPID_ZERO = new PlspId(Uint32.ZERO);
111 private static final SrpIdNumber SRPID_ZERO = new SrpIdNumber(Uint32.ZERO);
112 private static final String MISSING_XML_TAG = "Mandatory XML tags are missing.";
113 private static final MessageHeader MESSAGE_HEADER = new MessageHeader() {
114 private final ProtocolVersion version = new ProtocolVersion(Uint8.ONE);
117 public Class<MessageHeader> implementedInterface() {
118 return MessageHeader.class;
122 public ProtocolVersion getVersion() {
127 private final AtomicLong requestId = new AtomicLong(1L);
130 private final List<PlspId> staleLsps = new ArrayList<>();
132 private final PceServerProvider pceServerProvider;
135 * Creates a new stateful topology session listener for given server session manager.
137 PCEPTopologySessionListener(final ServerSessionManager serverSessionManager) {
138 super(serverSessionManager);
139 pceServerProvider = serverSessionManager.getPCEPTopologyProviderDependencies().getPceServerProvider();
142 private static LspDbVersion geLspDbVersionTlv(final Lsp lsp) {
143 final var tlvs = lsp.getTlvs();
145 final var tlvs1 = tlvs.augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang
146 .controller.pcep.sync.optimizations.rev200720.Tlvs1.class);
148 return tlvs1.getLspDbVersion();
155 public synchronized ListenableFuture<OperationResult> triggerSync(final TriggerSyncArgs input) {
156 if (isTriggeredInitialSynchro() && !isSynchronized()) {
157 return triggerSynchronization(input);
158 } else if (isSessionSynchronized() && isTriggeredReSyncEnabled()) {
159 checkArgument(input != null && input.getNode() != null, MISSING_XML_TAG);
160 return input.getName() == null ? triggerResyncronization(input) : triggerLspSyncronization(input);
162 return OperationResults.UNSENT.future();
165 private ListenableFuture<OperationResult> triggerLspSyncronization(final TriggerSyncArgs input) {
166 LOG.trace("Trigger Lsp Resynchronization {}", input);
168 // Make sure the LSP exists
169 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
170 final FluentFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
172 return OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future();
174 return Futures.transformAsync(f, new ResyncLspFunction(input), MoreExecutors.directExecutor());
177 private ListenableFuture<OperationResult> triggerResyncronization(final TriggerSyncArgs input) {
178 LOG.trace("Trigger Resynchronization {}", input);
180 updatePccState(PccSyncState.PcepTriggeredResync);
181 final PcupdMessageBuilder pcupdMessageBuilder = new PcupdMessageBuilder(MESSAGE_HEADER);
182 final SrpIdNumber srpIdNumber = createUpdateMessageSync(pcupdMessageBuilder);
183 final Message msg = new PcupdBuilder().setPcupdMessage(pcupdMessageBuilder.build()).build();
184 return sendMessage(msg, srpIdNumber, null);
187 private ListenableFuture<OperationResult> triggerSynchronization(final TriggerSyncArgs input) {
188 LOG.trace("Trigger Initial Synchronization {}", input);
189 final PcupdMessageBuilder pcupdMessageBuilder = new PcupdMessageBuilder(MESSAGE_HEADER);
190 final SrpIdNumber srpIdNumber = createUpdateMessageSync(pcupdMessageBuilder);
191 final Message msg = new PcupdBuilder().setPcupdMessage(pcupdMessageBuilder.build()).build();
192 return sendMessage(msg, srpIdNumber, null);
195 private SrpIdNumber createUpdateMessageSync(final PcupdMessageBuilder pcupdMessageBuilder) {
196 // FIXME: not sure whether use 0 instead of nextRequest() or do not insert srp == SRP-ID-number = 0
197 final var operationId = nextRequest();
199 pcupdMessageBuilder.setUpdates(List.of(new UpdatesBuilder()
200 // LSP mandatory in PCUpd
201 .setLsp(new LspBuilder().setPlspId(PLSPID_ZERO).setSync(Boolean.TRUE).build())
202 // SRP Mandatory in PCUpd
203 .setSrp(new SrpBuilder().setOperationId(operationId).build())
204 // ERO Mandatory in PCUpd
205 .setPath(new PathBuilder().setEro(new EroBuilder().build()).build())
212 private void markAllLspAsStale() {
213 staleLsps.addAll(lsps.keySet());
216 private boolean handleErrorMessage(final PcerrMessage message) {
217 final var errMsg = message.getPcerrMessage();
218 if (errMsg.getErrorType() instanceof StatefulCase) {
219 final StatefulCase stat = (StatefulCase) errMsg.getErrorType();
220 for (final Srps srps : stat.getStateful().nonnullSrps()) {
221 final SrpIdNumber id = srps.getSrp().getOperationId();
222 if (!SRPID_ZERO.equals(id)) {
223 final PCEPRequest req = removeRequest(id);
225 req.finish(OperationResults.createFailed(errMsg.getErrors()));
227 LOG.warn("Request ID {} not found in outstanding DB", id);
232 LOG.warn("Unhandled PCErr message {}.", errMsg);
238 private boolean isSolicited(final Srp srp, final Lsp lsp, final MessageContext ctx, final ReportedLspBuilder rlb) {
242 final SrpIdNumber id = srp.getOperationId();
243 if (SRPID_ZERO.equals(id)) {
246 switch (lsp.getOperational()) {
250 if (!isTriggeredSyncInProcess()) {
251 final PCEPRequest req = removeRequest(id);
253 LOG.debug("Request {} resulted in LSP operational state {}", id, lsp.getOperational());
254 rlb.setMetadata(req.getMetadata());
255 ctx.resolveRequest(req);
257 LOG.warn("Request ID {} not found in outstanding DB", id);
263 // These are transitive states, so we don't have to do anything, as they will be followed
273 private boolean manageNextReport(final Reports report, final MessageContext ctx) {
274 final Lsp lsp = report.getLsp();
275 final PlspId plspid = lsp.getPlspId();
276 final Srp srp = report.getSrp();
278 if (!lsp.getSync() && (plspid == null || PLSPID_ZERO.equals(plspid))) {
280 if (isTriggeredSyncInProcess()) {
284 final SrpIdNumber id = srp.getOperationId();
285 if (SRPID_ZERO.equals(id)) {
288 final PCEPRequest req = removeRequest(id);
289 ctx.resolveRequest(req);
291 stateSynchronizationAchieved(ctx);
294 final ReportedLspBuilder rlb = new ReportedLspBuilder();
295 boolean solicited = false;
296 solicited = isSolicited(srp, lsp, ctx, rlb);
298 // if remove flag is set in SRP object, remove the tunnel immediately
300 final Srp1 initiatedSrp = srp.augmentation(Srp1.class);
301 if (initiatedSrp != null && initiatedSrp.getRemove()) {
302 super.removeLsp(ctx, plspid);
306 rlb.setPath(BindingMap.of(buildPath(report, srp, lsp)));
308 String name = lookupLspName(plspid);
309 if (lsp.getTlvs() != null && lsp.getTlvs().getSymbolicPathName() != null) {
310 name = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(lsp.getTlvs().getSymbolicPathName().getPathName()
311 .getValue())).toString();
313 //get LspDB from LSP and write it to pcc's node
314 final LspDbVersion lspDbVersion = geLspDbVersionTlv(lsp);
315 if (lspDbVersion != null) {
316 updatePccNode(ctx, new PathComputationClientBuilder()
317 .addAugmentation(new PathComputationClient1Builder().setLspDbVersion(lspDbVersion).build()).build());
319 updateLsp(ctx, plspid, name, rlb, solicited, lsp.getRemove());
320 unmarkStaleLsp(plspid);
322 LOG.debug("LSP {} updated", lsp);
326 private static Path buildPath(final Reports report, final Srp srp, final Lsp lsp) {
327 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client
328 .attributes.path.computation.client.reported.lsp.PathBuilder pb = new org.opendaylight.yang.gen.v1
329 .urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client.attributes.path.computation
330 .client.reported.lsp.PathBuilder();
331 if (report.getPath() != null) {
332 pb.fieldsFrom(report.getPath());
334 // LSP is mandatory (if there is none, parser will throw an exception)
335 // this is to ensure a path will be created at any rate
336 final Path1Builder p1Builder = new Path1Builder();
337 p1Builder.setLsp(report.getLsp());
338 final PathSetupType pst;
339 if (srp != null && srp.getTlvs() != null && srp.getTlvs().getPathSetupType() != null) {
340 pst = srp.getTlvs().getPathSetupType();
341 p1Builder.setPathSetupType(pst);
345 pb.addAugmentation(p1Builder.build());
346 final var tlvs = report.getLsp().getTlvs();
348 if (tlvs.getLspIdentifiers() != null) {
349 pb.setLspId(tlvs.getLspIdentifiers().getLspId());
350 } else if (!PSTUtil.isDefaultPST(pst)) {
351 pb.setLspId(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820
352 .LspId(lsp.getPlspId().getValue()));
358 private boolean handlePcreqMessage(final PcreqMessage message) {
360 LOG.info("Start PcRequest Message handler");
363 /* Get a Path Computation to compute the Path from the Request */
364 // TODO: Adjust Junit Test to avoid this test
365 if (pceServerProvider == null) {
366 rep = createErrorMsg(PCEPErrors.RESOURCE_LIMIT_EXCEEDED, Uint32.ZERO);
367 sendMessage(rep, new SrpIdNumber(Uint32.ZERO), null);
370 PathComputation pathComputation = pceServerProvider.getPathComputation();
371 /* Reply with Error Message if no valid Path Computation is available */
372 if (pathComputation == null) {
373 rep = createErrorMsg(PCEPErrors.RESOURCE_LIMIT_EXCEEDED, Uint32.ZERO);
374 sendMessage(rep, new SrpIdNumber(Uint32.ZERO), null);
377 for (var req : message.nonnullRequests()) {
378 LOG.debug("Process request {}", req);
379 rep = pathComputation.computePath(req);
380 SrpIdNumber repId = null;
381 if (req.getRp() != null) {
382 repId = new SrpIdNumber(req.getRp().getRequestId().getValue());
384 repId = new SrpIdNumber(Uint32.ZERO);
386 sendMessage(rep, repId, null);
392 protected synchronized boolean onMessage(final MessageContext ctx, final Message message) {
393 if (message instanceof PcerrMessage) {
394 return handleErrorMessage((PcerrMessage) message);
396 if (message instanceof Pcreq) {
397 LOG.info("PcReq detected. Start Request Message handler");
398 return handlePcreqMessage(((Pcreq) message).getPcreqMessage());
400 if (!(message instanceof PcrptMessage)) {
403 listenerState.updateLastReceivedRptMsg();
404 final var rpt = ((PcrptMessage) message).getPcrptMessage();
405 for (final Reports report : rpt.nonnullReports()) {
406 if (!manageNextReport(report, ctx)) {
413 private SrpIdNumber nextRequest() {
414 return new SrpIdNumber(Uint32.valueOf(requestId.getAndIncrement()));
418 @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
419 public synchronized ListenableFuture<OperationResult> addLsp(final AddLspArgs input) {
420 checkArgument(input != null && input.getName() != null && input.getNode() != null
421 && input.getArguments() != null, MISSING_XML_TAG);
422 LOG.trace("AddLspArgs {}", input);
423 // Make sure there is no such LSP
424 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
425 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
426 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
427 : Futures.transformAsync(f, new AddFunction(input, lsp), MoreExecutors.directExecutor());
431 @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
432 public synchronized ListenableFuture<OperationResult> removeLsp(final RemoveLspArgs input) {
433 checkArgument(input != null && input.getName() != null && input.getNode() != null, MISSING_XML_TAG);
434 LOG.trace("RemoveLspArgs {}", input);
435 // Make sure the LSP exists, we need it for PLSP-ID
436 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
437 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
438 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
439 : Futures.transformAsync(f, rep -> {
440 final Lsp reportedLsp = validateReportedLsp(rep, input);
441 if (reportedLsp == null) {
442 return OperationResults.createUnsent(PCEPErrors.UNKNOWN_PLSP_ID).future();
444 final PcinitiateMessageBuilder ib = new PcinitiateMessageBuilder(MESSAGE_HEADER);
445 final Requests rb = buildRequest(rep, reportedLsp);
446 ib.setRequests(List.of(rb));
447 return sendMessage(new PcinitiateBuilder().setPcinitiateMessage(ib.build()).build(),
448 rb.getSrp().getOperationId(), null);
449 }, MoreExecutors.directExecutor());
452 private Requests buildRequest(final Optional<ReportedLsp> rep, final Lsp reportedLsp) {
453 // Build the request and send it
454 final RequestsBuilder rb = new RequestsBuilder();
455 final SrpBuilder srpBuilder = new SrpBuilder().addAugmentation(new Srp1Builder()
456 .setRemove(Boolean.TRUE).build()).setOperationId(nextRequest()).setProcessingRule(Boolean.TRUE);
457 final Optional<PathSetupType> maybePST = getPST(rep);
458 if (maybePST.isPresent()) {
459 srpBuilder.setTlvs(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
460 .rev200720.srp.object.srp.TlvsBuilder().setPathSetupType(maybePST.get()).build());
462 rb.setSrp(srpBuilder.build());
463 rb.setLsp(new LspBuilder().setRemove(Boolean.FALSE).setPlspId(reportedLsp.getPlspId())
464 .setDelegate(reportedLsp.getDelegate()).build());
468 private ListenableFuture<OperationResult> redelegate(final Lsp reportedLsp, final Srp srp, final Lsp lsp,
469 final UpdateLspArgs input) {
470 // the D bit that was reported decides the type of PCE message sent
471 final boolean isDelegate = requireNonNull(reportedLsp.getDelegate());
474 // we already have delegation, send update
475 final UpdatesBuilder rb = new UpdatesBuilder();
478 final PathBuilder pb = new PathBuilder();
479 pb.fieldsFrom(input.getArguments());
480 rb.setPath(pb.build());
481 final PcupdMessageBuilder ub = new PcupdMessageBuilder(MESSAGE_HEADER);
482 ub.setUpdates(List.of(rb.build()));
483 msg = new PcupdBuilder().setPcupdMessage(ub.build()).build();
485 final Lsp1 lspCreateFlag = reportedLsp.augmentation(Lsp1.class);
486 // we only retake delegation for PCE initiated tunnels
487 if (lspCreateFlag != null && !lspCreateFlag.getCreate()) {
488 LOG.warn("Unable to retake delegation of PCC-initiated tunnel: {}", reportedLsp);
489 return OperationResults.createUnsent(PCEPErrors.UPDATE_REQ_FOR_NON_LSP).future();
491 // we want to revoke delegation, different type of message
492 // is sent because of specification by Siva
493 // this message is also sent, when input delegate bit is set to 0
494 // generating an error in PCC
495 final List<Requests> reqs = new ArrayList<>();
496 reqs.add(new RequestsBuilder().setSrp(srp).setLsp(lsp).build());
497 final PcinitiateMessageBuilder ib = new PcinitiateMessageBuilder();
498 ib.setRequests(reqs);
499 msg = new PcinitiateBuilder().setPcinitiateMessage(ib.build()).build();
501 return sendMessage(msg, srp.getOperationId(), input.getArguments().getMetadata());
505 @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
506 public synchronized ListenableFuture<OperationResult> updateLsp(final UpdateLspArgs input) {
507 checkArgument(input != null && input.getName() != null && input.getNode() != null
508 && input.getArguments() != null, MISSING_XML_TAG);
509 LOG.trace("UpdateLspArgs {}", input);
510 // Make sure the LSP exists
511 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
512 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
513 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
514 : Futures.transformAsync(f, new UpdateFunction(input), MoreExecutors.directExecutor());
518 public synchronized ListenableFuture<OperationResult> ensureLspOperational(final EnsureLspOperationalInput input) {
519 checkArgument(input != null && input.getName() != null && input.getNode() != null, MISSING_XML_TAG);
520 final Arguments args = input.getArguments();
521 checkArgument(args != null, MISSING_XML_TAG);
523 final OperationalStatus op;
524 final Arguments1 aa = args.augmentation(Arguments1.class);
526 op = aa.getOperational();
531 // Make sure the LSP exists
532 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
533 LOG.debug("Checking if LSP {} has operational state {}", lsp, op);
534 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
535 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
536 : listenableFuture(f, input, op);
539 private static ListenableFuture<OperationResult> listenableFuture(
540 final ListenableFuture<Optional<ReportedLsp>> future, final EnsureLspOperationalInput input,
541 final OperationalStatus op) {
542 return Futures.transform(future, rep -> {
543 if (!rep.isPresent()) {
544 LOG.debug("Node {} does not contain LSP {}", input.getNode(), input.getName());
545 return OperationResults.UNSENT;
547 // check if at least one of the paths has the same status as requested
548 for (final Path p : rep.get().nonnullPath().values()) {
549 final Path1 p1 = p.augmentation(Path1.class);
551 LOG.warn("Node {} LSP {} does not contain data", input.getNode(), input.getName());
552 return OperationResults.UNSENT;
554 if (op.equals(p1.getLsp().getOperational())) {
555 return OperationResults.SUCCESS;
558 return OperationResults.UNSENT;
559 }, MoreExecutors.directExecutor());
563 protected Lsp validateReportedLsp(final Optional<ReportedLsp> rep, final LspId input) {
564 if (!rep.isPresent()) {
565 LOG.debug("Node {} does not contain LSP {}", input.getNode(), input.getName());
568 // it doesn't matter how many lsps there are in the path list, we only need data that is the same in each path
569 final Path1 ra = rep.get().getPath().values().iterator().next().augmentation(Path1.class);
570 checkState(ra != null, "Reported LSP reported null from data-store.");
571 final Lsp reportedLsp = ra.getLsp();
572 checkState(reportedLsp != null, "Reported LSP does not contain LSP object.");
576 private static Optional<PathSetupType> getPST(final Optional<ReportedLsp> rep) {
577 if (rep.isPresent()) {
578 final Path1 path1 = rep.get().getPath().values().iterator().next().augmentation(Path1.class);
580 final PathSetupType pst = path1.getPathSetupType();
581 if (!PSTUtil.isDefaultPST(pst)) {
582 return Optional.of(pst);
586 return Optional.empty();
590 * Recover lspData and mark any LSPs in the LSP database that were previously reported by the PCC as stale.
593 protected synchronized void loadLspData(final Node node, final Map<String, ReportedLsp> lspData,
594 final Map<PlspId, String> lsps, final boolean incrementalSynchro) {
595 //load node's lsps from DS
596 final PathComputationClient pcc = node.augmentation(Node1.class).getPathComputationClient();
597 for (final ReportedLsp reportedLsp : pcc.nonnullReportedLsp().values()) {
598 final String lspName = reportedLsp.getName();
599 lspData.put(lspName, reportedLsp);
600 if (!reportedLsp.getPath().isEmpty()) {
601 final Path1 path1 = reportedLsp.getPath().values().iterator().next().augmentation(Path1.class);
603 final PlspId plspId = path1.getLsp().getPlspId();
604 if (!incrementalSynchro) {
605 staleLsps.add(plspId);
607 lsps.put(plspId, lspName);
614 * When the PCC reports an LSP during state synchronization, if the LSP already
615 * exists in the LSP database, the PCE MUST update the LSP database and
616 * clear the stale marker from the LSP.
620 private synchronized void unmarkStaleLsp(final PlspId plspId) {
621 staleLsps.remove(plspId);
625 * Purge any LSPs from the LSP database that are still marked as stale.
627 * @param ctx message context
629 private synchronized void purgeStaleLsps(final MessageContext ctx) {
630 for (final PlspId plspId : staleLsps) {
631 removeLsp(ctx, plspId);
636 private class ResyncLspFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
637 private final TriggerSyncArgs input;
639 ResyncLspFunction(final TriggerSyncArgs input) {
644 public ListenableFuture<OperationResult> apply(final Optional<ReportedLsp> rep) {
645 final Lsp reportedLsp = validateReportedLsp(rep, input);
646 if (reportedLsp == null || !rep.isPresent()) {
647 return OperationResults.createUnsent(PCEPErrors.UNKNOWN_PLSP_ID).future();
650 final ReportedLsp staleLsp = rep.get();
651 if (!staleLsp.getPath().isEmpty()) {
652 final Path1 path1 = staleLsp.getPath().values().iterator().next().augmentation(Path1.class);
654 staleLsps.add(path1.getLsp().getPlspId());
657 updatePccState(PccSyncState.PcepTriggeredResync);
658 // create PCUpd with mandatory objects and LSP object set to 1
659 final SrpBuilder srpBuilder = new SrpBuilder();
660 srpBuilder.setOperationId(nextRequest());
661 srpBuilder.setProcessingRule(Boolean.TRUE);
663 final Optional<PathSetupType> maybePST = getPST(rep);
664 if (maybePST.isPresent()) {
666 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
667 .rev200720.srp.object.srp.TlvsBuilder()
668 .setPathSetupType(maybePST.get()).build());
671 final Srp srp = srpBuilder.build();
672 final Lsp lsp = new LspBuilder().setPlspId(reportedLsp.getPlspId()).setSync(Boolean.TRUE).build();
674 final Message msg = createPcepUpd(srp, lsp);
675 return sendMessage(msg, srp.getOperationId(), null);
678 private Message createPcepUpd(final Srp srp, final Lsp lsp) {
679 return new PcupdBuilder()
680 .setPcupdMessage(new PcupdMessageBuilder(MESSAGE_HEADER)
681 .setUpdates(List.of(new UpdatesBuilder()
684 .setPath(new PathBuilder().build())
691 private class AddFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
693 private final AddLspArgs input;
694 private final InstanceIdentifier<ReportedLsp> lsp;
696 AddFunction(final AddLspArgs input, final InstanceIdentifier<ReportedLsp> lsp) {
702 public ListenableFuture<OperationResult> apply(final Optional<ReportedLsp> rep) {
703 if (rep.isPresent()) {
704 LOG.debug("Node {} already contains lsp {} at {}", input.getNode(), input.getName(), lsp);
705 return OperationResults.createUnsent(PCEPErrors.USED_SYMBOLIC_PATH_NAME).future();
707 if (!isInitiationCapability()) {
708 return OperationResults.createUnsent(PCEPErrors.CAPABILITY_NOT_SUPPORTED).future();
712 final RequestsBuilder rb = new RequestsBuilder();
713 final var args = input.getArguments();
714 final Arguments2 args2 = args.augmentation(Arguments2.class);
715 final Lsp inputLsp = args2 != null ? args2.getLsp() : null;
716 if (inputLsp == null) {
717 return OperationResults.createUnsent(PCEPErrors.LSP_MISSING).future();
720 rb.fieldsFrom(input.getArguments());
722 boolean segmentRouting = !PSTUtil.isDefaultPST(args2.getPathSetupType());
724 /* Call Path Computation if an ERO was not provided */
725 if (rb.getEro() == null || rb.getEro().nonnullSubobject().isEmpty()) {
726 /* Get a Path Computation to compute the Path from the Arguments */
727 // TODO: Adjust Junit Test to avoid this test
728 if (pceServerProvider == null) {
729 return OperationResults.createUnsent(PCEPErrors.ERO_MISSING).future();
731 PathComputation pathComputation = pceServerProvider.getPathComputation();
732 if (pathComputation == null) {
733 return OperationResults.createUnsent(PCEPErrors.ERO_MISSING).future();
735 rb.setEro(pathComputation.computeEro(args.getEndpointsObj(), args.getBandwidth(),
736 args.getClassType(), args.getMetrics(), args.getXro(), args.getIro(), segmentRouting));
739 final TlvsBuilder tlvsBuilder;
740 if (inputLsp.getTlvs() != null) {
741 tlvsBuilder = new TlvsBuilder(inputLsp.getTlvs());
743 tlvsBuilder = new TlvsBuilder();
745 tlvsBuilder.setSymbolicPathName(
746 new SymbolicPathNameBuilder().setPathName(new SymbolicPathName(input.getName()
747 .getBytes(StandardCharsets.UTF_8))).build());
749 final SrpBuilder srpBuilder = new SrpBuilder()
750 .setOperationId(nextRequest())
751 .setProcessingRule(Boolean.TRUE);
752 if (segmentRouting) {
754 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf
755 .stateful.rev200720.srp.object.srp.TlvsBuilder()
756 .setPathSetupType(args2.getPathSetupType()).build());
758 rb.setSrp(srpBuilder.build());
760 rb.setLsp(new LspBuilder()
761 .setAdministrative(inputLsp.getAdministrative())
762 .setDelegate(inputLsp.getDelegate())
763 .setPlspId(PLSPID_ZERO)
764 .setTlvs(tlvsBuilder.build())
768 return sendMessage(new PcinitiateBuilder()
769 .setPcinitiateMessage(new PcinitiateMessageBuilder(MESSAGE_HEADER)
770 .setRequests(List.of(rb.build()))
773 rb.getSrp().getOperationId(), input.getArguments().getMetadata());
777 private class UpdateFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
779 private final UpdateLspArgs input;
781 UpdateFunction(final UpdateLspArgs input) {
786 public ListenableFuture<OperationResult> apply(final Optional<ReportedLsp> rep) {
787 final Lsp reportedLsp = validateReportedLsp(rep, input);
788 if (reportedLsp == null) {
789 return OperationResults.createUnsent(PCEPErrors.UNKNOWN_PLSP_ID).future();
791 // create mandatory objects
792 final Arguments3 args = input.getArguments().augmentation(Arguments3.class);
793 final SrpBuilder srpBuilder = new SrpBuilder();
794 srpBuilder.setOperationId(nextRequest());
795 srpBuilder.setProcessingRule(Boolean.TRUE);
796 if (args != null && args.getPathSetupType() != null) {
797 if (!PSTUtil.isDefaultPST(args.getPathSetupType())) {
799 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
800 .rev200720.srp.object.srp.TlvsBuilder()
801 .setPathSetupType(args.getPathSetupType()).build());
804 final Optional<PathSetupType> maybePST = getPST(rep);
805 if (maybePST.isPresent()) {
807 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
808 .rev200720.srp.object.srp.TlvsBuilder()
809 .setPathSetupType(maybePST.get()).build());
812 final Srp srp = srpBuilder.build();
813 final Lsp inputLsp = args != null ? args.getLsp() : null;
814 final LspBuilder lspBuilder = new LspBuilder().setPlspId(reportedLsp.getPlspId());
815 if (inputLsp != null) {
816 lspBuilder.setDelegate(Boolean.TRUE.equals(inputLsp.getDelegate()))
817 .setTlvs(inputLsp.getTlvs())
818 .setAdministrative(Boolean.TRUE.equals(inputLsp.getAdministrative()));
820 return redelegate(reportedLsp, srp, lspBuilder.build(), input);
824 private static Pcerr createErrorMsg(@NonNull final PCEPErrors pcepErrors, final Uint32 reqID) {
825 return new PcerrBuilder()
826 .setPcerrMessage(new PcerrMessageBuilder()
827 .setErrorType(new RequestCaseBuilder()
828 .setRequest(new RequestBuilder()
829 .setRps(List.of(new RpsBuilder()
830 .setRp(new RpBuilder()
831 .setProcessingRule(false)
833 .setRequestId(new RequestId(reqID))
838 .setErrors(List.of(new ErrorsBuilder()
839 .setErrorObject(new ErrorObjectBuilder()
840 .setType(pcepErrors.getErrorType())
841 .setValue(pcepErrors.getErrorValue())