2 * Copyright (c) 2015 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.rib.impl;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotEquals;
12 import com.google.common.collect.Lists;
13 import com.google.common.collect.Sets;
14 import com.google.common.primitives.UnsignedInteger;
15 import java.util.ArrayList;
16 import java.util.List;
17 import org.junit.Test;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.as.path.Segments;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.attributes.as.path.SegmentsBuilder;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerId;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpOrigin;
23 import org.opendaylight.yangtools.yang.common.QName;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
26 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
27 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
29 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
30 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
31 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
32 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeSchemaAwareBuilder;
33 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
34 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListNodeBuilder;
36 public class BestPathSelectorTest {
38 static final QName ATTRS_EXTENSION_Q = QName.create("urn:opendaylight:params:xml:ns:yang:bgp-inet", "2015-03-05", "attributes");
39 private final QName localPrefQName = QName.create(ATTRS_EXTENSION_Q, "local-pref");
40 private final QName multiExitDiscQName = QName.create(ATTRS_EXTENSION_Q, "multi-exit-disc");
41 private final QName originQName = QName.create(ATTRS_EXTENSION_Q, "origin");
42 private final QName asPathQName = QName.create(ATTRS_EXTENSION_Q, "as-path");
43 private final UnsignedInteger ROUTER_ID = RouterIds.routerIdForAddress("127.0.0.1");
44 private final UnsignedInteger ROUTER_ID2 = RouterIds.routerIdForPeerId(new PeerId("bgp://127.0.0.1"));
45 private final UnsignedInteger ROUTER_ID3 = RouterIds.routerIdForPeerId(new PeerId("bgp://127.0.0.2"));
46 private final BestPathState state = new BestPathState(createStateFromPrefMedOriginASPath());
47 private final BestPath originBestPath = new BestPath(this.ROUTER_ID, this.state);
48 private final BestPathSelector selector = new BestPathSelector(20L);
49 private DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> dataContBuilder;
51 static final QName AS_NUMBER_Q = QName.create(ATTRS_EXTENSION_Q, "as-number");
52 static final NodeIdentifier SEGMENTS_NID = new NodeIdentifier(QName.create(ATTRS_EXTENSION_Q, Segments.QNAME.getLocalName()));
53 static final NodeIdentifier SET_LEAFLIST_NID = new NodeIdentifier(QName.create(ATTRS_EXTENSION_Q, "as-set"));
54 static final NodeIdentifier SEQ_LEAFLIST_NID = new NodeIdentifier(QName.create(ATTRS_EXTENSION_Q, "as-sequence"));
56 static final UnkeyedListEntryNode SET_SEGMENT = Builders.unkeyedListEntryBuilder().withNodeIdentifier(SEGMENTS_NID)
57 .addChild(Builders.leafSetBuilder().withNodeIdentifier(SET_LEAFLIST_NID)
58 .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(AS_NUMBER_Q, 10L)).withValue(10L).build())
59 .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(AS_NUMBER_Q, 11L)).withValue(11L).build())
62 static final UnkeyedListEntryNode SEQ_SEGMENT = Builders.unkeyedListEntryBuilder().withNodeIdentifier(SEGMENTS_NID)
63 .addChild(Builders.orderedLeafSetBuilder().withNodeIdentifier(SEQ_LEAFLIST_NID)
64 .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(AS_NUMBER_Q, 1L)).withValue(1L).build())
65 .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(AS_NUMBER_Q, 2L)).withValue(2L).build())
66 .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(AS_NUMBER_Q, 3L)).withValue(3L).build())
69 static final UnkeyedListEntryNode SEQ_SEGMENT2 = Builders.unkeyedListEntryBuilder().withNodeIdentifier(SEGMENTS_NID)
70 .addChild(Builders.orderedLeafSetBuilder().withNodeIdentifier(SEQ_LEAFLIST_NID)
71 .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(AS_NUMBER_Q, 20L)).withValue(20L).build())
72 .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(AS_NUMBER_Q, 2L)).withValue(2L).build())
73 .addChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(AS_NUMBER_Q, 3L)).withValue(3L).build())
77 public void testBestPathForEquality() {
78 this.selector.processPath(this.ROUTER_ID2, createStateFromPrefMedOriginASPath());
79 final BestPath processedPath = this.selector.result();
81 assertEquals(this.originBestPath.getRouterId(), processedPath.getRouterId());
82 assertEquals(this.originBestPath.getState().getLocalPref(), processedPath.getState().getLocalPref());
83 assertEquals(this.originBestPath.getState().getMultiExitDisc(), processedPath.getState().getMultiExitDisc());
84 assertEquals(this.originBestPath.getState().getOrigin(), processedPath.getState().getOrigin());
85 assertEquals(this.originBestPath.getState().getPeerAs(), processedPath.getState().getPeerAs());
86 assertEquals(this.originBestPath.getState().getAsPathLength(), processedPath.getState().getAsPathLength());
90 public void testBestPathWithHigherLocalPref() {
91 this.selector.processPath(this.ROUTER_ID2, createStateFromPrefMedOrigin()); // local-pref 123
92 BestPath processedPath = this.selector.result();
93 assertEquals(123L, processedPath.getState().getLocalPref().longValue());
95 this.selector.processPath(this.ROUTER_ID2, createStateFromPrefMedOriginASPath()); // local-pref 321
96 processedPath = this.selector.result();
97 assertEquals(321L, processedPath.getState().getLocalPref().longValue());
99 addLowerLocalRef(); // prefer path with higher LOCAL_PREF
100 this.selector.processPath(this.ROUTER_ID2, this.dataContBuilder.build());
101 processedPath = this.selector.result();
102 assertEquals(321L, processedPath.getState().getLocalPref().longValue());
106 public void testBestPathSelectionOptions() {
107 this.selector.processPath(this.ROUTER_ID2, createStateFromPrefMedOriginASPath());
108 BestPath processedPath = this.selector.result();
109 assertEquals(1, processedPath.getState().getOrigin().getIntValue());
111 addIgpOrigin(); // prefer the path with the lowest origin type
112 this.selector.processPath(this.ROUTER_ID2, this.dataContBuilder.build());
113 processedPath = this.selector.result();
114 assertEquals(0, processedPath.getState().getOrigin().getIntValue());
117 this.selector.processPath(this.ROUTER_ID2, this.dataContBuilder.build());
118 processedPath = this.selector.result();
119 assertEquals(0, processedPath.getState().getOrigin().getIntValue());
121 // prefer the path with the lowest multi-exit discriminator (MED)
122 assertEquals(4321L, (long) processedPath.getState().getMultiExitDisc());
124 addLowerMultiExitDisc();
125 this.selector.processPath(this.ROUTER_ID2, this.dataContBuilder.build());
126 processedPath = this.selector.result();
127 assertEquals(1234L, (long) processedPath.getState().getMultiExitDisc());
129 addHigherMultiExitDisc();
130 this.selector.processPath(this.ROUTER_ID2, this.dataContBuilder.build());
131 processedPath = this.selector.result();
132 assertEquals(1234L, (long) processedPath.getState().getMultiExitDisc());
134 addLowerMultiExitDisc();
135 addAsPath(SEQ_SEGMENT2);
136 assertEquals(1L, (long) processedPath.getState().getPeerAs());
137 assertEquals(3, processedPath.getState().getAsPathLength());
138 this.selector.processPath(this.ROUTER_ID2, this.dataContBuilder.build());
139 processedPath = this.selector.result();
140 assertEquals(1L, (long) processedPath.getState().getPeerAs());
141 assertEquals(3, processedPath.getState().getAsPathLength());
145 public void testBestPathForNonEquality() {
146 this.selector.processPath(this.ROUTER_ID3, createStateFromPrefMedOrigin());
147 final BestPath processedPath = this.selector.result();
149 assertNotEquals(this.originBestPath.getRouterId(), processedPath.getRouterId());
150 assertNotEquals(this.originBestPath.getState().getLocalPref(), processedPath.getState().getLocalPref());
151 assertNotEquals(this.originBestPath.getState().getMultiExitDisc(), processedPath.getState().getMultiExitDisc());
152 assertNotEquals(this.originBestPath.getState().getOrigin(), processedPath.getState().getOrigin());
153 assertNotEquals(this.originBestPath.getState().getPeerAs(), processedPath.getState().getPeerAs());
154 assertNotEquals(this.originBestPath.getState().getAsPathLength(), processedPath.getState().getAsPathLength());
157 private ContainerNode createStateFromPrefMedOrigin() {
158 this.dataContBuilder = createContBuilder(ATTRS_EXTENSION_Q);
160 addLowerMultiExitDisc();
162 return this.dataContBuilder.build();
165 private ContainerNode createStateFromPrefMedOriginASPath() {
166 this.dataContBuilder = createContBuilder(ATTRS_EXTENSION_Q);
168 addHigherMultiExitDisc();
170 addAsPath(SEQ_SEGMENT);
171 return this.dataContBuilder.build();
174 private void addLowerLocalRef() {
175 this.dataContBuilder.addChild(createContBuilder(this.localPrefQName).addChild(createValueBuilder(123L, this.localPrefQName, "pref").build()).build());
178 private void addHigherLocalRef() {
179 this.dataContBuilder.addChild(createContBuilder(this.localPrefQName).addChild(createValueBuilder(321L, this.localPrefQName, "pref").build()).build());
182 private void addLowerMultiExitDisc() {
183 this.dataContBuilder.addChild(createContBuilder(this.multiExitDiscQName).addChild(createValueBuilder(1234L, this.multiExitDiscQName, "med").build()).build());
186 private void addHigherMultiExitDisc() {
187 this.dataContBuilder.addChild(createContBuilder(this.multiExitDiscQName).addChild(createValueBuilder(4321L, this.multiExitDiscQName, "med").build()).build());
190 private void addIgpOrigin() {
191 this.dataContBuilder.addChild(createContBuilder(this.originQName).addChild(createValueBuilder("igp", this.originQName, "value").build()).build());
194 private void addEgpOrigin() {
195 this.dataContBuilder.addChild(createContBuilder(this.originQName).addChild(createValueBuilder("egp", this.originQName, "value").build()).build());
198 private void addAsPath(final UnkeyedListEntryNode segment) {
199 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> asPathContBuilder = ImmutableContainerNodeSchemaAwareBuilder.create();
200 asPathContBuilder.withNodeIdentifier(new NodeIdentifier(this.asPathQName));
202 final CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> segments = ImmutableUnkeyedListNodeBuilder.create();
203 segments.withNodeIdentifier(SEGMENTS_NID);
204 segments.addChild(segment);
205 asPathContBuilder.addChild(segments.build());
206 this.dataContBuilder.addChild(asPathContBuilder.build());
210 private static DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> createContBuilder(final QName qname) {
211 return ImmutableContainerNodeSchemaAwareBuilder.create().withNodeIdentifier(new NodeIdentifier(qname));
214 private static <T> ImmutableLeafNodeBuilder<T> createValueBuilder(final T value, final QName qname, final String localName) {
215 final ImmutableLeafNodeBuilder<T> valueBuilder = new ImmutableLeafNodeBuilder<>();
216 valueBuilder.withNodeIdentifier(new NodeIdentifier(QName.create(qname, localName))).withValue(value);
221 public void testExtractSegments() {
222 // to be extracted from
223 final CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> builder = Builders.unkeyedListBuilder();
224 builder.withNodeIdentifier(SEGMENTS_NID);
225 builder.addChild(SET_SEGMENT);
226 builder.addChild(SEQ_SEGMENT);
229 final List<AsNumber> sequences = new ArrayList<>();
230 sequences.add(new AsNumber(1L));
231 sequences.add(new AsNumber(2L));
232 sequences.add(new AsNumber(3L));
233 final List<Segments> expected = new ArrayList<>();
234 expected.add(new SegmentsBuilder().setAsSet(Lists.newArrayList(new AsNumber(11L), new AsNumber(10L))).build());
235 expected.add(new SegmentsBuilder().setAsSequence(sequences).build());
237 final List<Segments> actual = this.state.extractSegments(builder.build());
238 assertEquals(expected.size(), actual.size());
239 assertEquals(Sets.newHashSet(1,2,3), Sets.newHashSet(1,3,2));
240 assertEquals(Sets.newHashSet(expected.get(0).getAsSet()), Sets.newHashSet(actual.get(0).getAsSet()));
241 assertEquals(expected.get(1), actual.get(1));
244 @Test(expected=IllegalArgumentException.class)
245 public void testBgpOrigin() {
246 final ContainerNode containerIncom = this.dataContBuilder.addChild(createContBuilder(this.originQName).addChild(createValueBuilder("incomplete", this.originQName, "value").build()).build()).build();
247 this.selector.processPath(this.ROUTER_ID3, containerIncom);
248 final BestPath processedPathIncom = this.selector.result();
249 assertEquals(BgpOrigin.Incomplete, processedPathIncom.getState().getOrigin());
251 final ContainerNode containerException = this.dataContBuilder.addChild(createContBuilder(this.originQName).addChild(createValueBuilder("LOL", this.originQName, "value").build()).build()).build();
252 this.selector.processPath(this.ROUTER_ID3, containerException);
253 final BestPath processedPathException = this.selector.result();
254 processedPathException.getState().getOrigin();