blob: ef4c2aa2f3261102e6bba651deb4581c4e47eee9 [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 Chan6c624992017-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 Chan910be6a2017-08-23 14:46:43 -070029import org.onosproject.net.config.ConfigApplyDelegate;
Charles Chan6c624992017-08-18 17:11:34 -070030import org.onosproject.net.ConnectPoint;
Charles Chanf0ae41e2017-08-23 13:55:39 -070031import org.onosproject.net.DefaultHost;
Charles Chan6c624992017-08-18 17:11:34 -070032import org.onosproject.net.DeviceId;
33import org.onosproject.net.Host;
Charles Chanf0ae41e2017-08-23 13:55:39 -070034import org.onosproject.net.HostId;
35import org.onosproject.net.HostLocation;
Charles Chan910be6a2017-08-23 14:46:43 -070036import org.onosproject.net.PortNumber;
Charles Chan6c624992017-08-18 17:11:34 -070037import org.onosproject.net.config.NetworkConfigRegistryAdapter;
38import org.onosproject.net.flow.TrafficTreatment;
Charles Chan910be6a2017-08-23 14:46:43 -070039import org.onosproject.net.host.HostEvent;
40import org.onosproject.net.host.HostService;
Charles Chan6c624992017-08-18 17:11:34 -070041import org.onosproject.net.intf.Interface;
Charles Chanf0ae41e2017-08-23 13:55:39 -070042import org.onosproject.net.provider.ProviderId;
Charles Chan6c624992017-08-18 17:11:34 -070043import org.onosproject.routeservice.ResolvedRoute;
44import org.onosproject.routeservice.Route;
45import org.onosproject.routeservice.RouteEvent;
Charles Chan6c624992017-08-18 17:11:34 -070046import org.onosproject.segmentrouting.config.DeviceConfiguration;
Charles Chan910be6a2017-08-23 14:46:43 -070047import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
Charles Chand66d6712018-03-29 16:03:41 -070048import org.onosproject.store.service.StorageService;
49import org.onosproject.store.service.TestConsistentMap;
Charles Chan6c624992017-08-18 17:11:34 -070050
51import java.util.Map;
52import java.util.Set;
53
Charles Chand66d6712018-03-29 16:03:41 -070054import static org.easymock.EasyMock.expect;
Charles Chan06f626c2018-02-05 17:20:05 -080055import static org.easymock.EasyMock.reset;
Charles Chan6c624992017-08-18 17:11:34 -070056import static org.junit.Assert.*;
Charles Chan06f626c2018-02-05 17:20:05 -080057import static org.easymock.EasyMock.createMock;
58import static org.easymock.EasyMock.expectLastCall;
59import static org.easymock.EasyMock.replay;
60import static org.easymock.EasyMock.verify;
Charles Chan6c624992017-08-18 17:11:34 -070061
62/**
63 * Unit test for {@link RouteHandler}.
64 */
65public class RouteHandlerTest {
Charles Chan06f626c2018-02-05 17:20:05 -080066 private SegmentRoutingManager srManager;
Charles Chan6c624992017-08-18 17:11:34 -070067 private RouteHandler routeHandler;
Charles Chan910be6a2017-08-23 14:46:43 -070068 private HostService hostService;
Charles Chan6c624992017-08-18 17:11:34 -070069
70 // Mocked routing and bridging tables
71 private static final Map<MockBridgingTableKey, MockBridgingTableValue> BRIDGING_TABLE =
72 Maps.newConcurrentMap();
73 private static final Map<MockRoutingTableKey, MockRoutingTableValue> ROUTING_TABLE =
74 Maps.newConcurrentMap();
75 private static final Map<ConnectPoint, Set<IpPrefix>> SUBNET_TABLE = Maps.newConcurrentMap();
76 // Mocked Next Id
77 private static final Map<Integer, TrafficTreatment> NEXT_TABLE = Maps.newConcurrentMap();
78
79 private static final IpPrefix P1 = IpPrefix.valueOf("10.0.0.0/24");
Charles Chan910be6a2017-08-23 14:46:43 -070080
81 // Single homed router 1
Charles Chan6c624992017-08-18 17:11:34 -070082 private static final IpAddress N1 = IpAddress.valueOf("10.0.1.254");
83 private static final MacAddress M1 = MacAddress.valueOf("00:00:00:00:00:01");
84 private static final VlanId V1 = VlanId.vlanId((short) 1);
85 private static final ConnectPoint CP1 = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
86 private static final Route R1 = new Route(Route.Source.STATIC, P1, N1);
Charles Chanf0ae41e2017-08-23 13:55:39 -070087 private static final ResolvedRoute RR1 = new ResolvedRoute(R1, M1, V1);
Charles Chan6c624992017-08-18 17:11:34 -070088
Charles Chan910be6a2017-08-23 14:46:43 -070089 // Single homed router 2
Charles Chan6c624992017-08-18 17:11:34 -070090 private static final IpAddress N2 = IpAddress.valueOf("10.0.2.254");
91 private static final MacAddress M2 = MacAddress.valueOf("00:00:00:00:00:02");
92 private static final VlanId V2 = VlanId.vlanId((short) 2);
Charles Chan910be6a2017-08-23 14:46:43 -070093 private static final ConnectPoint CP2 = ConnectPoint.deviceConnectPoint("of:0000000000000002/2");
Charles Chan6c624992017-08-18 17:11:34 -070094 private static final Route R2 = new Route(Route.Source.STATIC, P1, N2);
Charles Chanf0ae41e2017-08-23 13:55:39 -070095 private static final ResolvedRoute RR2 = new ResolvedRoute(R2, M2, V2);
Charles Chan6c624992017-08-18 17:11:34 -070096
Charles Chan910be6a2017-08-23 14:46:43 -070097 // Dual homed router 1
98 private static final IpAddress N3 = IpAddress.valueOf("10.0.3.254");
99 private static final MacAddress M3 = MacAddress.valueOf("00:00:00:00:00:03");
100 private static final VlanId V3 = VlanId.vlanId((short) 3);
101 private static final Route R3 = new Route(Route.Source.STATIC, P1, N3);
102 private static final ResolvedRoute RR3 = new ResolvedRoute(R3, M3, V3);
Charles Chan6c624992017-08-18 17:11:34 -0700103
Charles Chan482b6422018-04-09 11:52:08 -0400104 // Single homed router 3
105 private static final IpAddress N4 = IpAddress.valueOf("10.0.4.254");
106 private static final MacAddress M4 = MacAddress.valueOf("00:00:00:00:00:04");
107 private static final VlanId V4 = VlanId.vlanId((short) 4);
108 private static final ConnectPoint CP4 = ConnectPoint.deviceConnectPoint("of:0000000000000004/4");
109 private static final Route R4 = new Route(Route.Source.STATIC, P1, N4);
110 private static final ResolvedRoute RR4 = new ResolvedRoute(R4, M4, V4);
111
Charles Chan910be6a2017-08-23 14:46:43 -0700112 // Hosts
Charles Chanf0ae41e2017-08-23 13:55:39 -0700113 private static final Host H1 = new DefaultHost(ProviderId.NONE, HostId.hostId(M1, V1), M1, V1,
114 Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N1), false);
115 private static final Host H2 = new DefaultHost(ProviderId.NONE, HostId.hostId(M2, V2), M2, V2,
116 Sets.newHashSet(new HostLocation(CP2, 0)), Sets.newHashSet(N2), false);
Charles Chan910be6a2017-08-23 14:46:43 -0700117 private static final Host H3D = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
118 Sets.newHashSet(new HostLocation(CP1, 0), new HostLocation(CP2, 0)), Sets.newHashSet(N3), false);
119 private static final Host H3S = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
120 Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N3), false);
Charles Chan482b6422018-04-09 11:52:08 -0400121 private static final Host H4 = new DefaultHost(ProviderId.NONE, HostId.hostId(M4, V4), M4, V4,
122 Sets.newHashSet(new HostLocation(CP4, 0)), Sets.newHashSet(N4), false);
Charles Chan910be6a2017-08-23 14:46:43 -0700123
124 // Pair Local Port
125 private static final PortNumber P9 = PortNumber.portNumber(9);
Charles Chanf0ae41e2017-08-23 13:55:39 -0700126
Charles Chan6c624992017-08-18 17:11:34 -0700127 // A set of hosts
Charles Chan482b6422018-04-09 11:52:08 -0400128 private static final Set<Host> HOSTS = Sets.newHashSet(H1, H2, H3D, H4);
Charles Chan910be6a2017-08-23 14:46:43 -0700129 private static final Set<Host> HOSTS_ONE_FAIL = Sets.newHashSet(H1, H2, H3S);
130 private static final Set<Host> HOSTS_BOTH_FAIL = Sets.newHashSet(H1, H2);
Charles Chan6c624992017-08-18 17:11:34 -0700131 // A set of devices of which we have mastership
Charles Chan910be6a2017-08-23 14:46:43 -0700132 private static final Set<DeviceId> LOCAL_DEVICES = Sets.newHashSet(CP1.deviceId(), CP2.deviceId());
Charles Chan6c624992017-08-18 17:11:34 -0700133 // A set of interfaces
134 private static final Set<Interface> INTERFACES = Sets.newHashSet();
Charles Chan6c624992017-08-18 17:11:34 -0700135
136 @Before
Charles Chan482b6422018-04-09 11:52:08 -0400137 public void setUp() {
Charles Chan910be6a2017-08-23 14:46:43 -0700138 ObjectMapper mapper = new ObjectMapper();
139 ConfigApplyDelegate delegate = config -> { };
140
141 SegmentRoutingDeviceConfig dev1Config = new SegmentRoutingDeviceConfig();
142 JsonNode dev1Tree = mapper.createObjectNode();
143 dev1Config.init(CP1.deviceId(), "host-handler-test", dev1Tree, mapper, delegate);
144 dev1Config.setPairDeviceId(CP2.deviceId()).setPairLocalPort(P9);
145
146 SegmentRoutingDeviceConfig dev2Config = new SegmentRoutingDeviceConfig();
147 JsonNode dev2Tree = mapper.createObjectNode();
148 dev2Config.init(CP2.deviceId(), "host-handler-test", dev2Tree, mapper, delegate);
149 dev2Config.setPairDeviceId(CP1.deviceId()).setPairLocalPort(P9);
Charles Chan6c624992017-08-18 17:11:34 -0700150
151 MockNetworkConfigRegistry mockNetworkConfigRegistry = new MockNetworkConfigRegistry();
Charles Chan910be6a2017-08-23 14:46:43 -0700152 mockNetworkConfigRegistry.applyConfig(dev1Config);
153 mockNetworkConfigRegistry.applyConfig(dev2Config);
Charles Chan6c624992017-08-18 17:11:34 -0700154
155 // Initialize Segment Routing Manager
Charles Chan06f626c2018-02-05 17:20:05 -0800156 srManager = new MockSegmentRoutingManager(NEXT_TABLE);
Charles Chand66d6712018-03-29 16:03:41 -0700157 srManager.storageService = createMock(StorageService.class);
158 expect(srManager.storageService.consistentMapBuilder()).andReturn(new TestConsistentMap.Builder<>()).anyTimes();
159 replay(srManager.storageService);
Charles Chan6c624992017-08-18 17:11:34 -0700160 srManager.cfgService = new NetworkConfigRegistryAdapter();
Charles Chan06f626c2018-02-05 17:20:05 -0800161 srManager.deviceConfiguration = createMock(DeviceConfiguration.class);
Charles Chan6c624992017-08-18 17:11:34 -0700162 srManager.flowObjectiveService = new MockFlowObjectiveService(BRIDGING_TABLE, NEXT_TABLE);
163 srManager.routingRulePopulator = new MockRoutingRulePopulator(srManager, ROUTING_TABLE);
Charles Chanc4d68882018-03-15 16:41:10 -0700164 srManager.defaultRoutingHandler = new MockDefaultRoutingHandler(srManager, SUBNET_TABLE, ROUTING_TABLE);
Charles Chan6c624992017-08-18 17:11:34 -0700165 srManager.interfaceService = new MockInterfaceService(INTERFACES);
166 srManager.mastershipService = new MockMastershipService(LOCAL_DEVICES);
Charles Chan910be6a2017-08-23 14:46:43 -0700167 hostService = new MockHostService(HOSTS);
168 srManager.hostService = hostService;
Charles Chan6c624992017-08-18 17:11:34 -0700169 srManager.cfgService = mockNetworkConfigRegistry;
Charles Chan910be6a2017-08-23 14:46:43 -0700170 srManager.routeService = new MockRouteService(ROUTING_TABLE);
Charles Chan6c624992017-08-18 17:11:34 -0700171
Charles Chan910be6a2017-08-23 14:46:43 -0700172 routeHandler = new RouteHandler(srManager) {
173 // routeEventCache is not necessary for unit tests
174 @Override
175 void enqueueRouteEvent(RouteEvent routeEvent) {
176 dequeueRouteEvent(routeEvent);
177 }
178 };
Charles Chan6c624992017-08-18 17:11:34 -0700179
180 ROUTING_TABLE.clear();
181 BRIDGING_TABLE.clear();
182 SUBNET_TABLE.clear();
183 }
184
185 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400186 public void init() {
Charles Chan910be6a2017-08-23 14:46:43 -0700187 MockRoutingTableKey rtk = new MockRoutingTableKey(CP1.deviceId(), P1);
188 MockRoutingTableValue rtv = new MockRoutingTableValue(CP1.port(), M1, V1);
189 ROUTING_TABLE.put(rtk, rtv);
190
Charles Chan6c624992017-08-18 17:11:34 -0700191 routeHandler.init(CP1.deviceId());
192
193 assertEquals(1, ROUTING_TABLE.size());
Charles Chanf0ae41e2017-08-23 13:55:39 -0700194 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
195 assertEquals(M1, rtv1.macAddress);
196 assertEquals(V1, rtv1.vlanId);
197 assertEquals(CP1.port(), rtv1.portNumber);
198
Charles Chan6c624992017-08-18 17:11:34 -0700199 assertEquals(1, SUBNET_TABLE.size());
200 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
201 }
202
203 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400204 public void processRouteAdded() {
Charles Chan06f626c2018-02-05 17:20:05 -0800205 reset(srManager.deviceConfiguration);
206 srManager.deviceConfiguration.addSubnet(CP1, P1);
207 expectLastCall().once();
208 replay(srManager.deviceConfiguration);
209
Charles Chan910be6a2017-08-23 14:46:43 -0700210 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1));
Charles Chan6c624992017-08-18 17:11:34 -0700211 routeHandler.processRouteAdded(re);
212
213 assertEquals(1, ROUTING_TABLE.size());
Charles Chanf0ae41e2017-08-23 13:55:39 -0700214 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
215 assertEquals(M1, rtv1.macAddress);
216 assertEquals(V1, rtv1.vlanId);
217 assertEquals(CP1.port(), rtv1.portNumber);
218
Charles Chan6c624992017-08-18 17:11:34 -0700219 assertEquals(1, SUBNET_TABLE.size());
220 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800221
222 verify(srManager.deviceConfiguration);
Charles Chan6c624992017-08-18 17:11:34 -0700223 }
224
225 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400226 public void processRouteUpdated() {
Charles Chan6c624992017-08-18 17:11:34 -0700227 processRouteAdded();
228
Charles Chan06f626c2018-02-05 17:20:05 -0800229 reset(srManager.deviceConfiguration);
230 srManager.deviceConfiguration.removeSubnet(CP1, P1);
231 expectLastCall().once();
232 srManager.deviceConfiguration.addSubnet(CP2, P1);
233 expectLastCall().once();
234 replay(srManager.deviceConfiguration);
235
Charles Chan910be6a2017-08-23 14:46:43 -0700236 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_UPDATED, RR2, RR1, Sets.newHashSet(RR2),
237 Sets.newHashSet(RR1));
Charles Chan6c624992017-08-18 17:11:34 -0700238 routeHandler.processRouteUpdated(re);
239
Charles Chan06f626c2018-02-05 17:20:05 -0800240 // Note: We shouldn't remove the old nexthop during the occasion of route update
241 // since the populate subnet will take care of it and point it to an ECMP group
242 assertEquals(2, ROUTING_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700243 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
Charles Chanf0ae41e2017-08-23 13:55:39 -0700244 assertEquals(M2, rtv2.macAddress);
245 assertEquals(V2, rtv2.vlanId);
246 assertEquals(CP2.port(), rtv2.portNumber);
247
Charles Chan6c624992017-08-18 17:11:34 -0700248 assertEquals(1, SUBNET_TABLE.size());
249 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800250
251 verify(srManager.deviceConfiguration);
Charles Chan6c624992017-08-18 17:11:34 -0700252 }
253
254 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400255 public void processRouteRemoved() {
Charles Chan6c624992017-08-18 17:11:34 -0700256 processRouteAdded();
257
Charles Chan06f626c2018-02-05 17:20:05 -0800258 reset(srManager.deviceConfiguration);
259 srManager.deviceConfiguration.removeSubnet(CP1, P1);
260 expectLastCall().once();
261 replay(srManager.deviceConfiguration);
262
Charles Chan910be6a2017-08-23 14:46:43 -0700263 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1));
264 routeHandler.processRouteRemoved(re);
265
266 assertEquals(0, ROUTING_TABLE.size());
267 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800268
269 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700270 }
271
272 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400273 public void testTwoSingleHomedAdded() {
Charles Chan06f626c2018-02-05 17:20:05 -0800274 reset(srManager.deviceConfiguration);
275 srManager.deviceConfiguration.addSubnet(CP1, P1);
276 expectLastCall().once();
277 srManager.deviceConfiguration.addSubnet(CP2, P1);
278 expectLastCall().once();
279 replay(srManager.deviceConfiguration);
280
Charles Chan910be6a2017-08-23 14:46:43 -0700281 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
282 routeHandler.processRouteAdded(re);
283
284 assertEquals(2, ROUTING_TABLE.size());
285 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
286 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
287 assertEquals(M1, rtv1.macAddress);
288 assertEquals(M2, rtv2.macAddress);
289 assertEquals(V1, rtv1.vlanId);
290 assertEquals(V2, rtv2.vlanId);
291 assertEquals(CP1.port(), rtv1.portNumber);
292 assertEquals(CP2.port(), rtv2.portNumber);
293
294 assertEquals(2, SUBNET_TABLE.size());
295 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
296 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800297
298 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700299 }
300
301 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400302 public void testOneDualHomedAdded() {
Charles Chan06f626c2018-02-05 17:20:05 -0800303 reset(srManager.deviceConfiguration);
304 srManager.deviceConfiguration.addSubnet(CP1, P1);
305 expectLastCall().once();
306 srManager.deviceConfiguration.addSubnet(CP2, P1);
307 expectLastCall().once();
308 replay(srManager.deviceConfiguration);
309
Charles Chan910be6a2017-08-23 14:46:43 -0700310 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR3, Sets.newHashSet(RR3));
311 routeHandler.processRouteAdded(re);
312
313 assertEquals(2, ROUTING_TABLE.size());
314 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
315 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
316 assertEquals(M3, rtv1.macAddress);
317 assertEquals(M3, rtv2.macAddress);
318 assertEquals(V3, rtv1.vlanId);
319 assertEquals(V3, rtv2.vlanId);
320 assertEquals(CP1.port(), rtv1.portNumber);
321 assertEquals(CP2.port(), rtv2.portNumber);
322
323 assertEquals(2, SUBNET_TABLE.size());
324 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
325 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800326
327 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700328 }
329
330 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400331 public void testOneSingleHomedToTwoSingleHomed() {
Charles Chan910be6a2017-08-23 14:46:43 -0700332 processRouteAdded();
333
Charles Chan06f626c2018-02-05 17:20:05 -0800334 reset(srManager.deviceConfiguration);
335 srManager.deviceConfiguration.addSubnet(CP2, P1);
336 expectLastCall().once();
337 replay(srManager.deviceConfiguration);
338
Charles Chan910be6a2017-08-23 14:46:43 -0700339 RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
340 Sets.newHashSet(RR1, RR2), Sets.newHashSet(RR1));
341 routeHandler.processAlternativeRoutesChanged(re);
342
343 assertEquals(2, ROUTING_TABLE.size());
344 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
345 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
346 assertEquals(M1, rtv1.macAddress);
347 assertEquals(M2, rtv2.macAddress);
348 assertEquals(V1, rtv1.vlanId);
349 assertEquals(V2, rtv2.vlanId);
350 assertEquals(CP1.port(), rtv1.portNumber);
351 assertEquals(CP2.port(), rtv2.portNumber);
352
353 assertEquals(2, SUBNET_TABLE.size());
354 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
355 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800356
357 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700358 }
359
360 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400361 public void testTwoSingleHomedToOneSingleHomed() {
Charles Chan910be6a2017-08-23 14:46:43 -0700362 testTwoSingleHomedAdded();
363
Charles Chan06f626c2018-02-05 17:20:05 -0800364 reset(srManager.deviceConfiguration);
365 srManager.deviceConfiguration.removeSubnet(CP2, P1);
366 expectLastCall().once();
367 replay(srManager.deviceConfiguration);
368
Charles Chan910be6a2017-08-23 14:46:43 -0700369 RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
370 Sets.newHashSet(RR1), Sets.newHashSet(RR1, RR2));
371 routeHandler.processAlternativeRoutesChanged(re);
372
Charles Chan06f626c2018-02-05 17:20:05 -0800373 // Note: We shouldn't remove the old nexthop during the occasion of route update
374 // since the populate subnet will take care of it and point it to an ECMP group
375 assertEquals(2, ROUTING_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700376 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
377 assertEquals(M1, rtv1.macAddress);
378 assertEquals(V1, rtv1.vlanId);
379 assertEquals(CP1.port(), rtv1.portNumber);
380
381 assertEquals(1, SUBNET_TABLE.size());
382 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800383
384 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700385 }
386
Charles Chan06f626c2018-02-05 17:20:05 -0800387 // TODO Add test cases for two single homed next hop at same location
388
Charles Chan910be6a2017-08-23 14:46:43 -0700389 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400390 public void testDualHomedSingleLocationFail() {
Charles Chan910be6a2017-08-23 14:46:43 -0700391 testOneDualHomedAdded();
392
393 HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3S, H3D);
394 routeHandler.processHostMovedEvent(he);
395
396 assertEquals(2, ROUTING_TABLE.size());
397 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
398 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
399 assertEquals(M3, rtv1.macAddress);
400 assertEquals(M3, rtv2.macAddress);
401 assertEquals(V3, rtv1.vlanId);
402 assertEquals(V3, rtv2.vlanId);
403 assertEquals(CP1.port(), rtv1.portNumber);
404 assertEquals(P9, rtv2.portNumber);
405
406 // ECMP route table hasn't changed
407 assertEquals(2, SUBNET_TABLE.size());
408 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
409 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
410 }
411
412 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400413 public void testDualHomedBothLocationFail() {
Charles Chan910be6a2017-08-23 14:46:43 -0700414 testDualHomedSingleLocationFail();
415
416 hostService = new MockHostService(HOSTS_ONE_FAIL);
417
Charles Chan06f626c2018-02-05 17:20:05 -0800418 reset(srManager.deviceConfiguration);
419 srManager.deviceConfiguration.removeSubnet(CP1, P1);
420 expectLastCall().once();
421 srManager.deviceConfiguration.removeSubnet(CP2, P1);
422 expectLastCall().once();
423 replay(srManager.deviceConfiguration);
424
Charles Chan910be6a2017-08-23 14:46:43 -0700425 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
426 routeHandler.processRouteRemoved(re);
427
428 assertEquals(0, ROUTING_TABLE.size());
429 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800430
431 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700432 }
433
434 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400435 public void testTwoSingleHomedRemoved() {
Charles Chan910be6a2017-08-23 14:46:43 -0700436 testTwoSingleHomedAdded();
437
438 hostService = new MockHostService(HOSTS_BOTH_FAIL);
439
Charles Chan06f626c2018-02-05 17:20:05 -0800440 reset(srManager.deviceConfiguration);
441 srManager.deviceConfiguration.removeSubnet(CP1, P1);
442 expectLastCall().once();
443 srManager.deviceConfiguration.removeSubnet(CP2, P1);
444 expectLastCall().once();
445 replay(srManager.deviceConfiguration);
446
Charles Chan910be6a2017-08-23 14:46:43 -0700447 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1, RR2));
448 routeHandler.processRouteRemoved(re);
449
450 assertEquals(0, ROUTING_TABLE.size());
451 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800452
453 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700454 }
455
456 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400457 public void testOneDualHomeRemoved() {
Charles Chan910be6a2017-08-23 14:46:43 -0700458 testOneDualHomedAdded();
459
Charles Chan06f626c2018-02-05 17:20:05 -0800460 reset(srManager.deviceConfiguration);
461 srManager.deviceConfiguration.removeSubnet(CP1, P1);
462 expectLastCall().once();
463 srManager.deviceConfiguration.removeSubnet(CP2, P1);
464 expectLastCall().once();
465 replay(srManager.deviceConfiguration);
466
Charles Chan910be6a2017-08-23 14:46:43 -0700467 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
Charles Chan6c624992017-08-18 17:11:34 -0700468 routeHandler.processRouteRemoved(re);
469
470 assertEquals(0, ROUTING_TABLE.size());
471 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800472
473 verify(srManager.deviceConfiguration);
Charles Chan6c624992017-08-18 17:11:34 -0700474 }
Charles Chan482b6422018-04-09 11:52:08 -0400475
476 @Test
477 public void testMoreThanTwoNextHop() {
478 // next hop = CP1, CP2
479 reset(srManager.deviceConfiguration);
480 srManager.deviceConfiguration.addSubnet(CP1, P1);
481 srManager.deviceConfiguration.addSubnet(CP2, P1);
482 expectLastCall().once();
483 replay(srManager.deviceConfiguration);
484
485 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
486 routeHandler.processRouteAdded(re);
487
488 assertEquals(2, ROUTING_TABLE.size());
489 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
490 assertEquals(M1, rtv1.macAddress);
491 assertEquals(V1, rtv1.vlanId);
492 assertEquals(CP1.port(), rtv1.portNumber);
493 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
494 assertEquals(M2, rtv2.macAddress);
495 assertEquals(V2, rtv2.vlanId);
496 assertEquals(CP2.port(), rtv2.portNumber);
497
498 assertEquals(2, SUBNET_TABLE.size());
499 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
500 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
501
502 verify(srManager.deviceConfiguration);
503
504 // next hop = CP1, CP2, CP4 (invalid)
505 re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
506 Sets.newHashSet(RR1, RR2, RR4), Sets.newHashSet(RR1, RR2));
507 routeHandler.processAlternativeRoutesChanged(re);
508
509 assertEquals(2, ROUTING_TABLE.size());
510 rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
511 assertEquals(M1, rtv1.macAddress);
512 assertEquals(V1, rtv1.vlanId);
513 assertEquals(CP1.port(), rtv1.portNumber);
514 rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
515 assertEquals(M2, rtv2.macAddress);
516 assertEquals(V2, rtv2.vlanId);
517 assertEquals(CP2.port(), rtv2.portNumber);
518
519 assertEquals(2, SUBNET_TABLE.size());
520 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
521 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
522
523 // next hop = CP2, CP4
524 reset(srManager.deviceConfiguration);
525 srManager.deviceConfiguration.addSubnet(CP2, P1);
526 srManager.deviceConfiguration.addSubnet(CP4, P1);
527 expectLastCall().once();
528 replay(srManager.deviceConfiguration);
529
530 re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
531 Sets.newHashSet(RR2, RR4), Sets.newHashSet(RR1, RR2, RR4));
532 routeHandler.processAlternativeRoutesChanged(re);
533
534 assertEquals(2, ROUTING_TABLE.size());
535 rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
536 assertEquals(M2, rtv1.macAddress);
537 assertEquals(V2, rtv1.vlanId);
538 assertEquals(CP2.port(), rtv1.portNumber);
539 rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP4.deviceId(), P1));
540 assertEquals(M4, rtv2.macAddress);
541 assertEquals(V4, rtv2.vlanId);
542 assertEquals(CP4.port(), rtv2.portNumber);
543
544 assertEquals(2, SUBNET_TABLE.size());
545 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
546 assertTrue(SUBNET_TABLE.get(CP4).contains(P1));
547
548 verify(srManager.deviceConfiguration);
549 }
Charles Chan6c624992017-08-18 17:11:34 -0700550}