2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.protocol.bgp.mode.impl.base;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotEquals;
13 import com.google.common.collect.Lists;
14 import com.google.common.collect.Sets;
15 import com.google.common.primitives.UnsignedInteger;
16 import java.util.ArrayList;
17 import java.util.List;
18 import org.junit.Test;
19 import org.opendaylight.protocol.bgp.mode.impl.BestPathStateImpl;
20 import org.opendaylight.protocol.bgp.rib.spi.RouterIds;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.path.attributes.attributes.as.path.Segments;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.path.attributes.attributes.as.path.SegmentsBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev171207.PeerId;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpOrigin;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
29 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
32 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
33 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
34 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
35 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeSchemaAwareBuilder;
36 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
37 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListNodeBuilder;
39 public class BasePathSelectorTest {
41 public static final QName ATTRS_EXTENSION_Q = QName.create("urn:opendaylight:params:xml:ns:yang:bgp-inet",
42 "2017-12-07", "attributes");
43 public static final QName AS_NUMBER_Q = QName.create(ATTRS_EXTENSION_Q, "as-number");
44 public static final NodeIdentifier SEGMENTS_NID = new NodeIdentifier(QName.create(ATTRS_EXTENSION_Q,
45 Segments.QNAME.getLocalName()));
46 public static final NodeIdentifier SEQ_LEAFLIST_NID = new NodeIdentifier(QName.create(ATTRS_EXTENSION_Q,
48 public static final UnkeyedListEntryNode SEQ_SEGMENT = Builders.unkeyedListEntryBuilder()
49 .withNodeIdentifier(SEGMENTS_NID).addChild(Builders.orderedLeafSetBuilder()
50 .withNodeIdentifier(SEQ_LEAFLIST_NID)
51 .addChild(Builders.leafSetEntryBuilder()
52 .withNodeIdentifier(new NodeWithValue<>(AS_NUMBER_Q, 1L)).withValue(1L).build())
53 .addChild(Builders.leafSetEntryBuilder()
54 .withNodeIdentifier(new NodeWithValue<>(AS_NUMBER_Q, 2L)).withValue(2L).build())
55 .addChild(Builders.leafSetEntryBuilder()
56 .withNodeIdentifier(new NodeWithValue<>(AS_NUMBER_Q, 3L)).withValue(3L).build())
58 private static final NodeIdentifier SET_LEAFLIST_NID = new NodeIdentifier(QName.create(ATTRS_EXTENSION_Q,
60 public static final UnkeyedListEntryNode SET_SEGMENT = Builders.unkeyedListEntryBuilder()
61 .withNodeIdentifier(SEGMENTS_NID).addChild(Builders.leafSetBuilder().withNodeIdentifier(SET_LEAFLIST_NID)
62 .addChild(Builders.leafSetEntryBuilder()
63 .withNodeIdentifier(new NodeWithValue<>(AS_NUMBER_Q, 10L)).withValue(10L).build())
64 .addChild(Builders.leafSetEntryBuilder()
65 .withNodeIdentifier(new NodeWithValue<>(AS_NUMBER_Q, 11L)).withValue(11L).build())
67 private static final UnkeyedListEntryNode SEQ_SEGMENT2 = Builders.unkeyedListEntryBuilder()
68 .withNodeIdentifier(SEGMENTS_NID).addChild(Builders.orderedLeafSetBuilder()
69 .withNodeIdentifier(SEQ_LEAFLIST_NID)
70 .addChild(Builders.leafSetEntryBuilder()
71 .withNodeIdentifier(new NodeWithValue<>(AS_NUMBER_Q, 20L)).withValue(20L).build())
72 .addChild(Builders.leafSetEntryBuilder()
73 .withNodeIdentifier(new NodeWithValue<>(AS_NUMBER_Q, 2L)).withValue(2L).build())
74 .addChild(Builders.leafSetEntryBuilder()
75 .withNodeIdentifier(new NodeWithValue<>(AS_NUMBER_Q, 3L)).withValue(3L).build())
77 private static final QName LOCAL_PREF_Q_NAME = QName.create(ATTRS_EXTENSION_Q, "local-pref");
78 private static final QName MULTI_EXIT_DISC_Q_NAME = QName.create(ATTRS_EXTENSION_Q, "multi-exit-disc");
79 private static final QName ORIGIN_Q_NAME = QName.create(ATTRS_EXTENSION_Q, "origin");
80 private static final QName AS_PATH_Q_NAME = QName.create(ATTRS_EXTENSION_Q, "as-path");
81 private static final UnsignedInteger ROUTER_ID = RouterIds.routerIdForAddress("127.0.0.1");
82 static final UnsignedInteger ROUTER_ID2 = RouterIds.routerIdForPeerId(new PeerId("bgp://127.0.0.1"));
83 private static final UnsignedInteger ROUTER_ID3 = RouterIds.routerIdForPeerId(new PeerId("bgp://127.0.0.2"));
84 private final BasePathSelector selector = new BasePathSelector(20L);
85 private final BestPathStateImpl state = new BestPathStateImpl(createStateFromPrefMedOriginASPath().build());
86 private final BaseBestPath originBestPath = new BaseBestPath(ROUTER_ID, this.state);
89 public void testBestPathForEquality() {
90 this.selector.processPath(ROUTER_ID2, createStateFromPrefMedOriginASPath().build());
91 final BaseBestPath processedPath = this.selector.result();
93 assertEquals(this.originBestPath.getPeerId(), processedPath.getPeerId());
94 assertEquals(this.originBestPath.getState().getLocalPref(), processedPath.getState().getLocalPref());
95 assertEquals(this.originBestPath.getState().getMultiExitDisc(), processedPath.getState().getMultiExitDisc());
96 assertEquals(this.originBestPath.getState().getOrigin(), processedPath.getState().getOrigin());
97 assertEquals(this.originBestPath.getState().getPeerAs(), processedPath.getState().getPeerAs());
98 assertEquals(this.originBestPath.getState().getAsPathLength(), processedPath.getState().getAsPathLength());
102 public void testBestPathWithHigherLocalPref() {
103 this.selector.processPath(ROUTER_ID2, createStateFromPrefMedOrigin()); // local-pref 123
104 BaseBestPath processedPath = this.selector.result();
105 assertEquals(123L, processedPath.getState().getLocalPref().longValue());
107 this.selector.processPath(ROUTER_ID2, createStateFromPrefMedOriginASPath().build()); // local-pref 321
108 processedPath = this.selector.result();
109 assertEquals(321L, processedPath.getState().getLocalPref().longValue());
111 DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> dataContBuilder =
112 createContBuilder(ATTRS_EXTENSION_Q);
113 addLowerLocalRef(dataContBuilder); // prefer path with higher LOCAL_PREF
114 this.selector.processPath(ROUTER_ID2, dataContBuilder.build());
115 processedPath = this.selector.result();
116 assertEquals(321L, processedPath.getState().getLocalPref().longValue());
120 public void testBestPathSelectionOptions() {
121 DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> dataContBuilder
122 = createStateFromPrefMedOriginASPath();
123 this.selector.processPath(ROUTER_ID2, dataContBuilder.build());
124 BaseBestPath processedPath = this.selector.result();
125 assertEquals(1, processedPath.getState().getOrigin().getIntValue());
127 addIgpOrigin(dataContBuilder); // prefer the path with the lowest origin type
128 this.selector.processPath(ROUTER_ID2, dataContBuilder.build());
129 processedPath = this.selector.result();
130 assertEquals(0, processedPath.getState().getOrigin().getIntValue());
132 addEgpOrigin(dataContBuilder);
133 this.selector.processPath(ROUTER_ID2, dataContBuilder.build());
134 processedPath = this.selector.result();
135 assertEquals(0, processedPath.getState().getOrigin().getIntValue());
137 // prefer the path with the lowest multi-exit discriminator (MED)
138 assertEquals(4321L, (long) processedPath.getState().getMultiExitDisc());
139 addIgpOrigin(dataContBuilder);
140 addLowerMultiExitDisc(dataContBuilder);
141 this.selector.processPath(ROUTER_ID2, dataContBuilder.build());
142 processedPath = this.selector.result();
143 assertEquals(1234L, (long) processedPath.getState().getMultiExitDisc());
145 addHigherMultiExitDisc(dataContBuilder);
146 this.selector.processPath(ROUTER_ID2, dataContBuilder.build());
147 processedPath = this.selector.result();
148 assertEquals(1234L, (long) processedPath.getState().getMultiExitDisc());
150 addLowerMultiExitDisc(dataContBuilder);
151 addAsPath(dataContBuilder, SEQ_SEGMENT2);
152 assertEquals(1L, (long) processedPath.getState().getPeerAs());
153 assertEquals(3, processedPath.getState().getAsPathLength());
154 this.selector.processPath(ROUTER_ID2, dataContBuilder.build());
155 processedPath = this.selector.result();
156 assertEquals(1L, (long) processedPath.getState().getPeerAs());
157 assertEquals(3, processedPath.getState().getAsPathLength());
161 public void testBestPathForNonEquality() {
162 this.selector.processPath(ROUTER_ID3, createStateFromPrefMedOrigin());
163 final BaseBestPath processedPath = this.selector.result();
165 assertNotEquals(this.originBestPath.getPeerId(), processedPath.getPeerId());
166 assertNotEquals(this.originBestPath.getState().getLocalPref(), processedPath.getState().getLocalPref());
167 assertNotEquals(this.originBestPath.getState().getMultiExitDisc(), processedPath.getState().getMultiExitDisc());
168 assertNotEquals(this.originBestPath.getState().getOrigin(), processedPath.getState().getOrigin());
169 assertNotEquals(this.originBestPath.getState().getPeerAs(), processedPath.getState().getPeerAs());
170 assertNotEquals(this.originBestPath.getState().getAsPathLength(), processedPath.getState().getAsPathLength());
173 private static ContainerNode createStateFromPrefMedOrigin() {
174 DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> dataContBuilder
175 = createContBuilder(ATTRS_EXTENSION_Q);
176 addLowerLocalRef(dataContBuilder);
177 addLowerMultiExitDisc(dataContBuilder);
178 addIgpOrigin(dataContBuilder);
179 return dataContBuilder.build();
182 static DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> createStateFromPrefMedOriginASPath() {
183 DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> dataContBuilder
184 = createContBuilder(ATTRS_EXTENSION_Q);
185 addHigherLocalRef(dataContBuilder);
186 addHigherMultiExitDisc(dataContBuilder);
187 addEgpOrigin(dataContBuilder);
188 addAsPath(dataContBuilder,SEQ_SEGMENT);
189 return dataContBuilder;
192 private static void addLowerLocalRef(
193 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> dataContBuilder) {
194 dataContBuilder.addChild(createContBuilder(LOCAL_PREF_Q_NAME)
195 .addChild(createValueBuilder(123L, LOCAL_PREF_Q_NAME, "pref").build()).build());
198 private static void addHigherLocalRef(
199 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> dataContBuilder) {
200 dataContBuilder.addChild(createContBuilder(LOCAL_PREF_Q_NAME)
201 .addChild(createValueBuilder(321L, LOCAL_PREF_Q_NAME, "pref").build()).build());
204 private static void addLowerMultiExitDisc(
205 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> dataContBuilder) {
206 dataContBuilder.addChild(createContBuilder(MULTI_EXIT_DISC_Q_NAME)
207 .addChild(createValueBuilder(1234L, MULTI_EXIT_DISC_Q_NAME, "med").build()).build());
210 private static void addHigherMultiExitDisc(
211 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> dataContBuilder) {
212 dataContBuilder.addChild(createContBuilder(MULTI_EXIT_DISC_Q_NAME)
213 .addChild(createValueBuilder(4321L, MULTI_EXIT_DISC_Q_NAME, "med").build()).build());
216 private static void addIgpOrigin(
217 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> dataContBuilder) {
218 dataContBuilder.addChild(createContBuilder(ORIGIN_Q_NAME)
219 .addChild(createValueBuilder("igp", ORIGIN_Q_NAME, "value").build()).build());
222 private static void addEgpOrigin(
223 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> dataContBuilder) {
224 dataContBuilder.addChild(createContBuilder(ORIGIN_Q_NAME)
225 .addChild(createValueBuilder("egp", ORIGIN_Q_NAME, "value").build()).build());
228 private static void addAsPath(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> dataContBuilder,
229 final UnkeyedListEntryNode segment) {
230 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> asPathContBuilder
231 = ImmutableContainerNodeSchemaAwareBuilder.create();
232 asPathContBuilder.withNodeIdentifier(new NodeIdentifier(AS_PATH_Q_NAME));
234 final CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> segments
235 = ImmutableUnkeyedListNodeBuilder.create();
236 segments.withNodeIdentifier(SEGMENTS_NID);
237 segments.addChild(segment);
238 asPathContBuilder.addChild(segments.build());
239 dataContBuilder.addChild(asPathContBuilder.build());
243 private static DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> createContBuilder(final QName qname) {
244 return ImmutableContainerNodeSchemaAwareBuilder.create().withNodeIdentifier(new NodeIdentifier(qname));
247 private static <T> ImmutableLeafNodeBuilder<T> createValueBuilder(final T value, final QName qname,
248 final String localName) {
249 final ImmutableLeafNodeBuilder<T> valueBuilder = new ImmutableLeafNodeBuilder<>();
250 valueBuilder.withNodeIdentifier(new NodeIdentifier(QName.create(qname, localName))).withValue(value);
255 public void testExtractSegments() {
256 // to be extracted from
257 final CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> builder = Builders.unkeyedListBuilder();
258 builder.withNodeIdentifier(SEGMENTS_NID);
259 builder.addChild(SET_SEGMENT);
260 builder.addChild(SEQ_SEGMENT);
263 final List<AsNumber> sequences = new ArrayList<>();
264 sequences.add(new AsNumber(1L));
265 sequences.add(new AsNumber(2L));
266 sequences.add(new AsNumber(3L));
267 final List<Segments> expected = new ArrayList<>();
268 expected.add(new SegmentsBuilder()
269 .setAsSet(Lists.newArrayList(new AsNumber(11L), new AsNumber(10L))).build());
270 expected.add(new SegmentsBuilder().setAsSequence(sequences).build());
272 final List<Segments> actual = this.state.extractSegments(builder.build());
273 assertEquals(expected.size(), actual.size());
274 assertEquals(Sets.newHashSet(1, 2, 3), Sets.newHashSet(1, 3, 2));
275 assertEquals(Sets.newHashSet(expected.get(0).getAsSet()), Sets.newHashSet(actual.get(0).getAsSet()));
276 assertEquals(expected.get(1), actual.get(1));
279 @Test(expected = IllegalArgumentException.class)
280 public void testBgpOrigin() {
281 DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> dataContBuilder
282 = createContBuilder(ATTRS_EXTENSION_Q);
283 final ContainerNode containerIncom = dataContBuilder.addChild(createContBuilder(ORIGIN_Q_NAME)
284 .addChild(createValueBuilder("incomplete", ORIGIN_Q_NAME, "value")
285 .build()).build()).build();
286 this.selector.processPath(ROUTER_ID3, containerIncom);
287 final BaseBestPath processedPathIncom = this.selector.result();
288 assertEquals(BgpOrigin.Incomplete, processedPathIncom.getState().getOrigin());
290 final ContainerNode containerException = dataContBuilder.addChild(createContBuilder(ORIGIN_Q_NAME)
291 .addChild(createValueBuilder("LOL", ORIGIN_Q_NAME, "value").build()).build()).build();
292 this.selector.processPath(ROUTER_ID3, containerException);
293 final BaseBestPath processedPathException = this.selector.result();
294 processedPathException.getState().getOrigin();