Fixup Augmentable and Identifiable methods changing
[bgpcep.git] / pcep / pcc-mock / src / main / java / org / opendaylight / protocol / pcep / pcc / mock / PCCTunnelManagerImpl.java
1 /*
2  * Copyright (c) 2015 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
9 package org.opendaylight.protocol.pcep.pcc.mock;
10
11 import static java.util.Objects.requireNonNull;
12 import static org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil.createLsp;
13 import static org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil.createLspTlvs;
14 import static org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil.createLspTlvsEndofSync;
15 import static org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil.createPath;
16 import static org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil.createPcRtpMessage;
17 import static org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil.createSrp;
18 import static org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil.reqToRptPath;
19 import static org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil.updToRptPath;
20
21 import com.google.common.base.Optional;
22 import com.google.common.base.Preconditions;
23 import com.google.common.net.InetAddresses;
24 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
25 import io.netty.util.Timeout;
26 import io.netty.util.Timer;
27 import java.math.BigInteger;
28 import java.net.InetAddress;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Map.Entry;
34 import java.util.concurrent.TimeUnit;
35 import java.util.concurrent.atomic.AtomicLong;
36 import javax.annotation.Nonnull;
37 import javax.annotation.concurrent.GuardedBy;
38 import org.opendaylight.protocol.pcep.pcc.mock.api.LspType;
39 import org.opendaylight.protocol.pcep.pcc.mock.api.PCCSession;
40 import org.opendaylight.protocol.pcep.pcc.mock.api.PCCTunnelManager;
41 import org.opendaylight.protocol.pcep.pcc.mock.spi.MsgBuilderUtil;
42 import org.opendaylight.protocol.pcep.spi.PCEPErrors;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev171025.Lsp1;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev171025.Lsp1Builder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev171025.Srp1;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev171025.Srp1Builder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.crabbe.initiated.rev171025.pcinitiate.message.pcinitiate.message.Requests;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev171025.OperationalStatus;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev171025.Pcrpt;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev171025.PlspId;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev171025.SrpIdNumber;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev171025.lsp.object.Lsp;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev171025.lsp.object.LspBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev171025.lsp.object.lsp.Tlvs;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev171025.pcrpt.message.pcrpt.message.reports.Path;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev171025.pcrpt.message.pcrpt.message.reports.PathBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev171025.pcupd.message.pcupd.message.Updates;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev171025.srp.object.Srp;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev171025.srp.object.SrpBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.explicit.route.object.ero.Subobject;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.basic.explicit.route.subobjects.subobject.type.IpPrefixCase;
62
63 public final class PCCTunnelManagerImpl implements PCCTunnelManager {
64
65     private static final Optional<Srp> NO_SRP = Optional.absent();
66     @GuardedBy("this")
67     private final Map<Integer, PCCSession> sessions = new HashMap<>();
68     private final AtomicLong plspIDsCounter;
69     private final String address;
70     private final Timer timer;
71     private final int redelegationTimeout;
72     private final int stateTimeout;
73     private final int lspsCount;
74     private final Optional<TimerHandler> timerHandler;
75     @GuardedBy("this")
76     private final Map<PlspId, PCCTunnel> tunnels = new HashMap<>();
77     private PCCSyncOptimization syncOptimization;
78
79     public PCCTunnelManagerImpl(final int lspsCount, final InetAddress address, final int redelegationTimeout,
80                                 final int stateTimeout, final Timer timer, final Optional<TimerHandler> timerHandler) {
81         Preconditions.checkArgument(lspsCount >= 0);
82         this.redelegationTimeout = redelegationTimeout;
83         this.stateTimeout = stateTimeout;
84         this.plspIDsCounter = new AtomicLong(lspsCount);
85         this.address = InetAddresses.toAddrString(requireNonNull(address));
86         this.timer = requireNonNull(timer);
87         this.timerHandler = timerHandler;
88         this.lspsCount = lspsCount;
89     }
90
91     protected void reportToAll(final Updates update, final PCCSession session) {
92         final PlspId plspId = update.getLsp().getPlspId();
93         final PCCTunnel tunnel = this.tunnels.get(plspId);
94         final long srpId = update.getSrp().getOperationId().getValue();
95         if (tunnel != null) {
96             if (hasDelegation(tunnel, session)) {
97                 final Srp srp = createSrp(update.getSrp().getOperationId().getValue());
98                 final Path path = updToRptPath(update.getPath());
99                 final List<Subobject> subobjects = update.getPath().getEro().getSubobject();
100                 final Lsp lsp = update.getLsp();
101                 sendToAll(tunnel, plspId, subobjects, srp, path, lsp);
102                 //update tunnel state
103                 tunnel.setLspState(path);
104             } else {
105                 session.sendError(MsgBuilderUtil.createErrorMsg(PCEPErrors.UPDATE_REQ_FOR_NON_LSP, srpId));
106             }
107         } else {
108             session.sendError(MsgBuilderUtil.createErrorMsg(PCEPErrors.UNKNOWN_PLSP_ID, srpId));
109         }
110     }
111
112     private void returnDelegation(final Updates update, final PCCSession session) {
113         final PlspId plspId = update.getLsp().getPlspId();
114         final PCCTunnel tunnel = this.tunnels.get(plspId);
115         final long srpId = update.getSrp().getOperationId().getValue();
116         if (tunnel != null) {
117             //check if session really has a delegation
118             if (hasDelegation(tunnel, session)) {
119                 //send report D=0
120                 final Tlvs tlvs = buildTlvs(tunnel, plspId.getValue(), Optional.absent());
121                 final Pcrpt pcrtp = createPcRtpMessage(new LspBuilder(update.getLsp()).setSync(true)
122                         .setOperational(OperationalStatus.Up).setDelegate(false)
123                         .setTlvs(tlvs).build(), Optional.of(createSrp(srpId)), tunnel.getLspState());
124                 session.sendReport(pcrtp);
125                 //start state timer
126                 startStateTimeout(tunnel, plspId);
127                 //if PCC's LSP, start re-delegation timer
128                 if (tunnel.getType() == LspType.PCC_LSP) {
129                     startRedelegationTimer(tunnel, plspId, session);
130                 } else {
131                     //if PCE-initiated LSP, revoke delegation instantly
132                     setDelegation(plspId, null);
133                 }
134             } else {
135                 session.sendError(MsgBuilderUtil.createErrorMsg(PCEPErrors.UPDATE_REQ_FOR_NON_LSP, srpId));
136             }
137         } else {
138             session.sendError(MsgBuilderUtil.createErrorMsg(PCEPErrors.UNKNOWN_PLSP_ID, srpId));
139         }
140     }
141
142     protected void takeDelegation(final Requests request, final PCCSession session) {
143         final PlspId plspId = request.getLsp().getPlspId();
144         final PCCTunnel tunnel = this.tunnels.get(plspId);
145         final long srpId = request.getSrp().getOperationId().getValue();
146         if (tunnel != null) {
147             //check if tunnel has no delegation
148             if ((tunnel.getType() == LspType.PCE_LSP) && ((tunnel.getDelegationHolder() == -1)
149                     || (tunnel.getDelegationHolder() == session.getId()))) {
150                 //set delegation
151                 tunnel.cancelTimeouts();
152                 setDelegation(plspId, session);
153                 //send report
154                 final Tlvs tlvs = buildTlvs(tunnel, plspId.getValue(), Optional.absent());
155                 session.sendReport(createPcRtpMessage(
156                     new LspBuilder(request.getLsp()).setSync(true).setOperational(OperationalStatus.Up)
157                             .setDelegate(true).setTlvs(tlvs).build(),
158                     Optional.of(createSrp(srpId)), tunnel.getLspState()));
159             } else {
160                 session.sendError(MsgBuilderUtil.createErrorMsg(PCEPErrors.LSP_NOT_PCE_INITIATED, srpId));
161             }
162         } else {
163             session.sendError(MsgBuilderUtil.createErrorMsg(PCEPErrors.UNKNOWN_PLSP_ID, srpId));
164         }
165     }
166
167     @Override
168     public synchronized void onSessionUp(final PCCSession session) {
169         this.syncOptimization = new PCCSyncOptimization(session);
170         lazyTunnelInicialization();
171
172         //first session - delegate all PCC's LSPs only when reporting at startup
173         if (!this.sessions.containsKey(session.getId()) && (session.getId() == 0)) {
174             for (final PlspId plspId : this.tunnels.keySet()) {
175                 setDelegation(plspId, session);
176             }
177         }
178         this.sessions.put(session.getId(), session);
179
180         if (!this.syncOptimization.isTriggeredInitSyncEnabled()) {
181             lspReport(session);
182         }
183     }
184
185     @Override
186     public synchronized void onSessionDown(final PCCSession session) {
187         for (final Entry<PlspId, PCCTunnel> entry : this.tunnels.entrySet()) {
188             final PCCTunnel tunnel = entry.getValue();
189             final PlspId plspId = entry.getKey();
190             //deal with delegations
191             if (hasDelegation(tunnel, session)) {
192                 startStateTimeout(tunnel, entry.getKey());
193                 startRedelegationTimer(tunnel, plspId, session);
194             }
195         }
196     }
197
198     protected void addTunnel(final Requests request, final PCCSession session) {
199         final PlspId plspId = new PlspId(this.plspIDsCounter.incrementAndGet());
200         final PCCTunnel tunnel = new PCCTunnel(request.getLsp().getTlvs().getSymbolicPathName()
201                 .getPathName().getValue(), session.getId(), LspType.PCE_LSP, reqToRptPath(request));
202         sendToAll(tunnel, plspId, request.getEro().getSubobject(),
203                 createSrp(request.getSrp().getOperationId().getValue()), tunnel.getLspState(),
204                 new LspBuilder(request.getLsp())
205                         .addAugmentation(Lsp1.class, new Lsp1Builder().setCreate(true).build()).build());
206         this.tunnels.put(plspId, tunnel);
207     }
208
209     protected void removeTunnel(final Requests request, final PCCSession session) {
210         final PlspId plspId = request.getLsp().getPlspId();
211         final PCCTunnel tunnel = this.tunnels.get(plspId);
212         final long srpId = request.getSrp().getOperationId().getValue();
213         if (tunnel != null) {
214             if (tunnel.getType() == LspType.PCE_LSP) {
215                 if (hasDelegation(tunnel, session)) {
216                     this.tunnels.remove(plspId);
217                     sendToAll(tunnel, plspId, tunnel.getLspState().getEro().getSubobject(),
218                         new SrpBuilder(request.getSrp())
219                                 .addAugmentation(Srp1.class, new Srp1Builder().setRemove(true).build()).build(),
220                         reqToRptPath(request), request.getLsp());
221                 } else {
222                     session.sendError(MsgBuilderUtil.createErrorMsg(PCEPErrors.UPDATE_REQ_FOR_NON_LSP, srpId));
223                 }
224             } else {
225                 session.sendError(MsgBuilderUtil.createErrorMsg(PCEPErrors.LSP_NOT_PCE_INITIATED, srpId));
226             }
227         } else {
228             session.sendError(MsgBuilderUtil.createErrorMsg(PCEPErrors.UNKNOWN_PLSP_ID, srpId));
229         }
230     }
231
232     @Override
233     public void onMessagePcupd(@Nonnull final Updates update, @Nonnull final PCCSession session) {
234         final Lsp lsp = update.getLsp();
235         if (isInitialSyncTriggered(lsp)) {
236             lspReport(session);
237             if (this.timerHandler.isPresent()) {
238                 this.timerHandler.get().createDisconnectTask();
239             }
240         } else if (isReSyncTriggered(lsp)) {
241             handledDbTriggeredResync(update, session);
242         } else if ((lsp.isDelegate() != null) && lsp.isDelegate()) {
243             //regular LSP update
244             reportToAll(update, session);
245         } else {
246             //returning LSP delegation
247             returnDelegation(update, session);
248         }
249     }
250
251     @Override
252     public void onMessagePcInitiate(@Nonnull final Requests request, @Nonnull final PCCSession session) {
253         if ((request.getSrp().augmentation(Srp1.class) != null)
254                 && request.getSrp().augmentation(Srp1.class).isRemove()) {
255             //remove LSP
256             removeTunnel(request, session);
257         } else if ((request.getLsp().isDelegate() != null) && request.getLsp().isDelegate()
258                 && (request.getEndpointsObj() == null)) {
259             //take LSP delegation
260             takeDelegation(request, session);
261         } else {
262             //create LSP
263             addTunnel(request, session);
264         }
265     }
266
267     private Tlvs buildTlvs(final PCCTunnel tunnel, final Long plspId, final Optional<List<Subobject>> subobjectsList) {
268         final List<Subobject> subObject = subobjectsList.isPresent() ? subobjectsList.get() :
269                 tunnel.getLspState().getEro().getSubobject();
270         final String destinationAddress = getDestinationAddress(subObject, this.address);
271
272         return createLspTlvs(plspId, true, destinationAddress, this.address, this.address,
273                 Optional.of(tunnel.getPathName()), this.syncOptimization.incrementLspDBVersion());
274     }
275
276     private synchronized void lazyTunnelInicialization() {
277         if (this.tunnels.isEmpty()) {
278             final BigInteger dbV = this.syncOptimization.getLocalLspDbVersionValue();
279             if (dbV != null && this.syncOptimization.isSyncAvoidanceEnabled() && !dbV.equals(BigInteger.ONE)) {
280                 this.tunnels.putAll(PCCTunnelBuilder.createTunnels(this.address, dbV.intValue()));
281             } else {
282                 this.tunnels.putAll(PCCTunnelBuilder.createTunnels(this.address, this.lspsCount));
283             }
284         }
285     }
286
287     private boolean isReSyncTriggered(final Lsp lsp) {
288         return this.syncOptimization.isTriggeredReSyncEnabled() && lsp.isSync();
289     }
290
291     private boolean isInitialSyncTriggered(final Lsp lsp) {
292         return (lsp.getPlspId().getValue() == 0) && lsp.isSync() && this.syncOptimization.isTriggeredInitSyncEnabled();
293     }
294
295     private void handledDbTriggeredResync(final Updates update, final PCCSession session) {
296         this.syncOptimization.setResynchronizingState(Boolean.TRUE);
297         final SrpIdNumber operationId = update.getSrp().getOperationId();
298         if (update.getLsp().getPlspId().getValue() == 0) {
299             reportAllKnownLsp(Optional.of(operationId), session);
300         } else {
301             reportLsp(update.getLsp().getPlspId(), operationId, session);
302         }
303         sendEndOfSynchronization(session, Optional.of(operationId));
304         this.syncOptimization.setResynchronizingState(Boolean.FALSE);
305     }
306
307     private void lspReport(final PCCSession session) {
308         if (!this.tunnels.isEmpty()) {
309             if (!this.syncOptimization.isSyncAvoidanceEnabled()) {
310                 reportAllKnownLsp(session);
311                 sendEndOfSynchronization(session);
312             } else if (!this.syncOptimization.doesLspDbMatch()) {
313                 if (this.syncOptimization.isDeltaSyncEnabled()) {
314                     reportMissedLsp(session);
315                     sendEndOfSynchronization(session);
316                 } else {
317                     reportAllKnownLsp(session);
318                     sendEndOfSynchronization(session);
319                 }
320             }
321         }
322     }
323
324     /**
325      * Reports Missed Lsp when DbVersion doesnt match.
326      */
327     private void reportMissedLsp(final PCCSession session) {
328         for (long missedLsp = this.syncOptimization.getRemoteLspDbVersionValue().longValue() + 1;
329              missedLsp <= this.syncOptimization.getLocalLspDbVersionValue().longValue(); missedLsp++) {
330             final PlspId plspId = new PlspId(missedLsp);
331             final PCCTunnel tunnel = this.tunnels.get(plspId);
332             createLspAndSendReport(missedLsp, tunnel, session, Optional.absent(), NO_SRP);
333         }
334     }
335
336     private void createLspAndSendReport(final long plspId, final PCCTunnel tunnel, final PCCSession session,
337             final Optional<Boolean> isSync, final Optional<Srp> srp) {
338         final boolean delegation = hasDelegation(tunnel, session);
339         if (delegation) {
340             tunnel.cancelTimeouts();
341         }
342         final String destinationAddress
343                 = getDestinationAddress(tunnel.getLspState().getEro().getSubobject(), this.address);
344         final Tlvs tlvs = createLspTlvs(plspId, true, destinationAddress, this.address,
345                 this.address, Optional.of(tunnel.getPathName()), this.syncOptimization.incrementLspDBVersion());
346
347         final boolean sync = isSync.isPresent() ? isSync.get() : this.syncOptimization.isSyncNeedIt();
348         final Lsp lsp = createLsp(plspId, sync, Optional.fromNullable(tlvs), delegation, false);
349         final Pcrpt pcrtp = createPcRtpMessage(lsp, srp, tunnel.getLspState());
350         session.sendReport(pcrtp);
351     }
352
353     private void sendEndOfSynchronization(final PCCSession session) {
354         sendEndOfSynchronization(session, Optional.absent());
355     }
356
357     @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF", justification = "Unrecognised NullableDecl")
358     private void sendEndOfSynchronization(final PCCSession session, final Optional<SrpIdNumber> operationId) {
359         Srp srp = null;
360         if (operationId.isPresent()) {
361             srp = new SrpBuilder().setOperationId(operationId.get()).build();
362         }
363         Optional<Tlvs> tlv = Optional.absent();
364         if (this.syncOptimization.isSyncAvoidanceEnabled()) {
365             tlv = createLspTlvsEndofSync(this.syncOptimization.incrementLspDBVersion().get());
366         }
367         final Pcrpt pcrtp = createPcRtpMessage(createLsp(0, false, tlv, true, false),
368                 Optional.fromNullable(srp), createPath(Collections.emptyList()));
369         session.sendReport(pcrtp);
370     }
371
372     private void reportAllKnownLsp(final PCCSession session) {
373         reportAllKnownLsp(Optional.absent(), session);
374     }
375
376     private void reportAllKnownLsp(final Optional<SrpIdNumber> operationId, final PCCSession session) {
377         Srp srp = null;
378         if (operationId.isPresent()) {
379             srp = new SrpBuilder().setOperationId(operationId.get()).build();
380         }
381
382         for (final Entry<PlspId, PCCTunnel> entry : this.tunnels.entrySet()) {
383             final PCCTunnel tunnel = entry.getValue();
384             final long plspId = entry.getKey().getValue();
385             createLspAndSendReport(plspId, tunnel, session, Optional.absent(), Optional.fromNullable(srp));
386         }
387     }
388
389     private void reportLsp(final PlspId plspId, final SrpIdNumber operationId, final PCCSession session) {
390         final PCCTunnel tunnel = this.tunnels.get(plspId);
391         if (tunnel == null) {
392             return;
393         }
394         final Srp srp = new SrpBuilder().setOperationId(operationId).build();
395         createLspAndSendReport(plspId.getValue(), tunnel, session, Optional.of(Boolean.TRUE), Optional.of(srp));
396     }
397
398     private void sendToAll(final PCCTunnel tunnel, final PlspId plspId, final List<Subobject> subobjects, final Srp srp,
399             final Path path, final Lsp lsp) {
400         for (final PCCSession session : this.sessions.values()) {
401             final boolean isDelegated = hasDelegation(tunnel, session);
402             final Tlvs tlvs = buildTlvs(tunnel, plspId.getValue(), Optional.of(subobjects));
403
404             final Pcrpt pcRpt = createPcRtpMessage(
405                 new LspBuilder(lsp)
406                     .setPlspId(plspId)
407                     .setOperational(OperationalStatus.Up)
408                     .setDelegate(isDelegated)
409                     .setSync(true)
410                     .addAugmentation(Lsp1.class, new Lsp1Builder()
411                             .setCreate(tunnel.getType() == LspType.PCE_LSP).build())
412                     .setTlvs(tlvs).build(),
413                 Optional.fromNullable(srp), path);
414             session.sendReport(pcRpt);
415         }
416     }
417
418     private void startStateTimeout(final PCCTunnel tunnel, final PlspId plspId) {
419         if (this.stateTimeout > -1) {
420             final Timeout newStateTimeout = this.timer.newTimeout(timeout -> {
421                 if (tunnel.getType() == LspType.PCE_LSP) {
422                     PCCTunnelManagerImpl.this.tunnels.remove(plspId);
423                     //report tunnel removal to all
424                     sendToAll(tunnel, plspId, Collections.emptyList(), createSrp(0), new PathBuilder().build(),
425                         createLsp(plspId.getValue(), false, Optional.absent(), false, true));
426                 }
427             }, this.stateTimeout, TimeUnit.SECONDS);
428             tunnel.setStateTimeout(newStateTimeout);
429         }
430     }
431
432     private void startRedelegationTimer(final PCCTunnel tunnel, final PlspId plspId, final PCCSession session) {
433         final Timeout newRedelegationTimeout = this.timer.newTimeout(timeout -> {
434             //remove delegation
435             PCCTunnelManagerImpl.this.setDelegation(plspId, null);
436             //delegate to another PCE
437             int index = session.getId();
438             for (int i = 1; i < PCCTunnelManagerImpl.this.sessions.size(); i++) {
439                 index++;
440                 if (index == PCCTunnelManagerImpl.this.sessions.size()) {
441                     index = 0;
442                 }
443                 final PCCSession nextSession = PCCTunnelManagerImpl.this.sessions.get(index);
444                 if (nextSession != null) {
445                     tunnel.cancelTimeouts();
446                     final Tlvs tlvs = buildTlvs(tunnel, plspId.getValue(), Optional.absent());
447
448                     nextSession.sendReport(createPcRtpMessage(
449                         createLsp(plspId.getValue(), true, Optional.fromNullable(tlvs), true, false), NO_SRP,
450                         tunnel.getLspState()));
451                     tunnel.setDelegationHolder(nextSession.getId());
452                     break;
453                 }
454             }
455         }, this.redelegationTimeout, TimeUnit.SECONDS);
456         tunnel.setRedelegationTimeout(newRedelegationTimeout);
457     }
458
459     private void setDelegation(final PlspId plspId, final PCCSession session) {
460         final PCCTunnel tunnel = this.tunnels.get(plspId);
461         final int sessionId;
462         if (session != null) {
463             sessionId = session.getId();
464         } else {
465             sessionId = PCCTunnelBuilder.PCC_DELEGATION;
466         }
467         tunnel.setDelegationHolder(sessionId);
468     }
469
470     private static boolean hasDelegation(final PCCTunnel tunnel, final PCCSession session) {
471         final int sessionId = session.getId();
472         final int delegationHolder = tunnel.getDelegationHolder();
473         return delegationHolder == sessionId;
474     }
475
476     private static String getDestinationAddress(final List<Subobject> subobjects, final String defaultAddress) {
477         if ((subobjects != null) && !subobjects.isEmpty()) {
478             final String prefix = ((IpPrefixCase) subobjects.get(subobjects.size() - 1).getSubobjectType())
479                 .getIpPrefix().getIpPrefix().getIpv4Prefix().getValue();
480             return prefix.substring(0, prefix.indexOf('/'));
481         }
482         return defaultAddress;
483     }
484 }