blob: a727e67a6aeaeb34d7478f7bd93e9a919b04d1df [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 Chan2fde6d42017-08-23 14:46:43 -0700409 HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3S, H3D);
410 routeHandler.processHostMovedEvent(he);
411
412 assertEquals(2, ROUTING_TABLE.size());
413 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
414 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
415 assertEquals(M3, rtv1.macAddress);
416 assertEquals(M3, rtv2.macAddress);
417 assertEquals(V3, rtv1.vlanId);
418 assertEquals(V3, rtv2.vlanId);
419 assertEquals(CP1.port(), rtv1.portNumber);
420 assertEquals(P9, rtv2.portNumber);
421
422 // ECMP route table hasn't changed
423 assertEquals(2, SUBNET_TABLE.size());
424 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
425 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
426 }
427
428 @Test
Charles Chane7c7d052018-04-09 11:52:08 -0400429 public void testDualHomedBothLocationFail() {
Charles Chan2fde6d42017-08-23 14:46:43 -0700430 testDualHomedSingleLocationFail();
431
432 hostService = new MockHostService(HOSTS_ONE_FAIL);
433
Charles Chan08d91322018-02-05 17:20:05 -0800434 reset(srManager.deviceConfiguration);
435 srManager.deviceConfiguration.removeSubnet(CP1, P1);
436 expectLastCall().once();
437 srManager.deviceConfiguration.removeSubnet(CP2, P1);
438 expectLastCall().once();
439 replay(srManager.deviceConfiguration);
440
Charles Chan2fde6d42017-08-23 14:46:43 -0700441 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
442 routeHandler.processRouteRemoved(re);
443
444 assertEquals(0, ROUTING_TABLE.size());
445 assertEquals(0, SUBNET_TABLE.size());
Charles Chan08d91322018-02-05 17:20:05 -0800446
447 verify(srManager.deviceConfiguration);
Charles Chan2fde6d42017-08-23 14:46:43 -0700448 }
449
450 @Test
Charles Chane7c7d052018-04-09 11:52:08 -0400451 public void testTwoSingleHomedRemoved() {
Charles Chan2fde6d42017-08-23 14:46:43 -0700452 testTwoSingleHomedAdded();
453
454 hostService = new MockHostService(HOSTS_BOTH_FAIL);
455
Charles Chan08d91322018-02-05 17:20:05 -0800456 reset(srManager.deviceConfiguration);
457 srManager.deviceConfiguration.removeSubnet(CP1, P1);
458 expectLastCall().once();
459 srManager.deviceConfiguration.removeSubnet(CP2, P1);
460 expectLastCall().once();
461 replay(srManager.deviceConfiguration);
462
Charles Chan2fde6d42017-08-23 14:46:43 -0700463 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1, RR2));
464 routeHandler.processRouteRemoved(re);
465
466 assertEquals(0, ROUTING_TABLE.size());
467 assertEquals(0, SUBNET_TABLE.size());
Charles Chan08d91322018-02-05 17:20:05 -0800468
469 verify(srManager.deviceConfiguration);
Charles Chan2fde6d42017-08-23 14:46:43 -0700470 }
471
472 @Test
Charles Chane7c7d052018-04-09 11:52:08 -0400473 public void testOneDualHomeRemoved() {
Charles Chan2fde6d42017-08-23 14:46:43 -0700474 testOneDualHomedAdded();
475
Charles Chan08d91322018-02-05 17:20:05 -0800476 reset(srManager.deviceConfiguration);
477 srManager.deviceConfiguration.removeSubnet(CP1, P1);
478 expectLastCall().once();
479 srManager.deviceConfiguration.removeSubnet(CP2, P1);
480 expectLastCall().once();
481 replay(srManager.deviceConfiguration);
482
Charles Chan2fde6d42017-08-23 14:46:43 -0700483 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
Charles Chan1a3b02a2017-08-18 17:11:34 -0700484 routeHandler.processRouteRemoved(re);
485
486 assertEquals(0, ROUTING_TABLE.size());
487 assertEquals(0, SUBNET_TABLE.size());
Charles Chan08d91322018-02-05 17:20:05 -0800488
489 verify(srManager.deviceConfiguration);
Charles Chan1a3b02a2017-08-18 17:11:34 -0700490 }
Charles Chane7c7d052018-04-09 11:52:08 -0400491
492 @Test
493 public void testMoreThanTwoNextHop() {
494 // next hop = CP1, CP2
495 reset(srManager.deviceConfiguration);
496 srManager.deviceConfiguration.addSubnet(CP1, P1);
497 srManager.deviceConfiguration.addSubnet(CP2, P1);
498 expectLastCall().once();
499 replay(srManager.deviceConfiguration);
500
501 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
502 routeHandler.processRouteAdded(re);
503
504 assertEquals(2, ROUTING_TABLE.size());
505 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
506 assertEquals(M1, rtv1.macAddress);
507 assertEquals(V1, rtv1.vlanId);
508 assertEquals(CP1.port(), rtv1.portNumber);
509 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
510 assertEquals(M2, rtv2.macAddress);
511 assertEquals(V2, rtv2.vlanId);
512 assertEquals(CP2.port(), rtv2.portNumber);
513
514 assertEquals(2, SUBNET_TABLE.size());
515 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
516 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
517
518 verify(srManager.deviceConfiguration);
519
520 // next hop = CP1, CP2, CP4 (invalid)
521 re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
522 Sets.newHashSet(RR1, RR2, RR4), Sets.newHashSet(RR1, RR2));
523 routeHandler.processAlternativeRoutesChanged(re);
524
525 assertEquals(2, ROUTING_TABLE.size());
526 rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
527 assertEquals(M1, rtv1.macAddress);
528 assertEquals(V1, rtv1.vlanId);
529 assertEquals(CP1.port(), rtv1.portNumber);
530 rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
531 assertEquals(M2, rtv2.macAddress);
532 assertEquals(V2, rtv2.vlanId);
533 assertEquals(CP2.port(), rtv2.portNumber);
534
535 assertEquals(2, SUBNET_TABLE.size());
536 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
537 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
538
539 // next hop = CP2, CP4
540 reset(srManager.deviceConfiguration);
541 srManager.deviceConfiguration.addSubnet(CP2, P1);
542 srManager.deviceConfiguration.addSubnet(CP4, P1);
543 expectLastCall().once();
544 replay(srManager.deviceConfiguration);
545
546 re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
547 Sets.newHashSet(RR2, RR4), Sets.newHashSet(RR1, RR2, RR4));
548 routeHandler.processAlternativeRoutesChanged(re);
549
550 assertEquals(2, ROUTING_TABLE.size());
551 rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
552 assertEquals(M2, rtv1.macAddress);
553 assertEquals(V2, rtv1.vlanId);
554 assertEquals(CP2.port(), rtv1.portNumber);
555 rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP4.deviceId(), P1));
556 assertEquals(M4, rtv2.macAddress);
557 assertEquals(V4, rtv2.vlanId);
558 assertEquals(CP4.port(), rtv2.portNumber);
559
560 assertEquals(2, SUBNET_TABLE.size());
561 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
562 assertTrue(SUBNET_TABLE.get(CP4).contains(P1));
563
564 verify(srManager.deviceConfiguration);
565 }
Charles Chan1a3b02a2017-08-18 17:11:34 -0700566}