*/
package org.opendaylight.protocol.bgp.rib.impl;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
import com.google.common.base.MoreObjects.ToStringHelper;
import com.google.common.base.Optional;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.MultiExitDisc;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.Origin;
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;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
@NotThreadSafe
final class BestPathState {
- private static final class AttributesCollection {
+ private static final class NamespaceSpecificIds {
private final Collection<PathArgument> asPath;
private final Collection<PathArgument> locPref;
private final Collection<PathArgument> med;
private final Collection<PathArgument> orig;
-
- AttributesCollection(final QName namespace) {
+ 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())));
NodeIdentifier leaf = new NodeIdentifier(QName.cachedReference(QName.create(namespace, "segments")));
this.asPath = ImmutableList.<PathArgument>of(container, leaf);
container = new NodeIdentifier(QName.cachedReference(QName.create(namespace, Origin.QNAME.getLocalName())));
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")));
}
Collection<PathArgument> getAsPath() {
Collection<PathArgument> getOrig() {
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);
- private static final Cache<QNameModule, AttributesCollection> PATH_CACHE = CacheBuilder.newBuilder().weakKeys().weakValues().build();
+ private static final Cache<QNameModule, NamespaceSpecificIds> PATH_CACHE = CacheBuilder.newBuilder().weakKeys().weakValues().build();
- private static Long peerAs = 0L;
- private static int asPathLength = 0;
+ private long peerAs = 0L;
+ private int asPathLength = 0;
private final ContainerNode attributes;
- private final AttributesCollection collection;
+ private final NamespaceSpecificIds ids;
private Long localPref;
private Long multiExitDisc;
private BgpOrigin origin;
private boolean resolved;
BestPathState(final ContainerNode attributes) {
- final AttributesCollection col;
+ final NamespaceSpecificIds col;
try {
- col = PATH_CACHE.get(attributes.getNodeType().getModule(), new Callable<AttributesCollection>() {
+ col = PATH_CACHE.get(attributes.getNodeType().getModule(), new Callable<NamespaceSpecificIds>() {
@Override
- public AttributesCollection call() {
- return new AttributesCollection(attributes.getNodeType());
+ public NamespaceSpecificIds call() {
+ return new NamespaceSpecificIds(attributes.getNodeType());
}
});
} catch (final ExecutionException e) {
}
this.attributes = Preconditions.checkNotNull(attributes);
- this.collection = col;
+ this.ids = col;
}
private static BgpOrigin fromString(final String originStr) {
return;
}
- final Optional<NormalizedNode<?, ?>> maybeLocalPref = NormalizedNodes.findNode(this.attributes, this.collection.getLocPref());
+ final Optional<NormalizedNode<?, ?>> maybeLocalPref = NormalizedNodes.findNode(this.attributes, this.ids.getLocPref());
if (maybeLocalPref.isPresent()) {
this.localPref = (Long) ((LeafNode<?>)maybeLocalPref.get()).getValue();
} else {
this.localPref = null;
}
- final Optional<NormalizedNode<?, ?>> maybeMultiExitDisc = NormalizedNodes.findNode(this.attributes, this.collection.getMed());
+ final Optional<NormalizedNode<?, ?>> maybeMultiExitDisc = NormalizedNodes.findNode(this.attributes, this.ids.getMed());
if (maybeMultiExitDisc.isPresent()) {
this.multiExitDisc = (Long) ((LeafNode<?>)maybeMultiExitDisc.get()).getValue();
} else {
this.multiExitDisc = null;
}
- final Optional<NormalizedNode<?, ?>> maybeOrigin = NormalizedNodes.findNode(this.attributes, this.collection.getOrig());
+ final Optional<NormalizedNode<?, ?>> maybeOrigin = NormalizedNodes.findNode(this.attributes, this.ids.getOrig());
if (maybeOrigin.isPresent()) {
this.origin = fromString((String) ((LeafNode<?>)maybeOrigin.get()).getValue());
} else {
this.origin = null;
}
- final Optional<NormalizedNode<?, ?>> maybeSegments = NormalizedNodes.findNode(this.attributes, this.collection.getAsPath());
+ final Optional<NormalizedNode<?, ?>> maybeSegments = NormalizedNodes.findNode(this.attributes, this.ids.getAsPath());
if (maybeSegments.isPresent()) {
final UnkeyedListNode segments = (UnkeyedListNode) maybeSegments.get();
-
- if (segments.getSize() != 0) {
- // FIXME: peer AS number
-
- // FIXME: asPathLength = countAsPath(this.bestState.getAsPath().getSegments());
- final boolean haveSegment;
- for (final UnkeyedListEntryNode s : segments.getValue()) {
-
- }
+ final List<Segments> segs = extractSegments(segments);
+ if (segs.size() != 0) {
+ this.peerAs = getPeerAs(segs).getValue();
+ this.asPathLength = countAsPath(segs);
}
}
-
this.resolved = true;
}
Long getPeerAs() {
resolveValues();
- return peerAs;
+ return this.peerAs;
}
int getAsPathLength() {
resolveValues();
- return asPathLength;
+ return this.asPathLength;
}
private static int countAsPath(final List<Segments> segments) {
if (segments.isEmpty()) {
return null;
}
-
final AListCase first = (AListCase) segments.get(0).getCSegment();
return first.getAList().getAsSequence().get(0).getAs();
}
+ @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());
+ }
+ return extracted;
+ }
+
+ private CSegment extractAsSet(final DataContainerChild<? extends PathArgument, ?> container) {
+ 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();
+ for (final LeafSetEntryNode<?> as : list.getValue()) {
+ ases.add(new AsNumber(Long.valueOf((String)as.getValue())));
+ }
+ }
+ 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.valueOf((String)asLeaf.getValue()))).build());
+ }
+ }
+ }
+ return new AListCaseBuilder().setAList(new AListBuilder().setAsSequence(ases).build()).build();
+ }
+
ContainerNode getAttributes() {
return this.attributes;
}
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import com.google.common.primitives.UnsignedInteger;
+
+import java.util.ArrayList;
+import java.util.List;
+
import org.junit.Test;
+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.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.rib.rev130925.PeerId;
+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;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
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.impl.ImmutableContainerNodeSchemaAwareBuilder;
valueBuilder.withNodeIdentifier(new NodeIdentifier(QName.create(qname, localName))).withValue(value);
return valueBuilder;
}
+
+ @Test
+ public void testExtractSegments() {
+ final QName asNumberQ = QName.create(this.extensionQName, "as-number");
+ final NodeIdentifier segmentsNid = new NodeIdentifier(QName.create(this.extensionQName, Segments.QNAME.getLocalName()));
+ final NodeIdentifier cSegmentsNid = new NodeIdentifier(QName.create(this.extensionQName, CSegment.QNAME.getLocalName()));
+ final NodeIdentifier asSetNid = new NodeIdentifier(QName.create(this.extensionQName, "as-set"));
+ final NodeIdentifier aSetNid = new NodeIdentifier(QName.create(this.extensionQName, ASet.QNAME.getLocalName()));
+ final NodeIdentifier aListNid = new NodeIdentifier(QName.create(this.extensionQName, AList.QNAME.getLocalName()));
+ final NodeIdentifier asSeqNid = new NodeIdentifier(QName.create(this.extensionQName, AsSequence.QNAME.getLocalName()));
+ final NodeIdentifier asNid = new NodeIdentifier(QName.create(this.extensionQName, "as"));
+ // to be extracted from
+ final CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> builder = Builders.unkeyedListBuilder();
+ builder.withNodeIdentifier(segmentsNid);
+ builder.addChild(Builders.unkeyedListEntryBuilder().withNodeIdentifier(segmentsNid)
+ .addChild(Builders.choiceBuilder().withNodeIdentifier(cSegmentsNid)
+ .addChild(Builders.containerBuilder().withNodeIdentifier(aSetNid)
+ .addChild(Builders.leafSetBuilder().withNodeIdentifier(asSetNid)
+ .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(asNumberQ, "10")).withValue("10").build())
+ .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(asNumberQ, "11")).withValue("11").build())
+ .build())
+ .build())
+ .build())
+ .build());
+ builder.addChild(Builders.unkeyedListEntryBuilder().withNodeIdentifier(segmentsNid)
+ .addChild(Builders.choiceBuilder().withNodeIdentifier(cSegmentsNid)
+ .addChild(Builders.containerBuilder().withNodeIdentifier(aListNid)
+ .addChild(Builders.unkeyedListBuilder().withNodeIdentifier(asSeqNid)
+ .addChild(Builders.unkeyedListEntryBuilder().withNodeIdentifier(asSeqNid)
+ .addChild(Builders.leafBuilder().withNodeIdentifier(asNid).withValue("1").build())
+ .build())
+ .addChild(Builders.unkeyedListEntryBuilder().withNodeIdentifier(asSeqNid)
+ .addChild(Builders.leafBuilder().withNodeIdentifier(asNid).withValue("2").build())
+ .build())
+ .addChild(Builders.unkeyedListEntryBuilder().withNodeIdentifier(asSeqNid)
+ .addChild(Builders.leafBuilder().withNodeIdentifier(asNid).withValue("3").build())
+ .build())
+ .build())
+ .build())
+ .build())
+ .build());
+
+ // 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<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());
+ // 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(expected.get(1), actual.get(1));
+ }
}