blob: f2a439b8789be011e81bdaa792b9e548a1f27ed9 [file] [log] [blame]
Charles Chan6c624992017-08-18 17:11:34 -07001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.segmentrouting;
18
Charles Chan910be6a2017-08-23 14:46:43 -070019import com.fasterxml.jackson.databind.JsonNode;
20import com.fasterxml.jackson.databind.ObjectMapper;
Charles Chan5eec3b12019-04-18 14:30:41 -070021import com.google.common.collect.Lists;
Charles Chan6c624992017-08-18 17:11:34 -070022import com.google.common.collect.Maps;
23import com.google.common.collect.Sets;
24import org.junit.Before;
25import org.junit.Test;
26import org.onlab.packet.IpAddress;
27import org.onlab.packet.IpPrefix;
28import org.onlab.packet.MacAddress;
29import org.onlab.packet.VlanId;
Charles Chan910be6a2017-08-23 14:46:43 -070030import org.onosproject.net.config.ConfigApplyDelegate;
Charles Chan6c624992017-08-18 17:11:34 -070031import org.onosproject.net.ConnectPoint;
Charles Chanf0ae41e2017-08-23 13:55:39 -070032import org.onosproject.net.DefaultHost;
Charles Chan6c624992017-08-18 17:11:34 -070033import org.onosproject.net.DeviceId;
34import org.onosproject.net.Host;
Charles Chanf0ae41e2017-08-23 13:55:39 -070035import org.onosproject.net.HostId;
36import org.onosproject.net.HostLocation;
Charles Chan910be6a2017-08-23 14:46:43 -070037import org.onosproject.net.PortNumber;
Charles Chan6c624992017-08-18 17:11:34 -070038import org.onosproject.net.config.NetworkConfigRegistryAdapter;
39import org.onosproject.net.flow.TrafficTreatment;
Charles Chan910be6a2017-08-23 14:46:43 -070040import org.onosproject.net.host.HostEvent;
41import org.onosproject.net.host.HostService;
Charles Chan12a8a842020-02-14 13:23:57 -080042import org.onosproject.net.host.InterfaceIpAddress;
Charles Chan6c624992017-08-18 17:11:34 -070043import org.onosproject.net.intf.Interface;
Charles Chanf0ae41e2017-08-23 13:55:39 -070044import org.onosproject.net.provider.ProviderId;
Charles Chan6c624992017-08-18 17:11:34 -070045import org.onosproject.routeservice.ResolvedRoute;
46import org.onosproject.routeservice.Route;
47import org.onosproject.routeservice.RouteEvent;
Charles Chan6c624992017-08-18 17:11:34 -070048import org.onosproject.segmentrouting.config.DeviceConfiguration;
Charles Chan910be6a2017-08-23 14:46:43 -070049import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
Charles Chan12a8a842020-02-14 13:23:57 -080050import org.onosproject.segmentrouting.phasedrecovery.api.PhasedRecoveryService;
Charles Chand66d6712018-03-29 16:03:41 -070051import org.onosproject.store.service.StorageService;
52import org.onosproject.store.service.TestConsistentMap;
pierf331a492020-01-07 15:39:39 +010053import org.onosproject.store.service.TestConsistentMultimap;
Charles Chan6c624992017-08-18 17:11:34 -070054
55import java.util.Map;
56import java.util.Set;
57
Charles Chand66d6712018-03-29 16:03:41 -070058import static org.easymock.EasyMock.expect;
Charles Chan06f626c2018-02-05 17:20:05 -080059import static org.easymock.EasyMock.reset;
Charles Chan6c624992017-08-18 17:11:34 -070060import static org.junit.Assert.*;
Charles Chan06f626c2018-02-05 17:20:05 -080061import static org.easymock.EasyMock.createMock;
62import static org.easymock.EasyMock.expectLastCall;
63import static org.easymock.EasyMock.replay;
64import static org.easymock.EasyMock.verify;
Charles Chan6c624992017-08-18 17:11:34 -070065
66/**
67 * Unit test for {@link RouteHandler}.
68 */
69public class RouteHandlerTest {
Charles Chan06f626c2018-02-05 17:20:05 -080070 private SegmentRoutingManager srManager;
Charles Chan6c624992017-08-18 17:11:34 -070071 private RouteHandler routeHandler;
Charles Chan910be6a2017-08-23 14:46:43 -070072 private HostService hostService;
Charles Chan6c624992017-08-18 17:11:34 -070073
74 // Mocked routing and bridging tables
75 private static final Map<MockBridgingTableKey, MockBridgingTableValue> BRIDGING_TABLE =
76 Maps.newConcurrentMap();
77 private static final Map<MockRoutingTableKey, MockRoutingTableValue> ROUTING_TABLE =
78 Maps.newConcurrentMap();
79 private static final Map<ConnectPoint, Set<IpPrefix>> SUBNET_TABLE = Maps.newConcurrentMap();
80 // Mocked Next Id
81 private static final Map<Integer, TrafficTreatment> NEXT_TABLE = Maps.newConcurrentMap();
Charles Chan7d20a4e2018-04-13 14:01:49 -040082 private static final Map<IpPrefix, Set<ResolvedRoute>> ROUTE_STORE = Maps.newConcurrentMap();
Charles Chan6c624992017-08-18 17:11:34 -070083
84 private static final IpPrefix P1 = IpPrefix.valueOf("10.0.0.0/24");
Charles Chan910be6a2017-08-23 14:46:43 -070085
86 // Single homed router 1
Charles Chan12a8a842020-02-14 13:23:57 -080087 private static final IpAddress N1 = IpAddress.valueOf("10.0.1.1");
Charles Chan6c624992017-08-18 17:11:34 -070088 private static final MacAddress M1 = MacAddress.valueOf("00:00:00:00:00:01");
89 private static final VlanId V1 = VlanId.vlanId((short) 1);
90 private static final ConnectPoint CP1 = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
91 private static final Route R1 = new Route(Route.Source.STATIC, P1, N1);
Charles Chanf0ae41e2017-08-23 13:55:39 -070092 private static final ResolvedRoute RR1 = new ResolvedRoute(R1, M1, V1);
Charles Chan12a8a842020-02-14 13:23:57 -080093 private static final Route DHCP_R1 = new Route(Route.Source.DHCP, P1, N1);
94 private static final ResolvedRoute DHCP_RR1 = new ResolvedRoute(DHCP_R1, M1, V1);
Charles Chan6c624992017-08-18 17:11:34 -070095
Charles Chan910be6a2017-08-23 14:46:43 -070096 // Single homed router 2
Charles Chan12a8a842020-02-14 13:23:57 -080097 private static final IpAddress N2 = IpAddress.valueOf("10.0.2.1");
Charles Chan6c624992017-08-18 17:11:34 -070098 private static final MacAddress M2 = MacAddress.valueOf("00:00:00:00:00:02");
99 private static final VlanId V2 = VlanId.vlanId((short) 2);
Charles Chan910be6a2017-08-23 14:46:43 -0700100 private static final ConnectPoint CP2 = ConnectPoint.deviceConnectPoint("of:0000000000000002/2");
Charles Chan6c624992017-08-18 17:11:34 -0700101 private static final Route R2 = new Route(Route.Source.STATIC, P1, N2);
Charles Chanf0ae41e2017-08-23 13:55:39 -0700102 private static final ResolvedRoute RR2 = new ResolvedRoute(R2, M2, V2);
Charles Chan6c624992017-08-18 17:11:34 -0700103
Charles Chan910be6a2017-08-23 14:46:43 -0700104 // Dual homed router 1
Charles Chan12a8a842020-02-14 13:23:57 -0800105 private static final IpAddress N3 = IpAddress.valueOf("10.0.3.1");
Charles Chan910be6a2017-08-23 14:46:43 -0700106 private static final MacAddress M3 = MacAddress.valueOf("00:00:00:00:00:03");
107 private static final VlanId V3 = VlanId.vlanId((short) 3);
108 private static final Route R3 = new Route(Route.Source.STATIC, P1, N3);
109 private static final ResolvedRoute RR3 = new ResolvedRoute(R3, M3, V3);
Charles Chan12a8a842020-02-14 13:23:57 -0800110 private static final Route DHCP_R3 = new Route(Route.Source.DHCP, P1, N3);
111 private static final ResolvedRoute DHCP_RR3 = new ResolvedRoute(DHCP_R3, M3, V3);
Charles Chan6c624992017-08-18 17:11:34 -0700112
Charles Chan482b6422018-04-09 11:52:08 -0400113 // Single homed router 3
Charles Chan12a8a842020-02-14 13:23:57 -0800114 private static final IpAddress N4 = IpAddress.valueOf("10.0.4.1");
Charles Chan482b6422018-04-09 11:52:08 -0400115 private static final MacAddress M4 = MacAddress.valueOf("00:00:00:00:00:04");
116 private static final VlanId V4 = VlanId.vlanId((short) 4);
117 private static final ConnectPoint CP4 = ConnectPoint.deviceConnectPoint("of:0000000000000004/4");
118 private static final Route R4 = new Route(Route.Source.STATIC, P1, N4);
119 private static final ResolvedRoute RR4 = new ResolvedRoute(R4, M4, V4);
120
Charles Chan910be6a2017-08-23 14:46:43 -0700121 // Hosts
Charles Chanf0ae41e2017-08-23 13:55:39 -0700122 private static final Host H1 = new DefaultHost(ProviderId.NONE, HostId.hostId(M1, V1), M1, V1,
123 Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N1), false);
124 private static final Host H2 = new DefaultHost(ProviderId.NONE, HostId.hostId(M2, V2), M2, V2,
125 Sets.newHashSet(new HostLocation(CP2, 0)), Sets.newHashSet(N2), false);
Charles Chan910be6a2017-08-23 14:46:43 -0700126 private static final Host H3D = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
127 Sets.newHashSet(new HostLocation(CP1, 0), new HostLocation(CP2, 0)), Sets.newHashSet(N3), false);
128 private static final Host H3S = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
129 Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N3), false);
Charles Chan482b6422018-04-09 11:52:08 -0400130 private static final Host H4 = new DefaultHost(ProviderId.NONE, HostId.hostId(M4, V4), M4, V4,
131 Sets.newHashSet(new HostLocation(CP4, 0)), Sets.newHashSet(N4), false);
Charles Chan910be6a2017-08-23 14:46:43 -0700132
133 // Pair Local Port
134 private static final PortNumber P9 = PortNumber.portNumber(9);
Charles Chanf0ae41e2017-08-23 13:55:39 -0700135
Charles Chan6c624992017-08-18 17:11:34 -0700136 // A set of hosts
Charles Chan482b6422018-04-09 11:52:08 -0400137 private static final Set<Host> HOSTS = Sets.newHashSet(H1, H2, H3D, H4);
Charles Chan910be6a2017-08-23 14:46:43 -0700138 private static final Set<Host> HOSTS_ONE_FAIL = Sets.newHashSet(H1, H2, H3S);
139 private static final Set<Host> HOSTS_BOTH_FAIL = Sets.newHashSet(H1, H2);
Charles Chan6c624992017-08-18 17:11:34 -0700140 // A set of devices of which we have mastership
Charles Chan910be6a2017-08-23 14:46:43 -0700141 private static final Set<DeviceId> LOCAL_DEVICES = Sets.newHashSet(CP1.deviceId(), CP2.deviceId());
Charles Chan6c624992017-08-18 17:11:34 -0700142 // A set of interfaces
Charles Chan12a8a842020-02-14 13:23:57 -0800143 private static final InterfaceIpAddress IF_IP1 =
144 new InterfaceIpAddress(IpAddress.valueOf("10.0.1.254"), IpPrefix.valueOf("10.0.1.254/24"));
145 private static final InterfaceIpAddress IF_IP3 =
146 new InterfaceIpAddress(IpAddress.valueOf("10.0.3.254"), IpPrefix.valueOf("10.0.3.254/24"));
147 private static final Interface IF_CP1 = new Interface("if-cp1", CP1, Lists.newArrayList(IF_IP1, IF_IP3),
148 null, null, null, null, null);
149 private static final Interface IF_CP2 = new Interface("if-cp2", CP2, Lists.newArrayList(IF_IP1, IF_IP3),
150 null, null, null, null, null);
151 private static final Set<Interface> INTERFACES = Sets.newHashSet(IF_CP1, IF_CP2);
Charles Chan6c624992017-08-18 17:11:34 -0700152
153 @Before
Charles Chan482b6422018-04-09 11:52:08 -0400154 public void setUp() {
Charles Chan910be6a2017-08-23 14:46:43 -0700155 ObjectMapper mapper = new ObjectMapper();
156 ConfigApplyDelegate delegate = config -> { };
157
158 SegmentRoutingDeviceConfig dev1Config = new SegmentRoutingDeviceConfig();
159 JsonNode dev1Tree = mapper.createObjectNode();
160 dev1Config.init(CP1.deviceId(), "host-handler-test", dev1Tree, mapper, delegate);
161 dev1Config.setPairDeviceId(CP2.deviceId()).setPairLocalPort(P9);
162
163 SegmentRoutingDeviceConfig dev2Config = new SegmentRoutingDeviceConfig();
164 JsonNode dev2Tree = mapper.createObjectNode();
165 dev2Config.init(CP2.deviceId(), "host-handler-test", dev2Tree, mapper, delegate);
166 dev2Config.setPairDeviceId(CP1.deviceId()).setPairLocalPort(P9);
Charles Chan6c624992017-08-18 17:11:34 -0700167
168 MockNetworkConfigRegistry mockNetworkConfigRegistry = new MockNetworkConfigRegistry();
Charles Chan910be6a2017-08-23 14:46:43 -0700169 mockNetworkConfigRegistry.applyConfig(dev1Config);
170 mockNetworkConfigRegistry.applyConfig(dev2Config);
Charles Chan6c624992017-08-18 17:11:34 -0700171
172 // Initialize Segment Routing Manager
Charles Chan06f626c2018-02-05 17:20:05 -0800173 srManager = new MockSegmentRoutingManager(NEXT_TABLE);
Charles Chand66d6712018-03-29 16:03:41 -0700174 srManager.storageService = createMock(StorageService.class);
175 expect(srManager.storageService.consistentMapBuilder()).andReturn(new TestConsistentMap.Builder<>()).anyTimes();
pierf331a492020-01-07 15:39:39 +0100176 expect(srManager.storageService.consistentMultimapBuilder()).andReturn(
177 new TestConsistentMultimap.Builder<>()).anyTimes();
Charles Chand66d6712018-03-29 16:03:41 -0700178 replay(srManager.storageService);
Charles Chan6c624992017-08-18 17:11:34 -0700179 srManager.cfgService = new NetworkConfigRegistryAdapter();
Charles Chan06f626c2018-02-05 17:20:05 -0800180 srManager.deviceConfiguration = createMock(DeviceConfiguration.class);
Charles Chan6c624992017-08-18 17:11:34 -0700181 srManager.flowObjectiveService = new MockFlowObjectiveService(BRIDGING_TABLE, NEXT_TABLE);
182 srManager.routingRulePopulator = new MockRoutingRulePopulator(srManager, ROUTING_TABLE);
Charles Chanc4d68882018-03-15 16:41:10 -0700183 srManager.defaultRoutingHandler = new MockDefaultRoutingHandler(srManager, SUBNET_TABLE, ROUTING_TABLE);
Charles Chan6c624992017-08-18 17:11:34 -0700184 srManager.interfaceService = new MockInterfaceService(INTERFACES);
185 srManager.mastershipService = new MockMastershipService(LOCAL_DEVICES);
Charles Chan910be6a2017-08-23 14:46:43 -0700186 hostService = new MockHostService(HOSTS);
187 srManager.hostService = hostService;
Charles Chan6c624992017-08-18 17:11:34 -0700188 srManager.cfgService = mockNetworkConfigRegistry;
Charles Chan7d20a4e2018-04-13 14:01:49 -0400189 srManager.routeService = new MockRouteService(ROUTE_STORE);
Charles Chan12a8a842020-02-14 13:23:57 -0800190 srManager.phasedRecoveryService = createMock(PhasedRecoveryService.class);
191 expect(srManager.phasedRecoveryService.isEnabled()).andReturn(true).anyTimes();
192 replay(srManager.phasedRecoveryService);
Charles Chan6c624992017-08-18 17:11:34 -0700193
Charles Chanfbcb8812018-04-18 18:41:05 -0700194 routeHandler = new RouteHandler(srManager);
Charles Chan6c624992017-08-18 17:11:34 -0700195
196 ROUTING_TABLE.clear();
197 BRIDGING_TABLE.clear();
198 SUBNET_TABLE.clear();
199 }
200
201 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400202 public void init() {
Charles Chan7d20a4e2018-04-13 14:01:49 -0400203 ROUTE_STORE.put(P1, Sets.newHashSet(RR1));
Charles Chan910be6a2017-08-23 14:46:43 -0700204
Charles Chan6c624992017-08-18 17:11:34 -0700205 routeHandler.init(CP1.deviceId());
206
207 assertEquals(1, ROUTING_TABLE.size());
Charles Chanf0ae41e2017-08-23 13:55:39 -0700208 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
209 assertEquals(M1, rtv1.macAddress);
210 assertEquals(V1, rtv1.vlanId);
211 assertEquals(CP1.port(), rtv1.portNumber);
212
Charles Chan6c624992017-08-18 17:11:34 -0700213 assertEquals(1, SUBNET_TABLE.size());
Charles Chan6c624992017-08-18 17:11:34 -0700214 }
215
216 @Test
Charles Chan7d20a4e2018-04-13 14:01:49 -0400217 public void initTwoNextHops() {
218 ROUTE_STORE.put(P1, Sets.newHashSet(RR1, RR2));
219
220 routeHandler.init(CP1.deviceId());
221
222 assertEquals(2, ROUTING_TABLE.size());
223 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
224 assertEquals(M1, rtv1.macAddress);
225 assertEquals(V1, rtv1.vlanId);
226 assertEquals(CP1.port(), rtv1.portNumber);
227 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
228 assertEquals(M2, rtv2.macAddress);
229 assertEquals(V2, rtv2.vlanId);
230 assertEquals(CP2.port(), rtv2.portNumber);
231
232 assertEquals(2, SUBNET_TABLE.size());
Charles Chan12a8a842020-02-14 13:23:57 -0800233 }
234
235 // Only one of two dual-homed next hops present.
236 // Expect one routing table to be programmed with direct flow.
237 // The other is not programmed, not even for subnet
238 @Test
239 public void initDhcpRouteSingleDualHomeNextHop() {
240 ROUTE_STORE.put(P1, Sets.newHashSet(DHCP_RR1));
241
242 routeHandler.init(CP1.deviceId());
243
244 assertEquals(1, ROUTING_TABLE.size());
245 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
246 assertEquals(M1, rtv1.macAddress);
247 assertEquals(V1, rtv1.vlanId);
248 assertEquals(CP1.port(), rtv1.portNumber);
249
250 assertEquals(1, SUBNET_TABLE.size());
251 }
252
253 // Both dual-homed next hops present.
254 // Expect both routing table to be programmed with direct flow
255 @Test
256 public void initDhcpRouteBothDualHomeNextHop() {
257 ROUTE_STORE.put(P1, Sets.newHashSet(DHCP_RR3));
258
259 routeHandler.init(CP1.deviceId());
260
261 assertEquals(2, ROUTING_TABLE.size());
262 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
263 assertEquals(M3, rtv1.macAddress);
264 assertEquals(V3, rtv1.vlanId);
265 assertEquals(CP1.port(), rtv1.portNumber);
266
267 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
268 assertEquals(M3, rtv2.macAddress);
269 assertEquals(V3, rtv2.vlanId);
270 assertEquals(CP2.port(), rtv2.portNumber);
271
272 assertEquals(2, SUBNET_TABLE.size());
Charles Chan7d20a4e2018-04-13 14:01:49 -0400273 }
274
275 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400276 public void processRouteAdded() {
Charles Chan06f626c2018-02-05 17:20:05 -0800277 reset(srManager.deviceConfiguration);
278 srManager.deviceConfiguration.addSubnet(CP1, P1);
279 expectLastCall().once();
280 replay(srManager.deviceConfiguration);
281
Charles Chan910be6a2017-08-23 14:46:43 -0700282 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1));
Charles Chan6c624992017-08-18 17:11:34 -0700283 routeHandler.processRouteAdded(re);
284
285 assertEquals(1, ROUTING_TABLE.size());
Charles Chanf0ae41e2017-08-23 13:55:39 -0700286 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
287 assertEquals(M1, rtv1.macAddress);
288 assertEquals(V1, rtv1.vlanId);
289 assertEquals(CP1.port(), rtv1.portNumber);
290
Charles Chan6c624992017-08-18 17:11:34 -0700291 assertEquals(1, SUBNET_TABLE.size());
292 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800293
294 verify(srManager.deviceConfiguration);
Charles Chan6c624992017-08-18 17:11:34 -0700295 }
296
297 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400298 public void processRouteUpdated() {
Charles Chan6c624992017-08-18 17:11:34 -0700299 processRouteAdded();
300
Charles Chan06f626c2018-02-05 17:20:05 -0800301 reset(srManager.deviceConfiguration);
302 srManager.deviceConfiguration.removeSubnet(CP1, P1);
303 expectLastCall().once();
304 srManager.deviceConfiguration.addSubnet(CP2, P1);
305 expectLastCall().once();
306 replay(srManager.deviceConfiguration);
307
Charles Chan910be6a2017-08-23 14:46:43 -0700308 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_UPDATED, RR2, RR1, Sets.newHashSet(RR2),
309 Sets.newHashSet(RR1));
Charles Chan6c624992017-08-18 17:11:34 -0700310 routeHandler.processRouteUpdated(re);
311
Charles Chan06f626c2018-02-05 17:20:05 -0800312 // Note: We shouldn't remove the old nexthop during the occasion of route update
313 // since the populate subnet will take care of it and point it to an ECMP group
314 assertEquals(2, ROUTING_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700315 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
Charles Chanf0ae41e2017-08-23 13:55:39 -0700316 assertEquals(M2, rtv2.macAddress);
317 assertEquals(V2, rtv2.vlanId);
318 assertEquals(CP2.port(), rtv2.portNumber);
319
Charles Chan6c624992017-08-18 17:11:34 -0700320 assertEquals(1, SUBNET_TABLE.size());
321 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800322
323 verify(srManager.deviceConfiguration);
Charles Chan6c624992017-08-18 17:11:34 -0700324 }
325
326 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400327 public void processRouteRemoved() {
Charles Chan6c624992017-08-18 17:11:34 -0700328 processRouteAdded();
329
Charles Chan06f626c2018-02-05 17:20:05 -0800330 reset(srManager.deviceConfiguration);
331 srManager.deviceConfiguration.removeSubnet(CP1, P1);
332 expectLastCall().once();
333 replay(srManager.deviceConfiguration);
334
Charles Chan910be6a2017-08-23 14:46:43 -0700335 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1));
336 routeHandler.processRouteRemoved(re);
337
338 assertEquals(0, ROUTING_TABLE.size());
339 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800340
341 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700342 }
343
344 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400345 public void testTwoSingleHomedAdded() {
Charles Chan06f626c2018-02-05 17:20:05 -0800346 reset(srManager.deviceConfiguration);
347 srManager.deviceConfiguration.addSubnet(CP1, P1);
348 expectLastCall().once();
349 srManager.deviceConfiguration.addSubnet(CP2, P1);
350 expectLastCall().once();
351 replay(srManager.deviceConfiguration);
352
Charles Chan910be6a2017-08-23 14:46:43 -0700353 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
354 routeHandler.processRouteAdded(re);
355
356 assertEquals(2, ROUTING_TABLE.size());
357 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
358 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
359 assertEquals(M1, rtv1.macAddress);
360 assertEquals(M2, rtv2.macAddress);
361 assertEquals(V1, rtv1.vlanId);
362 assertEquals(V2, rtv2.vlanId);
363 assertEquals(CP1.port(), rtv1.portNumber);
364 assertEquals(CP2.port(), rtv2.portNumber);
365
366 assertEquals(2, SUBNET_TABLE.size());
367 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
368 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800369
370 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700371 }
372
373 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400374 public void testOneDualHomedAdded() {
Charles Chan06f626c2018-02-05 17:20:05 -0800375 reset(srManager.deviceConfiguration);
376 srManager.deviceConfiguration.addSubnet(CP1, P1);
377 expectLastCall().once();
378 srManager.deviceConfiguration.addSubnet(CP2, P1);
379 expectLastCall().once();
380 replay(srManager.deviceConfiguration);
381
Charles Chan910be6a2017-08-23 14:46:43 -0700382 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR3, Sets.newHashSet(RR3));
383 routeHandler.processRouteAdded(re);
384
385 assertEquals(2, ROUTING_TABLE.size());
386 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
387 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
388 assertEquals(M3, rtv1.macAddress);
389 assertEquals(M3, rtv2.macAddress);
390 assertEquals(V3, rtv1.vlanId);
391 assertEquals(V3, rtv2.vlanId);
392 assertEquals(CP1.port(), rtv1.portNumber);
393 assertEquals(CP2.port(), rtv2.portNumber);
394
395 assertEquals(2, SUBNET_TABLE.size());
396 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
397 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800398
399 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700400 }
401
402 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400403 public void testOneSingleHomedToTwoSingleHomed() {
Charles Chan910be6a2017-08-23 14:46:43 -0700404 processRouteAdded();
405
Charles Chan06f626c2018-02-05 17:20:05 -0800406 reset(srManager.deviceConfiguration);
407 srManager.deviceConfiguration.addSubnet(CP2, P1);
408 expectLastCall().once();
409 replay(srManager.deviceConfiguration);
410
Charles Chan910be6a2017-08-23 14:46:43 -0700411 RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
412 Sets.newHashSet(RR1, RR2), Sets.newHashSet(RR1));
413 routeHandler.processAlternativeRoutesChanged(re);
414
415 assertEquals(2, ROUTING_TABLE.size());
416 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
417 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
418 assertEquals(M1, rtv1.macAddress);
419 assertEquals(M2, rtv2.macAddress);
420 assertEquals(V1, rtv1.vlanId);
421 assertEquals(V2, rtv2.vlanId);
422 assertEquals(CP1.port(), rtv1.portNumber);
423 assertEquals(CP2.port(), rtv2.portNumber);
424
425 assertEquals(2, SUBNET_TABLE.size());
426 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
427 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800428
429 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700430 }
431
432 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400433 public void testTwoSingleHomedToOneSingleHomed() {
Charles Chan910be6a2017-08-23 14:46:43 -0700434 testTwoSingleHomedAdded();
435
Charles Chan06f626c2018-02-05 17:20:05 -0800436 reset(srManager.deviceConfiguration);
437 srManager.deviceConfiguration.removeSubnet(CP2, P1);
438 expectLastCall().once();
439 replay(srManager.deviceConfiguration);
440
Charles Chan910be6a2017-08-23 14:46:43 -0700441 RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
442 Sets.newHashSet(RR1), Sets.newHashSet(RR1, RR2));
443 routeHandler.processAlternativeRoutesChanged(re);
444
Charles Chan06f626c2018-02-05 17:20:05 -0800445 // Note: We shouldn't remove the old nexthop during the occasion of route update
446 // since the populate subnet will take care of it and point it to an ECMP group
447 assertEquals(2, ROUTING_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700448 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
449 assertEquals(M1, rtv1.macAddress);
450 assertEquals(V1, rtv1.vlanId);
451 assertEquals(CP1.port(), rtv1.portNumber);
452
453 assertEquals(1, SUBNET_TABLE.size());
454 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800455
456 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700457 }
458
Charles Chan06f626c2018-02-05 17:20:05 -0800459 // TODO Add test cases for two single homed next hop at same location
460
Charles Chan910be6a2017-08-23 14:46:43 -0700461 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400462 public void testDualHomedSingleLocationFail() {
Charles Chan910be6a2017-08-23 14:46:43 -0700463 testOneDualHomedAdded();
464
Charles Chan7d20a4e2018-04-13 14:01:49 -0400465 ROUTE_STORE.put(P1, Sets.newHashSet(RR3));
466
Charles Chan07203792018-07-17 16:33:11 -0700467 reset(srManager.deviceConfiguration);
Charles Chan5eec3b12019-04-18 14:30:41 -0700468 expect(srManager.deviceConfiguration.getBatchedSubnets(H3D.id()))
469 .andReturn(Lists.<Set<IpPrefix>>newArrayList(Sets.newHashSet(P1)));
Charles Chan07203792018-07-17 16:33:11 -0700470 srManager.deviceConfiguration.removeSubnet(CP2, P1);
471 expectLastCall().once();
472 replay(srManager.deviceConfiguration);
473
Charles Chan910be6a2017-08-23 14:46:43 -0700474 HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3S, H3D);
475 routeHandler.processHostMovedEvent(he);
476
Charles Chan4dcd5102019-02-28 15:40:57 -0800477 // We do not remove the route on CP2. Instead, we let the subnet population overrides it
478 assertEquals(2, ROUTING_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700479 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
Charles Chan910be6a2017-08-23 14:46:43 -0700480 assertEquals(M3, rtv1.macAddress);
Charles Chan910be6a2017-08-23 14:46:43 -0700481 assertEquals(V3, rtv1.vlanId);
Charles Chan910be6a2017-08-23 14:46:43 -0700482 assertEquals(CP1.port(), rtv1.portNumber);
Charles Chan910be6a2017-08-23 14:46:43 -0700483
484 // ECMP route table hasn't changed
Charles Chan07203792018-07-17 16:33:11 -0700485 assertEquals(1, SUBNET_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700486 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan07203792018-07-17 16:33:11 -0700487
488 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700489 }
490
491 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400492 public void testDualHomedBothLocationFail() {
Charles Chan910be6a2017-08-23 14:46:43 -0700493 testDualHomedSingleLocationFail();
494
495 hostService = new MockHostService(HOSTS_ONE_FAIL);
496
Charles Chan06f626c2018-02-05 17:20:05 -0800497 reset(srManager.deviceConfiguration);
498 srManager.deviceConfiguration.removeSubnet(CP1, P1);
499 expectLastCall().once();
500 srManager.deviceConfiguration.removeSubnet(CP2, P1);
501 expectLastCall().once();
502 replay(srManager.deviceConfiguration);
503
Charles Chan910be6a2017-08-23 14:46:43 -0700504 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
505 routeHandler.processRouteRemoved(re);
506
507 assertEquals(0, ROUTING_TABLE.size());
508 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800509
510 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700511 }
512
513 @Test
Charles Chan07203792018-07-17 16:33:11 -0700514 public void testSingleHomedToDualHomed() {
515 testDualHomedSingleLocationFail();
516
517 reset(srManager.deviceConfiguration);
Charles Chan5eec3b12019-04-18 14:30:41 -0700518 expect(srManager.deviceConfiguration.getBatchedSubnets(H3S.id()))
519 .andReturn(Lists.<Set<IpPrefix>>newArrayList(Sets.newHashSet(P1)));
Charles Chan07203792018-07-17 16:33:11 -0700520 srManager.deviceConfiguration.addSubnet(CP2, P1);
521 expectLastCall().once();
522 replay(srManager.deviceConfiguration);
523
524 HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3D, H3S);
525 routeHandler.processHostMovedEvent(he);
526
527 assertEquals(2, ROUTING_TABLE.size());
528 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
529 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
530 assertEquals(M3, rtv1.macAddress);
531 assertEquals(M3, rtv2.macAddress);
532 assertEquals(V3, rtv1.vlanId);
533 assertEquals(V3, rtv2.vlanId);
534 assertEquals(CP1.port(), rtv1.portNumber);
535 assertEquals(CP2.port(), rtv2.portNumber);
536
537 assertEquals(2, SUBNET_TABLE.size());
538 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
539 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
540
541 verify(srManager.deviceConfiguration);
542 }
543
544 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400545 public void testTwoSingleHomedRemoved() {
Charles Chan910be6a2017-08-23 14:46:43 -0700546 testTwoSingleHomedAdded();
547
548 hostService = new MockHostService(HOSTS_BOTH_FAIL);
549
Charles Chan06f626c2018-02-05 17:20:05 -0800550 reset(srManager.deviceConfiguration);
551 srManager.deviceConfiguration.removeSubnet(CP1, P1);
552 expectLastCall().once();
553 srManager.deviceConfiguration.removeSubnet(CP2, P1);
554 expectLastCall().once();
555 replay(srManager.deviceConfiguration);
556
Charles Chan910be6a2017-08-23 14:46:43 -0700557 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1, RR2));
558 routeHandler.processRouteRemoved(re);
559
560 assertEquals(0, ROUTING_TABLE.size());
561 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800562
563 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700564 }
565
566 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400567 public void testOneDualHomeRemoved() {
Charles Chan910be6a2017-08-23 14:46:43 -0700568 testOneDualHomedAdded();
569
Charles Chan06f626c2018-02-05 17:20:05 -0800570 reset(srManager.deviceConfiguration);
571 srManager.deviceConfiguration.removeSubnet(CP1, P1);
572 expectLastCall().once();
573 srManager.deviceConfiguration.removeSubnet(CP2, P1);
574 expectLastCall().once();
575 replay(srManager.deviceConfiguration);
576
Charles Chan910be6a2017-08-23 14:46:43 -0700577 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
Charles Chan6c624992017-08-18 17:11:34 -0700578 routeHandler.processRouteRemoved(re);
579
580 assertEquals(0, ROUTING_TABLE.size());
581 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800582
583 verify(srManager.deviceConfiguration);
Charles Chan6c624992017-08-18 17:11:34 -0700584 }
Charles Chan482b6422018-04-09 11:52:08 -0400585
586 @Test
587 public void testMoreThanTwoNextHop() {
588 // next hop = CP1, CP2
589 reset(srManager.deviceConfiguration);
590 srManager.deviceConfiguration.addSubnet(CP1, P1);
591 srManager.deviceConfiguration.addSubnet(CP2, P1);
592 expectLastCall().once();
593 replay(srManager.deviceConfiguration);
594
595 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
596 routeHandler.processRouteAdded(re);
597
598 assertEquals(2, ROUTING_TABLE.size());
599 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
600 assertEquals(M1, rtv1.macAddress);
601 assertEquals(V1, rtv1.vlanId);
602 assertEquals(CP1.port(), rtv1.portNumber);
603 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
604 assertEquals(M2, rtv2.macAddress);
605 assertEquals(V2, rtv2.vlanId);
606 assertEquals(CP2.port(), rtv2.portNumber);
607
608 assertEquals(2, SUBNET_TABLE.size());
609 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
610 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
611
612 verify(srManager.deviceConfiguration);
613
614 // next hop = CP1, CP2, CP4 (invalid)
615 re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
616 Sets.newHashSet(RR1, RR2, RR4), Sets.newHashSet(RR1, RR2));
617 routeHandler.processAlternativeRoutesChanged(re);
618
619 assertEquals(2, ROUTING_TABLE.size());
620 rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
621 assertEquals(M1, rtv1.macAddress);
622 assertEquals(V1, rtv1.vlanId);
623 assertEquals(CP1.port(), rtv1.portNumber);
624 rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
625 assertEquals(M2, rtv2.macAddress);
626 assertEquals(V2, rtv2.vlanId);
627 assertEquals(CP2.port(), rtv2.portNumber);
628
629 assertEquals(2, SUBNET_TABLE.size());
630 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
631 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
632
633 // next hop = CP2, CP4
634 reset(srManager.deviceConfiguration);
635 srManager.deviceConfiguration.addSubnet(CP2, P1);
636 srManager.deviceConfiguration.addSubnet(CP4, P1);
637 expectLastCall().once();
638 replay(srManager.deviceConfiguration);
639
640 re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
641 Sets.newHashSet(RR2, RR4), Sets.newHashSet(RR1, RR2, RR4));
642 routeHandler.processAlternativeRoutesChanged(re);
643
644 assertEquals(2, ROUTING_TABLE.size());
645 rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
646 assertEquals(M2, rtv1.macAddress);
647 assertEquals(V2, rtv1.vlanId);
648 assertEquals(CP2.port(), rtv1.portNumber);
649 rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP4.deviceId(), P1));
650 assertEquals(M4, rtv2.macAddress);
651 assertEquals(V4, rtv2.vlanId);
652 assertEquals(CP4.port(), rtv2.portNumber);
653
654 assertEquals(2, SUBNET_TABLE.size());
655 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
656 assertTrue(SUBNET_TABLE.get(CP4).contains(P1));
657
658 verify(srManager.deviceConfiguration);
659 }
Ruchi Sahota71bcb4e2019-01-28 01:08:18 +0000660}