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