Propogate SR SID info from BGP-LS routes in RIB to link-state topology 93/88293/1
authorAjay Lele <ajayslele@gmail.com>
Thu, 16 Jan 2020 21:24:54 +0000 (13:24 -0800)
committerRobert Varga <nite@hq.sk>
Fri, 6 Mar 2020 08:23:19 +0000 (08:23 +0000)
JIRA: BGPCEP-365
Change-Id: Ie4d9701459e163aad24ea1cca61e19fc1661d73a
Signed-off-by: Ajay Lele <ajayslele@gmail.com>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
(cherry picked from commit 9553bbac51ae890b9a923aa64ce8617ceae06666)

bgp/extensions/linkstate/src/main/java/org/opendaylight/protocol/bgp/linkstate/impl/attribute/sr/SidLabelIndexParser.java
bgp/extensions/linkstate/src/main/java/org/opendaylight/protocol/bgp/linkstate/impl/attribute/sr/SrLinkAttributesParser.java
bgp/extensions/linkstate/src/main/java/org/opendaylight/protocol/bgp/linkstate/impl/attribute/sr/SrPrefixAttributesParser.java
bgp/topology-provider/pom.xml
bgp/topology-provider/src/main/java/org/opendaylight/bgpcep/bgp/topology/provider/LinkstateTopologyBuilder.java
bgp/topology-provider/src/test/java/org/opendaylight/bgpcep/bgp/topology/provider/LinkstateTopologyBuilderTest.java
topology/segment-routing/pom.xml
topology/segment-routing/src/main/yang/network-topology-sr.yang

index 5bbeab15c3ac398698bc19b840964ffb0c52d0ed..53ebb57ff4cbc721df20593d00c5908c0390a64b 100644 (file)
@@ -83,8 +83,7 @@ public final class SidLabelIndexParser {
     public static SidLabelIndex parseSidLabelIndex(final Size length, final ByteBuf buffer) {
         switch (length) {
             case LABEL:
-                return new LocalLabelCaseBuilder()
-                        .setLocalLabel(new MplsLabel(Uint32.valueOf(buffer.readUnsignedMedium() & LABEL_MASK))).build();
+                return new LocalLabelCaseBuilder().setLocalLabel(new MplsLabel(readLabel(buffer))).build();
             case SID:
                 return new SidCaseBuilder().setSid(ByteBufUtils.readUint32(buffer)).build();
             case IPV6_ADD:
@@ -94,6 +93,47 @@ public final class SidLabelIndexParser {
         }
     }
 
+    private static Uint32 readLabel(final ByteBuf buffer) {
+        return Uint32.valueOf(buffer.readUnsignedMedium() & LABEL_MASK);
+    }
+
+    /**
+     * Parses SID/Label/Index value into appropriate type based on V-Flag and L-Flag
+     * values. This method is required as some device-side implementations
+     * incorrectly encode SID/Label/Index value using wrong type e.g. Label type to
+     * encode an Index value (V-Flag=false, L-Flag=false).
+     *
+     * @param length length of SID/Label/Index value
+     * @param buffer buffer containing SID/Label/Index value
+     * @param isValue V-Flag value
+     * @param isLocal L-Flag value
+     * @return SID/Label/Index value parsed into the appropriate type
+     */
+    public static SidLabelIndex parseSidLabelIndexByFlags(final Size length, final ByteBuf buffer,
+            final boolean isValue, final boolean isLocal) {
+        switch (length) {
+            case LABEL:
+                return getSidLabelIndexByFlags(readLabel(buffer), isValue, isLocal);
+            case SID:
+                return getSidLabelIndexByFlags(ByteBufUtils.readUint32(buffer), isValue, isLocal);
+            case IPV6_ADD:
+                return new Ipv6AddressCaseBuilder().setIpv6Address(Ipv6Util.addressForByteBuf(buffer)).build();
+            default:
+                return null;
+        }
+    }
+
+    private static SidLabelIndex getSidLabelIndexByFlags(final Uint32 sidLabelIndex, final boolean isValue,
+            final boolean isLocal) {
+        if (isValue && isLocal) {
+            return new LocalLabelCaseBuilder().setLocalLabel(new MplsLabel(sidLabelIndex)).build();
+        } else if (!isValue && !isLocal) {
+            return new SidCaseBuilder().setSid(sidLabelIndex).build();
+        } else {
+            return null;
+        }
+    }
+
     static void setFlags(final SidLabelIndex tlv, final BitArray flags, final int value, final int local) {
         if (tlv instanceof LocalLabelCase) {
             flags.set(value, Boolean.TRUE);
index 9e17fddbfb80448d22648c5ff889a49d549c833d..c4f139f7ebc14d5bad2aab105174323b3e599bbe 100644 (file)
@@ -83,7 +83,24 @@ public final class SrLinkAttributesParser {
             adjFlags = parseFlags(flags, protocolId);
             weight = new Weight(ByteBufUtils.readUint8(buffer));
             buffer.skipBytes(RESERVED);
-            sidValue = SidLabelIndexParser.parseSidLabelIndex(Size.forValue(buffer.readableBytes()), buffer);
+            final boolean isValue;
+            final boolean isLocal;
+            switch (protocolId) {
+                case IsisLevel1:
+                case IsisLevel2:
+                    isValue = flags.get(VALUE_ISIS);
+                    isLocal = flags.get(LOCAL_ISIS);
+                    break;
+                case Ospf:
+                case OspfV3:
+                    isValue = flags.get(VALUE_OSPF);
+                    isLocal = flags.get(LOCAL_OSPF);
+                    break;
+                default:
+                    return null;
+            }
+            sidValue = SidLabelIndexParser.parseSidLabelIndexByFlags(Size.forValue(buffer.readableBytes()), buffer,
+                    isValue, isLocal);
         } else {
             adjFlags = null;
             weight = null;
@@ -96,10 +113,11 @@ public final class SrLinkAttributesParser {
         final Weight weight;
         final SidLabelIndex sidValue;
         if (buffer.isReadable()) {
-            buffer.skipBytes(FLAGS_BYTE_SIZE);
+            final BitArray flags = BitArray.valueOf(buffer, FLAGS_BITS_SIZE);
             weight = new Weight(ByteBufUtils.readUint8(buffer));
             buffer.skipBytes(RESERVED);
-            sidValue = SidLabelIndexParser.parseSidLabelIndex(Size.forValue(buffer.readableBytes()), buffer);
+            sidValue = SidLabelIndexParser.parseSidLabelIndexByFlags(Size.forValue(buffer.readableBytes()), buffer,
+                    flags.get(VALUE_EPE), flags.get(LOCAL_EPE));
         } else {
             weight = null;
             sidValue = null;
@@ -131,22 +149,28 @@ public final class SrLinkAttributesParser {
         srLanAdjIdBuilder.setFlags(parseFlags(flags, protocolId));
         srLanAdjIdBuilder.setWeight(new Weight(ByteBufUtils.readUint8(buffer)));
         buffer.skipBytes(RESERVED);
+        final boolean isValue;
+        final boolean isLocal;
         switch (protocolId) {
             case IsisLevel1:
             case IsisLevel2:
+                isValue = flags.get(VALUE_ISIS);
+                isLocal = flags.get(LOCAL_ISIS);
                 srLanAdjIdBuilder.setIsoSystemId(new IsoSystemIdentifier(
                     ByteArray.readBytes(buffer, ISO_SYSTEM_ID_SIZE)));
                 break;
             case Ospf:
             case OspfV3:
+                isValue = flags.get(VALUE_OSPF);
+                isLocal = flags.get(LOCAL_OSPF);
                 srLanAdjIdBuilder.setNeighborId(Ipv4Util.addressForByteBuf(buffer));
                 break;
             default:
                 return null;
         }
         // length determines a type of next field, which is used for parsing
-        srLanAdjIdBuilder.setSidLabelIndex(SidLabelIndexParser.parseSidLabelIndex(
-            Size.forValue(buffer.readableBytes()), buffer));
+        srLanAdjIdBuilder.setSidLabelIndex(SidLabelIndexParser
+                .parseSidLabelIndexByFlags(Size.forValue(buffer.readableBytes()), buffer, isValue, isLocal));
         return srLanAdjIdBuilder.build();
     }
 
index cb8199057b4722dcf0c63120f8248f6639930723..746d68edc40e2f20540d4aa16f690cc8f2df02d3 100644 (file)
@@ -44,12 +44,15 @@ public final class SrPrefixAttributesParser {
     }
 
     public static SrPrefix parseSrPrefix(final ByteBuf buffer, final ProtocolId protocol) {
-        final SrPrefixBuilder builder = new SrPrefixBuilder();
-        builder.setFlags(parsePrefixFlags(BitArray.valueOf(buffer, FLAGS_SIZE), protocol));
-        builder.setAlgorithm(Algorithm.forValue(buffer.readUnsignedByte()));
+        final BitArray flags = BitArray.valueOf(buffer, FLAGS_SIZE);
+        final SrPrefixBuilder builder = new SrPrefixBuilder()
+                .setFlags(parsePrefixFlags(flags, protocol))
+                .setAlgorithm(Algorithm.forValue(buffer.readUnsignedByte()));
         buffer.skipBytes(RESERVED_PREFIX);
-        builder.setSidLabelIndex(SidLabelIndexParser.parseSidLabelIndex(Size.forValue(buffer.readableBytes()), buffer));
-        return builder.build();
+        return builder.setSidLabelIndex(
+                    SidLabelIndexParser.parseSidLabelIndexByFlags(Size.forValue(buffer.readableBytes()), buffer,
+                        flags.get(VALUE), flags.get(LOCAL)))
+                .build();
     }
 
     private static Flags parsePrefixFlags(final BitArray flags, final ProtocolId protocol) {
index ea15a4758003072d1be9371bab4024564ad44b52..8b15ec8c543c9edb12f206d10bf9101f4829899b 100644 (file)
             <groupId>${project.groupId}</groupId>
             <artifactId>topology-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>topology-segment-routing</artifactId>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>graph-api</artifactId>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal.model</groupId>
+            <artifactId>odl-uint24</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.mdsal.model</groupId>
             <artifactId>ietf-ted</artifactId>
index f94354590236686046ab94a7252e40b214338d20..b141b4b6a91bf968e9e60488635ff3ec9e2a51f6 100644 (file)
@@ -34,6 +34,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.link
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.TopologyIdentifier;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.bgp.rib.rib.loc.rib.tables.routes.LinkstateRoutesCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.ObjectType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.attribute.SrAdjIds;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.LinkCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.NodeCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.PrefixCase;
@@ -48,17 +49,32 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.link
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.routes.LinkstateRoutes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.routes.linkstate.routes.LinkstateRoute;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.routes.linkstate.routes.linkstate.route.Attributes1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.prefix.state.SrPrefix;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.Attributes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.prefix.sid.tlv.Flags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.prefix.sid.tlv.flags.IsisPrefixFlagsCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.sid.label.index.SidLabelIndex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.sid.label.index.sid.label.index.LocalLabelCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.sid.label.index.sid.label.index.SidCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.topology.types.rev160524.TopologyTypes1;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.topology.types.rev160524.TopologyTypes1Builder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.odl.bgp.topology.types.rev160524.bgp.linkstate.topology.type.BgpLinkstateTopologyBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.SegmentId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.sr.node.attributes.Segments;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.sr.node.attributes.SegmentsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.sr.node.attributes.SegmentsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.sr.node.attributes.segments.segment.specification.AdjacencyCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.sr.node.attributes.segments.segment.specification.PrefixCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.sr.node.attributes.segments.segment.specification.adjacency._case.AdjacencyBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.topology.sr.type.TopologySrBuilder;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.DestinationBuilder;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.link.attributes.SourceBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkBuilder;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.LinkKey;
@@ -92,9 +108,17 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateRoute> {
-    private static final TopologyTypes LINKSTATE_TOPOLOGY_TYPE = new TopologyTypesBuilder()
+    @VisibleForTesting
+    static final TopologyTypes LINKSTATE_TOPOLOGY_TYPE = new TopologyTypesBuilder()
             .addAugmentation(TopologyTypes1.class, new TopologyTypes1Builder()
                     .setBgpLinkstateTopology(new BgpLinkstateTopologyBuilder().build()).build()).build();
+    @VisibleForTesting
+    static final TopologyTypes SR_AWARE_LINKSTATE_TOPOLOGY_TYPE = new TopologyTypesBuilder(LINKSTATE_TOPOLOGY_TYPE)
+            .addAugmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819
+                .TopologyTypes1.class,
+                new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819
+                .TopologyTypes1Builder().setTopologySr(new TopologySrBuilder().build()).build())
+            .build();
 
     private static final String UNHANDLED_OBJECT_CLASS = "Unhandled object class {}";
 
@@ -124,7 +148,8 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
                 removed = this.local.remove(id);
             }
             if (!removed) {
-                LOG.warn("Removed non-reference link {} from TP {} isRemote {}", this.tp.getTpId(), id, isRemote);
+                LOG.warn("Removed non-reference link {} from TP {} isRemote {}", this.tp.getTpId().getValue(),
+                        id.getValue(), isRemote);
             }
 
             return this.local.isEmpty() && this.remote.isEmpty();
@@ -141,6 +166,7 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
         private boolean advertized = false;
         private IgpNodeAttributesBuilder inab;
         private NodeBuilder nb;
+        private NodeSrHolder sr;
 
         NodeHolder(final NodeId id) {
             this.inab = new IgpNodeAttributesBuilder();
@@ -164,12 +190,12 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
 
             if (!this.advertized) {
                 if (this.tps.isEmpty() && this.prefixes.isEmpty()) {
-                    LOG.trace("Removing unadvertized unused node {}", this.nb.getNodeId());
+                    LOG.trace("Removing unadvertized unused node {}", this.nb.getNodeId().getValue());
                     return true;
                 }
 
-                LOG.trace("Node {} is still implied by {} TPs and {} prefixes", this.nb.getNodeId(), this.tps.size(),
-                        this.prefixes.size());
+                LOG.trace("Node {} is still implied by {} TPs and {} prefixes", this.nb.getNodeId().getValue(),
+                        this.tps.size(), this.prefixes.size());
             }
 
             // Re-generate termination points
@@ -179,8 +205,15 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
             this.inab.setPrefix(Lists.newArrayList(this.prefixes.values()));
 
             // Write the node out
-            final Node n = this.nb.addAugmentation(Node1.class, new Node1Builder()
-                    .setIgpNodeAttributes(this.inab.build()).build()).build();
+            if (this.sr != null && this.sr.getSegmentCount() > 0) {
+                this.nb.addAugmentation(
+                    org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.Node1.class,
+                    new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819
+                        .Node1Builder().setSegments(this.sr.getSegments()).build());
+            }
+            final Node n = this.nb
+                    .addAugmentation(Node1.class, new Node1Builder().setIgpNodeAttributes(this.inab.build()).build())
+                    .build();
             trans.put(LogicalDatastoreType.OPERATIONAL, nid, n);
             LOG.trace("Created node {} at {}", n, nid);
             return false;
@@ -192,11 +225,11 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
             if (!this.advertized) {
                 if (this.tps.isEmpty() && this.prefixes.isEmpty()) {
                     trans.delete(LogicalDatastoreType.OPERATIONAL, nid);
-                    LOG.trace("Removing unadvertized unused node {}", this.nb.getNodeId());
+                    LOG.trace("Removing unadvertized unused node {}", this.nb.getNodeId().getValue());
                     return true;
                 }
 
-                LOG.trace("Node {} is still implied by {} TPs and {} prefixes", this.nb.getNodeId(),
+                LOG.trace("Node {} is still implied by {} TPs and {} prefixes", this.nb.getNodeId().getValue(),
                         this.tps.size(), this.prefixes.size());
             }
             return false;
@@ -207,10 +240,10 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
             if (h != null) {
                 if (h.removeLink(link, isRemote)) {
                     this.tps.remove(tp);
-                    LOG.trace("Removed TP {}", tp);
+                    LOG.trace("Removed TP {}", tp.getValue());
                 }
             } else {
-                LOG.warn("Removed non-present TP {} by link {}", tp, link);
+                LOG.warn("Removed non-present TP {} by link {}", tp.getValue(), link.getValue());
             }
         }
 
@@ -231,23 +264,217 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
             this.inab = new IgpNodeAttributesBuilder();
             this.nb = new NodeBuilder().withKey(this.nb.key()).setNodeId(this.nb.getNodeId());
             this.advertized = false;
-            LOG.debug("Node {} is unadvertized", this.nb.getNodeId());
+            LOG.debug("Node {} is unadvertized", this.nb.getNodeId().getValue());
         }
 
         void advertized(final NodeBuilder nodeBuilder, final IgpNodeAttributesBuilder igpNodeAttBuilder) {
             this.nb = requireNonNull(nodeBuilder);
             this.inab = requireNonNull(igpNodeAttBuilder);
             this.advertized = true;
-            LOG.debug("Node {} is advertized", nodeBuilder.getNodeId());
+            LOG.debug("Node {} is advertized", nodeBuilder.getNodeId().getValue());
         }
 
         NodeId getNodeId() {
             return this.nb.getNodeId();
         }
+
+        NodeSrHolder getSrHolder() {
+            return this.sr;
+        }
+
+        NodeSrHolder createSrHolderIfRequired() {
+            if (this.sr == null) {
+                this.sr = new NodeSrHolder(this.nb.getNodeId());
+            }
+            return this.sr;
+        }
+    }
+
+    private final class NodeSrHolder {
+        private NodeId nodeId;
+        private Long srgbFirstValue = null;
+        private Integer srgbRangeSize = null;
+        private List<Segments> segments = new ArrayList<>();
+        private Map<IpPrefix, SrPrefix> srPrefixes = new HashMap<>();
+        private Map<IpPrefix, Segments> prefixSegments = new HashMap<>();
+        private Map<LinkId, Segments> adjSegments = new HashMap<>();
+
+        NodeSrHolder(final NodeId nodeId) {
+            this.nodeId = nodeId;
+        }
+
+        void addSrgb(final WriteTransaction trans, final boolean updateNode, final Long srgbFirstVal,
+                final Integer srgbRangeSz) {
+            this.srgbFirstValue = srgbFirstVal;
+            this.srgbRangeSize = srgbRangeSz;
+            this.srPrefixes.entrySet().forEach(entry -> {
+                final IpPrefix ippfx = entry.getKey();
+                final SrPrefix srPrefix = entry.getValue();
+                final SidLabelIndex sidLabelIndex = srPrefix.getSidLabelIndex();
+                if (sidLabelIndex instanceof SidCase) {
+                    final Long sidIndex = ((SidCase) sidLabelIndex).getSid().longValue();
+                    if (sidIndex >= this.srgbRangeSize) {
+                        LOG.warn("Prefix SID index {} is outside the SRGB range of {} for node {}", sidIndex,
+                                this.srgbRangeSize, this.nodeId.getValue());
+                        return;
+                    }
+                    final Long prefixSid = this.srgbFirstValue + sidIndex;
+                    final boolean isNodeSid = isAssociatedWithNodeSid(ippfx, srPrefix);
+                    addPrefixSid(trans, updateNode, ippfx, prefixSid, isNodeSid);
+                }
+            });
+        }
+
+        void removeSrgb(final WriteTransaction trans) {
+            this.srgbFirstValue = null;
+            this.srgbRangeSize = null;
+            this.srPrefixes.entrySet().forEach(entry -> {
+                final IpPrefix ippfx = entry.getKey();
+                final SrPrefix srPrefix = entry.getValue();
+                final SidLabelIndex sidLabelIndex = srPrefix.getSidLabelIndex();
+                if (sidLabelIndex instanceof SidCase) {
+                    removePrefixSid(trans, false, ippfx);
+                }
+            });
+        }
+
+        void addSrPrefix(final WriteTransaction trans, final boolean updateNode, final IpPrefix ippfx,
+                final SrPrefix srPrefix) {
+            this.srPrefixes.put(ippfx, srPrefix);
+            final SidLabelIndex sidLabelIndex = srPrefix.getSidLabelIndex();
+            Long prefixSid = null;
+            if (sidLabelIndex instanceof LocalLabelCase) {
+                prefixSid = ((LocalLabelCase) sidLabelIndex).getLocalLabel().getValue().longValue();
+            } else if (sidLabelIndex instanceof SidCase) {
+                if (this.srgbFirstValue != null && this.srgbRangeSize != null) {
+                    final Long sidIndex = ((SidCase) sidLabelIndex).getSid().longValue();
+                    if (sidIndex >= this.srgbRangeSize) {
+                        LOG.warn("Prefix SID index {} is outside the SRGB range of {} for node {}", sidIndex,
+                                this.srgbRangeSize, this.nodeId.getValue());
+                        return;
+                    }
+                    prefixSid = this.srgbFirstValue + sidIndex;
+                }
+            }
+            if (prefixSid != null) {
+                final boolean isNodeSid = isAssociatedWithNodeSid(ippfx, srPrefix);
+                addPrefixSid(trans, updateNode, ippfx, prefixSid, isNodeSid);
+            }
+        }
+
+        void removeSrPrefix(final WriteTransaction trans, final IpPrefix ippfx) {
+            if (!this.srPrefixes.containsKey(ippfx)) {
+                return;
+            }
+            removePrefixSid(trans, true, ippfx);
+            this.srPrefixes.remove(ippfx);
+        }
+
+        void addPrefixSid(final WriteTransaction trans, final boolean updateNode, final IpPrefix ippfx,
+                final Long prefixSid, final boolean isNodeSid) {
+            LOG.trace("Adding prefix SID {} for prefix {} on node {}", prefixSid, ippfx.stringValue(),
+                    this.nodeId.getValue());
+            final SegmentId segmentId = new SegmentId(Uint32.valueOf(prefixSid));
+            final Segments prefixSegment = new SegmentsBuilder()
+                    .setSegmentId(segmentId)
+                    .withKey(new SegmentsKey(segmentId))
+                    .setSegmentSpecification(new PrefixCaseBuilder()
+                        .setPrefix(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr
+                            .rev130819.sr.node.attributes.segments.segment.specification.prefix._case.PrefixBuilder()
+                                .setPrefix(ippfx).setNodeSid(isNodeSid ? isNodeSid : null).build())
+                        .build())
+                    .build();
+            this.prefixSegments.put(ippfx, prefixSegment);
+            this.segments.add(prefixSegment);
+            addSegment(trans, updateNode, prefixSegment);
+        }
+
+        void removePrefixSid(final WriteTransaction trans, final boolean updateNode, final IpPrefix ippfx) {
+            if (!this.prefixSegments.containsKey(ippfx)) {
+                return;
+            }
+            LOG.trace("Removing prefix SID for prefix {} on node {}", ippfx.stringValue(),
+                    this.nodeId.getValue());
+            final Segments prefixSegment = this.prefixSegments.remove(ippfx);
+            this.segments.remove(prefixSegment);
+            removeSegment(trans, updateNode, prefixSegment);
+        }
+
+        void addAdjacencySid(final WriteTransaction trans, final boolean updateNode, final LinkId linkId,
+                final Long adjSid) {
+            LOG.trace("Adding adjacency SID {} for link {} on node {}", adjSid, linkId.getValue(),
+                    this.nodeId.getValue());
+            final SegmentId segmentId = new SegmentId(Uint32.valueOf(adjSid));
+            final SegmentsBuilder sb = new SegmentsBuilder();
+            sb.setSegmentId(segmentId);
+            sb.withKey(new SegmentsKey(segmentId));
+            sb.setSegmentSpecification(new AdjacencyCaseBuilder()
+                    .setAdjacency(new AdjacencyBuilder().setAdjacency(linkId).build()).build());
+            final Segments adjSegment = sb.build();
+            this.adjSegments.put(linkId, adjSegment);
+            this.segments.add(adjSegment);
+            addSegment(trans, updateNode, adjSegment);
+        }
+
+        void removeAdjacencySid(final WriteTransaction trans, final LinkId linkId) {
+            if (!this.adjSegments.containsKey(linkId)) {
+                return;
+            }
+            LOG.trace("Removing adjacency SID for link {} on node {}", linkId.getValue(),
+                    this.nodeId.getValue());
+            final Segments adjSegment = this.adjSegments.remove(linkId);
+            this.segments.remove(adjSegment);
+            removeSegment(trans, true, adjSegment);
+        }
+
+        void addSegment(final WriteTransaction trans, final boolean updateNode, final Segments segment) {
+            if (updateNode) {
+                final InstanceIdentifier<Node> nodeIId = getNodeInstanceIdentifier(new NodeKey(this.nodeId));
+                final InstanceIdentifier<Segments> segmentIId = nodeIId.builder()
+                        .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr
+                            .rev130819.Node1.class)
+                        .child(Segments.class, segment.key()).build();
+                trans.put(LogicalDatastoreType.OPERATIONAL, segmentIId, segment);
+            }
+            addSrAwareTopologyType(trans);
+        }
+
+        void removeSegment(final WriteTransaction trans, final boolean updateNode, final Segments segment) {
+            if (updateNode) {
+                final InstanceIdentifier<Node> nodeIId = getNodeInstanceIdentifier(new NodeKey(this.nodeId));
+                final InstanceIdentifier<Segments> segmentIId = nodeIId.builder()
+                        .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr
+                            .rev130819.Node1.class)
+                        .child(Segments.class, segment.key()).build();
+                trans.delete(LogicalDatastoreType.OPERATIONAL, segmentIId);
+            }
+            removeSrAwareTopologyTypeIfRequired(trans);
+        }
+
+        boolean isAssociatedWithNodeSid(final IpPrefix ippfx, final SrPrefix srPrefix) {
+            if (ippfx.getIpv4Prefix() != null && !ippfx.stringValue().endsWith("/32")
+                    || ippfx.getIpv6Prefix() != null && !ippfx.stringValue().endsWith("/128")) {
+                return false;
+            }
+            final Flags prefixFlags = srPrefix.getFlags();
+            if (prefixFlags instanceof IsisPrefixFlagsCase) {
+                return !Boolean.FALSE.equals(((IsisPrefixFlagsCase) prefixFlags).getIsisPrefixFlags().isNodeSid());
+            }
+            return true;
+        }
+
+        List<Segments> getSegments() {
+            return this.segments;
+        }
+
+        int getSegmentCount() {
+            return this.segments.size();
+        }
     }
 
     private static final Logger LOG = LoggerFactory.getLogger(LinkstateTopologyBuilder.class);
     private final Map<NodeId, NodeHolder> nodes = new HashMap<>();
+    private boolean srAwareTopologyTypeAdded;
 
     public LinkstateTopologyBuilder(final DataBroker dataProvider, final RibReference locRibReference,
             final TopologyId topologyId) {
@@ -398,11 +625,21 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
         }
 
         final IgpLinkAttributesBuilder ilab = new IgpLinkAttributesBuilder();
+        Long adjSid = null;
         if (la != null) {
             if (la.getMetric() != null) {
                 ilab.setMetric(la.getMetric().getValue());
             }
             ilab.setName(la.getLinkName());
+            if (la.getSrAdjIds() != null && !la.getSrAdjIds().isEmpty()) {
+                final SrAdjIds srAdjIds = la.getSrAdjIds().get(0);
+                if (srAdjIds != null) {
+                    final SidLabelIndex sidLabelIndex = srAdjIds.getSidLabelIndex();
+                    if (sidLabelIndex instanceof LocalLabelCase) {
+                        adjSid = ((LocalLabelCase) sidLabelIndex).getLocalLabel().getValue().longValue();
+                    }
+                }
+            }
         }
         ProtocolUtil.augmentProtocolId(value, ilab, la, linkCase.getLinkDescriptors());
 
@@ -430,12 +667,24 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
         if (snh == null) {
             snh = getNode(srcNode);
             snh.addTp(srcTp, lb.getLinkId(), false);
+            if (adjSid != null) {
+                snh.createSrHolderIfRequired().addAdjacencySid(trans, false, lb.getLinkId(), adjSid);
+            }
             putNode(trans, snh);
         } else {
             snh.addTp(srcTp, lb.getLinkId(), false);
+            if (adjSid != null) {
+                snh.createSrHolderIfRequired().addAdjacencySid(trans, true, lb.getLinkId(), adjSid);
+            }
             final InstanceIdentifier<Node> nid = getNodeInstanceIdentifier(new NodeKey(snh.getNodeId()));
             trans.put(LogicalDatastoreType.OPERATIONAL, nid.child(TerminationPoint.class, srcTp.key()), srcTp);
         }
+        if (adjSid != null) {
+            lb.addAugmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819
+                    .Link1.class,
+                new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819
+                    .Link1Builder().setSegment(new SegmentId(Uint32.valueOf(adjSid))).build());
+        }
 
         LOG.debug("Created TP {} as link destination", dstTp);
         NodeHolder dnh = this.nodes.get(dstNode);
@@ -466,9 +715,12 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
             trans.delete(LogicalDatastoreType.OPERATIONAL, nid.child(TerminationPoint.class,
                     new TerminationPointKey(tp)));
             nh.removeTp(tp, link, isRemote);
+            if (!isRemote) {
+                nh.createSrHolderIfRequired().removeAdjacencySid(trans, link);
+            }
             checkNodeForRemoval(trans, nh);
         } else {
-            LOG.warn("Removed non-existent node {}", node);
+            LOG.warn("Removed non-existent node {}", node.getValue());
         }
     }
 
@@ -503,6 +755,8 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
         }
         final IgpNodeAttributesBuilder inab = new IgpNodeAttributesBuilder();
         final List<IpAddress> ids = new ArrayList<>();
+        Long srgbFirstValue = null;
+        Integer srgbRangeSize = null;
         if (na != null) {
             if (na.getIpv4RouterId() != null) {
                 ids.add(new IpAddress(na.getIpv4RouterId()));
@@ -513,6 +767,15 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
             if (na.getDynamicHostname() != null) {
                 inab.setName(new DomainName(na.getDynamicHostname()));
             }
+            if (na.getSrCapabilities() != null) {
+                final SidLabelIndex sidLabelIndex = na.getSrCapabilities().getSidLabelIndex();
+                if (sidLabelIndex instanceof LocalLabelCase) {
+                    srgbFirstValue = ((LocalLabelCase) sidLabelIndex).getLocalLabel().getValue().longValue();
+                }
+                srgbRangeSize = na.getSrCapabilities().getRangeSize() != null
+                        ? na.getSrCapabilities().getRangeSize().getValue().intValue()
+                        : null;
+            }
         }
         if (!ids.isEmpty()) {
             inab.setRouterId(ids);
@@ -531,6 +794,9 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
         nb.withKey(new NodeKey(nb.getNodeId()));
 
         nh.advertized(nb, inab);
+        if (srgbFirstValue != null && srgbRangeSize != null) {
+            nh.createSrHolderIfRequired().addSrgb(trans, false, srgbFirstValue, srgbRangeSize);
+        }
         putNode(trans, nh);
     }
 
@@ -539,9 +805,10 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
         final NodeHolder nh = this.nodes.get(id);
         if (nh != null) {
             nh.unadvertized();
+            nh.createSrHolderIfRequired().removeSrgb(trans);
             putNode(trans, nh);
         } else {
-            LOG.warn("Node {} does not have a holder", id);
+            LOG.warn("Node {} does not have a holder", id.getValue());
         }
     }
 
@@ -572,8 +839,14 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
             LOG.debug("Missing attributes in IP {} prefix {} route {}, skipping it", ippfx, prefixCase, value);
             pa = null;
         }
-        if (pa != null && pa.getPrefixMetric() != null) {
-            pb.setMetric(pa.getPrefixMetric().getValue());
+        SrPrefix srPrefix = null;
+        if (pa != null) {
+            if (pa.getPrefixMetric() != null) {
+                pb.setMetric(pa.getPrefixMetric().getValue());
+            }
+            if (pa.getSrPrefix() != null) {
+                srPrefix = pa.getSrPrefix();
+            }
         }
         ProtocolUtil.augmentProtocolId(value, pa, pb);
 
@@ -588,9 +861,15 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
         if (nh == null) {
             nh = getNode(node);
             nh.addPrefix(pfx);
+            if (srPrefix != null) {
+                nh.createSrHolderIfRequired().addSrPrefix(trans, false, ippfx, srPrefix);
+            }
             putNode(trans, nh);
         } else {
             nh.addPrefix(pfx);
+            if (srPrefix != null) {
+                nh.createSrHolderIfRequired().addSrPrefix(trans, true, ippfx, srPrefix);
+            }
             final InstanceIdentifier<Node> nid = getNodeInstanceIdentifier(new NodeKey(nh.getNodeId()));
             final InstanceIdentifier<IgpNodeAttributes> inaId = nid.builder().augmentation(Node1.class)
                     .child(IgpNodeAttributes.class).build();
@@ -614,9 +893,10 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
             final PrefixKey pk = new PrefixKey(ippfx);
             trans.delete(LogicalDatastoreType.OPERATIONAL, inaId.child(Prefix.class, pk));
             nh.removePrefix(prefixCase);
+            nh.createSrHolderIfRequired().removeSrPrefix(trans, ippfx);
             checkNodeForRemoval(trans, nh);
         } else {
-            LOG.warn("Removing prefix from non-existing node {}", node);
+            LOG.warn("Removing prefix from non-existing node {}", node.getValue());
         }
     }
 
@@ -626,6 +906,33 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
                         .topology.topology.Node.class, nodeKey);
     }
 
+    protected void addSrAwareTopologyType(final WriteTransaction trans) {
+        if (this.srAwareTopologyTypeAdded) {
+            return;
+        }
+        LOG.debug("Adding SR-aware topology-type for topology {}",
+                getInstanceIdentifier().firstKeyOf(Topology.class).getTopologyId().getValue());
+        trans.put(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier().child(TopologyTypes.class),
+                SR_AWARE_LINKSTATE_TOPOLOGY_TYPE);
+        this.srAwareTopologyTypeAdded = true;
+    }
+
+    protected void removeSrAwareTopologyTypeIfRequired(final WriteTransaction trans) {
+        if (!this.srAwareTopologyTypeAdded) {
+            return;
+        }
+        final boolean isSidPresent = this.nodes.values().stream().filter(nh -> nh.getSrHolder() != null)
+                .map(nh -> nh.getSrHolder().getSegmentCount()).anyMatch(cnt -> cnt != 0);
+        if (isSidPresent) {
+            return;
+        }
+        LOG.debug("Removing SR-aware topology-type from topology {}",
+                getInstanceIdentifier().firstKeyOf(Topology.class).getTopologyId().getValue());
+        trans.put(LogicalDatastoreType.OPERATIONAL, getInstanceIdentifier().child(TopologyTypes.class),
+                LINKSTATE_TOPOLOGY_TYPE);
+        this.srAwareTopologyTypeAdded = false;
+    }
+
     @Override
     protected void createObject(final ReadWriteTransaction trans,
             final InstanceIdentifier<LinkstateRoute> id, final LinkstateRoute value) {
@@ -675,5 +982,6 @@ public class LinkstateTopologyBuilder extends AbstractTopologyBuilder<LinkstateR
     @Override
     protected void clearTopology() {
         this.nodes.clear();
+        this.srAwareTopologyTypeAdded = false;
     }
 }
index 33b80c25687fd7e1f45245cf6865ab45f8eba54f..f3ba073f70d794b9ee119535d6b125eaa2cdd85f 100644 (file)
@@ -9,7 +9,6 @@ package org.opendaylight.bgpcep.bgp.topology.provider;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -52,6 +51,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.link
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.ProtocolId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.TopologyIdentifier;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.bgp.rib.rib.loc.rib.tables.routes.LinkstateRoutesCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.attribute.SrAdjIdsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.attribute.UnreservedBandwidthBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.attribute.UnreservedBandwidthKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.link._case.LinkDescriptorsBuilder;
@@ -74,18 +74,25 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.link
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.routes.linkstate.routes.linkstate.route.Attributes1Builder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.node.identifier.c.router.identifier.IsisNodeCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.node.identifier.c.router.identifier.isis.node._case.IsisNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.node.state.SrCapabilitiesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.prefix.state.SrPrefixBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.PathId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.AttributesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.attributes.OriginBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.LocRib;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.Algorithm;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.sid.label.index.sid.label.index.LocalLabelCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.segment.routing.ext.rev200120.sid.label.index.sid.label.index.SidCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.BgpOrigin;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.Bandwidth;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.IgpMetric;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.IsoSystemIdentifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.MplsLabel;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.TeMetric;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.SrlgId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.uint24.rev200104.Uint24;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.isis.topology.rev131021.IgpLinkAttributes1;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.isis.topology.rev131021.IgpNodeAttributes1;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
@@ -103,8 +110,6 @@ import org.opendaylight.yangtools.yang.common.Uint8;
 
 public class LinkstateTopologyBuilderTest extends AbstractTopologyBuilderTest {
 
-    private static final String LINKSTATE_ROUTE_KEY = Unpooled.wrappedBuffer(
-        StandardCharsets.UTF_8.encode("linkstate-route")).array().toString();
     private static final String ROUTER_1_ID = "127.0.0.1";
     private static final String ROUTER_2_ID = "127.0.0.2";
     private static final String NODE_1_PREFIX = "127.0.1.1/32";
@@ -117,9 +122,19 @@ public class LinkstateTopologyBuilderTest extends AbstractTopologyBuilderTest {
     private static final Identifier IDENTIFIER = new Identifier(Uint64.ONE);
     private static final long LISTENER_RESTART_TIME = 20000;
     private static final int LISTENER_ENFORCE_COUNTER = 2;
+    private static final int SRGB_START = 90000;
+    private static final int SRGB_RANGE = 16;
+    private static final int NODE_SID_INDEX = 4;
+    private static final int ADJ_SID = 24001;
 
     private LinkstateTopologyBuilder linkstateTopoBuilder;
-    private InstanceIdentifier<LinkstateRoute> linkstateRouteIID;
+    private InstanceIdentifier<Tables> tablePathIID;
+    private String linkstateNodeRouteKey;
+    private String linkstatePrefixRouteKey;
+    private String linkstateLinkRouteKey;
+    private InstanceIdentifier<LinkstateRoute> linkstateNodeRouteIID;
+    private InstanceIdentifier<LinkstateRoute> linkstatePrefixRouteIID;
+    private InstanceIdentifier<LinkstateRoute> linkstateLinkRouteIID;
 
     @Before
     @Override
@@ -128,13 +143,17 @@ public class LinkstateTopologyBuilderTest extends AbstractTopologyBuilderTest {
         this.linkstateTopoBuilder = new LinkstateTopologyBuilder(getDataBroker(), LOC_RIB_REF, TEST_TOPOLOGY_ID,
             LISTENER_RESTART_TIME, LISTENER_ENFORCE_COUNTER);
         this.linkstateTopoBuilder.start();
-        final InstanceIdentifier<Tables> path = LOC_RIB_REF.getInstanceIdentifier().builder().child(LocRib.class)
-            .child(Tables.class, new TablesKey(LinkstateAddressFamily.class, LinkstateSubsequentAddressFamily.class))
-            .build();
-        this.linkstateRouteIID = path.builder().child(LinkstateRoutesCase.class, LinkstateRoutes.class)
-            .child(LinkstateRoute.class, new LinkstateRouteKey(new PathId(Uint32.ZERO), LINKSTATE_ROUTE_KEY))
-                .build();
-
+        this.tablePathIID =
+                LOC_RIB_REF.getInstanceIdentifier().builder().child(LocRib.class)
+                        .child(Tables.class,
+                                new TablesKey(LinkstateAddressFamily.class, LinkstateSubsequentAddressFamily.class))
+                        .build();
+        this.linkstateNodeRouteKey = getLinkstateRouteKey("node-route");
+        this.linkstatePrefixRouteKey = getLinkstateRouteKey("prefix-route");
+        this.linkstateLinkRouteKey = getLinkstateRouteKey("link-route");
+        this.linkstateNodeRouteIID = createLinkstateRouteIID(this.linkstateNodeRouteKey);
+        this.linkstatePrefixRouteIID = createLinkstateRouteIID(this.linkstatePrefixRouteKey);
+        this.linkstateLinkRouteIID = createLinkstateRouteIID(this.linkstateLinkRouteKey);
     }
 
     @After
@@ -146,19 +165,17 @@ public class LinkstateTopologyBuilderTest extends AbstractTopologyBuilderTest {
     @Test
     public void testLinkstateTopologyBuilderTopologyTypes() throws InterruptedException, ExecutionException {
         readDataOperational(getDataBroker(), this.linkstateTopoBuilder.getInstanceIdentifier(), topology -> {
-            assertNotNull(topology.getTopologyTypes().augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight
-                    .params.xml.ns.yang.odl.bgp.topology.types.rev160524.TopologyTypes1.class));
-            assertNotNull(topology.getTopologyTypes().augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight
-                    .params.xml.ns.yang.odl.bgp.topology.types.rev160524.TopologyTypes1.class)
-                    .getBgpLinkstateTopology());
+            assertEquals(LinkstateTopologyBuilder.LINKSTATE_TOPOLOGY_TYPE, topology.getTopologyTypes());
             return topology;
         });
     }
 
     @Test
+    @SuppressWarnings("checkstyle:LineLength")
     public void testIsisLinkstateTopologyBuilder() throws InterruptedException, ExecutionException {
         // create node
-        updateLinkstateRoute(createLinkstateNodeRoute(ProtocolId.IsisLevel2, "node1", NODE_1_AS, ROUTER_1_ID));
+        updateLinkstateRoute(this.linkstateNodeRouteIID,
+                createLinkstateNodeRoute(ProtocolId.IsisLevel2, "node1", NODE_1_AS, ROUTER_1_ID));
         readDataOperational(getDataBroker(), this.linkstateTopoBuilder.getInstanceIdentifier(), topology -> {
             assertEquals(1, topology.getNode().size());
             final Node node1 = topology.getNode().get(0);
@@ -175,12 +192,15 @@ public class LinkstateTopologyBuilderTest extends AbstractTopologyBuilderTest {
                     .getNet().get(0).getValue());
             assertNull(igpNode1.augmentation(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.ospf
                     .topology.rev131021.IgpNodeAttributes1.class));
+            assertEquals(LinkstateTopologyBuilder.LINKSTATE_TOPOLOGY_TYPE, topology.getTopologyTypes());
+            assertNull(node1.augmentation(
+                    org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.Node1.class));
             return topology;
         });
 
-
         // create link
-        updateLinkstateRoute(createLinkstateLinkRoute(ProtocolId.IsisLevel2, NODE_1_AS, NODE_2_AS, "link1"));
+        updateLinkstateRoute(this.linkstateLinkRouteIID,
+                createLinkstateLinkRoute(ProtocolId.IsisLevel2, NODE_1_AS, NODE_2_AS, "link1"));
         readDataOperational(getDataBroker(), this.linkstateTopoBuilder.getInstanceIdentifier(), topology -> {
             assertEquals(1, topology.getLink().size());
             final Link link1 = topology.getLink().get(0);
@@ -197,13 +217,27 @@ public class LinkstateTopologyBuilderTest extends AbstractTopologyBuilderTest {
                     .getMultiTopologyId().shortValue());
             assertNull(igpLink1.augmentation(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.ospf
                     .topology.rev131021.IgpLinkAttributes1.class));
+            assertEquals(LinkstateTopologyBuilder.SR_AWARE_LINKSTATE_TOPOLOGY_TYPE, topology.getTopologyTypes());
+            assertEquals(2, topology.getNode().size());
+            final Node srcNode;
+            if (topology.getNode().get(0).getNodeId().getValue().contains("0000.0102.0304")) {
+                srcNode = topology.getNode().get(0);
+            } else {
+                srcNode = topology.getNode().get(1);
+            }
+            assertEquals(1, srcNode.augmentation(
+                    org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.Node1.class)
+                    .getSegments().size());
+            assertEquals(ADJ_SID, link1.augmentation(
+                    org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.Link1.class)
+                    .getSegment().getValue().intValue());
             return topology;
         });
-
+        removeLinkstateRoute(this.linkstateLinkRouteIID);
 
         // update node
-        updateLinkstateRoute(createLinkstateNodeRoute(ProtocolId.IsisLevel2, "updated-node",
-                NODE_1_AS, ROUTER_2_ID));
+        updateLinkstateRoute(this.linkstateNodeRouteIID,
+                createLinkstateNodeRoute(ProtocolId.IsisLevel2, "updated-node", NODE_1_AS, ROUTER_2_ID));
         readDataOperational(getDataBroker(), this.linkstateTopoBuilder.getInstanceIdentifier(), topology -> {
             assertEquals(1, topology.getNode().size());
             final IgpNodeAttributes igpNode2 = topology.getNode().get(0).augmentation(Node1.class)
@@ -214,10 +248,9 @@ public class LinkstateTopologyBuilderTest extends AbstractTopologyBuilderTest {
         });
 
         // remove
-        final WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction();
-        wTx.delete(LogicalDatastoreType.OPERATIONAL, this.linkstateRouteIID);
-        wTx.commit();
+        removeLinkstateRoute(this.linkstateNodeRouteIID);
         readDataOperational(getDataBroker(), this.linkstateTopoBuilder.getInstanceIdentifier(), topology -> {
+            assertEquals(LinkstateTopologyBuilder.LINKSTATE_TOPOLOGY_TYPE, topology.getTopologyTypes());
             assertNull(topology.getNode());
             assertNull(topology.getLink());
             return topology;
@@ -225,9 +258,11 @@ public class LinkstateTopologyBuilderTest extends AbstractTopologyBuilderTest {
     }
 
     @Test
+    @SuppressWarnings("checkstyle:LineLength")
     public void testOspfLinkstateTopologyBuilder() throws InterruptedException, ExecutionException {
         // create node
-        updateLinkstateRoute(createLinkstateNodeRoute(ProtocolId.Ospf, "node1", NODE_1_AS, ROUTER_1_ID));
+        updateLinkstateRoute(this.linkstateNodeRouteIID,
+                createLinkstateNodeRoute(ProtocolId.Ospf, "node1", NODE_1_AS, ROUTER_1_ID));
         readDataOperational(getDataBroker(), this.linkstateTopoBuilder.getInstanceIdentifier(), topology -> {
             assertEquals(1, topology.getNode().size());
             final Node node1 = topology.getNode().get(0);
@@ -239,25 +274,35 @@ public class LinkstateTopologyBuilderTest extends AbstractTopologyBuilderTest {
             assertEquals(ROUTER_1_ID, igpNode1.augmentation(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns
                     .yang.ospf.topology.rev131021.IgpNodeAttributes1.class).getOspfNodeAttributes().getTed()
                     .getTeRouterIdIpv4().getValue());
+            assertEquals(LinkstateTopologyBuilder.LINKSTATE_TOPOLOGY_TYPE, topology.getTopologyTypes());
+            assertNull(node1.augmentation(
+                    org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.Node1.class));
             return topology;
         });
 
         // update node with prefix
-        updateLinkstateRoute(createLinkstatePrefixRoute(ProtocolId.Ospf, NODE_1_AS, NODE_1_PREFIX,
-                500L, ROUTER_1_ID));
+        updateLinkstateRoute(this.linkstatePrefixRouteIID,
+                createLinkstatePrefixRoute(ProtocolId.Ospf, NODE_1_AS, NODE_1_PREFIX, 500L, ROUTER_1_ID));
         readDataOperational(getDataBroker(), this.linkstateTopoBuilder.getInstanceIdentifier(), topology -> {
-            final IgpNodeAttributes igpNode2 = topology.getNode().get(0).augmentation(Node1.class)
-                    .getIgpNodeAttributes();
-            assertEquals(1, igpNode2.getPrefix().size());
-            final Prefix prefix = igpNode2.getPrefix().get(0);
+            final Node node1 = topology.getNode().get(0);
+            final IgpNodeAttributes igpNode1 = node1.augmentation(Node1.class).getIgpNodeAttributes();
+            assertEquals(1, igpNode1.getPrefix().size());
+            final Prefix prefix = igpNode1.getPrefix().get(0);
             assertEquals(NODE_1_PREFIX, prefix.getPrefix().getIpv4Prefix().getValue());
             assertEquals(500L, prefix.getMetric().longValue());
+            assertEquals(LinkstateTopologyBuilder.SR_AWARE_LINKSTATE_TOPOLOGY_TYPE, topology.getTopologyTypes());
+            assertEquals(1, node1.augmentation(
+                    org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.Node1.class)
+                    .getSegments().size());
+            assertEquals(SRGB_START + NODE_SID_INDEX, node1.augmentation(
+                    org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.Node1.class)
+                    .getSegments().get(0).getSegmentId().getValue().intValue());
             return topology;
         });
 
-
         // create link
-        updateLinkstateRoute(createLinkstateLinkRoute(ProtocolId.Ospf, NODE_1_AS, NODE_2_AS, "link1"));
+        updateLinkstateRoute(this.linkstateLinkRouteIID,
+                createLinkstateLinkRoute(ProtocolId.Ospf, NODE_1_AS, NODE_2_AS, "link1"));
         readDataOperational(getDataBroker(), this.linkstateTopoBuilder.getInstanceIdentifier(), topology -> {
             assertEquals(1, topology.getLink().size());
             final Link link1 = topology.getLink().get(0);
@@ -277,10 +322,22 @@ public class LinkstateTopologyBuilderTest extends AbstractTopologyBuilderTest {
             assertEquals(2, igpLink1.augmentation(org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns
                     .yang.ospf.topology.rev131021.IgpLinkAttributes1.class).getOspfLinkAttributes().getTed().getSrlg()
                     .getSrlgValues().size());
+            assertEquals(LinkstateTopologyBuilder.SR_AWARE_LINKSTATE_TOPOLOGY_TYPE, topology.getTopologyTypes());
+            assertEquals(2, topology.getNode().size());
+            final Node srcNode;
+            if (topology.getNode().get(0).getNodeId().getValue().contains("0000.0102.0304")) {
+                srcNode = topology.getNode().get(0);
+            } else {
+                srcNode = topology.getNode().get(1);
+            }
+            assertEquals(2, srcNode.augmentation(
+                    org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.Node1.class)
+                    .getSegments().size());
+            assertEquals(ADJ_SID, link1.augmentation(
+                    org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.sr.rev130819.Link1.class)
+                    .getSegment().getValue().intValue());
             return topology;
         });
-
-
     }
 
     /**
@@ -358,17 +415,33 @@ public class LinkstateTopologyBuilderTest extends AbstractTopologyBuilderTest {
         verify(spiedLinkstateTopologyBuilder, times(1)).resetListener();
     }
 
-    private void updateLinkstateRoute(final LinkstateRoute data) {
+    private static String getLinkstateRouteKey(final String routeKey) {
+        return Unpooled.wrappedBuffer(StandardCharsets.UTF_8.encode(routeKey)).array().toString();
+    }
+
+    private InstanceIdentifier<LinkstateRoute> createLinkstateRouteIID(final String linkstateRouteKey) {
+        return this.tablePathIID.builder().child(LinkstateRoutesCase.class, LinkstateRoutes.class)
+                .child(LinkstateRoute.class, new LinkstateRouteKey(new PathId(Uint32.ZERO), linkstateRouteKey)).build();
+    }
+
+    private void updateLinkstateRoute(final InstanceIdentifier<LinkstateRoute> linkstateRouteIID,
+            final LinkstateRoute data) {
         final WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction();
-        wTx.mergeParentStructurePut(LogicalDatastoreType.OPERATIONAL, this.linkstateRouteIID, data);
+        wTx.mergeParentStructurePut(LogicalDatastoreType.OPERATIONAL, linkstateRouteIID, data);
         wTx.commit();
     }
 
-    private static LinkstateRoute createLinkstateNodeRoute(final ProtocolId protocolId, final String nodeName,
+    private void removeLinkstateRoute(final InstanceIdentifier<LinkstateRoute> linkstateRouteIID) {
+        final WriteTransaction wTx = getDataBroker().newWriteOnlyTransaction();
+        wTx.delete(LogicalDatastoreType.OPERATIONAL, linkstateRouteIID);
+        wTx.commit();
+    }
+
+    private LinkstateRoute createLinkstateNodeRoute(final ProtocolId protocolId, final String nodeName,
             final AsNumber asNumber, final String ipv4RouterId) {
-        return createBaseBuilder(protocolId)
-                .setObjectType(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang
-                    .bgp.linkstate.rev200120.linkstate.object.type.NodeCaseBuilder()
+        return createBaseBuilder(this.linkstateNodeRouteKey, protocolId)
+                .setObjectType(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate
+                        .rev200120.linkstate.object.type.NodeCaseBuilder()
                         .setNodeDescriptors(new NodeDescriptorsBuilder()
                                 .setCRouterIdentifier(new IsisNodeCaseBuilder().setIsisNode(new IsisNodeBuilder()
                                         .setIsoSystemId(new IsoSystemIdentifier(new byte[]{0, 0, 1, 2, 3, 4})).build())
@@ -383,15 +456,25 @@ public class LinkstateTopologyBuilderTest extends AbstractTopologyBuilderTest {
                                                 .setIpv4RouterId(new Ipv4RouterIdentifier(ipv4RouterId))
                                                 .setIsisAreaId(Collections.singletonList(
                                                         new IsisAreaIdentifier(new byte[]{0x47})))
+                                                .setSrCapabilities(new SrCapabilitiesBuilder()
+                                                        .setRangeSize(new Uint24(Uint32.valueOf(SRGB_RANGE)))
+                                                        .setSidLabelIndex(new LocalLabelCaseBuilder()
+                                                                .setLocalLabel(
+                                                                        new MplsLabel(Uint32.valueOf(SRGB_START)))
+                                                                .build())
+                                                        .build())
                                                 .build()).build()).build()).build()).build();
     }
 
-    private static LinkstateRoute createLinkstatePrefixRoute(final ProtocolId protocolId, final AsNumber asNumber,
+    private LinkstateRoute createLinkstatePrefixRoute(final ProtocolId protocolId, final AsNumber asNumber,
             final String ipv4Prefix, final long igpMetric, final String ospfFwdAddress) {
-        return createBaseBuilder(protocolId)
+        return createBaseBuilder(this.linkstatePrefixRouteKey, protocolId)
             .setObjectType(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120
                     .linkstate.object.type.PrefixCaseBuilder()
-                .setAdvertisingNodeDescriptors(new AdvertisingNodeDescriptorsBuilder().setAsNumber(asNumber).build())
+                .setAdvertisingNodeDescriptors(new AdvertisingNodeDescriptorsBuilder()
+                        .setCRouterIdentifier(new IsisNodeCaseBuilder().setIsisNode(new IsisNodeBuilder()
+                                .setIsoSystemId(new IsoSystemIdentifier(new byte[]{0, 0, 1, 2, 3, 4})).build())
+                                .build()).setAsNumber(asNumber).build())
                 .setPrefixDescriptors(new PrefixDescriptorsBuilder()
                         .setIpReachabilityInformation(new IpPrefix(new Ipv4Prefix(ipv4Prefix))).build()).build())
             .setAttributes(new AttributesBuilder()
@@ -401,6 +484,11 @@ public class LinkstateTopologyBuilderTest extends AbstractTopologyBuilderTest {
                             .setPrefixAttributes(new PrefixAttributesBuilder()
                                 .setOspfForwardingAddress(new IpAddressNoZone(new Ipv4AddressNoZone(ospfFwdAddress)))
                                 .setPrefixMetric(new IgpMetric(Uint32.valueOf(igpMetric)))
+                                .setSrPrefix(new SrPrefixBuilder()
+                                        .setAlgorithm(Algorithm.ShortestPathFirst)
+                                        .setSidLabelIndex(new SidCaseBuilder()
+                                                .setSid(Uint32.valueOf(NODE_SID_INDEX)).build())
+                                        .build())
                                 .build())
                             .build())
                         .build())
@@ -408,11 +496,11 @@ public class LinkstateTopologyBuilderTest extends AbstractTopologyBuilderTest {
             .build();
     }
 
-    private static LinkstateRoute createLinkstateLinkRoute(final ProtocolId protocolId, final AsNumber localAs,
+    private LinkstateRoute createLinkstateLinkRoute(final ProtocolId protocolId, final AsNumber localAs,
             final AsNumber remoteAs, final String linkName) {
-        return createBaseBuilder(protocolId)
-                .setObjectType(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang
-                    .bgp.linkstate.rev200120.linkstate.object.type.LinkCaseBuilder()
+        return createBaseBuilder(this.linkstateLinkRouteKey, protocolId)
+                .setObjectType(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate
+                        .rev200120.linkstate.object.type.LinkCaseBuilder()
                         .setLocalNodeDescriptors(new LocalNodeDescriptorsBuilder().setAsNumber(localAs)
                                 .setCRouterIdentifier(new IsisNodeCaseBuilder().setIsisNode(new IsisNodeBuilder()
                                         .setIsoSystemId(new IsoSystemIdentifier(new byte[]{0, 0, 1, 2, 3, 4}))
@@ -438,6 +526,11 @@ public class LinkstateTopologyBuilderTest extends AbstractTopologyBuilderTest {
                                                 .build()))
                                         .setTeMetric(new TeMetric(Uint32.valueOf(100)))
                                         .setLinkName(linkName)
+                                        .setSrAdjIds(Collections.singletonList(new SrAdjIdsBuilder()
+                                                .setSidLabelIndex(new LocalLabelCaseBuilder()
+                                                        .setLocalLabel(new MplsLabel(Uint32.valueOf(ADJ_SID)))
+                                                        .build())
+                                                .build()))
                                         .build())
                                     .build())
                                 .build())
@@ -445,11 +538,12 @@ public class LinkstateTopologyBuilderTest extends AbstractTopologyBuilderTest {
                 .build();
     }
 
-    private static LinkstateRouteBuilder createBaseBuilder(final ProtocolId protocolId) {
+    private static LinkstateRouteBuilder createBaseBuilder(final String linkstateRouteKey,
+            final ProtocolId protocolId) {
         return new LinkstateRouteBuilder()
             .setIdentifier(IDENTIFIER)
-            .withKey(new LinkstateRouteKey(new PathId(Uint32.ZERO), LINKSTATE_ROUTE_KEY))
-            .setRouteKey(LINKSTATE_ROUTE_KEY)
+            .withKey(new LinkstateRouteKey(new PathId(Uint32.ZERO), linkstateRouteKey))
+            .setRouteKey(linkstateRouteKey)
             .setProtocolId(protocolId);
     }
 }
index 71cb5dd3d2d247f629772d5ee3bfbb5373b5320b..307f4610643b74ec86dec200fc43cbf78a5d4685 100644 (file)
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>concepts</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal.binding.model.ietf</groupId>
+            <artifactId>rfc6991-ietf-inet-types</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.mdsal.model</groupId>
             <artifactId>ietf-topology</artifactId>
index b94990aa8b92aa9b71e4c1796ee9f8a19c3aa45b..2adf5e91575c4281defad4cc6684552ba944c44c 100644 (file)
@@ -3,6 +3,7 @@ module network-topology-sr {
     namespace "urn:opendaylight:params:xml:ns:yang:topology:sr";
     prefix "sr";
 
+    import ietf-inet-types { prefix inet; revision-date 2013-07-15; }
     import network-topology { prefix nt; revision-date 2013-10-21; }
 
     organization "Cisco Systems, Inc.";
@@ -59,12 +60,16 @@ module network-topology-sr {
                         }
                     }
                 }
-                case node-case {
-                    container node {
-                        leaf node {
-                            type nt:node-ref;
+                case prefix-case {
+                    container prefix {
+                        leaf prefix {
+                            type inet:ip-prefix;
                             mandatory true;
                         }
+                        leaf node-sid {
+                            type boolean;
+                            default false;
+                        }
                     }
                 }
             }