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.PcerrMessage;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.RequestId;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.explicit.route.object.EroBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.path.setup.type.tlv.PathSetupType;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcep.error.object.ErrorObjectBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.PcerrMessageBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.ErrorsBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.error.type.RequestCaseBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.error.type.request._case.RequestBuilder;
79 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;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.PcreqMessage;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.rp.object.RpBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.AddLspArgs;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.EnsureLspOperationalInput;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.LspId;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.Node1;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.OperationResult;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.PccSyncState;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.RemoveLspArgs;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.TriggerSyncArgs;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.UpdateLspArgs;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.ensure.lsp.operational.args.Arguments;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.PathComputationClient;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.PathComputationClientBuilder;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.ReportedLsp;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.ReportedLspBuilder;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.reported.lsp.Path;
97 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
98 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
99 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
100 import org.opendaylight.yangtools.yang.common.Uint32;
101 import org.slf4j.Logger;
102 import org.slf4j.LoggerFactory;
104 // Non-final for testing
105 class PCEPTopologySessionListener extends AbstractTopologySessionListener {
106 private static final Logger LOG = LoggerFactory.getLogger(PCEPTopologySessionListener.class);
107 private static final PlspId PLSPID_ZERO = new PlspId(Uint32.ZERO);
108 private static final SrpIdNumber SRPID_ZERO = new SrpIdNumber(Uint32.ZERO);
110 private final AtomicLong requestId = new AtomicLong(1L);
113 private final List<PlspId> staleLsps = new ArrayList<>();
115 private final PceServerProvider pceServerProvider;
118 * Creates a new stateful topology session listener for given server session manager.
120 PCEPTopologySessionListener(final ServerSessionManager serverSessionManager) {
121 super(serverSessionManager);
122 pceServerProvider = serverSessionManager.getPCEPTopologyProviderDependencies().getPceServerProvider();
125 private static LspDbVersion geLspDbVersionTlv(final Lsp lsp) {
126 final var tlvs = lsp.getTlvs();
128 final var tlvs1 = tlvs.augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang
129 .controller.pcep.sync.optimizations.rev200720.Tlvs1.class);
131 return tlvs1.getLspDbVersion();
138 public synchronized ListenableFuture<OperationResult> triggerSync(final TriggerSyncArgs input) {
139 if (isTriggeredInitialSynchro() && !isSynchronized()) {
140 return triggerSynchronization(input);
141 } else if (isSessionSynchronized() && isTriggeredReSyncEnabled()) {
142 checkArgument(input != null && input.getNode() != null, MISSING_XML_TAG);
143 return input.getName() == null ? triggerResyncronization(input) : triggerLspSyncronization(input);
145 return OperationResults.UNSENT.future();
148 private ListenableFuture<OperationResult> triggerLspSyncronization(final TriggerSyncArgs input) {
149 LOG.trace("Trigger Lsp Resynchronization {}", input);
151 // Make sure the LSP exists
152 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
153 final FluentFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
155 return OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future();
157 return Futures.transformAsync(f, new ResyncLspFunction(input), MoreExecutors.directExecutor());
160 private ListenableFuture<OperationResult> triggerResyncronization(final TriggerSyncArgs input) {
161 LOG.trace("Trigger Resynchronization {}", input);
163 updatePccState(PccSyncState.PcepTriggeredResync);
164 final PcupdMessageBuilder pcupdMessageBuilder = new PcupdMessageBuilder(MESSAGE_HEADER);
165 final SrpIdNumber srpIdNumber = createUpdateMessageSync(pcupdMessageBuilder);
166 final Message msg = new PcupdBuilder().setPcupdMessage(pcupdMessageBuilder.build()).build();
167 return sendMessage(msg, srpIdNumber, null);
170 private ListenableFuture<OperationResult> triggerSynchronization(final TriggerSyncArgs input) {
171 LOG.trace("Trigger Initial Synchronization {}", input);
172 final PcupdMessageBuilder pcupdMessageBuilder = new PcupdMessageBuilder(MESSAGE_HEADER);
173 final SrpIdNumber srpIdNumber = createUpdateMessageSync(pcupdMessageBuilder);
174 final Message msg = new PcupdBuilder().setPcupdMessage(pcupdMessageBuilder.build()).build();
175 return sendMessage(msg, srpIdNumber, null);
178 private SrpIdNumber createUpdateMessageSync(final PcupdMessageBuilder pcupdMessageBuilder) {
179 final UpdatesBuilder updBuilder = new UpdatesBuilder();
180 // LSP mandatory in Upd
181 final Lsp lsp = new LspBuilder().setPlspId(PLSPID_ZERO).setSync(Boolean.TRUE).build();
182 // SRP Mandatory in Upd
183 final SrpBuilder srpBuilder = new SrpBuilder();
184 // not sue whether use 0 instead of nextRequest() or do not insert srp == SRP-ID-number = 0
185 srpBuilder.setOperationId(nextRequest());
186 final Srp srp = srpBuilder.build();
187 //ERO Mandatory in Upd
188 final PathBuilder pb = new PathBuilder();
189 pb.setEro(new EroBuilder().build());
191 updBuilder.setPath(pb.build());
192 updBuilder.setLsp(lsp).setSrp(srp).setPath(pb.build());
194 pcupdMessageBuilder.setUpdates(List.of(updBuilder.build()));
195 return srp.getOperationId();
199 private void markAllLspAsStale() {
200 staleLsps.addAll(lsps.keySet());
203 private boolean handleErrorMessage(final PcerrMessage message) {
204 final var errMsg = message.getPcerrMessage();
205 if (errMsg.getErrorType() instanceof StatefulCase) {
206 final StatefulCase stat = (StatefulCase) errMsg.getErrorType();
207 for (final Srps srps : stat.getStateful().nonnullSrps()) {
208 final SrpIdNumber id = srps.getSrp().getOperationId();
209 if (!SRPID_ZERO.equals(id)) {
210 final PCEPRequest req = removeRequest(id);
212 req.done(OperationResults.createFailed(errMsg.getErrors()));
214 LOG.warn("Request ID {} not found in outstanding DB", id);
219 LOG.warn("Unhandled PCErr message {}.", errMsg);
225 private boolean isSolicited(final Srp srp, final Lsp lsp, final MessageContext ctx, final ReportedLspBuilder rlb) {
229 final SrpIdNumber id = srp.getOperationId();
230 if (SRPID_ZERO.equals(id)) {
233 switch (lsp.getOperational()) {
237 if (!isTriggeredSyncInProcess()) {
238 final PCEPRequest req = removeRequest(id);
240 LOG.debug("Request {} resulted in LSP operational state {}", id, lsp.getOperational());
241 rlb.setMetadata(req.getMetadata());
242 ctx.resolveRequest(req);
244 LOG.warn("Request ID {} not found in outstanding DB", id);
250 // These are transitive states, so we don't have to do anything, as they will be followed
260 private boolean manageNextReport(final Reports report, final MessageContext ctx) {
261 final Lsp lsp = report.getLsp();
262 final PlspId plspid = lsp.getPlspId();
263 final Srp srp = report.getSrp();
265 if (!lsp.getSync() && (plspid == null || PLSPID_ZERO.equals(plspid))) {
267 if (isTriggeredSyncInProcess()) {
271 final SrpIdNumber id = srp.getOperationId();
272 if (SRPID_ZERO.equals(id)) {
275 final PCEPRequest req = removeRequest(id);
276 ctx.resolveRequest(req);
278 stateSynchronizationAchieved(ctx);
281 final ReportedLspBuilder rlb = new ReportedLspBuilder();
282 boolean solicited = false;
283 solicited = isSolicited(srp, lsp, ctx, rlb);
285 // if remove flag is set in SRP object, remove the tunnel immediately
287 final Srp1 initiatedSrp = srp.augmentation(Srp1.class);
288 if (initiatedSrp != null && initiatedSrp.getRemove()) {
289 super.removeLsp(ctx, plspid);
293 rlb.setPath(BindingMap.of(buildPath(report, srp, lsp)));
295 String name = lookupLspName(plspid);
296 if (lsp.getTlvs() != null && lsp.getTlvs().getSymbolicPathName() != null) {
297 name = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(lsp.getTlvs().getSymbolicPathName().getPathName()
298 .getValue())).toString();
300 //get LspDB from LSP and write it to pcc's node
301 final LspDbVersion lspDbVersion = geLspDbVersionTlv(lsp);
302 if (lspDbVersion != null) {
303 updatePccNode(ctx, new PathComputationClientBuilder()
304 .addAugmentation(new PathComputationClient1Builder().setLspDbVersion(lspDbVersion).build()).build());
306 updateLsp(ctx, plspid, name, rlb, solicited, lsp.getRemove());
307 unmarkStaleLsp(plspid);
309 LOG.debug("LSP {} updated", lsp);
313 private static Path buildPath(final Reports report, final Srp srp, final Lsp lsp) {
314 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client
315 .attributes.path.computation.client.reported.lsp.PathBuilder pb = new org.opendaylight.yang.gen.v1
316 .urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation
317 .client.reported.lsp.PathBuilder();
318 if (report.getPath() != null) {
319 pb.fieldsFrom(report.getPath());
321 // LSP is mandatory (if there is none, parser will throw an exception)
322 // this is to ensure a path will be created at any rate
323 final Path1Builder p1Builder = new Path1Builder();
324 p1Builder.setLsp(report.getLsp());
325 final PathSetupType pst;
326 if (srp != null && srp.getTlvs() != null && srp.getTlvs().getPathSetupType() != null) {
327 pst = srp.getTlvs().getPathSetupType();
328 p1Builder.setPathSetupType(pst);
332 pb.addAugmentation(p1Builder.build());
333 final var tlvs = report.getLsp().getTlvs();
335 if (tlvs.getLspIdentifiers() != null) {
336 pb.setLspId(tlvs.getLspIdentifiers().getLspId());
337 } else if (!PSTUtil.isDefaultPST(pst)) {
338 pb.setLspId(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820
339 .LspId(lsp.getPlspId().getValue()));
345 private boolean handlePcreqMessage(final PcreqMessage message) {
347 LOG.info("Start PcRequest Message handler");
350 /* Get a Path Computation to compute the Path from the Request */
351 // TODO: Adjust Junit Test to avoid this test
352 if (pceServerProvider == null) {
353 rep = createErrorMsg(PCEPErrors.RESOURCE_LIMIT_EXCEEDED, Uint32.ZERO);
354 sendMessage(rep, new SrpIdNumber(Uint32.ZERO), null);
357 PathComputation pathComputation = pceServerProvider.getPathComputation();
358 /* Reply with Error Message if no valid Path Computation is available */
359 if (pathComputation == null) {
360 rep = createErrorMsg(PCEPErrors.RESOURCE_LIMIT_EXCEEDED, Uint32.ZERO);
361 sendMessage(rep, new SrpIdNumber(Uint32.ZERO), null);
364 for (var req : message.nonnullRequests()) {
365 LOG.debug("Process request {}", req);
366 rep = pathComputation.computePath(req);
367 SrpIdNumber repId = null;
368 if (req.getRp() != null) {
369 repId = new SrpIdNumber(req.getRp().getRequestId().getValue());
371 repId = new SrpIdNumber(Uint32.ZERO);
373 sendMessage(rep, repId, null);
379 protected synchronized boolean onMessage(final MessageContext ctx, final Message message) {
380 if (message instanceof PcerrMessage) {
381 return handleErrorMessage((PcerrMessage) message);
383 if (message instanceof Pcreq) {
384 LOG.info("PcReq detected. Start Request Message handler");
385 return handlePcreqMessage(((Pcreq) message).getPcreqMessage());
387 if (!(message instanceof PcrptMessage)) {
390 listenerState.updateLastReceivedRptMsg();
391 final var rpt = ((PcrptMessage) message).getPcrptMessage();
392 for (final Reports report : rpt.nonnullReports()) {
393 if (!manageNextReport(report, ctx)) {
400 private SrpIdNumber nextRequest() {
401 return new SrpIdNumber(Uint32.valueOf(requestId.getAndIncrement()));
405 @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
406 public synchronized ListenableFuture<OperationResult> addLsp(final AddLspArgs input) {
407 checkArgument(input != null && input.getName() != null && input.getNode() != null
408 && input.getArguments() != null, MISSING_XML_TAG);
409 LOG.trace("AddLspArgs {}", input);
410 // Make sure there is no such LSP
411 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
412 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
413 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
414 : Futures.transformAsync(f, new AddFunction(input, lsp), MoreExecutors.directExecutor());
418 @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
419 public synchronized ListenableFuture<OperationResult> removeLsp(final RemoveLspArgs input) {
420 checkArgument(input != null && input.getName() != null && input.getNode() != null, MISSING_XML_TAG);
421 LOG.trace("RemoveLspArgs {}", input);
422 // Make sure the LSP exists, we need it for PLSP-ID
423 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
424 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
425 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
426 : Futures.transformAsync(f, rep -> {
427 final Lsp reportedLsp = validateReportedLsp(rep, input);
428 if (reportedLsp == null) {
429 return OperationResults.createUnsent(PCEPErrors.UNKNOWN_PLSP_ID).future();
431 final PcinitiateMessageBuilder ib = new PcinitiateMessageBuilder(MESSAGE_HEADER);
432 final Requests rb = buildRequest(rep, reportedLsp);
433 ib.setRequests(List.of(rb));
434 return sendMessage(new PcinitiateBuilder().setPcinitiateMessage(ib.build()).build(),
435 rb.getSrp().getOperationId(), null);
436 }, MoreExecutors.directExecutor());
439 private Requests buildRequest(final Optional<ReportedLsp> rep, final Lsp reportedLsp) {
440 // Build the request and send it
441 final RequestsBuilder rb = new RequestsBuilder();
442 final SrpBuilder srpBuilder = new SrpBuilder().addAugmentation(new Srp1Builder()
443 .setRemove(Boolean.TRUE).build()).setOperationId(nextRequest()).setProcessingRule(Boolean.TRUE);
444 final Optional<PathSetupType> maybePST = getPST(rep);
445 if (maybePST.isPresent()) {
446 srpBuilder.setTlvs(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
447 .rev200720.srp.object.srp.TlvsBuilder().setPathSetupType(maybePST.get()).build());
449 rb.setSrp(srpBuilder.build());
450 rb.setLsp(new LspBuilder().setRemove(Boolean.FALSE).setPlspId(reportedLsp.getPlspId())
451 .setDelegate(reportedLsp.getDelegate()).build());
455 private ListenableFuture<OperationResult> redelegate(final Lsp reportedLsp, final Srp srp, final Lsp lsp,
456 final UpdateLspArgs input) {
457 // the D bit that was reported decides the type of PCE message sent
458 final boolean isDelegate = requireNonNull(reportedLsp.getDelegate());
461 // we already have delegation, send update
462 final UpdatesBuilder rb = new UpdatesBuilder();
465 final PathBuilder pb = new PathBuilder();
466 pb.fieldsFrom(input.getArguments());
467 rb.setPath(pb.build());
468 final PcupdMessageBuilder ub = new PcupdMessageBuilder(MESSAGE_HEADER);
469 ub.setUpdates(List.of(rb.build()));
470 msg = new PcupdBuilder().setPcupdMessage(ub.build()).build();
472 final Lsp1 lspCreateFlag = reportedLsp.augmentation(Lsp1.class);
473 // we only retake delegation for PCE initiated tunnels
474 if (lspCreateFlag != null && !lspCreateFlag.getCreate()) {
475 LOG.warn("Unable to retake delegation of PCC-initiated tunnel: {}", reportedLsp);
476 return OperationResults.createUnsent(PCEPErrors.UPDATE_REQ_FOR_NON_LSP).future();
478 // we want to revoke delegation, different type of message
479 // is sent because of specification by Siva
480 // this message is also sent, when input delegate bit is set to 0
481 // generating an error in PCC
482 final List<Requests> reqs = new ArrayList<>();
483 reqs.add(new RequestsBuilder().setSrp(srp).setLsp(lsp).build());
484 final PcinitiateMessageBuilder ib = new PcinitiateMessageBuilder();
485 ib.setRequests(reqs);
486 msg = new PcinitiateBuilder().setPcinitiateMessage(ib.build()).build();
488 return sendMessage(msg, srp.getOperationId(), input.getArguments().getMetadata());
492 @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
493 public synchronized ListenableFuture<OperationResult> updateLsp(final UpdateLspArgs input) {
494 checkArgument(input != null && input.getName() != null && input.getNode() != null
495 && input.getArguments() != null, MISSING_XML_TAG);
496 LOG.trace("UpdateLspArgs {}", input);
497 // Make sure the LSP exists
498 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
499 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
500 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
501 : Futures.transformAsync(f, new UpdateFunction(input), MoreExecutors.directExecutor());
505 public synchronized ListenableFuture<OperationResult> ensureLspOperational(final EnsureLspOperationalInput input) {
506 checkArgument(input != null && input.getName() != null && input.getNode() != null, MISSING_XML_TAG);
507 final Arguments args = input.getArguments();
508 checkArgument(args != null, MISSING_XML_TAG);
510 final OperationalStatus op;
511 final Arguments1 aa = args.augmentation(Arguments1.class);
513 op = aa.getOperational();
518 // Make sure the LSP exists
519 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
520 LOG.debug("Checking if LSP {} has operational state {}", lsp, op);
521 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
522 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
523 : listenableFuture(f, input, op);
526 private static ListenableFuture<OperationResult> listenableFuture(
527 final ListenableFuture<Optional<ReportedLsp>> future, final EnsureLspOperationalInput input,
528 final OperationalStatus op) {
529 return Futures.transform(future, rep -> {
530 if (!rep.isPresent()) {
531 LOG.debug("Node {} does not contain LSP {}", input.getNode(), input.getName());
532 return OperationResults.UNSENT;
534 // check if at least one of the paths has the same status as requested
535 for (final Path p : rep.get().nonnullPath().values()) {
536 final Path1 p1 = p.augmentation(Path1.class);
538 LOG.warn("Node {} LSP {} does not contain data", input.getNode(), input.getName());
539 return OperationResults.UNSENT;
541 if (op.equals(p1.getLsp().getOperational())) {
542 return OperationResults.SUCCESS;
545 return OperationResults.UNSENT;
546 }, MoreExecutors.directExecutor());
550 protected Lsp validateReportedLsp(final Optional<ReportedLsp> rep, final LspId input) {
551 if (!rep.isPresent()) {
552 LOG.debug("Node {} does not contain LSP {}", input.getNode(), input.getName());
555 // it doesn't matter how many lsps there are in the path list, we only need data that is the same in each path
556 final Path1 ra = rep.get().getPath().values().iterator().next().augmentation(Path1.class);
557 checkState(ra != null, "Reported LSP reported null from data-store.");
558 final Lsp reportedLsp = ra.getLsp();
559 checkState(reportedLsp != null, "Reported LSP does not contain LSP object.");
563 private static Optional<PathSetupType> getPST(final Optional<ReportedLsp> rep) {
564 if (rep.isPresent()) {
565 final Path1 path1 = rep.get().getPath().values().iterator().next().augmentation(Path1.class);
567 final PathSetupType pst = path1.getPathSetupType();
568 if (!PSTUtil.isDefaultPST(pst)) {
569 return Optional.of(pst);
573 return Optional.empty();
577 * Recover lspData and mark any LSPs in the LSP database that were previously reported by the PCC as stale.
580 protected synchronized void loadLspData(final Node node, final Map<String, ReportedLsp> lspData,
581 final Map<PlspId, String> lsps, final boolean incrementalSynchro) {
582 //load node's lsps from DS
583 final PathComputationClient pcc = node.augmentation(Node1.class).getPathComputationClient();
584 for (final ReportedLsp reportedLsp : pcc.nonnullReportedLsp().values()) {
585 final String lspName = reportedLsp.getName();
586 lspData.put(lspName, reportedLsp);
587 if (!reportedLsp.getPath().isEmpty()) {
588 final Path1 path1 = reportedLsp.getPath().values().iterator().next().augmentation(Path1.class);
590 final PlspId plspId = path1.getLsp().getPlspId();
591 if (!incrementalSynchro) {
592 staleLsps.add(plspId);
594 lsps.put(plspId, lspName);
601 * When the PCC reports an LSP during state synchronization, if the LSP already
602 * exists in the LSP database, the PCE MUST update the LSP database and
603 * clear the stale marker from the LSP.
607 private synchronized void unmarkStaleLsp(final PlspId plspId) {
608 staleLsps.remove(plspId);
612 * Purge any LSPs from the LSP database that are still marked as stale.
614 * @param ctx message context
616 private synchronized void purgeStaleLsps(final MessageContext ctx) {
617 for (final PlspId plspId : staleLsps) {
618 removeLsp(ctx, plspId);
623 private class ResyncLspFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
624 private final TriggerSyncArgs input;
626 ResyncLspFunction(final TriggerSyncArgs input) {
631 public ListenableFuture<OperationResult> apply(final Optional<ReportedLsp> rep) {
632 final Lsp reportedLsp = validateReportedLsp(rep, input);
633 if (reportedLsp == null || !rep.isPresent()) {
634 return OperationResults.createUnsent(PCEPErrors.UNKNOWN_PLSP_ID).future();
637 final ReportedLsp staleLsp = rep.get();
638 if (!staleLsp.getPath().isEmpty()) {
639 final Path1 path1 = staleLsp.getPath().values().iterator().next().augmentation(Path1.class);
641 staleLsps.add(path1.getLsp().getPlspId());
644 updatePccState(PccSyncState.PcepTriggeredResync);
645 // create PCUpd with mandatory objects and LSP object set to 1
646 final SrpBuilder srpBuilder = new SrpBuilder();
647 srpBuilder.setOperationId(nextRequest());
648 srpBuilder.setProcessingRule(Boolean.TRUE);
650 final Optional<PathSetupType> maybePST = getPST(rep);
651 if (maybePST.isPresent()) {
653 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
654 .rev200720.srp.object.srp.TlvsBuilder()
655 .setPathSetupType(maybePST.get()).build());
658 final Srp srp = srpBuilder.build();
659 final Lsp lsp = new LspBuilder().setPlspId(reportedLsp.getPlspId()).setSync(Boolean.TRUE).build();
661 final Message msg = createPcepUpd(srp, lsp);
662 return sendMessage(msg, srp.getOperationId(), null);
665 private Message createPcepUpd(final Srp srp, final Lsp lsp) {
666 return new PcupdBuilder()
667 .setPcupdMessage(new PcupdMessageBuilder(MESSAGE_HEADER)
668 .setUpdates(List.of(new UpdatesBuilder()
671 .setPath(new PathBuilder().build())
678 private class AddFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
680 private final AddLspArgs input;
681 private final InstanceIdentifier<ReportedLsp> lsp;
683 AddFunction(final AddLspArgs input, final InstanceIdentifier<ReportedLsp> lsp) {
689 public ListenableFuture<OperationResult> apply(final Optional<ReportedLsp> rep) {
690 if (rep.isPresent()) {
691 LOG.debug("Node {} already contains lsp {} at {}", input.getNode(), input.getName(), lsp);
692 return OperationResults.createUnsent(PCEPErrors.USED_SYMBOLIC_PATH_NAME).future();
694 if (!isInitiationCapability()) {
695 return OperationResults.createUnsent(PCEPErrors.CAPABILITY_NOT_SUPPORTED).future();
699 final RequestsBuilder rb = new RequestsBuilder();
700 final var args = input.getArguments();
701 final Arguments2 args2 = args.augmentation(Arguments2.class);
702 final Lsp inputLsp = args2 != null ? args2.getLsp() : null;
703 if (inputLsp == null) {
704 return OperationResults.createUnsent(PCEPErrors.LSP_MISSING).future();
707 rb.fieldsFrom(input.getArguments());
709 boolean segmentRouting = !PSTUtil.isDefaultPST(args2.getPathSetupType());
711 /* Call Path Computation if an ERO was not provided */
712 if (rb.getEro() == null || rb.getEro().nonnullSubobject().isEmpty()) {
713 /* Get a Path Computation to compute the Path from the Arguments */
714 // TODO: Adjust Junit Test to avoid this test
715 if (pceServerProvider == null) {
716 return OperationResults.createUnsent(PCEPErrors.ERO_MISSING).future();
718 PathComputation pathComputation = pceServerProvider.getPathComputation();
719 if (pathComputation == null) {
720 return OperationResults.createUnsent(PCEPErrors.ERO_MISSING).future();
722 rb.setEro(pathComputation.computeEro(args.getEndpointsObj(), args.getBandwidth(),
723 args.getClassType(), args.getMetrics(), args.getXro(), args.getIro(), segmentRouting));
726 final TlvsBuilder tlvsBuilder;
727 if (inputLsp.getTlvs() != null) {
728 tlvsBuilder = new TlvsBuilder(inputLsp.getTlvs());
730 tlvsBuilder = new TlvsBuilder();
732 tlvsBuilder.setSymbolicPathName(
733 new SymbolicPathNameBuilder().setPathName(new SymbolicPathName(input.getName()
734 .getBytes(StandardCharsets.UTF_8))).build());
736 final SrpBuilder srpBuilder = new SrpBuilder()
737 .setOperationId(nextRequest())
738 .setProcessingRule(Boolean.TRUE);
739 if (segmentRouting) {
741 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf
742 .stateful.rev200720.srp.object.srp.TlvsBuilder()
743 .setPathSetupType(args2.getPathSetupType()).build());
745 rb.setSrp(srpBuilder.build());
747 rb.setLsp(new LspBuilder()
748 .setAdministrative(inputLsp.getAdministrative())
749 .setDelegate(inputLsp.getDelegate())
750 .setPlspId(PLSPID_ZERO)
751 .setTlvs(tlvsBuilder.build())
755 return sendMessage(new PcinitiateBuilder()
756 .setPcinitiateMessage(new PcinitiateMessageBuilder(MESSAGE_HEADER)
757 .setRequests(List.of(rb.build()))
760 rb.getSrp().getOperationId(), input.getArguments().getMetadata());
764 private class UpdateFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
766 private final UpdateLspArgs input;
768 UpdateFunction(final UpdateLspArgs input) {
773 public ListenableFuture<OperationResult> apply(final Optional<ReportedLsp> rep) {
774 final Lsp reportedLsp = validateReportedLsp(rep, input);
775 if (reportedLsp == null) {
776 return OperationResults.createUnsent(PCEPErrors.UNKNOWN_PLSP_ID).future();
778 // create mandatory objects
779 final Arguments3 args = input.getArguments().augmentation(Arguments3.class);
780 final SrpBuilder srpBuilder = new SrpBuilder();
781 srpBuilder.setOperationId(nextRequest());
782 srpBuilder.setProcessingRule(Boolean.TRUE);
783 if (args != null && args.getPathSetupType() != null) {
784 if (!PSTUtil.isDefaultPST(args.getPathSetupType())) {
786 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
787 .rev200720.srp.object.srp.TlvsBuilder()
788 .setPathSetupType(args.getPathSetupType()).build());
791 final Optional<PathSetupType> maybePST = getPST(rep);
792 if (maybePST.isPresent()) {
794 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
795 .rev200720.srp.object.srp.TlvsBuilder()
796 .setPathSetupType(maybePST.get()).build());
799 final Srp srp = srpBuilder.build();
800 final Lsp inputLsp = args != null ? args.getLsp() : null;
801 final LspBuilder lspBuilder = new LspBuilder().setPlspId(reportedLsp.getPlspId());
802 if (inputLsp != null) {
803 lspBuilder.setDelegate(Boolean.TRUE.equals(inputLsp.getDelegate()))
804 .setTlvs(inputLsp.getTlvs())
805 .setAdministrative(Boolean.TRUE.equals(inputLsp.getAdministrative()));
807 return redelegate(reportedLsp, srp, lspBuilder.build(), input);
811 private static Pcerr createErrorMsg(@NonNull final PCEPErrors pcepErrors, final Uint32 reqID) {
812 return new PcerrBuilder()
813 .setPcerrMessage(new PcerrMessageBuilder()
814 .setErrorType(new RequestCaseBuilder()
815 .setRequest(new RequestBuilder()
816 .setRps(List.of(new RpsBuilder()
817 .setRp(new RpBuilder()
818 .setProcessingRule(false)
820 .setRequestId(new RequestId(reqID))
825 .setErrors(List.of(new ErrorsBuilder()
826 .setErrorObject(new ErrorObjectBuilder()
827 .setType(pcepErrors.getErrorType())
828 .setValue(pcepErrors.getErrorValue())