blob: 2d365a2e4588b394ae8871c3f595c62071a04e03 [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 Chan6c624992017-08-18 17:11:34 -070042import org.onosproject.net.intf.Interface;
Charles Chanf0ae41e2017-08-23 13:55:39 -070043import org.onosproject.net.provider.ProviderId;
Charles Chan6c624992017-08-18 17:11:34 -070044import org.onosproject.routeservice.ResolvedRoute;
45import org.onosproject.routeservice.Route;
46import org.onosproject.routeservice.RouteEvent;
Charles Chan6c624992017-08-18 17:11:34 -070047import org.onosproject.segmentrouting.config.DeviceConfiguration;
Charles Chan910be6a2017-08-23 14:46:43 -070048import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
Charles Chand66d6712018-03-29 16:03:41 -070049import org.onosproject.store.service.StorageService;
50import org.onosproject.store.service.TestConsistentMap;
Charles Chan6c624992017-08-18 17:11:34 -070051
52import java.util.Map;
53import java.util.Set;
54
Charles Chand66d6712018-03-29 16:03:41 -070055import static org.easymock.EasyMock.expect;
Charles Chan06f626c2018-02-05 17:20:05 -080056import static org.easymock.EasyMock.reset;
Charles Chan6c624992017-08-18 17:11:34 -070057import static org.junit.Assert.*;
Charles Chan06f626c2018-02-05 17:20:05 -080058import static org.easymock.EasyMock.createMock;
59import static org.easymock.EasyMock.expectLastCall;
60import static org.easymock.EasyMock.replay;
61import static org.easymock.EasyMock.verify;
Charles Chan6c624992017-08-18 17:11:34 -070062
63/**
64 * Unit test for {@link RouteHandler}.
65 */
66public class RouteHandlerTest {
Charles Chan06f626c2018-02-05 17:20:05 -080067 private SegmentRoutingManager srManager;
Charles Chan6c624992017-08-18 17:11:34 -070068 private RouteHandler routeHandler;
Charles Chan910be6a2017-08-23 14:46:43 -070069 private HostService hostService;
Charles Chan6c624992017-08-18 17:11:34 -070070
71 // Mocked routing and bridging tables
72 private static final Map<MockBridgingTableKey, MockBridgingTableValue> BRIDGING_TABLE =
73 Maps.newConcurrentMap();
74 private static final Map<MockRoutingTableKey, MockRoutingTableValue> ROUTING_TABLE =
75 Maps.newConcurrentMap();
76 private static final Map<ConnectPoint, Set<IpPrefix>> SUBNET_TABLE = Maps.newConcurrentMap();
77 // Mocked Next Id
78 private static final Map<Integer, TrafficTreatment> NEXT_TABLE = Maps.newConcurrentMap();
Charles Chan7d20a4e2018-04-13 14:01:49 -040079 private static final Map<IpPrefix, Set<ResolvedRoute>> ROUTE_STORE = Maps.newConcurrentMap();
Charles Chan6c624992017-08-18 17:11:34 -070080
81 private static final IpPrefix P1 = IpPrefix.valueOf("10.0.0.0/24");
Charles Chan910be6a2017-08-23 14:46:43 -070082
83 // Single homed router 1
Charles Chan6c624992017-08-18 17:11:34 -070084 private static final IpAddress N1 = IpAddress.valueOf("10.0.1.254");
85 private static final MacAddress M1 = MacAddress.valueOf("00:00:00:00:00:01");
86 private static final VlanId V1 = VlanId.vlanId((short) 1);
87 private static final ConnectPoint CP1 = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
88 private static final Route R1 = new Route(Route.Source.STATIC, P1, N1);
Charles Chanf0ae41e2017-08-23 13:55:39 -070089 private static final ResolvedRoute RR1 = new ResolvedRoute(R1, M1, V1);
Charles Chan6c624992017-08-18 17:11:34 -070090
Charles Chan910be6a2017-08-23 14:46:43 -070091 // Single homed router 2
Charles Chan6c624992017-08-18 17:11:34 -070092 private static final IpAddress N2 = IpAddress.valueOf("10.0.2.254");
93 private static final MacAddress M2 = MacAddress.valueOf("00:00:00:00:00:02");
94 private static final VlanId V2 = VlanId.vlanId((short) 2);
Charles Chan910be6a2017-08-23 14:46:43 -070095 private static final ConnectPoint CP2 = ConnectPoint.deviceConnectPoint("of:0000000000000002/2");
Charles Chan6c624992017-08-18 17:11:34 -070096 private static final Route R2 = new Route(Route.Source.STATIC, P1, N2);
Charles Chanf0ae41e2017-08-23 13:55:39 -070097 private static final ResolvedRoute RR2 = new ResolvedRoute(R2, M2, V2);
Charles Chan6c624992017-08-18 17:11:34 -070098
Charles Chan910be6a2017-08-23 14:46:43 -070099 // Dual homed router 1
100 private static final IpAddress N3 = IpAddress.valueOf("10.0.3.254");
101 private static final MacAddress M3 = MacAddress.valueOf("00:00:00:00:00:03");
102 private static final VlanId V3 = VlanId.vlanId((short) 3);
103 private static final Route R3 = new Route(Route.Source.STATIC, P1, N3);
104 private static final ResolvedRoute RR3 = new ResolvedRoute(R3, M3, V3);
Charles Chan6c624992017-08-18 17:11:34 -0700105
Charles Chan482b6422018-04-09 11:52:08 -0400106 // Single homed router 3
107 private static final IpAddress N4 = IpAddress.valueOf("10.0.4.254");
108 private static final MacAddress M4 = MacAddress.valueOf("00:00:00:00:00:04");
109 private static final VlanId V4 = VlanId.vlanId((short) 4);
110 private static final ConnectPoint CP4 = ConnectPoint.deviceConnectPoint("of:0000000000000004/4");
111 private static final Route R4 = new Route(Route.Source.STATIC, P1, N4);
112 private static final ResolvedRoute RR4 = new ResolvedRoute(R4, M4, V4);
113
Charles Chan910be6a2017-08-23 14:46:43 -0700114 // Hosts
Charles Chanf0ae41e2017-08-23 13:55:39 -0700115 private static final Host H1 = new DefaultHost(ProviderId.NONE, HostId.hostId(M1, V1), M1, V1,
116 Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N1), false);
117 private static final Host H2 = new DefaultHost(ProviderId.NONE, HostId.hostId(M2, V2), M2, V2,
118 Sets.newHashSet(new HostLocation(CP2, 0)), Sets.newHashSet(N2), false);
Charles Chan910be6a2017-08-23 14:46:43 -0700119 private static final Host H3D = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
120 Sets.newHashSet(new HostLocation(CP1, 0), new HostLocation(CP2, 0)), Sets.newHashSet(N3), false);
121 private static final Host H3S = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
122 Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N3), false);
Charles Chan482b6422018-04-09 11:52:08 -0400123 private static final Host H4 = new DefaultHost(ProviderId.NONE, HostId.hostId(M4, V4), M4, V4,
124 Sets.newHashSet(new HostLocation(CP4, 0)), Sets.newHashSet(N4), false);
Charles Chan910be6a2017-08-23 14:46:43 -0700125
126 // Pair Local Port
127 private static final PortNumber P9 = PortNumber.portNumber(9);
Charles Chanf0ae41e2017-08-23 13:55:39 -0700128
Charles Chan6c624992017-08-18 17:11:34 -0700129 // A set of hosts
Charles Chan482b6422018-04-09 11:52:08 -0400130 private static final Set<Host> HOSTS = Sets.newHashSet(H1, H2, H3D, H4);
Charles Chan910be6a2017-08-23 14:46:43 -0700131 private static final Set<Host> HOSTS_ONE_FAIL = Sets.newHashSet(H1, H2, H3S);
132 private static final Set<Host> HOSTS_BOTH_FAIL = Sets.newHashSet(H1, H2);
Charles Chan6c624992017-08-18 17:11:34 -0700133 // A set of devices of which we have mastership
Charles Chan910be6a2017-08-23 14:46:43 -0700134 private static final Set<DeviceId> LOCAL_DEVICES = Sets.newHashSet(CP1.deviceId(), CP2.deviceId());
Charles Chan6c624992017-08-18 17:11:34 -0700135 // A set of interfaces
136 private static final Set<Interface> INTERFACES = Sets.newHashSet();
Charles Chan6c624992017-08-18 17:11:34 -0700137
138 @Before
Charles Chan482b6422018-04-09 11:52:08 -0400139 public void setUp() {
Charles Chan910be6a2017-08-23 14:46:43 -0700140 ObjectMapper mapper = new ObjectMapper();
141 ConfigApplyDelegate delegate = config -> { };
142
143 SegmentRoutingDeviceConfig dev1Config = new SegmentRoutingDeviceConfig();
144 JsonNode dev1Tree = mapper.createObjectNode();
145 dev1Config.init(CP1.deviceId(), "host-handler-test", dev1Tree, mapper, delegate);
146 dev1Config.setPairDeviceId(CP2.deviceId()).setPairLocalPort(P9);
147
148 SegmentRoutingDeviceConfig dev2Config = new SegmentRoutingDeviceConfig();
149 JsonNode dev2Tree = mapper.createObjectNode();
150 dev2Config.init(CP2.deviceId(), "host-handler-test", dev2Tree, mapper, delegate);
151 dev2Config.setPairDeviceId(CP1.deviceId()).setPairLocalPort(P9);
Charles Chan6c624992017-08-18 17:11:34 -0700152
153 MockNetworkConfigRegistry mockNetworkConfigRegistry = new MockNetworkConfigRegistry();
Charles Chan910be6a2017-08-23 14:46:43 -0700154 mockNetworkConfigRegistry.applyConfig(dev1Config);
155 mockNetworkConfigRegistry.applyConfig(dev2Config);
Charles Chan6c624992017-08-18 17:11:34 -0700156
157 // Initialize Segment Routing Manager
Charles Chan06f626c2018-02-05 17:20:05 -0800158 srManager = new MockSegmentRoutingManager(NEXT_TABLE);
Charles Chand66d6712018-03-29 16:03:41 -0700159 srManager.storageService = createMock(StorageService.class);
160 expect(srManager.storageService.consistentMapBuilder()).andReturn(new TestConsistentMap.Builder<>()).anyTimes();
161 replay(srManager.storageService);
Charles Chan6c624992017-08-18 17:11:34 -0700162 srManager.cfgService = new NetworkConfigRegistryAdapter();
Charles Chan06f626c2018-02-05 17:20:05 -0800163 srManager.deviceConfiguration = createMock(DeviceConfiguration.class);
Charles Chan6c624992017-08-18 17:11:34 -0700164 srManager.flowObjectiveService = new MockFlowObjectiveService(BRIDGING_TABLE, NEXT_TABLE);
165 srManager.routingRulePopulator = new MockRoutingRulePopulator(srManager, ROUTING_TABLE);
Charles Chanc4d68882018-03-15 16:41:10 -0700166 srManager.defaultRoutingHandler = new MockDefaultRoutingHandler(srManager, SUBNET_TABLE, ROUTING_TABLE);
Charles Chan6c624992017-08-18 17:11:34 -0700167 srManager.interfaceService = new MockInterfaceService(INTERFACES);
168 srManager.mastershipService = new MockMastershipService(LOCAL_DEVICES);
Charles Chan910be6a2017-08-23 14:46:43 -0700169 hostService = new MockHostService(HOSTS);
170 srManager.hostService = hostService;
Charles Chan6c624992017-08-18 17:11:34 -0700171 srManager.cfgService = mockNetworkConfigRegistry;
Charles Chan7d20a4e2018-04-13 14:01:49 -0400172 srManager.routeService = new MockRouteService(ROUTE_STORE);
Charles Chan6c624992017-08-18 17:11:34 -0700173
Charles Chanfbcb8812018-04-18 18:41:05 -0700174 routeHandler = new RouteHandler(srManager);
Charles Chan6c624992017-08-18 17:11:34 -0700175
176 ROUTING_TABLE.clear();
177 BRIDGING_TABLE.clear();
178 SUBNET_TABLE.clear();
179 }
180
181 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400182 public void init() {
Charles Chan7d20a4e2018-04-13 14:01:49 -0400183 ROUTE_STORE.put(P1, Sets.newHashSet(RR1));
Charles Chan910be6a2017-08-23 14:46:43 -0700184
Charles Chan6c624992017-08-18 17:11:34 -0700185 routeHandler.init(CP1.deviceId());
186
187 assertEquals(1, ROUTING_TABLE.size());
Charles Chanf0ae41e2017-08-23 13:55:39 -0700188 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
189 assertEquals(M1, rtv1.macAddress);
190 assertEquals(V1, rtv1.vlanId);
191 assertEquals(CP1.port(), rtv1.portNumber);
192
Charles Chan6c624992017-08-18 17:11:34 -0700193 assertEquals(1, SUBNET_TABLE.size());
194 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
195 }
196
197 @Test
Charles Chan7d20a4e2018-04-13 14:01:49 -0400198 public void initTwoNextHops() {
199 ROUTE_STORE.put(P1, Sets.newHashSet(RR1, RR2));
200
201 routeHandler.init(CP1.deviceId());
202
203 assertEquals(2, ROUTING_TABLE.size());
204 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
205 assertEquals(M1, rtv1.macAddress);
206 assertEquals(V1, rtv1.vlanId);
207 assertEquals(CP1.port(), rtv1.portNumber);
208 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
209 assertEquals(M2, rtv2.macAddress);
210 assertEquals(V2, rtv2.vlanId);
211 assertEquals(CP2.port(), rtv2.portNumber);
212
213 assertEquals(2, SUBNET_TABLE.size());
214 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
215 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
216 }
217
218 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400219 public void processRouteAdded() {
Charles Chan06f626c2018-02-05 17:20:05 -0800220 reset(srManager.deviceConfiguration);
221 srManager.deviceConfiguration.addSubnet(CP1, P1);
222 expectLastCall().once();
223 replay(srManager.deviceConfiguration);
224
Charles Chan910be6a2017-08-23 14:46:43 -0700225 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1));
Charles Chan6c624992017-08-18 17:11:34 -0700226 routeHandler.processRouteAdded(re);
227
228 assertEquals(1, ROUTING_TABLE.size());
Charles Chanf0ae41e2017-08-23 13:55:39 -0700229 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
230 assertEquals(M1, rtv1.macAddress);
231 assertEquals(V1, rtv1.vlanId);
232 assertEquals(CP1.port(), rtv1.portNumber);
233
Charles Chan6c624992017-08-18 17:11:34 -0700234 assertEquals(1, SUBNET_TABLE.size());
235 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800236
237 verify(srManager.deviceConfiguration);
Charles Chan6c624992017-08-18 17:11:34 -0700238 }
239
240 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400241 public void processRouteUpdated() {
Charles Chan6c624992017-08-18 17:11:34 -0700242 processRouteAdded();
243
Charles Chan06f626c2018-02-05 17:20:05 -0800244 reset(srManager.deviceConfiguration);
245 srManager.deviceConfiguration.removeSubnet(CP1, P1);
246 expectLastCall().once();
247 srManager.deviceConfiguration.addSubnet(CP2, P1);
248 expectLastCall().once();
249 replay(srManager.deviceConfiguration);
250
Charles Chan910be6a2017-08-23 14:46:43 -0700251 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_UPDATED, RR2, RR1, Sets.newHashSet(RR2),
252 Sets.newHashSet(RR1));
Charles Chan6c624992017-08-18 17:11:34 -0700253 routeHandler.processRouteUpdated(re);
254
Charles Chan06f626c2018-02-05 17:20:05 -0800255 // Note: We shouldn't remove the old nexthop during the occasion of route update
256 // since the populate subnet will take care of it and point it to an ECMP group
257 assertEquals(2, ROUTING_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700258 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
Charles Chanf0ae41e2017-08-23 13:55:39 -0700259 assertEquals(M2, rtv2.macAddress);
260 assertEquals(V2, rtv2.vlanId);
261 assertEquals(CP2.port(), rtv2.portNumber);
262
Charles Chan6c624992017-08-18 17:11:34 -0700263 assertEquals(1, SUBNET_TABLE.size());
264 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800265
266 verify(srManager.deviceConfiguration);
Charles Chan6c624992017-08-18 17:11:34 -0700267 }
268
269 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400270 public void processRouteRemoved() {
Charles Chan6c624992017-08-18 17:11:34 -0700271 processRouteAdded();
272
Charles Chan06f626c2018-02-05 17:20:05 -0800273 reset(srManager.deviceConfiguration);
274 srManager.deviceConfiguration.removeSubnet(CP1, P1);
275 expectLastCall().once();
276 replay(srManager.deviceConfiguration);
277
Charles Chan910be6a2017-08-23 14:46:43 -0700278 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1));
279 routeHandler.processRouteRemoved(re);
280
281 assertEquals(0, ROUTING_TABLE.size());
282 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800283
284 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700285 }
286
287 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400288 public void testTwoSingleHomedAdded() {
Charles Chan06f626c2018-02-05 17:20:05 -0800289 reset(srManager.deviceConfiguration);
290 srManager.deviceConfiguration.addSubnet(CP1, P1);
291 expectLastCall().once();
292 srManager.deviceConfiguration.addSubnet(CP2, P1);
293 expectLastCall().once();
294 replay(srManager.deviceConfiguration);
295
Charles Chan910be6a2017-08-23 14:46:43 -0700296 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
297 routeHandler.processRouteAdded(re);
298
299 assertEquals(2, ROUTING_TABLE.size());
300 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
301 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
302 assertEquals(M1, rtv1.macAddress);
303 assertEquals(M2, rtv2.macAddress);
304 assertEquals(V1, rtv1.vlanId);
305 assertEquals(V2, rtv2.vlanId);
306 assertEquals(CP1.port(), rtv1.portNumber);
307 assertEquals(CP2.port(), rtv2.portNumber);
308
309 assertEquals(2, SUBNET_TABLE.size());
310 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
311 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800312
313 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700314 }
315
316 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400317 public void testOneDualHomedAdded() {
Charles Chan06f626c2018-02-05 17:20:05 -0800318 reset(srManager.deviceConfiguration);
319 srManager.deviceConfiguration.addSubnet(CP1, P1);
320 expectLastCall().once();
321 srManager.deviceConfiguration.addSubnet(CP2, P1);
322 expectLastCall().once();
323 replay(srManager.deviceConfiguration);
324
Charles Chan910be6a2017-08-23 14:46:43 -0700325 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR3, Sets.newHashSet(RR3));
326 routeHandler.processRouteAdded(re);
327
328 assertEquals(2, ROUTING_TABLE.size());
329 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
330 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
331 assertEquals(M3, rtv1.macAddress);
332 assertEquals(M3, rtv2.macAddress);
333 assertEquals(V3, rtv1.vlanId);
334 assertEquals(V3, rtv2.vlanId);
335 assertEquals(CP1.port(), rtv1.portNumber);
336 assertEquals(CP2.port(), rtv2.portNumber);
337
338 assertEquals(2, SUBNET_TABLE.size());
339 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
340 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800341
342 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700343 }
344
345 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400346 public void testOneSingleHomedToTwoSingleHomed() {
Charles Chan910be6a2017-08-23 14:46:43 -0700347 processRouteAdded();
348
Charles Chan06f626c2018-02-05 17:20:05 -0800349 reset(srManager.deviceConfiguration);
350 srManager.deviceConfiguration.addSubnet(CP2, P1);
351 expectLastCall().once();
352 replay(srManager.deviceConfiguration);
353
Charles Chan910be6a2017-08-23 14:46:43 -0700354 RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
355 Sets.newHashSet(RR1, RR2), Sets.newHashSet(RR1));
356 routeHandler.processAlternativeRoutesChanged(re);
357
358 assertEquals(2, ROUTING_TABLE.size());
359 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
360 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
361 assertEquals(M1, rtv1.macAddress);
362 assertEquals(M2, rtv2.macAddress);
363 assertEquals(V1, rtv1.vlanId);
364 assertEquals(V2, rtv2.vlanId);
365 assertEquals(CP1.port(), rtv1.portNumber);
366 assertEquals(CP2.port(), rtv2.portNumber);
367
368 assertEquals(2, SUBNET_TABLE.size());
369 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
370 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800371
372 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700373 }
374
375 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400376 public void testTwoSingleHomedToOneSingleHomed() {
Charles Chan910be6a2017-08-23 14:46:43 -0700377 testTwoSingleHomedAdded();
378
Charles Chan06f626c2018-02-05 17:20:05 -0800379 reset(srManager.deviceConfiguration);
380 srManager.deviceConfiguration.removeSubnet(CP2, P1);
381 expectLastCall().once();
382 replay(srManager.deviceConfiguration);
383
Charles Chan910be6a2017-08-23 14:46:43 -0700384 RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
385 Sets.newHashSet(RR1), Sets.newHashSet(RR1, RR2));
386 routeHandler.processAlternativeRoutesChanged(re);
387
Charles Chan06f626c2018-02-05 17:20:05 -0800388 // Note: We shouldn't remove the old nexthop during the occasion of route update
389 // since the populate subnet will take care of it and point it to an ECMP group
390 assertEquals(2, ROUTING_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700391 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
392 assertEquals(M1, rtv1.macAddress);
393 assertEquals(V1, rtv1.vlanId);
394 assertEquals(CP1.port(), rtv1.portNumber);
395
396 assertEquals(1, SUBNET_TABLE.size());
397 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800398
399 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700400 }
401
Charles Chan06f626c2018-02-05 17:20:05 -0800402 // TODO Add test cases for two single homed next hop at same location
403
Charles Chan910be6a2017-08-23 14:46:43 -0700404 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400405 public void testDualHomedSingleLocationFail() {
Charles Chan910be6a2017-08-23 14:46:43 -0700406 testOneDualHomedAdded();
407
Charles Chan7d20a4e2018-04-13 14:01:49 -0400408 ROUTE_STORE.put(P1, Sets.newHashSet(RR3));
409
Charles Chan07203792018-07-17 16:33:11 -0700410 reset(srManager.deviceConfiguration);
Charles Chan5eec3b12019-04-18 14:30:41 -0700411 expect(srManager.deviceConfiguration.getBatchedSubnets(H3D.id()))
412 .andReturn(Lists.<Set<IpPrefix>>newArrayList(Sets.newHashSet(P1)));
Charles Chan07203792018-07-17 16:33:11 -0700413 srManager.deviceConfiguration.removeSubnet(CP2, P1);
414 expectLastCall().once();
415 replay(srManager.deviceConfiguration);
416
Charles Chan910be6a2017-08-23 14:46:43 -0700417 HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3S, H3D);
418 routeHandler.processHostMovedEvent(he);
419
Charles Chan4dcd5102019-02-28 15:40:57 -0800420 // We do not remove the route on CP2. Instead, we let the subnet population overrides it
421 assertEquals(2, ROUTING_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700422 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
Charles Chan910be6a2017-08-23 14:46:43 -0700423 assertEquals(M3, rtv1.macAddress);
Charles Chan910be6a2017-08-23 14:46:43 -0700424 assertEquals(V3, rtv1.vlanId);
Charles Chan910be6a2017-08-23 14:46:43 -0700425 assertEquals(CP1.port(), rtv1.portNumber);
Charles Chan910be6a2017-08-23 14:46:43 -0700426
427 // ECMP route table hasn't changed
Charles Chan07203792018-07-17 16:33:11 -0700428 assertEquals(1, SUBNET_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700429 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan07203792018-07-17 16:33:11 -0700430
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 testDualHomedBothLocationFail() {
Charles Chan910be6a2017-08-23 14:46:43 -0700436 testDualHomedSingleLocationFail();
437
438 hostService = new MockHostService(HOSTS_ONE_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, RR3, Sets.newHashSet(RR3));
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 Chan07203792018-07-17 16:33:11 -0700457 public void testSingleHomedToDualHomed() {
458 testDualHomedSingleLocationFail();
459
460 reset(srManager.deviceConfiguration);
Charles Chan5eec3b12019-04-18 14:30:41 -0700461 expect(srManager.deviceConfiguration.getBatchedSubnets(H3S.id()))
462 .andReturn(Lists.<Set<IpPrefix>>newArrayList(Sets.newHashSet(P1)));
Charles Chan07203792018-07-17 16:33:11 -0700463 srManager.deviceConfiguration.addSubnet(CP2, P1);
464 expectLastCall().once();
465 replay(srManager.deviceConfiguration);
466
467 HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3D, H3S);
468 routeHandler.processHostMovedEvent(he);
469
470 assertEquals(2, ROUTING_TABLE.size());
471 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
472 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
473 assertEquals(M3, rtv1.macAddress);
474 assertEquals(M3, rtv2.macAddress);
475 assertEquals(V3, rtv1.vlanId);
476 assertEquals(V3, rtv2.vlanId);
477 assertEquals(CP1.port(), rtv1.portNumber);
478 assertEquals(CP2.port(), rtv2.portNumber);
479
480 assertEquals(2, SUBNET_TABLE.size());
481 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
482 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
483
484 verify(srManager.deviceConfiguration);
485 }
486
487 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400488 public void testTwoSingleHomedRemoved() {
Charles Chan910be6a2017-08-23 14:46:43 -0700489 testTwoSingleHomedAdded();
490
491 hostService = new MockHostService(HOSTS_BOTH_FAIL);
492
Charles Chan06f626c2018-02-05 17:20:05 -0800493 reset(srManager.deviceConfiguration);
494 srManager.deviceConfiguration.removeSubnet(CP1, P1);
495 expectLastCall().once();
496 srManager.deviceConfiguration.removeSubnet(CP2, P1);
497 expectLastCall().once();
498 replay(srManager.deviceConfiguration);
499
Charles Chan910be6a2017-08-23 14:46:43 -0700500 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1, RR2));
501 routeHandler.processRouteRemoved(re);
502
503 assertEquals(0, ROUTING_TABLE.size());
504 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800505
506 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700507 }
508
509 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400510 public void testOneDualHomeRemoved() {
Charles Chan910be6a2017-08-23 14:46:43 -0700511 testOneDualHomedAdded();
512
Charles Chan06f626c2018-02-05 17:20:05 -0800513 reset(srManager.deviceConfiguration);
514 srManager.deviceConfiguration.removeSubnet(CP1, P1);
515 expectLastCall().once();
516 srManager.deviceConfiguration.removeSubnet(CP2, P1);
517 expectLastCall().once();
518 replay(srManager.deviceConfiguration);
519
Charles Chan910be6a2017-08-23 14:46:43 -0700520 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
Charles Chan6c624992017-08-18 17:11:34 -0700521 routeHandler.processRouteRemoved(re);
522
523 assertEquals(0, ROUTING_TABLE.size());
524 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800525
526 verify(srManager.deviceConfiguration);
Charles Chan6c624992017-08-18 17:11:34 -0700527 }
Charles Chan482b6422018-04-09 11:52:08 -0400528
529 @Test
530 public void testMoreThanTwoNextHop() {
531 // next hop = CP1, CP2
532 reset(srManager.deviceConfiguration);
533 srManager.deviceConfiguration.addSubnet(CP1, P1);
534 srManager.deviceConfiguration.addSubnet(CP2, P1);
535 expectLastCall().once();
536 replay(srManager.deviceConfiguration);
537
538 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
539 routeHandler.processRouteAdded(re);
540
541 assertEquals(2, ROUTING_TABLE.size());
542 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
543 assertEquals(M1, rtv1.macAddress);
544 assertEquals(V1, rtv1.vlanId);
545 assertEquals(CP1.port(), rtv1.portNumber);
546 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
547 assertEquals(M2, rtv2.macAddress);
548 assertEquals(V2, rtv2.vlanId);
549 assertEquals(CP2.port(), rtv2.portNumber);
550
551 assertEquals(2, SUBNET_TABLE.size());
552 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
553 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
554
555 verify(srManager.deviceConfiguration);
556
557 // next hop = CP1, CP2, CP4 (invalid)
558 re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
559 Sets.newHashSet(RR1, RR2, RR4), Sets.newHashSet(RR1, RR2));
560 routeHandler.processAlternativeRoutesChanged(re);
561
562 assertEquals(2, ROUTING_TABLE.size());
563 rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
564 assertEquals(M1, rtv1.macAddress);
565 assertEquals(V1, rtv1.vlanId);
566 assertEquals(CP1.port(), rtv1.portNumber);
567 rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
568 assertEquals(M2, rtv2.macAddress);
569 assertEquals(V2, rtv2.vlanId);
570 assertEquals(CP2.port(), rtv2.portNumber);
571
572 assertEquals(2, SUBNET_TABLE.size());
573 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
574 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
575
576 // next hop = CP2, CP4
577 reset(srManager.deviceConfiguration);
578 srManager.deviceConfiguration.addSubnet(CP2, P1);
579 srManager.deviceConfiguration.addSubnet(CP4, P1);
580 expectLastCall().once();
581 replay(srManager.deviceConfiguration);
582
583 re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
584 Sets.newHashSet(RR2, RR4), Sets.newHashSet(RR1, RR2, RR4));
585 routeHandler.processAlternativeRoutesChanged(re);
586
587 assertEquals(2, ROUTING_TABLE.size());
588 rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
589 assertEquals(M2, rtv1.macAddress);
590 assertEquals(V2, rtv1.vlanId);
591 assertEquals(CP2.port(), rtv1.portNumber);
592 rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP4.deviceId(), P1));
593 assertEquals(M4, rtv2.macAddress);
594 assertEquals(V4, rtv2.vlanId);
595 assertEquals(CP4.port(), rtv2.portNumber);
596
597 assertEquals(2, SUBNET_TABLE.size());
598 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
599 assertTrue(SUBNET_TABLE.get(CP4).contains(P1));
600
601 verify(srManager.deviceConfiguration);
602 }
Ruchi Sahota71bcb4e2019-01-28 01:08:18 +0000603}