9cb16c0900e77518ff18b32cf8b530ffa6193313
[bgpcep.git] / pcep / topology / topology-provider / src / main / java / org / opendaylight / bgpcep / pcep / topology / provider / PCEPTopologySessionListener.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.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;
111
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);
115
116     private final AtomicLong requestId = new AtomicLong(1L);
117
118     @GuardedBy("this")
119     private final List<PlspId> staleLsps = new ArrayList<>();
120
121     private final AtomicBoolean statefulCapability = new AtomicBoolean(false);
122     private final AtomicBoolean lspUpdateCapability = new AtomicBoolean(false);
123     private final AtomicBoolean initiationCapability = new AtomicBoolean(false);
124
125     private final PceServerProvider pceServerProvider;
126
127     /**
128      * Creates a new stateful topology session listener for given server session manager.
129      */
130     PCEPTopologySessionListener(final ServerSessionManager serverSessionManager) {
131         super(serverSessionManager);
132         this.pceServerProvider = serverSessionManager.getPCEPTopologyProviderDependencies().getPceServerProvider();
133     }
134
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();
142         }
143         return null;
144     }
145
146     @Override
147     protected void onSessionUp(final PCEPSession session, final PathComputationClientBuilder pccBuilder) {
148         final InetAddress peerAddress = session.getRemoteAddress();
149
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);
162                 } else {
163                     pccBuilder.setStateSync(PccSyncState.InitialResync);
164                 }
165                 pccBuilder.setStatefulTlv(new StatefulTlvBuilder().addAugmentation(
166                         new StatefulTlv1Builder(tlvs.augmentation(Tlvs1.class)).build()).build());
167             } else {
168                 LOG.debug("Peer {} does not advertise stateful TLV", peerAddress);
169             }
170         } else {
171             LOG.debug("Peer {} does not advertise stateful TLV", peerAddress);
172         }
173     }
174
175     @Override
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);
182         }
183         return OperationResults.UNSENT.future();
184     }
185
186     private ListenableFuture<OperationResult> triggerLspSyncronization(final TriggerSyncArgs input) {
187         LOG.trace("Trigger Lsp Resynchronization {}", input);
188
189         // Make sure the LSP exists
190         final InstanceIdentifier<ReportedLsp> lsp = lspIdentifier(input.getName());
191         final FluentFuture<Optional<ReportedLsp>> f = readOperationalData(lsp);
192         if (f == null) {
193             return OperationResults.createUnsent(PCEPErrors.LSP_INTERNAL_ERROR).future();
194         }
195         return Futures.transformAsync(f, new ResyncLspFunction(input), MoreExecutors.directExecutor());
196     }
197
198     private ListenableFuture<OperationResult> triggerResyncronization(final TriggerSyncArgs input) {
199         LOG.trace("Trigger Resynchronization {}", input);
200         markAllLspAsStale();
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);
206     }
207
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);
214     }
215
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());
228
229         updBuilder.setPath(pb.build());
230         updBuilder.setLsp(lsp).setSrp(srp).setPath(pb.build());
231
232         pcupdMessageBuilder.setUpdates(Collections.singletonList(updBuilder.build()));
233         return srp.getOperationId();
234     }
235
236     private void markAllLspAsStale() {
237         this.staleLsps.addAll(this.lsps.keySet());
238     }
239
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);
249                     if (req != null) {
250                         req.done(OperationResults.createFailed(errMsg.getErrors()));
251                     } else {
252                         LOG.warn("Request ID {} not found in outstanding DB", id);
253                     }
254                 }
255             }
256         } else {
257             LOG.warn("Unhandled PCErr message {}.", errMsg);
258             return true;
259         }
260         return false;
261     }
262
263     private boolean isSolicited(final Srp srp, final Lsp lsp, final MessageContext ctx, final ReportedLspBuilder rlb) {
264         if (srp == null) {
265             return false;
266         }
267         final SrpIdNumber id = srp.getOperationId();
268         if (id.getValue().toJava() == 0) {
269             return false;
270         }
271         switch (lsp.getOperational()) {
272             case Active:
273             case Down:
274             case Up:
275                 if (!isTriggeredSyncInProcess()) {
276                     final PCEPRequest req = removeRequest(id);
277                     if (req != null) {
278                         LOG.debug("Request {} resulted in LSP operational state {}", id, lsp.getOperational());
279                         rlb.setMetadata(req.getMetadata());
280                         ctx.resolveRequest(req);
281                     } else {
282                         LOG.warn("Request ID {} not found in outstanding DB", id);
283                     }
284                 }
285                 break;
286             case GoingDown:
287             case GoingUp:
288                 // These are transitive states, so we don't have to do anything, as they will be followed
289                 // up...
290                 break;
291             default:
292                 break;
293         }
294         return true;
295     }
296
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();
301
302         if (!lsp.isSync() && (plspid == null || plspid.getValue().toJava() == 0)) {
303             purgeStaleLsps(ctx);
304             if (isTriggeredSyncInProcess()) {
305                 if (srp == null) {
306                     return false;
307                 }
308                 final SrpIdNumber id = srp.getOperationId();
309                 if (id.getValue().toJava() == 0) {
310                     return false;
311                 }
312                 final PCEPRequest req = removeRequest(id);
313                 ctx.resolveRequest(req);
314             }
315             stateSynchronizationAchieved(ctx);
316             return true;
317         }
318         final ReportedLspBuilder rlb = new ReportedLspBuilder();
319         boolean solicited = false;
320         solicited = isSolicited(srp, lsp, ctx, rlb);
321
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);
327                 return false;
328             }
329         }
330         rlb.setPath(Collections.singletonList(buildPath(report, srp, lsp)));
331
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();
336         }
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());
342         }
343         updateLsp(ctx, plspid, name, rlb, solicited, lsp.isRemove());
344         unmarkStaleLsp(plspid);
345
346         LOG.debug("LSP {} updated", lsp);
347         return true;
348     }
349
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());
357         }
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);
366         } else {
367             pst = null;
368         }
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();
372         if (tlvs != null) {
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()));
378             }
379         }
380         return pb.build();
381     }
382
383     private boolean handlePcreqMessage(final PcreqMessage message) {
384
385         LOG.info("Start PcRequest Message handler");
386
387         /* Get a Path Computation to compute the Path from the Request */
388         PathComputation pathComputation = this.pceServerProvider.getPathComputation();
389         Message rep = null;
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);
394             return false;
395         }
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());
403             } else {
404                 repId = new SrpIdNumber(Uint32.ZERO);
405             }
406             sendMessage(rep, repId, null);
407         }
408         return false;
409     }
410
411     @Override
412     protected synchronized boolean onMessage(final MessageContext ctx, final Message message) {
413         if (message instanceof PcerrMessage) {
414             return handleErrorMessage((PcerrMessage) message);
415         }
416         if (message instanceof Pcreq) {
417             LOG.info("PcReq detected. Start Request Message handler");
418             return handlePcreqMessage(((Pcreq) message).getPcreqMessage());
419         }
420         if (!(message instanceof PcrptMessage)) {
421             return true;
422         }
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)) {
428                 return false;
429             }
430         }
431         return false;
432     }
433
434     private SrpIdNumber nextRequest() {
435         return new SrpIdNumber(Uint32.valueOf(this.requestId.getAndIncrement()));
436     }
437
438     @Override
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());
449     }
450
451     @Override
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();
464                     }
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());
471     }
472
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());
482         }
483         rb.setSrp(srpBuilder.build());
484         rb.setLsp(new LspBuilder().setRemove(Boolean.FALSE).setPlspId(reportedLsp.getPlspId())
485                 .setDelegate(reportedLsp.isDelegate()).build());
486         return rb.build();
487     }
488
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());
495         final Message msg;
496         if (reportedLsp.isDelegate()) {
497             // we already have delegation, send update
498             final UpdatesBuilder rb = new UpdatesBuilder();
499             rb.setSrp(srp);
500             rb.setLsp(lsp);
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();
507         } else {
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();
513             }
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();
523         }
524         return sendMessage(msg, srp.getOperationId(), input.getArguments().getMetadata());
525     }
526
527     @Override
528     @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "SB does not grok TYPE_USE")
529
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());
539     }
540
541     @Override
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);
546
547         final OperationalStatus op;
548         final Arguments1 aa = args.augmentation(Arguments1.class);
549         if (aa != null) {
550             op = aa.getOperational();
551         } else {
552             op = null;
553         }
554
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);
561     }
562
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;
570             }
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);
574                 if (p1 == null) {
575                     LOG.warn("Node {} LSP {} does not contain data", input.getNode(), input.getName());
576                     return OperationResults.UNSENT;
577                 }
578                 if (op.equals(p1.getLsp().getOperational())) {
579                     return OperationResults.SUCCESS;
580                 }
581             }
582             return OperationResults.UNSENT;
583         }, MoreExecutors.directExecutor());
584     }
585
586     @Override
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());
590             return null;
591         }
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.");
597         return reportedLsp;
598     }
599
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);
603             if (path1 != null) {
604                 final PathSetupType pst = path1.getPathSetupType();
605                 if (!PSTUtil.isDefaultPST(pst)) {
606                     return Optional.of(pst);
607                 }
608             }
609         }
610         return Optional.empty();
611     }
612
613     /**
614      * Recover lspData and mark any LSPs in the LSP database that were previously reported by the PCC as stale.
615      */
616     @Override
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);
626                 if (path1 != null) {
627                     final PlspId plspId = path1.getLsp().getPlspId();
628                     if (!incrementalSynchro) {
629                         this.staleLsps.add(plspId);
630                     }
631                     lsps.put(plspId, lspName);
632                 }
633             }
634         }
635     }
636
637     /**
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.
641      *
642      * @param plspId id
643      */
644     private synchronized void unmarkStaleLsp(final PlspId plspId) {
645         this.staleLsps.remove(plspId);
646     }
647
648     /**
649      * Purge any LSPs from the LSP database that are still marked as stale.
650      *
651      * @param ctx message context
652      */
653     private synchronized void purgeStaleLsps(final MessageContext ctx) {
654         for (final PlspId plspId : this.staleLsps) {
655             removeLsp(ctx, plspId);
656         }
657         this.staleLsps.clear();
658     }
659
660     @Override
661     public boolean isInitiationCapability() {
662         return this.initiationCapability.get();
663     }
664
665     @Override
666     public boolean isStatefulCapability() {
667         return this.statefulCapability.get();
668     }
669
670     @Override
671     public boolean isLspUpdateCapability() {
672         return this.lspUpdateCapability.get();
673     }
674
675     private synchronized void setStatefulCapabilities(final Stateful stateful) {
676         this.statefulCapability.set(true);
677         if (stateful.isLspUpdateCapability() != null) {
678             this.lspUpdateCapability.set(stateful.isLspUpdateCapability());
679         }
680         final Stateful1 stateful1 = stateful.augmentation(Stateful1.class);
681         if (stateful1 != null && stateful1.isInitiation() != null) {
682             this.initiationCapability.set(stateful1.isInitiation());
683         }
684     }
685
686     private class ResyncLspFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
687
688         private final TriggerSyncArgs input;
689
690         ResyncLspFunction(final TriggerSyncArgs input) {
691             this.input = input;
692         }
693
694         @Override
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();
699             }
700             // mark lsp as stale
701             final ReportedLsp staleLsp = rep.get();
702             if (!staleLsp.getPath().isEmpty()) {
703                 final Path1 path1 = staleLsp.getPath().values().iterator().next().augmentation(Path1.class);
704                 if (path1 != null) {
705                     PCEPTopologySessionListener.this.staleLsps.add(path1.getLsp().getPlspId());
706                 }
707             }
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);
713
714             final Optional<PathSetupType> maybePST = getPST(rep);
715             if (maybePST.isPresent()) {
716                 srpBuilder.setTlvs(
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());
720             }
721
722             final Srp srp = srpBuilder.build();
723             final Lsp lsp = new LspBuilder().setPlspId(reportedLsp.getPlspId()).setSync(Boolean.TRUE).build();
724
725             final Message msg = createPcepUpd(srp, lsp);
726             return sendMessage(msg, srp.getOperationId(), null);
727         }
728
729         private Message createPcepUpd(final Srp srp, final Lsp lsp) {
730             final UpdatesBuilder rb = new UpdatesBuilder();
731             rb.setSrp(srp);
732             rb.setLsp(lsp);
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();
738         }
739     }
740
741     private class AddFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
742
743         private final AddLspArgs input;
744         private final InstanceIdentifier<ReportedLsp> lsp;
745
746         AddFunction(final AddLspArgs input, final InstanceIdentifier<ReportedLsp> lsp) {
747             this.input = input;
748             this.lsp = lsp;
749         }
750
751         @Override
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(),
755                         this.lsp);
756                 return OperationResults.createUnsent(PCEPErrors.USED_SYMBOLIC_PATH_NAME).future();
757             }
758             if (!PCEPTopologySessionListener.this.initiationCapability.get()) {
759                 return OperationResults.createUnsent(PCEPErrors.CAPABILITY_NOT_SUPPORTED).future();
760             }
761
762             // Build the request
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();
770             }
771
772             rb.fieldsFrom(this.input.getArguments());
773
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) {
779
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();
784                 }
785                 rb.setEro(pathComputation.computeEro(args.getEndpointsObj(), args.getBandwidth(), args.getClassType(),
786                         args.getMetrics(), segmentRouting));
787             }
788
789             final TlvsBuilder tlvsBuilder;
790             if (inputLsp.getTlvs() != null) {
791                 tlvsBuilder = new TlvsBuilder(inputLsp.getTlvs());
792             } else {
793                 tlvsBuilder = new TlvsBuilder();
794             }
795             tlvsBuilder.setSymbolicPathName(
796                     new SymbolicPathNameBuilder().setPathName(new SymbolicPathName(this.input.getName()
797                             .getBytes(StandardCharsets.UTF_8))).build());
798
799             final SrpBuilder srpBuilder = new SrpBuilder()
800                     .setOperationId(nextRequest())
801                     .setProcessingRule(Boolean.TRUE);
802             if (segmentRouting) {
803                 srpBuilder.setTlvs(
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());
807             }
808             rb.setSrp(srpBuilder.build());
809
810             rb.setLsp(new LspBuilder()
811                 .setAdministrative(inputLsp.isAdministrative())
812                 .setDelegate(inputLsp.isDelegate())
813                 .setPlspId(PLSPID_ZERO)
814                 .setTlvs(tlvsBuilder.build())
815                 .build());
816
817             // Send the message
818             return sendMessage(new PcinitiateBuilder()
819                 .setPcinitiateMessage(new PcinitiateMessageBuilder(MESSAGE_HEADER)
820                     .setRequests(Collections.singletonList(rb.build()))
821                     .build())
822                 .build(),
823                 rb.getSrp().getOperationId(), this.input.getArguments().getMetadata());
824         }
825     }
826
827     private class UpdateFunction implements AsyncFunction<Optional<ReportedLsp>, OperationResult> {
828
829         private final UpdateLspArgs input;
830
831         UpdateFunction(final UpdateLspArgs input) {
832             this.input = input;
833         }
834
835         @Override
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();
840             }
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())) {
848                     srpBuilder.setTlvs(
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());
852                 }
853             } else {
854                 final Optional<PathSetupType> maybePST = getPST(rep);
855                 if (maybePST.isPresent()) {
856                     srpBuilder.setTlvs(
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());
860                 }
861             }
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());
869             }
870             return redelegate(reportedLsp, srp, lspBuilder.build(), this.input);
871         }
872     }
873
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)
882                                     .setIgnore(false)
883                                     .setRequestId(new RequestId(reqID))
884                                     .build())
885                                 .build()))
886                             .build())
887                         .build())
888                     .setErrors(Collections.singletonList(new ErrorsBuilder()
889                         .setErrorObject(new ErrorObjectBuilder()
890                             .setType(pcepErrors.getErrorType())
891                             .setValue(pcepErrors.getErrorValue())
892                             .build())
893                         .build()))
894                     .build())
895                 .build();
896     }
897 }