Update MRI projects for Aluminium
[bgpcep.git] / pcep / topology / topology-provider / src / main / java / org / opendaylight / bgpcep / pcep / topology / provider / Stateful07TopologySessionListener.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.bgpcep.pcep.topology.provider;
9
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;
13
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;
26 import java.util.Map;
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.opendaylight.bgpcep.pcep.server.PathComputation;
32 import org.opendaylight.bgpcep.pcep.server.PceServerProvider;
33 import org.opendaylight.protocol.pcep.PCEPSession;
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.rev181109.PathComputationClient1;
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.crabbe.initiated.rev181109.Lsp1;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev181109.PcinitiateBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev181109.Srp1;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev181109.Srp1Builder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev181109.Stateful1;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev181109.pcinitiate.message.PcinitiateMessageBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev181109.pcinitiate.message.pcinitiate.message.Requests;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.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.StatefulTlv1;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.StatefulTlv1Builder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.SymbolicPathName;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.Tlvs1;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.lsp.object.Lsp;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.lsp.object.LspBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.lsp.object.lsp.TlvsBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.pcerr.pcerr.message.error.type.StatefulCase;
65 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;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.pcrpt.message.pcrpt.message.Reports;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.pcupd.message.PcupdMessageBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.pcupd.message.pcupd.message.UpdatesBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.pcupd.message.pcupd.message.updates.PathBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.srp.object.Srp;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.srp.object.SrpBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.stateful.capability.tlv.Stateful;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.symbolic.path.name.tlv.SymbolicPathNameBuilder;
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.explicit.route.object.EroBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.open.object.open.Tlvs;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.path.setup.type.tlv.PathSetupType;
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.topology.pcep.rev200120.AddLspArgs;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.EnsureLspOperationalInput;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.LspId;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.Node1;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.OperationResult;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.PccSyncState;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.RemoveLspArgs;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.TriggerSyncArgs;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.UpdateLspArgs;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.ensure.lsp.operational.args.Arguments;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.PathComputationClient;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.PathComputationClientBuilder;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.ReportedLsp;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.ReportedLspBuilder;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.StatefulTlvBuilder;
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.common.Uint32;
100 import org.slf4j.Logger;
101 import org.slf4j.LoggerFactory;
102
103 class Stateful07TopologySessionListener extends AbstractTopologySessionListener<SrpIdNumber, PlspId> {
104     private static final Logger LOG = LoggerFactory.getLogger(Stateful07TopologySessionListener.class);
105     private static final PlspId PLSPID_ZERO = new PlspId(Uint32.ZERO);
106
107     private final AtomicLong requestId = new AtomicLong(1L);
108
109     @GuardedBy("this")
110     private final List<PlspId> staleLsps = new ArrayList<>();
111
112     private final AtomicBoolean statefulCapability = new AtomicBoolean(false);
113     private final AtomicBoolean lspUpdateCapability = new AtomicBoolean(false);
114     private final AtomicBoolean initiationCapability = new AtomicBoolean(false);
115
116     private final PceServerProvider pceServerProvider;
117
118     /**
119      * Creates a new stateful topology session listener for given server session manager.
120      */
121     Stateful07TopologySessionListener(final ServerSessionManager serverSessionManager) {
122         super(serverSessionManager);
123         this.pceServerProvider = serverSessionManager.getPCEPTopologyProviderDependencies().getPceServerProvider();
124     }
125
126     private static LspDbVersion geLspDbVersionTlv(final Lsp lsp) {
127         final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.lsp.object
128                 .lsp.Tlvs tlvs = lsp.getTlvs();
129         if (tlvs != null && tlvs.augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang
130                 .controller.pcep.sync.optimizations.rev181109.Tlvs1.class) != null) {
131             return tlvs.augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller
132                     .pcep.sync.optimizations.rev181109.Tlvs1.class).getLspDbVersion();
133         }
134         return null;
135     }
136
137     @Override
138     protected void onSessionUp(final PCEPSession session, final PathComputationClientBuilder pccBuilder) {
139         final InetAddress peerAddress = session.getRemoteAddress();
140
141         final Tlvs tlvs = session.getRemoteTlvs();
142         if (tlvs != null && tlvs.augmentation(Tlvs1.class) != null) {
143             final Stateful stateful = tlvs.augmentation(Tlvs1.class).getStateful();
144             if (stateful != null) {
145                 setStatefulCapabilities(stateful);
146                 pccBuilder.setReportedLsp(Collections.emptyList());
147                 if (isSynchronized()) {
148                     pccBuilder.setStateSync(PccSyncState.Synchronized);
149                 } else if (isTriggeredInitialSynchro()) {
150                     pccBuilder.setStateSync(PccSyncState.TriggeredInitialSync);
151                 } else if (isIncrementalSynchro()) {
152                     pccBuilder.setStateSync(PccSyncState.IncrementalSync);
153                 } else {
154                     pccBuilder.setStateSync(PccSyncState.InitialResync);
155                 }
156                 pccBuilder.setStatefulTlv(new StatefulTlvBuilder().addAugmentation(StatefulTlv1.class,
157                         new StatefulTlv1Builder(tlvs.augmentation(Tlvs1.class)).build()).build());
158             } else {
159                 LOG.debug("Peer {} does not advertise stateful TLV", peerAddress);
160             }
161         } else {
162             LOG.debug("Peer {} does not advertise stateful TLV", peerAddress);
163         }
164     }
165
166     @Override
167     public synchronized ListenableFuture<OperationResult> triggerSync(final TriggerSyncArgs input) {
168         if (isTriggeredInitialSynchro() && !isSynchronized()) {
169             return triggerSynchronization(input);
170         } else if (isSessionSynchronized() && isTriggeredReSyncEnabled()) {
171             checkArgument(input != null && input.getNode() != null, MISSING_XML_TAG);
172             return input.getName() == null ? triggerResyncronization(input) : triggerLspSyncronization(input);
173         }
174         return OperationResults.UNSENT.future();
175     }
176
177     private ListenableFuture<OperationResult> triggerLspSyncronization(final TriggerSyncArgs input) {
178         LOG.trace("Trigger Lsp Resynchronization {}", input);
179
180         // Make sure the LSP exists
181         final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
182         final FluentFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
183         if (f == null) {
184             return OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future();
185         }
186         return Futures.transformAsync(f, new ResyncLspFunction(input), MoreExecutors.directExecutor());
187     }
188
189     private ListenableFuture<OperationResult> triggerResyncronization(final TriggerSyncArgs input) {
190         LOG.trace("Trigger Resynchronization {}", input);
191         markAllLspAsStale();
192         updatePccState(PccSyncState.PcepTriggeredResync);
193         final PcupdMessageBuilder pcupdMessageBuilder = new PcupdMessageBuilder(MESSAGE_HEADER);
194         final SrpIdNumber srpIdNumber = createUpdateMessageSync(pcupdMessageBuilder);
195         final Message msg = new PcupdBuilder().setPcupdMessage(pcupdMessageBuilder.build()).build();
196         return sendMessage(msg, srpIdNumber, null);
197     }
198
199     private ListenableFuture<OperationResult> triggerSynchronization(final TriggerSyncArgs input) {
200         LOG.trace("Trigger Initial Synchronization {}", input);
201         final PcupdMessageBuilder pcupdMessageBuilder = new PcupdMessageBuilder(MESSAGE_HEADER);
202         final SrpIdNumber srpIdNumber = createUpdateMessageSync(pcupdMessageBuilder);
203         final Message msg = new PcupdBuilder().setPcupdMessage(pcupdMessageBuilder.build()).build();
204         return sendMessage(msg, srpIdNumber, null);
205     }
206
207     private SrpIdNumber createUpdateMessageSync(final PcupdMessageBuilder pcupdMessageBuilder) {
208         final UpdatesBuilder updBuilder = new UpdatesBuilder();
209         // LSP mandatory in Upd
210         final Lsp lsp = new LspBuilder().setPlspId(PLSPID_ZERO).setSync(Boolean.TRUE).build();
211         // SRP Mandatory in Upd
212         final SrpBuilder srpBuilder = new SrpBuilder();
213         // not sue whether use 0 instead of nextRequest() or do not insert srp == SRP-ID-number = 0
214         srpBuilder.setOperationId(nextRequest());
215         final Srp srp = srpBuilder.build();
216         //ERO Mandatory in Upd
217         final PathBuilder pb = new PathBuilder();
218         pb.setEro(new EroBuilder().build());
219
220         updBuilder.setPath(pb.build());
221         updBuilder.setLsp(lsp).setSrp(srp).setPath(pb.build());
222
223         pcupdMessageBuilder.setUpdates(Collections.singletonList(updBuilder.build()));
224         return srp.getOperationId();
225     }
226
227     private void markAllLspAsStale() {
228         this.staleLsps.addAll(this.lsps.keySet());
229     }
230
231     private boolean handleErrorMessage(final PcerrMessage message) {
232         final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcerr.message
233                 .PcerrMessage errMsg = message.getPcerrMessage();
234         if (errMsg.getErrorType() instanceof StatefulCase) {
235             final StatefulCase stat = (StatefulCase) errMsg.getErrorType();
236             for (final Srps srps : stat.getStateful().getSrps()) {
237                 final SrpIdNumber id = srps.getSrp().getOperationId();
238                 if (id.getValue().toJava() != 0) {
239                     final PCEPRequest req = removeRequest(id);
240                     if (req != null) {
241                         req.done(OperationResults.createFailed(errMsg.getErrors()));
242                     } else {
243                         LOG.warn("Request ID {} not found in outstanding DB", id);
244                     }
245                 }
246             }
247         } else {
248             LOG.warn("Unhandled PCErr message {}.", errMsg);
249             return true;
250         }
251         return false;
252     }
253
254     private boolean isSolicited(final Srp srp, final Lsp lsp, final MessageContext ctx, final ReportedLspBuilder rlb) {
255         if (srp == null) {
256             return false;
257         }
258         final SrpIdNumber id = srp.getOperationId();
259         if (id.getValue().toJava() == 0) {
260             return false;
261         }
262         switch (lsp.getOperational()) {
263             case Active:
264             case Down:
265             case Up:
266                 if (!isTriggeredSyncInProcess()) {
267                     final PCEPRequest req = removeRequest(id);
268                     if (req != null) {
269                         LOG.debug("Request {} resulted in LSP operational state {}", id, lsp.getOperational());
270                         rlb.setMetadata(req.getMetadata());
271                         ctx.resolveRequest(req);
272                     } else {
273                         LOG.warn("Request ID {} not found in outstanding DB", id);
274                     }
275                 }
276                 break;
277             case GoingDown:
278             case GoingUp:
279                 // These are transitive states, so we don't have to do anything, as they will be followed
280                 // up...
281                 break;
282             default:
283                 break;
284         }
285         return true;
286     }
287
288     private boolean manageNextReport(final Reports report, final MessageContext ctx) {
289         final Lsp lsp = report.getLsp();
290         final PlspId plspid = lsp.getPlspId();
291         final Srp srp = report.getSrp();
292
293         if (!lsp.isSync() && (plspid == null || plspid.getValue().toJava() == 0)) {
294             purgeStaleLsps(ctx);
295             if (isTriggeredSyncInProcess()) {
296                 if (srp == null) {
297                     return false;
298                 }
299                 final SrpIdNumber id = srp.getOperationId();
300                 if (id.getValue().toJava() == 0) {
301                     return false;
302                 }
303                 final PCEPRequest req = removeRequest(id);
304                 ctx.resolveRequest(req);
305             }
306             stateSynchronizationAchieved(ctx);
307             return true;
308         }
309         final ReportedLspBuilder rlb = new ReportedLspBuilder();
310         boolean solicited = false;
311         solicited = isSolicited(srp, lsp, ctx, rlb);
312
313         // if remove flag is set in SRP object, remove the tunnel immediately
314         if (solicited && srp.augmentation(Srp1.class) != null) {
315             final Srp1 initiatedSrp = srp.augmentation(Srp1.class);
316             if (initiatedSrp.isRemove()) {
317                 super.removeLsp(ctx, plspid);
318                 return false;
319             }
320         }
321         rlb.setPath(Collections.singletonList(buildPath(report, srp, lsp)));
322
323         String name = lookupLspName(plspid);
324         if (lsp.getTlvs() != null && lsp.getTlvs().getSymbolicPathName() != null) {
325             name = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(lsp.getTlvs().getSymbolicPathName().getPathName()
326                     .getValue())).toString();
327         }
328         //get LspDB from LSP and write it to pcc's node
329         final LspDbVersion lspDbVersion = geLspDbVersionTlv(lsp);
330         if (lspDbVersion != null) {
331             updatePccNode(ctx, new PathComputationClientBuilder().addAugmentation(PathComputationClient1.class,
332                     new PathComputationClient1Builder().setLspDbVersion(lspDbVersion).build()).build());
333         }
334         updateLsp(ctx, plspid, name, rlb, solicited, lsp.isRemove());
335         unmarkStaleLsp(plspid);
336
337         LOG.debug("LSP {} updated", lsp);
338         return true;
339     }
340
341     private static Path buildPath(final Reports report, final Srp srp, final Lsp lsp) {
342         final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client
343                 .attributes.path.computation.client.reported.lsp.PathBuilder pb = new org.opendaylight.yang.gen.v1
344                 .urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation
345                 .client.reported.lsp.PathBuilder();
346         if (report.getPath() != null) {
347             pb.fieldsFrom(report.getPath());
348         }
349         // LSP is mandatory (if there is none, parser will throw an exception)
350         // this is to ensure a path will be created at any rate
351         final Path1Builder p1Builder = new Path1Builder();
352         p1Builder.setLsp(report.getLsp());
353         final PathSetupType pst;
354         if (srp != null && srp.getTlvs() != null && srp.getTlvs().getPathSetupType() != null) {
355             pst = srp.getTlvs().getPathSetupType();
356             p1Builder.setPathSetupType(pst);
357         } else {
358             pst = null;
359         }
360         pb.addAugmentation(Path1.class, p1Builder.build());
361         final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.lsp
362                 .object.lsp.Tlvs tlvs = report.getLsp().getTlvs();
363         if (tlvs != null) {
364             if (tlvs.getLspIdentifiers() != null) {
365                 pb.setLspId(tlvs.getLspIdentifiers().getLspId());
366             } else if (!PSTUtil.isDefaultPST(pst)) {
367                 pb.setLspId(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820
368                         .LspId(lsp.getPlspId().getValue()));
369             }
370         }
371         return pb.build();
372     }
373
374     private boolean handlePcreqMessage(final PcreqMessage message) {
375
376         LOG.info("Start PcRequest Message handler");
377
378         /* Get a Path Computation to compute the Path from the Request */
379         PathComputation pathComputation = this.pceServerProvider.getPathComputation();
380         Message rep = null;
381         for (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.pcreq.message.pcreq
382                 .message.Requests req : message.getRequests()) {
383             LOG.debug("Process request {}", req);
384             rep = pathComputation.computePath(req);
385             SrpIdNumber repId = null;
386             if (req.getRp() != null) {
387                 repId = new SrpIdNumber(req.getRp().getRequestId().getValue());
388             } else {
389                 repId = new SrpIdNumber(Uint32.ZERO);
390             }
391             sendMessage(rep, repId, null);
392         }
393         return false;
394     }
395
396     @Override
397     protected synchronized boolean onMessage(final MessageContext ctx, final Message message) {
398         if (message instanceof PcerrMessage) {
399             return handleErrorMessage((PcerrMessage) message);
400         }
401         if (message instanceof Pcreq) {
402             LOG.info("PcReq detected. Start Request Message handler");
403             return handlePcreqMessage(((Pcreq) message).getPcreqMessage());
404         }
405         if (!(message instanceof PcrptMessage)) {
406             return true;
407         }
408         this.listenerState.updateLastReceivedRptMsg();
409         final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev181109.pcrpt
410                 .message.PcrptMessage rpt = ((PcrptMessage) message).getPcrptMessage();
411         for (final Reports report : rpt.getReports()) {
412             if (!manageNextReport(report, ctx)) {
413                 return false;
414             }
415         }
416         return false;
417     }
418
419     private SrpIdNumber nextRequest() {
420         return new SrpIdNumber(Uint32.valueOf(this.requestId.getAndIncrement()));
421     }
422
423     @Override
424     @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
425     public synchronized ListenableFuture<OperationResult> addLsp(final AddLspArgs input) {
426         checkArgument(input != null && input.getName() != null && input.getNode() != null
427                 && input.getArguments() != null, MISSING_XML_TAG);
428         LOG.trace("AddLspArgs {}", input);
429         // Make sure there is no such LSP
430         final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
431         final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
432         return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
433                 : Futures.transformAsync(f, new AddFunction(input, lsp), MoreExecutors.directExecutor());
434     }
435
436     @Override
437     @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
438     public synchronized ListenableFuture<OperationResult> removeLsp(final RemoveLspArgs input) {
439         checkArgument(input != null && input.getName() != null && input.getNode() != null, MISSING_XML_TAG);
440         LOG.trace("RemoveLspArgs {}", input);
441         // Make sure the LSP exists, we need it for PLSP-ID
442         final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
443         final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
444         return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
445                 : Futures.transformAsync(f, rep -> {
446                     final Lsp reportedLsp = validateReportedLsp(rep, input);
447                     if (reportedLsp == null) {
448                         return OperationResults.createUnsent(PCEPErrors.UNKNOWN_PLSP_ID).future();
449                     }
450                     final PcinitiateMessageBuilder ib = new PcinitiateMessageBuilder(MESSAGE_HEADER);
451                     final Requests rb = buildRequest(rep, reportedLsp);
452                     ib.setRequests(Collections.singletonList(rb));
453                     return sendMessage(new PcinitiateBuilder().setPcinitiateMessage(ib.build()).build(),
454                         rb.getSrp().getOperationId(), null);
455                 }, MoreExecutors.directExecutor());
456     }
457
458     private Requests buildRequest(final Optional<ReportedLsp> rep, final Lsp reportedLsp) {
459         // Build the request and send it
460         final RequestsBuilder rb = new RequestsBuilder();
461         final SrpBuilder srpBuilder = new SrpBuilder().addAugmentation(Srp1.class, new Srp1Builder()
462                 .setRemove(Boolean.TRUE).build()).setOperationId(nextRequest()).setProcessingRule(Boolean.TRUE);
463         final Optional<PathSetupType> maybePST = getPST(rep);
464         if (maybePST.isPresent()) {
465             srpBuilder.setTlvs(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
466                     .rev181109.srp.object.srp.TlvsBuilder().setPathSetupType(maybePST.get()).build());
467         }
468         rb.setSrp(srpBuilder.build());
469         rb.setLsp(new LspBuilder().setRemove(Boolean.FALSE).setPlspId(reportedLsp.getPlspId())
470                 .setDelegate(reportedLsp.isDelegate()).build());
471         return rb.build();
472     }
473
474     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
475             justification = "https://github.com/spotbugs/spotbugs/issues/811")
476     private ListenableFuture<OperationResult> redelegate(final Lsp reportedLsp, final Srp srp, final Lsp lsp,
477             final UpdateLspArgs input) {
478         // the D bit that was reported decides the type of PCE message sent
479         requireNonNull(reportedLsp.isDelegate());
480         final Message msg;
481         if (reportedLsp.isDelegate()) {
482             // we already have delegation, send update
483             final UpdatesBuilder rb = new UpdatesBuilder();
484             rb.setSrp(srp);
485             rb.setLsp(lsp);
486             final PathBuilder pb = new PathBuilder();
487             pb.fieldsFrom(input.getArguments());
488             rb.setPath(pb.build());
489             final PcupdMessageBuilder ub = new PcupdMessageBuilder(MESSAGE_HEADER);
490             ub.setUpdates(Collections.singletonList(rb.build()));
491             msg = new PcupdBuilder().setPcupdMessage(ub.build()).build();
492         } else {
493             final Lsp1 lspCreateFlag = reportedLsp.augmentation(Lsp1.class);
494             // we only retake delegation for PCE initiated tunnels
495             if (lspCreateFlag != null && !lspCreateFlag.isCreate()) {
496                 LOG.warn("Unable to retake delegation of PCC-initiated tunnel: {}", reportedLsp);
497                 return OperationResults.createUnsent(PCEPErrors.UPDATE_REQ_FOR_NON_LSP).future();
498             }
499             // we want to revoke delegation, different type of message
500             // is sent because of specification by Siva
501             // this message is also sent, when input delegate bit is set to 0
502             // generating an error in PCC
503             final List<Requests> reqs = new ArrayList<>();
504             reqs.add(new RequestsBuilder().setSrp(srp).setLsp(lsp).build());
505             final PcinitiateMessageBuilder ib = new PcinitiateMessageBuilder();
506             ib.setRequests(reqs);
507             msg = new PcinitiateBuilder().setPcinitiateMessage(ib.build()).build();
508         }
509         return sendMessage(msg, srp.getOperationId(), input.getArguments().getMetadata());
510     }
511
512     @Override
513     @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
514
515     public synchronized ListenableFuture<OperationResult> updateLsp(final UpdateLspArgs input) {
516         checkArgument(input != null && input.getName() != null && input.getNode() != null
517                 && input.getArguments() != null, MISSING_XML_TAG);
518         LOG.trace("UpdateLspArgs {}", input);
519         // Make sure the LSP exists
520         final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
521         final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
522         return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
523                 : Futures.transformAsync(f, new UpdateFunction(input), MoreExecutors.directExecutor());
524     }
525
526     @Override
527     public synchronized ListenableFuture<OperationResult> ensureLspOperational(final EnsureLspOperationalInput input) {
528         checkArgument(input != null && input.getName() != null && input.getNode() != null, MISSING_XML_TAG);
529         final Arguments args = input.getArguments();
530         checkArgument(args != null, MISSING_XML_TAG);
531
532         final OperationalStatus op;
533         final Arguments1 aa = args.augmentation(Arguments1.class);
534         if (aa != null) {
535             op = aa.getOperational();
536         } else {
537             op = null;
538         }
539
540         // Make sure the LSP exists
541         final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
542         LOG.debug("Checking if LSP {} has operational state {}", lsp, op);
543         final ListenableFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
544         return f == null ? OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future()
545                 : listenableFuture(f, input, op);
546     }
547
548     private static ListenableFuture<OperationResult> listenableFuture(
549             final ListenableFuture<Optional<ReportedLsp>> future, final EnsureLspOperationalInput input,
550             final OperationalStatus op) {
551         return Futures.transform(future, rep -> {
552             if (!rep.isPresent()) {
553                 LOG.debug("Node {} does not contain LSP {}", input.getNode(), input.getName());
554                 return OperationResults.UNSENT;
555             }
556             // check if at least one of the paths has the same status as requested
557             for (final Path p : rep.get().nonnullPath().values()) {
558                 final Path1 p1 = p.augmentation(Path1.class);
559                 if (p1 == null) {
560                     LOG.warn("Node {} LSP {} does not contain data", input.getNode(), input.getName());
561                     return OperationResults.UNSENT;
562                 }
563                 if (op.equals(p1.getLsp().getOperational())) {
564                     return OperationResults.SUCCESS;
565                 }
566             }
567             return OperationResults.UNSENT;
568         }, MoreExecutors.directExecutor());
569     }
570
571     @Override
572     protected Lsp validateReportedLsp(final Optional<ReportedLsp> rep, final LspId input) {
573         if (!rep.isPresent()) {
574             LOG.debug("Node {} does not contain LSP {}", input.getNode(), input.getName());
575             return null;
576         }
577         // it doesn't matter how many lsps there are in the path list, we only need data that is the same in each path
578         final Path1 ra = rep.get().getPath().values().iterator().next().augmentation(Path1.class);
579         checkState(ra != null, "Reported LSP reported null from data-store.");
580         final Lsp reportedLsp = ra.getLsp();
581         checkState(reportedLsp != null, "Reported LSP does not contain LSP object.");
582         return reportedLsp;
583     }
584
585     private static Optional<PathSetupType> getPST(final Optional<ReportedLsp> rep) {
586         if (rep.isPresent()) {
587             final Path1 path1 = rep.get().getPath().values().iterator().next().augmentation(Path1.class);
588             if (path1 != null) {
589                 final PathSetupType pst = path1.getPathSetupType();
590                 if (!PSTUtil.isDefaultPST(pst)) {
591                     return Optional.of(pst);
592                 }
593             }
594         }
595         return Optional.empty();
596     }
597
598     /**
599      * Recover lspData and mark any LSPs in the LSP database that were previously reported by the PCC as stale.
600      */
601     @Override
602     protected synchronized void loadLspData(final Node node, final Map<String, ReportedLsp> lspData,
603             final Map<PlspId, String> lsps, final boolean incrementalSynchro) {
604         //load node's lsps from DS
605         final PathComputationClient pcc = node.augmentation(Node1.class).getPathComputationClient();
606         for (final ReportedLsp reportedLsp : pcc.nonnullReportedLsp().values()) {
607             final String lspName = reportedLsp.getName();
608             lspData.put(lspName, reportedLsp);
609             if (!reportedLsp.getPath().isEmpty()) {
610                 final Path1 path1 = reportedLsp.getPath().values().iterator().next().augmentation(Path1.class);
611                 if (path1 != null) {
612                     final PlspId plspId = path1.getLsp().getPlspId();
613                     if (!incrementalSynchro) {
614                         this.staleLsps.add(plspId);
615                     }
616                     lsps.put(plspId, lspName);
617                 }
618             }
619         }
620     }
621
622     /**
623      * When the PCC reports an LSP during state synchronization, if the LSP already
624      * exists in the LSP database, the PCE MUST update the LSP database and
625      * clear the stale marker from the LSP.
626      *
627      * @param plspId id
628      */
629     private synchronized void unmarkStaleLsp(final PlspId plspId) {
630         this.staleLsps.remove(plspId);
631     }
632
633     /**
634      * Purge any LSPs from the LSP database that are still marked as stale.
635      *
636      * @param ctx message context
637      */
638     private synchronized void purgeStaleLsps(final MessageContext ctx) {
639         for (final PlspId plspId : this.staleLsps) {
640             removeLsp(ctx, plspId);
641         }
642         this.staleLsps.clear();
643     }
644
645     @Override
646     public boolean isInitiationCapability() {
647         return this.initiationCapability.get();
648     }
649
650     @Override
651     public boolean isStatefulCapability() {
652         return this.statefulCapability.get();
653     }
654
655     @Override
656     public boolean isLspUpdateCapability() {
657         return this.lspUpdateCapability.get();
658     }
659
660     private synchronized void setStatefulCapabilities(final Stateful stateful) {
661         this.statefulCapability.set(true);
662         if (stateful.isLspUpdateCapability() != null) {
663             this.lspUpdateCapability.set(stateful.isLspUpdateCapability());
664         }
665         final Stateful1 stateful1 = stateful.augmentation(Stateful1.class);
666         if (stateful1 != null && stateful1.isInitiation() != null) {
667             this.initiationCapability.set(stateful1.isInitiation());
668         }
669     }
670
671     private class ResyncLspFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
672
673         private final TriggerSyncArgs input;
674
675         ResyncLspFunction(final TriggerSyncArgs input) {
676             this.input = input;
677         }
678
679         @Override
680         public ListenableFuture<OperationResult> apply(final Optional<ReportedLsp> rep) {
681             final Lsp reportedLsp = validateReportedLsp(rep, this.input);
682             if (reportedLsp == null || !rep.isPresent()) {
683                 return OperationResults.createUnsent(PCEPErrors.UNKNOWN_PLSP_ID).future();
684             }
685             // mark lsp as stale
686             final ReportedLsp staleLsp = rep.get();
687             if (!staleLsp.getPath().isEmpty()) {
688                 final Path1 path1 = staleLsp.getPath().values().iterator().next().augmentation(Path1.class);
689                 if (path1 != null) {
690                     Stateful07TopologySessionListener.this.staleLsps.add(path1.getLsp().getPlspId());
691                 }
692             }
693             updatePccState(PccSyncState.PcepTriggeredResync);
694             // create PCUpd with mandatory objects and LSP object set to 1
695             final SrpBuilder srpBuilder = new SrpBuilder();
696             srpBuilder.setOperationId(nextRequest());
697             srpBuilder.setProcessingRule(Boolean.TRUE);
698
699             final Optional<PathSetupType> maybePST = getPST(rep);
700             if (maybePST.isPresent()) {
701                 srpBuilder.setTlvs(
702                         new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
703                                 .rev181109.srp.object.srp.TlvsBuilder()
704                                 .setPathSetupType(maybePST.get()).build());
705             }
706
707             final Srp srp = srpBuilder.build();
708             final Lsp lsp = new LspBuilder().setPlspId(reportedLsp.getPlspId()).setSync(Boolean.TRUE).build();
709
710             final Message msg = createPcepUpd(srp, lsp);
711             return sendMessage(msg, srp.getOperationId(), null);
712         }
713
714         private Message createPcepUpd(final Srp srp, final Lsp lsp) {
715             final UpdatesBuilder rb = new UpdatesBuilder();
716             rb.setSrp(srp);
717             rb.setLsp(lsp);
718             final PathBuilder pb = new PathBuilder();
719             rb.setPath(pb.build());
720             final PcupdMessageBuilder ub = new PcupdMessageBuilder(MESSAGE_HEADER);
721             ub.setUpdates(Collections.singletonList(rb.build()));
722             return new PcupdBuilder().setPcupdMessage(ub.build()).build();
723         }
724     }
725
726     private class AddFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
727
728         private final AddLspArgs input;
729         private final InstanceIdentifier<ReportedLsp> lsp;
730
731         AddFunction(final AddLspArgs input, final InstanceIdentifier<ReportedLsp> lsp) {
732             this.input = input;
733             this.lsp = lsp;
734         }
735
736         @Override
737         public ListenableFuture<OperationResult> apply(final Optional<ReportedLsp> rep) {
738             if (rep.isPresent()) {
739                 LOG.debug("Node {} already contains lsp {} at {}", this.input.getNode(), this.input.getName(),
740                         this.lsp);
741                 return OperationResults.createUnsent(PCEPErrors.USED_SYMBOLIC_PATH_NAME).future();
742             }
743             if (!Stateful07TopologySessionListener.this.initiationCapability.get()) {
744                 return OperationResults.createUnsent(PCEPErrors.CAPABILITY_NOT_SUPPORTED).future();
745             }
746
747             // Build the request
748             final RequestsBuilder rb = new RequestsBuilder();
749             final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120
750                     .add.lsp.args.Arguments args = this.input.getArguments();
751             final Arguments2 args2 = args.augmentation(Arguments2.class);
752             final Lsp inputLsp = args2 != null ? args2.getLsp() : null;
753             if (inputLsp == null) {
754                 return OperationResults.createUnsent(PCEPErrors.LSP_MISSING).future();
755             }
756
757             rb.fieldsFrom(this.input.getArguments());
758
759             /* Call Path Computation if an ERO was not provided */
760             boolean segmentRouting = !PSTUtil.isDefaultPST(args2.getPathSetupType());
761             if (rb.getEro() == null
762                     || rb.getEro().getSubobject() == null
763                     || rb.getEro().getSubobject().size() == 0) {
764
765                 /* Get a Path Computation to compute the Path from the Arguments */
766                 PathComputation pathComputation = pceServerProvider.getPathComputation();
767                 rb.setEro(pathComputation.computeEro(args.getEndpointsObj(), args.getBandwidth(), args.getClassType(),
768                         args.getMetrics(), segmentRouting));
769             }
770
771             final TlvsBuilder tlvsBuilder;
772             if (inputLsp.getTlvs() != null) {
773                 tlvsBuilder = new TlvsBuilder(inputLsp.getTlvs());
774             } else {
775                 tlvsBuilder = new TlvsBuilder();
776             }
777             tlvsBuilder.setSymbolicPathName(
778                     new SymbolicPathNameBuilder().setPathName(new SymbolicPathName(this.input.getName()
779                             .getBytes(StandardCharsets.UTF_8))).build());
780
781             final SrpBuilder srpBuilder = new SrpBuilder()
782                     .setOperationId(nextRequest())
783                     .setProcessingRule(Boolean.TRUE);
784             if (segmentRouting) {
785                 srpBuilder.setTlvs(
786                         new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf
787                                 .stateful.rev181109.srp.object.srp.TlvsBuilder()
788                                 .setPathSetupType(args2.getPathSetupType()).build());
789             }
790             rb.setSrp(srpBuilder.build());
791
792             rb.setLsp(new LspBuilder()
793                 .setAdministrative(inputLsp.isAdministrative())
794                 .setDelegate(inputLsp.isDelegate())
795                 .setPlspId(PLSPID_ZERO)
796                 .setTlvs(tlvsBuilder.build())
797                 .build());
798
799             // Send the message
800             return sendMessage(new PcinitiateBuilder()
801                 .setPcinitiateMessage(new PcinitiateMessageBuilder(MESSAGE_HEADER)
802                     .setRequests(Collections.singletonList(rb.build()))
803                     .build())
804                 .build(),
805                 rb.getSrp().getOperationId(), this.input.getArguments().getMetadata());
806         }
807     }
808
809     private class UpdateFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
810
811         private final UpdateLspArgs input;
812
813         UpdateFunction(final UpdateLspArgs input) {
814             this.input = input;
815         }
816
817         @Override
818         public ListenableFuture<OperationResult> apply(final Optional<ReportedLsp> rep) {
819             final Lsp reportedLsp = validateReportedLsp(rep, this.input);
820             if (reportedLsp == null) {
821                 return OperationResults.createUnsent(PCEPErrors.UNKNOWN_PLSP_ID).future();
822             }
823             // create mandatory objects
824             final Arguments3 args = this.input.getArguments().augmentation(Arguments3.class);
825             final SrpBuilder srpBuilder = new SrpBuilder();
826             srpBuilder.setOperationId(nextRequest());
827             srpBuilder.setProcessingRule(Boolean.TRUE);
828             if (args != null && args.getPathSetupType() != null) {
829                 if (!PSTUtil.isDefaultPST(args.getPathSetupType())) {
830                     srpBuilder.setTlvs(
831                             new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
832                                     .rev181109.srp.object.srp.TlvsBuilder()
833                                     .setPathSetupType(args.getPathSetupType()).build());
834                 }
835             } else {
836                 final Optional<PathSetupType> maybePST = getPST(rep);
837                 if (maybePST.isPresent()) {
838                     srpBuilder.setTlvs(
839                             new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful
840                                     .rev181109.srp.object.srp.TlvsBuilder()
841                                     .setPathSetupType(maybePST.get()).build());
842                 }
843             }
844             final Srp srp = srpBuilder.build();
845             final Lsp inputLsp = args != null ? args.getLsp() : null;
846             final LspBuilder lspBuilder = new LspBuilder().setPlspId(reportedLsp.getPlspId());
847             if (inputLsp != null) {
848                 lspBuilder.setDelegate(inputLsp.isDelegate() != null && inputLsp.isDelegate())
849                         .setTlvs(inputLsp.getTlvs())
850                         .setAdministrative(inputLsp.isAdministrative() != null && inputLsp.isAdministrative());
851             }
852             return redelegate(reportedLsp, srp, lspBuilder.build(), this.input);
853         }
854     }
855 }