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.List;
26 import java.util.Optional;
27 import java.util.concurrent.atomic.AtomicBoolean;
28 import java.util.concurrent.atomic.AtomicLong;
29 import org.checkerframework.checker.lock.qual.GuardedBy;
30 import org.checkerframework.checker.lock.qual.Holding;
31 import org.eclipse.jdt.annotation.NonNull;
32 import org.opendaylight.bgpcep.pcep.server.PathComputation;
33 import org.opendaylight.bgpcep.pcep.server.PceServerProvider;
34 import org.opendaylight.protocol.pcep.spi.PCEPErrors;
35 import org.opendaylight.protocol.pcep.spi.PSTUtil;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev200720.PathComputationClient1Builder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev200720.lsp.db.version.tlv.LspDbVersion;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.Lsp1;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.PcinitiateBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.Srp1;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.Srp1Builder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.Stateful1;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.pcinitiate.message.PcinitiateMessageBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.pcinitiate.message.pcinitiate.message.Requests;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.pcinitiate.message.pcinitiate.message.RequestsBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Arguments1;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Arguments2;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Arguments3;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.OperationalStatus;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Path1;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Path1Builder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.PcrptMessage;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.PcupdBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.PlspId;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.SrpIdNumber;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.StatefulTlv1Builder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.SymbolicPathName;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Tlvs1;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object.Lsp;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object.LspBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object.lsp.TlvsBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.pcerr.pcerr.message.error.type.StatefulCase;
63 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;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.pcrpt.message.pcrpt.message.Reports;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.pcupd.message.PcupdMessageBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.pcupd.message.pcupd.message.UpdatesBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.pcupd.message.pcupd.message.updates.PathBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.srp.object.Srp;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.srp.object.SrpBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.stateful.capability.tlv.Stateful;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.symbolic.path.name.tlv.SymbolicPathNameBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.Pcerr;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.PcerrBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.Pcreq;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Message;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.PcerrMessage;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.RequestId;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.explicit.route.object.EroBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.open.object.open.Tlvs;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.path.setup.type.tlv.PathSetupType;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcep.error.object.ErrorObjectBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.PcerrMessageBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.ErrorsBuilder;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.error.type.RequestCaseBuilder;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.error.type.request._case.RequestBuilder;
86 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;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.PcreqMessage;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.rp.object.RpBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.AddLspArgs;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.EnsureLspOperationalInput;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.LspId;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.Node1;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.OperationResult;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.PccSyncState;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.RemoveLspArgs;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.TriggerSyncArgs;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.UpdateLspArgs;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.ensure.lsp.operational.args.Arguments;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.PathComputationClient;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.PathComputationClientBuilder;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.ReportedLsp;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.ReportedLspBuilder;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.StatefulTlvBuilder;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.reported.lsp.Path;
105 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
106 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
107 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
108 import org.opendaylight.yangtools.yang.common.Uint32;
109 import org.slf4j.Logger;
110 import org.slf4j.LoggerFactory;
112 // Non-final for testing
113 class PCEPTopologySessionListener extends AbstractTopologySessionListener<SrpIdNumber, PlspId> {
114 private static final Logger LOG = LoggerFactory.getLogger(PCEPTopologySessionListener.class);
115 private static final PlspId PLSPID_ZERO = new PlspId(Uint32.ZERO);
117 private final AtomicLong requestId = new AtomicLong(1L);
120 private final List<PlspId> staleLsps = new ArrayList<>();
122 private final AtomicBoolean statefulCapability = new AtomicBoolean(false);
123 private final AtomicBoolean lspUpdateCapability = new AtomicBoolean(false);
124 private final AtomicBoolean initiationCapability = new AtomicBoolean(false);
126 private final PceServerProvider pceServerProvider;
129 * Creates a new stateful topology session listener for given server session manager.
131 PCEPTopologySessionListener(final ServerSessionManager serverSessionManager) {
132 super(serverSessionManager);
133 pceServerProvider = serverSessionManager.getPCEPTopologyProviderDependencies().getPceServerProvider();
136 private static LspDbVersion geLspDbVersionTlv(final Lsp lsp) {
137 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object
138 .lsp.Tlvs tlvs = lsp.getTlvs();
139 if (tlvs != null && tlvs.augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang
140 .controller.pcep.sync.optimizations.rev200720.Tlvs1.class) != null) {
141 return tlvs.augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller
142 .pcep.sync.optimizations.rev200720.Tlvs1.class).getLspDbVersion();
148 protected void onSessionUp(final PathComputationClientBuilder pccBuilder, final InetAddress peerAddress,
149 final Tlvs remoteTlvs) {
150 if (remoteTlvs != null) {
151 final Tlvs1 statefulTlvs = remoteTlvs.augmentation(Tlvs1.class);
152 if (statefulTlvs != null) {
153 final Stateful stateful = statefulTlvs.getStateful();
154 if (stateful != null) {
155 setStatefulCapabilities(stateful);
156 pccBuilder.setReportedLsp(Map.of());
157 if (isSynchronized()) {
158 pccBuilder.setStateSync(PccSyncState.Synchronized);
159 } else if (isTriggeredInitialSynchro()) {
160 pccBuilder.setStateSync(PccSyncState.TriggeredInitialSync);
161 } else if (isIncrementalSynchro()) {
162 pccBuilder.setStateSync(PccSyncState.IncrementalSync);
164 pccBuilder.setStateSync(PccSyncState.InitialResync);
166 pccBuilder.setStatefulTlv(new StatefulTlvBuilder()
167 .addAugmentation(new StatefulTlv1Builder(statefulTlvs).build())
173 LOG.debug("Peer {} does not advertise stateful TLV", peerAddress);
177 public synchronized ListenableFuture<OperationResult> triggerSync(final TriggerSyncArgs input) {
178 if (isTriggeredInitialSynchro() && !isSynchronized()) {
179 return triggerSynchronization(input);
180 } else if (isSessionSynchronized() && isTriggeredReSyncEnabled()) {
181 checkArgument(input != null && input.getNode() != null, MISSING_XML_TAG);
182 return input.getName() == null ? triggerResyncronization(input) : triggerLspSyncronization(input);
184 return OperationResults.UNSENT.future();
187 private ListenableFuture<OperationResult> triggerLspSyncronization(final TriggerSyncArgs input) {
188 LOG.trace("Trigger Lsp Resynchronization {}", input);
190 // Make sure the LSP exists
191 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
192 final FluentFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
194 return OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future();
196 return Futures.transformAsync(f, new ResyncLspFunction(input), MoreExecutors.directExecutor());
199 private ListenableFuture<OperationResult> triggerResyncronization(final TriggerSyncArgs input) {
200 LOG.trace("Trigger Resynchronization {}", input);
202 updatePccState(PccSyncState.PcepTriggeredResync);
203 final PcupdMessageBuilder pcupdMessageBuilder = new PcupdMessageBuilder(MESSAGE_HEADER);
204 final SrpIdNumber srpIdNumber = createUpdateMessageSync(pcupdMessageBuilder);
205 final Message msg = new PcupdBuilder().setPcupdMessage(pcupdMessageBuilder.build()).build();
206 return sendMessage(msg, srpIdNumber, null);
209 private ListenableFuture<OperationResult> triggerSynchronization(final TriggerSyncArgs input) {
210 LOG.trace("Trigger Initial Synchronization {}", input);
211 final PcupdMessageBuilder pcupdMessageBuilder = new PcupdMessageBuilder(MESSAGE_HEADER);
212 final SrpIdNumber srpIdNumber = createUpdateMessageSync(pcupdMessageBuilder);
213 final Message msg = new PcupdBuilder().setPcupdMessage(pcupdMessageBuilder.build()).build();
214 return sendMessage(msg, srpIdNumber, null);
217 private SrpIdNumber createUpdateMessageSync(final PcupdMessageBuilder pcupdMessageBuilder) {
218 final UpdatesBuilder updBuilder = new UpdatesBuilder();
219 // LSP mandatory in Upd
220 final Lsp lsp = new LspBuilder().setPlspId(PLSPID_ZERO).setSync(Boolean.TRUE).build();
221 // SRP Mandatory in Upd
222 final SrpBuilder srpBuilder = new SrpBuilder();
223 // not sue whether use 0 instead of nextRequest() or do not insert srp == SRP-ID-number = 0
224 srpBuilder.setOperationId(nextRequest());
225 final Srp srp = srpBuilder.build();
226 //ERO Mandatory in Upd
227 final PathBuilder pb = new PathBuilder();
228 pb.setEro(new EroBuilder().build());
230 updBuilder.setPath(pb.build());
231 updBuilder.setLsp(lsp).setSrp(srp).setPath(pb.build());
233 pcupdMessageBuilder.setUpdates(List.of(updBuilder.build()));
234 return srp.getOperationId();
238 private void markAllLspAsStale() {
239 staleLsps.addAll(lsps.keySet());
242 private boolean handleErrorMessage(final PcerrMessage message) {
243 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message
244 .PcerrMessage errMsg = message.getPcerrMessage();
245 if (errMsg.getErrorType() instanceof StatefulCase) {
246 final StatefulCase stat = (StatefulCase) errMsg.getErrorType();
247 for (final Srps srps : stat.getStateful().getSrps()) {
248 final SrpIdNumber id = srps.getSrp().getOperationId();
249 if (id.getValue().toJava() != 0) {
250 final PCEPRequest req = removeRequest(id);
252 req.done(OperationResults.createFailed(errMsg.getErrors()));
254 LOG.warn("Request ID {} not found in outstanding DB", id);
259 LOG.warn("Unhandled PCErr message {}.", errMsg);
265 private boolean isSolicited(final Srp srp, final Lsp lsp, final MessageContext ctx, final ReportedLspBuilder rlb) {
269 final SrpIdNumber id = srp.getOperationId();
270 if (id.getValue().toJava() == 0) {
273 switch (lsp.getOperational()) {
277 if (!isTriggeredSyncInProcess()) {
278 final PCEPRequest req = removeRequest(id);
280 LOG.debug("Request {} resulted in LSP operational state {}", id, lsp.getOperational());
281 rlb.setMetadata(req.getMetadata());
282 ctx.resolveRequest(req);
284 LOG.warn("Request ID {} not found in outstanding DB", id);
290 // These are transitive states, so we don't have to do anything, as they will be followed
300 private boolean manageNextReport(final Reports report, final MessageContext ctx) {
301 final Lsp lsp = report.getLsp();
302 final PlspId plspid = lsp.getPlspId();
303 final Srp srp = report.getSrp();
305 if (!lsp.getSync() && (plspid == null || plspid.getValue().toJava() == 0)) {
307 if (isTriggeredSyncInProcess()) {
311 final SrpIdNumber id = srp.getOperationId();
312 if (id.getValue().toJava() == 0) {
315 final PCEPRequest req = removeRequest(id);
316 ctx.resolveRequest(req);
318 stateSynchronizationAchieved(ctx);
321 final ReportedLspBuilder rlb = new ReportedLspBuilder();
322 boolean solicited = false;
323 solicited = isSolicited(srp, lsp, ctx, rlb);
325 // if remove flag is set in SRP object, remove the tunnel immediately
327 final Srp1 initiatedSrp = srp.augmentation(Srp1.class);
328 if (initiatedSrp != null && initiatedSrp.getRemove()) {
329 super.removeLsp(ctx, plspid);
333 rlb.setPath(BindingMap.of(buildPath(report, srp, lsp)));
335 String name = lookupLspName(plspid);
336 if (lsp.getTlvs() != null && lsp.getTlvs().getSymbolicPathName() != null) {
337 name = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(lsp.getTlvs().getSymbolicPathName().getPathName()
338 .getValue())).toString();
340 //get LspDB from LSP and write it to pcc's node
341 final LspDbVersion lspDbVersion = geLspDbVersionTlv(lsp);
342 if (lspDbVersion != null) {
343 updatePccNode(ctx, new PathComputationClientBuilder()
344 .addAugmentation(new PathComputationClient1Builder().setLspDbVersion(lspDbVersion).build()).build());
346 updateLsp(ctx, plspid, name, rlb, solicited, lsp.getRemove());
347 unmarkStaleLsp(plspid);
349 LOG.debug("LSP {} updated", lsp);
353 private static Path buildPath(final Reports report, final Srp srp, final Lsp lsp) {
354 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client
355 .attributes.path.computation.client.reported.lsp.PathBuilder pb = new org.opendaylight.yang.gen.v1
356 .urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation
357 .client.reported.lsp.PathBuilder();
358 if (report.getPath() != null) {
359 pb.fieldsFrom(report.getPath());
361 // LSP is mandatory (if there is none, parser will throw an exception)
362 // this is to ensure a path will be created at any rate
363 final Path1Builder p1Builder = new Path1Builder();
364 p1Builder.setLsp(report.getLsp());
365 final PathSetupType pst;
366 if (srp != null && srp.getTlvs() != null && srp.getTlvs().getPathSetupType() != null) {
367 pst = srp.getTlvs().getPathSetupType();
368 p1Builder.setPathSetupType(pst);
372 pb.addAugmentation(p1Builder.build());
373 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp
374 .object.lsp.Tlvs tlvs = report.getLsp().getTlvs();
376 if (tlvs.getLspIdentifiers() != null) {
377 pb.setLspId(tlvs.getLspIdentifiers().getLspId());
378 } else if (!PSTUtil.isDefaultPST(pst)) {
379 pb.setLspId(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820
380 .LspId(lsp.getPlspId().getValue()));
386 private boolean handlePcreqMessage(final PcreqMessage message) {
388 LOG.info("Start PcRequest Message handler");
391 /* Get a Path Computation to compute the Path from the Request */
392 // TODO: Adjust Junit Test to avoid this test
393 if (pceServerProvider == null) {
394 rep = createErrorMsg(PCEPErrors.RESOURCE_LIMIT_EXCEEDED, Uint32.ZERO);
395 sendMessage(rep, new SrpIdNumber(Uint32.ZERO), null);
398 PathComputation pathComputation = pceServerProvider.getPathComputation();
399 /* Reply with Error Message if no valid Path Computation is available */
400 if (pathComputation == null) {
401 rep = createErrorMsg(PCEPErrors.RESOURCE_LIMIT_EXCEEDED, Uint32.ZERO);
402 sendMessage(rep, new SrpIdNumber(Uint32.ZERO), null);
405 for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq
406 .message.Requests req : message.getRequests()) {
407 LOG.debug("Process request {}", req);
408 rep = pathComputation.computePath(req);
409 SrpIdNumber repId = null;
410 if (req.getRp() != null) {
411 repId = new SrpIdNumber(req.getRp().getRequestId().getValue());
413 repId = new SrpIdNumber(Uint32.ZERO);
415 sendMessage(rep, repId, null);
421 protected synchronized boolean onMessage(final MessageContext ctx, final Message message) {
422 if (message instanceof PcerrMessage) {
423 return handleErrorMessage((PcerrMessage) message);
425 if (message instanceof Pcreq) {
426 LOG.info("PcReq detected. Start Request Message handler");
427 return handlePcreqMessage(((Pcreq) message).getPcreqMessage());
429 if (!(message instanceof PcrptMessage)) {
432 listenerState.updateLastReceivedRptMsg();
433 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.pcrpt
434 .message.PcrptMessage rpt = ((PcrptMessage) message).getPcrptMessage();
435 for (final Reports report : rpt.getReports()) {
436 if (!manageNextReport(report, ctx)) {
443 private SrpIdNumber nextRequest() {
444 return new SrpIdNumber(Uint32.valueOf(requestId.getAndIncrement()));
448 @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
449 public synchronized ListenableFuture<OperationResult> addLsp(final AddLspArgs input) {
450 checkArgument(input != null && input.getName() != null && input.getNode() != null
451 && input.getArguments() != null, MISSING_XML_TAG);
452 LOG.trace("AddLspArgs {}", input);
453 // Make sure there is no such LSP
454 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
455 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
456 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
457 : Futures.transformAsync(f, new AddFunction(input, lsp), MoreExecutors.directExecutor());
461 @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
462 public synchronized ListenableFuture<OperationResult> removeLsp(final RemoveLspArgs input) {
463 checkArgument(input != null && input.getName() != null && input.getNode() != null, MISSING_XML_TAG);
464 LOG.trace("RemoveLspArgs {}", input);
465 // Make sure the LSP exists, we need it for PLSP-ID
466 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
467 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
468 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
469 : Futures.transformAsync(f, rep -> {
470 final Lsp reportedLsp = validateReportedLsp(rep, input);
471 if (reportedLsp == null) {
472 return OperationResults.createUnsent(PCEPErrors.UNKNOWN_PLSP_ID).future();
474 final PcinitiateMessageBuilder ib = new PcinitiateMessageBuilder(MESSAGE_HEADER);
475 final Requests rb = buildRequest(rep, reportedLsp);
476 ib.setRequests(List.of(rb));
477 return sendMessage(new PcinitiateBuilder().setPcinitiateMessage(ib.build()).build(),
478 rb.getSrp().getOperationId(), null);
479 }, MoreExecutors.directExecutor());
482 private Requests buildRequest(final Optional<ReportedLsp> rep, final Lsp reportedLsp) {
483 // Build the request and send it
484 final RequestsBuilder rb = new RequestsBuilder();
485 final SrpBuilder srpBuilder = new SrpBuilder().addAugmentation(new Srp1Builder()
486 .setRemove(Boolean.TRUE).build()).setOperationId(nextRequest()).setProcessingRule(Boolean.TRUE);
487 final Optional<PathSetupType> maybePST = getPST(rep);
488 if (maybePST.isPresent()) {
489 srpBuilder.setTlvs(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
490 .rev200720.srp.object.srp.TlvsBuilder().setPathSetupType(maybePST.get()).build());
492 rb.setSrp(srpBuilder.build());
493 rb.setLsp(new LspBuilder().setRemove(Boolean.FALSE).setPlspId(reportedLsp.getPlspId())
494 .setDelegate(reportedLsp.getDelegate()).build());
498 private ListenableFuture<OperationResult> redelegate(final Lsp reportedLsp, final Srp srp, final Lsp lsp,
499 final UpdateLspArgs input) {
500 // the D bit that was reported decides the type of PCE message sent
501 final boolean isDelegate = requireNonNull(reportedLsp.getDelegate());
504 // we already have delegation, send update
505 final UpdatesBuilder rb = new UpdatesBuilder();
508 final PathBuilder pb = new PathBuilder();
509 pb.fieldsFrom(input.getArguments());
510 rb.setPath(pb.build());
511 final PcupdMessageBuilder ub = new PcupdMessageBuilder(MESSAGE_HEADER);
512 ub.setUpdates(List.of(rb.build()));
513 msg = new PcupdBuilder().setPcupdMessage(ub.build()).build();
515 final Lsp1 lspCreateFlag = reportedLsp.augmentation(Lsp1.class);
516 // we only retake delegation for PCE initiated tunnels
517 if (lspCreateFlag != null && !lspCreateFlag.getCreate()) {
518 LOG.warn("Unable to retake delegation of PCC-initiated tunnel: {}", reportedLsp);
519 return OperationResults.createUnsent(PCEPErrors.UPDATE_REQ_FOR_NON_LSP).future();
521 // we want to revoke delegation, different type of message
522 // is sent because of specification by Siva
523 // this message is also sent, when input delegate bit is set to 0
524 // generating an error in PCC
525 final List<Requests> reqs = new ArrayList<>();
526 reqs.add(new RequestsBuilder().setSrp(srp).setLsp(lsp).build());
527 final PcinitiateMessageBuilder ib = new PcinitiateMessageBuilder();
528 ib.setRequests(reqs);
529 msg = new PcinitiateBuilder().setPcinitiateMessage(ib.build()).build();
531 return sendMessage(msg, srp.getOperationId(), input.getArguments().getMetadata());
535 @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
536 public synchronized ListenableFuture<OperationResult> updateLsp(final UpdateLspArgs input) {
537 checkArgument(input != null && input.getName() != null && input.getNode() != null
538 && input.getArguments() != null, MISSING_XML_TAG);
539 LOG.trace("UpdateLspArgs {}", input);
540 // Make sure the LSP exists
541 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
542 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
543 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
544 : Futures.transformAsync(f, new UpdateFunction(input), MoreExecutors.directExecutor());
548 public synchronized ListenableFuture<OperationResult> ensureLspOperational(final EnsureLspOperationalInput input) {
549 checkArgument(input != null && input.getName() != null && input.getNode() != null, MISSING_XML_TAG);
550 final Arguments args = input.getArguments();
551 checkArgument(args != null, MISSING_XML_TAG);
553 final OperationalStatus op;
554 final Arguments1 aa = args.augmentation(Arguments1.class);
556 op = aa.getOperational();
561 // Make sure the LSP exists
562 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
563 LOG.debug("Checking if LSP {} has operational state {}", lsp, op);
564 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
565 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
566 : listenableFuture(f, input, op);
569 private static ListenableFuture<OperationResult> listenableFuture(
570 final ListenableFuture<Optional<ReportedLsp>> future, final EnsureLspOperationalInput input,
571 final OperationalStatus op) {
572 return Futures.transform(future, rep -> {
573 if (!rep.isPresent()) {
574 LOG.debug("Node {} does not contain LSP {}", input.getNode(), input.getName());
575 return OperationResults.UNSENT;
577 // check if at least one of the paths has the same status as requested
578 for (final Path p : rep.get().nonnullPath().values()) {
579 final Path1 p1 = p.augmentation(Path1.class);
581 LOG.warn("Node {} LSP {} does not contain data", input.getNode(), input.getName());
582 return OperationResults.UNSENT;
584 if (op.equals(p1.getLsp().getOperational())) {
585 return OperationResults.SUCCESS;
588 return OperationResults.UNSENT;
589 }, MoreExecutors.directExecutor());
593 protected Lsp validateReportedLsp(final Optional<ReportedLsp> rep, final LspId input) {
594 if (!rep.isPresent()) {
595 LOG.debug("Node {} does not contain LSP {}", input.getNode(), input.getName());
598 // it doesn't matter how many lsps there are in the path list, we only need data that is the same in each path
599 final Path1 ra = rep.get().getPath().values().iterator().next().augmentation(Path1.class);
600 checkState(ra != null, "Reported LSP reported null from data-store.");
601 final Lsp reportedLsp = ra.getLsp();
602 checkState(reportedLsp != null, "Reported LSP does not contain LSP object.");
606 private static Optional<PathSetupType> getPST(final Optional<ReportedLsp> rep) {
607 if (rep.isPresent()) {
608 final Path1 path1 = rep.get().getPath().values().iterator().next().augmentation(Path1.class);
610 final PathSetupType pst = path1.getPathSetupType();
611 if (!PSTUtil.isDefaultPST(pst)) {
612 return Optional.of(pst);
616 return Optional.empty();
620 * Recover lspData and mark any LSPs in the LSP database that were previously reported by the PCC as stale.
623 protected synchronized void loadLspData(final Node node, final Map<String, ReportedLsp> lspData,
624 final Map<PlspId, String> lsps, final boolean incrementalSynchro) {
625 //load node's lsps from DS
626 final PathComputationClient pcc = node.augmentation(Node1.class).getPathComputationClient();
627 for (final ReportedLsp reportedLsp : pcc.nonnullReportedLsp().values()) {
628 final String lspName = reportedLsp.getName();
629 lspData.put(lspName, reportedLsp);
630 if (!reportedLsp.getPath().isEmpty()) {
631 final Path1 path1 = reportedLsp.getPath().values().iterator().next().augmentation(Path1.class);
633 final PlspId plspId = path1.getLsp().getPlspId();
634 if (!incrementalSynchro) {
635 staleLsps.add(plspId);
637 lsps.put(plspId, lspName);
644 * When the PCC reports an LSP during state synchronization, if the LSP already
645 * exists in the LSP database, the PCE MUST update the LSP database and
646 * clear the stale marker from the LSP.
650 private synchronized void unmarkStaleLsp(final PlspId plspId) {
651 staleLsps.remove(plspId);
655 * Purge any LSPs from the LSP database that are still marked as stale.
657 * @param ctx message context
659 private synchronized void purgeStaleLsps(final MessageContext ctx) {
660 for (final PlspId plspId : staleLsps) {
661 removeLsp(ctx, plspId);
667 public boolean isInitiationCapability() {
668 return initiationCapability.get();
672 public boolean isStatefulCapability() {
673 return statefulCapability.get();
677 public boolean isLspUpdateCapability() {
678 return lspUpdateCapability.get();
681 private synchronized void setStatefulCapabilities(final Stateful stateful) {
682 statefulCapability.set(true);
683 if (stateful.getLspUpdateCapability() != null) {
684 lspUpdateCapability.set(stateful.getLspUpdateCapability());
686 final Stateful1 stateful1 = stateful.augmentation(Stateful1.class);
687 if (stateful1 != null && stateful1.getInitiation() != null) {
688 initiationCapability.set(stateful1.getInitiation());
692 private class ResyncLspFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
694 private final TriggerSyncArgs input;
696 ResyncLspFunction(final TriggerSyncArgs input) {
701 public ListenableFuture<OperationResult> apply(final Optional<ReportedLsp> rep) {
702 final Lsp reportedLsp = validateReportedLsp(rep, input);
703 if (reportedLsp == null || !rep.isPresent()) {
704 return OperationResults.createUnsent(PCEPErrors.UNKNOWN_PLSP_ID).future();
707 final ReportedLsp staleLsp = rep.get();
708 if (!staleLsp.getPath().isEmpty()) {
709 final Path1 path1 = staleLsp.getPath().values().iterator().next().augmentation(Path1.class);
711 staleLsps.add(path1.getLsp().getPlspId());
714 updatePccState(PccSyncState.PcepTriggeredResync);
715 // create PCUpd with mandatory objects and LSP object set to 1
716 final SrpBuilder srpBuilder = new SrpBuilder();
717 srpBuilder.setOperationId(nextRequest());
718 srpBuilder.setProcessingRule(Boolean.TRUE);
720 final Optional<PathSetupType> maybePST = getPST(rep);
721 if (maybePST.isPresent()) {
723 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
724 .rev200720.srp.object.srp.TlvsBuilder()
725 .setPathSetupType(maybePST.get()).build());
728 final Srp srp = srpBuilder.build();
729 final Lsp lsp = new LspBuilder().setPlspId(reportedLsp.getPlspId()).setSync(Boolean.TRUE).build();
731 final Message msg = createPcepUpd(srp, lsp);
732 return sendMessage(msg, srp.getOperationId(), null);
735 private Message createPcepUpd(final Srp srp, final Lsp lsp) {
736 final UpdatesBuilder rb = new UpdatesBuilder();
739 final PathBuilder pb = new PathBuilder();
740 rb.setPath(pb.build());
741 final PcupdMessageBuilder ub = new PcupdMessageBuilder(MESSAGE_HEADER);
742 ub.setUpdates(List.of(rb.build()));
743 return new PcupdBuilder().setPcupdMessage(ub.build()).build();
747 private class AddFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
749 private final AddLspArgs input;
750 private final InstanceIdentifier<ReportedLsp> lsp;
752 AddFunction(final AddLspArgs input, final InstanceIdentifier<ReportedLsp> lsp) {
758 public ListenableFuture<OperationResult> apply(final Optional<ReportedLsp> rep) {
759 if (rep.isPresent()) {
760 LOG.debug("Node {} already contains lsp {} at {}", input.getNode(), input.getName(), lsp);
761 return OperationResults.createUnsent(PCEPErrors.USED_SYMBOLIC_PATH_NAME).future();
763 if (!initiationCapability.get()) {
764 return OperationResults.createUnsent(PCEPErrors.CAPABILITY_NOT_SUPPORTED).future();
768 final RequestsBuilder rb = new RequestsBuilder();
769 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120
770 .add.lsp.args.Arguments args = input.getArguments();
771 final Arguments2 args2 = args.augmentation(Arguments2.class);
772 final Lsp inputLsp = args2 != null ? args2.getLsp() : null;
773 if (inputLsp == null) {
774 return OperationResults.createUnsent(PCEPErrors.LSP_MISSING).future();
777 rb.fieldsFrom(input.getArguments());
779 boolean segmentRouting = !PSTUtil.isDefaultPST(args2.getPathSetupType());
781 /* Call Path Computation if an ERO was not provided */
782 if (rb.getEro() == null
783 || rb.getEro().getSubobject() == null
784 || rb.getEro().getSubobject().size() == 0) {
786 /* Get a Path Computation to compute the Path from the Arguments */
787 // TODO: Adjust Junit Test to avoid this test
788 if (pceServerProvider == null) {
789 return OperationResults.createUnsent(PCEPErrors.ERO_MISSING).future();
791 PathComputation pathComputation = pceServerProvider.getPathComputation();
792 if (pathComputation == null) {
793 return OperationResults.createUnsent(PCEPErrors.ERO_MISSING).future();
795 rb.setEro(pathComputation.computeEro(args.getEndpointsObj(), args.getBandwidth(),
796 args.getClassType(), args.getMetrics(), args.getXro(), args.getIro(), segmentRouting));
799 final TlvsBuilder tlvsBuilder;
800 if (inputLsp.getTlvs() != null) {
801 tlvsBuilder = new TlvsBuilder(inputLsp.getTlvs());
803 tlvsBuilder = new TlvsBuilder();
805 tlvsBuilder.setSymbolicPathName(
806 new SymbolicPathNameBuilder().setPathName(new SymbolicPathName(input.getName()
807 .getBytes(StandardCharsets.UTF_8))).build());
809 final SrpBuilder srpBuilder = new SrpBuilder()
810 .setOperationId(nextRequest())
811 .setProcessingRule(Boolean.TRUE);
812 if (segmentRouting) {
814 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf
815 .stateful.rev200720.srp.object.srp.TlvsBuilder()
816 .setPathSetupType(args2.getPathSetupType()).build());
818 rb.setSrp(srpBuilder.build());
820 rb.setLsp(new LspBuilder()
821 .setAdministrative(inputLsp.getAdministrative())
822 .setDelegate(inputLsp.getDelegate())
823 .setPlspId(PLSPID_ZERO)
824 .setTlvs(tlvsBuilder.build())
828 return sendMessage(new PcinitiateBuilder()
829 .setPcinitiateMessage(new PcinitiateMessageBuilder(MESSAGE_HEADER)
830 .setRequests(List.of(rb.build()))
833 rb.getSrp().getOperationId(), input.getArguments().getMetadata());
837 private class UpdateFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
839 private final UpdateLspArgs input;
841 UpdateFunction(final UpdateLspArgs input) {
846 public ListenableFuture<OperationResult> apply(final Optional<ReportedLsp> rep) {
847 final Lsp reportedLsp = validateReportedLsp(rep, input);
848 if (reportedLsp == null) {
849 return OperationResults.createUnsent(PCEPErrors.UNKNOWN_PLSP_ID).future();
851 // create mandatory objects
852 final Arguments3 args = input.getArguments().augmentation(Arguments3.class);
853 final SrpBuilder srpBuilder = new SrpBuilder();
854 srpBuilder.setOperationId(nextRequest());
855 srpBuilder.setProcessingRule(Boolean.TRUE);
856 if (args != null && args.getPathSetupType() != null) {
857 if (!PSTUtil.isDefaultPST(args.getPathSetupType())) {
859 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
860 .rev200720.srp.object.srp.TlvsBuilder()
861 .setPathSetupType(args.getPathSetupType()).build());
864 final Optional<PathSetupType> maybePST = getPST(rep);
865 if (maybePST.isPresent()) {
867 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
868 .rev200720.srp.object.srp.TlvsBuilder()
869 .setPathSetupType(maybePST.get()).build());
872 final Srp srp = srpBuilder.build();
873 final Lsp inputLsp = args != null ? args.getLsp() : null;
874 final LspBuilder lspBuilder = new LspBuilder().setPlspId(reportedLsp.getPlspId());
875 if (inputLsp != null) {
876 lspBuilder.setDelegate(Boolean.TRUE.equals(inputLsp.getDelegate()))
877 .setTlvs(inputLsp.getTlvs())
878 .setAdministrative(Boolean.TRUE.equals(inputLsp.getAdministrative()));
880 return redelegate(reportedLsp, srp, lspBuilder.build(), input);
884 private static Pcerr createErrorMsg(@NonNull final PCEPErrors pcepErrors, final Uint32 reqID) {
885 return new PcerrBuilder()
886 .setPcerrMessage(new PcerrMessageBuilder()
887 .setErrorType(new RequestCaseBuilder()
888 .setRequest(new RequestBuilder()
889 .setRps(List.of(new RpsBuilder()
890 .setRp(new RpBuilder()
891 .setProcessingRule(false)
893 .setRequestId(new RequestId(reqID))
898 .setErrors(List.of(new ErrorsBuilder()
899 .setErrorObject(new ErrorObjectBuilder()
900 .setType(pcepErrors.getErrorType())
901 .setValue(pcepErrors.getErrorValue())