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