b141b4b6a91bf968e9e60488635ff3ec9e2a51f6
[bgpcep.git] / bgp / topology-provider / src / main / java / org / opendaylight / bgpcep / bgp / topology / provider / LinkstateTopologyBuilder.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 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 com.google.common.collect.Collections2;
15 import com.google.common.collect.Lists;
16 import java.util.ArrayList;
17 import java.util.HashMap;
18 import java.util.HashSet;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22 import org.opendaylight.mdsal.binding.api.DataBroker;
23 import org.opendaylight.mdsal.binding.api.ReadWriteTransaction;
24 import org.opendaylight.mdsal.binding.api.WriteTransaction;
25 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
26 import org.opendaylight.protocol.bgp.rib.RibReference;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.DomainName;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.Ipv4InterfaceIdentifier;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.Ipv6InterfaceIdentifier;
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.TopologyIdentifier;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.bgp.rib.rib.loc.rib.tables.routes.LinkstateRoutesCase;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.ObjectType;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.attribute.SrAdjIds;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.LinkCase;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.NodeCase;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.PrefixCase;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.link._case.LinkDescriptors;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.LinkStateAttribute;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.LinkAttributesCase;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.NodeAttributesCase;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.path.attribute.link.state.attribute.PrefixAttributesCase;
46 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;
47 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;
48 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;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.routes.LinkstateRoutes;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.routes.linkstate.routes.LinkstateRoute;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.routes.linkstate.routes.linkstate.route.Attributes1;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.prefix.state.SrPrefix;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.Attributes;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.prefix.sid.tlv.Flags;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.prefix.sid.tlv.flags.IsisPrefixFlagsCase;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.sid.label.index.SidLabelIndex;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.sid.label.index.sid.label.index.LocalLabelCase;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.sid.label.index.sid.label.index.SidCase;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.topology.types.rev160524.TopologyTypes1;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.topology.types.rev160524.TopologyTypes1Builder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.topology.types.rev160524.bgp.linkstate.topology.type.BgpLinkstateTopologyBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.SegmentId;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.sr.node.attributes.Segments;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.sr.node.attributes.SegmentsBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.sr.node.attributes.SegmentsKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.sr.node.attributes.segments.segment.specification.AdjacencyCaseBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.sr.node.attributes.segments.segment.specification.PrefixCaseBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.sr.node.attributes.segments.segment.specification.adjacency._case.AdjacencyBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.topology.sr.type.TopologySrBuilder;
71 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId;
72 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
73 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
74 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
75 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.DestinationBuilder;
76 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.SourceBuilder;
77 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
78 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
79 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkBuilder;
80 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkKey;
81 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
82 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
83 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
84 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypes;
85 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypesBuilder;
86 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
87 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
88 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
89 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.Link1;
90 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.Link1Builder;
91 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.Node1;
92 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.Node1Builder;
93 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.TerminationPoint1;
94 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.TerminationPoint1Builder;
95 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.link.attributes.IgpLinkAttributesBuilder;
96 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.IgpNodeAttributes;
97 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.IgpNodeAttributesBuilder;
98 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.igp.node.attributes.Prefix;
99 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.igp.node.attributes.PrefixBuilder;
100 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.node.attributes.igp.node.attributes.PrefixKey;
101 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.termination.point.attributes.IgpTerminationPointAttributesBuilder;
102 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.termination.point.attributes.igp.termination.point.attributes.TerminationPointType;
103 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.termination.point.attributes.igp.termination.point.attributes.termination.point.type.IpBuilder;
104 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.nt.l3.unicast.igp.topology.rev131021.igp.termination.point.attributes.igp.termination.point.attributes.termination.point.type.UnnumberedBuilder;
105 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
106 import org.opendaylight.yangtools.yang.common.Uint32;
107 import org.slf4j.Logger;
108 import org.slf4j.LoggerFactory;
109
110 public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateRoute> {
111     @VisibleForTesting
112     static final TopologyTypes LINKSTATE_TOPOLOGY_TYPE = new TopologyTypesBuilder()
113             .addAugmentation(TopologyTypes1.class, new TopologyTypes1Builder()
114                     .setBgpLinkstateTopology(new BgpLinkstateTopologyBuilder().build()).build()).build();
115     @VisibleForTesting
116     static final TopologyTypes SR_AWARE_LINKSTATE_TOPOLOGY_TYPE = new TopologyTypesBuilder(LINKSTATE_TOPOLOGY_TYPE)
117             .addAugmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819
118                 .TopologyTypes1.class,
119                 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819
120                 .TopologyTypes1Builder().setTopologySr(new TopologySrBuilder().build()).build())
121             .build();
122
123     private static final String UNHANDLED_OBJECT_CLASS = "Unhandled object class {}";
124
125     private static final class TpHolder {
126         private final Set<LinkId> local = new HashSet<>();
127         private final Set<LinkId> remote = new HashSet<>();
128
129         private final TerminationPoint tp;
130
131         TpHolder(final TerminationPoint tp) {
132             this.tp = requireNonNull(tp);
133         }
134
135         synchronized void addLink(final LinkId id, final boolean isRemote) {
136             if (isRemote) {
137                 this.remote.add(id);
138             } else {
139                 this.local.add(id);
140             }
141         }
142
143         synchronized boolean removeLink(final LinkId id, final boolean isRemote) {
144             final boolean removed;
145             if (isRemote) {
146                 removed = this.remote.remove(id);
147             } else {
148                 removed = this.local.remove(id);
149             }
150             if (!removed) {
151                 LOG.warn("Removed non-reference link {} from TP {} isRemote {}", this.tp.getTpId().getValue(),
152                         id.getValue(), isRemote);
153             }
154
155             return this.local.isEmpty() && this.remote.isEmpty();
156         }
157
158         TerminationPoint getTp() {
159             return this.tp;
160         }
161     }
162
163     private final class NodeHolder {
164         private final Map<PrefixKey, Prefix> prefixes = new HashMap<>();
165         private final Map<TpId, TpHolder> tps = new HashMap<>();
166         private boolean advertized = false;
167         private IgpNodeAttributesBuilder inab;
168         private NodeBuilder nb;
169         private NodeSrHolder sr;
170
171         NodeHolder(final NodeId id) {
172             this.inab = new IgpNodeAttributesBuilder();
173             this.nb = new NodeBuilder().withKey(new NodeKey(id)).setNodeId(id);
174         }
175
176         /**
177          * Synchronized in-core state of a node into the backing store using the transaction.
178          *
179          * @param trans data modification transaction which to use
180          * @return True if the node has been purged, false otherwise.
181          */
182         boolean syncState(final WriteTransaction trans) {
183             final InstanceIdentifier<Node> nid = getNodeInstanceIdentifier(this.nb.key());
184
185             /*
186              * Transaction's putOperationalData() does a merge. Force it onto a replace
187              * by removing the data. If we decide to remove the node -- we just skip the put.
188              */
189             trans.delete(LogicalDatastoreType.OPERATIONAL, nid);
190
191             if (!this.advertized) {
192                 if (this.tps.isEmpty() && this.prefixes.isEmpty()) {
193                     LOG.trace("Removing unadvertized unused node {}", this.nb.getNodeId().getValue());
194                     return true;
195                 }
196
197                 LOG.trace("Node {} is still implied by {} TPs and {} prefixes", this.nb.getNodeId().getValue(),
198                         this.tps.size(), this.prefixes.size());
199             }
200
201             // Re-generate termination points
202             this.nb.setTerminationPoint(Lists.newArrayList(Collections2.transform(this.tps.values(), TpHolder::getTp)));
203
204             // Re-generate prefixes
205             this.inab.setPrefix(Lists.newArrayList(this.prefixes.values()));
206
207             // Write the node out
208             if (this.sr != null && this.sr.getSegmentCount() > 0) {
209                 this.nb.addAugmentation(
210                     org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.Node1.class,
211                     new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819
212                         .Node1Builder().setSegments(this.sr.getSegments()).build());
213             }
214             final Node n = this.nb
215                     .addAugmentation(Node1.class, new Node1Builder().setIgpNodeAttributes(this.inab.build()).build())
216                     .build();
217             trans.put(LogicalDatastoreType.OPERATIONAL, nid, n);
218             LOG.trace("Created node {} at {}", n, nid);
219             return false;
220         }
221
222         boolean checkForRemoval(final WriteTransaction trans) {
223             final InstanceIdentifier<Node> nid = getNodeInstanceIdentifier(this.nb.key());
224
225             if (!this.advertized) {
226                 if (this.tps.isEmpty() && this.prefixes.isEmpty()) {
227                     trans.delete(LogicalDatastoreType.OPERATIONAL, nid);
228                     LOG.trace("Removing unadvertized unused node {}", this.nb.getNodeId().getValue());
229                     return true;
230                 }
231
232                 LOG.trace("Node {} is still implied by {} TPs and {} prefixes", this.nb.getNodeId().getValue(),
233                         this.tps.size(), this.prefixes.size());
234             }
235             return false;
236         }
237
238         synchronized void removeTp(final TpId tp, final LinkId link, final boolean isRemote) {
239             final TpHolder h = this.tps.get(tp);
240             if (h != null) {
241                 if (h.removeLink(link, isRemote)) {
242                     this.tps.remove(tp);
243                     LOG.trace("Removed TP {}", tp.getValue());
244                 }
245             } else {
246                 LOG.warn("Removed non-present TP {} by link {}", tp.getValue(), link.getValue());
247             }
248         }
249
250         void addTp(final TerminationPoint tp, final LinkId link, final boolean isRemote) {
251             final TpHolder h = this.tps.computeIfAbsent(tp.getTpId(), k -> new TpHolder(tp));
252             h.addLink(link, isRemote);
253         }
254
255         void addPrefix(final Prefix pfx) {
256             this.prefixes.put(pfx.key(), pfx);
257         }
258
259         void removePrefix(final PrefixCase prefixCase) {
260             this.prefixes.remove(new PrefixKey(prefixCase.getPrefixDescriptors().getIpReachabilityInformation()));
261         }
262
263         void unadvertized() {
264             this.inab = new IgpNodeAttributesBuilder();
265             this.nb = new NodeBuilder().withKey(this.nb.key()).setNodeId(this.nb.getNodeId());
266             this.advertized = false;
267             LOG.debug("Node {} is unadvertized", this.nb.getNodeId().getValue());
268         }
269
270         void advertized(final NodeBuilder nodeBuilder, final IgpNodeAttributesBuilder igpNodeAttBuilder) {
271             this.nb = requireNonNull(nodeBuilder);
272             this.inab = requireNonNull(igpNodeAttBuilder);
273             this.advertized = true;
274             LOG.debug("Node {} is advertized", nodeBuilder.getNodeId().getValue());
275         }
276
277         NodeId getNodeId() {
278             return this.nb.getNodeId();
279         }
280
281         NodeSrHolder getSrHolder() {
282             return this.sr;
283         }
284
285         NodeSrHolder createSrHolderIfRequired() {
286             if (this.sr == null) {
287                 this.sr = new NodeSrHolder(this.nb.getNodeId());
288             }
289             return this.sr;
290         }
291     }
292
293     private final class NodeSrHolder {
294         private NodeId nodeId;
295         private Long srgbFirstValue = null;
296         private Integer srgbRangeSize = null;
297         private List<Segments> segments = new ArrayList<>();
298         private Map<IpPrefix, SrPrefix> srPrefixes = new HashMap<>();
299         private Map<IpPrefix, Segments> prefixSegments = new HashMap<>();
300         private Map<LinkId, Segments> adjSegments = new HashMap<>();
301
302         NodeSrHolder(final NodeId nodeId) {
303             this.nodeId = nodeId;
304         }
305
306         void addSrgb(final WriteTransaction trans, final boolean updateNode, final Long srgbFirstVal,
307                 final Integer srgbRangeSz) {
308             this.srgbFirstValue = srgbFirstVal;
309             this.srgbRangeSize = srgbRangeSz;
310             this.srPrefixes.entrySet().forEach(entry -> {
311                 final IpPrefix ippfx = entry.getKey();
312                 final SrPrefix srPrefix = entry.getValue();
313                 final SidLabelIndex sidLabelIndex = srPrefix.getSidLabelIndex();
314                 if (sidLabelIndex instanceof SidCase) {
315                     final Long sidIndex = ((SidCase) sidLabelIndex).getSid().longValue();
316                     if (sidIndex >= this.srgbRangeSize) {
317                         LOG.warn("Prefix SID index {} is outside the SRGB range of {} for node {}", sidIndex,
318                                 this.srgbRangeSize, this.nodeId.getValue());
319                         return;
320                     }
321                     final Long prefixSid = this.srgbFirstValue + sidIndex;
322                     final boolean isNodeSid = isAssociatedWithNodeSid(ippfx, srPrefix);
323                     addPrefixSid(trans, updateNode, ippfx, prefixSid, isNodeSid);
324                 }
325             });
326         }
327
328         void removeSrgb(final WriteTransaction trans) {
329             this.srgbFirstValue = null;
330             this.srgbRangeSize = null;
331             this.srPrefixes.entrySet().forEach(entry -> {
332                 final IpPrefix ippfx = entry.getKey();
333                 final SrPrefix srPrefix = entry.getValue();
334                 final SidLabelIndex sidLabelIndex = srPrefix.getSidLabelIndex();
335                 if (sidLabelIndex instanceof SidCase) {
336                     removePrefixSid(trans, false, ippfx);
337                 }
338             });
339         }
340
341         void addSrPrefix(final WriteTransaction trans, final boolean updateNode, final IpPrefix ippfx,
342                 final SrPrefix srPrefix) {
343             this.srPrefixes.put(ippfx, srPrefix);
344             final SidLabelIndex sidLabelIndex = srPrefix.getSidLabelIndex();
345             Long prefixSid = null;
346             if (sidLabelIndex instanceof LocalLabelCase) {
347                 prefixSid = ((LocalLabelCase) sidLabelIndex).getLocalLabel().getValue().longValue();
348             } else if (sidLabelIndex instanceof SidCase) {
349                 if (this.srgbFirstValue != null && this.srgbRangeSize != null) {
350                     final Long sidIndex = ((SidCase) sidLabelIndex).getSid().longValue();
351                     if (sidIndex >= this.srgbRangeSize) {
352                         LOG.warn("Prefix SID index {} is outside the SRGB range of {} for node {}", sidIndex,
353                                 this.srgbRangeSize, this.nodeId.getValue());
354                         return;
355                     }
356                     prefixSid = this.srgbFirstValue + sidIndex;
357                 }
358             }
359             if (prefixSid != null) {
360                 final boolean isNodeSid = isAssociatedWithNodeSid(ippfx, srPrefix);
361                 addPrefixSid(trans, updateNode, ippfx, prefixSid, isNodeSid);
362             }
363         }
364
365         void removeSrPrefix(final WriteTransaction trans, final IpPrefix ippfx) {
366             if (!this.srPrefixes.containsKey(ippfx)) {
367                 return;
368             }
369             removePrefixSid(trans, true, ippfx);
370             this.srPrefixes.remove(ippfx);
371         }
372
373         void addPrefixSid(final WriteTransaction trans, final boolean updateNode, final IpPrefix ippfx,
374                 final Long prefixSid, final boolean isNodeSid) {
375             LOG.trace("Adding prefix SID {} for prefix {} on node {}", prefixSid, ippfx.stringValue(),
376                     this.nodeId.getValue());
377             final SegmentId segmentId = new SegmentId(Uint32.valueOf(prefixSid));
378             final Segments prefixSegment = new SegmentsBuilder()
379                     .setSegmentId(segmentId)
380                     .withKey(new SegmentsKey(segmentId))
381                     .setSegmentSpecification(new PrefixCaseBuilder()
382                         .setPrefix(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr
383                             .rev130819.sr.node.attributes.segments.segment.specification.prefix._case.PrefixBuilder()
384                                 .setPrefix(ippfx).setNodeSid(isNodeSid ? isNodeSid : null).build())
385                         .build())
386                     .build();
387             this.prefixSegments.put(ippfx, prefixSegment);
388             this.segments.add(prefixSegment);
389             addSegment(trans, updateNode, prefixSegment);
390         }
391
392         void removePrefixSid(final WriteTransaction trans, final boolean updateNode, final IpPrefix ippfx) {
393             if (!this.prefixSegments.containsKey(ippfx)) {
394                 return;
395             }
396             LOG.trace("Removing prefix SID for prefix {} on node {}", ippfx.stringValue(),
397                     this.nodeId.getValue());
398             final Segments prefixSegment = this.prefixSegments.remove(ippfx);
399             this.segments.remove(prefixSegment);
400             removeSegment(trans, updateNode, prefixSegment);
401         }
402
403         void addAdjacencySid(final WriteTransaction trans, final boolean updateNode, final LinkId linkId,
404                 final Long adjSid) {
405             LOG.trace("Adding adjacency SID {} for link {} on node {}", adjSid, linkId.getValue(),
406                     this.nodeId.getValue());
407             final SegmentId segmentId = new SegmentId(Uint32.valueOf(adjSid));
408             final SegmentsBuilder sb = new SegmentsBuilder();
409             sb.setSegmentId(segmentId);
410             sb.withKey(new SegmentsKey(segmentId));
411             sb.setSegmentSpecification(new AdjacencyCaseBuilder()
412                     .setAdjacency(new AdjacencyBuilder().setAdjacency(linkId).build()).build());
413             final Segments adjSegment = sb.build();
414             this.adjSegments.put(linkId, adjSegment);
415             this.segments.add(adjSegment);
416             addSegment(trans, updateNode, adjSegment);
417         }
418
419         void removeAdjacencySid(final WriteTransaction trans, final LinkId linkId) {
420             if (!this.adjSegments.containsKey(linkId)) {
421                 return;
422             }
423             LOG.trace("Removing adjacency SID for link {} on node {}", linkId.getValue(),
424                     this.nodeId.getValue());
425             final Segments adjSegment = this.adjSegments.remove(linkId);
426             this.segments.remove(adjSegment);
427             removeSegment(trans, true, adjSegment);
428         }
429
430         void addSegment(final WriteTransaction trans, final boolean updateNode, final Segments segment) {
431             if (updateNode) {
432                 final InstanceIdentifier<Node> nodeIId = getNodeInstanceIdentifier(new NodeKey(this.nodeId));
433                 final InstanceIdentifier<Segments> segmentIId = nodeIId.builder()
434                         .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr
435                             .rev130819.Node1.class)
436                         .child(Segments.class, segment.key()).build();
437                 trans.put(LogicalDatastoreType.OPERATIONAL, segmentIId, segment);
438             }
439             addSrAwareTopologyType(trans);
440         }
441
442         void removeSegment(final WriteTransaction trans, final boolean updateNode, final Segments segment) {
443             if (updateNode) {
444                 final InstanceIdentifier<Node> nodeIId = getNodeInstanceIdentifier(new NodeKey(this.nodeId));
445                 final InstanceIdentifier<Segments> segmentIId = nodeIId.builder()
446                         .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr
447                             .rev130819.Node1.class)
448                         .child(Segments.class, segment.key()).build();
449                 trans.delete(LogicalDatastoreType.OPERATIONAL, segmentIId);
450             }
451             removeSrAwareTopologyTypeIfRequired(trans);
452         }
453
454         boolean isAssociatedWithNodeSid(final IpPrefix ippfx, final SrPrefix srPrefix) {
455             if (ippfx.getIpv4Prefix() != null && !ippfx.stringValue().endsWith("/32")
456                     || ippfx.getIpv6Prefix() != null && !ippfx.stringValue().endsWith("/128")) {
457                 return false;
458             }
459             final Flags prefixFlags = srPrefix.getFlags();
460             if (prefixFlags instanceof IsisPrefixFlagsCase) {
461                 return !Boolean.FALSE.equals(((IsisPrefixFlagsCase) prefixFlags).getIsisPrefixFlags().isNodeSid());
462             }
463             return true;
464         }
465
466         List<Segments> getSegments() {
467             return this.segments;
468         }
469
470         int getSegmentCount() {
471             return this.segments.size();
472         }
473     }
474
475     private static final Logger LOG = LoggerFactory.getLogger(LinkstateTopologyBuilder.class);
476     private final Map<NodeId, NodeHolder> nodes = new HashMap<>();
477     private boolean srAwareTopologyTypeAdded;
478
479     public LinkstateTopologyBuilder(final DataBroker dataProvider, final RibReference locRibReference,
480             final TopologyId topologyId) {
481         super(dataProvider, locRibReference, topologyId, LINKSTATE_TOPOLOGY_TYPE, LinkstateAddressFamily.class,
482                 LinkstateSubsequentAddressFamily.class);
483     }
484
485     @VisibleForTesting
486     LinkstateTopologyBuilder(final DataBroker dataProvider, final RibReference locRibReference,
487             final TopologyId topologyId, final long listenerResetLimitInMillsec,
488             final int listenerResetEnforceCounter) {
489         super(dataProvider, locRibReference, topologyId, LINKSTATE_TOPOLOGY_TYPE, LinkstateAddressFamily.class,
490                 LinkstateSubsequentAddressFamily.class,
491                 listenerResetLimitInMillsec, listenerResetEnforceCounter);
492     }
493
494     private static LinkId buildLinkId(final UriBuilder base, final LinkCase link) {
495         return new LinkId(new UriBuilder(base, "link").add(link).toString());
496     }
497
498     private static NodeId buildNodeId(final UriBuilder base, final org.opendaylight.yang.gen.v1.urn.opendaylight
499             .params.xml.ns.yang.bgp.linkstate.rev200120.NodeIdentifier node) {
500         return new NodeId(new UriBuilder(base, "node").addPrefix("", node).toString());
501     }
502
503     private static TpId buildTpId(final UriBuilder base, final TopologyIdentifier topologyIdentifier,
504             final Ipv4InterfaceIdentifier ipv4InterfaceIdentifier,
505             final Ipv6InterfaceIdentifier ipv6InterfaceIdentifier, final Uint32 id) {
506         final UriBuilder b = new UriBuilder(base, "tp");
507         if (topologyIdentifier != null) {
508             b.add("mt", topologyIdentifier.getValue());
509         }
510         if (ipv4InterfaceIdentifier != null) {
511             b.add("ipv4", ipv4InterfaceIdentifier.getValue());
512         }
513         if (ipv6InterfaceIdentifier != null) {
514             b.add("ipv6", ipv6InterfaceIdentifier.getValue());
515         }
516
517         return new TpId(b.add("id", id).toString());
518     }
519
520     private static TpId buildLocalTpId(final UriBuilder base, final LinkDescriptors linkDescriptors) {
521         return buildTpId(base, linkDescriptors.getMultiTopologyId(), linkDescriptors.getIpv4InterfaceAddress(),
522                 linkDescriptors.getIpv6InterfaceAddress(), linkDescriptors.getLinkLocalIdentifier());
523     }
524
525     private static TerminationPoint buildTp(final TpId id, final TerminationPointType type) {
526         final TerminationPointBuilder stpb = new TerminationPointBuilder();
527         stpb.withKey(new TerminationPointKey(id));
528         stpb.setTpId(id);
529
530         if (type != null) {
531             stpb.addAugmentation(TerminationPoint1.class, new TerminationPoint1Builder()
532                     .setIgpTerminationPointAttributes(
533                     new IgpTerminationPointAttributesBuilder().setTerminationPointType(type).build()).build());
534         }
535
536         return stpb.build();
537     }
538
539     private static TerminationPointType getTpType(final Ipv4InterfaceIdentifier ipv4InterfaceIdentifier,
540             final Ipv6InterfaceIdentifier ipv6InterfaceIdentifier, final Uint32 id) {
541         // Order of preference: Unnumbered first, then IP
542         if (id != null) {
543             LOG.debug("Unnumbered termination point type: {}", id);
544             return new UnnumberedBuilder().setUnnumberedId(id).build();
545         }
546
547         final IpAddress ip;
548         if (ipv6InterfaceIdentifier != null) {
549             ip = new IpAddress(ipv6InterfaceIdentifier);
550         } else if (ipv4InterfaceIdentifier != null) {
551             ip = new IpAddress(ipv4InterfaceIdentifier);
552         } else {
553             ip = null;
554         }
555
556         if (ip != null) {
557             LOG.debug("IP termination point type: {}", ip);
558             return new IpBuilder().setIpAddress(Lists.newArrayList(ip)).build();
559         }
560
561         return null;
562     }
563
564     private static TerminationPoint buildLocalTp(final UriBuilder base, final LinkDescriptors linkDescriptors) {
565         final TpId id = buildLocalTpId(base, linkDescriptors);
566         final TerminationPointType t = getTpType(linkDescriptors.getIpv4InterfaceAddress(),
567                 linkDescriptors.getIpv6InterfaceAddress(),
568                 linkDescriptors.getLinkLocalIdentifier());
569
570         return buildTp(id, t);
571     }
572
573     private static TpId buildRemoteTpId(final UriBuilder base, final LinkDescriptors linkDescriptors) {
574         return buildTpId(base, linkDescriptors.getMultiTopologyId(), linkDescriptors.getIpv4NeighborAddress(),
575                 linkDescriptors.getIpv6NeighborAddress(), linkDescriptors.getLinkRemoteIdentifier());
576     }
577
578     private static TerminationPoint buildRemoteTp(final UriBuilder base, final LinkDescriptors linkDescriptors) {
579         final TpId id = buildRemoteTpId(base, linkDescriptors);
580         final TerminationPointType t = getTpType(linkDescriptors.getIpv4NeighborAddress(),
581                 linkDescriptors.getIpv6NeighborAddress(),
582                 linkDescriptors.getLinkRemoteIdentifier());
583
584         return buildTp(id, t);
585     }
586
587     private InstanceIdentifier<Link> buildLinkIdentifier(final LinkId id) {
588         return getInstanceIdentifier().child(
589                 org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology
590                         .topology.Link.class, new LinkKey(id));
591     }
592
593     private NodeHolder getNode(final NodeId id) {
594         return this.nodes.computeIfAbsent(id, NodeHolder::new);
595     }
596
597     private void putNode(final WriteTransaction trans, final NodeHolder holder) {
598         if (holder.syncState(trans)) {
599             this.nodes.remove(holder.getNodeId());
600         }
601     }
602
603     private void checkNodeForRemoval(final WriteTransaction trans, final NodeHolder holder) {
604         if (holder.checkForRemoval(trans)) {
605             this.nodes.remove(holder.getNodeId());
606         }
607     }
608
609     private void createLink(final WriteTransaction trans, final UriBuilder base,
610             final LinkstateRoute value, final LinkCase linkCase, final Attributes attributes) {
611         // defensive lookup
612         final LinkAttributes la;
613         final Attributes1 attr = attributes.augmentation(Attributes1.class);
614         if (attr != null) {
615             final LinkStateAttribute attrType = attr.getLinkStateAttribute();
616             if (attrType != null) {
617                 la = ((LinkAttributesCase)attrType).getLinkAttributes();
618             } else {
619                 LOG.debug("Missing attribute type in link {} route {}, skipping it", linkCase, value);
620                 la = null;
621             }
622         } else {
623             LOG.debug("Missing attributes in link {} route {}, skipping it", linkCase, value);
624             la = null;
625         }
626
627         final IgpLinkAttributesBuilder ilab = new IgpLinkAttributesBuilder();
628         Long adjSid = null;
629         if (la != null) {
630             if (la.getMetric() != null) {
631                 ilab.setMetric(la.getMetric().getValue());
632             }
633             ilab.setName(la.getLinkName());
634             if (la.getSrAdjIds() != null && !la.getSrAdjIds().isEmpty()) {
635                 final SrAdjIds srAdjIds = la.getSrAdjIds().get(0);
636                 if (srAdjIds != null) {
637                     final SidLabelIndex sidLabelIndex = srAdjIds.getSidLabelIndex();
638                     if (sidLabelIndex instanceof LocalLabelCase) {
639                         adjSid = ((LocalLabelCase) sidLabelIndex).getLocalLabel().getValue().longValue();
640                     }
641                 }
642             }
643         }
644         ProtocolUtil.augmentProtocolId(value, ilab, la, linkCase.getLinkDescriptors());
645
646         final LinkBuilder lb = new LinkBuilder();
647         lb.setLinkId(buildLinkId(base, linkCase));
648         lb.addAugmentation(Link1.class, new Link1Builder().setIgpLinkAttributes(ilab.build()).build());
649
650         final NodeId srcNode = buildNodeId(base, linkCase.getLocalNodeDescriptors());
651         LOG.trace("Link {} implies source node {}", linkCase, srcNode);
652
653         final NodeId dstNode = buildNodeId(base, linkCase.getRemoteNodeDescriptors());
654         LOG.trace("Link {} implies destination node {}", linkCase, dstNode);
655
656         final TerminationPoint srcTp = buildLocalTp(base, linkCase.getLinkDescriptors());
657         LOG.trace("Link {} implies source TP {}", linkCase, srcTp);
658
659         final TerminationPoint dstTp = buildRemoteTp(base, linkCase.getLinkDescriptors());
660         LOG.trace("Link {} implies destination TP {}", linkCase, dstTp);
661
662         lb.setSource(new SourceBuilder().setSourceNode(srcNode).setSourceTp(srcTp.getTpId()).build());
663         lb.setDestination(new DestinationBuilder().setDestNode(dstNode).setDestTp(dstTp.getTpId()).build());
664
665         LOG.trace("Created TP {} as link source", srcTp);
666         NodeHolder snh = this.nodes.get(srcNode);
667         if (snh == null) {
668             snh = getNode(srcNode);
669             snh.addTp(srcTp, lb.getLinkId(), false);
670             if (adjSid != null) {
671                 snh.createSrHolderIfRequired().addAdjacencySid(trans, false, lb.getLinkId(), adjSid);
672             }
673             putNode(trans, snh);
674         } else {
675             snh.addTp(srcTp, lb.getLinkId(), false);
676             if (adjSid != null) {
677                 snh.createSrHolderIfRequired().addAdjacencySid(trans, true, lb.getLinkId(), adjSid);
678             }
679             final InstanceIdentifier<Node> nid = getNodeInstanceIdentifier(new NodeKey(snh.getNodeId()));
680             trans.put(LogicalDatastoreType.OPERATIONAL, nid.child(TerminationPoint.class, srcTp.key()), srcTp);
681         }
682         if (adjSid != null) {
683             lb.addAugmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819
684                     .Link1.class,
685                 new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819
686                     .Link1Builder().setSegment(new SegmentId(Uint32.valueOf(adjSid))).build());
687         }
688
689         LOG.debug("Created TP {} as link destination", dstTp);
690         NodeHolder dnh = this.nodes.get(dstNode);
691         if (dnh == null) {
692             dnh = getNode(dstNode);
693             dnh.addTp(dstTp, lb.getLinkId(), true);
694             putNode(trans, dnh);
695         } else {
696             dnh.addTp(dstTp, lb.getLinkId(), true);
697             final InstanceIdentifier<Node> nid = getInstanceIdentifier().child(
698                     org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network
699                             .topology.topology.Node.class, new NodeKey(dnh.getNodeId()));
700             trans.put(LogicalDatastoreType.OPERATIONAL, nid.child(TerminationPoint.class, dstTp.key()), dstTp);
701         }
702
703         final InstanceIdentifier<Link> lid = buildLinkIdentifier(lb.getLinkId());
704         final Link link = lb.build();
705
706         trans.put(LogicalDatastoreType.OPERATIONAL, lid, link);
707         LOG.debug("Created link {} at {} for {}", link, lid, linkCase);
708     }
709
710     private void removeTp(final WriteTransaction trans, final NodeId node, final TpId tp,
711             final LinkId link, final boolean isRemote) {
712         final NodeHolder nh = this.nodes.get(node);
713         if (nh != null) {
714             final InstanceIdentifier<Node> nid = getNodeInstanceIdentifier(new NodeKey(nh.getNodeId()));
715             trans.delete(LogicalDatastoreType.OPERATIONAL, nid.child(TerminationPoint.class,
716                     new TerminationPointKey(tp)));
717             nh.removeTp(tp, link, isRemote);
718             if (!isRemote) {
719                 nh.createSrHolderIfRequired().removeAdjacencySid(trans, link);
720             }
721             checkNodeForRemoval(trans, nh);
722         } else {
723             LOG.warn("Removed non-existent node {}", node.getValue());
724         }
725     }
726
727     private void removeLink(final WriteTransaction trans, final UriBuilder base, final LinkCase linkCase) {
728         final LinkId id = buildLinkId(base, linkCase);
729         final InstanceIdentifier<?> lid = buildLinkIdentifier(id);
730         trans.delete(LogicalDatastoreType.OPERATIONAL, lid);
731         LOG.debug("Removed link {}", lid);
732
733         removeTp(trans, buildNodeId(base, linkCase.getLocalNodeDescriptors()),
734                 buildLocalTpId(base, linkCase.getLinkDescriptors()), id, false);
735         removeTp(trans, buildNodeId(base, linkCase.getRemoteNodeDescriptors()),
736                 buildRemoteTpId(base, linkCase.getLinkDescriptors()), id, true);
737     }
738
739     private void createNode(final WriteTransaction trans, final UriBuilder base,
740             final LinkstateRoute value, final NodeCase nodeCase, final Attributes attributes) {
741         final NodeAttributes na;
742         //defensive lookup
743         final Attributes1 attr = attributes.augmentation(Attributes1.class);
744         if (attr != null) {
745             final LinkStateAttribute attrType = attr.getLinkStateAttribute();
746             if (attrType != null) {
747                 na = ((NodeAttributesCase)attrType).getNodeAttributes();
748             } else {
749                 LOG.debug("Missing attribute type in node {} route {}, skipping it", nodeCase, value);
750                 na = null;
751             }
752         } else {
753             LOG.debug("Missing attributes in node {} route {}, skipping it", nodeCase, value);
754             na = null;
755         }
756         final IgpNodeAttributesBuilder inab = new IgpNodeAttributesBuilder();
757         final List<IpAddress> ids = new ArrayList<>();
758         Long srgbFirstValue = null;
759         Integer srgbRangeSize = null;
760         if (na != null) {
761             if (na.getIpv4RouterId() != null) {
762                 ids.add(new IpAddress(na.getIpv4RouterId()));
763             }
764             if (na.getIpv6RouterId() != null) {
765                 ids.add(new IpAddress(na.getIpv6RouterId()));
766             }
767             if (na.getDynamicHostname() != null) {
768                 inab.setName(new DomainName(na.getDynamicHostname()));
769             }
770             if (na.getSrCapabilities() != null) {
771                 final SidLabelIndex sidLabelIndex = na.getSrCapabilities().getSidLabelIndex();
772                 if (sidLabelIndex instanceof LocalLabelCase) {
773                     srgbFirstValue = ((LocalLabelCase) sidLabelIndex).getLocalLabel().getValue().longValue();
774                 }
775                 srgbRangeSize = na.getSrCapabilities().getRangeSize() != null
776                         ? na.getSrCapabilities().getRangeSize().getValue().intValue()
777                         : null;
778             }
779         }
780         if (!ids.isEmpty()) {
781             inab.setRouterId(ids);
782         }
783         ProtocolUtil.augmentProtocolId(value, inab, na, nodeCase.getNodeDescriptors());
784
785         final NodeId nid = buildNodeId(base, nodeCase.getNodeDescriptors());
786         final NodeHolder nh = getNode(nid);
787         /*
788          *  Eventhough the the holder creates a dummy structure, we need to duplicate it here,
789          *  as that is the API requirement. The reason for it is the possible presence of supporting
790          *  node -- something which the holder does not track.
791          */
792         final NodeBuilder nb = new NodeBuilder();
793         nb.setNodeId(nid);
794         nb.withKey(new NodeKey(nb.getNodeId()));
795
796         nh.advertized(nb, inab);
797         if (srgbFirstValue != null && srgbRangeSize != null) {
798             nh.createSrHolderIfRequired().addSrgb(trans, false, srgbFirstValue, srgbRangeSize);
799         }
800         putNode(trans, nh);
801     }
802
803     private void removeNode(final WriteTransaction trans, final UriBuilder base, final NodeCase nodeCase) {
804         final NodeId id = buildNodeId(base, nodeCase.getNodeDescriptors());
805         final NodeHolder nh = this.nodes.get(id);
806         if (nh != null) {
807             nh.unadvertized();
808             nh.createSrHolderIfRequired().removeSrgb(trans);
809             putNode(trans, nh);
810         } else {
811             LOG.warn("Node {} does not have a holder", id.getValue());
812         }
813     }
814
815     private void createPrefix(final WriteTransaction trans, final UriBuilder base,
816             final LinkstateRoute value, final PrefixCase prefixCase, final Attributes attributes) {
817         final IpPrefix ippfx = prefixCase.getPrefixDescriptors().getIpReachabilityInformation();
818         if (ippfx == null) {
819             LOG.warn("IP reachability not present in prefix {} route {}, skipping it", prefixCase, value);
820             return;
821         }
822         final PrefixBuilder pb = new PrefixBuilder();
823         final PrefixKey pk = new PrefixKey(ippfx);
824         pb.withKey(pk);
825         pb.setPrefix(ippfx);
826
827         final PrefixAttributes pa;
828         // Very defensive lookup
829         final Attributes1 attr = attributes.augmentation(Attributes1.class);
830         if (attr != null) {
831             final LinkStateAttribute attrType = attr.getLinkStateAttribute();
832             if (attrType != null) {
833                 pa = ((PrefixAttributesCase)attrType).getPrefixAttributes();
834             } else {
835                 LOG.debug("Missing attribute type in IP {} prefix {} route {}, skipping it", ippfx, prefixCase, value);
836                 pa = null;
837             }
838         } else {
839             LOG.debug("Missing attributes in IP {} prefix {} route {}, skipping it", ippfx, prefixCase, value);
840             pa = null;
841         }
842         SrPrefix srPrefix = null;
843         if (pa != null) {
844             if (pa.getPrefixMetric() != null) {
845                 pb.setMetric(pa.getPrefixMetric().getValue());
846             }
847             if (pa.getSrPrefix() != null) {
848                 srPrefix = pa.getSrPrefix();
849             }
850         }
851         ProtocolUtil.augmentProtocolId(value, pa, pb);
852
853         final Prefix pfx = pb.build();
854         LOG.debug("Created prefix {} for {}", pfx, prefixCase);
855
856         /*
857          * All set, but... the hosting node may not exist, we may need to fake it.
858          */
859         final NodeId node = buildNodeId(base, prefixCase.getAdvertisingNodeDescriptors());
860         NodeHolder nh = this.nodes.get(node);
861         if (nh == null) {
862             nh = getNode(node);
863             nh.addPrefix(pfx);
864             if (srPrefix != null) {
865                 nh.createSrHolderIfRequired().addSrPrefix(trans, false, ippfx, srPrefix);
866             }
867             putNode(trans, nh);
868         } else {
869             nh.addPrefix(pfx);
870             if (srPrefix != null) {
871                 nh.createSrHolderIfRequired().addSrPrefix(trans, true, ippfx, srPrefix);
872             }
873             final InstanceIdentifier<Node> nid = getNodeInstanceIdentifier(new NodeKey(nh.getNodeId()));
874             final InstanceIdentifier<IgpNodeAttributes> inaId = nid.builder().augmentation(Node1.class)
875                     .child(IgpNodeAttributes.class).build();
876             trans.put(LogicalDatastoreType.OPERATIONAL, inaId.child(Prefix.class, pk), pfx);
877         }
878     }
879
880     private void removePrefix(final WriteTransaction trans, final UriBuilder base, final PrefixCase prefixCase) {
881         final NodeId node = buildNodeId(base, prefixCase.getAdvertisingNodeDescriptors());
882         final NodeHolder nh = this.nodes.get(node);
883         if (nh != null) {
884             LOG.debug("Removed prefix {}", prefixCase);
885             final InstanceIdentifier<Node> nid = getNodeInstanceIdentifier(new NodeKey(nh.getNodeId()));
886             final InstanceIdentifier<IgpNodeAttributes> inaId = nid.builder().augmentation(Node1.class)
887                     .child(IgpNodeAttributes.class).build();
888             final IpPrefix ippfx = prefixCase.getPrefixDescriptors().getIpReachabilityInformation();
889             if (ippfx == null) {
890                 LOG.warn("IP reachability not present in prefix {}, skipping it", prefixCase);
891                 return;
892             }
893             final PrefixKey pk = new PrefixKey(ippfx);
894             trans.delete(LogicalDatastoreType.OPERATIONAL, inaId.child(Prefix.class, pk));
895             nh.removePrefix(prefixCase);
896             nh.createSrHolderIfRequired().removeSrPrefix(trans, ippfx);
897             checkNodeForRemoval(trans, nh);
898         } else {
899             LOG.warn("Removing prefix from non-existing node {}", node.getValue());
900         }
901     }
902
903     private InstanceIdentifier<Node> getNodeInstanceIdentifier(final NodeKey nodeKey) {
904         return getInstanceIdentifier().child(
905                 org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network
906                         .topology.topology.Node.class, nodeKey);
907     }
908
909     protected void addSrAwareTopologyType(final WriteTransaction trans) {
910         if (this.srAwareTopologyTypeAdded) {
911             return;
912         }
913         LOG.debug("Adding SR-aware topology-type for topology {}",
914                 getInstanceIdentifier().firstKeyOf(Topology.class).getTopologyId().getValue());
915         trans.put(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier().child(TopologyTypes.class),
916                 SR_AWARE_LINKSTATE_TOPOLOGY_TYPE);
917         this.srAwareTopologyTypeAdded = true;
918     }
919
920     protected void removeSrAwareTopologyTypeIfRequired(final WriteTransaction trans) {
921         if (!this.srAwareTopologyTypeAdded) {
922             return;
923         }
924         final boolean isSidPresent = this.nodes.values().stream().filter(nh -> nh.getSrHolder() != null)
925                 .map(nh -> nh.getSrHolder().getSegmentCount()).anyMatch(cnt -> cnt != 0);
926         if (isSidPresent) {
927             return;
928         }
929         LOG.debug("Removing SR-aware topology-type from topology {}",
930                 getInstanceIdentifier().firstKeyOf(Topology.class).getTopologyId().getValue());
931         trans.put(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier().child(TopologyTypes.class),
932                 LINKSTATE_TOPOLOGY_TYPE);
933         this.srAwareTopologyTypeAdded = false;
934     }
935
936     @Override
937     protected void createObject(final ReadWriteTransaction trans,
938             final InstanceIdentifier<LinkstateRoute> id, final LinkstateRoute value) {
939         final UriBuilder base = new UriBuilder(value);
940
941         final ObjectType t = value.getObjectType();
942         Preconditions.checkArgument(t != null, "Route %s value %s has null object type", id, value);
943
944         if (t instanceof LinkCase) {
945             createLink(trans, base, value, (LinkCase) t, value.getAttributes());
946         } else if (t instanceof NodeCase) {
947             createNode(trans, base, value, (NodeCase) t, value.getAttributes());
948         } else if (t instanceof PrefixCase) {
949             createPrefix(trans, base, value, (PrefixCase) t, value.getAttributes());
950         } else {
951             LOG.debug(UNHANDLED_OBJECT_CLASS, t.implementedInterface());
952         }
953     }
954
955     @Override
956     protected void removeObject(final ReadWriteTransaction trans,
957             final InstanceIdentifier<LinkstateRoute> id, final LinkstateRoute value) {
958         if (value == null) {
959             LOG.error("Empty before-data received in delete data change notification for instance id {}", id);
960             return;
961         }
962
963         final UriBuilder base = new UriBuilder(value);
964
965         final ObjectType t = value.getObjectType();
966         if (t instanceof LinkCase) {
967             removeLink(trans, base, (LinkCase) t);
968         } else if (t instanceof NodeCase) {
969             removeNode(trans, base, (NodeCase) t);
970         } else if (t instanceof PrefixCase) {
971             removePrefix(trans, base, (PrefixCase) t);
972         } else {
973             LOG.debug(UNHANDLED_OBJECT_CLASS, t.implementedInterface());
974         }
975     }
976
977     @Override
978     protected InstanceIdentifier<LinkstateRoute> getRouteWildcard(final InstanceIdentifier<Tables> tablesId) {
979         return tablesId.child(LinkstateRoutesCase.class, LinkstateRoutes.class).child(LinkstateRoute.class);
980     }
981
982     @Override
983     protected void clearTopology() {
984         this.nodes.clear();
985         this.srAwareTopologyTypeAdded = false;
986     }
987 }