blob: bdf056e37fdb1b4e1f98a0473481f0ed540c12e6 [file] [log] [blame]
Charles Chan6c624992017-08-18 17:11:34 -07001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.segmentrouting;
18
Charles Chan910be6a2017-08-23 14:46:43 -070019import com.fasterxml.jackson.databind.JsonNode;
20import com.fasterxml.jackson.databind.ObjectMapper;
Charles Chan6c624992017-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 Chan910be6a2017-08-23 14:46:43 -070029import org.onosproject.net.config.ConfigApplyDelegate;
Charles Chan6c624992017-08-18 17:11:34 -070030import org.onosproject.net.ConnectPoint;
Charles Chanf0ae41e2017-08-23 13:55:39 -070031import org.onosproject.net.DefaultHost;
Charles Chan6c624992017-08-18 17:11:34 -070032import org.onosproject.net.DeviceId;
33import org.onosproject.net.Host;
Charles Chanf0ae41e2017-08-23 13:55:39 -070034import org.onosproject.net.HostId;
35import org.onosproject.net.HostLocation;
Charles Chan910be6a2017-08-23 14:46:43 -070036import org.onosproject.net.PortNumber;
Charles Chan6c624992017-08-18 17:11:34 -070037import org.onosproject.net.config.NetworkConfigRegistryAdapter;
38import org.onosproject.net.flow.TrafficTreatment;
Charles Chan910be6a2017-08-23 14:46:43 -070039import org.onosproject.net.host.HostEvent;
40import org.onosproject.net.host.HostService;
Charles Chan6c624992017-08-18 17:11:34 -070041import org.onosproject.net.intf.Interface;
Charles Chanf0ae41e2017-08-23 13:55:39 -070042import org.onosproject.net.provider.ProviderId;
Charles Chan6c624992017-08-18 17:11:34 -070043import org.onosproject.routeservice.ResolvedRoute;
44import org.onosproject.routeservice.Route;
45import org.onosproject.routeservice.RouteEvent;
Charles Chan6c624992017-08-18 17:11:34 -070046import org.onosproject.segmentrouting.config.DeviceConfiguration;
Charles Chan910be6a2017-08-23 14:46:43 -070047import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
Charles Chand66d6712018-03-29 16:03:41 -070048import org.onosproject.store.service.StorageService;
49import org.onosproject.store.service.TestConsistentMap;
Charles Chan6c624992017-08-18 17:11:34 -070050
51import java.util.Map;
52import java.util.Set;
53
Charles Chand66d6712018-03-29 16:03:41 -070054import static org.easymock.EasyMock.expect;
Charles Chan06f626c2018-02-05 17:20:05 -080055import static org.easymock.EasyMock.reset;
Charles Chan6c624992017-08-18 17:11:34 -070056import static org.junit.Assert.*;
Charles Chan06f626c2018-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 Chan6c624992017-08-18 17:11:34 -070061
62/**
63 * Unit test for {@link RouteHandler}.
64 */
65public class RouteHandlerTest {
Charles Chan06f626c2018-02-05 17:20:05 -080066 private SegmentRoutingManager srManager;
Charles Chan6c624992017-08-18 17:11:34 -070067 private RouteHandler routeHandler;
Charles Chan910be6a2017-08-23 14:46:43 -070068 private HostService hostService;
Charles Chan6c624992017-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 Chan7d20a4e2018-04-13 14:01:49 -040078 private static final Map<IpPrefix, Set<ResolvedRoute>> ROUTE_STORE = Maps.newConcurrentMap();
Charles Chan6c624992017-08-18 17:11:34 -070079
80 private static final IpPrefix P1 = IpPrefix.valueOf("10.0.0.0/24");
Charles Chan910be6a2017-08-23 14:46:43 -070081
82 // Single homed router 1
Charles Chan6c624992017-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 Chanf0ae41e2017-08-23 13:55:39 -070088 private static final ResolvedRoute RR1 = new ResolvedRoute(R1, M1, V1);
Charles Chan6c624992017-08-18 17:11:34 -070089
Charles Chan910be6a2017-08-23 14:46:43 -070090 // Single homed router 2
Charles Chan6c624992017-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 Chan910be6a2017-08-23 14:46:43 -070094 private static final ConnectPoint CP2 = ConnectPoint.deviceConnectPoint("of:0000000000000002/2");
Charles Chan6c624992017-08-18 17:11:34 -070095 private static final Route R2 = new Route(Route.Source.STATIC, P1, N2);
Charles Chanf0ae41e2017-08-23 13:55:39 -070096 private static final ResolvedRoute RR2 = new ResolvedRoute(R2, M2, V2);
Charles Chan6c624992017-08-18 17:11:34 -070097
Charles Chan910be6a2017-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 Chan6c624992017-08-18 17:11:34 -0700104
Charles Chan482b6422018-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 Chan910be6a2017-08-23 14:46:43 -0700113 // Hosts
Charles Chanf0ae41e2017-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 Chan910be6a2017-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 Chan482b6422018-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 Chan910be6a2017-08-23 14:46:43 -0700124
125 // Pair Local Port
126 private static final PortNumber P9 = PortNumber.portNumber(9);
Charles Chanf0ae41e2017-08-23 13:55:39 -0700127
Charles Chan6c624992017-08-18 17:11:34 -0700128 // A set of hosts
Charles Chan482b6422018-04-09 11:52:08 -0400129 private static final Set<Host> HOSTS = Sets.newHashSet(H1, H2, H3D, H4);
Charles Chan910be6a2017-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 Chan6c624992017-08-18 17:11:34 -0700132 // A set of devices of which we have mastership
Charles Chan910be6a2017-08-23 14:46:43 -0700133 private static final Set<DeviceId> LOCAL_DEVICES = Sets.newHashSet(CP1.deviceId(), CP2.deviceId());
Charles Chan6c624992017-08-18 17:11:34 -0700134 // A set of interfaces
135 private static final Set<Interface> INTERFACES = Sets.newHashSet();
Charles Chan6c624992017-08-18 17:11:34 -0700136
137 @Before
Charles Chan482b6422018-04-09 11:52:08 -0400138 public void setUp() {
Charles Chan910be6a2017-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 Chan6c624992017-08-18 17:11:34 -0700151
152 MockNetworkConfigRegistry mockNetworkConfigRegistry = new MockNetworkConfigRegistry();
Charles Chan910be6a2017-08-23 14:46:43 -0700153 mockNetworkConfigRegistry.applyConfig(dev1Config);
154 mockNetworkConfigRegistry.applyConfig(dev2Config);
Charles Chan6c624992017-08-18 17:11:34 -0700155
156 // Initialize Segment Routing Manager
Charles Chan06f626c2018-02-05 17:20:05 -0800157 srManager = new MockSegmentRoutingManager(NEXT_TABLE);
Charles Chand66d6712018-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 Chan6c624992017-08-18 17:11:34 -0700161 srManager.cfgService = new NetworkConfigRegistryAdapter();
Charles Chan06f626c2018-02-05 17:20:05 -0800162 srManager.deviceConfiguration = createMock(DeviceConfiguration.class);
Charles Chan6c624992017-08-18 17:11:34 -0700163 srManager.flowObjectiveService = new MockFlowObjectiveService(BRIDGING_TABLE, NEXT_TABLE);
164 srManager.routingRulePopulator = new MockRoutingRulePopulator(srManager, ROUTING_TABLE);
Charles Chanc4d68882018-03-15 16:41:10 -0700165 srManager.defaultRoutingHandler = new MockDefaultRoutingHandler(srManager, SUBNET_TABLE, ROUTING_TABLE);
Charles Chan6c624992017-08-18 17:11:34 -0700166 srManager.interfaceService = new MockInterfaceService(INTERFACES);
167 srManager.mastershipService = new MockMastershipService(LOCAL_DEVICES);
Charles Chan910be6a2017-08-23 14:46:43 -0700168 hostService = new MockHostService(HOSTS);
169 srManager.hostService = hostService;
Charles Chan6c624992017-08-18 17:11:34 -0700170 srManager.cfgService = mockNetworkConfigRegistry;
Charles Chan7d20a4e2018-04-13 14:01:49 -0400171 srManager.routeService = new MockRouteService(ROUTE_STORE);
Charles Chan6c624992017-08-18 17:11:34 -0700172
Charles Chan910be6a2017-08-23 14:46:43 -0700173 routeHandler = new RouteHandler(srManager) {
174 // routeEventCache is not necessary for unit tests
175 @Override
176 void enqueueRouteEvent(RouteEvent routeEvent) {
177 dequeueRouteEvent(routeEvent);
178 }
179 };
Charles Chan6c624992017-08-18 17:11:34 -0700180
181 ROUTING_TABLE.clear();
182 BRIDGING_TABLE.clear();
183 SUBNET_TABLE.clear();
184 }
185
186 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400187 public void init() {
Charles Chan7d20a4e2018-04-13 14:01:49 -0400188 ROUTE_STORE.put(P1, Sets.newHashSet(RR1));
Charles Chan910be6a2017-08-23 14:46:43 -0700189
Charles Chan6c624992017-08-18 17:11:34 -0700190 routeHandler.init(CP1.deviceId());
191
192 assertEquals(1, ROUTING_TABLE.size());
Charles Chanf0ae41e2017-08-23 13:55:39 -0700193 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
194 assertEquals(M1, rtv1.macAddress);
195 assertEquals(V1, rtv1.vlanId);
196 assertEquals(CP1.port(), rtv1.portNumber);
197
Charles Chan6c624992017-08-18 17:11:34 -0700198 assertEquals(1, SUBNET_TABLE.size());
199 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
200 }
201
202 @Test
Charles Chan7d20a4e2018-04-13 14:01:49 -0400203 public void initTwoNextHops() {
204 ROUTE_STORE.put(P1, Sets.newHashSet(RR1, RR2));
205
206 routeHandler.init(CP1.deviceId());
207
208 assertEquals(2, ROUTING_TABLE.size());
209 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
210 assertEquals(M1, rtv1.macAddress);
211 assertEquals(V1, rtv1.vlanId);
212 assertEquals(CP1.port(), rtv1.portNumber);
213 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
214 assertEquals(M2, rtv2.macAddress);
215 assertEquals(V2, rtv2.vlanId);
216 assertEquals(CP2.port(), rtv2.portNumber);
217
218 assertEquals(2, SUBNET_TABLE.size());
219 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
220 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
221 }
222
223 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400224 public void processRouteAdded() {
Charles Chan06f626c2018-02-05 17:20:05 -0800225 reset(srManager.deviceConfiguration);
226 srManager.deviceConfiguration.addSubnet(CP1, P1);
227 expectLastCall().once();
228 replay(srManager.deviceConfiguration);
229
Charles Chan910be6a2017-08-23 14:46:43 -0700230 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1));
Charles Chan6c624992017-08-18 17:11:34 -0700231 routeHandler.processRouteAdded(re);
232
233 assertEquals(1, ROUTING_TABLE.size());
Charles Chanf0ae41e2017-08-23 13:55:39 -0700234 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
235 assertEquals(M1, rtv1.macAddress);
236 assertEquals(V1, rtv1.vlanId);
237 assertEquals(CP1.port(), rtv1.portNumber);
238
Charles Chan6c624992017-08-18 17:11:34 -0700239 assertEquals(1, SUBNET_TABLE.size());
240 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800241
242 verify(srManager.deviceConfiguration);
Charles Chan6c624992017-08-18 17:11:34 -0700243 }
244
245 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400246 public void processRouteUpdated() {
Charles Chan6c624992017-08-18 17:11:34 -0700247 processRouteAdded();
248
Charles Chan06f626c2018-02-05 17:20:05 -0800249 reset(srManager.deviceConfiguration);
250 srManager.deviceConfiguration.removeSubnet(CP1, P1);
251 expectLastCall().once();
252 srManager.deviceConfiguration.addSubnet(CP2, P1);
253 expectLastCall().once();
254 replay(srManager.deviceConfiguration);
255
Charles Chan910be6a2017-08-23 14:46:43 -0700256 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_UPDATED, RR2, RR1, Sets.newHashSet(RR2),
257 Sets.newHashSet(RR1));
Charles Chan6c624992017-08-18 17:11:34 -0700258 routeHandler.processRouteUpdated(re);
259
Charles Chan06f626c2018-02-05 17:20:05 -0800260 // Note: We shouldn't remove the old nexthop during the occasion of route update
261 // since the populate subnet will take care of it and point it to an ECMP group
262 assertEquals(2, ROUTING_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700263 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
Charles Chanf0ae41e2017-08-23 13:55:39 -0700264 assertEquals(M2, rtv2.macAddress);
265 assertEquals(V2, rtv2.vlanId);
266 assertEquals(CP2.port(), rtv2.portNumber);
267
Charles Chan6c624992017-08-18 17:11:34 -0700268 assertEquals(1, SUBNET_TABLE.size());
269 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800270
271 verify(srManager.deviceConfiguration);
Charles Chan6c624992017-08-18 17:11:34 -0700272 }
273
274 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400275 public void processRouteRemoved() {
Charles Chan6c624992017-08-18 17:11:34 -0700276 processRouteAdded();
277
Charles Chan06f626c2018-02-05 17:20:05 -0800278 reset(srManager.deviceConfiguration);
279 srManager.deviceConfiguration.removeSubnet(CP1, P1);
280 expectLastCall().once();
281 replay(srManager.deviceConfiguration);
282
Charles Chan910be6a2017-08-23 14:46:43 -0700283 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1));
284 routeHandler.processRouteRemoved(re);
285
286 assertEquals(0, ROUTING_TABLE.size());
287 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800288
289 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700290 }
291
292 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400293 public void testTwoSingleHomedAdded() {
Charles Chan06f626c2018-02-05 17:20:05 -0800294 reset(srManager.deviceConfiguration);
295 srManager.deviceConfiguration.addSubnet(CP1, P1);
296 expectLastCall().once();
297 srManager.deviceConfiguration.addSubnet(CP2, P1);
298 expectLastCall().once();
299 replay(srManager.deviceConfiguration);
300
Charles Chan910be6a2017-08-23 14:46:43 -0700301 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
302 routeHandler.processRouteAdded(re);
303
304 assertEquals(2, ROUTING_TABLE.size());
305 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
306 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
307 assertEquals(M1, rtv1.macAddress);
308 assertEquals(M2, rtv2.macAddress);
309 assertEquals(V1, rtv1.vlanId);
310 assertEquals(V2, rtv2.vlanId);
311 assertEquals(CP1.port(), rtv1.portNumber);
312 assertEquals(CP2.port(), rtv2.portNumber);
313
314 assertEquals(2, SUBNET_TABLE.size());
315 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
316 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800317
318 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700319 }
320
321 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400322 public void testOneDualHomedAdded() {
Charles Chan06f626c2018-02-05 17:20:05 -0800323 reset(srManager.deviceConfiguration);
324 srManager.deviceConfiguration.addSubnet(CP1, P1);
325 expectLastCall().once();
326 srManager.deviceConfiguration.addSubnet(CP2, P1);
327 expectLastCall().once();
328 replay(srManager.deviceConfiguration);
329
Charles Chan910be6a2017-08-23 14:46:43 -0700330 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR3, Sets.newHashSet(RR3));
331 routeHandler.processRouteAdded(re);
332
333 assertEquals(2, ROUTING_TABLE.size());
334 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
335 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
336 assertEquals(M3, rtv1.macAddress);
337 assertEquals(M3, rtv2.macAddress);
338 assertEquals(V3, rtv1.vlanId);
339 assertEquals(V3, rtv2.vlanId);
340 assertEquals(CP1.port(), rtv1.portNumber);
341 assertEquals(CP2.port(), rtv2.portNumber);
342
343 assertEquals(2, SUBNET_TABLE.size());
344 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
345 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800346
347 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700348 }
349
350 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400351 public void testOneSingleHomedToTwoSingleHomed() {
Charles Chan910be6a2017-08-23 14:46:43 -0700352 processRouteAdded();
353
Charles Chan06f626c2018-02-05 17:20:05 -0800354 reset(srManager.deviceConfiguration);
355 srManager.deviceConfiguration.addSubnet(CP2, P1);
356 expectLastCall().once();
357 replay(srManager.deviceConfiguration);
358
Charles Chan910be6a2017-08-23 14:46:43 -0700359 RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
360 Sets.newHashSet(RR1, RR2), Sets.newHashSet(RR1));
361 routeHandler.processAlternativeRoutesChanged(re);
362
363 assertEquals(2, ROUTING_TABLE.size());
364 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
365 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
366 assertEquals(M1, rtv1.macAddress);
367 assertEquals(M2, rtv2.macAddress);
368 assertEquals(V1, rtv1.vlanId);
369 assertEquals(V2, rtv2.vlanId);
370 assertEquals(CP1.port(), rtv1.portNumber);
371 assertEquals(CP2.port(), rtv2.portNumber);
372
373 assertEquals(2, SUBNET_TABLE.size());
374 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
375 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800376
377 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700378 }
379
380 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400381 public void testTwoSingleHomedToOneSingleHomed() {
Charles Chan910be6a2017-08-23 14:46:43 -0700382 testTwoSingleHomedAdded();
383
Charles Chan06f626c2018-02-05 17:20:05 -0800384 reset(srManager.deviceConfiguration);
385 srManager.deviceConfiguration.removeSubnet(CP2, P1);
386 expectLastCall().once();
387 replay(srManager.deviceConfiguration);
388
Charles Chan910be6a2017-08-23 14:46:43 -0700389 RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
390 Sets.newHashSet(RR1), Sets.newHashSet(RR1, RR2));
391 routeHandler.processAlternativeRoutesChanged(re);
392
Charles Chan06f626c2018-02-05 17:20:05 -0800393 // Note: We shouldn't remove the old nexthop during the occasion of route update
394 // since the populate subnet will take care of it and point it to an ECMP group
395 assertEquals(2, ROUTING_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700396 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
397 assertEquals(M1, rtv1.macAddress);
398 assertEquals(V1, rtv1.vlanId);
399 assertEquals(CP1.port(), rtv1.portNumber);
400
401 assertEquals(1, SUBNET_TABLE.size());
402 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800403
404 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700405 }
406
Charles Chan06f626c2018-02-05 17:20:05 -0800407 // TODO Add test cases for two single homed next hop at same location
408
Charles Chan910be6a2017-08-23 14:46:43 -0700409 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400410 public void testDualHomedSingleLocationFail() {
Charles Chan910be6a2017-08-23 14:46:43 -0700411 testOneDualHomedAdded();
412
Charles Chan7d20a4e2018-04-13 14:01:49 -0400413 ROUTE_STORE.put(P1, Sets.newHashSet(RR3));
414
Charles Chan910be6a2017-08-23 14:46:43 -0700415 HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3S, H3D);
416 routeHandler.processHostMovedEvent(he);
417
418 assertEquals(2, ROUTING_TABLE.size());
419 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
420 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
421 assertEquals(M3, rtv1.macAddress);
422 assertEquals(M3, rtv2.macAddress);
423 assertEquals(V3, rtv1.vlanId);
424 assertEquals(V3, rtv2.vlanId);
425 assertEquals(CP1.port(), rtv1.portNumber);
426 assertEquals(P9, rtv2.portNumber);
427
428 // ECMP route table hasn't changed
429 assertEquals(2, SUBNET_TABLE.size());
430 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
431 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
432 }
433
434 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400435 public void testDualHomedBothLocationFail() {
Charles Chan910be6a2017-08-23 14:46:43 -0700436 testDualHomedSingleLocationFail();
437
438 hostService = new MockHostService(HOSTS_ONE_FAIL);
439
Charles Chan06f626c2018-02-05 17:20:05 -0800440 reset(srManager.deviceConfiguration);
441 srManager.deviceConfiguration.removeSubnet(CP1, P1);
442 expectLastCall().once();
443 srManager.deviceConfiguration.removeSubnet(CP2, P1);
444 expectLastCall().once();
445 replay(srManager.deviceConfiguration);
446
Charles Chan910be6a2017-08-23 14:46:43 -0700447 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
448 routeHandler.processRouteRemoved(re);
449
450 assertEquals(0, ROUTING_TABLE.size());
451 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800452
453 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700454 }
455
456 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400457 public void testTwoSingleHomedRemoved() {
Charles Chan910be6a2017-08-23 14:46:43 -0700458 testTwoSingleHomedAdded();
459
460 hostService = new MockHostService(HOSTS_BOTH_FAIL);
461
Charles Chan06f626c2018-02-05 17:20:05 -0800462 reset(srManager.deviceConfiguration);
463 srManager.deviceConfiguration.removeSubnet(CP1, P1);
464 expectLastCall().once();
465 srManager.deviceConfiguration.removeSubnet(CP2, P1);
466 expectLastCall().once();
467 replay(srManager.deviceConfiguration);
468
Charles Chan910be6a2017-08-23 14:46:43 -0700469 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1, RR2));
470 routeHandler.processRouteRemoved(re);
471
472 assertEquals(0, ROUTING_TABLE.size());
473 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800474
475 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700476 }
477
478 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400479 public void testOneDualHomeRemoved() {
Charles Chan910be6a2017-08-23 14:46:43 -0700480 testOneDualHomedAdded();
481
Charles Chan06f626c2018-02-05 17:20:05 -0800482 reset(srManager.deviceConfiguration);
483 srManager.deviceConfiguration.removeSubnet(CP1, P1);
484 expectLastCall().once();
485 srManager.deviceConfiguration.removeSubnet(CP2, P1);
486 expectLastCall().once();
487 replay(srManager.deviceConfiguration);
488
Charles Chan910be6a2017-08-23 14:46:43 -0700489 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
Charles Chan6c624992017-08-18 17:11:34 -0700490 routeHandler.processRouteRemoved(re);
491
492 assertEquals(0, ROUTING_TABLE.size());
493 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800494
495 verify(srManager.deviceConfiguration);
Charles Chan6c624992017-08-18 17:11:34 -0700496 }
Charles Chan482b6422018-04-09 11:52:08 -0400497
498 @Test
499 public void testMoreThanTwoNextHop() {
500 // next hop = CP1, CP2
501 reset(srManager.deviceConfiguration);
502 srManager.deviceConfiguration.addSubnet(CP1, P1);
503 srManager.deviceConfiguration.addSubnet(CP2, P1);
504 expectLastCall().once();
505 replay(srManager.deviceConfiguration);
506
507 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
508 routeHandler.processRouteAdded(re);
509
510 assertEquals(2, ROUTING_TABLE.size());
511 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
512 assertEquals(M1, rtv1.macAddress);
513 assertEquals(V1, rtv1.vlanId);
514 assertEquals(CP1.port(), rtv1.portNumber);
515 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
516 assertEquals(M2, rtv2.macAddress);
517 assertEquals(V2, rtv2.vlanId);
518 assertEquals(CP2.port(), rtv2.portNumber);
519
520 assertEquals(2, SUBNET_TABLE.size());
521 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
522 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
523
524 verify(srManager.deviceConfiguration);
525
526 // next hop = CP1, CP2, CP4 (invalid)
527 re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
528 Sets.newHashSet(RR1, RR2, RR4), Sets.newHashSet(RR1, RR2));
529 routeHandler.processAlternativeRoutesChanged(re);
530
531 assertEquals(2, ROUTING_TABLE.size());
532 rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
533 assertEquals(M1, rtv1.macAddress);
534 assertEquals(V1, rtv1.vlanId);
535 assertEquals(CP1.port(), rtv1.portNumber);
536 rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
537 assertEquals(M2, rtv2.macAddress);
538 assertEquals(V2, rtv2.vlanId);
539 assertEquals(CP2.port(), rtv2.portNumber);
540
541 assertEquals(2, SUBNET_TABLE.size());
542 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
543 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
544
545 // next hop = CP2, CP4
546 reset(srManager.deviceConfiguration);
547 srManager.deviceConfiguration.addSubnet(CP2, P1);
548 srManager.deviceConfiguration.addSubnet(CP4, P1);
549 expectLastCall().once();
550 replay(srManager.deviceConfiguration);
551
552 re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
553 Sets.newHashSet(RR2, RR4), Sets.newHashSet(RR1, RR2, RR4));
554 routeHandler.processAlternativeRoutesChanged(re);
555
556 assertEquals(2, ROUTING_TABLE.size());
557 rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
558 assertEquals(M2, rtv1.macAddress);
559 assertEquals(V2, rtv1.vlanId);
560 assertEquals(CP2.port(), rtv1.portNumber);
561 rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP4.deviceId(), P1));
562 assertEquals(M4, rtv2.macAddress);
563 assertEquals(V4, rtv2.vlanId);
564 assertEquals(CP4.port(), rtv2.portNumber);
565
566 assertEquals(2, SUBNET_TABLE.size());
567 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
568 assertTrue(SUBNET_TABLE.get(CP4).contains(P1));
569
570 verify(srManager.deviceConfiguration);
571 }
Charles Chan6c624992017-08-18 17:11:34 -0700572}