blob: 6332856b6c560165893c7bbc41ff7a9ba53cd6bb [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;
pierf331a492020-01-07 15:39:39 +010051import org.onosproject.store.service.TestConsistentMultimap;
Charles Chan6c624992017-08-18 17:11:34 -070052
53import java.util.Map;
54import java.util.Set;
55
Charles Chand66d6712018-03-29 16:03:41 -070056import static org.easymock.EasyMock.expect;
Charles Chan06f626c2018-02-05 17:20:05 -080057import static org.easymock.EasyMock.reset;
Charles Chan6c624992017-08-18 17:11:34 -070058import static org.junit.Assert.*;
Charles Chan06f626c2018-02-05 17:20:05 -080059import static org.easymock.EasyMock.createMock;
60import static org.easymock.EasyMock.expectLastCall;
61import static org.easymock.EasyMock.replay;
62import static org.easymock.EasyMock.verify;
Charles Chan6c624992017-08-18 17:11:34 -070063
64/**
65 * Unit test for {@link RouteHandler}.
66 */
67public class RouteHandlerTest {
Charles Chan06f626c2018-02-05 17:20:05 -080068 private SegmentRoutingManager srManager;
Charles Chan6c624992017-08-18 17:11:34 -070069 private RouteHandler routeHandler;
Charles Chan910be6a2017-08-23 14:46:43 -070070 private HostService hostService;
Charles Chan6c624992017-08-18 17:11:34 -070071
72 // Mocked routing and bridging tables
73 private static final Map<MockBridgingTableKey, MockBridgingTableValue> BRIDGING_TABLE =
74 Maps.newConcurrentMap();
75 private static final Map<MockRoutingTableKey, MockRoutingTableValue> ROUTING_TABLE =
76 Maps.newConcurrentMap();
77 private static final Map<ConnectPoint, Set<IpPrefix>> SUBNET_TABLE = Maps.newConcurrentMap();
78 // Mocked Next Id
79 private static final Map<Integer, TrafficTreatment> NEXT_TABLE = Maps.newConcurrentMap();
Charles Chan7d20a4e2018-04-13 14:01:49 -040080 private static final Map<IpPrefix, Set<ResolvedRoute>> ROUTE_STORE = Maps.newConcurrentMap();
Charles Chan6c624992017-08-18 17:11:34 -070081
82 private static final IpPrefix P1 = IpPrefix.valueOf("10.0.0.0/24");
Charles Chan910be6a2017-08-23 14:46:43 -070083
84 // Single homed router 1
Charles Chan6c624992017-08-18 17:11:34 -070085 private static final IpAddress N1 = IpAddress.valueOf("10.0.1.254");
86 private static final MacAddress M1 = MacAddress.valueOf("00:00:00:00:00:01");
87 private static final VlanId V1 = VlanId.vlanId((short) 1);
88 private static final ConnectPoint CP1 = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
89 private static final Route R1 = new Route(Route.Source.STATIC, P1, N1);
Charles Chanf0ae41e2017-08-23 13:55:39 -070090 private static final ResolvedRoute RR1 = new ResolvedRoute(R1, M1, V1);
Charles Chan6c624992017-08-18 17:11:34 -070091
Charles Chan910be6a2017-08-23 14:46:43 -070092 // Single homed router 2
Charles Chan6c624992017-08-18 17:11:34 -070093 private static final IpAddress N2 = IpAddress.valueOf("10.0.2.254");
94 private static final MacAddress M2 = MacAddress.valueOf("00:00:00:00:00:02");
95 private static final VlanId V2 = VlanId.vlanId((short) 2);
Charles Chan910be6a2017-08-23 14:46:43 -070096 private static final ConnectPoint CP2 = ConnectPoint.deviceConnectPoint("of:0000000000000002/2");
Charles Chan6c624992017-08-18 17:11:34 -070097 private static final Route R2 = new Route(Route.Source.STATIC, P1, N2);
Charles Chanf0ae41e2017-08-23 13:55:39 -070098 private static final ResolvedRoute RR2 = new ResolvedRoute(R2, M2, V2);
Charles Chan6c624992017-08-18 17:11:34 -070099
Charles Chan910be6a2017-08-23 14:46:43 -0700100 // Dual homed router 1
101 private static final IpAddress N3 = IpAddress.valueOf("10.0.3.254");
102 private static final MacAddress M3 = MacAddress.valueOf("00:00:00:00:00:03");
103 private static final VlanId V3 = VlanId.vlanId((short) 3);
104 private static final Route R3 = new Route(Route.Source.STATIC, P1, N3);
105 private static final ResolvedRoute RR3 = new ResolvedRoute(R3, M3, V3);
Charles Chan6c624992017-08-18 17:11:34 -0700106
Charles Chan482b6422018-04-09 11:52:08 -0400107 // Single homed router 3
108 private static final IpAddress N4 = IpAddress.valueOf("10.0.4.254");
109 private static final MacAddress M4 = MacAddress.valueOf("00:00:00:00:00:04");
110 private static final VlanId V4 = VlanId.vlanId((short) 4);
111 private static final ConnectPoint CP4 = ConnectPoint.deviceConnectPoint("of:0000000000000004/4");
112 private static final Route R4 = new Route(Route.Source.STATIC, P1, N4);
113 private static final ResolvedRoute RR4 = new ResolvedRoute(R4, M4, V4);
114
Charles Chan910be6a2017-08-23 14:46:43 -0700115 // Hosts
Charles Chanf0ae41e2017-08-23 13:55:39 -0700116 private static final Host H1 = new DefaultHost(ProviderId.NONE, HostId.hostId(M1, V1), M1, V1,
117 Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N1), false);
118 private static final Host H2 = new DefaultHost(ProviderId.NONE, HostId.hostId(M2, V2), M2, V2,
119 Sets.newHashSet(new HostLocation(CP2, 0)), Sets.newHashSet(N2), false);
Charles Chan910be6a2017-08-23 14:46:43 -0700120 private static final Host H3D = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
121 Sets.newHashSet(new HostLocation(CP1, 0), new HostLocation(CP2, 0)), Sets.newHashSet(N3), false);
122 private static final Host H3S = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
123 Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N3), false);
Charles Chan482b6422018-04-09 11:52:08 -0400124 private static final Host H4 = new DefaultHost(ProviderId.NONE, HostId.hostId(M4, V4), M4, V4,
125 Sets.newHashSet(new HostLocation(CP4, 0)), Sets.newHashSet(N4), false);
Charles Chan910be6a2017-08-23 14:46:43 -0700126
127 // Pair Local Port
128 private static final PortNumber P9 = PortNumber.portNumber(9);
Charles Chanf0ae41e2017-08-23 13:55:39 -0700129
Charles Chan6c624992017-08-18 17:11:34 -0700130 // A set of hosts
Charles Chan482b6422018-04-09 11:52:08 -0400131 private static final Set<Host> HOSTS = Sets.newHashSet(H1, H2, H3D, H4);
Charles Chan910be6a2017-08-23 14:46:43 -0700132 private static final Set<Host> HOSTS_ONE_FAIL = Sets.newHashSet(H1, H2, H3S);
133 private static final Set<Host> HOSTS_BOTH_FAIL = Sets.newHashSet(H1, H2);
Charles Chan6c624992017-08-18 17:11:34 -0700134 // A set of devices of which we have mastership
Charles Chan910be6a2017-08-23 14:46:43 -0700135 private static final Set<DeviceId> LOCAL_DEVICES = Sets.newHashSet(CP1.deviceId(), CP2.deviceId());
Charles Chan6c624992017-08-18 17:11:34 -0700136 // A set of interfaces
137 private static final Set<Interface> INTERFACES = Sets.newHashSet();
Charles Chan6c624992017-08-18 17:11:34 -0700138
139 @Before
Charles Chan482b6422018-04-09 11:52:08 -0400140 public void setUp() {
Charles Chan910be6a2017-08-23 14:46:43 -0700141 ObjectMapper mapper = new ObjectMapper();
142 ConfigApplyDelegate delegate = config -> { };
143
144 SegmentRoutingDeviceConfig dev1Config = new SegmentRoutingDeviceConfig();
145 JsonNode dev1Tree = mapper.createObjectNode();
146 dev1Config.init(CP1.deviceId(), "host-handler-test", dev1Tree, mapper, delegate);
147 dev1Config.setPairDeviceId(CP2.deviceId()).setPairLocalPort(P9);
148
149 SegmentRoutingDeviceConfig dev2Config = new SegmentRoutingDeviceConfig();
150 JsonNode dev2Tree = mapper.createObjectNode();
151 dev2Config.init(CP2.deviceId(), "host-handler-test", dev2Tree, mapper, delegate);
152 dev2Config.setPairDeviceId(CP1.deviceId()).setPairLocalPort(P9);
Charles Chan6c624992017-08-18 17:11:34 -0700153
154 MockNetworkConfigRegistry mockNetworkConfigRegistry = new MockNetworkConfigRegistry();
Charles Chan910be6a2017-08-23 14:46:43 -0700155 mockNetworkConfigRegistry.applyConfig(dev1Config);
156 mockNetworkConfigRegistry.applyConfig(dev2Config);
Charles Chan6c624992017-08-18 17:11:34 -0700157
158 // Initialize Segment Routing Manager
Charles Chan06f626c2018-02-05 17:20:05 -0800159 srManager = new MockSegmentRoutingManager(NEXT_TABLE);
Charles Chand66d6712018-03-29 16:03:41 -0700160 srManager.storageService = createMock(StorageService.class);
161 expect(srManager.storageService.consistentMapBuilder()).andReturn(new TestConsistentMap.Builder<>()).anyTimes();
pierf331a492020-01-07 15:39:39 +0100162 expect(srManager.storageService.consistentMultimapBuilder()).andReturn(
163 new TestConsistentMultimap.Builder<>()).anyTimes();
Charles Chand66d6712018-03-29 16:03:41 -0700164 replay(srManager.storageService);
Charles Chan6c624992017-08-18 17:11:34 -0700165 srManager.cfgService = new NetworkConfigRegistryAdapter();
Charles Chan06f626c2018-02-05 17:20:05 -0800166 srManager.deviceConfiguration = createMock(DeviceConfiguration.class);
Charles Chan6c624992017-08-18 17:11:34 -0700167 srManager.flowObjectiveService = new MockFlowObjectiveService(BRIDGING_TABLE, NEXT_TABLE);
168 srManager.routingRulePopulator = new MockRoutingRulePopulator(srManager, ROUTING_TABLE);
Charles Chanc4d68882018-03-15 16:41:10 -0700169 srManager.defaultRoutingHandler = new MockDefaultRoutingHandler(srManager, SUBNET_TABLE, ROUTING_TABLE);
Charles Chan6c624992017-08-18 17:11:34 -0700170 srManager.interfaceService = new MockInterfaceService(INTERFACES);
171 srManager.mastershipService = new MockMastershipService(LOCAL_DEVICES);
Charles Chan910be6a2017-08-23 14:46:43 -0700172 hostService = new MockHostService(HOSTS);
173 srManager.hostService = hostService;
Charles Chan6c624992017-08-18 17:11:34 -0700174 srManager.cfgService = mockNetworkConfigRegistry;
Charles Chan7d20a4e2018-04-13 14:01:49 -0400175 srManager.routeService = new MockRouteService(ROUTE_STORE);
Charles Chan6c624992017-08-18 17:11:34 -0700176
Charles Chanfbcb8812018-04-18 18:41:05 -0700177 routeHandler = new RouteHandler(srManager);
Charles Chan6c624992017-08-18 17:11:34 -0700178
179 ROUTING_TABLE.clear();
180 BRIDGING_TABLE.clear();
181 SUBNET_TABLE.clear();
182 }
183
184 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400185 public void init() {
Charles Chan7d20a4e2018-04-13 14:01:49 -0400186 ROUTE_STORE.put(P1, Sets.newHashSet(RR1));
Charles Chan910be6a2017-08-23 14:46:43 -0700187
Charles Chan6c624992017-08-18 17:11:34 -0700188 routeHandler.init(CP1.deviceId());
189
190 assertEquals(1, ROUTING_TABLE.size());
Charles Chanf0ae41e2017-08-23 13:55:39 -0700191 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
192 assertEquals(M1, rtv1.macAddress);
193 assertEquals(V1, rtv1.vlanId);
194 assertEquals(CP1.port(), rtv1.portNumber);
195
Charles Chan6c624992017-08-18 17:11:34 -0700196 assertEquals(1, SUBNET_TABLE.size());
197 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
198 }
199
200 @Test
Charles Chan7d20a4e2018-04-13 14:01:49 -0400201 public void initTwoNextHops() {
202 ROUTE_STORE.put(P1, Sets.newHashSet(RR1, RR2));
203
204 routeHandler.init(CP1.deviceId());
205
206 assertEquals(2, ROUTING_TABLE.size());
207 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
208 assertEquals(M1, rtv1.macAddress);
209 assertEquals(V1, rtv1.vlanId);
210 assertEquals(CP1.port(), rtv1.portNumber);
211 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
212 assertEquals(M2, rtv2.macAddress);
213 assertEquals(V2, rtv2.vlanId);
214 assertEquals(CP2.port(), rtv2.portNumber);
215
216 assertEquals(2, SUBNET_TABLE.size());
217 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
218 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
219 }
220
221 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400222 public void processRouteAdded() {
Charles Chan06f626c2018-02-05 17:20:05 -0800223 reset(srManager.deviceConfiguration);
224 srManager.deviceConfiguration.addSubnet(CP1, P1);
225 expectLastCall().once();
226 replay(srManager.deviceConfiguration);
227
Charles Chan910be6a2017-08-23 14:46:43 -0700228 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1));
Charles Chan6c624992017-08-18 17:11:34 -0700229 routeHandler.processRouteAdded(re);
230
231 assertEquals(1, ROUTING_TABLE.size());
Charles Chanf0ae41e2017-08-23 13:55:39 -0700232 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
233 assertEquals(M1, rtv1.macAddress);
234 assertEquals(V1, rtv1.vlanId);
235 assertEquals(CP1.port(), rtv1.portNumber);
236
Charles Chan6c624992017-08-18 17:11:34 -0700237 assertEquals(1, SUBNET_TABLE.size());
238 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800239
240 verify(srManager.deviceConfiguration);
Charles Chan6c624992017-08-18 17:11:34 -0700241 }
242
243 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400244 public void processRouteUpdated() {
Charles Chan6c624992017-08-18 17:11:34 -0700245 processRouteAdded();
246
Charles Chan06f626c2018-02-05 17:20:05 -0800247 reset(srManager.deviceConfiguration);
248 srManager.deviceConfiguration.removeSubnet(CP1, P1);
249 expectLastCall().once();
250 srManager.deviceConfiguration.addSubnet(CP2, P1);
251 expectLastCall().once();
252 replay(srManager.deviceConfiguration);
253
Charles Chan910be6a2017-08-23 14:46:43 -0700254 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_UPDATED, RR2, RR1, Sets.newHashSet(RR2),
255 Sets.newHashSet(RR1));
Charles Chan6c624992017-08-18 17:11:34 -0700256 routeHandler.processRouteUpdated(re);
257
Charles Chan06f626c2018-02-05 17:20:05 -0800258 // Note: We shouldn't remove the old nexthop during the occasion of route update
259 // since the populate subnet will take care of it and point it to an ECMP group
260 assertEquals(2, ROUTING_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700261 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
Charles Chanf0ae41e2017-08-23 13:55:39 -0700262 assertEquals(M2, rtv2.macAddress);
263 assertEquals(V2, rtv2.vlanId);
264 assertEquals(CP2.port(), rtv2.portNumber);
265
Charles Chan6c624992017-08-18 17:11:34 -0700266 assertEquals(1, SUBNET_TABLE.size());
267 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800268
269 verify(srManager.deviceConfiguration);
Charles Chan6c624992017-08-18 17:11:34 -0700270 }
271
272 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400273 public void processRouteRemoved() {
Charles Chan6c624992017-08-18 17:11:34 -0700274 processRouteAdded();
275
Charles Chan06f626c2018-02-05 17:20:05 -0800276 reset(srManager.deviceConfiguration);
277 srManager.deviceConfiguration.removeSubnet(CP1, P1);
278 expectLastCall().once();
279 replay(srManager.deviceConfiguration);
280
Charles Chan910be6a2017-08-23 14:46:43 -0700281 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1));
282 routeHandler.processRouteRemoved(re);
283
284 assertEquals(0, ROUTING_TABLE.size());
285 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800286
287 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700288 }
289
290 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400291 public void testTwoSingleHomedAdded() {
Charles Chan06f626c2018-02-05 17:20:05 -0800292 reset(srManager.deviceConfiguration);
293 srManager.deviceConfiguration.addSubnet(CP1, P1);
294 expectLastCall().once();
295 srManager.deviceConfiguration.addSubnet(CP2, P1);
296 expectLastCall().once();
297 replay(srManager.deviceConfiguration);
298
Charles Chan910be6a2017-08-23 14:46:43 -0700299 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
300 routeHandler.processRouteAdded(re);
301
302 assertEquals(2, ROUTING_TABLE.size());
303 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
304 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
305 assertEquals(M1, rtv1.macAddress);
306 assertEquals(M2, rtv2.macAddress);
307 assertEquals(V1, rtv1.vlanId);
308 assertEquals(V2, rtv2.vlanId);
309 assertEquals(CP1.port(), rtv1.portNumber);
310 assertEquals(CP2.port(), rtv2.portNumber);
311
312 assertEquals(2, SUBNET_TABLE.size());
313 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
314 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800315
316 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700317 }
318
319 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400320 public void testOneDualHomedAdded() {
Charles Chan06f626c2018-02-05 17:20:05 -0800321 reset(srManager.deviceConfiguration);
322 srManager.deviceConfiguration.addSubnet(CP1, P1);
323 expectLastCall().once();
324 srManager.deviceConfiguration.addSubnet(CP2, P1);
325 expectLastCall().once();
326 replay(srManager.deviceConfiguration);
327
Charles Chan910be6a2017-08-23 14:46:43 -0700328 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR3, Sets.newHashSet(RR3));
329 routeHandler.processRouteAdded(re);
330
331 assertEquals(2, ROUTING_TABLE.size());
332 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
333 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
334 assertEquals(M3, rtv1.macAddress);
335 assertEquals(M3, rtv2.macAddress);
336 assertEquals(V3, rtv1.vlanId);
337 assertEquals(V3, rtv2.vlanId);
338 assertEquals(CP1.port(), rtv1.portNumber);
339 assertEquals(CP2.port(), rtv2.portNumber);
340
341 assertEquals(2, SUBNET_TABLE.size());
342 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
343 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800344
345 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700346 }
347
348 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400349 public void testOneSingleHomedToTwoSingleHomed() {
Charles Chan910be6a2017-08-23 14:46:43 -0700350 processRouteAdded();
351
Charles Chan06f626c2018-02-05 17:20:05 -0800352 reset(srManager.deviceConfiguration);
353 srManager.deviceConfiguration.addSubnet(CP2, P1);
354 expectLastCall().once();
355 replay(srManager.deviceConfiguration);
356
Charles Chan910be6a2017-08-23 14:46:43 -0700357 RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
358 Sets.newHashSet(RR1, RR2), Sets.newHashSet(RR1));
359 routeHandler.processAlternativeRoutesChanged(re);
360
361 assertEquals(2, ROUTING_TABLE.size());
362 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
363 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
364 assertEquals(M1, rtv1.macAddress);
365 assertEquals(M2, rtv2.macAddress);
366 assertEquals(V1, rtv1.vlanId);
367 assertEquals(V2, rtv2.vlanId);
368 assertEquals(CP1.port(), rtv1.portNumber);
369 assertEquals(CP2.port(), rtv2.portNumber);
370
371 assertEquals(2, SUBNET_TABLE.size());
372 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
373 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800374
375 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700376 }
377
378 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400379 public void testTwoSingleHomedToOneSingleHomed() {
Charles Chan910be6a2017-08-23 14:46:43 -0700380 testTwoSingleHomedAdded();
381
Charles Chan06f626c2018-02-05 17:20:05 -0800382 reset(srManager.deviceConfiguration);
383 srManager.deviceConfiguration.removeSubnet(CP2, P1);
384 expectLastCall().once();
385 replay(srManager.deviceConfiguration);
386
Charles Chan910be6a2017-08-23 14:46:43 -0700387 RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
388 Sets.newHashSet(RR1), Sets.newHashSet(RR1, RR2));
389 routeHandler.processAlternativeRoutesChanged(re);
390
Charles Chan06f626c2018-02-05 17:20:05 -0800391 // Note: We shouldn't remove the old nexthop during the occasion of route update
392 // since the populate subnet will take care of it and point it to an ECMP group
393 assertEquals(2, ROUTING_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700394 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
395 assertEquals(M1, rtv1.macAddress);
396 assertEquals(V1, rtv1.vlanId);
397 assertEquals(CP1.port(), rtv1.portNumber);
398
399 assertEquals(1, SUBNET_TABLE.size());
400 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800401
402 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700403 }
404
Charles Chan06f626c2018-02-05 17:20:05 -0800405 // TODO Add test cases for two single homed next hop at same location
406
Charles Chan910be6a2017-08-23 14:46:43 -0700407 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400408 public void testDualHomedSingleLocationFail() {
Charles Chan910be6a2017-08-23 14:46:43 -0700409 testOneDualHomedAdded();
410
Charles Chan7d20a4e2018-04-13 14:01:49 -0400411 ROUTE_STORE.put(P1, Sets.newHashSet(RR3));
412
Charles Chan07203792018-07-17 16:33:11 -0700413 reset(srManager.deviceConfiguration);
Charles Chan5eec3b12019-04-18 14:30:41 -0700414 expect(srManager.deviceConfiguration.getBatchedSubnets(H3D.id()))
415 .andReturn(Lists.<Set<IpPrefix>>newArrayList(Sets.newHashSet(P1)));
Charles Chan07203792018-07-17 16:33:11 -0700416 srManager.deviceConfiguration.removeSubnet(CP2, P1);
417 expectLastCall().once();
418 replay(srManager.deviceConfiguration);
419
Charles Chan910be6a2017-08-23 14:46:43 -0700420 HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3S, H3D);
421 routeHandler.processHostMovedEvent(he);
422
Charles Chan4dcd5102019-02-28 15:40:57 -0800423 // We do not remove the route on CP2. Instead, we let the subnet population overrides it
424 assertEquals(2, ROUTING_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700425 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
Charles Chan910be6a2017-08-23 14:46:43 -0700426 assertEquals(M3, rtv1.macAddress);
Charles Chan910be6a2017-08-23 14:46:43 -0700427 assertEquals(V3, rtv1.vlanId);
Charles Chan910be6a2017-08-23 14:46:43 -0700428 assertEquals(CP1.port(), rtv1.portNumber);
Charles Chan910be6a2017-08-23 14:46:43 -0700429
430 // ECMP route table hasn't changed
Charles Chan07203792018-07-17 16:33:11 -0700431 assertEquals(1, SUBNET_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700432 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan07203792018-07-17 16:33:11 -0700433
434 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700435 }
436
437 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400438 public void testDualHomedBothLocationFail() {
Charles Chan910be6a2017-08-23 14:46:43 -0700439 testDualHomedSingleLocationFail();
440
441 hostService = new MockHostService(HOSTS_ONE_FAIL);
442
Charles Chan06f626c2018-02-05 17:20:05 -0800443 reset(srManager.deviceConfiguration);
444 srManager.deviceConfiguration.removeSubnet(CP1, P1);
445 expectLastCall().once();
446 srManager.deviceConfiguration.removeSubnet(CP2, P1);
447 expectLastCall().once();
448 replay(srManager.deviceConfiguration);
449
Charles Chan910be6a2017-08-23 14:46:43 -0700450 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
451 routeHandler.processRouteRemoved(re);
452
453 assertEquals(0, ROUTING_TABLE.size());
454 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800455
456 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700457 }
458
459 @Test
Charles Chan07203792018-07-17 16:33:11 -0700460 public void testSingleHomedToDualHomed() {
461 testDualHomedSingleLocationFail();
462
463 reset(srManager.deviceConfiguration);
Charles Chan5eec3b12019-04-18 14:30:41 -0700464 expect(srManager.deviceConfiguration.getBatchedSubnets(H3S.id()))
465 .andReturn(Lists.<Set<IpPrefix>>newArrayList(Sets.newHashSet(P1)));
Charles Chan07203792018-07-17 16:33:11 -0700466 srManager.deviceConfiguration.addSubnet(CP2, P1);
467 expectLastCall().once();
468 replay(srManager.deviceConfiguration);
469
470 HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3D, H3S);
471 routeHandler.processHostMovedEvent(he);
472
473 assertEquals(2, ROUTING_TABLE.size());
474 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
475 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
476 assertEquals(M3, rtv1.macAddress);
477 assertEquals(M3, rtv2.macAddress);
478 assertEquals(V3, rtv1.vlanId);
479 assertEquals(V3, rtv2.vlanId);
480 assertEquals(CP1.port(), rtv1.portNumber);
481 assertEquals(CP2.port(), rtv2.portNumber);
482
483 assertEquals(2, SUBNET_TABLE.size());
484 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
485 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
486
487 verify(srManager.deviceConfiguration);
488 }
489
490 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400491 public void testTwoSingleHomedRemoved() {
Charles Chan910be6a2017-08-23 14:46:43 -0700492 testTwoSingleHomedAdded();
493
494 hostService = new MockHostService(HOSTS_BOTH_FAIL);
495
Charles Chan06f626c2018-02-05 17:20:05 -0800496 reset(srManager.deviceConfiguration);
497 srManager.deviceConfiguration.removeSubnet(CP1, P1);
498 expectLastCall().once();
499 srManager.deviceConfiguration.removeSubnet(CP2, P1);
500 expectLastCall().once();
501 replay(srManager.deviceConfiguration);
502
Charles Chan910be6a2017-08-23 14:46:43 -0700503 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1, RR2));
504 routeHandler.processRouteRemoved(re);
505
506 assertEquals(0, ROUTING_TABLE.size());
507 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800508
509 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700510 }
511
512 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400513 public void testOneDualHomeRemoved() {
Charles Chan910be6a2017-08-23 14:46:43 -0700514 testOneDualHomedAdded();
515
Charles Chan06f626c2018-02-05 17:20:05 -0800516 reset(srManager.deviceConfiguration);
517 srManager.deviceConfiguration.removeSubnet(CP1, P1);
518 expectLastCall().once();
519 srManager.deviceConfiguration.removeSubnet(CP2, P1);
520 expectLastCall().once();
521 replay(srManager.deviceConfiguration);
522
Charles Chan910be6a2017-08-23 14:46:43 -0700523 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
Charles Chan6c624992017-08-18 17:11:34 -0700524 routeHandler.processRouteRemoved(re);
525
526 assertEquals(0, ROUTING_TABLE.size());
527 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800528
529 verify(srManager.deviceConfiguration);
Charles Chan6c624992017-08-18 17:11:34 -0700530 }
Charles Chan482b6422018-04-09 11:52:08 -0400531
532 @Test
533 public void testMoreThanTwoNextHop() {
534 // next hop = CP1, CP2
535 reset(srManager.deviceConfiguration);
536 srManager.deviceConfiguration.addSubnet(CP1, P1);
537 srManager.deviceConfiguration.addSubnet(CP2, P1);
538 expectLastCall().once();
539 replay(srManager.deviceConfiguration);
540
541 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
542 routeHandler.processRouteAdded(re);
543
544 assertEquals(2, ROUTING_TABLE.size());
545 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
546 assertEquals(M1, rtv1.macAddress);
547 assertEquals(V1, rtv1.vlanId);
548 assertEquals(CP1.port(), rtv1.portNumber);
549 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
550 assertEquals(M2, rtv2.macAddress);
551 assertEquals(V2, rtv2.vlanId);
552 assertEquals(CP2.port(), rtv2.portNumber);
553
554 assertEquals(2, SUBNET_TABLE.size());
555 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
556 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
557
558 verify(srManager.deviceConfiguration);
559
560 // next hop = CP1, CP2, CP4 (invalid)
561 re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
562 Sets.newHashSet(RR1, RR2, RR4), Sets.newHashSet(RR1, RR2));
563 routeHandler.processAlternativeRoutesChanged(re);
564
565 assertEquals(2, ROUTING_TABLE.size());
566 rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
567 assertEquals(M1, rtv1.macAddress);
568 assertEquals(V1, rtv1.vlanId);
569 assertEquals(CP1.port(), rtv1.portNumber);
570 rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
571 assertEquals(M2, rtv2.macAddress);
572 assertEquals(V2, rtv2.vlanId);
573 assertEquals(CP2.port(), rtv2.portNumber);
574
575 assertEquals(2, SUBNET_TABLE.size());
576 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
577 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
578
579 // next hop = CP2, CP4
580 reset(srManager.deviceConfiguration);
581 srManager.deviceConfiguration.addSubnet(CP2, P1);
582 srManager.deviceConfiguration.addSubnet(CP4, P1);
583 expectLastCall().once();
584 replay(srManager.deviceConfiguration);
585
586 re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
587 Sets.newHashSet(RR2, RR4), Sets.newHashSet(RR1, RR2, RR4));
588 routeHandler.processAlternativeRoutesChanged(re);
589
590 assertEquals(2, ROUTING_TABLE.size());
591 rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
592 assertEquals(M2, rtv1.macAddress);
593 assertEquals(V2, rtv1.vlanId);
594 assertEquals(CP2.port(), rtv1.portNumber);
595 rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP4.deviceId(), P1));
596 assertEquals(M4, rtv2.macAddress);
597 assertEquals(V4, rtv2.vlanId);
598 assertEquals(CP4.port(), rtv2.portNumber);
599
600 assertEquals(2, SUBNET_TABLE.size());
601 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
602 assertTrue(SUBNET_TABLE.get(CP4).contains(P1));
603
604 verify(srManager.deviceConfiguration);
605 }
Ruchi Sahota71bcb4e2019-01-28 01:08:18 +0000606}