Ignore more than two next hops
Change-Id: Ie42365a3a8b9e7f763c21e3f9be9e9abfc35dbf7
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RouteHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RouteHandler.java
index 4b95bf3..6d77da4 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RouteHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RouteHandler.java
@@ -111,6 +111,11 @@
log.info("processRouteAddedInternal. routes={}", routes);
+ if (routes.size() > 2) {
+ log.info("Route {} has more than two next hops. Do not process route change", routes);
+ return;
+ }
+
Set<ConnectPoint> allLocations = Sets.newHashSet();
Set<IpPrefix> allPrefixes = Sets.newHashSet();
routes.forEach(route -> {
@@ -152,12 +157,26 @@
log.info("processRouteUpdatedInternal. routes={}, oldRoutes={}", routes, oldRoutes);
+ if (routes.size() > 2) {
+ log.info("Route {} has more than two next hops. Do not process route change", routes);
+ return;
+ }
+
Set<ConnectPoint> allLocations = Sets.newHashSet();
Set<IpPrefix> allPrefixes = Sets.newHashSet();
routes.forEach(route -> {
allLocations.addAll(srManager.nextHopLocations(route));
allPrefixes.add(route.prefix());
});
+
+ // Just come back from an invalid next hop count
+ // Revoke subnet from all locations and reset oldRoutes such that system will be reprogrammed from scratch
+ if (oldRoutes.size() > 2) {
+ log.info("Revoke subnet {} and reset oldRoutes");
+ srManager.defaultRoutingHandler.revokeSubnet(allPrefixes);
+ oldRoutes = Sets.newHashSet();
+ }
+
log.debug("RouteUpdated. populateSubnet {}, {}", allLocations, allPrefixes);
srManager.defaultRoutingHandler.populateSubnet(allLocations, allPrefixes);
diff --git a/apps/segmentrouting/app/src/test/java/org/onosproject/segmentrouting/RouteHandlerTest.java b/apps/segmentrouting/app/src/test/java/org/onosproject/segmentrouting/RouteHandlerTest.java
index a7388d1..ef4c2aa 100644
--- a/apps/segmentrouting/app/src/test/java/org/onosproject/segmentrouting/RouteHandlerTest.java
+++ b/apps/segmentrouting/app/src/test/java/org/onosproject/segmentrouting/RouteHandlerTest.java
@@ -101,6 +101,14 @@
private static final Route R3 = new Route(Route.Source.STATIC, P1, N3);
private static final ResolvedRoute RR3 = new ResolvedRoute(R3, M3, V3);
+ // Single homed router 3
+ private static final IpAddress N4 = IpAddress.valueOf("10.0.4.254");
+ private static final MacAddress M4 = MacAddress.valueOf("00:00:00:00:00:04");
+ private static final VlanId V4 = VlanId.vlanId((short) 4);
+ private static final ConnectPoint CP4 = ConnectPoint.deviceConnectPoint("of:0000000000000004/4");
+ private static final Route R4 = new Route(Route.Source.STATIC, P1, N4);
+ private static final ResolvedRoute RR4 = new ResolvedRoute(R4, M4, V4);
+
// Hosts
private static final Host H1 = new DefaultHost(ProviderId.NONE, HostId.hostId(M1, V1), M1, V1,
Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N1), false);
@@ -110,12 +118,14 @@
Sets.newHashSet(new HostLocation(CP1, 0), new HostLocation(CP2, 0)), Sets.newHashSet(N3), false);
private static final Host H3S = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N3), false);
+ private static final Host H4 = new DefaultHost(ProviderId.NONE, HostId.hostId(M4, V4), M4, V4,
+ Sets.newHashSet(new HostLocation(CP4, 0)), Sets.newHashSet(N4), false);
// Pair Local Port
private static final PortNumber P9 = PortNumber.portNumber(9);
// A set of hosts
- private static final Set<Host> HOSTS = Sets.newHashSet(H1, H2, H3D);
+ private static final Set<Host> HOSTS = Sets.newHashSet(H1, H2, H3D, H4);
private static final Set<Host> HOSTS_ONE_FAIL = Sets.newHashSet(H1, H2, H3S);
private static final Set<Host> HOSTS_BOTH_FAIL = Sets.newHashSet(H1, H2);
// A set of devices of which we have mastership
@@ -124,7 +134,7 @@
private static final Set<Interface> INTERFACES = Sets.newHashSet();
@Before
- public void setUp() throws Exception {
+ public void setUp() {
ObjectMapper mapper = new ObjectMapper();
ConfigApplyDelegate delegate = config -> { };
@@ -173,7 +183,7 @@
}
@Test
- public void init() throws Exception {
+ public void init() {
MockRoutingTableKey rtk = new MockRoutingTableKey(CP1.deviceId(), P1);
MockRoutingTableValue rtv = new MockRoutingTableValue(CP1.port(), M1, V1);
ROUTING_TABLE.put(rtk, rtv);
@@ -191,7 +201,7 @@
}
@Test
- public void processRouteAdded() throws Exception {
+ public void processRouteAdded() {
reset(srManager.deviceConfiguration);
srManager.deviceConfiguration.addSubnet(CP1, P1);
expectLastCall().once();
@@ -213,7 +223,7 @@
}
@Test
- public void processRouteUpdated() throws Exception {
+ public void processRouteUpdated() {
processRouteAdded();
reset(srManager.deviceConfiguration);
@@ -242,7 +252,7 @@
}
@Test
- public void processRouteRemoved() throws Exception {
+ public void processRouteRemoved() {
processRouteAdded();
reset(srManager.deviceConfiguration);
@@ -260,7 +270,7 @@
}
@Test
- public void testTwoSingleHomedAdded() throws Exception {
+ public void testTwoSingleHomedAdded() {
reset(srManager.deviceConfiguration);
srManager.deviceConfiguration.addSubnet(CP1, P1);
expectLastCall().once();
@@ -289,7 +299,7 @@
}
@Test
- public void testOneDualHomedAdded() throws Exception {
+ public void testOneDualHomedAdded() {
reset(srManager.deviceConfiguration);
srManager.deviceConfiguration.addSubnet(CP1, P1);
expectLastCall().once();
@@ -318,7 +328,7 @@
}
@Test
- public void testOneSingleHomedToTwoSingleHomed() throws Exception {
+ public void testOneSingleHomedToTwoSingleHomed() {
processRouteAdded();
reset(srManager.deviceConfiguration);
@@ -348,7 +358,7 @@
}
@Test
- public void testTwoSingleHomedToOneSingleHomed() throws Exception {
+ public void testTwoSingleHomedToOneSingleHomed() {
testTwoSingleHomedAdded();
reset(srManager.deviceConfiguration);
@@ -377,7 +387,7 @@
// TODO Add test cases for two single homed next hop at same location
@Test
- public void testDualHomedSingleLocationFail() throws Exception {
+ public void testDualHomedSingleLocationFail() {
testOneDualHomedAdded();
HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3S, H3D);
@@ -400,7 +410,7 @@
}
@Test
- public void testDualHomedBothLocationFail() throws Exception {
+ public void testDualHomedBothLocationFail() {
testDualHomedSingleLocationFail();
hostService = new MockHostService(HOSTS_ONE_FAIL);
@@ -422,7 +432,7 @@
}
@Test
- public void testTwoSingleHomedRemoved() throws Exception {
+ public void testTwoSingleHomedRemoved() {
testTwoSingleHomedAdded();
hostService = new MockHostService(HOSTS_BOTH_FAIL);
@@ -444,7 +454,7 @@
}
@Test
- public void testOneDualHomeRemoved() throws Exception {
+ public void testOneDualHomeRemoved() {
testOneDualHomedAdded();
reset(srManager.deviceConfiguration);
@@ -462,4 +472,79 @@
verify(srManager.deviceConfiguration);
}
+
+ @Test
+ public void testMoreThanTwoNextHop() {
+ // next hop = CP1, CP2
+ reset(srManager.deviceConfiguration);
+ srManager.deviceConfiguration.addSubnet(CP1, P1);
+ srManager.deviceConfiguration.addSubnet(CP2, P1);
+ expectLastCall().once();
+ replay(srManager.deviceConfiguration);
+
+ RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
+ routeHandler.processRouteAdded(re);
+
+ assertEquals(2, ROUTING_TABLE.size());
+ MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
+ assertEquals(M1, rtv1.macAddress);
+ assertEquals(V1, rtv1.vlanId);
+ assertEquals(CP1.port(), rtv1.portNumber);
+ MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
+ assertEquals(M2, rtv2.macAddress);
+ assertEquals(V2, rtv2.vlanId);
+ assertEquals(CP2.port(), rtv2.portNumber);
+
+ assertEquals(2, SUBNET_TABLE.size());
+ assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
+ assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
+
+ verify(srManager.deviceConfiguration);
+
+ // next hop = CP1, CP2, CP4 (invalid)
+ re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
+ Sets.newHashSet(RR1, RR2, RR4), Sets.newHashSet(RR1, RR2));
+ routeHandler.processAlternativeRoutesChanged(re);
+
+ assertEquals(2, ROUTING_TABLE.size());
+ rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
+ assertEquals(M1, rtv1.macAddress);
+ assertEquals(V1, rtv1.vlanId);
+ assertEquals(CP1.port(), rtv1.portNumber);
+ rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
+ assertEquals(M2, rtv2.macAddress);
+ assertEquals(V2, rtv2.vlanId);
+ assertEquals(CP2.port(), rtv2.portNumber);
+
+ assertEquals(2, SUBNET_TABLE.size());
+ assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
+ assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
+
+ // next hop = CP2, CP4
+ reset(srManager.deviceConfiguration);
+ srManager.deviceConfiguration.addSubnet(CP2, P1);
+ srManager.deviceConfiguration.addSubnet(CP4, P1);
+ expectLastCall().once();
+ replay(srManager.deviceConfiguration);
+
+ re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
+ Sets.newHashSet(RR2, RR4), Sets.newHashSet(RR1, RR2, RR4));
+ routeHandler.processAlternativeRoutesChanged(re);
+
+ assertEquals(2, ROUTING_TABLE.size());
+ rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
+ assertEquals(M2, rtv1.macAddress);
+ assertEquals(V2, rtv1.vlanId);
+ assertEquals(CP2.port(), rtv1.portNumber);
+ rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP4.deviceId(), P1));
+ assertEquals(M4, rtv2.macAddress);
+ assertEquals(V4, rtv2.vlanId);
+ assertEquals(CP4.port(), rtv2.portNumber);
+
+ assertEquals(2, SUBNET_TABLE.size());
+ assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
+ assertTrue(SUBNET_TABLE.get(CP4).contains(P1));
+
+ verify(srManager.deviceConfiguration);
+ }
}
\ No newline at end of file