blob: ade5d0c1f5037e1ebfe25f18d90880e6db424a88 [file] [log] [blame]
Charles Chan1a3b02a2017-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 Chan2fde6d42017-08-23 14:46:43 -070019import com.fasterxml.jackson.databind.JsonNode;
20import com.fasterxml.jackson.databind.ObjectMapper;
Charles Chan1a3b02a2017-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 Chan2fde6d42017-08-23 14:46:43 -070029import org.onosproject.net.config.ConfigApplyDelegate;
Charles Chan1a3b02a2017-08-18 17:11:34 -070030import org.onosproject.net.ConnectPoint;
Charles Chan9640c812017-08-23 13:55:39 -070031import org.onosproject.net.DefaultHost;
Charles Chan1a3b02a2017-08-18 17:11:34 -070032import org.onosproject.net.DeviceId;
33import org.onosproject.net.Host;
Charles Chan9640c812017-08-23 13:55:39 -070034import org.onosproject.net.HostId;
35import org.onosproject.net.HostLocation;
Charles Chan2fde6d42017-08-23 14:46:43 -070036import org.onosproject.net.PortNumber;
Charles Chan1a3b02a2017-08-18 17:11:34 -070037import org.onosproject.net.config.NetworkConfigRegistryAdapter;
38import org.onosproject.net.flow.TrafficTreatment;
Charles Chan2fde6d42017-08-23 14:46:43 -070039import org.onosproject.net.host.HostEvent;
40import org.onosproject.net.host.HostService;
Charles Chan1a3b02a2017-08-18 17:11:34 -070041import org.onosproject.net.intf.Interface;
Charles Chan9640c812017-08-23 13:55:39 -070042import org.onosproject.net.provider.ProviderId;
Charles Chan1a3b02a2017-08-18 17:11:34 -070043import org.onosproject.routeservice.ResolvedRoute;
44import org.onosproject.routeservice.Route;
45import org.onosproject.routeservice.RouteEvent;
Charles Chan1a3b02a2017-08-18 17:11:34 -070046import org.onosproject.segmentrouting.config.DeviceConfiguration;
Charles Chan2fde6d42017-08-23 14:46:43 -070047import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
Charles Chan2ff1bac2018-03-29 16:03:41 -070048import org.onosproject.store.service.StorageService;
49import org.onosproject.store.service.TestConsistentMap;
Charles Chan1a3b02a2017-08-18 17:11:34 -070050
51import java.util.Map;
52import java.util.Set;
53
Charles Chan2ff1bac2018-03-29 16:03:41 -070054import static org.easymock.EasyMock.expect;
Charles Chan08d91322018-02-05 17:20:05 -080055import static org.easymock.EasyMock.reset;
Charles Chan1a3b02a2017-08-18 17:11:34 -070056import static org.junit.Assert.*;
Charles Chan08d91322018-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 Chan1a3b02a2017-08-18 17:11:34 -070061
62/**
63 * Unit test for {@link RouteHandler}.
64 */
65public class RouteHandlerTest {
Charles Chan08d91322018-02-05 17:20:05 -080066 private SegmentRoutingManager srManager;
Charles Chan1a3b02a2017-08-18 17:11:34 -070067 private RouteHandler routeHandler;
Charles Chan2fde6d42017-08-23 14:46:43 -070068 private HostService hostService;
Charles Chan1a3b02a2017-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();
Charles Chan2690fac2018-04-13 14:01:49 -040078 private static final Map<IpPrefix, Set<ResolvedRoute>> ROUTE_STORE = Maps.newConcurrentMap();
Charles Chan1a3b02a2017-08-18 17:11:34 -070079
80 private static final IpPrefix P1 = IpPrefix.valueOf("10.0.0.0/24");
Charles Chan2fde6d42017-08-23 14:46:43 -070081
82 // Single homed router 1
Charles Chan1a3b02a2017-08-18 17:11:34 -070083 private static final IpAddress N1 = IpAddress.valueOf("10.0.1.254");
84 private static final MacAddress M1 = MacAddress.valueOf("00:00:00:00:00:01");
85 private static final VlanId V1 = VlanId.vlanId((short) 1);
86 private static final ConnectPoint CP1 = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
87 private static final Route R1 = new Route(Route.Source.STATIC, P1, N1);
Charles Chan9640c812017-08-23 13:55:39 -070088 private static final ResolvedRoute RR1 = new ResolvedRoute(R1, M1, V1);
Charles Chan1a3b02a2017-08-18 17:11:34 -070089
Charles Chan2fde6d42017-08-23 14:46:43 -070090 // Single homed router 2
Charles Chan1a3b02a2017-08-18 17:11:34 -070091 private static final IpAddress N2 = IpAddress.valueOf("10.0.2.254");
92 private static final MacAddress M2 = MacAddress.valueOf("00:00:00:00:00:02");
93 private static final VlanId V2 = VlanId.vlanId((short) 2);
Charles Chan2fde6d42017-08-23 14:46:43 -070094 private static final ConnectPoint CP2 = ConnectPoint.deviceConnectPoint("of:0000000000000002/2");
Charles Chan1a3b02a2017-08-18 17:11:34 -070095 private static final Route R2 = new Route(Route.Source.STATIC, P1, N2);
Charles Chan9640c812017-08-23 13:55:39 -070096 private static final ResolvedRoute RR2 = new ResolvedRoute(R2, M2, V2);
Charles Chan1a3b02a2017-08-18 17:11:34 -070097
Charles Chan2fde6d42017-08-23 14:46:43 -070098 // Dual homed router 1
99 private static final IpAddress N3 = IpAddress.valueOf("10.0.3.254");
100 private static final MacAddress M3 = MacAddress.valueOf("00:00:00:00:00:03");
101 private static final VlanId V3 = VlanId.vlanId((short) 3);
102 private static final Route R3 = new Route(Route.Source.STATIC, P1, N3);
103 private static final ResolvedRoute RR3 = new ResolvedRoute(R3, M3, V3);
Charles Chan1a3b02a2017-08-18 17:11:34 -0700104
Charles Chane7c7d052018-04-09 11:52:08 -0400105 // Single homed router 3
106 private static final IpAddress N4 = IpAddress.valueOf("10.0.4.254");
107 private static final MacAddress M4 = MacAddress.valueOf("00:00:00:00:00:04");
108 private static final VlanId V4 = VlanId.vlanId((short) 4);
109 private static final ConnectPoint CP4 = ConnectPoint.deviceConnectPoint("of:0000000000000004/4");
110 private static final Route R4 = new Route(Route.Source.STATIC, P1, N4);
111 private static final ResolvedRoute RR4 = new ResolvedRoute(R4, M4, V4);
112
Charles Chan2fde6d42017-08-23 14:46:43 -0700113 // Hosts
Charles Chan9640c812017-08-23 13:55:39 -0700114 private static final Host H1 = new DefaultHost(ProviderId.NONE, HostId.hostId(M1, V1), M1, V1,
115 Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N1), false);
116 private static final Host H2 = new DefaultHost(ProviderId.NONE, HostId.hostId(M2, V2), M2, V2,
117 Sets.newHashSet(new HostLocation(CP2, 0)), Sets.newHashSet(N2), false);
Charles Chan2fde6d42017-08-23 14:46:43 -0700118 private static final Host H3D = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
119 Sets.newHashSet(new HostLocation(CP1, 0), new HostLocation(CP2, 0)), Sets.newHashSet(N3), false);
120 private static final Host H3S = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
121 Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N3), false);
Charles Chane7c7d052018-04-09 11:52:08 -0400122 private static final Host H4 = new DefaultHost(ProviderId.NONE, HostId.hostId(M4, V4), M4, V4,
123 Sets.newHashSet(new HostLocation(CP4, 0)), Sets.newHashSet(N4), false);
Charles Chan2fde6d42017-08-23 14:46:43 -0700124
125 // Pair Local Port
126 private static final PortNumber P9 = PortNumber.portNumber(9);
Charles Chan9640c812017-08-23 13:55:39 -0700127
Charles Chan1a3b02a2017-08-18 17:11:34 -0700128 // A set of hosts
Charles Chane7c7d052018-04-09 11:52:08 -0400129 private static final Set<Host> HOSTS = Sets.newHashSet(H1, H2, H3D, H4);
Charles Chan2fde6d42017-08-23 14:46:43 -0700130 private static final Set<Host> HOSTS_ONE_FAIL = Sets.newHashSet(H1, H2, H3S);
131 private static final Set<Host> HOSTS_BOTH_FAIL = Sets.newHashSet(H1, H2);
Charles Chan1a3b02a2017-08-18 17:11:34 -0700132 // A set of devices of which we have mastership
Charles Chan2fde6d42017-08-23 14:46:43 -0700133 private static final Set<DeviceId> LOCAL_DEVICES = Sets.newHashSet(CP1.deviceId(), CP2.deviceId());
Charles Chan1a3b02a2017-08-18 17:11:34 -0700134 // A set of interfaces
135 private static final Set<Interface> INTERFACES = Sets.newHashSet();
Charles Chan1a3b02a2017-08-18 17:11:34 -0700136
137 @Before
Charles Chane7c7d052018-04-09 11:52:08 -0400138 public void setUp() {
Charles Chan2fde6d42017-08-23 14:46:43 -0700139 ObjectMapper mapper = new ObjectMapper();
140 ConfigApplyDelegate delegate = config -> { };
141
142 SegmentRoutingDeviceConfig dev1Config = new SegmentRoutingDeviceConfig();
143 JsonNode dev1Tree = mapper.createObjectNode();
144 dev1Config.init(CP1.deviceId(), "host-handler-test", dev1Tree, mapper, delegate);
145 dev1Config.setPairDeviceId(CP2.deviceId()).setPairLocalPort(P9);
146
147 SegmentRoutingDeviceConfig dev2Config = new SegmentRoutingDeviceConfig();
148 JsonNode dev2Tree = mapper.createObjectNode();
149 dev2Config.init(CP2.deviceId(), "host-handler-test", dev2Tree, mapper, delegate);
150 dev2Config.setPairDeviceId(CP1.deviceId()).setPairLocalPort(P9);
Charles Chan1a3b02a2017-08-18 17:11:34 -0700151
152 MockNetworkConfigRegistry mockNetworkConfigRegistry = new MockNetworkConfigRegistry();
Charles Chan2fde6d42017-08-23 14:46:43 -0700153 mockNetworkConfigRegistry.applyConfig(dev1Config);
154 mockNetworkConfigRegistry.applyConfig(dev2Config);
Charles Chan1a3b02a2017-08-18 17:11:34 -0700155
156 // Initialize Segment Routing Manager
Charles Chan08d91322018-02-05 17:20:05 -0800157 srManager = new MockSegmentRoutingManager(NEXT_TABLE);
Charles Chan2ff1bac2018-03-29 16:03:41 -0700158 srManager.storageService = createMock(StorageService.class);
159 expect(srManager.storageService.consistentMapBuilder()).andReturn(new TestConsistentMap.Builder<>()).anyTimes();
160 replay(srManager.storageService);
Charles Chan1a3b02a2017-08-18 17:11:34 -0700161 srManager.cfgService = new NetworkConfigRegistryAdapter();
Charles Chan08d91322018-02-05 17:20:05 -0800162 srManager.deviceConfiguration = createMock(DeviceConfiguration.class);
Charles Chan1a3b02a2017-08-18 17:11:34 -0700163 srManager.flowObjectiveService = new MockFlowObjectiveService(BRIDGING_TABLE, NEXT_TABLE);
164 srManager.routingRulePopulator = new MockRoutingRulePopulator(srManager, ROUTING_TABLE);
Charles Chanf433f952018-03-15 16:41:10 -0700165 srManager.defaultRoutingHandler = new MockDefaultRoutingHandler(srManager, SUBNET_TABLE, ROUTING_TABLE);
Charles Chan1a3b02a2017-08-18 17:11:34 -0700166 srManager.interfaceService = new MockInterfaceService(INTERFACES);
167 srManager.mastershipService = new MockMastershipService(LOCAL_DEVICES);
Charles Chan2fde6d42017-08-23 14:46:43 -0700168 hostService = new MockHostService(HOSTS);
169 srManager.hostService = hostService;
Charles Chan1a3b02a2017-08-18 17:11:34 -0700170 srManager.cfgService = mockNetworkConfigRegistry;
Charles Chan2690fac2018-04-13 14:01:49 -0400171 srManager.routeService = new MockRouteService(ROUTE_STORE);
Charles Chan1a3b02a2017-08-18 17:11:34 -0700172
Charles Chan50bb6ef2018-04-18 18:41:05 -0700173 routeHandler = new RouteHandler(srManager);
Charles Chan1a3b02a2017-08-18 17:11:34 -0700174
175 ROUTING_TABLE.clear();
176 BRIDGING_TABLE.clear();
177 SUBNET_TABLE.clear();
178 }
179
180 @Test
Charles Chane7c7d052018-04-09 11:52:08 -0400181 public void init() {
Charles Chan2690fac2018-04-13 14:01:49 -0400182 ROUTE_STORE.put(P1, Sets.newHashSet(RR1));
Charles Chan2fde6d42017-08-23 14:46:43 -0700183
Charles Chan1a3b02a2017-08-18 17:11:34 -0700184 routeHandler.init(CP1.deviceId());
185
186 assertEquals(1, ROUTING_TABLE.size());
Charles Chan9640c812017-08-23 13:55:39 -0700187 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
188 assertEquals(M1, rtv1.macAddress);
189 assertEquals(V1, rtv1.vlanId);
190 assertEquals(CP1.port(), rtv1.portNumber);
191
Charles Chan1a3b02a2017-08-18 17:11:34 -0700192 assertEquals(1, SUBNET_TABLE.size());
193 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
194 }
195
196 @Test
Charles Chan2690fac2018-04-13 14:01:49 -0400197 public void initTwoNextHops() {
198 ROUTE_STORE.put(P1, Sets.newHashSet(RR1, RR2));
199
200 routeHandler.init(CP1.deviceId());
201
202 assertEquals(2, ROUTING_TABLE.size());
203 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
204 assertEquals(M1, rtv1.macAddress);
205 assertEquals(V1, rtv1.vlanId);
206 assertEquals(CP1.port(), rtv1.portNumber);
207 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
208 assertEquals(M2, rtv2.macAddress);
209 assertEquals(V2, rtv2.vlanId);
210 assertEquals(CP2.port(), rtv2.portNumber);
211
212 assertEquals(2, SUBNET_TABLE.size());
213 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
214 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
215 }
216
217 @Test
Charles Chane7c7d052018-04-09 11:52:08 -0400218 public void processRouteAdded() {
Charles Chan08d91322018-02-05 17:20:05 -0800219 reset(srManager.deviceConfiguration);
220 srManager.deviceConfiguration.addSubnet(CP1, P1);
221 expectLastCall().once();
222 replay(srManager.deviceConfiguration);
223
Charles Chan2fde6d42017-08-23 14:46:43 -0700224 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1));
Charles Chan1a3b02a2017-08-18 17:11:34 -0700225 routeHandler.processRouteAdded(re);
226
227 assertEquals(1, ROUTING_TABLE.size());
Charles Chan9640c812017-08-23 13:55:39 -0700228 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
229 assertEquals(M1, rtv1.macAddress);
230 assertEquals(V1, rtv1.vlanId);
231 assertEquals(CP1.port(), rtv1.portNumber);
232
Charles Chan1a3b02a2017-08-18 17:11:34 -0700233 assertEquals(1, SUBNET_TABLE.size());
234 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan08d91322018-02-05 17:20:05 -0800235
236 verify(srManager.deviceConfiguration);
Charles Chan1a3b02a2017-08-18 17:11:34 -0700237 }
238
239 @Test
Charles Chane7c7d052018-04-09 11:52:08 -0400240 public void processRouteUpdated() {
Charles Chan1a3b02a2017-08-18 17:11:34 -0700241 processRouteAdded();
242
Charles Chan08d91322018-02-05 17:20:05 -0800243 reset(srManager.deviceConfiguration);
244 srManager.deviceConfiguration.removeSubnet(CP1, P1);
245 expectLastCall().once();
246 srManager.deviceConfiguration.addSubnet(CP2, P1);
247 expectLastCall().once();
248 replay(srManager.deviceConfiguration);
249
Charles Chan2fde6d42017-08-23 14:46:43 -0700250 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_UPDATED, RR2, RR1, Sets.newHashSet(RR2),
251 Sets.newHashSet(RR1));
Charles Chan1a3b02a2017-08-18 17:11:34 -0700252 routeHandler.processRouteUpdated(re);
253
Charles Chan08d91322018-02-05 17:20:05 -0800254 // Note: We shouldn't remove the old nexthop during the occasion of route update
255 // since the populate subnet will take care of it and point it to an ECMP group
256 assertEquals(2, ROUTING_TABLE.size());
Charles Chan2fde6d42017-08-23 14:46:43 -0700257 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
Charles Chan9640c812017-08-23 13:55:39 -0700258 assertEquals(M2, rtv2.macAddress);
259 assertEquals(V2, rtv2.vlanId);
260 assertEquals(CP2.port(), rtv2.portNumber);
261
Charles Chan1a3b02a2017-08-18 17:11:34 -0700262 assertEquals(1, SUBNET_TABLE.size());
263 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan08d91322018-02-05 17:20:05 -0800264
265 verify(srManager.deviceConfiguration);
Charles Chan1a3b02a2017-08-18 17:11:34 -0700266 }
267
268 @Test
Charles Chane7c7d052018-04-09 11:52:08 -0400269 public void processRouteRemoved() {
Charles Chan1a3b02a2017-08-18 17:11:34 -0700270 processRouteAdded();
271
Charles Chan08d91322018-02-05 17:20:05 -0800272 reset(srManager.deviceConfiguration);
273 srManager.deviceConfiguration.removeSubnet(CP1, P1);
274 expectLastCall().once();
275 replay(srManager.deviceConfiguration);
276
Charles Chan2fde6d42017-08-23 14:46:43 -0700277 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1));
278 routeHandler.processRouteRemoved(re);
279
280 assertEquals(0, ROUTING_TABLE.size());
281 assertEquals(0, SUBNET_TABLE.size());
Charles Chan08d91322018-02-05 17:20:05 -0800282
283 verify(srManager.deviceConfiguration);
Charles Chan2fde6d42017-08-23 14:46:43 -0700284 }
285
286 @Test
Charles Chane7c7d052018-04-09 11:52:08 -0400287 public void testTwoSingleHomedAdded() {
Charles Chan08d91322018-02-05 17:20:05 -0800288 reset(srManager.deviceConfiguration);
289 srManager.deviceConfiguration.addSubnet(CP1, P1);
290 expectLastCall().once();
291 srManager.deviceConfiguration.addSubnet(CP2, P1);
292 expectLastCall().once();
293 replay(srManager.deviceConfiguration);
294
Charles Chan2fde6d42017-08-23 14:46:43 -0700295 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
296 routeHandler.processRouteAdded(re);
297
298 assertEquals(2, ROUTING_TABLE.size());
299 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
300 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
301 assertEquals(M1, rtv1.macAddress);
302 assertEquals(M2, rtv2.macAddress);
303 assertEquals(V1, rtv1.vlanId);
304 assertEquals(V2, rtv2.vlanId);
305 assertEquals(CP1.port(), rtv1.portNumber);
306 assertEquals(CP2.port(), rtv2.portNumber);
307
308 assertEquals(2, SUBNET_TABLE.size());
309 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
310 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan08d91322018-02-05 17:20:05 -0800311
312 verify(srManager.deviceConfiguration);
Charles Chan2fde6d42017-08-23 14:46:43 -0700313 }
314
315 @Test
Charles Chane7c7d052018-04-09 11:52:08 -0400316 public void testOneDualHomedAdded() {
Charles Chan08d91322018-02-05 17:20:05 -0800317 reset(srManager.deviceConfiguration);
318 srManager.deviceConfiguration.addSubnet(CP1, P1);
319 expectLastCall().once();
320 srManager.deviceConfiguration.addSubnet(CP2, P1);
321 expectLastCall().once();
322 replay(srManager.deviceConfiguration);
323
Charles Chan2fde6d42017-08-23 14:46:43 -0700324 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR3, Sets.newHashSet(RR3));
325 routeHandler.processRouteAdded(re);
326
327 assertEquals(2, ROUTING_TABLE.size());
328 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
329 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
330 assertEquals(M3, rtv1.macAddress);
331 assertEquals(M3, rtv2.macAddress);
332 assertEquals(V3, rtv1.vlanId);
333 assertEquals(V3, rtv2.vlanId);
334 assertEquals(CP1.port(), rtv1.portNumber);
335 assertEquals(CP2.port(), rtv2.portNumber);
336
337 assertEquals(2, SUBNET_TABLE.size());
338 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
339 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan08d91322018-02-05 17:20:05 -0800340
341 verify(srManager.deviceConfiguration);
Charles Chan2fde6d42017-08-23 14:46:43 -0700342 }
343
344 @Test
Charles Chane7c7d052018-04-09 11:52:08 -0400345 public void testOneSingleHomedToTwoSingleHomed() {
Charles Chan2fde6d42017-08-23 14:46:43 -0700346 processRouteAdded();
347
Charles Chan08d91322018-02-05 17:20:05 -0800348 reset(srManager.deviceConfiguration);
349 srManager.deviceConfiguration.addSubnet(CP2, P1);
350 expectLastCall().once();
351 replay(srManager.deviceConfiguration);
352
Charles Chan2fde6d42017-08-23 14:46:43 -0700353 RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
354 Sets.newHashSet(RR1, RR2), Sets.newHashSet(RR1));
355 routeHandler.processAlternativeRoutesChanged(re);
356
357 assertEquals(2, ROUTING_TABLE.size());
358 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
359 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
360 assertEquals(M1, rtv1.macAddress);
361 assertEquals(M2, rtv2.macAddress);
362 assertEquals(V1, rtv1.vlanId);
363 assertEquals(V2, rtv2.vlanId);
364 assertEquals(CP1.port(), rtv1.portNumber);
365 assertEquals(CP2.port(), rtv2.portNumber);
366
367 assertEquals(2, SUBNET_TABLE.size());
368 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
369 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan08d91322018-02-05 17:20:05 -0800370
371 verify(srManager.deviceConfiguration);
Charles Chan2fde6d42017-08-23 14:46:43 -0700372 }
373
374 @Test
Charles Chane7c7d052018-04-09 11:52:08 -0400375 public void testTwoSingleHomedToOneSingleHomed() {
Charles Chan2fde6d42017-08-23 14:46:43 -0700376 testTwoSingleHomedAdded();
377
Charles Chan08d91322018-02-05 17:20:05 -0800378 reset(srManager.deviceConfiguration);
379 srManager.deviceConfiguration.removeSubnet(CP2, P1);
380 expectLastCall().once();
381 replay(srManager.deviceConfiguration);
382
Charles Chan2fde6d42017-08-23 14:46:43 -0700383 RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
384 Sets.newHashSet(RR1), Sets.newHashSet(RR1, RR2));
385 routeHandler.processAlternativeRoutesChanged(re);
386
Charles Chan08d91322018-02-05 17:20:05 -0800387 // Note: We shouldn't remove the old nexthop during the occasion of route update
388 // since the populate subnet will take care of it and point it to an ECMP group
389 assertEquals(2, ROUTING_TABLE.size());
Charles Chan2fde6d42017-08-23 14:46:43 -0700390 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
391 assertEquals(M1, rtv1.macAddress);
392 assertEquals(V1, rtv1.vlanId);
393 assertEquals(CP1.port(), rtv1.portNumber);
394
395 assertEquals(1, SUBNET_TABLE.size());
396 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan08d91322018-02-05 17:20:05 -0800397
398 verify(srManager.deviceConfiguration);
Charles Chan2fde6d42017-08-23 14:46:43 -0700399 }
400
Charles Chan08d91322018-02-05 17:20:05 -0800401 // TODO Add test cases for two single homed next hop at same location
402
Charles Chan2fde6d42017-08-23 14:46:43 -0700403 @Test
Charles Chane7c7d052018-04-09 11:52:08 -0400404 public void testDualHomedSingleLocationFail() {
Charles Chan2fde6d42017-08-23 14:46:43 -0700405 testOneDualHomedAdded();
406
Charles Chan2690fac2018-04-13 14:01:49 -0400407 ROUTE_STORE.put(P1, Sets.newHashSet(RR3));
408
Charles Chan05b06bc2018-07-17 16:33:11 -0700409 reset(srManager.deviceConfiguration);
410 srManager.deviceConfiguration.removeSubnet(CP2, P1);
411 expectLastCall().once();
412 replay(srManager.deviceConfiguration);
413
Charles Chan2fde6d42017-08-23 14:46:43 -0700414 HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3S, H3D);
415 routeHandler.processHostMovedEvent(he);
416
Charles Chan0f7897f2019-02-28 15:40:57 -0800417 // We do not remove the route on CP2. Instead, we let the subnet population overrides it
418 assertEquals(2, ROUTING_TABLE.size());
Charles Chan2fde6d42017-08-23 14:46:43 -0700419 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
Charles Chan2fde6d42017-08-23 14:46:43 -0700420 assertEquals(M3, rtv1.macAddress);
Charles Chan2fde6d42017-08-23 14:46:43 -0700421 assertEquals(V3, rtv1.vlanId);
Charles Chan2fde6d42017-08-23 14:46:43 -0700422 assertEquals(CP1.port(), rtv1.portNumber);
Charles Chan2fde6d42017-08-23 14:46:43 -0700423
424 // ECMP route table hasn't changed
Charles Chan05b06bc2018-07-17 16:33:11 -0700425 assertEquals(1, SUBNET_TABLE.size());
Charles Chan2fde6d42017-08-23 14:46:43 -0700426 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan05b06bc2018-07-17 16:33:11 -0700427
428 verify(srManager.deviceConfiguration);
Charles Chan2fde6d42017-08-23 14:46:43 -0700429 }
430
431 @Test
Charles Chane7c7d052018-04-09 11:52:08 -0400432 public void testDualHomedBothLocationFail() {
Charles Chan2fde6d42017-08-23 14:46:43 -0700433 testDualHomedSingleLocationFail();
434
435 hostService = new MockHostService(HOSTS_ONE_FAIL);
436
Charles Chan08d91322018-02-05 17:20:05 -0800437 reset(srManager.deviceConfiguration);
438 srManager.deviceConfiguration.removeSubnet(CP1, P1);
439 expectLastCall().once();
440 srManager.deviceConfiguration.removeSubnet(CP2, P1);
441 expectLastCall().once();
442 replay(srManager.deviceConfiguration);
443
Charles Chan2fde6d42017-08-23 14:46:43 -0700444 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
445 routeHandler.processRouteRemoved(re);
446
447 assertEquals(0, ROUTING_TABLE.size());
448 assertEquals(0, SUBNET_TABLE.size());
Charles Chan08d91322018-02-05 17:20:05 -0800449
450 verify(srManager.deviceConfiguration);
Charles Chan2fde6d42017-08-23 14:46:43 -0700451 }
452
453 @Test
Charles Chan05b06bc2018-07-17 16:33:11 -0700454 public void testSingleHomedToDualHomed() {
455 testDualHomedSingleLocationFail();
456
457 reset(srManager.deviceConfiguration);
458 srManager.deviceConfiguration.addSubnet(CP2, P1);
459 expectLastCall().once();
460 replay(srManager.deviceConfiguration);
461
462 HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3D, H3S);
463 routeHandler.processHostMovedEvent(he);
464
465 assertEquals(2, ROUTING_TABLE.size());
466 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
467 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
468 assertEquals(M3, rtv1.macAddress);
469 assertEquals(M3, rtv2.macAddress);
470 assertEquals(V3, rtv1.vlanId);
471 assertEquals(V3, rtv2.vlanId);
472 assertEquals(CP1.port(), rtv1.portNumber);
473 assertEquals(CP2.port(), rtv2.portNumber);
474
475 assertEquals(2, SUBNET_TABLE.size());
476 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
477 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
478
479 verify(srManager.deviceConfiguration);
480 }
481
482 @Test
Charles Chane7c7d052018-04-09 11:52:08 -0400483 public void testTwoSingleHomedRemoved() {
Charles Chan2fde6d42017-08-23 14:46:43 -0700484 testTwoSingleHomedAdded();
485
486 hostService = new MockHostService(HOSTS_BOTH_FAIL);
487
Charles Chan08d91322018-02-05 17:20:05 -0800488 reset(srManager.deviceConfiguration);
489 srManager.deviceConfiguration.removeSubnet(CP1, P1);
490 expectLastCall().once();
491 srManager.deviceConfiguration.removeSubnet(CP2, P1);
492 expectLastCall().once();
493 replay(srManager.deviceConfiguration);
494
Charles Chan2fde6d42017-08-23 14:46:43 -0700495 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1, RR2));
496 routeHandler.processRouteRemoved(re);
497
498 assertEquals(0, ROUTING_TABLE.size());
499 assertEquals(0, SUBNET_TABLE.size());
Charles Chan08d91322018-02-05 17:20:05 -0800500
501 verify(srManager.deviceConfiguration);
Charles Chan2fde6d42017-08-23 14:46:43 -0700502 }
503
504 @Test
Charles Chane7c7d052018-04-09 11:52:08 -0400505 public void testOneDualHomeRemoved() {
Charles Chan2fde6d42017-08-23 14:46:43 -0700506 testOneDualHomedAdded();
507
Charles Chan08d91322018-02-05 17:20:05 -0800508 reset(srManager.deviceConfiguration);
509 srManager.deviceConfiguration.removeSubnet(CP1, P1);
510 expectLastCall().once();
511 srManager.deviceConfiguration.removeSubnet(CP2, P1);
512 expectLastCall().once();
513 replay(srManager.deviceConfiguration);
514
Charles Chan2fde6d42017-08-23 14:46:43 -0700515 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
Charles Chan1a3b02a2017-08-18 17:11:34 -0700516 routeHandler.processRouteRemoved(re);
517
518 assertEquals(0, ROUTING_TABLE.size());
519 assertEquals(0, SUBNET_TABLE.size());
Charles Chan08d91322018-02-05 17:20:05 -0800520
521 verify(srManager.deviceConfiguration);
Charles Chan1a3b02a2017-08-18 17:11:34 -0700522 }
Charles Chane7c7d052018-04-09 11:52:08 -0400523
524 @Test
525 public void testMoreThanTwoNextHop() {
526 // next hop = CP1, CP2
527 reset(srManager.deviceConfiguration);
528 srManager.deviceConfiguration.addSubnet(CP1, P1);
529 srManager.deviceConfiguration.addSubnet(CP2, P1);
530 expectLastCall().once();
531 replay(srManager.deviceConfiguration);
532
533 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
534 routeHandler.processRouteAdded(re);
535
536 assertEquals(2, ROUTING_TABLE.size());
537 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
538 assertEquals(M1, rtv1.macAddress);
539 assertEquals(V1, rtv1.vlanId);
540 assertEquals(CP1.port(), rtv1.portNumber);
541 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
542 assertEquals(M2, rtv2.macAddress);
543 assertEquals(V2, rtv2.vlanId);
544 assertEquals(CP2.port(), rtv2.portNumber);
545
546 assertEquals(2, SUBNET_TABLE.size());
547 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
548 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
549
550 verify(srManager.deviceConfiguration);
551
552 // next hop = CP1, CP2, CP4 (invalid)
553 re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
554 Sets.newHashSet(RR1, RR2, RR4), Sets.newHashSet(RR1, RR2));
555 routeHandler.processAlternativeRoutesChanged(re);
556
557 assertEquals(2, ROUTING_TABLE.size());
558 rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
559 assertEquals(M1, rtv1.macAddress);
560 assertEquals(V1, rtv1.vlanId);
561 assertEquals(CP1.port(), rtv1.portNumber);
562 rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
563 assertEquals(M2, rtv2.macAddress);
564 assertEquals(V2, rtv2.vlanId);
565 assertEquals(CP2.port(), rtv2.portNumber);
566
567 assertEquals(2, SUBNET_TABLE.size());
568 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
569 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
570
571 // next hop = CP2, CP4
572 reset(srManager.deviceConfiguration);
573 srManager.deviceConfiguration.addSubnet(CP2, P1);
574 srManager.deviceConfiguration.addSubnet(CP4, P1);
575 expectLastCall().once();
576 replay(srManager.deviceConfiguration);
577
578 re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
579 Sets.newHashSet(RR2, RR4), Sets.newHashSet(RR1, RR2, RR4));
580 routeHandler.processAlternativeRoutesChanged(re);
581
582 assertEquals(2, ROUTING_TABLE.size());
583 rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
584 assertEquals(M2, rtv1.macAddress);
585 assertEquals(V2, rtv1.vlanId);
586 assertEquals(CP2.port(), rtv1.portNumber);
587 rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP4.deviceId(), P1));
588 assertEquals(M4, rtv2.macAddress);
589 assertEquals(V4, rtv2.vlanId);
590 assertEquals(CP4.port(), rtv2.portNumber);
591
592 assertEquals(2, SUBNET_TABLE.size());
593 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
594 assertTrue(SUBNET_TABLE.get(CP4).contains(P1));
595
596 verify(srManager.deviceConfiguration);
597 }
Ruchi Sahotaef0761c2019-01-28 01:08:18 +0000598}