BUG-2823: Simplify AS_PATH encoding 75/23775/22
authorIveta Halanova <iveta.halanova@pantheon.sk>
Mon, 13 Jul 2015 05:43:24 +0000 (07:43 +0200)
committerIveta Halanova <iveta.halanova@pantheon.sk>
Mon, 13 Jul 2015 12:29:28 +0000 (14:29 +0200)
Expaned yang model by leaf-lists as-set and as-sequence as new type and marked
old type as obsolete.
Changed bgp-parser functionality to support just new type.
Changed bgp-rib functionality to support just new type.
Updated and expanded unit tests.

Change-Id: I1a832167afa9c19f4de358704d122d969b8b6fa8
Signed-off-by: Iveta Halanova <iveta.halanova@pantheon.sk>
bgp/concepts/src/main/yang/bgp-types.yang
bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/AsPathAttributeParser.java
bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/AsPathSegmentParser.java
bgp/parser-impl/src/test/java/org/opendaylight/protocol/bgp/parser/impl/BGPParserTest.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AttributeOperations.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/BestPathState.java
bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/AttributeOperationsTest.java
bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/BestPathSelectorTest.java

index f860d9feb03b3f1af2b41f6ac96e9fea5a1a30ce..1e5c2ad10cf039bd509e7c235e89f9abd0f7d32f 100644 (file)
@@ -211,6 +211,8 @@ module bgp-types {
     grouping as-path-segment {
         reference "http://tools.ietf.org/html/rfc4271#section-5.1.2";
         choice c-segment {
+        description "This model is obsolete and please use just leaf-lists as-sequence and as-set nested directly under as-path-segment.";
+            status obsolete;
             case a-set-case {
                 container a-set {
                     leaf-list as-set {
@@ -228,5 +230,13 @@ module bgp-types {
                 }
             }
         }
+        leaf-list as-sequence {
+            type inet:as-number;
+            ordered-by user;
+            max-elements "255";
+        }
+        leaf-list as-set {
+            type inet:as-number;
+        }
     }
 }
index 30a9ca671861832283eb39e80e999879595b88b6..3871c175305adafff3504c6d98046ddf3822aeaa 100644 (file)
@@ -28,13 +28,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.mess
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.AsPathBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.as.path.Segments;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.as.path.SegmentsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.AListCase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.AListCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.ASetCase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.ASetCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.AListBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.a.list.AsSequence;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.set._case.ASetBuilder;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -75,14 +68,12 @@ public final class AsPathAttributeParser implements AttributeParser, AttributeSe
             }
             final int count = buffer.readUnsignedByte();
 
+            final List<AsNumber> asList = AsPathSegmentParser.parseAsSegment(refCache, count, buffer.readSlice(count * AsPathSegmentParser.AS_NUMBER_LENGTH));
             if (segmentType == SegmentType.AS_SEQUENCE) {
-                final List<AsSequence> numbers = AsPathSegmentParser.parseAsSequence(refCache, count, buffer.readSlice(count * AsPathSegmentParser.AS_NUMBER_LENGTH));
-                ases.add(new SegmentsBuilder().setCSegment(
-                    new AListCaseBuilder().setAList(new AListBuilder().setAsSequence(numbers).build()).build()).build());
+                ases.add(new SegmentsBuilder().setAsSequence(asList).build());
                 isSequence = true;
             } else {
-                final List<AsNumber> list = AsPathSegmentParser.parseAsSet(refCache, count, buffer.readSlice(count * AsPathSegmentParser.AS_NUMBER_LENGTH));
-                ases.add(new SegmentsBuilder().setCSegment(new ASetCaseBuilder().setASet(new ASetBuilder().setAsSet(list).build()).build()).build());
+                ases.add(new SegmentsBuilder().setAsSet(asList).build());
             }
         }
         if (!isSequence) {
@@ -109,14 +100,12 @@ public final class AsPathAttributeParser implements AttributeParser, AttributeSe
         final ByteBuf segmentsBuffer = Unpooled.buffer();
         if (asPath.getSegments() != null) {
             for (final Segments segments : asPath.getSegments()) {
-                if (segments.getCSegment() instanceof AListCase) {
-                    final AListCase listCase = (AListCase) segments.getCSegment();
-                    AsPathSegmentParser.serializeAsSequence(listCase, segmentsBuffer);
-                } else if (segments.getCSegment() instanceof ASetCase) {
-                    final ASetCase set = (ASetCase) segments.getCSegment();
-                    AsPathSegmentParser.serializeAsSet(set, segmentsBuffer);
+                if (segments.getAsSequence() != null) {
+                    AsPathSegmentParser.serializeAsList(segments.getAsSequence(), SegmentType.AS_SEQUENCE, segmentsBuffer);
+                } else if (segments.getAsSet() != null) {
+                    AsPathSegmentParser.serializeAsList(segments.getAsSet(), SegmentType.AS_SET, segmentsBuffer);
                 } else {
-                    LOG.warn("Segment class is neither AListCase nor ASetCase.");
+                    LOG.warn("Segment doesn't have AsSequence nor AsSet list.");
                 }
             }
         }
index 2bc08e57af143d59534ebdda6c8f269252ed2731..1d1103a5a7e3b4dfbf9f910ea506bb9f9bdf554c 100644 (file)
@@ -10,19 +10,12 @@ package org.opendaylight.protocol.bgp.parser.impl.message.update;
 
 import static org.opendaylight.protocol.bgp.parser.impl.message.update.AsPathSegmentParser.SegmentType.AS_SEQUENCE;
 import static org.opendaylight.protocol.bgp.parser.impl.message.update.AsPathSegmentParser.SegmentType.AS_SET;
-
 import io.netty.buffer.ByteBuf;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import org.opendaylight.protocol.util.ReferenceCache;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.AListCase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.ASetCase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.AList;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.a.list.AsSequence;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.a.list.AsSequenceBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.set._case.ASet;
 
 /**
  * Representation of one AS Path Segment. It is, in fact, a TLV, but the length field is representing the count of AS
@@ -66,15 +59,7 @@ public final class AsPathSegmentParser {
         }
     }
 
-    static List<AsSequence> parseAsSequence(final ReferenceCache refCache, final int count, final ByteBuf buffer) {
-        final List<AsSequence> coll = new ArrayList<>(count);
-        for (int i = 0; i < count; i++) {
-            coll.add(refCache.getSharedReference(new AsSequenceBuilder().setAs(refCache.getSharedReference(new AsNumber(buffer.readUnsignedInt()))).build()));
-        }
-        return (coll.isEmpty()) ? Collections.<AsSequence>emptyList() : coll;
-    }
-
-    static List<AsNumber> parseAsSet(final ReferenceCache refCache, final int count, final ByteBuf buffer) {
+    static List<AsNumber> parseAsSegment(final ReferenceCache refCache, final int count, final ByteBuf buffer) {
         final List<AsNumber> coll = new ArrayList<>(count);
         for (int i = 0; i < count; i++) {
             coll.add(refCache.getSharedReference(new AsNumber(buffer.readUnsignedInt())));
@@ -82,27 +67,14 @@ public final class AsPathSegmentParser {
         return (coll.isEmpty()) ? Collections.<AsNumber>emptyList() : coll;
     }
 
-    static void serializeAsSet(final ASetCase aSetCase, final ByteBuf byteAggregator) {
-        final ASet aset = aSetCase.getASet();
-        if (aset == null || aset.getAsSet() == null) {
-            return;
-        }
-        byteAggregator.writeByte(serializeType(AS_SET));
-        byteAggregator.writeByte(aset.getAsSet().size());
-        for (final AsNumber asNumber : aset.getAsSet()) {
-            byteAggregator.writeInt(asNumber.getValue().intValue());
-        }
-    }
-
-    static void serializeAsSequence(final AListCase aListCase, final ByteBuf byteAggregator) {
-        final AList alist = aListCase.getAList();
-        if (alist == null || alist.getAsSequence() == null) {
+    static void serializeAsList(final List<AsNumber> asList, final SegmentType type, final ByteBuf byteAggregator) {
+        if (asList == null) {
             return;
         }
-        byteAggregator.writeByte(serializeType(AS_SEQUENCE));
-        byteAggregator.writeByte(alist.getAsSequence().size());
-        for (final AsSequence value : alist.getAsSequence()) {
-            byteAggregator.writeInt(value.getAs().getValue().intValue());
+        byteAggregator.writeByte(serializeType(type));
+        byteAggregator.writeByte(asList.size());
+        for (final AsNumber asNumber : asList) {
+            byteAggregator.writeInt( asNumber.getValue().intValue());
         }
     }
 }
index 6fb3c022976c2f3216af425e8064a585ed810ea1..06f73993467078fb24c6162e5a2b0aa20bba5ca7 100644 (file)
@@ -11,7 +11,6 @@ import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
-
 import com.google.common.collect.Lists;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
@@ -71,12 +70,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.type
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Ipv6AddressFamily;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.SubsequentAddressFamily;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.UnicastSubsequentAddressFamily;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.AListCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.ASetCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.AListBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.a.list.AsSequence;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.a.list.AsSequenceBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.set._case.ASetBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.extended.community.extended.community.Inet4SpecificExtendedCommunityCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.extended.community.extended.community.inet4.specific.extended.community._case.Inet4SpecificExtendedCommunityBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.c.next.hop.Ipv4NextHopCase;
@@ -184,11 +177,10 @@ public class BGPParserTest {
         assertNull(message.getWithdrawnRoutes());
 
         // attributes
-
-        final List<AsSequence> asnums = Lists.newArrayList(new AsSequenceBuilder().setAs(new AsNumber(65002L)).build());
+        final List<AsNumber> asNumbers = new ArrayList<AsNumber>();
+        asNumbers.add(new AsNumber(65002L));
         final List<Segments> asPath = Lists.newArrayList();
-        asPath.add(new SegmentsBuilder().setCSegment(
-            new AListCaseBuilder().setAList(new AListBuilder().setAsSequence(asnums).build()).build()).build());
+        asPath.add(new SegmentsBuilder().setAsSequence(asNumbers).build());
 
         final Ipv4NextHopCase nextHop = new Ipv4NextHopCaseBuilder().setIpv4NextHop(
             new Ipv4NextHopBuilder().setGlobal(new Ipv4Address("10.0.0.2")).build()).build();
@@ -321,11 +313,10 @@ public class BGPParserTest {
         assertNull(message.getNlri());
 
         // attributes
-
-        final List<AsSequence> asnums = Lists.newArrayList(new AsSequenceBuilder().setAs(new AsNumber(65001L)).build());
+        final List<AsNumber> asNumbers = new ArrayList<AsNumber>();
+        asNumbers.add(new AsNumber(65001L));
         final List<Segments> asPath = Lists.newArrayList();
-        asPath.add(new SegmentsBuilder().setCSegment(
-            new AListCaseBuilder().setAList(new AListBuilder().setAsSequence(asnums).build()).build()).build());
+        asPath.add(new SegmentsBuilder().setAsSequence(asNumbers).build());
 
         final Ipv6NextHopCase nextHop = new Ipv6NextHopCaseBuilder().setIpv6NextHop(
             new Ipv6NextHopBuilder().setGlobal(new Ipv6Address("2001:db8::1")).setLinkLocal(new Ipv6Address("fe80::c001:bff:fe7e:0")).build()).build();
@@ -433,12 +424,12 @@ public class BGPParserTest {
         assertNull(message.getWithdrawnRoutes());
 
         // attributes
-        final List<AsSequence> asnums = Lists.newArrayList(new AsSequenceBuilder().setAs(new AsNumber(30L)).build());
+        final List<AsNumber> asNumbers = new ArrayList<AsNumber>();
+        asNumbers.add(new AsNumber(30L));
         final List<Segments> asPath = Lists.newArrayList();
-        asPath.add(new SegmentsBuilder().setCSegment(
-            new AListCaseBuilder().setAList(new AListBuilder().setAsSequence(asnums).build()).build()).build());
-        asPath.add(new SegmentsBuilder().setCSegment(
-            new ASetCaseBuilder().setASet(new ASetBuilder().setAsSet(Lists.newArrayList(new AsNumber(10L), new AsNumber(20L))).build()).build()).build());
+        asPath.add(new SegmentsBuilder().setAsSequence(asNumbers).build());
+        final List<AsNumber> asSet = Lists.newArrayList(new AsNumber(10L), new AsNumber(20L));
+        asPath.add(new SegmentsBuilder().setAsSet(asSet).build());
 
         final Aggregator aggregator = new AggregatorBuilder().setAsNumber(new AsNumber((long) 30)).setNetworkAddress(
             new Ipv4Address("10.0.0.9")).build();
index d77401d459892888a014a2c718026e4d3a701948..d24bbe4d20b88ad6db3fc510ecd7712fdc07cdb7 100644 (file)
@@ -13,7 +13,6 @@ import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
-import java.util.Collection;
 import java.util.Iterator;
 import org.opendaylight.protocol.util.Values;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
@@ -26,9 +25,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.mess
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.UnrecognizedAttributes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.as.path.Segments;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.CSegment;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.AList;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.a.list.AsSequence;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.CNextHop;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
@@ -36,7 +32,6 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.Augmentat
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
@@ -50,7 +45,6 @@ import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -90,19 +84,15 @@ final class AttributeOperations {
     private final NodeIdentifier clusterListLeaf;
     private final NodeIdentifier asPathContainer;
     private final NodeIdentifier asPathSegments;
-    private final NodeIdentifier asPathChoice;
-    private final NodeIdentifier asPathList;
     private final NodeIdentifier asPathSequence;
-    private final NodeIdentifier asPathId;
+    private final QName asNumberQname;
     private final NodeIdentifier transitiveLeaf;
 
     private AttributeOperations(final QNameModule namespace) {
         this.asPathContainer = new NodeIdentifier(QName.cachedReference(QName.create(namespace, AsPath.QNAME.getLocalName())));
         this.asPathSegments = new NodeIdentifier(QName.cachedReference(QName.create(namespace, Segments.QNAME.getLocalName())));
-        this.asPathChoice = new NodeIdentifier(QName.cachedReference(QName.create(namespace, CSegment.QNAME.getLocalName())));
-        this.asPathList = new NodeIdentifier(QName.cachedReference(QName.create(namespace, AList.QNAME.getLocalName())));
-        this.asPathSequence = new NodeIdentifier(QName.cachedReference(QName.create(namespace, AsSequence.QNAME.getLocalName())));
-        this.asPathId = new NodeIdentifier(QName.cachedReference(QName.create(namespace, "as")));
+        this.asPathSequence = new NodeIdentifier(QName.cachedReference(QName.create(namespace, "as-sequence")));
+        this.asNumberQname = QName.cachedReference(QName.create(namespace, "as-number"));
 
         this.clusterListContainer = new NodeIdentifier(QName.cachedReference(QName.create(namespace, ClusterId.QNAME.getLocalName())));
         this.clusterListLeaf = new NodeIdentifier(QName.cachedReference(QName.create(namespace, "cluster")));
@@ -119,91 +109,73 @@ final class AttributeOperations {
         return ATTRIBUTES_CACHE.getUnchecked(attributes.getNodeType().getModule());
     }
 
-    private Collection<UnkeyedListEntryNode> reusableSequence(final UnkeyedListEntryNode segment) {
-        final Optional<NormalizedNode<?, ?>> maybeAsSequence = NormalizedNodes.findNode(segment, this.asPathChoice, this.asPathList, this.asPathSequence);
+    private LeafSetNode<?> reusableSegment(final UnkeyedListEntryNode segment) {
+        final Optional<NormalizedNode<?, ?>> maybeAsSequence = NormalizedNodes.findNode(segment, this.asPathSequence);
         if (maybeAsSequence.isPresent()) {
-            final UnkeyedListNode asList = (UnkeyedListNode) maybeAsSequence.get();
-            if (asList.getSize() < Values.UNSIGNED_BYTE_MAX_VALUE) {
-                return asList.getValue();
+            final LeafSetNode<?> asList = (LeafSetNode<?>) maybeAsSequence.get();
+            if (asList.getValue().size() < Values.UNSIGNED_BYTE_MAX_VALUE) {
+                return asList;
             }
         }
-
         return null;
     }
 
     ContainerNode exportedAttributes(final ContainerNode attributes, final Long localAs) {
-        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> b = Builders.containerBuilder();
-        b.withNodeIdentifier(attributes.getIdentifier());
+        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> containerBuilder = Builders.containerBuilder();
+        containerBuilder.withNodeIdentifier(attributes.getIdentifier());
 
         // First filter out non-transitive attributes
         // FIXME: removes MULTI_EXIT_DISC, too.
-        spliceTransitives(b, attributes);
+        spliceTransitives(containerBuilder, attributes);
 
-        /*
-         * This is very ugly, as our AS_PATH model is needlessly complex. The top-level container contains a list
-         * of segments, each of which is a choice containing another list. Both are unkeyed lists, so we need to
-         * perform a wholesale replace.
-         */
-        final CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> sb = Builders.unkeyedListBuilder();
-        sb.withNodeIdentifier(this.asPathSegments);
+        final CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> segmentsBuilder = Builders.unkeyedListBuilder();
+        segmentsBuilder.withNodeIdentifier(this.asPathSegments);
 
         final Optional<NormalizedNode<?, ?>> maybeOldAsSegments = NormalizedNodes.findNode(attributes, this.asPathContainer, this.asPathSegments);
         if (maybeOldAsSegments.isPresent() && !((UnkeyedListNode) maybeOldAsSegments.get()).getValue().isEmpty()) {
-            // Builder of inner list
-            final CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> ilb = Builders.unkeyedListBuilder();
-            ilb.withNodeIdentifier(this.asPathSequence);
-            ilb.withChild(Builders.unkeyedListEntryBuilder().withNodeIdentifier(this.asPathSequence).withChild(ImmutableNodes.leafNode(this.asPathId, localAs)).build());
 
             /*
-             * We need to check the first entry in the outer list, to check if the choice is a-list. If it is and its
-             * total number of elements is less than 255, we need to modify that one. Otherwise we need to create a
-             * new entry.
+             * We need to check the first segment.
+             * If it has as-set then new as-sequence with local AS is prepended.
+             * If it has as-sequence, we may add local AS when it has less than 255 elements.
+             * Otherwise we need to create new as-sequence for local AS.
              */
+
+            final ListNodeBuilder<Object,LeafSetEntryNode<Object>> asSequenceBuilder = Builders.orderedLeafSetBuilder();
+            // add local AS
+            asSequenceBuilder.withNodeIdentifier(this.asPathSequence).addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(this.asNumberQname, localAs)).withValue(localAs).build());
+
             final Iterator<UnkeyedListEntryNode> oldAsSegments = ((UnkeyedListNode) maybeOldAsSegments.get()).getValue().iterator();
             final UnkeyedListEntryNode firstSegment = oldAsSegments.next();
-            final Collection<UnkeyedListEntryNode> reusable = reusableSequence(firstSegment);
-            if (reusable != null) {
-                for (final UnkeyedListEntryNode child : reusable) {
-                    ilb.withChild(child);
+            final LeafSetNode<?> reusableAsSeq = reusableSegment(firstSegment);
+            // first segment contains as-sequence with less then 255 elements and it's append to local AS
+            if (reusableAsSeq != null) {
+                for (final LeafSetEntryNode<?> child : reusableAsSeq.getValue())  {
+                    asSequenceBuilder.withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(this.asNumberQname, child.getValue())).withValue(child.getValue()).build());
                 }
             }
-
-            // Builder of inner container
-            final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> icb = Builders.containerBuilder();
-            icb.withNodeIdentifier(this.asPathList);
-            icb.withChild(ilb.build());
-
-            // Choice inside the outer list
-            final DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> ocb = Builders.choiceBuilder();
-            ocb.withNodeIdentifier(this.asPathChoice);
-            ocb.withChild(icb.build());
-
             // Add the new first segment
-            sb.withChild(Builders.unkeyedListEntryBuilder().withNodeIdentifier(this.asPathSegments).withChild(ocb.build()).build());
+            segmentsBuilder.withChild(Builders.unkeyedListEntryBuilder().withNodeIdentifier(this.asPathSegments).withChild(asSequenceBuilder.build()).build());
 
-            // If we did not merge into the original segment, add it
-            if (reusable == null) {
-                sb.withChild(firstSegment);
+            // When first segment contains as-set or full as-sequence, append it
+            if (reusableAsSeq == null) {
+                segmentsBuilder.withChild(firstSegment);
             }
 
             // Add all subsequent segments
             while (oldAsSegments.hasNext()) {
-                sb.withChild(oldAsSegments.next());
+                segmentsBuilder.withChild(oldAsSegments.next());
             }
         } else {
             // Segments are completely empty, create a completely new AS_PATH container with
             // a single entry
-            sb.withChild(Builders.unkeyedListEntryBuilder().withNodeIdentifier(this.asPathSegments).withChild(
-                Builders.choiceBuilder().withNodeIdentifier(this.asPathChoice).withChild(
-                    Builders.containerBuilder().withNodeIdentifier(this.asPathList).withChild(
-                        Builders.unkeyedListBuilder().withNodeIdentifier(this.asPathSequence).withChild(
-                            Builders.unkeyedListEntryBuilder().withNodeIdentifier(this.asPathSequence).withChild(
-                                ImmutableNodes.leafNode(this.asPathId, localAs)).build()).build()).build()).build()).build());
-
+            segmentsBuilder.withChild(Builders.unkeyedListEntryBuilder().withNodeIdentifier(this.asPathSegments).withChild(
+                Builders.orderedLeafSetBuilder().withNodeIdentifier(this.asPathSequence).addChild(
+                    Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(this.asNumberQname, localAs)).withValue(localAs).build()).build()).build());
         }
 
-        b.withChild(Builders.containerBuilder().withNodeIdentifier(this.asPathContainer).withChild(sb.build()).build());
-        return b.build();
+        containerBuilder.withChild(Builders.containerBuilder().withNodeIdentifier(this.asPathContainer).withChild(segmentsBuilder.build()).build());
+        return containerBuilder.build();
     }
 
     // Attributes when reflecting a route
index 41dafa04151410868a51a747c9abca0be1e60ab8..e17cad2e673133343890f4dcc8445e212e54ec52 100644 (file)
@@ -29,24 +29,11 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.mess
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.as.path.Segments;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.as.path.SegmentsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpOrigin;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.CSegment;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.AListCase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.AListCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.ASetCase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.ASetCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.AList;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.AListBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.a.list.AsSequence;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.a.list.AsSequenceBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.set._case.ASet;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.set._case.ASetBuilder;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
@@ -64,12 +51,8 @@ final class BestPathState {
         private final Collection<PathArgument> locPref;
         private final Collection<PathArgument> med;
         private final Collection<PathArgument> orig;
-        private final NodeIdentifier cSegmentNid;
-        private final NodeIdentifier aSetNid;
         private final NodeIdentifier asSetNid;
-        private final NodeIdentifier aListNid;
         private final NodeIdentifier asSeqNid;
-        private final NodeIdentifier asNid;
 
         NamespaceSpecificIds(final QName namespace) {
             NodeIdentifier container = new NodeIdentifier(QName.cachedReference(QName.create(namespace, AsPath.QNAME.getLocalName())));
@@ -88,12 +71,8 @@ final class BestPathState {
             leaf = new NodeIdentifier(QName.cachedReference(QName.create(namespace, "value")));
             this.orig = ImmutableList.<PathArgument>of(container, leaf);
 
-            this.cSegmentNid = new NodeIdentifier(QName.cachedReference(QName.create(namespace, CSegment.QNAME.getLocalName())));
-            this.aSetNid = new NodeIdentifier(QName.cachedReference(QName.create(namespace, ASet.QNAME.getLocalName())));
             this.asSetNid = new NodeIdentifier(QName.cachedReference(QName.create(namespace, "as-set")));
-            this.aListNid = new NodeIdentifier(QName.cachedReference(QName.create(namespace, AList.QNAME.getLocalName())));
-            this.asSeqNid = new NodeIdentifier(QName.cachedReference(QName.create(namespace, AsSequence.QNAME.getLocalName())));
-            this.asNid = new NodeIdentifier(QName.cachedReference(QName.create(namespace, "as")));
+            this.asSeqNid = new NodeIdentifier(QName.cachedReference(QName.create(namespace, "as-sequence")));
         }
 
         Collection<PathArgument> getAsPath() {
@@ -112,29 +91,13 @@ final class BestPathState {
             return this.orig;
         }
 
-        NodeIdentifier getCSegment() {
-            return this.cSegmentNid;
-        }
-
-        NodeIdentifier getASet() {
-            return this.aSetNid;
-        }
-
         NodeIdentifier getAsSet() {
             return this.asSetNid;
         }
 
-        NodeIdentifier getAList() {
-            return this.aListNid;
-        }
-
         NodeIdentifier getAsSeq() {
             return this.asSeqNid;
         }
-
-        NodeIdentifier getAs() {
-            return this.asNid;
-        }
     }
 
     private static final Logger LOG = LoggerFactory.getLogger(BestPathState.class);
@@ -249,74 +212,52 @@ final class BestPathState {
         int count = 0;
         boolean setPresent = false;
         for (final Segments s : segments) {
-            if (s.getCSegment() instanceof ASetCase) {
+            if (s.getAsSet() != null && !setPresent) {
                 setPresent = true;
-            } else {
-                final AListCase list = (AListCase) s.getCSegment();
-                count += list.getAList().getAsSequence().size();
+                count++;
+            } else if (s.getAsSequence() != null) {
+                count += s.getAsSequence().size();
             }
         }
-        return (setPresent) ? count + 1 : count;
+        return count;
     }
 
     private static AsNumber getPeerAs(final List<Segments> segments) {
         if (segments.isEmpty()) {
-            return null;
+            return new AsNumber(0L);
         }
-        final AListCase first = (AListCase) segments.get(0).getCSegment();
-        return first.getAList().getAsSequence().get(0).getAs();
+        for (final Segments seg : segments) {
+            if (seg.getAsSequence() != null && !seg.getAsSequence().isEmpty()) {
+                return segments.get(0).getAsSequence().get(0);
+            }
+        }
+        return new AsNumber(0L);
     }
 
     @VisibleForTesting
     public List<Segments> extractSegments(final UnkeyedListNode segments) {
         // list segments
         final List<Segments> extracted = new ArrayList<>();
-        for (final UnkeyedListEntryNode seg : segments.getValue()) {
-            CSegment cs = null;
-            // choice c-segment
-            final ChoiceNode segmentType = (ChoiceNode) seg.getChild(this.ids.getCSegment()).get();
-            if (segmentType.getChild(this.ids.getASet()).isPresent()) {
-                // container a-set
-                cs = extractAsSet(segmentType.getChild(this.ids.getASet()).get());
-            } else if (segmentType.getChild(this.ids.getAList()).isPresent()) {
-                // container a-list
-                cs = extractAsSequence(segmentType.getChild(this.ids.getAList()).get());
-            }
-            extracted.add(new SegmentsBuilder().setCSegment(cs).build());
+        for (final UnkeyedListEntryNode segment : segments.getValue()) {
+            final SegmentsBuilder sb = new SegmentsBuilder();
+            // We are expecting that segment contains either as-sequence or as-set, so just one of them will be set, other would be null
+            sb.setAsSequence(extractAsList(segment, this.ids.getAsSeq())).setAsSet(extractAsList(segment, this.ids.getAsSet()));
+            extracted.add(sb.build());
         }
         return extracted;
     }
 
-    private CSegment extractAsSet(final DataContainerChild<? extends PathArgument, ?> container) {
+    private List<AsNumber> extractAsList(final UnkeyedListEntryNode segment, final NodeIdentifier nid) {
         final List<AsNumber> ases = new ArrayList<>();
-        // leaf-list a-set
-        final Optional<NormalizedNode<?, ?>> maybeSet = NormalizedNodes.findNode(container, this.ids.getAsSet());
-        if (maybeSet.isPresent()) {
-            final LeafSetNode<?> list = (LeafSetNode<?>)maybeSet.get();
+        final Optional<NormalizedNode<?, ?>> maybeAsList = NormalizedNodes.findNode(segment, nid);
+        if (maybeAsList.isPresent()) {
+            final LeafSetNode<?> list = (LeafSetNode<?>)maybeAsList.get();
             for (final LeafSetEntryNode<?> as : list.getValue())  {
                 ases.add(new AsNumber((Long)as.getValue()));
             }
+            return ases;
         }
-        return new ASetCaseBuilder().setASet(new ASetBuilder().setAsSet(ases).build()).build();
-    }
-
-    private CSegment extractAsSequence(final DataContainerChild<? extends PathArgument, ?> container) {
-        final List<AsSequence> ases = new ArrayList<>();
-        // list as-sequence
-        final Optional<NormalizedNode<?, ?>> maybeSet = NormalizedNodes.findNode(container, this.ids.getAsSeq());
-        if (maybeSet.isPresent()) {
-            final UnkeyedListNode list = (UnkeyedListNode)maybeSet.get();
-            // as-sequence
-            for (final UnkeyedListEntryNode as : list.getValue())  {
-                // as
-                final Optional<NormalizedNode<?, ?>> maybeAsSeq = NormalizedNodes.findNode(as, this.ids.getAs());
-                if (maybeAsSeq.isPresent()) {
-                    final LeafNode<?> asLeaf = (LeafNode<?>)maybeAsSeq.get();
-                    ases.add(new AsSequenceBuilder().setAs(new AsNumber((Long)asLeaf.getValue())).build());
-                }
-            }
-        }
-        return new AListCaseBuilder().setAList(new AListBuilder().setAsSequence(ases).build()).build();
+        return null;
     }
 
     ContainerNode getAttributes() {
index c872c49f8ec1b8f9b25cef42d81e002da6618659..9cc93e22acdfc6e57c806dc057b97e00ab246be1 100644 (file)
@@ -10,10 +10,8 @@ package org.opendaylight.protocol.bgp.rib.impl;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-
 import java.util.Collection;
 import java.util.Iterator;
-
 import org.junit.Test;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.AsPath;
@@ -26,7 +24,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.type
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
@@ -45,7 +45,6 @@ public class AttributeOperationsTest {
     static final NodeIdentifier ORIGINATOR_C_NID = new NodeIdentifier(QName.create(BestPathSelectorTest.ATTRS_EXTENSION_Q, OriginatorId.QNAME.getLocalName()));
     static final NodeIdentifier ORIGINATOR_NID = new NodeIdentifier(QName.create(BestPathSelectorTest.ATTRS_EXTENSION_Q, "originator"));
 
-
     @Test
     public void testExportedAttributesSetFirst() {
         final Long ourAs = 72L;
@@ -53,7 +52,7 @@ public class AttributeOperationsTest {
             .addChild(Builders.containerBuilder().withNodeIdentifier(AS_PATH_NID)
                 .addChild(Builders.unkeyedListBuilder().withNodeIdentifier(BestPathSelectorTest.SEGMENTS_NID)
                     .addChild(BestPathSelectorTest.SET_SEGMENT)
-                    .addChild(BestPathSelectorTest.LIST_SEGMENT)
+                    .addChild(BestPathSelectorTest.SEQ_SEGMENT)
                     .build())
             .build())
             .build();
@@ -61,9 +60,8 @@ public class AttributeOperationsTest {
         final ContainerNode exportedAttributes = operations.exportedAttributes(attributesSetBefore, ourAs);
 
         // make sure our AS is prepended to the list (as the AS-PATH starts with AS-SET)
-        final UnkeyedListEntryNode as = checkAsList(exportedAttributes).getValue().iterator().next();
-        assertTrue(as.getChild(BestPathSelectorTest.AS_NID).isPresent());
-        assertEquals(ourAs, as.getChild(BestPathSelectorTest.AS_NID).get().getValue());
+        final LeafSetNode<?> list = checkFirstLeafList(exportedAttributes);
+        assertEquals(ourAs, list.getValue().iterator().next().getValue());
     }
 
     @Test
@@ -72,7 +70,7 @@ public class AttributeOperationsTest {
         final ContainerNode attributesListBefore = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(BestPathSelectorTest.ATTRS_EXTENSION_Q))
             .addChild(Builders.containerBuilder().withNodeIdentifier(AS_PATH_NID)
                 .addChild(Builders.unkeyedListBuilder().withNodeIdentifier(BestPathSelectorTest.SEGMENTS_NID)
-                    .addChild(BestPathSelectorTest.LIST_SEGMENT)
+                    .addChild(BestPathSelectorTest.SEQ_SEGMENT)
                     .addChild(BestPathSelectorTest.SET_SEGMENT)
                     .build())
             .build())
@@ -81,23 +79,12 @@ public class AttributeOperationsTest {
         final ContainerNode exportedAttributes = operations.exportedAttributes(attributesListBefore, ourAs);
 
         // make sure our AS is appended to the a-list (as the AS-PATH starts with A-LIST)
-        final Iterator<UnkeyedListEntryNode> as = checkAsList(exportedAttributes).getValue().iterator();
-
-        final UnkeyedListEntryNode a1 = as.next();
-        assertTrue(a1.getChild(BestPathSelectorTest.AS_NID).isPresent());
-        assertEquals(ourAs, a1.getChild(BestPathSelectorTest.AS_NID).get().getValue());
-
-        final UnkeyedListEntryNode a2 = as.next();
-        assertTrue(a2.getChild(BestPathSelectorTest.AS_NID).isPresent());
-        assertEquals(new Long(1), a2.getChild(BestPathSelectorTest.AS_NID).get().getValue());
-
-        final UnkeyedListEntryNode a3 = as.next();
-        assertTrue(a3.getChild(BestPathSelectorTest.AS_NID).isPresent());
-        assertEquals(new Long(2), a3.getChild(BestPathSelectorTest.AS_NID).get().getValue());
-
-        final UnkeyedListEntryNode a4 = as.next();
-        assertTrue(a4.getChild(BestPathSelectorTest.AS_NID).isPresent());
-        assertEquals(new Long(3), a4.getChild(BestPathSelectorTest.AS_NID).get().getValue());
+        final LeafSetNode<?> list = checkFirstLeafList(exportedAttributes);
+        final Iterator<?> iter = list.getValue().iterator();
+        assertEquals(ourAs, ((LeafSetEntryNode<?>)iter.next()).getValue());
+        assertEquals(1L, ((LeafSetEntryNode<?>)iter.next()).getValue());
+        assertEquals(2L, ((LeafSetEntryNode<?>)iter.next()).getValue());
+        assertEquals(3L, ((LeafSetEntryNode<?>)iter.next()).getValue());
     }
 
     @Test
@@ -119,23 +106,20 @@ public class AttributeOperationsTest {
         assertTrue(exportedAttributes.getChild(ORIGIN_NID).isPresent());
 
         // AS-PATH should also be there with our AS
-        final Collection<UnkeyedListEntryNode> asList = checkAsList(exportedAttributes).getValue();
-        assertEquals(1, asList.size());
-        final UnkeyedListEntryNode as = asList.iterator().next();
-        assertTrue(as.getChild(BestPathSelectorTest.AS_NID).isPresent());
-        assertEquals(ourAs, as.getChild(BestPathSelectorTest.AS_NID).get().getValue());
+        final LeafSetNode<?> list = checkFirstLeafList(exportedAttributes);
+        assertEquals(1, list.getValue().size());
+        assertEquals(ourAs, list.getValue().iterator().next().getValue());
 
         // Atomic Aggregate should be filtered out
         assertFalse(exportedAttributes.getChild(ATOMIC_NID).isPresent());
     }
 
-    private UnkeyedListNode checkAsList(final ContainerNode exportedAttributes) {
+    private LeafSetNode<?> checkFirstLeafList(final ContainerNode exportedAttributes) {
         assertTrue(NormalizedNodes.findNode(exportedAttributes, AS_PATH_NID, BestPathSelectorTest.SEGMENTS_NID).isPresent());
         final UnkeyedListNode segments = (UnkeyedListNode) NormalizedNodes.findNode(exportedAttributes, AS_PATH_NID, BestPathSelectorTest.SEGMENTS_NID).get();
         final UnkeyedListEntryNode seg = segments.getValue().iterator().next();
-        assertTrue(NormalizedNodes.findNode(seg, BestPathSelectorTest.C_SEGMENTS_NID, BestPathSelectorTest.A_LIST_NID, BestPathSelectorTest.AS_SEQ_NID).isPresent());
-        final UnkeyedListNode list = (UnkeyedListNode) NormalizedNodes.findNode(seg, BestPathSelectorTest.C_SEGMENTS_NID, BestPathSelectorTest.A_LIST_NID, BestPathSelectorTest.AS_SEQ_NID).get();
-        return list;
+        final DataContainerChild<? extends PathArgument, ?> firstLeafList = seg.getValue().iterator().next();
+        return (LeafSetNode<?>) firstLeafList;
     }
 
     @Test
index 266a7531f8e734c171e62323c15bc001db521523..601b8f811b45c674a2848e200514b1cd99e292e8 100644 (file)
@@ -20,16 +20,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.mess
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.as.path.SegmentsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpOrigin;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.CSegment;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.AListCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.ASetCase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.ASetCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.AList;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.AListBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.a.list.AsSequence;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.a.list.AsSequenceBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.set._case.ASet;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.set._case.ASetBuilder;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
@@ -60,41 +50,28 @@ public class BestPathSelectorTest {
 
     static final QName AS_NUMBER_Q = QName.create(ATTRS_EXTENSION_Q, "as-number");
     static final NodeIdentifier SEGMENTS_NID = new NodeIdentifier(QName.create(ATTRS_EXTENSION_Q, Segments.QNAME.getLocalName()));
-    static final NodeIdentifier C_SEGMENTS_NID = new NodeIdentifier(QName.create(ATTRS_EXTENSION_Q, CSegment.QNAME.getLocalName()));
-    static final NodeIdentifier AS_SET_NID = new NodeIdentifier(QName.create(ATTRS_EXTENSION_Q, "as-set"));
-    static final NodeIdentifier A_SET_NID = new NodeIdentifier(QName.create(ATTRS_EXTENSION_Q, ASet.QNAME.getLocalName()));
-    static final NodeIdentifier A_LIST_NID = new NodeIdentifier(QName.create(ATTRS_EXTENSION_Q, AList.QNAME.getLocalName()));
-    static final NodeIdentifier AS_SEQ_NID = new NodeIdentifier(QName.create(ATTRS_EXTENSION_Q, AsSequence.QNAME.getLocalName()));
-    static final NodeIdentifier AS_NID = new NodeIdentifier(QName.create(ATTRS_EXTENSION_Q, "as"));
+    static final NodeIdentifier SET_LEAFLIST_NID = new NodeIdentifier(QName.create(ATTRS_EXTENSION_Q, "as-set"));
+    static final NodeIdentifier SEQ_LEAFLIST_NID = new NodeIdentifier(QName.create(ATTRS_EXTENSION_Q, "as-sequence"));
 
     static final UnkeyedListEntryNode SET_SEGMENT = Builders.unkeyedListEntryBuilder().withNodeIdentifier(SEGMENTS_NID)
-        .addChild(Builders.choiceBuilder().withNodeIdentifier(C_SEGMENTS_NID)
-            .addChild(Builders.containerBuilder().withNodeIdentifier(A_SET_NID)
-                .addChild(Builders.leafSetBuilder().withNodeIdentifier(AS_SET_NID)
-                    .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(AS_NUMBER_Q, 10L)).withValue(10L).build())
-                    .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(AS_NUMBER_Q, 11L)).withValue(11L).build())
-                .build())
-            .build())
-        .build())
-        .build();
-
-    static final UnkeyedListEntryNode LIST_SEGMENT = Builders.unkeyedListEntryBuilder().withNodeIdentifier(SEGMENTS_NID)
-        .addChild(Builders.choiceBuilder().withNodeIdentifier(C_SEGMENTS_NID)
-            .addChild(Builders.containerBuilder().withNodeIdentifier(A_LIST_NID)
-                .addChild(Builders.unkeyedListBuilder().withNodeIdentifier(AS_SEQ_NID)
-                    .addChild(Builders.unkeyedListEntryBuilder().withNodeIdentifier(AS_SEQ_NID)
-                        .addChild(Builders.leafBuilder().withNodeIdentifier(AS_NID).withValue(1L).build())
-                    .build())
-                    .addChild(Builders.unkeyedListEntryBuilder().withNodeIdentifier(AS_SEQ_NID)
-                        .addChild(Builders.leafBuilder().withNodeIdentifier(AS_NID).withValue(2L).build())
-                    .build())
-                    .addChild(Builders.unkeyedListEntryBuilder().withNodeIdentifier(AS_SEQ_NID)
-                        .addChild(Builders.leafBuilder().withNodeIdentifier(AS_NID).withValue(3L).build())
-                    .build())
-                .build())
-            .build())
-        .build())
-        .build();
+        .addChild(Builders.leafSetBuilder().withNodeIdentifier(SET_LEAFLIST_NID)
+            .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(AS_NUMBER_Q, 10L)).withValue(10L).build())
+            .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(AS_NUMBER_Q, 11L)).withValue(11L).build())
+            .build()).build();
+
+    static final UnkeyedListEntryNode SEQ_SEGMENT = Builders.unkeyedListEntryBuilder().withNodeIdentifier(SEGMENTS_NID)
+        .addChild(Builders.orderedLeafSetBuilder().withNodeIdentifier(SEQ_LEAFLIST_NID)
+            .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(AS_NUMBER_Q, 1L)).withValue(1L).build())
+            .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(AS_NUMBER_Q, 2L)).withValue(2L).build())
+            .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(AS_NUMBER_Q, 3L)).withValue(3L).build())
+            .build()).build();
+
+    static final UnkeyedListEntryNode SEQ_SEGMENT2 = Builders.unkeyedListEntryBuilder().withNodeIdentifier(SEGMENTS_NID)
+        .addChild(Builders.orderedLeafSetBuilder().withNodeIdentifier(SEQ_LEAFLIST_NID)
+            .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(AS_NUMBER_Q, 20L)).withValue(20L).build())
+            .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(AS_NUMBER_Q, 2L)).withValue(2L).build())
+            .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(AS_NUMBER_Q, 3L)).withValue(3L).build())
+            .build()).build();
 
     @Test
     public void testBestPathForEquality() {
@@ -102,11 +79,11 @@ public class BestPathSelectorTest {
         final BestPath processedPath = this.selector.result();
 
         assertEquals(this.originBestPath.getRouterId(), processedPath.getRouterId());
-        assertEquals(this.originBestPath.getState().getAsPathLength(), processedPath.getState().getAsPathLength());
         assertEquals(this.originBestPath.getState().getLocalPref(), processedPath.getState().getLocalPref());
         assertEquals(this.originBestPath.getState().getMultiExitDisc(), processedPath.getState().getMultiExitDisc());
         assertEquals(this.originBestPath.getState().getOrigin(), processedPath.getState().getOrigin());
         assertEquals(this.originBestPath.getState().getPeerAs(), processedPath.getState().getPeerAs());
+        assertEquals(this.originBestPath.getState().getAsPathLength(), processedPath.getState().getAsPathLength());
     }
 
     @Test
@@ -119,11 +96,51 @@ public class BestPathSelectorTest {
         processedPath = this.selector.result();
         assertEquals(321L, processedPath.getState().getLocalPref().longValue());
 
-        this.selector.processPath(this.ROUTER_ID2, createStateFromPrefMedOrigin());   // local-pref 123
+        addLowerLocalRef(); // prefer path with higher LOCAL_PREF
+        this.selector.processPath(this.ROUTER_ID2, this.dataContBuilder.build());
         processedPath = this.selector.result();
         assertEquals(321L, processedPath.getState().getLocalPref().longValue());
     }
 
+    @Test
+    public void testBestPathSelectionOptions() {
+        this.selector.processPath(this.ROUTER_ID2, createStateFromPrefMedOriginASPath());
+        BestPath processedPath = this.selector.result();
+        assertEquals(1, processedPath.getState().getOrigin().getIntValue());
+
+        addIgpOrigin(); // prefer the path with the lowest origin type
+        this.selector.processPath(this.ROUTER_ID2, this.dataContBuilder.build());
+        processedPath = this.selector.result();
+        assertEquals(0, processedPath.getState().getOrigin().getIntValue());
+
+        addEgpOrigin();
+        this.selector.processPath(this.ROUTER_ID2, this.dataContBuilder.build());
+        processedPath = this.selector.result();
+        assertEquals(0, processedPath.getState().getOrigin().getIntValue());
+
+        // prefer the path with the lowest multi-exit discriminator (MED)
+        assertEquals(4321L, (long) processedPath.getState().getMultiExitDisc());
+        addIgpOrigin();
+        addLowerMultiExitDisc();
+        this.selector.processPath(this.ROUTER_ID2, this.dataContBuilder.build());
+        processedPath = this.selector.result();
+        assertEquals(1234L, (long) processedPath.getState().getMultiExitDisc());
+
+        addHigherMultiExitDisc();
+        this.selector.processPath(this.ROUTER_ID2, this.dataContBuilder.build());
+        processedPath = this.selector.result();
+        assertEquals(1234L, (long) processedPath.getState().getMultiExitDisc());
+
+        addLowerMultiExitDisc();
+        addAsPath(SEQ_SEGMENT2);
+        assertEquals(1L, (long) processedPath.getState().getPeerAs());
+        assertEquals(3, processedPath.getState().getAsPathLength());
+        this.selector.processPath(this.ROUTER_ID2, this.dataContBuilder.build());
+        processedPath = this.selector.result();
+        assertEquals(1L, (long) processedPath.getState().getPeerAs());
+        assertEquals(3, processedPath.getState().getAsPathLength());
+    }
+
     @Test
     public void testBestPathForNonEquality() {
         this.selector.processPath(this.ROUTER_ID3, createStateFromPrefMedOrigin());
@@ -150,7 +167,7 @@ public class BestPathSelectorTest {
         addHigherLocalRef();
         addHigherMultiExitDisc();
         addEgpOrigin();
-        addAsPath(LIST_SEGMENT);
+        addAsPath(SEQ_SEGMENT);
         return this.dataContBuilder.build();
     }
 
@@ -189,6 +206,7 @@ public class BestPathSelectorTest {
         this.dataContBuilder.addChild(asPathContBuilder.build());
     }
 
+
     private static DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> createContBuilder(final QName qname) {
         return ImmutableContainerNodeSchemaAwareBuilder.create().withNodeIdentifier(new NodeIdentifier(qname));
     }
@@ -205,21 +223,21 @@ public class BestPathSelectorTest {
         final CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> builder = Builders.unkeyedListBuilder();
         builder.withNodeIdentifier(SEGMENTS_NID);
         builder.addChild(SET_SEGMENT);
-        builder.addChild(LIST_SEGMENT).build();
+        builder.addChild(SEQ_SEGMENT);
 
         // expected
-        final List<AsSequence> sequences = new ArrayList<>();
-        sequences.add(new AsSequenceBuilder().setAs(new AsNumber(1L)).build());
-        sequences.add(new AsSequenceBuilder().setAs(new AsNumber(2L)).build());
-        sequences.add(new AsSequenceBuilder().setAs(new AsNumber(3L)).build());
+        final List<AsNumber> sequences = new ArrayList<>();
+        sequences.add(new AsNumber(1L));
+        sequences.add(new AsNumber(2L));
+        sequences.add(new AsNumber(3L));
         final List<Segments> expected = new ArrayList<>();
-        expected.add(new SegmentsBuilder().setCSegment(new ASetCaseBuilder().setASet(new ASetBuilder().setAsSet(Lists.newArrayList(new AsNumber(11L), new AsNumber(10L))).build()).build()).build());
-        expected.add(new SegmentsBuilder().setCSegment(new AListCaseBuilder().setAList(new AListBuilder().setAsSequence(sequences).build()).build()).build());
+        expected.add(new SegmentsBuilder().setAsSet(Lists.newArrayList(new AsNumber(11L), new AsNumber(10L))).build());
+        expected.add(new SegmentsBuilder().setAsSequence(sequences).build());
         // test
         final List<Segments> actual = this.state.extractSegments(builder.build());
         assertEquals(expected.size(), actual.size());
         assertEquals(Sets.newHashSet(1,2,3), Sets.newHashSet(1,3,2));
-        assertEquals(Sets.newHashSet(((ASetCase)expected.get(0).getCSegment()).getASet().getAsSet()), Sets.newHashSet(((ASetCase)actual.get(0).getCSegment()).getASet().getAsSet()));
+        assertEquals(Sets.newHashSet(expected.get(0).getAsSet()), Sets.newHashSet(actual.get(0).getAsSet()));
         assertEquals(expected.get(1), actual.get(1));
     }