2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.bgpcep.pcep.topology.provider;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static com.google.common.base.Preconditions.checkState;
12 import static java.util.Objects.requireNonNull;
14 import com.google.common.util.concurrent.AsyncFunction;
15 import com.google.common.util.concurrent.FluentFuture;
16 import com.google.common.util.concurrent.Futures;
17 import com.google.common.util.concurrent.ListenableFuture;
18 import com.google.common.util.concurrent.MoreExecutors;
19 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
20 import java.net.InetAddress;
21 import java.nio.ByteBuffer;
22 import java.nio.charset.StandardCharsets;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.List;
27 import java.util.Optional;
28 import java.util.concurrent.atomic.AtomicBoolean;
29 import java.util.concurrent.atomic.AtomicLong;
30 import org.checkerframework.checker.lock.qual.GuardedBy;
31 import org.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.PCEPSession;
35 import org.opendaylight.protocol.pcep.spi.PCEPErrors;
36 import org.opendaylight.protocol.pcep.spi.PSTUtil;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev181109.PathComputationClient1Builder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.sync.optimizations.rev181109.lsp.db.version.tlv.LspDbVersion;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev181109.Lsp1;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev181109.PcinitiateBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev181109.Srp1;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev181109.Srp1Builder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev181109.Stateful1;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev181109.pcinitiate.message.PcinitiateMessageBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev181109.pcinitiate.message.pcinitiate.message.Requests;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev181109.pcinitiate.message.pcinitiate.message.RequestsBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.Arguments1;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.Arguments2;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.Arguments3;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.OperationalStatus;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.Path1;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.Path1Builder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.PcrptMessage;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.PcupdBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.PlspId;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.SrpIdNumber;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.StatefulTlv1Builder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.SymbolicPathName;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.Tlvs1;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.lsp.object.Lsp;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.lsp.object.LspBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.lsp.object.lsp.TlvsBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.pcerr.pcerr.message.error.type.StatefulCase;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.pcerr.pcerr.message.error.type.stateful._case.stateful.Srps;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.pcrpt.message.pcrpt.message.Reports;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.pcupd.message.PcupdMessageBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.pcupd.message.pcupd.message.UpdatesBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.pcupd.message.pcupd.message.updates.PathBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.srp.object.Srp;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.srp.object.SrpBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.stateful.capability.tlv.Stateful;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.symbolic.path.name.tlv.SymbolicPathNameBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.Pcerr;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.PcerrBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev181109.Pcreq;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.Message;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.PcerrMessage;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.RequestId;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.explicit.route.object.EroBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.open.object.open.Tlvs;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.path.setup.type.tlv.PathSetupType;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcep.error.object.ErrorObjectBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.PcerrMessageBuilder;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.ErrorsBuilder;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.error.type.RequestCaseBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message.pcerr.message.error.type.request._case.RequestBuilder;
87 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;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.PcreqMessage;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.rp.object.RpBuilder;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.AddLspArgs;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.EnsureLspOperationalInput;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.LspId;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.Node1;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.OperationResult;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.PccSyncState;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.RemoveLspArgs;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.TriggerSyncArgs;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.UpdateLspArgs;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.ensure.lsp.operational.args.Arguments;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.PathComputationClient;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.PathComputationClientBuilder;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.ReportedLsp;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.ReportedLspBuilder;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.StatefulTlvBuilder;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.reported.lsp.Path;
106 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
107 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
108 import org.opendaylight.yangtools.yang.common.Uint32;
109 import org.slf4j.Logger;
110 import org.slf4j.LoggerFactory;
112 class PCEPTopologySessionListener extends AbstractTopologySessionListener<SrpIdNumber, PlspId> {
113 private static final Logger LOG = LoggerFactory.getLogger(PCEPTopologySessionListener.class);
114 private static final PlspId PLSPID_ZERO = new PlspId(Uint32.ZERO);
116 private final AtomicLong requestId = new AtomicLong(1L);
119 private final List<PlspId> staleLsps = new ArrayList<>();
121 private final AtomicBoolean statefulCapability = new AtomicBoolean(false);
122 private final AtomicBoolean lspUpdateCapability = new AtomicBoolean(false);
123 private final AtomicBoolean initiationCapability = new AtomicBoolean(false);
125 private final PceServerProvider pceServerProvider;
128 * Creates a new stateful topology session listener for given server session manager.
130 PCEPTopologySessionListener(final ServerSessionManager serverSessionManager) {
131 super(serverSessionManager);
132 this.pceServerProvider = serverSessionManager.getPCEPTopologyProviderDependencies().getPceServerProvider();
135 private static LspDbVersion geLspDbVersionTlv(final Lsp lsp) {
136 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.lsp.object
137 .lsp.Tlvs tlvs = lsp.getTlvs();
138 if (tlvs != null && tlvs.augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang
139 .controller.pcep.sync.optimizations.rev181109.Tlvs1.class) != null) {
140 return tlvs.augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller
141 .pcep.sync.optimizations.rev181109.Tlvs1.class).getLspDbVersion();
147 protected void onSessionUp(final PCEPSession session, final PathComputationClientBuilder pccBuilder) {
148 final InetAddress peerAddress = session.getRemoteAddress();
150 final Tlvs tlvs = session.getRemoteTlvs();
151 if (tlvs != null && tlvs.augmentation(Tlvs1.class) != null) {
152 final Stateful stateful = tlvs.augmentation(Tlvs1.class).getStateful();
153 if (stateful != null) {
154 setStatefulCapabilities(stateful);
155 pccBuilder.setReportedLsp(Collections.emptyMap());
156 if (isSynchronized()) {
157 pccBuilder.setStateSync(PccSyncState.Synchronized);
158 } else if (isTriggeredInitialSynchro()) {
159 pccBuilder.setStateSync(PccSyncState.TriggeredInitialSync);
160 } else if (isIncrementalSynchro()) {
161 pccBuilder.setStateSync(PccSyncState.IncrementalSync);
163 pccBuilder.setStateSync(PccSyncState.InitialResync);
165 pccBuilder.setStatefulTlv(new StatefulTlvBuilder().addAugmentation(
166 new StatefulTlv1Builder(tlvs.augmentation(Tlvs1.class)).build()).build());
168 LOG.debug("Peer {} does not advertise stateful TLV", peerAddress);
171 LOG.debug("Peer {} does not advertise stateful TLV", peerAddress);
176 public synchronized ListenableFuture<OperationResult> triggerSync(final TriggerSyncArgs input) {
177 if (isTriggeredInitialSynchro() && !isSynchronized()) {
178 return triggerSynchronization(input);
179 } else if (isSessionSynchronized() && isTriggeredReSyncEnabled()) {
180 checkArgument(input != null && input.getNode() != null, MISSING_XML_TAG);
181 return input.getName() == null ? triggerResyncronization(input) : triggerLspSyncronization(input);
183 return OperationResults.UNSENT.future();
186 private ListenableFuture<OperationResult> triggerLspSyncronization(final TriggerSyncArgs input) {
187 LOG.trace("Trigger Lsp Resynchronization {}", input);
189 // Make sure the LSP exists
190 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
191 final FluentFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
193 return OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future();
195 return Futures.transformAsync(f, new ResyncLspFunction(input), MoreExecutors.directExecutor());
198 private ListenableFuture<OperationResult> triggerResyncronization(final TriggerSyncArgs input) {
199 LOG.trace("Trigger Resynchronization {}", input);
201 updatePccState(PccSyncState.PcepTriggeredResync);
202 final PcupdMessageBuilder pcupdMessageBuilder = new PcupdMessageBuilder(MESSAGE_HEADER);
203 final SrpIdNumber srpIdNumber = createUpdateMessageSync(pcupdMessageBuilder);
204 final Message msg = new PcupdBuilder().setPcupdMessage(pcupdMessageBuilder.build()).build();
205 return sendMessage(msg, srpIdNumber, null);
208 private ListenableFuture<OperationResult> triggerSynchronization(final TriggerSyncArgs input) {
209 LOG.trace("Trigger Initial Synchronization {}", input);
210 final PcupdMessageBuilder pcupdMessageBuilder = new PcupdMessageBuilder(MESSAGE_HEADER);
211 final SrpIdNumber srpIdNumber = createUpdateMessageSync(pcupdMessageBuilder);
212 final Message msg = new PcupdBuilder().setPcupdMessage(pcupdMessageBuilder.build()).build();
213 return sendMessage(msg, srpIdNumber, null);
216 private SrpIdNumber createUpdateMessageSync(final PcupdMessageBuilder pcupdMessageBuilder) {
217 final UpdatesBuilder updBuilder = new UpdatesBuilder();
218 // LSP mandatory in Upd
219 final Lsp lsp = new LspBuilder().setPlspId(PLSPID_ZERO).setSync(Boolean.TRUE).build();
220 // SRP Mandatory in Upd
221 final SrpBuilder srpBuilder = new SrpBuilder();
222 // not sue whether use 0 instead of nextRequest() or do not insert srp == SRP-ID-number = 0
223 srpBuilder.setOperationId(nextRequest());
224 final Srp srp = srpBuilder.build();
225 //ERO Mandatory in Upd
226 final PathBuilder pb = new PathBuilder();
227 pb.setEro(new EroBuilder().build());
229 updBuilder.setPath(pb.build());
230 updBuilder.setLsp(lsp).setSrp(srp).setPath(pb.build());
232 pcupdMessageBuilder.setUpdates(Collections.singletonList(updBuilder.build()));
233 return srp.getOperationId();
236 private void markAllLspAsStale() {
237 this.staleLsps.addAll(this.lsps.keySet());
240 private boolean handleErrorMessage(final PcerrMessage message) {
241 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message
242 .PcerrMessage errMsg = message.getPcerrMessage();
243 if (errMsg.getErrorType() instanceof StatefulCase) {
244 final StatefulCase stat = (StatefulCase) errMsg.getErrorType();
245 for (final Srps srps : stat.getStateful().getSrps()) {
246 final SrpIdNumber id = srps.getSrp().getOperationId();
247 if (id.getValue().toJava() != 0) {
248 final PCEPRequest req = removeRequest(id);
250 req.done(OperationResults.createFailed(errMsg.getErrors()));
252 LOG.warn("Request ID {} not found in outstanding DB", id);
257 LOG.warn("Unhandled PCErr message {}.", errMsg);
263 private boolean isSolicited(final Srp srp, final Lsp lsp, final MessageContext ctx, final ReportedLspBuilder rlb) {
267 final SrpIdNumber id = srp.getOperationId();
268 if (id.getValue().toJava() == 0) {
271 switch (lsp.getOperational()) {
275 if (!isTriggeredSyncInProcess()) {
276 final PCEPRequest req = removeRequest(id);
278 LOG.debug("Request {} resulted in LSP operational state {}", id, lsp.getOperational());
279 rlb.setMetadata(req.getMetadata());
280 ctx.resolveRequest(req);
282 LOG.warn("Request ID {} not found in outstanding DB", id);
288 // These are transitive states, so we don't have to do anything, as they will be followed
297 private boolean manageNextReport(final Reports report, final MessageContext ctx) {
298 final Lsp lsp = report.getLsp();
299 final PlspId plspid = lsp.getPlspId();
300 final Srp srp = report.getSrp();
302 if (!lsp.isSync() && (plspid == null || plspid.getValue().toJava() == 0)) {
304 if (isTriggeredSyncInProcess()) {
308 final SrpIdNumber id = srp.getOperationId();
309 if (id.getValue().toJava() == 0) {
312 final PCEPRequest req = removeRequest(id);
313 ctx.resolveRequest(req);
315 stateSynchronizationAchieved(ctx);
318 final ReportedLspBuilder rlb = new ReportedLspBuilder();
319 boolean solicited = false;
320 solicited = isSolicited(srp, lsp, ctx, rlb);
322 // if remove flag is set in SRP object, remove the tunnel immediately
323 if (solicited && srp.augmentation(Srp1.class) != null) {
324 final Srp1 initiatedSrp = srp.augmentation(Srp1.class);
325 if (initiatedSrp.isRemove()) {
326 super.removeLsp(ctx, plspid);
330 rlb.setPath(Collections.singletonList(buildPath(report, srp, lsp)));
332 String name = lookupLspName(plspid);
333 if (lsp.getTlvs() != null && lsp.getTlvs().getSymbolicPathName() != null) {
334 name = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(lsp.getTlvs().getSymbolicPathName().getPathName()
335 .getValue())).toString();
337 //get LspDB from LSP and write it to pcc's node
338 final LspDbVersion lspDbVersion = geLspDbVersionTlv(lsp);
339 if (lspDbVersion != null) {
340 updatePccNode(ctx, new PathComputationClientBuilder()
341 .addAugmentation(new PathComputationClient1Builder().setLspDbVersion(lspDbVersion).build()).build());
343 updateLsp(ctx, plspid, name, rlb, solicited, lsp.isRemove());
344 unmarkStaleLsp(plspid);
346 LOG.debug("LSP {} updated", lsp);
350 private static Path buildPath(final Reports report, final Srp srp, final Lsp lsp) {
351 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client
352 .attributes.path.computation.client.reported.lsp.PathBuilder pb = new org.opendaylight.yang.gen.v1
353 .urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation
354 .client.reported.lsp.PathBuilder();
355 if (report.getPath() != null) {
356 pb.fieldsFrom(report.getPath());
358 // LSP is mandatory (if there is none, parser will throw an exception)
359 // this is to ensure a path will be created at any rate
360 final Path1Builder p1Builder = new Path1Builder();
361 p1Builder.setLsp(report.getLsp());
362 final PathSetupType pst;
363 if (srp != null && srp.getTlvs() != null && srp.getTlvs().getPathSetupType() != null) {
364 pst = srp.getTlvs().getPathSetupType();
365 p1Builder.setPathSetupType(pst);
369 pb.addAugmentation(p1Builder.build());
370 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.lsp
371 .object.lsp.Tlvs tlvs = report.getLsp().getTlvs();
373 if (tlvs.getLspIdentifiers() != null) {
374 pb.setLspId(tlvs.getLspIdentifiers().getLspId());
375 } else if (!PSTUtil.isDefaultPST(pst)) {
376 pb.setLspId(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820
377 .LspId(lsp.getPlspId().getValue()));
383 private boolean handlePcreqMessage(final PcreqMessage message) {
385 LOG.info("Start PcRequest Message handler");
387 /* Get a Path Computation to compute the Path from the Request */
388 PathComputation pathComputation = this.pceServerProvider.getPathComputation();
390 /* Reply with Error Message if no valid Path Computation is available */
391 if (pathComputation == null) {
392 rep = createErrorMsg(PCEPErrors.RESOURCE_LIMIT_EXCEEDED, Uint32.ZERO);
393 sendMessage(rep, new SrpIdNumber(Uint32.ZERO), null);
396 for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq
397 .message.Requests req : message.getRequests()) {
398 LOG.debug("Process request {}", req);
399 rep = pathComputation.computePath(req);
400 SrpIdNumber repId = null;
401 if (req.getRp() != null) {
402 repId = new SrpIdNumber(req.getRp().getRequestId().getValue());
404 repId = new SrpIdNumber(Uint32.ZERO);
406 sendMessage(rep, repId, null);
412 protected synchronized boolean onMessage(final MessageContext ctx, final Message message) {
413 if (message instanceof PcerrMessage) {
414 return handleErrorMessage((PcerrMessage) message);
416 if (message instanceof Pcreq) {
417 LOG.info("PcReq detected. Start Request Message handler");
418 return handlePcreqMessage(((Pcreq) message).getPcreqMessage());
420 if (!(message instanceof PcrptMessage)) {
423 this.listenerState.updateLastReceivedRptMsg();
424 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.pcrpt
425 .message.PcrptMessage rpt = ((PcrptMessage) message).getPcrptMessage();
426 for (final Reports report : rpt.getReports()) {
427 if (!manageNextReport(report, ctx)) {
434 private SrpIdNumber nextRequest() {
435 return new SrpIdNumber(Uint32.valueOf(this.requestId.getAndIncrement()));
439 @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
440 public synchronized ListenableFuture<OperationResult> addLsp(final AddLspArgs input) {
441 checkArgument(input != null && input.getName() != null && input.getNode() != null
442 && input.getArguments() != null, MISSING_XML_TAG);
443 LOG.trace("AddLspArgs {}", input);
444 // Make sure there is no such LSP
445 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
446 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
447 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
448 : Futures.transformAsync(f, new AddFunction(input, lsp), MoreExecutors.directExecutor());
452 @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
453 public synchronized ListenableFuture<OperationResult> removeLsp(final RemoveLspArgs input) {
454 checkArgument(input != null && input.getName() != null && input.getNode() != null, MISSING_XML_TAG);
455 LOG.trace("RemoveLspArgs {}", input);
456 // Make sure the LSP exists, we need it for PLSP-ID
457 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
458 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
459 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
460 : Futures.transformAsync(f, rep -> {
461 final Lsp reportedLsp = validateReportedLsp(rep, input);
462 if (reportedLsp == null) {
463 return OperationResults.createUnsent(PCEPErrors.UNKNOWN_PLSP_ID).future();
465 final PcinitiateMessageBuilder ib = new PcinitiateMessageBuilder(MESSAGE_HEADER);
466 final Requests rb = buildRequest(rep, reportedLsp);
467 ib.setRequests(Collections.singletonList(rb));
468 return sendMessage(new PcinitiateBuilder().setPcinitiateMessage(ib.build()).build(),
469 rb.getSrp().getOperationId(), null);
470 }, MoreExecutors.directExecutor());
473 private Requests buildRequest(final Optional<ReportedLsp> rep, final Lsp reportedLsp) {
474 // Build the request and send it
475 final RequestsBuilder rb = new RequestsBuilder();
476 final SrpBuilder srpBuilder = new SrpBuilder().addAugmentation(new Srp1Builder()
477 .setRemove(Boolean.TRUE).build()).setOperationId(nextRequest()).setProcessingRule(Boolean.TRUE);
478 final Optional<PathSetupType> maybePST = getPST(rep);
479 if (maybePST.isPresent()) {
480 srpBuilder.setTlvs(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
481 .rev181109.srp.object.srp.TlvsBuilder().setPathSetupType(maybePST.get()).build());
483 rb.setSrp(srpBuilder.build());
484 rb.setLsp(new LspBuilder().setRemove(Boolean.FALSE).setPlspId(reportedLsp.getPlspId())
485 .setDelegate(reportedLsp.isDelegate()).build());
489 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
490 justification = "https://github.com/spotbugs/spotbugs/issues/811")
491 private ListenableFuture<OperationResult> redelegate(final Lsp reportedLsp, final Srp srp, final Lsp lsp,
492 final UpdateLspArgs input) {
493 // the D bit that was reported decides the type of PCE message sent
494 requireNonNull(reportedLsp.isDelegate());
496 if (reportedLsp.isDelegate()) {
497 // we already have delegation, send update
498 final UpdatesBuilder rb = new UpdatesBuilder();
501 final PathBuilder pb = new PathBuilder();
502 pb.fieldsFrom(input.getArguments());
503 rb.setPath(pb.build());
504 final PcupdMessageBuilder ub = new PcupdMessageBuilder(MESSAGE_HEADER);
505 ub.setUpdates(Collections.singletonList(rb.build()));
506 msg = new PcupdBuilder().setPcupdMessage(ub.build()).build();
508 final Lsp1 lspCreateFlag = reportedLsp.augmentation(Lsp1.class);
509 // we only retake delegation for PCE initiated tunnels
510 if (lspCreateFlag != null && !lspCreateFlag.isCreate()) {
511 LOG.warn("Unable to retake delegation of PCC-initiated tunnel: {}", reportedLsp);
512 return OperationResults.createUnsent(PCEPErrors.UPDATE_REQ_FOR_NON_LSP).future();
514 // we want to revoke delegation, different type of message
515 // is sent because of specification by Siva
516 // this message is also sent, when input delegate bit is set to 0
517 // generating an error in PCC
518 final List<Requests> reqs = new ArrayList<>();
519 reqs.add(new RequestsBuilder().setSrp(srp).setLsp(lsp).build());
520 final PcinitiateMessageBuilder ib = new PcinitiateMessageBuilder();
521 ib.setRequests(reqs);
522 msg = new PcinitiateBuilder().setPcinitiateMessage(ib.build()).build();
524 return sendMessage(msg, srp.getOperationId(), input.getArguments().getMetadata());
528 @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
530 public synchronized ListenableFuture<OperationResult> updateLsp(final UpdateLspArgs input) {
531 checkArgument(input != null && input.getName() != null && input.getNode() != null
532 && input.getArguments() != null, MISSING_XML_TAG);
533 LOG.trace("UpdateLspArgs {}", input);
534 // Make sure the LSP exists
535 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
536 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
537 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
538 : Futures.transformAsync(f, new UpdateFunction(input), MoreExecutors.directExecutor());
542 public synchronized ListenableFuture<OperationResult> ensureLspOperational(final EnsureLspOperationalInput input) {
543 checkArgument(input != null && input.getName() != null && input.getNode() != null, MISSING_XML_TAG);
544 final Arguments args = input.getArguments();
545 checkArgument(args != null, MISSING_XML_TAG);
547 final OperationalStatus op;
548 final Arguments1 aa = args.augmentation(Arguments1.class);
550 op = aa.getOperational();
555 // Make sure the LSP exists
556 final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
557 LOG.debug("Checking if LSP {} has operational state {}", lsp, op);
558 final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
559 return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
560 : listenableFuture(f, input, op);
563 private static ListenableFuture<OperationResult> listenableFuture(
564 final ListenableFuture<Optional<ReportedLsp>> future, final EnsureLspOperationalInput input,
565 final OperationalStatus op) {
566 return Futures.transform(future, rep -> {
567 if (!rep.isPresent()) {
568 LOG.debug("Node {} does not contain LSP {}", input.getNode(), input.getName());
569 return OperationResults.UNSENT;
571 // check if at least one of the paths has the same status as requested
572 for (final Path p : rep.get().nonnullPath().values()) {
573 final Path1 p1 = p.augmentation(Path1.class);
575 LOG.warn("Node {} LSP {} does not contain data", input.getNode(), input.getName());
576 return OperationResults.UNSENT;
578 if (op.equals(p1.getLsp().getOperational())) {
579 return OperationResults.SUCCESS;
582 return OperationResults.UNSENT;
583 }, MoreExecutors.directExecutor());
587 protected Lsp validateReportedLsp(final Optional<ReportedLsp> rep, final LspId input) {
588 if (!rep.isPresent()) {
589 LOG.debug("Node {} does not contain LSP {}", input.getNode(), input.getName());
592 // it doesn't matter how many lsps there are in the path list, we only need data that is the same in each path
593 final Path1 ra = rep.get().getPath().values().iterator().next().augmentation(Path1.class);
594 checkState(ra != null, "Reported LSP reported null from data-store.");
595 final Lsp reportedLsp = ra.getLsp();
596 checkState(reportedLsp != null, "Reported LSP does not contain LSP object.");
600 private static Optional<PathSetupType> getPST(final Optional<ReportedLsp> rep) {
601 if (rep.isPresent()) {
602 final Path1 path1 = rep.get().getPath().values().iterator().next().augmentation(Path1.class);
604 final PathSetupType pst = path1.getPathSetupType();
605 if (!PSTUtil.isDefaultPST(pst)) {
606 return Optional.of(pst);
610 return Optional.empty();
614 * Recover lspData and mark any LSPs in the LSP database that were previously reported by the PCC as stale.
617 protected synchronized void loadLspData(final Node node, final Map<String, ReportedLsp> lspData,
618 final Map<PlspId, String> lsps, final boolean incrementalSynchro) {
619 //load node's lsps from DS
620 final PathComputationClient pcc = node.augmentation(Node1.class).getPathComputationClient();
621 for (final ReportedLsp reportedLsp : pcc.nonnullReportedLsp().values()) {
622 final String lspName = reportedLsp.getName();
623 lspData.put(lspName, reportedLsp);
624 if (!reportedLsp.getPath().isEmpty()) {
625 final Path1 path1 = reportedLsp.getPath().values().iterator().next().augmentation(Path1.class);
627 final PlspId plspId = path1.getLsp().getPlspId();
628 if (!incrementalSynchro) {
629 this.staleLsps.add(plspId);
631 lsps.put(plspId, lspName);
638 * When the PCC reports an LSP during state synchronization, if the LSP already
639 * exists in the LSP database, the PCE MUST update the LSP database and
640 * clear the stale marker from the LSP.
644 private synchronized void unmarkStaleLsp(final PlspId plspId) {
645 this.staleLsps.remove(plspId);
649 * Purge any LSPs from the LSP database that are still marked as stale.
651 * @param ctx message context
653 private synchronized void purgeStaleLsps(final MessageContext ctx) {
654 for (final PlspId plspId : this.staleLsps) {
655 removeLsp(ctx, plspId);
657 this.staleLsps.clear();
661 public boolean isInitiationCapability() {
662 return this.initiationCapability.get();
666 public boolean isStatefulCapability() {
667 return this.statefulCapability.get();
671 public boolean isLspUpdateCapability() {
672 return this.lspUpdateCapability.get();
675 private synchronized void setStatefulCapabilities(final Stateful stateful) {
676 this.statefulCapability.set(true);
677 if (stateful.isLspUpdateCapability() != null) {
678 this.lspUpdateCapability.set(stateful.isLspUpdateCapability());
680 final Stateful1 stateful1 = stateful.augmentation(Stateful1.class);
681 if (stateful1 != null && stateful1.isInitiation() != null) {
682 this.initiationCapability.set(stateful1.isInitiation());
686 private class ResyncLspFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
688 private final TriggerSyncArgs input;
690 ResyncLspFunction(final TriggerSyncArgs input) {
695 public ListenableFuture<OperationResult> apply(final Optional<ReportedLsp> rep) {
696 final Lsp reportedLsp = validateReportedLsp(rep, this.input);
697 if (reportedLsp == null || !rep.isPresent()) {
698 return OperationResults.createUnsent(PCEPErrors.UNKNOWN_PLSP_ID).future();
701 final ReportedLsp staleLsp = rep.get();
702 if (!staleLsp.getPath().isEmpty()) {
703 final Path1 path1 = staleLsp.getPath().values().iterator().next().augmentation(Path1.class);
705 PCEPTopologySessionListener.this.staleLsps.add(path1.getLsp().getPlspId());
708 updatePccState(PccSyncState.PcepTriggeredResync);
709 // create PCUpd with mandatory objects and LSP object set to 1
710 final SrpBuilder srpBuilder = new SrpBuilder();
711 srpBuilder.setOperationId(nextRequest());
712 srpBuilder.setProcessingRule(Boolean.TRUE);
714 final Optional<PathSetupType> maybePST = getPST(rep);
715 if (maybePST.isPresent()) {
717 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
718 .rev181109.srp.object.srp.TlvsBuilder()
719 .setPathSetupType(maybePST.get()).build());
722 final Srp srp = srpBuilder.build();
723 final Lsp lsp = new LspBuilder().setPlspId(reportedLsp.getPlspId()).setSync(Boolean.TRUE).build();
725 final Message msg = createPcepUpd(srp, lsp);
726 return sendMessage(msg, srp.getOperationId(), null);
729 private Message createPcepUpd(final Srp srp, final Lsp lsp) {
730 final UpdatesBuilder rb = new UpdatesBuilder();
733 final PathBuilder pb = new PathBuilder();
734 rb.setPath(pb.build());
735 final PcupdMessageBuilder ub = new PcupdMessageBuilder(MESSAGE_HEADER);
736 ub.setUpdates(Collections.singletonList(rb.build()));
737 return new PcupdBuilder().setPcupdMessage(ub.build()).build();
741 private class AddFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
743 private final AddLspArgs input;
744 private final InstanceIdentifier<ReportedLsp> lsp;
746 AddFunction(final AddLspArgs input, final InstanceIdentifier<ReportedLsp> lsp) {
752 public ListenableFuture<OperationResult> apply(final Optional<ReportedLsp> rep) {
753 if (rep.isPresent()) {
754 LOG.debug("Node {} already contains lsp {} at {}", this.input.getNode(), this.input.getName(),
756 return OperationResults.createUnsent(PCEPErrors.USED_SYMBOLIC_PATH_NAME).future();
758 if (!PCEPTopologySessionListener.this.initiationCapability.get()) {
759 return OperationResults.createUnsent(PCEPErrors.CAPABILITY_NOT_SUPPORTED).future();
763 final RequestsBuilder rb = new RequestsBuilder();
764 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120
765 .add.lsp.args.Arguments args = this.input.getArguments();
766 final Arguments2 args2 = args.augmentation(Arguments2.class);
767 final Lsp inputLsp = args2 != null ? args2.getLsp() : null;
768 if (inputLsp == null) {
769 return OperationResults.createUnsent(PCEPErrors.LSP_MISSING).future();
772 rb.fieldsFrom(this.input.getArguments());
774 /* Call Path Computation if an ERO was not provided */
775 boolean segmentRouting = !PSTUtil.isDefaultPST(args2.getPathSetupType());
776 if (rb.getEro() == null
777 || rb.getEro().getSubobject() == null
778 || rb.getEro().getSubobject().size() == 0) {
780 /* Get a Path Computation to compute the Path from the Arguments */
781 PathComputation pathComputation = pceServerProvider.getPathComputation();
782 if (pathComputation == null) {
783 return OperationResults.createUnsent(PCEPErrors.ERO_MISSING).future();
785 rb.setEro(pathComputation.computeEro(args.getEndpointsObj(), args.getBandwidth(), args.getClassType(),
786 args.getMetrics(), segmentRouting));
789 final TlvsBuilder tlvsBuilder;
790 if (inputLsp.getTlvs() != null) {
791 tlvsBuilder = new TlvsBuilder(inputLsp.getTlvs());
793 tlvsBuilder = new TlvsBuilder();
795 tlvsBuilder.setSymbolicPathName(
796 new SymbolicPathNameBuilder().setPathName(new SymbolicPathName(this.input.getName()
797 .getBytes(StandardCharsets.UTF_8))).build());
799 final SrpBuilder srpBuilder = new SrpBuilder()
800 .setOperationId(nextRequest())
801 .setProcessingRule(Boolean.TRUE);
802 if (segmentRouting) {
804 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf
805 .stateful.rev181109.srp.object.srp.TlvsBuilder()
806 .setPathSetupType(args2.getPathSetupType()).build());
808 rb.setSrp(srpBuilder.build());
810 rb.setLsp(new LspBuilder()
811 .setAdministrative(inputLsp.isAdministrative())
812 .setDelegate(inputLsp.isDelegate())
813 .setPlspId(PLSPID_ZERO)
814 .setTlvs(tlvsBuilder.build())
818 return sendMessage(new PcinitiateBuilder()
819 .setPcinitiateMessage(new PcinitiateMessageBuilder(MESSAGE_HEADER)
820 .setRequests(Collections.singletonList(rb.build()))
823 rb.getSrp().getOperationId(), this.input.getArguments().getMetadata());
827 private class UpdateFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
829 private final UpdateLspArgs input;
831 UpdateFunction(final UpdateLspArgs input) {
836 public ListenableFuture<OperationResult> apply(final Optional<ReportedLsp> rep) {
837 final Lsp reportedLsp = validateReportedLsp(rep, this.input);
838 if (reportedLsp == null) {
839 return OperationResults.createUnsent(PCEPErrors.UNKNOWN_PLSP_ID).future();
841 // create mandatory objects
842 final Arguments3 args = this.input.getArguments().augmentation(Arguments3.class);
843 final SrpBuilder srpBuilder = new SrpBuilder();
844 srpBuilder.setOperationId(nextRequest());
845 srpBuilder.setProcessingRule(Boolean.TRUE);
846 if (args != null && args.getPathSetupType() != null) {
847 if (!PSTUtil.isDefaultPST(args.getPathSetupType())) {
849 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
850 .rev181109.srp.object.srp.TlvsBuilder()
851 .setPathSetupType(args.getPathSetupType()).build());
854 final Optional<PathSetupType> maybePST = getPST(rep);
855 if (maybePST.isPresent()) {
857 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
858 .rev181109.srp.object.srp.TlvsBuilder()
859 .setPathSetupType(maybePST.get()).build());
862 final Srp srp = srpBuilder.build();
863 final Lsp inputLsp = args != null ? args.getLsp() : null;
864 final LspBuilder lspBuilder = new LspBuilder().setPlspId(reportedLsp.getPlspId());
865 if (inputLsp != null) {
866 lspBuilder.setDelegate(inputLsp.isDelegate() != null && inputLsp.isDelegate())
867 .setTlvs(inputLsp.getTlvs())
868 .setAdministrative(inputLsp.isAdministrative() != null && inputLsp.isAdministrative());
870 return redelegate(reportedLsp, srp, lspBuilder.build(), this.input);
874 private static Pcerr createErrorMsg(@NonNull final PCEPErrors pcepErrors, final Uint32 reqID) {
875 return new PcerrBuilder()
876 .setPcerrMessage(new PcerrMessageBuilder()
877 .setErrorType(new RequestCaseBuilder()
878 .setRequest(new RequestBuilder()
879 .setRps(Collections.singletonList(new RpsBuilder()
880 .setRp(new RpBuilder()
881 .setProcessingRule(false)
883 .setRequestId(new RequestId(reqID))
888 .setErrors(Collections.singletonList(new ErrorsBuilder()
889 .setErrorObject(new ErrorObjectBuilder()
890 .setType(pcepErrors.getErrorType())
891 .setValue(pcepErrors.getErrorValue())