ccf0f22eb9f17cd9548d396c2d07ffb25ec05001
[bgpcep.git] / pcep / server / server-provider / src / main / java / org / opendaylight / bgpcep / pcep / server / provider / PcepTopologyListener.java
1 /*
2  * Copyright (c) 2021 Orange. 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.server.provider;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.collect.Iterables;
13 import java.nio.ByteBuffer;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.List;
17 import java.util.stream.Collectors;
18 import org.opendaylight.mdsal.binding.api.DataBroker;
19 import org.opendaylight.mdsal.binding.api.DataObjectModification;
20 import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
21 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
22 import org.opendaylight.mdsal.binding.api.DataTreeModification;
23 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev220720.DecimalBandwidth;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev220720.Delay;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.AddressFamily;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.ComputationStatus;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.path.descriptions.PathDescription;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.path.computation.rev220324.path.descriptions.PathDescriptionBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.initiated.rev200720.Lsp1;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.OperationalStatus;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.Path1;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.identifiers.tlv.lsp.identifiers.address.family.Ipv4Case;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.identifiers.tlv.lsp.identifiers.address.family.Ipv6Case;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.identifiers.tlv.lsp.identifiers.address.family.ipv4._case.Ipv4;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.identifiers.tlv.lsp.identifiers.address.family.ipv6._case.Ipv6;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object.Lsp;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev200720.SrSubobject;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev200720.sr.subobject.nai.IpAdjacency;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.segment.routing.rev200720.sr.subobject.nai.IpNodeId;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.PathStatus;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.PathType;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.ConfiguredLsp;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.ConfiguredLspBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.ConfiguredLspKey;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.configured.lsp.ComputedPathBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.configured.lsp.IntendedPathBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.server.rev220321.pcc.configured.lsp.configured.lsp.intended.path.ConstraintsBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.explicit.route.object.Ero;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.explicit.route.object.ero.Subobject;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.lsp.attributes.Metrics;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev181109.reported.route.object.Rro;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.basic.explicit.route.subobjects.SubobjectType;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.basic.explicit.route.subobjects.subobject.type.IpPrefixCase;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.Node1;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.PccSyncState;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client.attributes.PathComputationClient;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client.attributes.path.computation.client.ReportedLsp;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.pcep.client.attributes.path.computation.client.reported.lsp.Path;
63 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
64 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
65 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
66 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
67 import org.opendaylight.yangtools.concepts.ListenerRegistration;
68 import org.opendaylight.yangtools.yang.binding.DataObject;
69 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
70 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
71 import org.opendaylight.yangtools.yang.common.Decimal64;
72 import org.opendaylight.yangtools.yang.common.Uint32;
73 import org.opendaylight.yangtools.yang.common.Uint8;
74 import org.slf4j.Logger;
75 import org.slf4j.LoggerFactory;
76
77 /**
78  * This Class listen to the PCEP Topology in order to trigger Path Manager methods to control Managed TE Path.
79  *
80  * @author Olivier Dugeon
81  */
82
83 public final class PcepTopologyListener implements DataTreeChangeListener<Node>, AutoCloseable {
84     private static final Logger LOG = LoggerFactory.getLogger(PcepTopologyListener.class);
85     private ListenerRegistration<PcepTopologyListener> listenerRegistration;
86     private final PathManagerProvider pathManager;
87
88     public PcepTopologyListener(final DataBroker dataBroker,
89             final KeyedInstanceIdentifier<Topology, TopologyKey> topology, final PathManagerProvider pathManager) {
90         requireNonNull(dataBroker);
91         requireNonNull(topology);
92         this.pathManager = requireNonNull(pathManager);
93         final InstanceIdentifier<Node> nodeTopology = topology.child(Node.class);
94         listenerRegistration = dataBroker.registerDataTreeChangeListener(
95                 DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL, nodeTopology), this);
96         LOG.info("Registered PCE Server listener {} for Operational PCEP Topology {}",
97                 listenerRegistration, topology.getKey().getTopologyId().getValue());
98     }
99
100     /**
101      * Close this Listener.
102      */
103     @Override
104     public void close() {
105         if (listenerRegistration != null) {
106             LOG.info("Unregistered PCE Server listener {} for Operational PCEP Topology", listenerRegistration);
107             listenerRegistration.close();
108             listenerRegistration = null;
109         }
110     }
111
112     /**
113      * Handle reported LSP modifications.
114      *
115      * @param nodeId    Node Identifier to which the modified children belongs to.
116      * @param lspMod    List of Reported LSP modifications.
117      */
118     private void handleLspChange(final NodeId nodeId, final List<DataObjectModification<?>> lspMod) {
119         for (DataObjectModification<?> lsp : lspMod) {
120             ReportedLsp rptLsp;
121
122             switch (lsp.getModificationType()) {
123                 case DELETE:
124                     rptLsp = (ReportedLsp) lsp.getDataBefore();
125                     LOG.debug("Un-Register Managed TE Path: {}", rptLsp.getName());
126                     pathManager.unregisterTePath(nodeId, new ConfiguredLspKey(rptLsp.getName()));
127                     break;
128                 case SUBTREE_MODIFIED:
129                 case WRITE:
130                     rptLsp = (ReportedLsp) lsp.getDataAfter();
131                     LOG.debug("Register Managed TE Path {}", rptLsp.getName());
132                     pathManager.registerTePath(nodeId,  getConfiguredLsp(rptLsp), getPathType(rptLsp));
133                     break;
134                 default:
135                     break;
136             }
137
138         }
139     }
140
141     /**
142      * Parse Sub Tree modification. Given list has been filtered to get only Path Computation Client modifications.
143      * This function first create, update or delete Managed TE Node that corresponds to the given NodeId. Then, it
144      * filter the children to retain only the reported LSP modifications.
145      *
146      * @param nodeId    Node Identifier to which the modified children belongs to.
147      * @param pccMod    List of Path Computation Client modifications.
148      */
149     private void handlePccChange(final NodeId nodeId, final List<DataObjectModification<?>> pccMod) {
150         for (DataObjectModification<?> node : pccMod) {
151             /* First, process PCC modification */
152             switch (node.getModificationType()) {
153                 case DELETE:
154                     LOG.debug("Un-Register Managed TE Node: {}", nodeId);
155                     pathManager.disableManagedTeNode(nodeId);
156                     /* Should stop here to avoid deleting later the associated Managed TE Path */
157                     return;
158                 case SUBTREE_MODIFIED:
159                 case WRITE:
160                     /* First look if the PCC was already created or not yet */
161                     if (pathManager.checkManagedTeNode(nodeId)) {
162                         /* Check if PCC State is Synchronized */
163                         if (node.getModifiedChildren() == null || node.getModifiedChildren().isEmpty()) {
164                             PathComputationClient pcc = (PathComputationClient) node.getDataAfter();
165                             if (pcc.getStateSync() == PccSyncState.Synchronized) {
166                                 LOG.debug("Synchronize Managed TE Node {}", nodeId);
167                                 pathManager.syncManagedTeNode(nodeId);
168                             }
169                             return;
170                         }
171                     } else {
172                         LOG.debug("Register new Managed TE Node {}", nodeId);
173                         pathManager.registerManagedTeNode(nodeId);
174                     }
175                     break;
176                 default:
177                     break;
178             }
179
180             /* Then, look to reported LSP modification */
181             final List<DataObjectModification<? extends DataObject>> lspMod = node.getModifiedChildren()
182                     .stream().filter(mod -> mod.getDataType().equals(ReportedLsp.class))
183                     .collect(Collectors.toList());
184             if (!lspMod.isEmpty()) {
185                 handleLspChange(nodeId, lspMod);
186             }
187         }
188     }
189
190     /**
191      * Parse Sub Tree modification. Given children list has been filtered to get only Node1 modifications.
192      * This function filter again this given list to retain only PathComputationClient modifications.
193      *
194      * @param nodeId    Node Identifier to which the modified children belongs to.
195      * @param node1Mod  List of Node1 modifications.
196      */
197     private void handleNode1Change(final NodeId nodeId, final List<DataObjectModification<?>> node1Mod) {
198         for (DataObjectModification<?> child : node1Mod) {
199             /* Then, look only to PathComputationClient.class modification */
200             final List<DataObjectModification<?>> pccMod = child.getModifiedChildren()
201                     .stream().filter(mod -> mod.getDataType().equals(PathComputationClient.class))
202                     .collect(Collectors.toList());
203             if (!pccMod.isEmpty()) {
204                 handlePccChange(nodeId, pccMod);
205             }
206         }
207     }
208
209     @Override
210     public void onDataTreeChanged(final Collection<DataTreeModification<Node>> changes) {
211         for (DataTreeModification<Node> change : changes) {
212             DataObjectModification<Node> root = change.getRootNode();
213
214             final NodeId nodeId =
215                 root.getModificationType() == DataObjectModification.ModificationType.DELETE
216                     ? root.getDataBefore().getNodeId()
217                     : root.getDataAfter().getNodeId();
218
219             /* Look only to Node1.class modification */
220             final List<DataObjectModification<?>> node1Mod = root.getModifiedChildren().stream()
221                     .filter(mod -> mod.getDataType().equals(Node1.class))
222                     .collect(Collectors.toList());
223             if (!node1Mod.isEmpty()) {
224                 handleNode1Change(nodeId, node1Mod);
225             }
226         }
227     }
228
229     /**
230      * Translate ERO Segment Routing SubOject i.e. NaiType into Path Description.
231      *
232      * @param srObj Segment Routing SubObject.
233      * @param af    Address Family, SR-IPv4 or SR-IPv6.
234      *
235      * @return      Path Description of the corresponding ERO SubObject.
236      */
237     private static PathDescription getSrPath(final SrSubobject srObj, final AddressFamily af) {
238         switch (af) {
239             case SrIpv4:
240                 switch (srObj.getNaiType()) {
241                     case Ipv4Adjacency:
242                         return new PathDescriptionBuilder()
243                             .setSid(srObj.getSid())
244                             .setIpv4(((IpAdjacency)srObj.getNai()).getLocalIpAddress().getIpv4AddressNoZone())
245                             .setRemoteIpv4(((IpAdjacency)srObj.getNai()).getRemoteIpAddress().getIpv4AddressNoZone())
246                             .build();
247                     case Ipv4NodeId:
248                         return new PathDescriptionBuilder()
249                             .setSid(srObj.getSid())
250                             .setRemoteIpv4(((IpNodeId)srObj.getNai()).getIpAddress().getIpv4AddressNoZone())
251                             .build();
252                     default:
253                         return null;
254                 }
255             case SrIpv6:
256                 switch (srObj.getNaiType()) {
257                     case Ipv6Adjacency:
258                         return new PathDescriptionBuilder()
259                             .setSid(srObj.getSid())
260                             .setIpv6(((IpAdjacency)srObj.getNai()).getLocalIpAddress().getIpv6AddressNoZone())
261                             .setRemoteIpv6(((IpAdjacency)srObj.getNai()).getRemoteIpAddress().getIpv6AddressNoZone())
262                             .build();
263                     case Ipv6NodeId:
264                         return new PathDescriptionBuilder()
265                             .setSid(srObj.getSid())
266                             .setRemoteIpv6(((IpNodeId)srObj.getNai()).getIpAddress().getIpv6AddressNoZone())
267                             .build();
268                     default:
269                         return null;
270                 }
271             default:
272                 return null;
273         }
274     }
275
276     /**
277      * Translate ERO RSVP-TE SubObject i.e. IpPrefixCase into Path Description.
278      *
279      * @param srObj Segment Routing SubObject.
280      * @param af    Address Family, SR-IPv4 or SR-IPv6.
281      *
282      * @return      Path Description of the corresponding ERO SubObject.
283      */
284     private static PathDescription getIpPath(final IpPrefixCase ipc, final AddressFamily af) {
285         switch (af) {
286             case Ipv4:
287                 return new PathDescriptionBuilder().setRemoteIpv4(
288                         new Ipv4Address(ipc.getIpPrefix().getIpPrefix().getIpv4Prefix().getValue().split("/")[0]))
289                         .build();
290             case Ipv6:
291                 return new PathDescriptionBuilder().setRemoteIpv6(
292                         new Ipv6Address(ipc.getIpPrefix().getIpPrefix().getIpv6Prefix().getValue().split("/")[0]))
293                         .build();
294             default:
295                 return null;
296         }
297     }
298
299     /**
300      * Translate RRO RSVP-TE SubObject i.e. IpPrefixCase into Path Description.
301      *
302      * @param srObj Segment Routing SubObject.
303      * @param af    Address Family, SR-IPv4 or SR-IPv6.
304      *
305      * @return      Path Description of the corresponding RRO SubObject.
306      */
307     private static PathDescription getIpPath(final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang
308             .rsvp.rev150820._record.route.subobjects.subobject.type.IpPrefixCase ipc, final AddressFamily af) {
309         switch (af) {
310             case Ipv4:
311                 return new PathDescriptionBuilder().setRemoteIpv4(
312                         new Ipv4Address(ipc.getIpPrefix().getIpPrefix().getIpv4Prefix().getValue().split("/")[0]))
313                         .build();
314             case Ipv6:
315                 return new PathDescriptionBuilder().setRemoteIpv6(
316                         new Ipv6Address(ipc.getIpPrefix().getIpPrefix().getIpv6Prefix().getValue().split("/")[0]))
317                         .build();
318             default:
319                 return null;
320         }
321     }
322
323     /**
324      * Translate Explicit Route Object (ERO) of the LSP into Path Description.
325      *
326      * @param ero   Explicit Route Object.
327      * @param af    Address Family, IPv4 or IPv6.
328      *
329      * @return      Path Description of the corresponding TE Path.
330      */
331     private static List<PathDescription> getPathDescription(final Ero ero, final AddressFamily af) {
332         final ArrayList<PathDescription> pathDesc = new ArrayList<>();
333         for (Subobject element : ero.getSubobject()) {
334             final SubobjectType sbt = element.getSubobjectType();
335             if (sbt instanceof SrSubobject) {
336                 pathDesc.add(getSrPath((SrSubobject) sbt, af));
337             } else if (sbt instanceof IpPrefixCase) {
338                 pathDesc.add(getIpPath((IpPrefixCase) sbt, af));
339             }
340         }
341         return pathDesc.isEmpty() ? null : pathDesc;
342     }
343
344     /**
345      * Translate Record Route Object (RRO) of the LSP into a Path Description.
346      *
347      * @param rro   Record Route Object of the reported LSP.
348      * @param af    Address Family, IPv4, IPv6, SR-IPv4 or SR-IPv6
349      *
350      * @return      Path Description of the corresponding TE Path.
351      */
352     private static List<PathDescription> getPathDescription(final Rro rro, final AddressFamily af) {
353         final ArrayList<PathDescription> pathDesc = new ArrayList<>();
354         for (var element : rro.nonnullSubobject()) {
355             final var sbt = element.getSubobjectType();
356             if (sbt instanceof SrSubobject) {
357                 pathDesc.add(getSrPath((SrSubobject) sbt, af));
358             } else if (sbt instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820
359                     ._record.route.subobjects.subobject.type.IpPrefixCase) {
360                 pathDesc.add(getIpPath((org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820
361                         ._record.route.subobjects.subobject.type.IpPrefixCase)sbt, af));
362             }
363         }
364         return pathDesc.isEmpty() ? null : pathDesc;
365     }
366
367     /**
368      * Build a new TE Path from a reported LSP.
369      *
370      * @param rl    Reported LSP.
371      *
372      * @return      new TE Path.
373      */
374     private static ConfiguredLsp getConfiguredLsp(final ReportedLsp rl) {
375         /* New reported LSP is always the last Path in the List i.e. old Paths are place before */
376         Path path = Iterables.getLast(rl.getPath().values());
377         Float convert;
378         ConstraintsBuilder cb = new ConstraintsBuilder();
379
380         /* Set Constraints */
381         if (path.getClassType() != null) {
382             cb.setClassType(path.getClassType().getClassType().getValue());
383         }
384         if (path.getBandwidth() != null) {
385             convert = ByteBuffer.wrap(path.getBandwidth().getBandwidth().getValue()).getFloat();
386             cb.setBandwidth(new DecimalBandwidth(Decimal64.valueOf(2, convert.longValue())));
387         }
388         if ((cb.getBandwidth() == null || cb.getBandwidth().getValue().equals(Decimal64.valueOf(2, 0)))
389                 && path.getReoptimizationBandwidth() != null) {
390             convert = ByteBuffer.wrap(path.getReoptimizationBandwidth().getBandwidth().getValue()).getFloat();
391             cb.setBandwidth(new DecimalBandwidth(Decimal64.valueOf(2, convert.longValue())));
392         }
393         if (path.getMetrics() != null) {
394             for (Metrics metric: path.getMetrics()) {
395                 convert = ByteBuffer.wrap(metric.getMetric().getValue().getValue()).getFloat();
396                 switch (metric.getMetric().getMetricType().intValue()) {
397                     case MessagesUtil.IGP_METRIC:
398                         cb.setMetric(Uint32.valueOf(convert.longValue()));
399                         break;
400                     case MessagesUtil.TE_METRIC:
401                         cb.setTeMetric(Uint32.valueOf(convert.longValue()));
402                         break;
403                     case MessagesUtil.PATH_DELAY:
404                         cb.setDelay(new Delay(Uint32.valueOf(convert.longValue())));
405                         break;
406                     default:
407                         break;
408                 }
409             }
410         }
411
412         /* Get Source and Destination addresses and family */
413         if (path.augmentations() == null) {
414             return null;
415         }
416         final Path1 p1 = path.augmentation(Path1.class);
417         final Uint8 pst = p1.getPathSetupType() != null ? p1.getPathSetupType().getPst() : Uint8.ZERO;
418         final Lsp lsp = p1.getLsp();
419         final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp
420             .identifiers.tlv.lsp.identifiers.AddressFamily af = lsp.getTlvs().getLspIdentifiers().getAddressFamily();
421         IpAddress source = null;
422         IpAddress destination = null;
423         if (af instanceof Ipv4Case) {
424             final Ipv4 ipv4 = ((Ipv4Case) af).getIpv4();
425             source = new IpAddress(ipv4.getIpv4TunnelSenderAddress());
426             destination = new IpAddress(ipv4.getIpv4TunnelEndpointAddress());
427             cb.setAddressFamily(pst == Uint8.ZERO ? AddressFamily.Ipv4 : AddressFamily.SrIpv4);
428         } else if (af instanceof Ipv6Case) {
429             final Ipv6 ipv6 = ((Ipv6Case) af).getIpv6();
430             source = new IpAddress(ipv6.getIpv6TunnelSenderAddress());
431             destination = new IpAddress(ipv6.getIpv6TunnelSenderAddress());
432             cb.setAddressFamily(pst == Uint8.ZERO ? AddressFamily.Ipv6 : AddressFamily.SrIpv6);
433         } else {
434             return null;
435         }
436
437         /* Build Intended Path */
438         final IntendedPathBuilder ipb = new IntendedPathBuilder()
439                 .setSource(source)
440                 .setDestination(destination)
441                 .setConstraints(cb.build());
442
443         /* Get a Valid Path Description for this TePath if any */
444         List<PathDescription> pathDesc = null;
445         if (path.getEro() != null
446                 && path.getEro().getSubobject() != null
447                 && path.getEro().getSubobject().size() > 0) {
448             pathDesc = getPathDescription(path.getEro(), cb.getAddressFamily());
449         }
450         if (pathDesc == null
451                 && path.getRro() != null
452                 && path.getRro().getSubobject() != null
453                 && path.getRro().getSubobject().size() > 0) {
454             pathDesc = getPathDescription(path.getRro(), cb.getAddressFamily());
455         }
456
457         ConfiguredLspBuilder clb =
458             new ConfiguredLspBuilder()
459                 .setName(rl.getName())
460                 .setPathStatus(PathStatus.Reported)
461                 .setIntendedPath(ipb.build());
462
463         /* Finally Build Actual Path and TE Path */
464         if (pathDesc == null) {
465             return clb.setComputedPath(
466                     new ComputedPathBuilder().setComputationStatus(ComputationStatus.Failed).build())
467                 .build();
468         }
469         return clb.setComputedPath(
470                 new ComputedPathBuilder()
471                     .setPathDescription(pathDesc)
472                     .setComputationStatus(
473                         lsp.getOperational() == OperationalStatus.Down
474                             ? ComputationStatus.Failed
475                             : ComputationStatus.Completed)
476                     .build())
477             .build();
478     }
479
480     /**
481      * get Path Type from a reported LSP.
482      *
483      * @param rl    Reported LSP.
484      *
485      * @return      Path Type.
486      */
487     private static PathType getPathType(final ReportedLsp rl) {
488         /* New reported LSP is always the last Path in the List i.e. old Paths are place before */
489         final Path1 p1 = Iterables.getLast(rl.getPath().values()).augmentation(Path1.class);
490         if (!p1.getLsp().getDelegate()) {
491             return PathType.Pcc;
492         }
493         final Lsp1 lspCreateFlag = p1.getLsp().augmentation(Lsp1.class);
494         if (lspCreateFlag == null || !lspCreateFlag.getCreate()) {
495             return PathType.Delegated;
496         }
497         return PathType.Initiated;
498     }
499
500 }
501