Correctly initialize routes with multiple next hops
- Solve an issue where next hops are available on both leaf switch but one still pointing to its pair through the spines
- Improve unit tests
Change-Id: I94fe79bd9289efe544d82b858928d65201a0b0b2
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 6d77da4..b278b8c 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
@@ -83,26 +83,24 @@
}
protected void init(DeviceId deviceId) {
- srManager.routeService.getRouteTables().forEach(routeTableId ->
- srManager.routeService.getRoutes(routeTableId).forEach(routeInfo ->
- routeInfo.allRoutes().forEach(resolvedRoute ->
- srManager.nextHopLocations(resolvedRoute).stream()
- .filter(location -> deviceId.equals(location.deviceId()))
- .forEach(location -> processRouteAddedInternal(resolvedRoute)
- )
- )
- )
- );
+ Optional<DeviceId> pairDeviceId = srManager.getPairDeviceId(deviceId);
+
+ srManager.routeService.getRouteTables().stream()
+ .map(srManager.routeService::getRoutes)
+ .flatMap(Collection::stream)
+ .map(RouteInfo::allRoutes)
+ .filter(allRoutes -> allRoutes.stream().allMatch(resolvedRoute ->
+ srManager.nextHopLocations(resolvedRoute).stream().allMatch(cp ->
+ deviceId.equals(cp.deviceId()) ||
+ (pairDeviceId.isPresent() && pairDeviceId.get().equals(cp.deviceId()))
+ )))
+ .forEach(this::processRouteAddedInternal);
}
void processRouteAdded(RouteEvent event) {
enqueueRouteEvent(event);
}
- private void processRouteAddedInternal(ResolvedRoute route) {
- processRouteAddedInternal(Sets.newHashSet(route));
- }
-
private void processRouteAddedInternal(Collection<ResolvedRoute> routes) {
if (!isReady()) {
log.info("System is not ready. Skip adding route for {}", routes);
diff --git a/apps/segmentrouting/app/src/test/java/org/onosproject/segmentrouting/MockRouteService.java b/apps/segmentrouting/app/src/test/java/org/onosproject/segmentrouting/MockRouteService.java
index 7927636..bfeca1f 100644
--- a/apps/segmentrouting/app/src/test/java/org/onosproject/segmentrouting/MockRouteService.java
+++ b/apps/segmentrouting/app/src/test/java/org/onosproject/segmentrouting/MockRouteService.java
@@ -17,18 +17,15 @@
package org.onosproject.segmentrouting;
import com.google.common.collect.Sets;
-import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
import org.onosproject.routeservice.ResolvedRoute;
-import org.onosproject.routeservice.Route;
import org.onosproject.routeservice.RouteInfo;
import org.onosproject.routeservice.RouteServiceAdapter;
import org.onosproject.routeservice.RouteTableId;
import java.util.Collection;
import java.util.Map;
+import java.util.Set;
import java.util.stream.Collectors;
/**
@@ -36,23 +33,19 @@
* We assume there is only one routing table named "default".
*/
public class MockRouteService extends RouteServiceAdapter {
- private Map<MockRoutingTableKey, MockRoutingTableValue> routingTable;
+ private Map<IpPrefix, Set<ResolvedRoute>> routeStore;
- MockRouteService(Map<MockRoutingTableKey, MockRoutingTableValue> routingTable) {
- this.routingTable = routingTable;
+ MockRouteService(Map<IpPrefix, Set<ResolvedRoute>> routeStore) {
+ this.routeStore = routeStore;
}
@Override
public Collection<RouteInfo> getRoutes(RouteTableId id) {
- return routingTable.entrySet().stream().map(e -> {
- IpPrefix prefix = e.getKey().ipPrefix;
- IpAddress nextHop = IpAddress.valueOf(0); // dummy
- MacAddress mac = e.getValue().macAddress;
- VlanId vlan = e.getValue().vlanId;
- Route route = new Route(Route.Source.STATIC, prefix, nextHop);
- ResolvedRoute rr = new ResolvedRoute(route, mac, vlan);
-
- return new RouteInfo(prefix, rr, Sets.newHashSet(rr));
+ return routeStore.entrySet().stream().map(e -> {
+ IpPrefix prefix = e.getKey();
+ Set<ResolvedRoute> resolvedRoutes = e.getValue();
+ ResolvedRoute bestRoute = resolvedRoutes.stream().findFirst().orElse(null);
+ return new RouteInfo(prefix, bestRoute, resolvedRoutes);
}).collect(Collectors.toSet());
}
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 ef4c2aa..bdf056e 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
@@ -75,6 +75,7 @@
private static final Map<ConnectPoint, Set<IpPrefix>> SUBNET_TABLE = Maps.newConcurrentMap();
// Mocked Next Id
private static final Map<Integer, TrafficTreatment> NEXT_TABLE = Maps.newConcurrentMap();
+ private static final Map<IpPrefix, Set<ResolvedRoute>> ROUTE_STORE = Maps.newConcurrentMap();
private static final IpPrefix P1 = IpPrefix.valueOf("10.0.0.0/24");
@@ -167,7 +168,7 @@
hostService = new MockHostService(HOSTS);
srManager.hostService = hostService;
srManager.cfgService = mockNetworkConfigRegistry;
- srManager.routeService = new MockRouteService(ROUTING_TABLE);
+ srManager.routeService = new MockRouteService(ROUTE_STORE);
routeHandler = new RouteHandler(srManager) {
// routeEventCache is not necessary for unit tests
@@ -184,9 +185,7 @@
@Test
public void init() {
- MockRoutingTableKey rtk = new MockRoutingTableKey(CP1.deviceId(), P1);
- MockRoutingTableValue rtv = new MockRoutingTableValue(CP1.port(), M1, V1);
- ROUTING_TABLE.put(rtk, rtv);
+ ROUTE_STORE.put(P1, Sets.newHashSet(RR1));
routeHandler.init(CP1.deviceId());
@@ -201,6 +200,27 @@
}
@Test
+ public void initTwoNextHops() {
+ ROUTE_STORE.put(P1, Sets.newHashSet(RR1, RR2));
+
+ routeHandler.init(CP1.deviceId());
+
+ 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));
+ }
+
+ @Test
public void processRouteAdded() {
reset(srManager.deviceConfiguration);
srManager.deviceConfiguration.addSubnet(CP1, P1);
@@ -390,6 +410,8 @@
public void testDualHomedSingleLocationFail() {
testOneDualHomedAdded();
+ ROUTE_STORE.put(P1, Sets.newHashSet(RR3));
+
HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3S, H3D);
routeHandler.processHostMovedEvent(he);