aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/apps/routing/src/test/java/org
diff options
context:
space:
mode:
authorAshlee Young <ashlee@onosfw.com>2015-09-09 22:15:21 -0700
committerAshlee Young <ashlee@onosfw.com>2015-09-09 22:15:21 -0700
commit13d05bc8458758ee39cb829098241e89616717ee (patch)
tree22a4d1ce65f15952f07a3df5af4b462b4697cb3a /framework/src/onos/apps/routing/src/test/java/org
parent6139282e1e93c2322076de4b91b1c85d0bc4a8b3 (diff)
ONOS checkin based on commit tag e796610b1f721d02f9b0e213cf6f7790c10ecd60
Change-Id: Ife8810491034fe7becdba75dda20de4267bd15cd
Diffstat (limited to 'framework/src/onos/apps/routing/src/test/java/org')
-rw-r--r--framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/AsPathTest.java233
-rw-r--r--framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/BgpRouteEntryTest.java520
-rw-r--r--framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/BgpSessionManagerTest.java895
-rw-r--r--framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/PathSegmentTest.java131
-rw-r--r--framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/TestBgpPeerChannelHandler.java207
-rw-r--r--framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/TestBgpPeerFrameDecoder.java175
-rw-r--r--framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/config/impl/HostToInterfaceAdaptorTest.java210
-rw-r--r--framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/impl/RouterAsyncArpTest.java232
-rw-r--r--framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/impl/RouterTest.java287
9 files changed, 2890 insertions, 0 deletions
diff --git a/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/AsPathTest.java b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/AsPathTest.java
new file mode 100644
index 00000000..9213e4e0
--- /dev/null
+++ b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/AsPathTest.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.routing.bgp;
+
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+import java.util.ArrayList;
+
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Unit tests for the BgpRouteEntry.AsPath class.
+ */
+public class AsPathTest {
+ /**
+ * Generates Path Segments.
+ *
+ * @return the generated Path Segments
+ */
+ private ArrayList<BgpRouteEntry.PathSegment> generatePathSegments() {
+ ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
+ byte pathSegmentType;
+ ArrayList<Long> segmentAsNumbers;
+ BgpRouteEntry.PathSegment pathSegment;
+
+ pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_CONFED_SEQUENCE;
+ segmentAsNumbers = new ArrayList<>();
+ segmentAsNumbers.add(1L);
+ segmentAsNumbers.add(2L);
+ segmentAsNumbers.add(3L);
+ pathSegment =
+ new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
+ pathSegments.add(pathSegment);
+ //
+ pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_CONFED_SET;
+ segmentAsNumbers = new ArrayList<>();
+ segmentAsNumbers.add(4L);
+ segmentAsNumbers.add(5L);
+ segmentAsNumbers.add(6L);
+ pathSegment =
+ new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
+ pathSegments.add(pathSegment);
+ //
+ pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
+ segmentAsNumbers = new ArrayList<>();
+ segmentAsNumbers.add(7L);
+ segmentAsNumbers.add(8L);
+ segmentAsNumbers.add(9L);
+ pathSegment =
+ new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
+ pathSegments.add(pathSegment);
+ //
+ pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SET;
+ segmentAsNumbers = new ArrayList<>();
+ segmentAsNumbers.add(10L);
+ segmentAsNumbers.add(11L);
+ segmentAsNumbers.add(12L);
+ pathSegment =
+ new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
+ pathSegments.add(pathSegment);
+
+ return pathSegments;
+ }
+
+ /**
+ * Generates an AS Path.
+ *
+ * @return a generated AS Path
+ */
+ private BgpRouteEntry.AsPath generateAsPath() {
+ ArrayList<BgpRouteEntry.PathSegment> pathSegments =
+ generatePathSegments();
+ BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
+
+ return asPath;
+ }
+
+ /**
+ * Tests valid class constructor.
+ */
+ @Test
+ public void testConstructor() {
+ BgpRouteEntry.AsPath asPath = generateAsPath();
+
+ String expectedString =
+ "AsPath{pathSegments=[" +
+ "PathSegment{type=AS_CONFED_SEQUENCE, segmentAsNumbers=[1, 2, 3]}, " +
+ "PathSegment{type=AS_CONFED_SET, segmentAsNumbers=[4, 5, 6]}, " +
+ "PathSegment{type=AS_SEQUENCE, segmentAsNumbers=[7, 8, 9]}, " +
+ "PathSegment{type=AS_SET, segmentAsNumbers=[10, 11, 12]}]}";
+ assertThat(asPath.toString(), is(expectedString));
+ }
+
+ /**
+ * Tests invalid class constructor for null Path Segments.
+ */
+ @Test(expected = NullPointerException.class)
+ public void testInvalidConstructorNullPathSegments() {
+ ArrayList<BgpRouteEntry.PathSegment> pathSegments = null;
+ new BgpRouteEntry.AsPath(pathSegments);
+ }
+
+ /**
+ * Tests getting the fields of an AS Path.
+ */
+ @Test
+ public void testGetFields() {
+ // Create the fields to compare against
+ ArrayList<BgpRouteEntry.PathSegment> pathSegments =
+ generatePathSegments();
+
+ // Generate the entry to test
+ BgpRouteEntry.AsPath asPath = generateAsPath();
+
+ assertThat(asPath.getPathSegments(), is(pathSegments));
+ }
+
+ /**
+ * Tests getting the AS Path Length.
+ */
+ @Test
+ public void testGetAsPathLength() {
+ //
+ // NOTE:
+ // - AS_CONFED_SEQUENCE and AS_CONFED_SET are excluded
+ // - AS_SET counts as a single hop
+ //
+ BgpRouteEntry.AsPath asPath = generateAsPath();
+ assertThat(asPath.getAsPathLength(), is(4));
+
+ // Create an empty AS Path
+ ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
+ asPath = new BgpRouteEntry.AsPath(pathSegments);
+ assertThat(asPath.getAsPathLength(), is(0));
+ }
+
+ /**
+ * Tests equality of {@link BgpRouteEntry.AsPath}.
+ */
+ @Test
+ public void testEquality() {
+ BgpRouteEntry.AsPath asPath1 = generateAsPath();
+ BgpRouteEntry.AsPath asPath2 = generateAsPath();
+
+ assertThat(asPath1, is(asPath2));
+ }
+
+ /**
+ * Tests non-equality of {@link BgpRouteEntry.AsPath}.
+ */
+ @Test
+ public void testNonEquality() {
+ BgpRouteEntry.AsPath asPath1 = generateAsPath();
+
+ // Setup AS Path 2
+ ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
+ byte pathSegmentType;
+ ArrayList<Long> segmentAsNumbers;
+ BgpRouteEntry.PathSegment pathSegment;
+
+ pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_CONFED_SEQUENCE;
+ segmentAsNumbers = new ArrayList<>();
+ segmentAsNumbers.add(1L);
+ segmentAsNumbers.add(2L);
+ segmentAsNumbers.add(3L);
+ pathSegment =
+ new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
+ pathSegments.add(pathSegment);
+ //
+ pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_CONFED_SET;
+ segmentAsNumbers = new ArrayList<>();
+ segmentAsNumbers.add(4L);
+ segmentAsNumbers.add(5L);
+ segmentAsNumbers.add(6L);
+ pathSegment =
+ new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
+ pathSegments.add(pathSegment);
+ //
+ pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
+ segmentAsNumbers = new ArrayList<>();
+ segmentAsNumbers.add(7L);
+ segmentAsNumbers.add(8L);
+ segmentAsNumbers.add(9L);
+ pathSegment =
+ new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
+ pathSegments.add(pathSegment);
+ //
+ pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SET;
+ segmentAsNumbers = new ArrayList<>();
+ segmentAsNumbers.add(10L);
+ segmentAsNumbers.add(111L); // Different
+ segmentAsNumbers.add(12L);
+ pathSegment =
+ new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
+ pathSegments.add(pathSegment);
+ //
+ BgpRouteEntry.AsPath asPath2 = new BgpRouteEntry.AsPath(pathSegments);
+
+ assertThat(asPath1, Matchers.is(not(asPath2)));
+ }
+
+ /**
+ * Tests object string representation.
+ */
+ @Test
+ public void testToString() {
+ BgpRouteEntry.AsPath asPath = generateAsPath();
+
+ String expectedString =
+ "AsPath{pathSegments=[" +
+ "PathSegment{type=AS_CONFED_SEQUENCE, segmentAsNumbers=[1, 2, 3]}, " +
+ "PathSegment{type=AS_CONFED_SET, segmentAsNumbers=[4, 5, 6]}, " +
+ "PathSegment{type=AS_SEQUENCE, segmentAsNumbers=[7, 8, 9]}, " +
+ "PathSegment{type=AS_SET, segmentAsNumbers=[10, 11, 12]}]}";
+ assertThat(asPath.toString(), is(expectedString));
+ }
+}
diff --git a/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/BgpRouteEntryTest.java b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/BgpRouteEntryTest.java
new file mode 100644
index 00000000..446056e9
--- /dev/null
+++ b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/BgpRouteEntryTest.java
@@ -0,0 +1,520 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.routing.bgp;
+
+import org.easymock.EasyMock;
+import org.hamcrest.Matchers;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+
+import java.util.ArrayList;
+
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Unit tests for the BgpRouteEntry class.
+ */
+public class BgpRouteEntryTest {
+ private BgpSession bgpSession;
+ private static final Ip4Address BGP_SESSION_BGP_ID =
+ Ip4Address.valueOf("10.0.0.1");
+ private static final Ip4Address BGP_SESSION_IP_ADDRESS =
+ Ip4Address.valueOf("20.0.0.1");
+
+ private BgpSession bgpSession2;
+ private static final Ip4Address BGP_SESSION_BGP_ID2 =
+ Ip4Address.valueOf("10.0.0.2");
+ private static final Ip4Address BGP_SESSION_IP_ADDRESS2 =
+ Ip4Address.valueOf("20.0.0.1");
+
+ private BgpSession bgpSession3;
+ private static final Ip4Address BGP_SESSION_BGP_ID3 =
+ Ip4Address.valueOf("10.0.0.1");
+ private static final Ip4Address BGP_SESSION_IP_ADDRESS3 =
+ Ip4Address.valueOf("20.0.0.2");
+
+ private final BgpSessionInfo localInfo = new BgpSessionInfo();
+ private final BgpSessionInfo remoteInfo = new BgpSessionInfo();
+
+ private final BgpSessionInfo localInfo2 = new BgpSessionInfo();
+ private final BgpSessionInfo remoteInfo2 = new BgpSessionInfo();
+
+ private final BgpSessionInfo localInfo3 = new BgpSessionInfo();
+ private final BgpSessionInfo remoteInfo3 = new BgpSessionInfo();
+
+ @Before
+ public void setUp() throws Exception {
+ // Mock objects for testing
+ bgpSession = EasyMock.createMock(BgpSession.class);
+ bgpSession2 = EasyMock.createMock(BgpSession.class);
+ bgpSession3 = EasyMock.createMock(BgpSession.class);
+
+ // Setup the BGP Sessions
+ remoteInfo.setIp4Address(BGP_SESSION_IP_ADDRESS);
+ remoteInfo2.setIp4Address(BGP_SESSION_IP_ADDRESS2);
+ remoteInfo3.setIp4Address(BGP_SESSION_IP_ADDRESS3);
+ remoteInfo.setBgpId(BGP_SESSION_BGP_ID);
+ remoteInfo2.setBgpId(BGP_SESSION_BGP_ID2);
+ remoteInfo3.setBgpId(BGP_SESSION_BGP_ID3);
+
+ EasyMock.expect(bgpSession.localInfo()).andReturn(localInfo).anyTimes();
+ EasyMock.expect(bgpSession.remoteInfo()).andReturn(remoteInfo).anyTimes();
+ EasyMock.expect(bgpSession2.localInfo()).andReturn(localInfo2).anyTimes();
+ EasyMock.expect(bgpSession2.remoteInfo()).andReturn(remoteInfo2).anyTimes();
+ EasyMock.expect(bgpSession3.localInfo()).andReturn(localInfo3).anyTimes();
+ EasyMock.expect(bgpSession3.remoteInfo()).andReturn(remoteInfo3).anyTimes();
+
+ EasyMock.replay(bgpSession);
+ EasyMock.replay(bgpSession2);
+ EasyMock.replay(bgpSession3);
+ }
+
+ /**
+ * Generates a BGP Route Entry.
+ *
+ * @return a generated BGP Route Entry
+ */
+ private BgpRouteEntry generateBgpRouteEntry() {
+ Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
+ Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
+ byte origin = BgpConstants.Update.Origin.IGP;
+ // Setup the AS Path
+ ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
+ byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
+ ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
+ segmentAsNumbers1.add(1L);
+ segmentAsNumbers1.add(2L);
+ segmentAsNumbers1.add(3L);
+ BgpRouteEntry.PathSegment pathSegment1 =
+ new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
+ pathSegments.add(pathSegment1);
+ //
+ byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
+ ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
+ segmentAsNumbers2.add(4L);
+ segmentAsNumbers2.add(5L);
+ segmentAsNumbers2.add(6L);
+ BgpRouteEntry.PathSegment pathSegment2 =
+ new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
+ pathSegments.add(pathSegment2);
+ //
+ BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
+ //
+ long localPref = 100;
+ long multiExitDisc = 20;
+
+ BgpRouteEntry bgpRouteEntry =
+ new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
+ localPref);
+ bgpRouteEntry.setMultiExitDisc(multiExitDisc);
+
+ return bgpRouteEntry;
+ }
+
+ /**
+ * Tests valid class constructor.
+ */
+ @Test
+ public void testConstructor() {
+ BgpRouteEntry bgpRouteEntry = generateBgpRouteEntry();
+
+ String expectedString =
+ "BgpRouteEntry{prefix=1.2.3.0/24, nextHop=5.6.7.8, " +
+ "bgpId=10.0.0.1, origin=IGP, asPath=AsPath{pathSegments=" +
+ "[PathSegment{type=AS_SEQUENCE, segmentAsNumbers=[1, 2, 3]}, " +
+ "PathSegment{type=AS_SET, segmentAsNumbers=[4, 5, 6]}]}, " +
+ "localPref=100, multiExitDisc=20}";
+ assertThat(bgpRouteEntry.toString(), is(expectedString));
+ }
+
+ /**
+ * Tests invalid class constructor for null BGP Session.
+ */
+ @Test(expected = NullPointerException.class)
+ public void testInvalidConstructorNullBgpSession() {
+ BgpSession bgpSessionNull = null;
+ Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
+ Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
+ byte origin = BgpConstants.Update.Origin.IGP;
+ // Setup the AS Path
+ ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
+ BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
+ //
+ long localPref = 100;
+
+ new BgpRouteEntry(bgpSessionNull, prefix, nextHop, origin, asPath,
+ localPref);
+ }
+
+ /**
+ * Tests invalid class constructor for null AS Path.
+ */
+ @Test(expected = NullPointerException.class)
+ public void testInvalidConstructorNullAsPath() {
+ Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
+ Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
+ byte origin = BgpConstants.Update.Origin.IGP;
+ BgpRouteEntry.AsPath asPath = null;
+ long localPref = 100;
+
+ new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
+ localPref);
+ }
+
+ /**
+ * Tests getting the fields of a BGP route entry.
+ */
+ @Test
+ public void testGetFields() {
+ // Create the fields to compare against
+ Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
+ Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
+ byte origin = BgpConstants.Update.Origin.IGP;
+ // Setup the AS Path
+ ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
+ byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
+ ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
+ segmentAsNumbers1.add(1L);
+ segmentAsNumbers1.add(2L);
+ segmentAsNumbers1.add(3L);
+ BgpRouteEntry.PathSegment pathSegment1 =
+ new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
+ pathSegments.add(pathSegment1);
+ //
+ byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
+ ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
+ segmentAsNumbers2.add(4L);
+ segmentAsNumbers2.add(5L);
+ segmentAsNumbers2.add(6L);
+ BgpRouteEntry.PathSegment pathSegment2 =
+ new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
+ pathSegments.add(pathSegment2);
+ //
+ BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
+ //
+ long localPref = 100;
+ long multiExitDisc = 20;
+
+ // Generate the entry to test
+ BgpRouteEntry bgpRouteEntry = generateBgpRouteEntry();
+
+ assertThat(bgpRouteEntry.prefix(), is(prefix));
+ assertThat(bgpRouteEntry.nextHop(), is(nextHop));
+ assertThat(bgpRouteEntry.getBgpSession(), is(bgpSession));
+ assertThat(bgpRouteEntry.getOrigin(), is(origin));
+ assertThat(bgpRouteEntry.getAsPath(), is(asPath));
+ assertThat(bgpRouteEntry.getLocalPref(), is(localPref));
+ assertThat(bgpRouteEntry.getMultiExitDisc(), is(multiExitDisc));
+ }
+
+ /**
+ * Tests whether a BGP route entry is a local route.
+ */
+ @Test
+ public void testIsLocalRoute() {
+ //
+ // Test non-local route
+ //
+ BgpRouteEntry bgpRouteEntry = generateBgpRouteEntry();
+ assertThat(bgpRouteEntry.isLocalRoute(), is(false));
+
+ //
+ // Test local route with AS Path that begins with AS_SET
+ //
+ Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
+ Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
+ byte origin = BgpConstants.Update.Origin.IGP;
+ // Setup the AS Path
+ ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
+ byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SET;
+ ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
+ segmentAsNumbers1.add(1L);
+ segmentAsNumbers1.add(2L);
+ segmentAsNumbers1.add(3L);
+ BgpRouteEntry.PathSegment pathSegment1 =
+ new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
+ pathSegments.add(pathSegment1);
+ //
+ byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
+ ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
+ segmentAsNumbers2.add(4L);
+ segmentAsNumbers2.add(5L);
+ segmentAsNumbers2.add(6L);
+ BgpRouteEntry.PathSegment pathSegment2 =
+ new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
+ pathSegments.add(pathSegment2);
+ //
+ BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
+ //
+ long localPref = 100;
+ long multiExitDisc = 20;
+ //
+ bgpRouteEntry =
+ new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
+ localPref);
+ bgpRouteEntry.setMultiExitDisc(multiExitDisc);
+ assertThat(bgpRouteEntry.isLocalRoute(), is(true));
+
+ //
+ // Test local route with empty AS Path
+ //
+ pathSegments = new ArrayList<>();
+ asPath = new BgpRouteEntry.AsPath(pathSegments);
+ bgpRouteEntry =
+ new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
+ localPref);
+ bgpRouteEntry.setMultiExitDisc(multiExitDisc);
+ assertThat(bgpRouteEntry.isLocalRoute(), is(true));
+ }
+
+ /**
+ * Tests getting the BGP Neighbor AS number for a route.
+ */
+ @Test
+ public void testGetNeighborAs() {
+ //
+ // Get neighbor AS for non-local route
+ //
+ BgpRouteEntry bgpRouteEntry = generateBgpRouteEntry();
+ assertThat(bgpRouteEntry.getNeighborAs(), is(1L));
+
+ //
+ // Get neighbor AS for a local route
+ //
+ Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
+ Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
+ byte origin = BgpConstants.Update.Origin.IGP;
+ // Setup the AS Path
+ ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
+ BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
+ //
+ long localPref = 100;
+ long multiExitDisc = 20;
+ //
+ bgpRouteEntry =
+ new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
+ localPref);
+ bgpRouteEntry.setMultiExitDisc(multiExitDisc);
+ assertThat(bgpRouteEntry.getNeighborAs(), is(BgpConstants.BGP_AS_0));
+ }
+
+ /**
+ * Tests whether a BGP route entry has AS Path loop.
+ */
+ @Test
+ public void testHasAsPathLoop() {
+ BgpRouteEntry bgpRouteEntry = generateBgpRouteEntry();
+
+ // Test for loops: test each AS number in the interval [1, 6]
+ for (int i = 1; i <= 6; i++) {
+ assertThat(bgpRouteEntry.hasAsPathLoop(i), is(true));
+ }
+
+ // Test for non-loops
+ assertThat(bgpRouteEntry.hasAsPathLoop(500), is(false));
+ }
+
+ /**
+ * Tests the BGP Decision Process comparison of BGP routes.
+ */
+ @Test
+ public void testBgpDecisionProcessComparison() {
+ BgpRouteEntry bgpRouteEntry1 = generateBgpRouteEntry();
+ BgpRouteEntry bgpRouteEntry2 = generateBgpRouteEntry();
+
+ //
+ // Compare two routes that are same
+ //
+ assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(true));
+ assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(true));
+
+ //
+ // Compare two routes with different LOCAL_PREF
+ //
+ Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
+ Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
+ byte origin = BgpConstants.Update.Origin.IGP;
+ // Setup the AS Path
+ ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
+ byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
+ ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
+ segmentAsNumbers1.add(1L);
+ segmentAsNumbers1.add(2L);
+ segmentAsNumbers1.add(3L);
+ BgpRouteEntry.PathSegment pathSegment1 =
+ new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
+ pathSegments.add(pathSegment1);
+ //
+ byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
+ ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
+ segmentAsNumbers2.add(4L);
+ segmentAsNumbers2.add(5L);
+ segmentAsNumbers2.add(6L);
+ BgpRouteEntry.PathSegment pathSegment2 =
+ new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
+ pathSegments.add(pathSegment2);
+ //
+ BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
+ //
+ long localPref = 50; // Different
+ long multiExitDisc = 20;
+ bgpRouteEntry2 =
+ new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
+ localPref);
+ bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
+ //
+ assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(true));
+ assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(false));
+ localPref = bgpRouteEntry1.getLocalPref(); // Restore
+
+ //
+ // Compare two routes with different AS_PATH length
+ //
+ ArrayList<BgpRouteEntry.PathSegment> pathSegments2 = new ArrayList<>();
+ pathSegments2.add(pathSegment1);
+ // Different AS Path
+ BgpRouteEntry.AsPath asPath2 = new BgpRouteEntry.AsPath(pathSegments2);
+ bgpRouteEntry2 =
+ new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath2,
+ localPref);
+ bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
+ //
+ assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(false));
+ assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(true));
+
+ //
+ // Compare two routes with different ORIGIN
+ //
+ origin = BgpConstants.Update.Origin.EGP; // Different
+ bgpRouteEntry2 =
+ new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
+ localPref);
+ bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
+ //
+ assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(true));
+ assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(false));
+ origin = bgpRouteEntry1.getOrigin(); // Restore
+
+ //
+ // Compare two routes with different MULTI_EXIT_DISC
+ //
+ multiExitDisc = 10; // Different
+ bgpRouteEntry2 =
+ new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
+ localPref);
+ bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
+ //
+ assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(true));
+ assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(false));
+ multiExitDisc = bgpRouteEntry1.getMultiExitDisc(); // Restore
+
+ //
+ // Compare two routes with different BGP ID
+ //
+ bgpRouteEntry2 =
+ new BgpRouteEntry(bgpSession2, prefix, nextHop, origin, asPath,
+ localPref);
+ bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
+ //
+ assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(true));
+ assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(false));
+
+ //
+ // Compare two routes with different BGP address
+ //
+ bgpRouteEntry2 =
+ new BgpRouteEntry(bgpSession3, prefix, nextHop, origin, asPath,
+ localPref);
+ bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
+ //
+ assertThat(bgpRouteEntry1.isBetterThan(bgpRouteEntry2), is(true));
+ assertThat(bgpRouteEntry2.isBetterThan(bgpRouteEntry1), is(false));
+ }
+
+ /**
+ * Tests equality of {@link BgpRouteEntry}.
+ */
+ @Test
+ public void testEquality() {
+ BgpRouteEntry bgpRouteEntry1 = generateBgpRouteEntry();
+ BgpRouteEntry bgpRouteEntry2 = generateBgpRouteEntry();
+
+ assertThat(bgpRouteEntry1, is(bgpRouteEntry2));
+ }
+
+ /**
+ * Tests non-equality of {@link BgpRouteEntry}.
+ */
+ @Test
+ public void testNonEquality() {
+ BgpRouteEntry bgpRouteEntry1 = generateBgpRouteEntry();
+
+ // Setup BGP Route 2
+ Ip4Prefix prefix = Ip4Prefix.valueOf("1.2.3.0/24");
+ Ip4Address nextHop = Ip4Address.valueOf("5.6.7.8");
+ byte origin = BgpConstants.Update.Origin.IGP;
+ // Setup the AS Path
+ ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
+ byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
+ ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
+ segmentAsNumbers1.add(1L);
+ segmentAsNumbers1.add(2L);
+ segmentAsNumbers1.add(3L);
+ BgpRouteEntry.PathSegment pathSegment1 =
+ new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
+ pathSegments.add(pathSegment1);
+ //
+ byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
+ ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
+ segmentAsNumbers2.add(4L);
+ segmentAsNumbers2.add(5L);
+ segmentAsNumbers2.add(6L);
+ BgpRouteEntry.PathSegment pathSegment2 =
+ new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
+ pathSegments.add(pathSegment2);
+ //
+ BgpRouteEntry.AsPath asPath = new BgpRouteEntry.AsPath(pathSegments);
+ //
+ long localPref = 500; // Different
+ long multiExitDisc = 20;
+ BgpRouteEntry bgpRouteEntry2 =
+ new BgpRouteEntry(bgpSession, prefix, nextHop, origin, asPath,
+ localPref);
+ bgpRouteEntry2.setMultiExitDisc(multiExitDisc);
+
+ assertThat(bgpRouteEntry1, Matchers.is(not(bgpRouteEntry2)));
+ }
+
+ /**
+ * Tests object string representation.
+ */
+ @Test
+ public void testToString() {
+ BgpRouteEntry bgpRouteEntry = generateBgpRouteEntry();
+
+ String expectedString =
+ "BgpRouteEntry{prefix=1.2.3.0/24, nextHop=5.6.7.8, " +
+ "bgpId=10.0.0.1, origin=IGP, asPath=AsPath{pathSegments=" +
+ "[PathSegment{type=AS_SEQUENCE, segmentAsNumbers=[1, 2, 3]}, " +
+ "PathSegment{type=AS_SET, segmentAsNumbers=[4, 5, 6]}]}, " +
+ "localPref=100, multiExitDisc=20}";
+ assertThat(bgpRouteEntry.toString(), is(expectedString));
+ }
+}
diff --git a/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/BgpSessionManagerTest.java b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/BgpSessionManagerTest.java
new file mode 100644
index 00000000..634e87b9
--- /dev/null
+++ b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/BgpSessionManagerTest.java
@@ -0,0 +1,895 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.routing.bgp;
+
+import com.google.common.net.InetAddresses;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+import org.jboss.netty.bootstrap.ClientBootstrap;
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelFactory;
+import org.jboss.netty.channel.ChannelPipeline;
+import org.jboss.netty.channel.ChannelPipelineFactory;
+import org.jboss.netty.channel.Channels;
+import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.junit.TestUtils;
+import org.onlab.junit.TestUtils.TestUtilsException;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onosproject.routing.RouteListener;
+import org.onosproject.routing.RouteUpdate;
+import org.osgi.service.component.ComponentContext;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.LinkedList;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Unit tests for the BgpSessionManager class.
+ */
+public class BgpSessionManagerTest {
+ private static final Ip4Address IP_LOOPBACK_ID =
+ Ip4Address.valueOf("127.0.0.1");
+ private static final Ip4Address BGP_PEER1_ID =
+ Ip4Address.valueOf("10.0.0.1");
+ private static final Ip4Address BGP_PEER2_ID =
+ Ip4Address.valueOf("10.0.0.2");
+ private static final Ip4Address BGP_PEER3_ID =
+ Ip4Address.valueOf("10.0.0.3");
+ private static final Ip4Address NEXT_HOP1_ROUTER =
+ Ip4Address.valueOf("10.20.30.41");
+ private static final Ip4Address NEXT_HOP2_ROUTER =
+ Ip4Address.valueOf("10.20.30.42");
+ private static final Ip4Address NEXT_HOP3_ROUTER =
+ Ip4Address.valueOf("10.20.30.43");
+
+ private static final long DEFAULT_LOCAL_PREF = 10;
+ private static final long BETTER_LOCAL_PREF = 20;
+ private static final long DEFAULT_MULTI_EXIT_DISC = 20;
+ private static final long BETTER_MULTI_EXIT_DISC = 30;
+
+ BgpRouteEntry.AsPath asPathShort;
+ BgpRouteEntry.AsPath asPathLong;
+
+ // Timeout waiting for a message to be received
+ private static final int MESSAGE_TIMEOUT_MS = 5000; // 5s
+
+ // The BGP Session Manager to test
+ private BgpSessionManager bgpSessionManager;
+
+ // Remote Peer state
+ private final Collection<TestBgpPeer> peers = new LinkedList<>();
+ TestBgpPeer peer1;
+ TestBgpPeer peer2;
+ TestBgpPeer peer3;
+
+ // Local BGP per-peer session state
+ BgpSession bgpSession1;
+ BgpSession bgpSession2;
+ BgpSession bgpSession3;
+
+ // The socket that the remote peers should connect to
+ private InetSocketAddress connectToSocket;
+
+ private final DummyRouteListener dummyRouteListener =
+ new DummyRouteListener();
+
+ /**
+ * Dummy implementation for the RouteListener interface.
+ */
+ private class DummyRouteListener implements RouteListener {
+ @Override
+ public void update(Collection<RouteUpdate> routeUpdate) {
+ // Nothing to do
+ }
+ }
+
+ /**
+ * A class to capture the state for a BGP peer.
+ */
+ private final class TestBgpPeer {
+ private final Ip4Address peerId;
+ private ClientBootstrap peerBootstrap;
+ private TestBgpPeerChannelHandler peerChannelHandler;
+ private TestBgpPeerFrameDecoder peerFrameDecoder =
+ new TestBgpPeerFrameDecoder();
+
+ /**
+ * Constructor.
+ *
+ * @param peerId the peer ID
+ */
+ private TestBgpPeer(Ip4Address peerId) {
+ this.peerId = peerId;
+ peerChannelHandler = new TestBgpPeerChannelHandler(peerId);
+ }
+
+ /**
+ * Starts up the BGP peer and connects it to the tested SDN-IP
+ * instance.
+ *
+ * @param connectToSocket the socket to connect to
+ */
+ private void connect(InetSocketAddress connectToSocket)
+ throws InterruptedException {
+ //
+ // Setup the BGP Peer, i.e., the "remote" BGP router that will
+ // initiate the BGP connection, send BGP UPDATE messages, etc.
+ //
+ ChannelFactory channelFactory =
+ new NioClientSocketChannelFactory(
+ Executors.newCachedThreadPool(),
+ Executors.newCachedThreadPool());
+ ChannelPipelineFactory pipelineFactory =
+ new ChannelPipelineFactory() {
+ @Override
+ public ChannelPipeline getPipeline() throws Exception {
+ // Setup the transmitting pipeline
+ ChannelPipeline pipeline = Channels.pipeline();
+ pipeline.addLast("TestBgpPeerFrameDecoder",
+ peerFrameDecoder);
+ pipeline.addLast("TestBgpPeerChannelHandler",
+ peerChannelHandler);
+ return pipeline;
+ }
+ };
+
+ peerBootstrap = new ClientBootstrap(channelFactory);
+ peerBootstrap.setOption("child.keepAlive", true);
+ peerBootstrap.setOption("child.tcpNoDelay", true);
+ peerBootstrap.setPipelineFactory(pipelineFactory);
+ peerBootstrap.connect(connectToSocket);
+
+ boolean result;
+ // Wait until the OPEN message is received
+ result = peerFrameDecoder.receivedOpenMessageLatch.await(
+ MESSAGE_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS);
+ assertThat(result, is(true));
+ // Wait until the KEEPALIVE message is received
+ result = peerFrameDecoder.receivedKeepaliveMessageLatch.await(
+ MESSAGE_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS);
+ assertThat(result, is(true));
+
+ for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
+ if (bgpSession.remoteInfo().bgpId().equals(BGP_PEER1_ID)) {
+ bgpSession1 = bgpSession;
+ }
+ if (bgpSession.remoteInfo().bgpId().equals(BGP_PEER2_ID)) {
+ bgpSession2 = bgpSession;
+ }
+ if (bgpSession.remoteInfo().bgpId().equals(BGP_PEER3_ID)) {
+ bgpSession3 = bgpSession;
+ }
+ }
+ }
+ }
+
+ /**
+ * Class that implements a matcher for BgpRouteEntry by considering
+ * the BGP peer the entry was received from.
+ */
+ private static final class BgpRouteEntryAndPeerMatcher
+ extends TypeSafeMatcher<Collection<BgpRouteEntry>> {
+ private final BgpRouteEntry bgpRouteEntry;
+
+ private BgpRouteEntryAndPeerMatcher(BgpRouteEntry bgpRouteEntry) {
+ this.bgpRouteEntry = bgpRouteEntry;
+ }
+
+ @Override
+ public boolean matchesSafely(Collection<BgpRouteEntry> entries) {
+ for (BgpRouteEntry entry : entries) {
+ if (bgpRouteEntry.equals(entry) &&
+ bgpRouteEntry.getBgpSession() == entry.getBgpSession()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("BGP route entry lookup for entry \"").
+ appendText(bgpRouteEntry.toString()).
+ appendText("\"");
+ }
+ }
+
+ /**
+ * A helper method used for testing whether a collection of
+ * BGP route entries contains an entry from a specific BGP peer.
+ *
+ * @param bgpRouteEntry the BGP route entry to test
+ * @return an instance of BgpRouteEntryAndPeerMatcher that implements
+ * the matching logic
+ */
+ private static BgpRouteEntryAndPeerMatcher hasBgpRouteEntry(
+ BgpRouteEntry bgpRouteEntry) {
+ return new BgpRouteEntryAndPeerMatcher(bgpRouteEntry);
+ }
+
+ @SuppressWarnings("unchecked")
+ private Dictionary<String, String>
+ getDictionaryMock(ComponentContext componentContext) {
+ Dictionary<String, String> dictionary = createMock(Dictionary.class);
+ expect(dictionary.get("bgpPort")).andReturn("0");
+ replay(dictionary);
+ expect(componentContext.getProperties()).andReturn(dictionary);
+ return dictionary;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ peer1 = new TestBgpPeer(BGP_PEER1_ID);
+ peer2 = new TestBgpPeer(BGP_PEER2_ID);
+ peer3 = new TestBgpPeer(BGP_PEER3_ID);
+ peers.clear();
+ peers.add(peer1);
+ peers.add(peer2);
+ peers.add(peer3);
+
+ //
+ // Setup the BGP Session Manager to test, and start listening for BGP
+ // connections.
+ //
+ bgpSessionManager = new BgpSessionManager();
+ // NOTE: We use port 0 to bind on any available port
+ ComponentContext componentContext = createMock(ComponentContext.class);
+ Dictionary<String, String> dictionary = getDictionaryMock(componentContext);
+ replay(componentContext);
+ bgpSessionManager.activate(componentContext);
+ bgpSessionManager.start(dummyRouteListener);
+
+ // Get the port number the BGP Session Manager is listening on
+ Channel serverChannel = TestUtils.getField(bgpSessionManager,
+ "serverChannel");
+ SocketAddress socketAddress = serverChannel.getLocalAddress();
+ InetSocketAddress inetSocketAddress =
+ (InetSocketAddress) socketAddress;
+ InetAddress connectToAddress = InetAddresses.forString("127.0.0.1");
+ connectToSocket = new InetSocketAddress(connectToAddress,
+ inetSocketAddress.getPort());
+
+ //
+ // Setup the AS Paths
+ //
+ ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
+ byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
+ ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
+ segmentAsNumbers1.add(65010L);
+ segmentAsNumbers1.add(65020L);
+ segmentAsNumbers1.add(65030L);
+ BgpRouteEntry.PathSegment pathSegment1 =
+ new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
+ pathSegments.add(pathSegment1);
+ asPathShort = new BgpRouteEntry.AsPath(new ArrayList<>(pathSegments));
+ //
+ byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
+ ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
+ segmentAsNumbers2.add(65041L);
+ segmentAsNumbers2.add(65042L);
+ segmentAsNumbers2.add(65043L);
+ BgpRouteEntry.PathSegment pathSegment2 =
+ new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
+ pathSegments.add(pathSegment2);
+ //
+ asPathLong = new BgpRouteEntry.AsPath(pathSegments);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ bgpSessionManager.stop();
+ bgpSessionManager = null;
+ }
+
+ /**
+ * Gets BGP RIB-IN routes by waiting until they are received.
+ * <p>
+ * NOTE: We keep checking once every 10ms the number of received routes,
+ * up to 5 seconds.
+ * </p>
+ *
+ * @param bgpSession the BGP session that is expected to receive the
+ * routes
+ * @param expectedRoutes the expected number of routes
+ * @return the BGP RIB-IN routes as received within the expected
+ * time interval
+ */
+ private Collection<BgpRouteEntry> waitForBgpRibIn(BgpSession bgpSession,
+ long expectedRoutes)
+ throws InterruptedException {
+ Collection<BgpRouteEntry> bgpRibIn = bgpSession.getBgpRibIn4();
+
+ final int maxChecks = 500; // Max wait of 5 seconds
+ for (int i = 0; i < maxChecks; i++) {
+ if (bgpRibIn.size() == expectedRoutes) {
+ break;
+ }
+ Thread.sleep(10);
+ bgpRibIn = bgpSession.getBgpRibIn4();
+ }
+
+ return bgpRibIn;
+ }
+
+ /**
+ * Gets BGP merged routes by waiting until they are received.
+ * <p>
+ * NOTE: We keep checking once every 10ms the number of received routes,
+ * up to 5 seconds.
+ * </p>
+ *
+ * @param expectedRoutes the expected number of routes
+ * @return the BGP Session Manager routes as received within the expected
+ * time interval
+ */
+ private Collection<BgpRouteEntry> waitForBgpRoutes(long expectedRoutes)
+ throws InterruptedException {
+ Collection<BgpRouteEntry> bgpRoutes =
+ bgpSessionManager.getBgpRoutes4();
+
+ final int maxChecks = 500; // Max wait of 5 seconds
+ for (int i = 0; i < maxChecks; i++) {
+ if (bgpRoutes.size() == expectedRoutes) {
+ break;
+ }
+ Thread.sleep(10);
+ bgpRoutes = bgpSessionManager.getBgpRoutes4();
+ }
+
+ return bgpRoutes;
+ }
+
+ /**
+ * Gets a merged BGP route by waiting until it is received.
+ * <p>
+ * NOTE: We keep checking once every 10ms whether the route is received,
+ * up to 5 seconds.
+ * </p>
+ *
+ * @param expectedRoute the expected route
+ * @return the merged BGP route if received within the expected time
+ * interval, otherwise null
+ */
+ private BgpRouteEntry waitForBgpRoute(BgpRouteEntry expectedRoute)
+ throws InterruptedException {
+ Collection<BgpRouteEntry> bgpRoutes =
+ bgpSessionManager.getBgpRoutes4();
+
+ final int maxChecks = 500; // Max wait of 5 seconds
+ for (int i = 0; i < maxChecks; i++) {
+ for (BgpRouteEntry bgpRouteEntry : bgpRoutes) {
+ if (bgpRouteEntry.equals(expectedRoute) &&
+ bgpRouteEntry.getBgpSession() ==
+ expectedRoute.getBgpSession()) {
+ return bgpRouteEntry;
+ }
+ }
+ Thread.sleep(10);
+ bgpRoutes = bgpSessionManager.getBgpRoutes4();
+ }
+
+ return null;
+ }
+
+ /**
+ * Tests that the BGP OPEN messages have been exchanged, followed by
+ * KEEPALIVE.
+ * <p>
+ * The BGP Peer opens the sessions and transmits OPEN Message, eventually
+ * followed by KEEPALIVE. The tested BGP listener should respond by
+ * OPEN Message, followed by KEEPALIVE.
+ * </p>
+ *
+ * @throws TestUtilsException TestUtils error
+ */
+ @Test
+ public void testExchangedBgpOpenMessages()
+ throws InterruptedException, TestUtilsException {
+ // Initiate the connections
+ peer1.connect(connectToSocket);
+ peer2.connect(connectToSocket);
+ peer3.connect(connectToSocket);
+
+ //
+ // Test the fields from the BGP OPEN message:
+ // BGP version, AS number, BGP ID
+ //
+ for (TestBgpPeer peer : peers) {
+ assertThat(peer.peerFrameDecoder.remoteInfo.bgpVersion(),
+ is(BgpConstants.BGP_VERSION));
+ assertThat(peer.peerFrameDecoder.remoteInfo.bgpId(),
+ is(IP_LOOPBACK_ID));
+ assertThat(peer.peerFrameDecoder.remoteInfo.asNumber(),
+ is(TestBgpPeerChannelHandler.PEER_AS));
+ }
+
+ //
+ // Test that the BgpSession instances have been created
+ //
+ assertThat(bgpSessionManager.getMyBgpId(), is(IP_LOOPBACK_ID));
+ assertThat(bgpSessionManager.getBgpSessions(), hasSize(3));
+ assertThat(bgpSession1, notNullValue());
+ assertThat(bgpSession2, notNullValue());
+ assertThat(bgpSession3, notNullValue());
+ for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
+ long sessionAs = bgpSession.localInfo().asNumber();
+ assertThat(sessionAs, is(TestBgpPeerChannelHandler.PEER_AS));
+ }
+ }
+
+
+ /**
+ * Tests that the BGP OPEN with Capability messages have been exchanged,
+ * followed by KEEPALIVE.
+ * <p>
+ * The BGP Peer opens the sessions and transmits OPEN Message, eventually
+ * followed by KEEPALIVE. The tested BGP listener should respond by
+ * OPEN Message, followed by KEEPALIVE.
+ * </p>
+ *
+ * @throws TestUtilsException TestUtils error
+ */
+ @Test
+ public void testExchangedBgpOpenCapabilityMessages()
+ throws InterruptedException, TestUtilsException {
+ //
+ // Setup the BGP Capabilities for all peers
+ //
+ for (TestBgpPeer peer : peers) {
+ peer.peerChannelHandler.localInfo.setIpv4Unicast();
+ peer.peerChannelHandler.localInfo.setIpv4Multicast();
+ peer.peerChannelHandler.localInfo.setIpv6Unicast();
+ peer.peerChannelHandler.localInfo.setIpv6Multicast();
+ peer.peerChannelHandler.localInfo.setAs4OctetCapability();
+ peer.peerChannelHandler.localInfo.setAs4Number(
+ TestBgpPeerChannelHandler.PEER_AS4);
+ }
+
+ // Initiate the connections
+ peer1.connect(connectToSocket);
+ peer2.connect(connectToSocket);
+ peer3.connect(connectToSocket);
+
+ //
+ // Test the fields from the BGP OPEN message:
+ // BGP version, BGP ID
+ //
+ for (TestBgpPeer peer : peers) {
+ assertThat(peer.peerFrameDecoder.remoteInfo.bgpVersion(),
+ is(BgpConstants.BGP_VERSION));
+ assertThat(peer.peerFrameDecoder.remoteInfo.bgpId(),
+ is(IP_LOOPBACK_ID));
+ }
+
+ //
+ // Test that the BgpSession instances have been created,
+ // and contain the appropriate BGP session information.
+ //
+ assertThat(bgpSessionManager.getMyBgpId(), is(IP_LOOPBACK_ID));
+ assertThat(bgpSessionManager.getBgpSessions(), hasSize(3));
+ assertThat(bgpSession1, notNullValue());
+ assertThat(bgpSession2, notNullValue());
+ assertThat(bgpSession3, notNullValue());
+ for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
+ BgpSessionInfo localInfo = bgpSession.localInfo();
+ assertThat(localInfo.ipv4Unicast(), is(true));
+ assertThat(localInfo.ipv4Multicast(), is(true));
+ assertThat(localInfo.ipv6Unicast(), is(true));
+ assertThat(localInfo.ipv6Multicast(), is(true));
+ assertThat(localInfo.as4OctetCapability(), is(true));
+ assertThat(localInfo.asNumber(),
+ is(TestBgpPeerChannelHandler.PEER_AS4));
+ assertThat(localInfo.as4Number(),
+ is(TestBgpPeerChannelHandler.PEER_AS4));
+ }
+ }
+
+ /**
+ * Tests that the BGP UPDATE messages have been received and processed.
+ */
+ @Test
+ public void testProcessedBgpUpdateMessages() throws InterruptedException {
+ ChannelBuffer message;
+ BgpRouteEntry bgpRouteEntry;
+ Collection<BgpRouteEntry> bgpRibIn1;
+ Collection<BgpRouteEntry> bgpRibIn2;
+ Collection<BgpRouteEntry> bgpRibIn3;
+ Collection<BgpRouteEntry> bgpRoutes;
+
+ // Initiate the connections
+ peer1.connect(connectToSocket);
+ peer2.connect(connectToSocket);
+ peer3.connect(connectToSocket);
+
+ // Prepare routes to add/delete
+ Collection<Ip4Prefix> addedRoutes = new LinkedList<>();
+ Collection<Ip4Prefix> withdrawnRoutes = new LinkedList<>();
+
+ //
+ // Add and delete some routes
+ //
+ addedRoutes.add(Ip4Prefix.valueOf("0.0.0.0/0"));
+ addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
+ addedRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
+ addedRoutes.add(Ip4Prefix.valueOf("40.0.0.0/24"));
+ addedRoutes.add(Ip4Prefix.valueOf("50.0.0.0/32"));
+ withdrawnRoutes.add(Ip4Prefix.valueOf("60.0.0.0/8"));
+ withdrawnRoutes.add(Ip4Prefix.valueOf("70.0.0.0/16"));
+ withdrawnRoutes.add(Ip4Prefix.valueOf("80.0.0.0/24"));
+ withdrawnRoutes.add(Ip4Prefix.valueOf("90.0.0.0/32"));
+ // Write the routes
+ message = peer1.peerChannelHandler.prepareBgpUpdate(
+ NEXT_HOP1_ROUTER,
+ DEFAULT_LOCAL_PREF,
+ DEFAULT_MULTI_EXIT_DISC,
+ asPathLong,
+ addedRoutes,
+ withdrawnRoutes);
+ peer1.peerChannelHandler.savedCtx.getChannel().write(message);
+ //
+ // Check that the routes have been received, processed and stored
+ //
+ bgpRibIn1 = waitForBgpRibIn(bgpSession1, 5);
+ assertThat(bgpRibIn1, hasSize(5));
+ bgpRoutes = waitForBgpRoutes(5);
+ assertThat(bgpRoutes, hasSize(5));
+ //
+ bgpRouteEntry =
+ new BgpRouteEntry(bgpSession1,
+ Ip4Prefix.valueOf("0.0.0.0/0"),
+ NEXT_HOP1_ROUTER,
+ (byte) BgpConstants.Update.Origin.IGP,
+ asPathLong,
+ DEFAULT_LOCAL_PREF);
+ bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
+ assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
+ assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
+ //
+ bgpRouteEntry =
+ new BgpRouteEntry(bgpSession1,
+ Ip4Prefix.valueOf("20.0.0.0/8"),
+ NEXT_HOP1_ROUTER,
+ (byte) BgpConstants.Update.Origin.IGP,
+ asPathLong,
+ DEFAULT_LOCAL_PREF);
+ bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
+ assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
+ assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
+ //
+ bgpRouteEntry =
+ new BgpRouteEntry(bgpSession1,
+ Ip4Prefix.valueOf("30.0.0.0/16"),
+ NEXT_HOP1_ROUTER,
+ (byte) BgpConstants.Update.Origin.IGP,
+ asPathLong,
+ DEFAULT_LOCAL_PREF);
+ bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
+ assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
+ assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
+ //
+ bgpRouteEntry =
+ new BgpRouteEntry(bgpSession1,
+ Ip4Prefix.valueOf("40.0.0.0/24"),
+ NEXT_HOP1_ROUTER,
+ (byte) BgpConstants.Update.Origin.IGP,
+ asPathLong,
+ DEFAULT_LOCAL_PREF);
+ bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
+ assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
+ assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
+ //
+ bgpRouteEntry =
+ new BgpRouteEntry(bgpSession1,
+ Ip4Prefix.valueOf("50.0.0.0/32"),
+ NEXT_HOP1_ROUTER,
+ (byte) BgpConstants.Update.Origin.IGP,
+ asPathLong,
+ DEFAULT_LOCAL_PREF);
+ bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
+ assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
+ assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
+
+ //
+ // Delete some routes
+ //
+ addedRoutes = new LinkedList<>();
+ withdrawnRoutes = new LinkedList<>();
+ withdrawnRoutes.add(Ip4Prefix.valueOf("0.0.0.0/0"));
+ withdrawnRoutes.add(Ip4Prefix.valueOf("50.0.0.0/32"));
+ // Write the routes
+ message = peer1.peerChannelHandler.prepareBgpUpdate(
+ NEXT_HOP1_ROUTER,
+ DEFAULT_LOCAL_PREF,
+ DEFAULT_MULTI_EXIT_DISC,
+ asPathLong,
+ addedRoutes,
+ withdrawnRoutes);
+ peer1.peerChannelHandler.savedCtx.getChannel().write(message);
+ //
+ // Check that the routes have been received, processed and stored
+ //
+ bgpRibIn1 = waitForBgpRibIn(bgpSession1, 3);
+ assertThat(bgpRibIn1, hasSize(3));
+ bgpRoutes = waitForBgpRoutes(3);
+ assertThat(bgpRoutes, hasSize(3));
+ //
+ bgpRouteEntry =
+ new BgpRouteEntry(bgpSession1,
+ Ip4Prefix.valueOf("20.0.0.0/8"),
+ NEXT_HOP1_ROUTER,
+ (byte) BgpConstants.Update.Origin.IGP,
+ asPathLong,
+ DEFAULT_LOCAL_PREF);
+ bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
+ assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
+ assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
+ //
+ bgpRouteEntry =
+ new BgpRouteEntry(bgpSession1,
+ Ip4Prefix.valueOf("30.0.0.0/16"),
+ NEXT_HOP1_ROUTER,
+ (byte) BgpConstants.Update.Origin.IGP,
+ asPathLong,
+ DEFAULT_LOCAL_PREF);
+ bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
+ assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
+ assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
+ //
+ bgpRouteEntry =
+ new BgpRouteEntry(bgpSession1,
+ Ip4Prefix.valueOf("40.0.0.0/24"),
+ NEXT_HOP1_ROUTER,
+ (byte) BgpConstants.Update.Origin.IGP,
+ asPathLong,
+ DEFAULT_LOCAL_PREF);
+ bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
+ assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
+ assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
+
+
+ // Close the channels and test there are no routes
+ peer1.peerChannelHandler.closeChannel();
+ peer2.peerChannelHandler.closeChannel();
+ peer3.peerChannelHandler.closeChannel();
+ bgpRoutes = waitForBgpRoutes(0);
+ assertThat(bgpRoutes, hasSize(0));
+ }
+
+ /**
+ * Tests the BGP route preference.
+ */
+ @Test
+ public void testBgpRoutePreference() throws InterruptedException {
+ ChannelBuffer message;
+ BgpRouteEntry bgpRouteEntry;
+ Collection<BgpRouteEntry> bgpRibIn1;
+ Collection<BgpRouteEntry> bgpRibIn2;
+ Collection<BgpRouteEntry> bgpRibIn3;
+ Collection<BgpRouteEntry> bgpRoutes;
+ Collection<Ip4Prefix> addedRoutes = new LinkedList<>();
+ Collection<Ip4Prefix> withdrawnRoutes = new LinkedList<>();
+
+ // Initiate the connections
+ peer1.connect(connectToSocket);
+ peer2.connect(connectToSocket);
+ peer3.connect(connectToSocket);
+
+ //
+ // Setup the initial set of routes to Peer1
+ //
+ addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
+ addedRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
+ // Write the routes
+ message = peer1.peerChannelHandler.prepareBgpUpdate(
+ NEXT_HOP1_ROUTER,
+ DEFAULT_LOCAL_PREF,
+ DEFAULT_MULTI_EXIT_DISC,
+ asPathLong,
+ addedRoutes,
+ withdrawnRoutes);
+ peer1.peerChannelHandler.savedCtx.getChannel().write(message);
+ bgpRoutes = waitForBgpRoutes(2);
+ assertThat(bgpRoutes, hasSize(2));
+
+ //
+ // Add a route entry to Peer2 with a better LOCAL_PREF
+ //
+ addedRoutes = new LinkedList<>();
+ withdrawnRoutes = new LinkedList<>();
+ addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
+ // Write the routes
+ message = peer2.peerChannelHandler.prepareBgpUpdate(
+ NEXT_HOP2_ROUTER,
+ BETTER_LOCAL_PREF,
+ DEFAULT_MULTI_EXIT_DISC,
+ asPathLong,
+ addedRoutes,
+ withdrawnRoutes);
+ peer2.peerChannelHandler.savedCtx.getChannel().write(message);
+ //
+ // Check that the routes have been received, processed and stored
+ //
+ bgpRibIn2 = waitForBgpRibIn(bgpSession2, 1);
+ assertThat(bgpRibIn2, hasSize(1));
+ bgpRoutes = waitForBgpRoutes(2);
+ assertThat(bgpRoutes, hasSize(2));
+ //
+ bgpRouteEntry =
+ new BgpRouteEntry(bgpSession2,
+ Ip4Prefix.valueOf("20.0.0.0/8"),
+ NEXT_HOP2_ROUTER,
+ (byte) BgpConstants.Update.Origin.IGP,
+ asPathLong,
+ BETTER_LOCAL_PREF);
+ bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
+ assertThat(bgpRibIn2, hasBgpRouteEntry(bgpRouteEntry));
+ assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
+
+ //
+ // Add a route entry to Peer3 with a shorter AS path
+ //
+ addedRoutes = new LinkedList<>();
+ withdrawnRoutes = new LinkedList<>();
+ addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
+ // Write the routes
+ message = peer3.peerChannelHandler.prepareBgpUpdate(
+ NEXT_HOP3_ROUTER,
+ BETTER_LOCAL_PREF,
+ DEFAULT_MULTI_EXIT_DISC,
+ asPathShort,
+ addedRoutes,
+ withdrawnRoutes);
+ peer3.peerChannelHandler.savedCtx.getChannel().write(message);
+ //
+ // Check that the routes have been received, processed and stored
+ //
+ bgpRibIn3 = waitForBgpRibIn(bgpSession3, 1);
+ assertThat(bgpRibIn3, hasSize(1));
+ bgpRoutes = waitForBgpRoutes(2);
+ assertThat(bgpRoutes, hasSize(2));
+ //
+ bgpRouteEntry =
+ new BgpRouteEntry(bgpSession3,
+ Ip4Prefix.valueOf("20.0.0.0/8"),
+ NEXT_HOP3_ROUTER,
+ (byte) BgpConstants.Update.Origin.IGP,
+ asPathShort,
+ BETTER_LOCAL_PREF);
+ bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
+ assertThat(bgpRibIn3, hasBgpRouteEntry(bgpRouteEntry));
+ assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
+
+ //
+ // Cleanup in preparation for next test: delete old route entry from
+ // Peer2
+ //
+ addedRoutes = new LinkedList<>();
+ withdrawnRoutes = new LinkedList<>();
+ withdrawnRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
+ // Write the routes
+ message = peer2.peerChannelHandler.prepareBgpUpdate(
+ NEXT_HOP2_ROUTER,
+ BETTER_LOCAL_PREF,
+ BETTER_MULTI_EXIT_DISC,
+ asPathShort,
+ addedRoutes,
+ withdrawnRoutes);
+ peer2.peerChannelHandler.savedCtx.getChannel().write(message);
+ //
+ // Check that the routes have been received, processed and stored
+ //
+ bgpRibIn2 = waitForBgpRibIn(bgpSession2, 0);
+ assertThat(bgpRibIn2, hasSize(0));
+
+ //
+ // Add a route entry to Peer2 with a better MED
+ //
+ addedRoutes = new LinkedList<>();
+ withdrawnRoutes = new LinkedList<>();
+ addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
+ // Write the routes
+ message = peer2.peerChannelHandler.prepareBgpUpdate(
+ NEXT_HOP2_ROUTER,
+ BETTER_LOCAL_PREF,
+ BETTER_MULTI_EXIT_DISC,
+ asPathShort,
+ addedRoutes,
+ withdrawnRoutes);
+ peer2.peerChannelHandler.savedCtx.getChannel().write(message);
+ //
+ // Check that the routes have been received, processed and stored
+ //
+ bgpRibIn2 = waitForBgpRibIn(bgpSession2, 1);
+ assertThat(bgpRibIn2, hasSize(1));
+ bgpRoutes = waitForBgpRoutes(2);
+ assertThat(bgpRoutes, hasSize(2));
+ //
+ bgpRouteEntry =
+ new BgpRouteEntry(bgpSession2,
+ Ip4Prefix.valueOf("20.0.0.0/8"),
+ NEXT_HOP2_ROUTER,
+ (byte) BgpConstants.Update.Origin.IGP,
+ asPathShort,
+ BETTER_LOCAL_PREF);
+ bgpRouteEntry.setMultiExitDisc(BETTER_MULTI_EXIT_DISC);
+ assertThat(bgpRibIn2, hasBgpRouteEntry(bgpRouteEntry));
+ assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
+
+ //
+ // Add a route entry to Peer1 with a better (lower) BGP ID
+ //
+ addedRoutes = new LinkedList<>();
+ withdrawnRoutes = new LinkedList<>();
+ addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
+ withdrawnRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
+ // Write the routes
+ message = peer1.peerChannelHandler.prepareBgpUpdate(
+ NEXT_HOP1_ROUTER,
+ BETTER_LOCAL_PREF,
+ BETTER_MULTI_EXIT_DISC,
+ asPathShort,
+ addedRoutes,
+ withdrawnRoutes);
+ peer1.peerChannelHandler.savedCtx.getChannel().write(message);
+ //
+ // Check that the routes have been received, processed and stored
+ //
+ bgpRibIn1 = waitForBgpRibIn(bgpSession1, 1);
+ assertThat(bgpRibIn1, hasSize(1));
+ bgpRoutes = waitForBgpRoutes(1);
+ assertThat(bgpRoutes, hasSize(1));
+ //
+ bgpRouteEntry =
+ new BgpRouteEntry(bgpSession1,
+ Ip4Prefix.valueOf("20.0.0.0/8"),
+ NEXT_HOP1_ROUTER,
+ (byte) BgpConstants.Update.Origin.IGP,
+ asPathShort,
+ BETTER_LOCAL_PREF);
+ bgpRouteEntry.setMultiExitDisc(BETTER_MULTI_EXIT_DISC);
+ assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
+ assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
+
+
+ // Close the channels and test there are no routes
+ peer1.peerChannelHandler.closeChannel();
+ peer2.peerChannelHandler.closeChannel();
+ peer3.peerChannelHandler.closeChannel();
+ bgpRoutes = waitForBgpRoutes(0);
+ assertThat(bgpRoutes, hasSize(0));
+ }
+}
diff --git a/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/PathSegmentTest.java b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/PathSegmentTest.java
new file mode 100644
index 00000000..516bf578
--- /dev/null
+++ b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/PathSegmentTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.routing.bgp;
+
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+import java.util.ArrayList;
+
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Unit tests for the BgpRouteEntry.PathSegment class.
+ */
+public class PathSegmentTest {
+ /**
+ * Generates a Path Segment.
+ *
+ * @return a generated PathSegment
+ */
+ private BgpRouteEntry.PathSegment generatePathSegment() {
+ byte pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
+ ArrayList<Long> segmentAsNumbers = new ArrayList<>();
+ segmentAsNumbers.add(1L);
+ segmentAsNumbers.add(2L);
+ segmentAsNumbers.add(3L);
+ BgpRouteEntry.PathSegment pathSegment =
+ new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
+
+ return pathSegment;
+ }
+
+ /**
+ * Tests valid class constructor.
+ */
+ @Test
+ public void testConstructor() {
+ BgpRouteEntry.PathSegment pathSegment = generatePathSegment();
+
+ String expectedString =
+ "PathSegment{type=AS_SEQUENCE, segmentAsNumbers=[1, 2, 3]}";
+ assertThat(pathSegment.toString(), is(expectedString));
+ }
+
+ /**
+ * Tests invalid class constructor for null Segment AS Numbers.
+ */
+ @Test(expected = NullPointerException.class)
+ public void testInvalidConstructorNullSegmentAsNumbers() {
+ byte pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
+ ArrayList<Long> segmentAsNumbers = null;
+ new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
+ }
+
+ /**
+ * Tests getting the fields of a Path Segment.
+ */
+ @Test
+ public void testGetFields() {
+ // Create the fields to compare against
+ byte pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
+ ArrayList<Long> segmentAsNumbers = new ArrayList<>();
+ segmentAsNumbers.add(1L);
+ segmentAsNumbers.add(2L);
+ segmentAsNumbers.add(3L);
+
+ // Generate the entry to test
+ BgpRouteEntry.PathSegment pathSegment = generatePathSegment();
+
+ assertThat(pathSegment.getType(), is(pathSegmentType));
+ assertThat(pathSegment.getSegmentAsNumbers(), is(segmentAsNumbers));
+ }
+
+ /**
+ * Tests equality of {@link BgpRouteEntry.PathSegment}.
+ */
+ @Test
+ public void testEquality() {
+ BgpRouteEntry.PathSegment pathSegment1 = generatePathSegment();
+ BgpRouteEntry.PathSegment pathSegment2 = generatePathSegment();
+
+ assertThat(pathSegment1, is(pathSegment2));
+ }
+
+ /**
+ * Tests non-equality of {@link BgpRouteEntry.PathSegment}.
+ */
+ @Test
+ public void testNonEquality() {
+ BgpRouteEntry.PathSegment pathSegment1 = generatePathSegment();
+
+ // Setup Path Segment 2
+ byte pathSegmentType = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
+ ArrayList<Long> segmentAsNumbers = new ArrayList<>();
+ segmentAsNumbers.add(1L);
+ segmentAsNumbers.add(22L); // Different
+ segmentAsNumbers.add(3L);
+ //
+ BgpRouteEntry.PathSegment pathSegment2 =
+ new BgpRouteEntry.PathSegment(pathSegmentType, segmentAsNumbers);
+
+ assertThat(pathSegment1, Matchers.is(not(pathSegment2)));
+ }
+
+ /**
+ * Tests object string representation.
+ */
+ @Test
+ public void testToString() {
+ BgpRouteEntry.PathSegment pathSegment = generatePathSegment();
+
+ String expectedString =
+ "PathSegment{type=AS_SEQUENCE, segmentAsNumbers=[1, 2, 3]}";
+ assertThat(pathSegment.toString(), is(expectedString));
+ }
+}
diff --git a/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/TestBgpPeerChannelHandler.java b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/TestBgpPeerChannelHandler.java
new file mode 100644
index 00000000..41485e95
--- /dev/null
+++ b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/TestBgpPeerChannelHandler.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.routing.bgp;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.ChannelStateEvent;
+import org.jboss.netty.channel.SimpleChannelHandler;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+
+import java.util.Collection;
+
+/**
+ * Class for handling the remote BGP Peer session.
+ */
+class TestBgpPeerChannelHandler extends SimpleChannelHandler {
+ static final long PEER_AS = 65001;
+ static final long PEER_AS4 = 0x12345678;
+ static final int PEER_HOLDTIME = 120; // 120 seconds
+
+ final BgpSessionInfo localInfo = new BgpSessionInfo();
+ ChannelHandlerContext savedCtx;
+
+ /**
+ * Constructor for given BGP ID.
+ *
+ * @param bgpId the BGP ID to use
+ */
+ TestBgpPeerChannelHandler(Ip4Address bgpId) {
+ this.localInfo.setBgpVersion(BgpConstants.BGP_VERSION);
+ this.localInfo.setBgpId(bgpId);
+ this.localInfo.setAsNumber(PEER_AS);
+ this.localInfo.setHoldtime(PEER_HOLDTIME);
+ }
+
+ /**
+ * Closes the channel.
+ */
+ void closeChannel() {
+ savedCtx.getChannel().close();
+ }
+
+ @Override
+ public void channelConnected(ChannelHandlerContext ctx,
+ ChannelStateEvent channelEvent) {
+ this.savedCtx = ctx;
+ // Prepare and transmit BGP OPEN message
+ ChannelBuffer message = BgpOpen.prepareBgpOpen(localInfo);
+ ctx.getChannel().write(message);
+
+ // Prepare and transmit BGP KEEPALIVE message
+ message = BgpKeepalive.prepareBgpKeepalive();
+ ctx.getChannel().write(message);
+ }
+
+ @Override
+ public void channelDisconnected(ChannelHandlerContext ctx,
+ ChannelStateEvent channelEvent) {
+ // Nothing to do
+ }
+
+ /**
+ * Prepares BGP UPDATE message.
+ *
+ * @param nextHopRouter the next-hop router address for the routes to add
+ * @param localPref the local preference for the routes to use
+ * @param multiExitDisc the MED value
+ * @param asPath the AS path for the routes to add
+ * @param addedRoutes the routes to add
+ * @param withdrawnRoutes the routes to withdraw
+ * @return the message to transmit (BGP header included)
+ */
+ ChannelBuffer prepareBgpUpdate(Ip4Address nextHopRouter,
+ long localPref,
+ long multiExitDisc,
+ BgpRouteEntry.AsPath asPath,
+ Collection<Ip4Prefix> addedRoutes,
+ Collection<Ip4Prefix> withdrawnRoutes) {
+ int attrFlags;
+ ChannelBuffer message =
+ ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
+ ChannelBuffer pathAttributes =
+ ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
+
+ // Encode the Withdrawn Routes
+ ChannelBuffer encodedPrefixes = encodePackedPrefixes(withdrawnRoutes);
+ message.writeShort(encodedPrefixes.readableBytes());
+ message.writeBytes(encodedPrefixes);
+
+ // Encode the Path Attributes
+ // ORIGIN: IGP
+ attrFlags = 0x40; // Transitive flag
+ pathAttributes.writeByte(attrFlags);
+ pathAttributes.writeByte(BgpConstants.Update.Origin.TYPE);
+ pathAttributes.writeByte(1); // Data length
+ pathAttributes.writeByte(BgpConstants.Update.Origin.IGP);
+
+ // AS_PATH: asPath
+ attrFlags = 0x40; // Transitive flag
+ pathAttributes.writeByte(attrFlags);
+ pathAttributes.writeByte(BgpConstants.Update.AsPath.TYPE);
+ ChannelBuffer encodedAsPath = encodeAsPath(asPath);
+ pathAttributes.writeByte(encodedAsPath.readableBytes()); // Data length
+ pathAttributes.writeBytes(encodedAsPath);
+ // NEXT_HOP: nextHopRouter
+ attrFlags = 0x40; // Transitive flag
+ pathAttributes.writeByte(attrFlags);
+ pathAttributes.writeByte(BgpConstants.Update.NextHop.TYPE);
+ pathAttributes.writeByte(4); // Data length
+ pathAttributes.writeInt(nextHopRouter.toInt()); // Next-hop router
+ // LOCAL_PREF: localPref
+ attrFlags = 0x40; // Transitive flag
+ pathAttributes.writeByte(attrFlags);
+ pathAttributes.writeByte(BgpConstants.Update.LocalPref.TYPE);
+ pathAttributes.writeByte(4); // Data length
+ pathAttributes.writeInt((int) localPref); // Preference value
+ // MULTI_EXIT_DISC: multiExitDisc
+ attrFlags = 0x80; // Optional
+ // Non-Transitive flag
+ pathAttributes.writeByte(attrFlags);
+ pathAttributes.writeByte(BgpConstants.Update.MultiExitDisc.TYPE);
+ pathAttributes.writeByte(4); // Data length
+ pathAttributes.writeInt((int) multiExitDisc); // Preference value
+ // The NLRI prefixes
+ encodedPrefixes = encodePackedPrefixes(addedRoutes);
+
+ // Write the Path Attributes, beginning with its length
+ message.writeShort(pathAttributes.readableBytes());
+ message.writeBytes(pathAttributes);
+ message.writeBytes(encodedPrefixes);
+
+ return BgpMessage.prepareBgpMessage(BgpConstants.BGP_TYPE_UPDATE,
+ message);
+ }
+
+ /**
+ * Encodes a collection of IPv4 network prefixes in a packed format.
+ * <p>
+ * The IPv4 prefixes are encoded in the form:
+ * <Length, Prefix> where Length is the length in bits of the IPv4 prefix,
+ * and Prefix is the IPv4 prefix (padded with trailing bits to the end
+ * of an octet).
+ *
+ * @param prefixes the prefixes to encode
+ * @return the buffer with the encoded prefixes
+ */
+ private ChannelBuffer encodePackedPrefixes(Collection<Ip4Prefix> prefixes) {
+ ChannelBuffer message =
+ ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
+
+ // Write each of the prefixes
+ for (Ip4Prefix prefix : prefixes) {
+ int prefixBitlen = prefix.prefixLength();
+ int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
+ message.writeByte(prefixBitlen);
+
+ Ip4Address address = prefix.address();
+ long value = address.toInt() & 0xffffffffL;
+ for (int i = 0; i < Ip4Address.BYTE_LENGTH; i++) {
+ if (prefixBytelen-- == 0) {
+ break;
+ }
+ long nextByte =
+ (value >> ((Ip4Address.BYTE_LENGTH - i - 1) * 8)) & 0xff;
+ message.writeByte((int) nextByte);
+ }
+ }
+
+ return message;
+ }
+
+ /**
+ * Encodes an AS path.
+ *
+ * @param asPath the AS path to encode
+ * @return the buffer with the encoded AS path
+ */
+ private ChannelBuffer encodeAsPath(BgpRouteEntry.AsPath asPath) {
+ ChannelBuffer message =
+ ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
+
+ for (BgpRouteEntry.PathSegment pathSegment : asPath.getPathSegments()) {
+ message.writeByte(pathSegment.getType());
+ message.writeByte(pathSegment.getSegmentAsNumbers().size());
+ for (Long asNumber : pathSegment.getSegmentAsNumbers()) {
+ message.writeShort(asNumber.intValue());
+ }
+ }
+
+ return message;
+ }
+}
diff --git a/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/TestBgpPeerFrameDecoder.java b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/TestBgpPeerFrameDecoder.java
new file mode 100644
index 00000000..b4ff40d2
--- /dev/null
+++ b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/bgp/TestBgpPeerFrameDecoder.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.routing.bgp;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.handler.codec.frame.FrameDecoder;
+import org.onlab.packet.Ip4Address;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * Class for handling the decoding of the BGP messages at the remote
+ * BGP peer session.
+ */
+class TestBgpPeerFrameDecoder extends FrameDecoder {
+ final BgpSessionInfo remoteInfo = new BgpSessionInfo();
+
+ final CountDownLatch receivedOpenMessageLatch = new CountDownLatch(1);
+ final CountDownLatch receivedKeepaliveMessageLatch = new CountDownLatch(1);
+
+ @Override
+ protected Object decode(ChannelHandlerContext ctx,
+ Channel channel,
+ ChannelBuffer buf) throws Exception {
+ // Test for minimum length of the BGP message
+ if (buf.readableBytes() < BgpConstants.BGP_HEADER_LENGTH) {
+ // No enough data received
+ return null;
+ }
+
+ //
+ // Mark the current buffer position in case we haven't received
+ // the whole message.
+ //
+ buf.markReaderIndex();
+
+ //
+ // Read and check the BGP message Marker field: it must be all ones
+ //
+ byte[] marker = new byte[BgpConstants.BGP_HEADER_MARKER_LENGTH];
+ buf.readBytes(marker);
+ for (int i = 0; i < marker.length; i++) {
+ if (marker[i] != (byte) 0xff) {
+ // ERROR: Connection Not Synchronized. Close the channel.
+ ctx.getChannel().close();
+ return null;
+ }
+ }
+
+ //
+ // Read and check the BGP message Length field
+ //
+ int length = buf.readUnsignedShort();
+ if ((length < BgpConstants.BGP_HEADER_LENGTH) ||
+ (length > BgpConstants.BGP_MESSAGE_MAX_LENGTH)) {
+ // ERROR: Bad Message Length. Close the channel.
+ ctx.getChannel().close();
+ return null;
+ }
+
+ //
+ // Test whether the rest of the message is received:
+ // So far we have read the Marker (16 octets) and the
+ // Length (2 octets) fields.
+ //
+ int remainingMessageLen =
+ length - BgpConstants.BGP_HEADER_MARKER_LENGTH - 2;
+ if (buf.readableBytes() < remainingMessageLen) {
+ // No enough data received
+ buf.resetReaderIndex();
+ return null;
+ }
+
+ //
+ // Read the BGP message Type field, and process based on that type
+ //
+ int type = buf.readUnsignedByte();
+ remainingMessageLen--; // Adjust after reading the type
+ ChannelBuffer message = buf.readBytes(remainingMessageLen);
+
+ //
+ // Process the remaining of the message based on the message type
+ //
+ switch (type) {
+ case BgpConstants.BGP_TYPE_OPEN:
+ processBgpOpen(ctx, message);
+ break;
+ case BgpConstants.BGP_TYPE_UPDATE:
+ // NOTE: Not used as part of the test, because ONOS does not
+ // originate UPDATE messages.
+ break;
+ case BgpConstants.BGP_TYPE_NOTIFICATION:
+ // NOTE: Not used as part of the testing (yet)
+ break;
+ case BgpConstants.BGP_TYPE_KEEPALIVE:
+ processBgpKeepalive(ctx, message);
+ break;
+ default:
+ // ERROR: Bad Message Type. Close the channel.
+ ctx.getChannel().close();
+ return null;
+ }
+
+ return null;
+ }
+
+ /**
+ * Processes BGP OPEN message.
+ *
+ * @param ctx the Channel Handler Context.
+ * @param message the message to process.
+ */
+ private void processBgpOpen(ChannelHandlerContext ctx,
+ ChannelBuffer message) {
+ int minLength =
+ BgpConstants.BGP_OPEN_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
+ if (message.readableBytes() < minLength) {
+ // ERROR: Bad Message Length. Close the channel.
+ ctx.getChannel().close();
+ return;
+ }
+
+ //
+ // Parse the OPEN message
+ //
+ remoteInfo.setBgpVersion(message.readUnsignedByte());
+ remoteInfo.setAsNumber(message.readUnsignedShort());
+ remoteInfo.setHoldtime(message.readUnsignedShort());
+ remoteInfo.setBgpId(Ip4Address.valueOf((int) message.readUnsignedInt()));
+ // Optional Parameters
+ int optParamLen = message.readUnsignedByte();
+ if (message.readableBytes() < optParamLen) {
+ // ERROR: Bad Message Length. Close the channel.
+ ctx.getChannel().close();
+ return;
+ }
+ message.readBytes(optParamLen); // NOTE: data ignored
+
+ // BGP OPEN message successfully received
+ receivedOpenMessageLatch.countDown();
+ }
+
+ /**
+ * Processes BGP KEEPALIVE message.
+ *
+ * @param ctx the Channel Handler Context.
+ * @param message the message to process.
+ */
+ private void processBgpKeepalive(ChannelHandlerContext ctx,
+ ChannelBuffer message) {
+ if (message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH !=
+ BgpConstants.BGP_KEEPALIVE_EXPECTED_LENGTH) {
+ // ERROR: Bad Message Length. Close the channel.
+ ctx.getChannel().close();
+ return;
+ }
+ // BGP KEEPALIVE message successfully received
+ receivedKeepaliveMessageLatch.countDown();
+ }
+}
diff --git a/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/config/impl/HostToInterfaceAdaptorTest.java b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/config/impl/HostToInterfaceAdaptorTest.java
new file mode 100644
index 00000000..0347fc5f
--- /dev/null
+++ b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/config/impl/HostToInterfaceAdaptorTest.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.routing.config.impl;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.host.HostService;
+import org.onosproject.net.host.InterfaceIpAddress;
+import org.onosproject.net.host.PortAddresses;
+import org.onosproject.routing.config.Interface;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Unit tests for the HostToInterfaceAdaptor class.
+ */
+public class HostToInterfaceAdaptorTest {
+
+ private HostService hostService;
+ private HostToInterfaceAdaptor adaptor;
+
+ private Set<PortAddresses> portAddresses;
+ private Map<ConnectPoint, Interface> interfaces;
+
+ private static final ConnectPoint CP1 = new ConnectPoint(
+ DeviceId.deviceId("of:1"), PortNumber.portNumber(1));
+ private static final ConnectPoint CP2 = new ConnectPoint(
+ DeviceId.deviceId("of:1"), PortNumber.portNumber(2));
+ private static final ConnectPoint CP3 = new ConnectPoint(
+ DeviceId.deviceId("of:2"), PortNumber.portNumber(1));
+
+ private static final ConnectPoint NON_EXISTENT_CP = new ConnectPoint(
+ DeviceId.deviceId("doesnotexist"), PortNumber.portNumber(1));
+
+ @Before
+ public void setUp() throws Exception {
+ hostService = createMock(HostService.class);
+
+ portAddresses = Sets.newHashSet();
+ interfaces = Maps.newHashMap();
+
+ InterfaceIpAddress ia11 =
+ new InterfaceIpAddress(IpAddress.valueOf("192.168.1.1"),
+ IpPrefix.valueOf("192.168.1.0/24"));
+ createPortAddressesAndInterface(CP1,
+ Sets.newHashSet(ia11),
+ MacAddress.valueOf("00:00:00:00:00:01"),
+ VlanId.NONE);
+
+ // Two addresses in the same subnet
+ InterfaceIpAddress ia21 =
+ new InterfaceIpAddress(IpAddress.valueOf("192.168.2.1"),
+ IpPrefix.valueOf("192.168.2.0/24"));
+ InterfaceIpAddress ia22 =
+ new InterfaceIpAddress(IpAddress.valueOf("192.168.2.2"),
+ IpPrefix.valueOf("192.168.2.0/24"));
+ createPortAddressesAndInterface(CP2,
+ Sets.newHashSet(ia21, ia22),
+ MacAddress.valueOf("00:00:00:00:00:02"),
+ VlanId.vlanId((short) 4));
+
+ // Two addresses in different subnets
+ InterfaceIpAddress ia31 =
+ new InterfaceIpAddress(IpAddress.valueOf("192.168.3.1"),
+ IpPrefix.valueOf("192.168.3.0/24"));
+ InterfaceIpAddress ia41 =
+ new InterfaceIpAddress(IpAddress.valueOf("192.168.4.1"),
+ IpPrefix.valueOf("192.168.4.0/24"));
+ createPortAddressesAndInterface(CP3,
+ Sets.newHashSet(ia31, ia41),
+ MacAddress.valueOf("00:00:00:00:00:03"),
+ VlanId.NONE);
+
+ expect(hostService.getAddressBindings()).andReturn(portAddresses).anyTimes();
+
+ replay(hostService);
+
+ adaptor = new HostToInterfaceAdaptor(hostService);
+ }
+
+ /**
+ * Creates both a PortAddresses and an Interface for the given inputs and
+ * places them in the correct global data stores.
+ *
+ * @param cp the connect point
+ * @param ipAddresses the set of interface IP addresses
+ * @param mac the MAC address
+ * @param vlan the VLAN ID
+ */
+ private void createPortAddressesAndInterface(
+ ConnectPoint cp, Set<InterfaceIpAddress> ipAddresses,
+ MacAddress mac, VlanId vlan) {
+ PortAddresses pa = new PortAddresses(cp, ipAddresses, mac, vlan);
+ portAddresses.add(pa);
+ expect(hostService.getAddressBindingsForPort(cp)).andReturn(
+ Collections.singleton(pa)).anyTimes();
+
+ Interface intf = new Interface(cp, ipAddresses, mac, vlan);
+ interfaces.put(cp, intf);
+ }
+
+ /**
+ * Tests {@link HostToInterfaceAdaptor#getInterfaces()}.
+ * Verifies that the set of interfaces returned matches what is expected
+ * based on the input PortAddresses data.
+ */
+ @Test
+ public void testGetInterfaces() {
+ Set<Interface> adaptorIntfs = adaptor.getInterfaces();
+
+ assertEquals(3, adaptorIntfs.size());
+ assertTrue(adaptorIntfs.contains(this.interfaces.get(CP1)));
+ assertTrue(adaptorIntfs.contains(this.interfaces.get(CP2)));
+ assertTrue(adaptorIntfs.contains(this.interfaces.get(CP3)));
+ }
+
+ /**
+ * Tests {@link HostToInterfaceAdaptor#getInterface(ConnectPoint)}.
+ * Verifies that the correct interface is returned for a given connect
+ * point.
+ */
+ @Test
+ public void testGetInterface() {
+ assertEquals(this.interfaces.get(CP1), adaptor.getInterface(CP1));
+ assertEquals(this.interfaces.get(CP2), adaptor.getInterface(CP2));
+ assertEquals(this.interfaces.get(CP3), adaptor.getInterface(CP3));
+
+ // Try and get an interface for a connect point with no addresses
+ reset(hostService);
+ expect(hostService.getAddressBindingsForPort(NON_EXISTENT_CP))
+ .andReturn(Collections.<PortAddresses>emptySet()).anyTimes();
+ replay(hostService);
+
+ assertNull(adaptor.getInterface(NON_EXISTENT_CP));
+ }
+
+ /**
+ * Tests {@link HostToInterfaceAdaptor#getInterface(ConnectPoint)} in the
+ * case that the input connect point is null.
+ * Verifies that a NullPointerException is thrown.
+ */
+ @Test(expected = NullPointerException.class)
+ public void testGetInterfaceNull() {
+ ConnectPoint c = null;
+ adaptor.getInterface(c);
+ }
+
+ /**
+ * Tests {@link HostToInterfaceAdaptor#getMatchingInterface(IpAddress)}.
+ * Verifies that the correct interface is returned based on the given IP
+ * address.
+ */
+ @Test
+ public void testGetMatchingInterface() {
+ assertEquals(this.interfaces.get(CP1),
+ adaptor.getMatchingInterface(IpAddress.valueOf("192.168.1.100")));
+ assertEquals(this.interfaces.get(CP2),
+ adaptor.getMatchingInterface(IpAddress.valueOf("192.168.2.100")));
+ assertEquals(this.interfaces.get(CP3),
+ adaptor.getMatchingInterface(IpAddress.valueOf("192.168.3.100")));
+ assertEquals(this.interfaces.get(CP3),
+ adaptor.getMatchingInterface(IpAddress.valueOf("192.168.4.100")));
+
+ // Try and match an address we don't have subnet configured for
+ assertNull(adaptor.getMatchingInterface(IpAddress.valueOf("1.1.1.1")));
+ }
+
+ /**
+ * Tests {@link HostToInterfaceAdaptor#getMatchingInterface(IpAddress)} in the
+ * case that the input IP address is null.
+ * Verifies that a NullPointerException is thrown.
+ */
+ @Test(expected = NullPointerException.class)
+ public void testGetMatchingInterfaceNull() {
+ adaptor.getMatchingInterface(null);
+ }
+
+}
diff --git a/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/impl/RouterAsyncArpTest.java b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/impl/RouterAsyncArpTest.java
new file mode 100644
index 00000000..100c13d4
--- /dev/null
+++ b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/impl/RouterAsyncArpTest.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.routing.impl;
+
+import com.google.common.collect.Sets;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultHost;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.host.HostEvent;
+import org.onosproject.net.host.HostListener;
+import org.onosproject.net.host.HostService;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.routing.config.RoutingConfigurationService;
+import org.onosproject.routing.impl.Router.InternalHostListener;
+import org.onosproject.routing.BgpService;
+import org.onosproject.routing.FibEntry;
+import org.onosproject.routing.FibListener;
+import org.onosproject.routing.FibUpdate;
+import org.onosproject.routing.RouteEntry;
+import org.onosproject.routing.RouteListener;
+import org.onosproject.routing.RouteUpdate;
+
+import java.util.Collections;
+
+import static org.easymock.EasyMock.*;
+
+/**
+* This class tests adding a route and updating a route.
+* The HostService module answers the MAC address asynchronously.
+*/
+public class RouterAsyncArpTest {
+
+ private HostService hostService;
+ private FibListener fibListener;
+ private RoutingConfigurationService routingConfigurationService;
+
+ private static final ConnectPoint SW1_ETH1 = new ConnectPoint(
+ DeviceId.deviceId("of:0000000000000001"),
+ PortNumber.portNumber(1));
+
+ private static final ConnectPoint SW2_ETH1 = new ConnectPoint(
+ DeviceId.deviceId("of:0000000000000002"),
+ PortNumber.portNumber(1));
+
+ private static final ConnectPoint SW3_ETH1 = new ConnectPoint(
+ DeviceId.deviceId("of:0000000000000003"),
+ PortNumber.portNumber(1));
+
+ private Router router;
+ private InternalHostListener internalHostListener;
+
+ @Before
+ public void setUp() throws Exception {
+ hostService = createMock(HostService.class);
+ routingConfigurationService =
+ createMock(RoutingConfigurationService.class);
+
+ BgpService bgpService = createMock(BgpService.class);
+ bgpService.start(anyObject(RouteListener.class));
+ bgpService.stop();
+ replay(bgpService);
+
+ fibListener = createMock(FibListener.class);
+
+ router = new Router();
+ router.coreService = createNiceMock(CoreService.class);
+ router.hostService = hostService;
+ router.routingConfigurationService = routingConfigurationService;
+ router.bgpService = bgpService;
+ router.activate();
+
+ router.addFibListener(fibListener);
+ router.start();
+
+ internalHostListener = router.new InternalHostListener();
+ }
+
+ @After
+ public void tearDown() {
+ // Called during shutdown
+ reset(hostService);
+ hostService.removeListener(anyObject(HostListener.class));
+
+ router.stop();
+ }
+
+ /**
+ * Tests adding a route entry with asynchronous HostService replies.
+ */
+ @Test
+ public void testRouteAdd() {
+ // Construct a route entry
+ IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24");
+ IpAddress nextHopIp = Ip4Address.valueOf("192.168.10.1");
+
+ RouteEntry routeEntry = new RouteEntry(prefix, nextHopIp);
+
+ // Host service will reply with no hosts when asked
+ reset(hostService);
+ expect(hostService.getHostsByIp(anyObject(IpAddress.class))).andReturn(
+ Collections.emptySet()).anyTimes();
+ hostService.startMonitoringIp(IpAddress.valueOf("192.168.10.1"));
+ replay(hostService);
+
+ reset(routingConfigurationService);
+ expect(routingConfigurationService.isIpPrefixLocal(
+ anyObject(IpPrefix.class))).andReturn(false);
+ replay(routingConfigurationService);
+
+ // Initially when we add the route, no FIB update will be sent
+ replay(fibListener);
+
+ router.processRouteUpdates(Collections.singletonList(
+ new RouteUpdate(RouteUpdate.Type.UPDATE, routeEntry)));
+
+ verify(fibListener);
+
+
+ // Now when we send the event, we expect the FIB update to be sent
+ reset(fibListener);
+ FibEntry fibEntry = new FibEntry(prefix, nextHopIp,
+ MacAddress.valueOf("00:00:00:00:00:01"));
+
+ fibListener.update(Collections.singletonList(new FibUpdate(
+ FibUpdate.Type.UPDATE, fibEntry)), Collections.emptyList());
+ replay(fibListener);
+
+ Host host = new DefaultHost(ProviderId.NONE, HostId.NONE,
+ MacAddress.valueOf("00:00:00:00:00:01"), VlanId.NONE,
+ new HostLocation(
+ SW1_ETH1.deviceId(),
+ SW1_ETH1.port(), 1),
+ Sets.newHashSet(IpAddress.valueOf("192.168.10.1")));
+
+ // Send in the host event
+ internalHostListener.event(
+ new HostEvent(HostEvent.Type.HOST_ADDED, host));
+
+ verify(fibListener);
+ }
+
+ /**
+ * Tests updating a route entry with asynchronous HostService replies.
+ */
+ @Test
+ public void testRouteUpdate() {
+ // Add a route
+ testRouteAdd();
+
+ // Construct a route entry
+ IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24");
+ IpAddress nextHopIp = Ip4Address.valueOf("192.168.20.1");
+
+ RouteEntry routeEntry = new RouteEntry(prefix, nextHopIp);
+
+ // Host service will reply with no hosts when asked
+ reset(hostService);
+ expect(hostService.getHostsByIp(anyObject(IpAddress.class))).andReturn(
+ Collections.emptySet()).anyTimes();
+ hostService.startMonitoringIp(IpAddress.valueOf("192.168.20.1"));
+ replay(hostService);
+
+ reset(routingConfigurationService);
+ expect(routingConfigurationService.isIpPrefixLocal(
+ anyObject(IpPrefix.class))).andReturn(false);
+ replay(routingConfigurationService);
+
+ // Initially when we add the route, the DELETE FIB update will be sent
+ // but the UPDATE FIB update will come later when the MAC is resolved
+ reset(fibListener);
+
+ fibListener.update(Collections.emptyList(), Collections.singletonList(new FibUpdate(
+ FibUpdate.Type.DELETE, new FibEntry(prefix, null, null))));
+ replay(fibListener);
+
+ router.processRouteUpdates(Collections.singletonList(
+ new RouteUpdate(RouteUpdate.Type.UPDATE, routeEntry)));
+
+ verify(fibListener);
+
+
+ // Now when we send the event, we expect the FIB update to be sent
+ reset(fibListener);
+ FibEntry fibEntry = new FibEntry(prefix, nextHopIp,
+ MacAddress.valueOf("00:00:00:00:00:02"));
+
+ fibListener.update(Collections.singletonList(new FibUpdate(
+ FibUpdate.Type.UPDATE, fibEntry)), Collections.emptyList());
+ replay(fibListener);
+
+ Host host = new DefaultHost(ProviderId.NONE, HostId.NONE,
+ MacAddress.valueOf("00:00:00:00:00:02"), VlanId.NONE,
+ new HostLocation(
+ SW1_ETH1.deviceId(),
+ SW1_ETH1.port(), 1),
+ Sets.newHashSet(IpAddress.valueOf("192.168.20.1")));
+
+ // Send in the host event
+ internalHostListener.event(
+ new HostEvent(HostEvent.Type.HOST_ADDED, host));
+
+ verify(fibListener);
+ }
+}
diff --git a/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/impl/RouterTest.java b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/impl/RouterTest.java
new file mode 100644
index 00000000..45bc309f
--- /dev/null
+++ b/framework/src/onos/apps/routing/src/test/java/org/onosproject/routing/impl/RouterTest.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.routing.impl;
+
+import com.google.common.collect.Sets;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultHost;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.host.HostListener;
+import org.onosproject.net.host.HostService;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.routing.BgpService;
+import org.onosproject.routing.FibEntry;
+import org.onosproject.routing.FibListener;
+import org.onosproject.routing.FibUpdate;
+import org.onosproject.routing.RouteEntry;
+import org.onosproject.routing.RouteListener;
+import org.onosproject.routing.RouteUpdate;
+import org.onosproject.routing.config.RoutingConfigurationService;
+
+import java.util.Collections;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * This class tests adding a route, updating a route, deleting a route,
+ * and adding a route whose next hop is the local BGP speaker.
+ * <p/>
+ * The HostService answers requests synchronously.
+ */
+public class RouterTest {
+
+ private HostService hostService;
+ private RoutingConfigurationService routingConfigurationService;
+
+ private FibListener fibListener;
+
+ private static final ConnectPoint SW1_ETH1 = new ConnectPoint(
+ DeviceId.deviceId("of:0000000000000001"),
+ PortNumber.portNumber(1));
+
+ private static final ConnectPoint SW2_ETH1 = new ConnectPoint(
+ DeviceId.deviceId("of:0000000000000002"),
+ PortNumber.portNumber(1));
+
+ private static final ConnectPoint SW3_ETH1 = new ConnectPoint(
+ DeviceId.deviceId("of:0000000000000003"),
+ PortNumber.portNumber(1));
+
+ private static final ConnectPoint SW4_ETH1 = new ConnectPoint(
+ DeviceId.deviceId("of:0000000000000004"),
+ PortNumber.portNumber(1));
+
+ private Router router;
+
+ @Before
+ public void setUp() throws Exception {
+ setUpHostService();
+ routingConfigurationService =
+ createMock(RoutingConfigurationService.class);
+
+ BgpService bgpService = createMock(BgpService.class);
+ bgpService.start(anyObject(RouteListener.class));
+ bgpService.stop();
+ replay(bgpService);
+
+ fibListener = createMock(FibListener.class);
+
+ router = new Router();
+ router.coreService = createNiceMock(CoreService.class);
+ router.hostService = hostService;
+ router.routingConfigurationService = routingConfigurationService;
+ router.bgpService = bgpService;
+ router.activate();
+
+ router.addFibListener(fibListener);
+ router.start();
+ }
+
+ @After
+ public void tearDown() {
+ router.stop();
+ }
+
+ /**
+ * Sets up the host service with details of some hosts.
+ */
+ private void setUpHostService() {
+ hostService = createMock(HostService.class);
+
+ hostService.addListener(anyObject(HostListener.class));
+ expectLastCall().anyTimes();
+
+ IpAddress host1Address = IpAddress.valueOf("192.168.10.1");
+ Host host1 = new DefaultHost(ProviderId.NONE, HostId.NONE,
+ MacAddress.valueOf("00:00:00:00:00:01"), VlanId.NONE,
+ new HostLocation(SW1_ETH1, 1),
+ Sets.newHashSet(host1Address));
+
+ expect(hostService.getHostsByIp(host1Address))
+ .andReturn(Sets.newHashSet(host1)).anyTimes();
+ hostService.startMonitoringIp(host1Address);
+ expectLastCall().anyTimes();
+
+
+ IpAddress host2Address = IpAddress.valueOf("192.168.20.1");
+ Host host2 = new DefaultHost(ProviderId.NONE, HostId.NONE,
+ MacAddress.valueOf("00:00:00:00:00:02"), VlanId.NONE,
+ new HostLocation(SW2_ETH1, 1),
+ Sets.newHashSet(host2Address));
+
+ expect(hostService.getHostsByIp(host2Address))
+ .andReturn(Sets.newHashSet(host2)).anyTimes();
+ hostService.startMonitoringIp(host2Address);
+ expectLastCall().anyTimes();
+
+ // Next hop on a VLAN
+ IpAddress host3Address = IpAddress.valueOf("192.168.40.1");
+ Host host3 = new DefaultHost(ProviderId.NONE, HostId.NONE,
+ MacAddress.valueOf("00:00:00:00:00:03"), VlanId.vlanId((short) 1),
+ new HostLocation(SW4_ETH1, 1),
+ Sets.newHashSet(host3Address));
+
+ expect(hostService.getHostsByIp(host3Address))
+ .andReturn(Sets.newHashSet(host3)).anyTimes();
+ hostService.startMonitoringIp(host3Address);
+ expectLastCall().anyTimes();
+
+ // Called during shutdown
+ hostService.removeListener(anyObject(HostListener.class));
+
+ replay(hostService);
+ }
+
+ /**
+ * Tests adding a route entry.
+ */
+ @Test
+ public void testRouteAdd() {
+ // Construct a route entry
+ IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24");
+ IpAddress nextHopIp = Ip4Address.valueOf("192.168.10.1");
+
+ RouteEntry routeEntry = new RouteEntry(prefix, nextHopIp);
+
+ // Expected FIB entry
+ FibEntry fibEntry = new FibEntry(prefix, nextHopIp,
+ MacAddress.valueOf("00:00:00:00:00:01"));
+
+ fibListener.update(Collections.singletonList(new FibUpdate(
+ FibUpdate.Type.UPDATE, fibEntry)), Collections.emptyList());
+
+ replay(fibListener);
+
+ router.processRouteUpdates(Collections.singletonList(
+ new RouteUpdate(RouteUpdate.Type.UPDATE, routeEntry)));
+
+ verify(fibListener);
+ }
+
+ /**
+ * Tests updating a route entry.
+ */
+ @Test
+ public void testRouteUpdate() {
+ // Firstly add a route
+ testRouteAdd();
+
+ // Route entry with updated next hop for the original prefix
+ RouteEntry routeEntryUpdate = new RouteEntry(
+ Ip4Prefix.valueOf("1.1.1.0/24"),
+ Ip4Address.valueOf("192.168.20.1"));
+
+ // The old FIB entry will be withdrawn
+ FibEntry withdrawFibEntry = new FibEntry(
+ Ip4Prefix.valueOf("1.1.1.0/24"), null, null);
+
+ // A new FIB entry will be added
+ FibEntry updateFibEntry = new FibEntry(
+ Ip4Prefix.valueOf("1.1.1.0/24"),
+ Ip4Address.valueOf("192.168.20.1"),
+ MacAddress.valueOf("00:00:00:00:00:02"));
+
+ reset(fibListener);
+ fibListener.update(Collections.singletonList(new FibUpdate(
+ FibUpdate.Type.UPDATE, updateFibEntry)),
+ Collections.singletonList(new FibUpdate(
+ FibUpdate.Type.DELETE, withdrawFibEntry)));
+ replay(fibListener);
+
+ reset(routingConfigurationService);
+ expect(routingConfigurationService.isIpPrefixLocal(
+ anyObject(IpPrefix.class))).andReturn(false);
+ replay(routingConfigurationService);
+
+ router.processRouteUpdates(Collections.singletonList(new RouteUpdate(
+ RouteUpdate.Type.UPDATE, routeEntryUpdate)));
+
+ verify(fibListener);
+ }
+
+ /**
+ * Tests deleting a route entry.
+ */
+ @Test
+ public void testRouteDelete() {
+ // Firstly add a route
+ testRouteAdd();
+
+ RouteEntry deleteRouteEntry = new RouteEntry(
+ Ip4Prefix.valueOf("1.1.1.0/24"),
+ Ip4Address.valueOf("192.168.10.1"));
+
+ FibEntry deleteFibEntry = new FibEntry(
+ Ip4Prefix.valueOf("1.1.1.0/24"), null, null);
+
+ reset(fibListener);
+ fibListener.update(Collections.emptyList(), Collections.singletonList(
+ new FibUpdate(FibUpdate.Type.DELETE, deleteFibEntry)));
+
+ replay(fibListener);
+
+ router.processRouteUpdates(Collections.singletonList(
+ new RouteUpdate(RouteUpdate.Type.DELETE, deleteRouteEntry)));
+
+ verify(fibListener);
+ }
+
+ /**
+ * Tests adding a route whose next hop is the local BGP speaker.
+ */
+ @Test
+ public void testLocalRouteAdd() {
+ // Construct a route entry, the next hop is the local BGP speaker
+ RouteEntry routeEntry = new RouteEntry(
+ Ip4Prefix.valueOf("1.1.1.0/24"),
+ Ip4Address.valueOf("0.0.0.0"));
+
+ // No methods on the FIB listener should be called
+ replay(fibListener);
+
+ reset(routingConfigurationService);
+ expect(routingConfigurationService.isIpPrefixLocal(
+ anyObject(IpPrefix.class))).andReturn(true);
+ replay(routingConfigurationService);
+
+ // Call the processRouteUpdates() method in Router class
+ RouteUpdate routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
+ routeEntry);
+ router.processRouteUpdates(Collections.singletonList(routeUpdate));
+
+ // Verify
+ assertEquals(1, router.getRoutes4().size());
+ assertTrue(router.getRoutes4().contains(routeEntry));
+ verify(fibListener);
+ }
+}