blob: 7804e6893015c78e7f0820ba9ec2752179206ae9 [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 Chan05b06bc2018-07-17 16:33:11 -0700417 assertEquals(1, ROUTING_TABLE.size());
Charles Chan2fde6d42017-08-23 14:46:43 -0700418 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
Charles Chan2fde6d42017-08-23 14:46:43 -0700419 assertEquals(M3, rtv1.macAddress);
Charles Chan2fde6d42017-08-23 14:46:43 -0700420 assertEquals(V3, rtv1.vlanId);
Charles Chan2fde6d42017-08-23 14:46:43 -0700421 assertEquals(CP1.port(), rtv1.portNumber);
Charles Chan2fde6d42017-08-23 14:46:43 -0700422
423 // ECMP route table hasn't changed
Charles Chan05b06bc2018-07-17 16:33:11 -0700424 assertEquals(1, SUBNET_TABLE.size());
Charles Chan2fde6d42017-08-23 14:46:43 -0700425 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan05b06bc2018-07-17 16:33:11 -0700426
427 verify(srManager.deviceConfiguration);
Charles Chan2fde6d42017-08-23 14:46:43 -0700428 }
429
430 @Test
Charles Chane7c7d052018-04-09 11:52:08 -0400431 public void testDualHomedBothLocationFail() {
Charles Chan2fde6d42017-08-23 14:46:43 -0700432 testDualHomedSingleLocationFail();
433
434 hostService = new MockHostService(HOSTS_ONE_FAIL);
435
Charles Chan08d91322018-02-05 17:20:05 -0800436 reset(srManager.deviceConfiguration);
437 srManager.deviceConfiguration.removeSubnet(CP1, P1);
438 expectLastCall().once();
439 srManager.deviceConfiguration.removeSubnet(CP2, P1);
440 expectLastCall().once();
441 replay(srManager.deviceConfiguration);
442
Charles Chan2fde6d42017-08-23 14:46:43 -0700443 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
444 routeHandler.processRouteRemoved(re);
445
446 assertEquals(0, ROUTING_TABLE.size());
447 assertEquals(0, SUBNET_TABLE.size());
Charles Chan08d91322018-02-05 17:20:05 -0800448
449 verify(srManager.deviceConfiguration);
Charles Chan2fde6d42017-08-23 14:46:43 -0700450 }
451
452 @Test
Charles Chan05b06bc2018-07-17 16:33:11 -0700453 public void testSingleHomedToDualHomed() {
454 testDualHomedSingleLocationFail();
455
456 reset(srManager.deviceConfiguration);
457 srManager.deviceConfiguration.addSubnet(CP2, P1);
458 expectLastCall().once();
459 replay(srManager.deviceConfiguration);
460
461 HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3D, H3S);
462 routeHandler.processHostMovedEvent(he);
463
464 assertEquals(2, ROUTING_TABLE.size());
465 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
466 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
467 assertEquals(M3, rtv1.macAddress);
468 assertEquals(M3, rtv2.macAddress);
469 assertEquals(V3, rtv1.vlanId);
470 assertEquals(V3, rtv2.vlanId);
471 assertEquals(CP1.port(), rtv1.portNumber);
472 assertEquals(CP2.port(), rtv2.portNumber);
473
474 assertEquals(2, SUBNET_TABLE.size());
475 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
476 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
477
478 verify(srManager.deviceConfiguration);
479 }
480
481 @Test
Charles Chane7c7d052018-04-09 11:52:08 -0400482 public void testTwoSingleHomedRemoved() {
Charles Chan2fde6d42017-08-23 14:46:43 -0700483 testTwoSingleHomedAdded();
484
485 hostService = new MockHostService(HOSTS_BOTH_FAIL);
486
Charles Chan08d91322018-02-05 17:20:05 -0800487 reset(srManager.deviceConfiguration);
488 srManager.deviceConfiguration.removeSubnet(CP1, P1);
489 expectLastCall().once();
490 srManager.deviceConfiguration.removeSubnet(CP2, P1);
491 expectLastCall().once();
492 replay(srManager.deviceConfiguration);
493
Charles Chan2fde6d42017-08-23 14:46:43 -0700494 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1, RR2));
495 routeHandler.processRouteRemoved(re);
496
497 assertEquals(0, ROUTING_TABLE.size());
498 assertEquals(0, SUBNET_TABLE.size());
Charles Chan08d91322018-02-05 17:20:05 -0800499
500 verify(srManager.deviceConfiguration);
Charles Chan2fde6d42017-08-23 14:46:43 -0700501 }
502
503 @Test
Charles Chane7c7d052018-04-09 11:52:08 -0400504 public void testOneDualHomeRemoved() {
Charles Chan2fde6d42017-08-23 14:46:43 -0700505 testOneDualHomedAdded();
506
Charles Chan08d91322018-02-05 17:20:05 -0800507 reset(srManager.deviceConfiguration);
508 srManager.deviceConfiguration.removeSubnet(CP1, P1);
509 expectLastCall().once();
510 srManager.deviceConfiguration.removeSubnet(CP2, P1);
511 expectLastCall().once();
512 replay(srManager.deviceConfiguration);
513
Charles Chan2fde6d42017-08-23 14:46:43 -0700514 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
Charles Chan1a3b02a2017-08-18 17:11:34 -0700515 routeHandler.processRouteRemoved(re);
516
517 assertEquals(0, ROUTING_TABLE.size());
518 assertEquals(0, SUBNET_TABLE.size());
Charles Chan08d91322018-02-05 17:20:05 -0800519
520 verify(srManager.deviceConfiguration);
Charles Chan1a3b02a2017-08-18 17:11:34 -0700521 }
Charles Chane7c7d052018-04-09 11:52:08 -0400522
523 @Test
524 public void testMoreThanTwoNextHop() {
525 // next hop = CP1, CP2
526 reset(srManager.deviceConfiguration);
527 srManager.deviceConfiguration.addSubnet(CP1, P1);
528 srManager.deviceConfiguration.addSubnet(CP2, P1);
529 expectLastCall().once();
530 replay(srManager.deviceConfiguration);
531
532 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
533 routeHandler.processRouteAdded(re);
534
535 assertEquals(2, ROUTING_TABLE.size());
536 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
537 assertEquals(M1, rtv1.macAddress);
538 assertEquals(V1, rtv1.vlanId);
539 assertEquals(CP1.port(), rtv1.portNumber);
540 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
541 assertEquals(M2, rtv2.macAddress);
542 assertEquals(V2, rtv2.vlanId);
543 assertEquals(CP2.port(), rtv2.portNumber);
544
545 assertEquals(2, SUBNET_TABLE.size());
546 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
547 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
548
549 verify(srManager.deviceConfiguration);
550
551 // next hop = CP1, CP2, CP4 (invalid)
552 re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
553 Sets.newHashSet(RR1, RR2, RR4), Sets.newHashSet(RR1, RR2));
554 routeHandler.processAlternativeRoutesChanged(re);
555
556 assertEquals(2, ROUTING_TABLE.size());
557 rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
558 assertEquals(M1, rtv1.macAddress);
559 assertEquals(V1, rtv1.vlanId);
560 assertEquals(CP1.port(), rtv1.portNumber);
561 rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
562 assertEquals(M2, rtv2.macAddress);
563 assertEquals(V2, rtv2.vlanId);
564 assertEquals(CP2.port(), rtv2.portNumber);
565
566 assertEquals(2, SUBNET_TABLE.size());
567 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
568 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
569
570 // next hop = CP2, CP4
571 reset(srManager.deviceConfiguration);
572 srManager.deviceConfiguration.addSubnet(CP2, P1);
573 srManager.deviceConfiguration.addSubnet(CP4, P1);
574 expectLastCall().once();
575 replay(srManager.deviceConfiguration);
576
577 re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
578 Sets.newHashSet(RR2, RR4), Sets.newHashSet(RR1, RR2, RR4));
579 routeHandler.processAlternativeRoutesChanged(re);
580
581 assertEquals(2, ROUTING_TABLE.size());
582 rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
583 assertEquals(M2, rtv1.macAddress);
584 assertEquals(V2, rtv1.vlanId);
585 assertEquals(CP2.port(), rtv1.portNumber);
586 rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP4.deviceId(), P1));
587 assertEquals(M4, rtv2.macAddress);
588 assertEquals(V4, rtv2.vlanId);
589 assertEquals(CP4.port(), rtv2.portNumber);
590
591 assertEquals(2, SUBNET_TABLE.size());
592 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
593 assertTrue(SUBNET_TABLE.get(CP4).contains(P1));
594
595 verify(srManager.deviceConfiguration);
596 }
Charles Chan1a3b02a2017-08-18 17:11:34 -0700597}