Path Computation Server
[bgpcep.git] / bgp / topology-provider / src / main / java / org / opendaylight / bgpcep / bgp / topology / provider / LinkstateGraphBuilder.java
1 /*
2  * Copyright (c) 2020 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.bgp.topology.provider;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.annotations.VisibleForTesting;
13 import com.google.common.base.Preconditions;
14 import java.math.BigDecimal;
15 import java.net.Inet4Address;
16 import java.net.Inet6Address;
17 import java.net.UnknownHostException;
18 import java.nio.ByteBuffer;
19 import java.util.ArrayList;
20 import java.util.List;
21 import org.opendaylight.graph.ConnectedGraph;
22 import org.opendaylight.graph.ConnectedGraphProvider;
23 import org.opendaylight.mdsal.binding.api.DataBroker;
24 import org.opendaylight.mdsal.binding.api.ReadWriteTransaction;
25 import org.opendaylight.protocol.bgp.rib.RibReference;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.LinkstateAddressFamily;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.LinkstateSubsequentAddressFamily;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.bgp.rib.rib.loc.rib.tables.routes.LinkstateRoutesCase;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.ObjectType;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.attribute.SrAdjIds;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.LinkCase;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.NodeCase;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.PrefixCase;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.link._case.LinkDescriptors;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.LinkStateAttribute;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.LinkAttributesCase;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.NodeAttributesCase;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.PrefixAttributesCase;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.link.attributes._case.LinkAttributes;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.node.attributes._case.NodeAttributes;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.prefix.attributes._case.PrefixAttributes;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.routes.LinkstateRoutes;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.routes.linkstate.routes.LinkstateRoute;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.routes.linkstate.routes.linkstate.route.Attributes1;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.node.identifier.CRouterIdentifier;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.node.identifier.c.router.identifier.IsisNodeCase;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.node.identifier.c.router.identifier.OspfNodeCase;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.Attributes;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.adj.flags.flags.isis.adj.flags._case.IsisAdjFlags;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.adj.flags.flags.ospf.adj.flags._case.OspfAdjFlags;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.prefix.sid.tlv.flags.IsisPrefixFlagsCase;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.sid.label.index.sid.label.index.LocalLabelCase;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.sid.label.index.sid.label.index.SidCase;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.DecimalBandwidth;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.Delay;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.Loss;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.Vertex.VertexType;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.edge.EdgeAttributes;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.edge.EdgeAttributesBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.edge.attributes.MinMaxDelay;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.edge.attributes.MinMaxDelayBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.edge.attributes.UnreservedBandwidth;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.edge.attributes.UnreservedBandwidthBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.edge.attributes.UnreservedBandwidthKey;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.Graph.DomainScope;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Edge;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.EdgeBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.EdgeKey;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Prefix;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.PrefixBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Vertex;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.VertexBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.VertexKey;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.vertex.SrgbBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.Bandwidth;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.topology.types.rev160524.TopologyTypes1;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.topology.types.rev160524.TopologyTypes1Builder;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.topology.types.rev160524.bgp.linkstate.topology.type.BgpLinkstateTopologyBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.SrlgId;
87 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
88 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypes;
89 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypesBuilder;
90 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
91 import org.opendaylight.yangtools.yang.common.Uint32;
92 import org.opendaylight.yangtools.yang.common.Uint64;
93 import org.slf4j.Logger;
94 import org.slf4j.LoggerFactory;
95
96 /**
97  * This Class build the Traffic Engineering Database as a Connected Graph
98  * suitable to be used latter by Path Computation algorithms to compute end to
99  * end path.
100  *
101  * @author Olivier Dugeon
102  * @author Philippe Niger
103  *
104  */
105
106 public class LinkstateGraphBuilder extends AbstractTopologyBuilder<LinkstateRoute> {
107     private static final TopologyTypes LINKSTATE_TOPOLOGY_TYPE = new TopologyTypesBuilder().addAugmentation(
108             TopologyTypes1.class,
109             new TopologyTypes1Builder().setBgpLinkstateTopology(new BgpLinkstateTopologyBuilder().build()).build())
110             .build();
111
112     private static final String UNHANDLED_OBJECT_CLASS = "Unhandled object class {}";
113
114     private static final Logger LOG = LoggerFactory.getLogger(LinkstateGraphBuilder.class);
115
116     private ConnectedGraphProvider graphProvider;
117     private ConnectedGraph cgraph;
118
119     public LinkstateGraphBuilder(final DataBroker dataProvider, final RibReference locRibReference,
120             final TopologyId topologyId, ConnectedGraphProvider provider) {
121         super(dataProvider, locRibReference, topologyId, LINKSTATE_TOPOLOGY_TYPE, LinkstateAddressFamily.class,
122                 LinkstateSubsequentAddressFamily.class);
123         this.graphProvider = requireNonNull(provider);
124         this.cgraph = provider.createConnectedGraph("ted://" + topologyId.getValue(),
125                 DomainScope.IntraDomain);
126         /* LinkStateGraphBuilder doesn't write information in the Network Topology tree of the Data Store.
127          * This is performed by ConnectedGraphProvider which write element in Graph tree of the Data Store */
128         this.networkTopologyTransaction = false;
129         LOG.info("Started Traffic Engineering Graph Builder");
130     }
131
132     @VisibleForTesting
133     LinkstateGraphBuilder(final DataBroker dataProvider, final RibReference locRibReference,
134             final TopologyId topologyId, ConnectedGraphProvider provider, final long listenerResetLimitInMillsec,
135             final int listenerResetEnforceCounter) {
136         super(dataProvider, locRibReference, topologyId, LINKSTATE_TOPOLOGY_TYPE, LinkstateAddressFamily.class,
137                 LinkstateSubsequentAddressFamily.class, listenerResetLimitInMillsec, listenerResetEnforceCounter);
138         this.graphProvider = requireNonNull(provider);
139         this.cgraph = provider.createConnectedGraph("ted://" + topologyId.getValue(),
140                 DomainScope.IntraDomain);
141         /* LinkStateGraphBuilder doesn't write information in the Network Topology tree of the Data Store.
142          * This is performed by ConnectedGraphProvider which write element in Graph tree of the Data Store */
143         this.networkTopologyTransaction = false;
144         LOG.info("Started Traffic Engineering Graph Builder");
145     }
146
147     @Override
148     protected void createObject(final ReadWriteTransaction trans, final InstanceIdentifier<LinkstateRoute> id,
149             final LinkstateRoute value) {
150         final ObjectType t = value.getObjectType();
151         Preconditions.checkArgument(t != null, "Route %s value %s has null object type", id, value);
152
153         if (t instanceof LinkCase) {
154             createEdge(value, (LinkCase) t, value.getAttributes());
155         } else if (t instanceof NodeCase) {
156             createVertex(value, (NodeCase) t, value.getAttributes());
157         } else if (t instanceof PrefixCase) {
158             createPrefix(value, (PrefixCase) t, value.getAttributes());
159         } else {
160             LOG.debug(UNHANDLED_OBJECT_CLASS, t.implementedInterface());
161         }
162     }
163
164     /**
165      * Verify that mandatory information (Local & Remote Node and Link
166      * descriptors) are present in the link.
167      *
168      * @param linkCase  The Link part of the Linkstate route
169      *
170      * @return True if all information are present, false otherwise
171      */
172     private boolean checkLinkState(final LinkCase linkCase) {
173         if (linkCase.getLocalNodeDescriptors() == null || linkCase.getRemoteNodeDescriptors() == null) {
174             LOG.warn("Missing Local or Remote Node descriptor in link {}, skipping it", linkCase);
175             return false;
176         }
177         if (linkCase.getLinkDescriptors() == null) {
178             LOG.warn("Missing Link descriptor in link {}, skipping it", linkCase);
179             return false;
180         }
181         return true;
182     }
183
184     /**
185      * Get Link attributes from the Link State route.
186      *
187      * @param attributes  Link State Route Attributes
188      *
189      * @return Link Attributes
190      */
191     private LinkAttributes getLinkAttributes(final Attributes attributes) {
192         final LinkAttributes la;
193         final Attributes1 attr = attributes.augmentation(Attributes1.class);
194         if (attr != null) {
195             final LinkStateAttribute attrType = attr.getLinkStateAttribute();
196             if (attrType != null) {
197                 la = ((LinkAttributesCase) attrType).getLinkAttributes();
198             } else {
199                 return null;
200             }
201         } else {
202             return null;
203         }
204         return la;
205     }
206
207     /**
208      * Determine the Source Edge Key from the link descriptor.
209      * There is several case: IPv4, IPv6 address or Unnumbered Interface.
210      *
211      * @param linkCase The Link part of the Linkstate route
212      *
213      * @return Unique key
214      */
215     private Uint64 getEdgeId(LinkCase linkCase) {
216         long key = 0;
217         if (linkCase.getLinkDescriptors().getIpv4InterfaceAddress() != null) {
218             key = ipv4ToKey(linkCase.getLinkDescriptors().getIpv4InterfaceAddress().getValue());
219         }
220         if (linkCase.getLinkDescriptors().getIpv6InterfaceAddress() != null) {
221             key = ipv6ToKey(linkCase.getLinkDescriptors().getIpv6InterfaceAddress().getValue());
222         }
223         if (linkCase.getLinkDescriptors().getLinkLocalIdentifier() != null) {
224             key = linkCase.getLinkDescriptors().getLinkLocalIdentifier().longValue();
225         }
226         return Uint64.valueOf(key);
227     }
228
229     /**
230      * Create new Connected Edge in the Connected Graph.
231      *
232      * @param value       The complete Linkstate route information
233      * @param linkCase    The Link part of the Linkstate route
234      * @param attributes  The Link attributes
235      *
236      */
237     private void createEdge(final LinkstateRoute value, final LinkCase linkCase, final Attributes attributes) {
238         Preconditions.checkArgument(checkLinkState(linkCase), "Missing mandatory information in link {}", linkCase);
239
240         final LinkAttributes la = getLinkAttributes(attributes);
241         if (la == null) {
242             LOG.warn("Missing attributes in link {} route {}, skipping it", linkCase, value);
243             return;
244         }
245
246         /* Get Source and Destination Vertex from the graph */
247         Uint64 srcId = getVertexId(linkCase.getLocalNodeDescriptors().getCRouterIdentifier());
248         Uint64 dstId = getVertexId(linkCase.getRemoteNodeDescriptors().getCRouterIdentifier());
249         if (srcId == Uint64.ZERO || dstId == Uint64.ZERO) {
250             LOG.warn("Unable to get the Source or Destination Vertex Identifier from link {}, skipping it", linkCase);
251             return;
252         }
253
254         /* Get Source and Destination Key for the corresponding Edge */
255         Uint64 edgeId = getEdgeId(linkCase);
256         if (edgeId == Uint64.ZERO) {
257             LOG.warn("Unable to get the Edge Identifier from link {}, skipping it", linkCase);
258             return;
259         }
260
261         /* Add associated Edge */
262         Edge edge = new EdgeBuilder().setEdgeId(edgeId).setLocalVertexId(srcId).setRemoteVertexId(dstId)
263                 .setName(srcId + " - " + dstId)
264                 .setEdgeAttributes(createEdgeAttributes(la, linkCase.getLinkDescriptors())).build();
265
266         /*
267          * Add corresponding Prefix for the Local Address. Remote address will be added with the remote Edge */
268         PrefixBuilder prefBuilder = new PrefixBuilder().setVertexId(srcId);
269         if (edge.getEdgeAttributes().getLocalAddress().getIpv4Address() != null) {
270             prefBuilder.setPrefix(new IpPrefix(
271                     new Ipv4Prefix(edge.getEdgeAttributes().getLocalAddress().getIpv4Address().getValue() + "/32")));
272         }
273         if (edge.getEdgeAttributes().getLocalAddress().getIpv6Address() != null) {
274             prefBuilder.setPrefix(new IpPrefix(
275                     new Ipv6Prefix(edge.getEdgeAttributes().getLocalAddress().getIpv6Address().getValue() + "/128")));
276         }
277         Prefix prefix = prefBuilder.build();
278
279         /* Add the Edge in the Connected Graph */
280         LOG.info("Add Edge {} and associated Prefix {} in TED[{}]", edge.getName(), prefix.getPrefix(), cgraph);
281         cgraph.addEdge(edge);
282         cgraph.addPrefix(prefix);
283     }
284
285     /**
286      * Create Edge Attributes from Link attributes.
287      *
288      * @param la         Linkstate Attributes
289      * @param linkDesc   Linkstate Descriptors
290      *
291      * @return EdgeAttributes
292      */
293     private static final int MAX_PRIORITY = 8;
294
295     private EdgeAttributes createEdgeAttributes(LinkAttributes la, final LinkDescriptors linkDesc) {
296         EdgeAttributesBuilder builder = new EdgeAttributesBuilder();
297
298         if (linkDesc.getIpv4InterfaceAddress() != null) {
299             builder.setLocalAddress(new IpAddress(new Ipv4Address(linkDesc.getIpv4InterfaceAddress())));
300         }
301         if (linkDesc.getIpv6InterfaceAddress() != null) {
302             builder.setLocalAddress(new IpAddress(new Ipv6Address(linkDesc.getIpv6InterfaceAddress())));
303         }
304         if (linkDesc.getIpv4NeighborAddress() != null) {
305             builder.setRemoteAddress(new IpAddress(new Ipv4Address(linkDesc.getIpv4NeighborAddress())));
306         }
307         if (linkDesc.getIpv6NeighborAddress() != null) {
308             builder.setRemoteAddress(new IpAddress(new Ipv6Address(linkDesc.getIpv6NeighborAddress())));
309         }
310         if (linkDesc.getLinkLocalIdentifier() != null) {
311             builder.setLocalIdentifier(linkDesc.getLinkLocalIdentifier());
312         }
313         if (linkDesc.getLinkRemoteIdentifier() != null) {
314             builder.setRemoteIdentifier(linkDesc.getLinkRemoteIdentifier());
315         }
316         if (la.getMetric() != null) {
317             builder.setMetric(la.getMetric().getValue());
318         }
319         if (la.getTeMetric() != null) {
320             builder.setTeMetric(la.getTeMetric().getValue());
321         }
322         if (la.getMaxLinkBandwidth() != null) {
323             builder.setMaxLinkBandwidth(bandwithToDecimalBandwidth(la.getMaxLinkBandwidth()));
324         }
325         if (la.getMaxReservableBandwidth() != null) {
326             builder.setMaxResvLinkBandwidth(bandwithToDecimalBandwidth(la.getMaxReservableBandwidth()));
327         }
328         if (la.getUnreservedBandwidth() != null) {
329             int upperBound = Math.min(la.getUnreservedBandwidth().size(), MAX_PRIORITY);
330             final List<UnreservedBandwidth> unRsvBw = new ArrayList<>(upperBound);
331
332             for (final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120
333                     .UnreservedBandwidth bandwidth : la.getUnreservedBandwidth()) {
334                 unRsvBw.add(new UnreservedBandwidthBuilder()
335                         .setBandwidth(bandwithToDecimalBandwidth(bandwidth.getBandwidth()))
336                         .withKey(new UnreservedBandwidthKey(bandwidth.getPriority())).build());
337             }
338             builder.setUnreservedBandwidth(unRsvBw);
339         }
340         if (la.getAdminGroup() != null) {
341             builder.setAdminGroup(la.getAdminGroup().getValue());
342         }
343         if (la.getLinkDelay() != null) {
344             builder.setDelay(new Delay(la.getLinkDelay().getValue()));
345         }
346         if (la.getLinkMinMaxDelay() != null && la.getLinkMinMaxDelay() != null) {
347             MinMaxDelay mmDelay = new MinMaxDelayBuilder()
348                     .setMaxDelay(new Delay(la.getLinkMinMaxDelay().getMaxDelay().getValue()))
349                     .setMinDelay(new Delay(la.getLinkMinMaxDelay().getMinDelay().getValue())).build();
350             builder.setMinMaxDelay(mmDelay);
351         }
352         if (la.getDelayVariation() != null) {
353             builder.setJitter(new Delay(la.getDelayVariation().getValue()));
354         }
355         if (la.getLinkLoss() != null) {
356             builder.setLoss(new Loss(la.getLinkLoss().getValue()));
357         }
358         if (la.getAvailableBandwidth() != null) {
359             builder.setAvailableBandwidth(bandwithToDecimalBandwidth(la.getAvailableBandwidth()));
360         }
361         if (la.getResidualBandwidth() != null) {
362             builder.setResidualBandwidth(bandwithToDecimalBandwidth(la.getResidualBandwidth()));
363         }
364         if (la.getUtilizedBandwidth() != null) {
365             builder.setUtilizedBandwidth(bandwithToDecimalBandwidth(la.getUtilizedBandwidth()));
366         }
367         if (la.getSharedRiskLinkGroups() != null) {
368             List<Uint32> srlgs = new ArrayList<Uint32>();
369             for (SrlgId srlg : la.getSharedRiskLinkGroups()) {
370                 srlgs.add(srlg.getValue());
371             }
372             builder.setSrlgs(srlgs);
373         }
374         if (la.getSrAdjIds() != null) {
375             for (SrAdjIds adj : la.getSrAdjIds()) {
376                 if (adj.getSidLabelIndex() instanceof LocalLabelCase) {
377                     boolean backup = false;
378                     if (adj.getFlags() instanceof OspfAdjFlags) {
379                         backup = ((OspfAdjFlags) adj.getFlags()).isBackup();
380                     }
381                     if (adj.getFlags() instanceof IsisAdjFlags) {
382                         backup = ((IsisAdjFlags) adj.getFlags()).isBackup();
383                     }
384                     if (!backup) {
385                         builder.setAdjSid(((LocalLabelCase) adj.getSidLabelIndex()).getLocalLabel().getValue());
386                     } else {
387                         builder.setBackupAdjSid(((LocalLabelCase) adj.getSidLabelIndex()).getLocalLabel().getValue());
388                     }
389                 }
390             }
391         }
392         return builder.build();
393     }
394
395     /**
396      * Get Node Attributes from Link State Route attributes.
397      *
398      * @param attributes  The attribute part from the Link State route
399      *
400      * @return Node Attributes
401      */
402     private NodeAttributes getNodeAttributes(final Attributes attributes) {
403         final NodeAttributes na;
404         final Attributes1 attr = attributes.augmentation(Attributes1.class);
405         if (attr != null) {
406             final LinkStateAttribute attrType = attr.getLinkStateAttribute();
407             if (attrType != null) {
408                 na = ((NodeAttributesCase) attrType).getNodeAttributes();
409             } else {
410                 return null;
411             }
412         } else {
413             return null;
414         }
415         return na;
416     }
417
418     /**
419      * Create Vertex from the Node Attributes.
420      *
421      * @param na       Node Attributes
422      * @param cvertex  Connected Vertex associated to this Vertex
423      * @param as       As number
424      *
425      * @return New Vertex
426      */
427     private Vertex getVertex(NodeAttributes na, Uint64 id, int as) {
428         VertexBuilder builder = new VertexBuilder().setVertexId(id).setAsn(Uint32.valueOf(as));
429         if (na.getIpv4RouterId() != null) {
430             builder.setRouterId(new IpAddress(new Ipv4Address(na.getIpv4RouterId().getValue())));
431         }
432         if (na.getIpv6RouterId() != null) {
433             builder.setRouterId(new IpAddress(new Ipv6Address(na.getIpv6RouterId().getValue())));
434         }
435         /*
436          * Set Router Name with dynamic hostname (IS-IS) or IPv4 address in dot decimal format (OSPF)
437          */
438         if (na.getDynamicHostname() != null) {
439             builder.setName(na.getDynamicHostname());
440         } else {
441             int key = id.intValue();
442             builder.setName(
443                     ((key << 24) & 0xFF) + "." + ((key << 16) & 0xFF) + "." + ((key << 8) & 0xFF) + "." + (key & 0xFF));
444         }
445         if (na.getSrCapabilities() != null) {
446             builder.setSrgb(new SrgbBuilder()
447                     .setLowerBound(
448                             ((LocalLabelCase) na.getSrCapabilities().getSidLabelIndex()).getLocalLabel().getValue())
449                     .setRangeSize(na.getSrCapabilities().getRangeSize().getValue())
450                     .build());
451         }
452         if (na.getNodeFlags() != null) {
453             if (na.getNodeFlags().isAbr()) {
454                 builder.setVertexType(VertexType.Abr);
455             }
456             if (na.getNodeFlags().isExternal()) {
457                 builder.setVertexType(VertexType.AsbrOut);
458             }
459         } else {
460             builder.setVertexType(VertexType.Standard);
461         }
462         return builder.build();
463     }
464
465     /**
466      * Create new Connected Vertex in the Connected Graph.
467      *
468      * @param value       The complete Linkstate route information
469      * @param nodeCase    The node part of the Linkstate route
470      * @param attributes  The node attributes
471      */
472     private void createVertex(final LinkstateRoute value, final NodeCase nodeCase, final Attributes attributes) {
473         Preconditions.checkArgument(nodeCase != null, "Missing Node Case. Skip this Node");
474         Preconditions.checkArgument(nodeCase.getNodeDescriptors() != null, "Missing Node Descriptors. Skip this Node");
475
476         Uint64 vertexId = getVertexId(nodeCase.getNodeDescriptors().getCRouterIdentifier());
477         if (vertexId == Uint64.ZERO) {
478             LOG.warn("Unable to get Vertex Identifier from descriptor {}, skipping it", nodeCase.getNodeDescriptors());
479             return;
480         }
481
482         NodeAttributes na = getNodeAttributes(attributes);
483         if (na == null) {
484             LOG.warn("Missing attributes in node {} route {}, skipping it", nodeCase, value);
485             return;
486         }
487
488         int asNumber = 0;
489         if (nodeCase.getNodeDescriptors() != null) {
490             asNumber = nodeCase.getNodeDescriptors().getAsNumber().getValue().intValue();
491         }
492         Vertex vertex = getVertex(na, vertexId, asNumber);
493
494         /* Add the Connected Vertex and associated Vertex in the Graph */
495         LOG.info("Add Vertex {} in TED[{}]", vertex.getName(), cgraph);
496         cgraph.addVertex(vertex);
497     }
498
499     /**
500      * Create new Prefix in the Connected Graph.
501      *
502      * @param value       The complete Linkstate route information
503      * @param prefixCase  The Prefix part of the Linkstate route
504      * @param attributes  The Prefix attributes
505      */
506     private void createPrefix(final LinkstateRoute value, final PrefixCase prefixCase, final Attributes attributes) {
507         final IpPrefix ippfx = prefixCase.getPrefixDescriptors().getIpReachabilityInformation();
508         if (ippfx == null) {
509             LOG.warn("IP reachability not present in prefix {} route {}, skipping it", prefixCase, value);
510             return;
511         }
512
513         /* Verify that all mandatory information are present */
514         final PrefixAttributes pa;
515         final Attributes1 attr = attributes.augmentation(Attributes1.class);
516         if (attr != null) {
517             final LinkStateAttribute attrType = attr.getLinkStateAttribute();
518             if (attrType != null) {
519                 pa = ((PrefixAttributesCase) attrType).getPrefixAttributes();
520             } else {
521                 LOG.warn("Missing attribute type in IP {} prefix {} route {}, skipping it", ippfx, prefixCase, value);
522                 return;
523             }
524         } else {
525             LOG.warn("Missing attributes in IP {} prefix {} route {}, skipping it", ippfx, prefixCase, value);
526             return;
527         }
528
529         /*
530          * Get Connected Vertex from Connected Graph corresponding to the
531          * Advertising Node Descriptor
532          */
533         Uint64 vertexId = getVertexId(prefixCase.getAdvertisingNodeDescriptors().getCRouterIdentifier());
534         if (vertexId == Uint64.ZERO) {
535             LOG.warn("Unable to get the Vertex Identifier from descriptor {}, skipping it",
536                     prefixCase.getAdvertisingNodeDescriptors());
537             return;
538         }
539
540         /* Create Prefix */
541         PrefixBuilder builder = new PrefixBuilder().setVertexId(vertexId);
542         if (pa.getSrPrefix() != null && pa.getSrPrefix().getSidLabelIndex() instanceof SidCase) {
543             builder.setPrefixSid(((SidCase) pa.getSrPrefix().getSidLabelIndex()).getSid());
544             if (pa.getSrPrefix().getFlags() instanceof IsisPrefixFlagsCase) {
545                 builder.setNodeSid(
546                         ((IsisPrefixFlagsCase) pa.getSrPrefix().getFlags()).getIsisPrefixFlags().isNodeSid());
547             } else {
548                 /*
549                  * Seems that OSPF Flags are not accessible. Assuming that the
550                  * Prefix is a Node SID
551                  */
552                 builder.setNodeSid(true);
553             }
554         }
555         if (ippfx.getIpv4Prefix() != null) {
556             builder.setPrefix(new IpPrefix(ippfx.getIpv4Prefix()));
557         }
558         if (ippfx.getIpv6Prefix() != null) {
559             builder.setPrefix(new IpPrefix(ippfx.getIpv6Prefix()));
560         }
561         Prefix prefix = builder.build();
562
563         /* Add the Prefix to the Connected Vertex within the Connected Graph */
564         LOG.info("Add prefix {} in TED[{}]", builder.getPrefix(), cgraph);
565         cgraph.addPrefix(prefix);
566     }
567
568     @Override
569     protected void removeObject(final ReadWriteTransaction trans, final InstanceIdentifier<LinkstateRoute> id,
570             final LinkstateRoute value) {
571         if (value == null) {
572             LOG.error("Empty before-data received in delete data change notification for instance id {}", id);
573             return;
574         }
575
576         final ObjectType t = value.getObjectType();
577         if (t instanceof LinkCase) {
578             removeEdge((LinkCase) t);
579         } else if (t instanceof NodeCase) {
580             removeVertex((NodeCase) t);
581         } else if (t instanceof PrefixCase) {
582             removePrefix((PrefixCase) t);
583         } else {
584             LOG.debug(UNHANDLED_OBJECT_CLASS, t.implementedInterface());
585         }
586     }
587
588     private void removeEdge(LinkCase linkCase) {
589         /* Get Source and Destination Connected Vertex */
590         if (linkCase.getLinkDescriptors() == null) {
591             LOG.warn("Missing Link descriptor in link {}, skipping it", linkCase);
592             return;
593         }
594         EdgeKey edgeKey = new EdgeKey(getEdgeId(linkCase));
595         if ((edgeKey == null) || (edgeKey.getEdgeId() == Uint64.ZERO)) {
596             LOG.warn("Unable to get the Edge Key from link {}, skipping it", linkCase);
597             return;
598         }
599
600         LOG.info("Deleted Edge {} from TED[{}]", edgeKey, cgraph);
601         cgraph.deleteEdge(edgeKey);
602     }
603
604     private void removeVertex(NodeCase nodeCase) {
605         VertexKey vertexKey = new VertexKey(getVertexId(nodeCase.getNodeDescriptors().getCRouterIdentifier()));
606         if ((vertexKey == null) || (vertexKey.getVertexId() == Uint64.ZERO)) {
607             LOG.warn("Unable to get Vertex Key from descriptor {}, skipping it", nodeCase.getNodeDescriptors());
608             return;
609         }
610
611         LOG.info("Deleted Vertex {} in TED[{}]", vertexKey, cgraph);
612         cgraph.deleteVertex(vertexKey);
613     }
614
615     private void removePrefix(PrefixCase prefixCase) {
616         final IpPrefix ippfx = prefixCase.getPrefixDescriptors().getIpReachabilityInformation();
617         if (ippfx == null) {
618             LOG.warn("IP reachability not present in prefix {}, skipping it", prefixCase);
619             return;
620         }
621
622         LOG.info("Deleted prefix {} in TED[{}]", ippfx, cgraph);
623         cgraph.deletePrefix(ippfx);
624     }
625
626     /**
627      * Get Vertex in the Graph by the OSPF Router ID or IS-IS-System ID.
628      *
629      * @param routerID  The Router Identifier entry
630      *
631      * @return Vertex in the Connected Graph that corresponds to this Router ID. Vertex is created if not found.
632      */
633     private Uint64 getVertexId(CRouterIdentifier routerID) {
634         Long rid = 0L;
635
636         if (routerID instanceof IsisNodeCase) {
637             byte[] isoId = ((IsisNodeCase) routerID).getIsisNode().getIsoSystemId().getValue();
638             final byte[] convert =  {0, 0, isoId[0], isoId[1], isoId[2], isoId[3], isoId[4], isoId[5]};
639             rid = ByteBuffer.wrap(convert).getLong();
640         }
641         if (routerID instanceof OspfNodeCase) {
642             rid = ((OspfNodeCase) routerID).getOspfNode().getOspfRouterId().longValue();
643         }
644
645         LOG.debug("Get Vertex Identifier {}", rid);
646         return Uint64.valueOf(rid);
647     }
648
649     private DecimalBandwidth bandwithToDecimalBandwidth(Bandwidth bw) {
650         return new DecimalBandwidth(BigDecimal.valueOf(ByteBuffer.wrap(bw.getValue()).getFloat()));
651     }
652
653     private long ipv4ToKey(String str) {
654         byte[] ip;
655         try {
656             ip = ((Inet4Address) Inet4Address.getByName(str)).getAddress();
657         } catch (UnknownHostException e) {
658             return 0;
659         }
660         return (((0xFF & ip[0]) << 24) | ((0xFF & ip[1]) << 16) | ((0xFF & ip[2]) << 8) | (0xFF & ip[3]));
661     }
662
663     private Long ipv6ToKey(String str) {
664         byte[] ip;
665         try {
666             ip = ((Inet6Address) Inet6Address.getByName(str)).getAddress();
667         } catch (UnknownHostException e) {
668             return 0L;
669         }
670         /* Keep only the lower 64bits from the IP address */
671         byte[] lowerIP = {ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]};
672         return ByteBuffer.wrap(lowerIP).getLong();
673     }
674
675     @Override
676     protected InstanceIdentifier<LinkstateRoute> getRouteWildcard(final InstanceIdentifier<Tables> tablesId) {
677         return tablesId.child(LinkstateRoutesCase.class, LinkstateRoutes.class).child(LinkstateRoute.class);
678     }
679
680     @Override
681     protected void clearTopology() {
682         cgraph.clear();
683     }
684
685 }