blob: 843ba6bd2bb5d64ac455b9b2b775b20e90ee5ef9 [file] [log] [blame]
Charles Chan48f89a52017-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 Chan23686832017-08-23 14:46:43 -070019import com.fasterxml.jackson.databind.JsonNode;
20import com.fasterxml.jackson.databind.ObjectMapper;
Charles Chan48f89a52017-08-18 17:11:34 -070021import com.google.common.collect.Maps;
22import com.google.common.collect.Sets;
23import org.junit.Before;
24import org.junit.Test;
25import org.onlab.packet.IpAddress;
26import org.onlab.packet.IpPrefix;
27import org.onlab.packet.MacAddress;
28import org.onlab.packet.VlanId;
Charles Chan23686832017-08-23 14:46:43 -070029import org.onosproject.net.config.ConfigApplyDelegate;
Charles Chan48f89a52017-08-18 17:11:34 -070030import org.onosproject.net.ConnectPoint;
Charles Chanb15d0102017-08-23 13:55:39 -070031import org.onosproject.net.DefaultHost;
Charles Chan48f89a52017-08-18 17:11:34 -070032import org.onosproject.net.DeviceId;
33import org.onosproject.net.Host;
Charles Chanb15d0102017-08-23 13:55:39 -070034import org.onosproject.net.HostId;
35import org.onosproject.net.HostLocation;
Charles Chan23686832017-08-23 14:46:43 -070036import org.onosproject.net.PortNumber;
Charles Chan48f89a52017-08-18 17:11:34 -070037import org.onosproject.net.config.NetworkConfigRegistryAdapter;
38import org.onosproject.net.flow.TrafficTreatment;
Charles Chan23686832017-08-23 14:46:43 -070039import org.onosproject.net.host.HostEvent;
40import org.onosproject.net.host.HostService;
Charles Chan48f89a52017-08-18 17:11:34 -070041import org.onosproject.net.intf.Interface;
Charles Chanb15d0102017-08-23 13:55:39 -070042import org.onosproject.net.provider.ProviderId;
Charles Chan48f89a52017-08-18 17:11:34 -070043import org.onosproject.routeservice.ResolvedRoute;
44import org.onosproject.routeservice.Route;
45import org.onosproject.routeservice.RouteEvent;
Charles Chan48f89a52017-08-18 17:11:34 -070046import org.onosproject.segmentrouting.config.DeviceConfiguration;
Charles Chan23686832017-08-23 14:46:43 -070047import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
Charles Chan48f89a52017-08-18 17:11:34 -070048
49import java.util.Map;
50import java.util.Set;
51
Charles Chan3cb4cb92018-02-05 17:20:05 -080052import static org.easymock.EasyMock.reset;
Charles Chan48f89a52017-08-18 17:11:34 -070053import static org.junit.Assert.*;
Charles Chan3cb4cb92018-02-05 17:20:05 -080054import static org.easymock.EasyMock.createMock;
55import static org.easymock.EasyMock.expectLastCall;
56import static org.easymock.EasyMock.replay;
57import static org.easymock.EasyMock.verify;
Charles Chan48f89a52017-08-18 17:11:34 -070058
59/**
60 * Unit test for {@link RouteHandler}.
61 */
62public class RouteHandlerTest {
Charles Chan3cb4cb92018-02-05 17:20:05 -080063 private SegmentRoutingManager srManager;
Charles Chan48f89a52017-08-18 17:11:34 -070064 private RouteHandler routeHandler;
Charles Chan23686832017-08-23 14:46:43 -070065 private HostService hostService;
Charles Chan48f89a52017-08-18 17:11:34 -070066
67 // Mocked routing and bridging tables
68 private static final Map<MockBridgingTableKey, MockBridgingTableValue> BRIDGING_TABLE =
69 Maps.newConcurrentMap();
70 private static final Map<MockRoutingTableKey, MockRoutingTableValue> ROUTING_TABLE =
71 Maps.newConcurrentMap();
72 private static final Map<ConnectPoint, Set<IpPrefix>> SUBNET_TABLE = Maps.newConcurrentMap();
73 // Mocked Next Id
74 private static final Map<Integer, TrafficTreatment> NEXT_TABLE = Maps.newConcurrentMap();
75
76 private static final IpPrefix P1 = IpPrefix.valueOf("10.0.0.0/24");
Charles Chan23686832017-08-23 14:46:43 -070077
78 // Single homed router 1
Charles Chan48f89a52017-08-18 17:11:34 -070079 private static final IpAddress N1 = IpAddress.valueOf("10.0.1.254");
80 private static final MacAddress M1 = MacAddress.valueOf("00:00:00:00:00:01");
81 private static final VlanId V1 = VlanId.vlanId((short) 1);
82 private static final ConnectPoint CP1 = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
83 private static final Route R1 = new Route(Route.Source.STATIC, P1, N1);
Charles Chanb15d0102017-08-23 13:55:39 -070084 private static final ResolvedRoute RR1 = new ResolvedRoute(R1, M1, V1);
Charles Chan48f89a52017-08-18 17:11:34 -070085
Charles Chan23686832017-08-23 14:46:43 -070086 // Single homed router 2
Charles Chan48f89a52017-08-18 17:11:34 -070087 private static final IpAddress N2 = IpAddress.valueOf("10.0.2.254");
88 private static final MacAddress M2 = MacAddress.valueOf("00:00:00:00:00:02");
89 private static final VlanId V2 = VlanId.vlanId((short) 2);
Charles Chan23686832017-08-23 14:46:43 -070090 private static final ConnectPoint CP2 = ConnectPoint.deviceConnectPoint("of:0000000000000002/2");
Charles Chan48f89a52017-08-18 17:11:34 -070091 private static final Route R2 = new Route(Route.Source.STATIC, P1, N2);
Charles Chanb15d0102017-08-23 13:55:39 -070092 private static final ResolvedRoute RR2 = new ResolvedRoute(R2, M2, V2);
Charles Chan48f89a52017-08-18 17:11:34 -070093
Charles Chan23686832017-08-23 14:46:43 -070094 // Dual homed router 1
95 private static final IpAddress N3 = IpAddress.valueOf("10.0.3.254");
96 private static final MacAddress M3 = MacAddress.valueOf("00:00:00:00:00:03");
97 private static final VlanId V3 = VlanId.vlanId((short) 3);
98 private static final Route R3 = new Route(Route.Source.STATIC, P1, N3);
99 private static final ResolvedRoute RR3 = new ResolvedRoute(R3, M3, V3);
Charles Chan48f89a52017-08-18 17:11:34 -0700100
Charles Chan23686832017-08-23 14:46:43 -0700101 // Hosts
Charles Chanb15d0102017-08-23 13:55:39 -0700102 private static final Host H1 = new DefaultHost(ProviderId.NONE, HostId.hostId(M1, V1), M1, V1,
103 Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N1), false);
104 private static final Host H2 = new DefaultHost(ProviderId.NONE, HostId.hostId(M2, V2), M2, V2,
105 Sets.newHashSet(new HostLocation(CP2, 0)), Sets.newHashSet(N2), false);
Charles Chan23686832017-08-23 14:46:43 -0700106 private static final Host H3D = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
107 Sets.newHashSet(new HostLocation(CP1, 0), new HostLocation(CP2, 0)), Sets.newHashSet(N3), false);
108 private static final Host H3S = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
109 Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N3), false);
110
111 // Pair Local Port
112 private static final PortNumber P9 = PortNumber.portNumber(9);
Charles Chanb15d0102017-08-23 13:55:39 -0700113
Charles Chan48f89a52017-08-18 17:11:34 -0700114 // A set of hosts
Charles Chan23686832017-08-23 14:46:43 -0700115 private static final Set<Host> HOSTS = Sets.newHashSet(H1, H2, H3D);
116 private static final Set<Host> HOSTS_ONE_FAIL = Sets.newHashSet(H1, H2, H3S);
117 private static final Set<Host> HOSTS_BOTH_FAIL = Sets.newHashSet(H1, H2);
Charles Chan48f89a52017-08-18 17:11:34 -0700118 // A set of devices of which we have mastership
Charles Chan23686832017-08-23 14:46:43 -0700119 private static final Set<DeviceId> LOCAL_DEVICES = Sets.newHashSet(CP1.deviceId(), CP2.deviceId());
Charles Chan48f89a52017-08-18 17:11:34 -0700120 // A set of interfaces
121 private static final Set<Interface> INTERFACES = Sets.newHashSet();
Charles Chan48f89a52017-08-18 17:11:34 -0700122
123 @Before
124 public void setUp() throws Exception {
Charles Chan23686832017-08-23 14:46:43 -0700125 ObjectMapper mapper = new ObjectMapper();
126 ConfigApplyDelegate delegate = config -> { };
127
128 SegmentRoutingDeviceConfig dev1Config = new SegmentRoutingDeviceConfig();
129 JsonNode dev1Tree = mapper.createObjectNode();
130 dev1Config.init(CP1.deviceId(), "host-handler-test", dev1Tree, mapper, delegate);
131 dev1Config.setPairDeviceId(CP2.deviceId()).setPairLocalPort(P9);
132
133 SegmentRoutingDeviceConfig dev2Config = new SegmentRoutingDeviceConfig();
134 JsonNode dev2Tree = mapper.createObjectNode();
135 dev2Config.init(CP2.deviceId(), "host-handler-test", dev2Tree, mapper, delegate);
136 dev2Config.setPairDeviceId(CP1.deviceId()).setPairLocalPort(P9);
Charles Chan48f89a52017-08-18 17:11:34 -0700137
138 MockNetworkConfigRegistry mockNetworkConfigRegistry = new MockNetworkConfigRegistry();
Charles Chan23686832017-08-23 14:46:43 -0700139 mockNetworkConfigRegistry.applyConfig(dev1Config);
140 mockNetworkConfigRegistry.applyConfig(dev2Config);
Charles Chan48f89a52017-08-18 17:11:34 -0700141
142 // Initialize Segment Routing Manager
Charles Chan3cb4cb92018-02-05 17:20:05 -0800143 srManager = new MockSegmentRoutingManager(NEXT_TABLE);
Charles Chan48f89a52017-08-18 17:11:34 -0700144 srManager.cfgService = new NetworkConfigRegistryAdapter();
Charles Chan3cb4cb92018-02-05 17:20:05 -0800145 srManager.deviceConfiguration = createMock(DeviceConfiguration.class);
Charles Chan48f89a52017-08-18 17:11:34 -0700146 srManager.flowObjectiveService = new MockFlowObjectiveService(BRIDGING_TABLE, NEXT_TABLE);
147 srManager.routingRulePopulator = new MockRoutingRulePopulator(srManager, ROUTING_TABLE);
148 srManager.defaultRoutingHandler = new MockDefaultRoutingHandler(srManager, SUBNET_TABLE);
149 srManager.interfaceService = new MockInterfaceService(INTERFACES);
150 srManager.mastershipService = new MockMastershipService(LOCAL_DEVICES);
Charles Chan23686832017-08-23 14:46:43 -0700151 hostService = new MockHostService(HOSTS);
152 srManager.hostService = hostService;
Charles Chan48f89a52017-08-18 17:11:34 -0700153 srManager.cfgService = mockNetworkConfigRegistry;
Charles Chan23686832017-08-23 14:46:43 -0700154 srManager.routeService = new MockRouteService(ROUTING_TABLE);
Charles Chan48f89a52017-08-18 17:11:34 -0700155
Charles Chan23686832017-08-23 14:46:43 -0700156 routeHandler = new RouteHandler(srManager) {
157 // routeEventCache is not necessary for unit tests
158 @Override
159 void enqueueRouteEvent(RouteEvent routeEvent) {
160 dequeueRouteEvent(routeEvent);
161 }
162 };
Charles Chan48f89a52017-08-18 17:11:34 -0700163
164 ROUTING_TABLE.clear();
165 BRIDGING_TABLE.clear();
166 SUBNET_TABLE.clear();
167 }
168
169 @Test
170 public void init() throws Exception {
Charles Chan23686832017-08-23 14:46:43 -0700171 MockRoutingTableKey rtk = new MockRoutingTableKey(CP1.deviceId(), P1);
172 MockRoutingTableValue rtv = new MockRoutingTableValue(CP1.port(), M1, V1);
173 ROUTING_TABLE.put(rtk, rtv);
174
Charles Chan48f89a52017-08-18 17:11:34 -0700175 routeHandler.init(CP1.deviceId());
176
177 assertEquals(1, ROUTING_TABLE.size());
Charles Chanb15d0102017-08-23 13:55:39 -0700178 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
179 assertEquals(M1, rtv1.macAddress);
180 assertEquals(V1, rtv1.vlanId);
181 assertEquals(CP1.port(), rtv1.portNumber);
182
Charles Chan48f89a52017-08-18 17:11:34 -0700183 assertEquals(1, SUBNET_TABLE.size());
184 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
185 }
186
187 @Test
188 public void processRouteAdded() throws Exception {
Charles Chan3cb4cb92018-02-05 17:20:05 -0800189 reset(srManager.deviceConfiguration);
190 srManager.deviceConfiguration.addSubnet(CP1, P1);
191 expectLastCall().once();
192 replay(srManager.deviceConfiguration);
193
Charles Chan23686832017-08-23 14:46:43 -0700194 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1));
Charles Chan48f89a52017-08-18 17:11:34 -0700195 routeHandler.processRouteAdded(re);
196
197 assertEquals(1, ROUTING_TABLE.size());
Charles Chanb15d0102017-08-23 13:55:39 -0700198 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
199 assertEquals(M1, rtv1.macAddress);
200 assertEquals(V1, rtv1.vlanId);
201 assertEquals(CP1.port(), rtv1.portNumber);
202
Charles Chan48f89a52017-08-18 17:11:34 -0700203 assertEquals(1, SUBNET_TABLE.size());
204 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan3cb4cb92018-02-05 17:20:05 -0800205
206 verify(srManager.deviceConfiguration);
Charles Chan48f89a52017-08-18 17:11:34 -0700207 }
208
209 @Test
210 public void processRouteUpdated() throws Exception {
211 processRouteAdded();
212
Charles Chan3cb4cb92018-02-05 17:20:05 -0800213 reset(srManager.deviceConfiguration);
214 srManager.deviceConfiguration.removeSubnet(CP1, P1);
215 expectLastCall().once();
216 srManager.deviceConfiguration.addSubnet(CP2, P1);
217 expectLastCall().once();
218 replay(srManager.deviceConfiguration);
219
Charles Chan23686832017-08-23 14:46:43 -0700220 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_UPDATED, RR2, RR1, Sets.newHashSet(RR2),
221 Sets.newHashSet(RR1));
Charles Chan48f89a52017-08-18 17:11:34 -0700222 routeHandler.processRouteUpdated(re);
223
Charles Chan3cb4cb92018-02-05 17:20:05 -0800224 // Note: We shouldn't remove the old nexthop during the occasion of route update
225 // since the populate subnet will take care of it and point it to an ECMP group
226 assertEquals(2, ROUTING_TABLE.size());
Charles Chan23686832017-08-23 14:46:43 -0700227 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
Charles Chanb15d0102017-08-23 13:55:39 -0700228 assertEquals(M2, rtv2.macAddress);
229 assertEquals(V2, rtv2.vlanId);
230 assertEquals(CP2.port(), rtv2.portNumber);
231
Charles Chan48f89a52017-08-18 17:11:34 -0700232 assertEquals(1, SUBNET_TABLE.size());
233 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan3cb4cb92018-02-05 17:20:05 -0800234
235 verify(srManager.deviceConfiguration);
Charles Chan48f89a52017-08-18 17:11:34 -0700236 }
237
238 @Test
239 public void processRouteRemoved() throws Exception {
240 processRouteAdded();
241
Charles Chan3cb4cb92018-02-05 17:20:05 -0800242 reset(srManager.deviceConfiguration);
243 srManager.deviceConfiguration.removeSubnet(CP1, P1);
244 expectLastCall().once();
245 replay(srManager.deviceConfiguration);
246
Charles Chan23686832017-08-23 14:46:43 -0700247 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1));
248 routeHandler.processRouteRemoved(re);
249
250 assertEquals(0, ROUTING_TABLE.size());
251 assertEquals(0, SUBNET_TABLE.size());
Charles Chan3cb4cb92018-02-05 17:20:05 -0800252
253 verify(srManager.deviceConfiguration);
Charles Chan23686832017-08-23 14:46:43 -0700254 }
255
256 @Test
257 public void testTwoSingleHomedAdded() throws Exception {
Charles Chan3cb4cb92018-02-05 17:20:05 -0800258 reset(srManager.deviceConfiguration);
259 srManager.deviceConfiguration.addSubnet(CP1, P1);
260 expectLastCall().once();
261 srManager.deviceConfiguration.addSubnet(CP2, P1);
262 expectLastCall().once();
263 replay(srManager.deviceConfiguration);
264
Charles Chan23686832017-08-23 14:46:43 -0700265 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
266 routeHandler.processRouteAdded(re);
267
268 assertEquals(2, ROUTING_TABLE.size());
269 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
270 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
271 assertEquals(M1, rtv1.macAddress);
272 assertEquals(M2, rtv2.macAddress);
273 assertEquals(V1, rtv1.vlanId);
274 assertEquals(V2, rtv2.vlanId);
275 assertEquals(CP1.port(), rtv1.portNumber);
276 assertEquals(CP2.port(), rtv2.portNumber);
277
278 assertEquals(2, SUBNET_TABLE.size());
279 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
280 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan3cb4cb92018-02-05 17:20:05 -0800281
282 verify(srManager.deviceConfiguration);
Charles Chan23686832017-08-23 14:46:43 -0700283 }
284
285 @Test
286 public void testOneDualHomedAdded() throws Exception {
Charles Chan3cb4cb92018-02-05 17:20:05 -0800287 reset(srManager.deviceConfiguration);
288 srManager.deviceConfiguration.addSubnet(CP1, P1);
289 expectLastCall().once();
290 srManager.deviceConfiguration.addSubnet(CP2, P1);
291 expectLastCall().once();
292 replay(srManager.deviceConfiguration);
293
Charles Chan23686832017-08-23 14:46:43 -0700294 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR3, Sets.newHashSet(RR3));
295 routeHandler.processRouteAdded(re);
296
297 assertEquals(2, ROUTING_TABLE.size());
298 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
299 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
300 assertEquals(M3, rtv1.macAddress);
301 assertEquals(M3, rtv2.macAddress);
302 assertEquals(V3, rtv1.vlanId);
303 assertEquals(V3, rtv2.vlanId);
304 assertEquals(CP1.port(), rtv1.portNumber);
305 assertEquals(CP2.port(), rtv2.portNumber);
306
307 assertEquals(2, SUBNET_TABLE.size());
308 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
309 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan3cb4cb92018-02-05 17:20:05 -0800310
311 verify(srManager.deviceConfiguration);
Charles Chan23686832017-08-23 14:46:43 -0700312 }
313
314 @Test
315 public void testOneSingleHomedToTwoSingleHomed() throws Exception {
316 processRouteAdded();
317
Charles Chan3cb4cb92018-02-05 17:20:05 -0800318 reset(srManager.deviceConfiguration);
319 srManager.deviceConfiguration.addSubnet(CP2, P1);
320 expectLastCall().once();
321 replay(srManager.deviceConfiguration);
322
Charles Chan23686832017-08-23 14:46:43 -0700323 RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
324 Sets.newHashSet(RR1, RR2), Sets.newHashSet(RR1));
325 routeHandler.processAlternativeRoutesChanged(re);
326
327 assertEquals(2, ROUTING_TABLE.size());
328 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
329 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
330 assertEquals(M1, rtv1.macAddress);
331 assertEquals(M2, rtv2.macAddress);
332 assertEquals(V1, rtv1.vlanId);
333 assertEquals(V2, rtv2.vlanId);
334 assertEquals(CP1.port(), rtv1.portNumber);
335 assertEquals(CP2.port(), rtv2.portNumber);
336
337 assertEquals(2, SUBNET_TABLE.size());
338 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
339 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan3cb4cb92018-02-05 17:20:05 -0800340
341 verify(srManager.deviceConfiguration);
Charles Chan23686832017-08-23 14:46:43 -0700342 }
343
344 @Test
345 public void testTwoSingleHomedToOneSingleHomed() throws Exception {
346 testTwoSingleHomedAdded();
347
Charles Chan3cb4cb92018-02-05 17:20:05 -0800348 reset(srManager.deviceConfiguration);
349 srManager.deviceConfiguration.removeSubnet(CP2, P1);
350 expectLastCall().once();
351 replay(srManager.deviceConfiguration);
352
Charles Chan23686832017-08-23 14:46:43 -0700353 RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
354 Sets.newHashSet(RR1), Sets.newHashSet(RR1, RR2));
355 routeHandler.processAlternativeRoutesChanged(re);
356
Charles Chan3cb4cb92018-02-05 17:20:05 -0800357 // Note: We shouldn't remove the old nexthop during the occasion of route update
358 // since the populate subnet will take care of it and point it to an ECMP group
359 assertEquals(2, ROUTING_TABLE.size());
Charles Chan23686832017-08-23 14:46:43 -0700360 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
361 assertEquals(M1, rtv1.macAddress);
362 assertEquals(V1, rtv1.vlanId);
363 assertEquals(CP1.port(), rtv1.portNumber);
364
365 assertEquals(1, SUBNET_TABLE.size());
366 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan3cb4cb92018-02-05 17:20:05 -0800367
368 verify(srManager.deviceConfiguration);
Charles Chan23686832017-08-23 14:46:43 -0700369 }
370
Charles Chan3cb4cb92018-02-05 17:20:05 -0800371 // TODO Add test cases for two single homed next hop at same location
372
Charles Chan23686832017-08-23 14:46:43 -0700373 @Test
374 public void testDualHomedSingleLocationFail() throws Exception {
375 testOneDualHomedAdded();
376
377 HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3S, H3D);
378 routeHandler.processHostMovedEvent(he);
379
380 assertEquals(2, ROUTING_TABLE.size());
381 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
382 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
383 assertEquals(M3, rtv1.macAddress);
384 assertEquals(M3, rtv2.macAddress);
385 assertEquals(V3, rtv1.vlanId);
386 assertEquals(V3, rtv2.vlanId);
387 assertEquals(CP1.port(), rtv1.portNumber);
388 assertEquals(P9, rtv2.portNumber);
389
390 // ECMP route table hasn't changed
391 assertEquals(2, SUBNET_TABLE.size());
392 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
393 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
394 }
395
396 @Test
397 public void testDualHomedBothLocationFail() throws Exception {
398 testDualHomedSingleLocationFail();
399
400 hostService = new MockHostService(HOSTS_ONE_FAIL);
401
Charles Chan3cb4cb92018-02-05 17:20:05 -0800402 reset(srManager.deviceConfiguration);
403 srManager.deviceConfiguration.removeSubnet(CP1, P1);
404 expectLastCall().once();
405 srManager.deviceConfiguration.removeSubnet(CP2, P1);
406 expectLastCall().once();
407 replay(srManager.deviceConfiguration);
408
Charles Chan23686832017-08-23 14:46:43 -0700409 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
410 routeHandler.processRouteRemoved(re);
411
412 assertEquals(0, ROUTING_TABLE.size());
413 assertEquals(0, SUBNET_TABLE.size());
Charles Chan3cb4cb92018-02-05 17:20:05 -0800414
415 verify(srManager.deviceConfiguration);
Charles Chan23686832017-08-23 14:46:43 -0700416 }
417
418 @Test
419 public void testTwoSingleHomedRemoved() throws Exception {
420 testTwoSingleHomedAdded();
421
422 hostService = new MockHostService(HOSTS_BOTH_FAIL);
423
Charles Chan3cb4cb92018-02-05 17:20:05 -0800424 reset(srManager.deviceConfiguration);
425 srManager.deviceConfiguration.removeSubnet(CP1, P1);
426 expectLastCall().once();
427 srManager.deviceConfiguration.removeSubnet(CP2, P1);
428 expectLastCall().once();
429 replay(srManager.deviceConfiguration);
430
Charles Chan23686832017-08-23 14:46:43 -0700431 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1, RR2));
432 routeHandler.processRouteRemoved(re);
433
434 assertEquals(0, ROUTING_TABLE.size());
435 assertEquals(0, SUBNET_TABLE.size());
Charles Chan3cb4cb92018-02-05 17:20:05 -0800436
437 verify(srManager.deviceConfiguration);
Charles Chan23686832017-08-23 14:46:43 -0700438 }
439
440 @Test
441 public void testOneDualHomeRemoved() throws Exception {
442 testOneDualHomedAdded();
443
Charles Chan3cb4cb92018-02-05 17:20:05 -0800444 reset(srManager.deviceConfiguration);
445 srManager.deviceConfiguration.removeSubnet(CP1, P1);
446 expectLastCall().once();
447 srManager.deviceConfiguration.removeSubnet(CP2, P1);
448 expectLastCall().once();
449 replay(srManager.deviceConfiguration);
450
Charles Chan23686832017-08-23 14:46:43 -0700451 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
Charles Chan48f89a52017-08-18 17:11:34 -0700452 routeHandler.processRouteRemoved(re);
453
454 assertEquals(0, ROUTING_TABLE.size());
455 assertEquals(0, SUBNET_TABLE.size());
Charles Chan3cb4cb92018-02-05 17:20:05 -0800456
457 verify(srManager.deviceConfiguration);
Charles Chan48f89a52017-08-18 17:11:34 -0700458 }
Charles Chan48f89a52017-08-18 17:11:34 -0700459}