blob: 690f87e1f50bdc5b216ea78e95abb4dc518f3c37 [file] [log] [blame]
Charles Chan6c624992017-08-18 17:11:34 -07001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.segmentrouting;
18
Charles Chan910be6a2017-08-23 14:46:43 -070019import com.fasterxml.jackson.databind.JsonNode;
20import com.fasterxml.jackson.databind.ObjectMapper;
Charles Chan5eec3b12019-04-18 14:30:41 -070021import com.google.common.collect.Lists;
Charles Chan6c624992017-08-18 17:11:34 -070022import com.google.common.collect.Maps;
23import com.google.common.collect.Sets;
24import org.junit.Before;
25import org.junit.Test;
26import org.onlab.packet.IpAddress;
27import org.onlab.packet.IpPrefix;
28import org.onlab.packet.MacAddress;
29import org.onlab.packet.VlanId;
Charles Chan910be6a2017-08-23 14:46:43 -070030import org.onosproject.net.config.ConfigApplyDelegate;
Charles Chan6c624992017-08-18 17:11:34 -070031import org.onosproject.net.ConnectPoint;
Charles Chanf0ae41e2017-08-23 13:55:39 -070032import org.onosproject.net.DefaultHost;
Charles Chan6c624992017-08-18 17:11:34 -070033import org.onosproject.net.DeviceId;
34import org.onosproject.net.Host;
Charles Chanf0ae41e2017-08-23 13:55:39 -070035import org.onosproject.net.HostId;
36import org.onosproject.net.HostLocation;
Charles Chan910be6a2017-08-23 14:46:43 -070037import org.onosproject.net.PortNumber;
Charles Chan6c624992017-08-18 17:11:34 -070038import org.onosproject.net.config.NetworkConfigRegistryAdapter;
39import org.onosproject.net.flow.TrafficTreatment;
Charles Chan910be6a2017-08-23 14:46:43 -070040import org.onosproject.net.host.HostEvent;
41import org.onosproject.net.host.HostService;
Charles Chan12a8a842020-02-14 13:23:57 -080042import org.onosproject.net.host.InterfaceIpAddress;
Charles Chan6c624992017-08-18 17:11:34 -070043import org.onosproject.net.intf.Interface;
Charles Chanf0ae41e2017-08-23 13:55:39 -070044import org.onosproject.net.provider.ProviderId;
Charles Chan6c624992017-08-18 17:11:34 -070045import org.onosproject.routeservice.ResolvedRoute;
46import org.onosproject.routeservice.Route;
47import org.onosproject.routeservice.RouteEvent;
Charles Chan910be6a2017-08-23 14:46:43 -070048import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
Charles Chan12a8a842020-02-14 13:23:57 -080049import org.onosproject.segmentrouting.phasedrecovery.api.PhasedRecoveryService;
Charles Chand66d6712018-03-29 16:03:41 -070050import org.onosproject.store.service.StorageService;
51import org.onosproject.store.service.TestConsistentMap;
pierf331a492020-01-07 15:39:39 +010052import org.onosproject.store.service.TestConsistentMultimap;
Charles Chan6c624992017-08-18 17:11:34 -070053
54import java.util.Map;
55import java.util.Set;
56
Charles Chand66d6712018-03-29 16:03:41 -070057import static org.easymock.EasyMock.expect;
Charles Chan06f626c2018-02-05 17:20:05 -080058import static org.easymock.EasyMock.reset;
Charles Chan6c624992017-08-18 17:11:34 -070059import static org.junit.Assert.*;
Charles Chan06f626c2018-02-05 17:20:05 -080060import static org.easymock.EasyMock.createMock;
61import static org.easymock.EasyMock.expectLastCall;
62import static org.easymock.EasyMock.replay;
63import static org.easymock.EasyMock.verify;
Charles Chan6c624992017-08-18 17:11:34 -070064
65/**
66 * Unit test for {@link RouteHandler}.
67 */
68public class RouteHandlerTest {
Charles Chan06f626c2018-02-05 17:20:05 -080069 private SegmentRoutingManager srManager;
Charles Chan6c624992017-08-18 17:11:34 -070070 private RouteHandler routeHandler;
Charles Chan910be6a2017-08-23 14:46:43 -070071 private HostService hostService;
Charles Chan6c624992017-08-18 17:11:34 -070072
73 // Mocked routing and bridging tables
74 private static final Map<MockBridgingTableKey, MockBridgingTableValue> BRIDGING_TABLE =
75 Maps.newConcurrentMap();
76 private static final Map<MockRoutingTableKey, MockRoutingTableValue> ROUTING_TABLE =
77 Maps.newConcurrentMap();
78 private static final Map<ConnectPoint, Set<IpPrefix>> SUBNET_TABLE = Maps.newConcurrentMap();
79 // Mocked Next Id
80 private static final Map<Integer, TrafficTreatment> NEXT_TABLE = Maps.newConcurrentMap();
Charles Chan7d20a4e2018-04-13 14:01:49 -040081 private static final Map<IpPrefix, Set<ResolvedRoute>> ROUTE_STORE = Maps.newConcurrentMap();
Charles Chan6c624992017-08-18 17:11:34 -070082
83 private static final IpPrefix P1 = IpPrefix.valueOf("10.0.0.0/24");
Charles Chan910be6a2017-08-23 14:46:43 -070084
85 // Single homed router 1
Charles Chan12a8a842020-02-14 13:23:57 -080086 private static final IpAddress N1 = IpAddress.valueOf("10.0.1.1");
Charles Chan6c624992017-08-18 17:11:34 -070087 private static final MacAddress M1 = MacAddress.valueOf("00:00:00:00:00:01");
88 private static final VlanId V1 = VlanId.vlanId((short) 1);
89 private static final ConnectPoint CP1 = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
90 private static final Route R1 = new Route(Route.Source.STATIC, P1, N1);
Charles Chanf0ae41e2017-08-23 13:55:39 -070091 private static final ResolvedRoute RR1 = new ResolvedRoute(R1, M1, V1);
Charles Chan12a8a842020-02-14 13:23:57 -080092 private static final Route DHCP_R1 = new Route(Route.Source.DHCP, P1, N1);
93 private static final ResolvedRoute DHCP_RR1 = new ResolvedRoute(DHCP_R1, M1, V1);
Charles Chan6c624992017-08-18 17:11:34 -070094
Charles Chan910be6a2017-08-23 14:46:43 -070095 // Single homed router 2
Charles Chan12a8a842020-02-14 13:23:57 -080096 private static final IpAddress N2 = IpAddress.valueOf("10.0.2.1");
Charles Chan6c624992017-08-18 17:11:34 -070097 private static final MacAddress M2 = MacAddress.valueOf("00:00:00:00:00:02");
98 private static final VlanId V2 = VlanId.vlanId((short) 2);
Charles Chan910be6a2017-08-23 14:46:43 -070099 private static final ConnectPoint CP2 = ConnectPoint.deviceConnectPoint("of:0000000000000002/2");
Charles Chan6c624992017-08-18 17:11:34 -0700100 private static final Route R2 = new Route(Route.Source.STATIC, P1, N2);
Charles Chanf0ae41e2017-08-23 13:55:39 -0700101 private static final ResolvedRoute RR2 = new ResolvedRoute(R2, M2, V2);
Charles Chan6c624992017-08-18 17:11:34 -0700102
Charles Chan910be6a2017-08-23 14:46:43 -0700103 // Dual homed router 1
Charles Chan12a8a842020-02-14 13:23:57 -0800104 private static final IpAddress N3 = IpAddress.valueOf("10.0.3.1");
Charles Chan910be6a2017-08-23 14:46:43 -0700105 private static final MacAddress M3 = MacAddress.valueOf("00:00:00:00:00:03");
106 private static final VlanId V3 = VlanId.vlanId((short) 3);
107 private static final Route R3 = new Route(Route.Source.STATIC, P1, N3);
108 private static final ResolvedRoute RR3 = new ResolvedRoute(R3, M3, V3);
Charles Chan12a8a842020-02-14 13:23:57 -0800109 private static final Route DHCP_R3 = new Route(Route.Source.DHCP, P1, N3);
110 private static final ResolvedRoute DHCP_RR3 = new ResolvedRoute(DHCP_R3, M3, V3);
Charles Chan6c624992017-08-18 17:11:34 -0700111
Charles Chan482b6422018-04-09 11:52:08 -0400112 // Single homed router 3
Charles Chan12a8a842020-02-14 13:23:57 -0800113 private static final IpAddress N4 = IpAddress.valueOf("10.0.4.1");
Charles Chan482b6422018-04-09 11:52:08 -0400114 private static final MacAddress M4 = MacAddress.valueOf("00:00:00:00:00:04");
115 private static final VlanId V4 = VlanId.vlanId((short) 4);
116 private static final ConnectPoint CP4 = ConnectPoint.deviceConnectPoint("of:0000000000000004/4");
117 private static final Route R4 = new Route(Route.Source.STATIC, P1, N4);
118 private static final ResolvedRoute RR4 = new ResolvedRoute(R4, M4, V4);
119
Charles Chan910be6a2017-08-23 14:46:43 -0700120 // Hosts
Charles Chanf0ae41e2017-08-23 13:55:39 -0700121 private static final Host H1 = new DefaultHost(ProviderId.NONE, HostId.hostId(M1, V1), M1, V1,
122 Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N1), false);
123 private static final Host H2 = new DefaultHost(ProviderId.NONE, HostId.hostId(M2, V2), M2, V2,
124 Sets.newHashSet(new HostLocation(CP2, 0)), Sets.newHashSet(N2), false);
Charles Chan910be6a2017-08-23 14:46:43 -0700125 private static final Host H3D = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
126 Sets.newHashSet(new HostLocation(CP1, 0), new HostLocation(CP2, 0)), Sets.newHashSet(N3), false);
127 private static final Host H3S = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
128 Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N3), false);
Charles Chan482b6422018-04-09 11:52:08 -0400129 private static final Host H4 = new DefaultHost(ProviderId.NONE, HostId.hostId(M4, V4), M4, V4,
130 Sets.newHashSet(new HostLocation(CP4, 0)), Sets.newHashSet(N4), false);
Charles Chan910be6a2017-08-23 14:46:43 -0700131
132 // Pair Local Port
133 private static final PortNumber P9 = PortNumber.portNumber(9);
Charles Chanf0ae41e2017-08-23 13:55:39 -0700134
Charles Chan6c624992017-08-18 17:11:34 -0700135 // A set of hosts
Charles Chan482b6422018-04-09 11:52:08 -0400136 private static final Set<Host> HOSTS = Sets.newHashSet(H1, H2, H3D, H4);
Charles Chan910be6a2017-08-23 14:46:43 -0700137 private static final Set<Host> HOSTS_ONE_FAIL = Sets.newHashSet(H1, H2, H3S);
138 private static final Set<Host> HOSTS_BOTH_FAIL = Sets.newHashSet(H1, H2);
Charles Chan6c624992017-08-18 17:11:34 -0700139 // A set of devices of which we have mastership
Charles Chan910be6a2017-08-23 14:46:43 -0700140 private static final Set<DeviceId> LOCAL_DEVICES = Sets.newHashSet(CP1.deviceId(), CP2.deviceId());
Charles Chan6c624992017-08-18 17:11:34 -0700141 // A set of interfaces
Charles Chan12a8a842020-02-14 13:23:57 -0800142 private static final InterfaceIpAddress IF_IP1 =
143 new InterfaceIpAddress(IpAddress.valueOf("10.0.1.254"), IpPrefix.valueOf("10.0.1.254/24"));
144 private static final InterfaceIpAddress IF_IP3 =
145 new InterfaceIpAddress(IpAddress.valueOf("10.0.3.254"), IpPrefix.valueOf("10.0.3.254/24"));
146 private static final Interface IF_CP1 = new Interface("if-cp1", CP1, Lists.newArrayList(IF_IP1, IF_IP3),
147 null, null, null, null, null);
148 private static final Interface IF_CP2 = new Interface("if-cp2", CP2, Lists.newArrayList(IF_IP1, IF_IP3),
149 null, null, null, null, null);
150 private static final Set<Interface> INTERFACES = Sets.newHashSet(IF_CP1, IF_CP2);
Charles Chan6c624992017-08-18 17:11:34 -0700151
152 @Before
Charles Chan482b6422018-04-09 11:52:08 -0400153 public void setUp() {
Charles Chan910be6a2017-08-23 14:46:43 -0700154 ObjectMapper mapper = new ObjectMapper();
155 ConfigApplyDelegate delegate = config -> { };
156
157 SegmentRoutingDeviceConfig dev1Config = new SegmentRoutingDeviceConfig();
158 JsonNode dev1Tree = mapper.createObjectNode();
159 dev1Config.init(CP1.deviceId(), "host-handler-test", dev1Tree, mapper, delegate);
160 dev1Config.setPairDeviceId(CP2.deviceId()).setPairLocalPort(P9);
161
162 SegmentRoutingDeviceConfig dev2Config = new SegmentRoutingDeviceConfig();
163 JsonNode dev2Tree = mapper.createObjectNode();
164 dev2Config.init(CP2.deviceId(), "host-handler-test", dev2Tree, mapper, delegate);
165 dev2Config.setPairDeviceId(CP1.deviceId()).setPairLocalPort(P9);
Charles Chan6c624992017-08-18 17:11:34 -0700166
167 MockNetworkConfigRegistry mockNetworkConfigRegistry = new MockNetworkConfigRegistry();
Charles Chan910be6a2017-08-23 14:46:43 -0700168 mockNetworkConfigRegistry.applyConfig(dev1Config);
169 mockNetworkConfigRegistry.applyConfig(dev2Config);
Charles Chan6c624992017-08-18 17:11:34 -0700170
171 // Initialize Segment Routing Manager
Charles Chan06f626c2018-02-05 17:20:05 -0800172 srManager = new MockSegmentRoutingManager(NEXT_TABLE);
Charles Chand66d6712018-03-29 16:03:41 -0700173 srManager.storageService = createMock(StorageService.class);
174 expect(srManager.storageService.consistentMapBuilder()).andReturn(new TestConsistentMap.Builder<>()).anyTimes();
pierf331a492020-01-07 15:39:39 +0100175 expect(srManager.storageService.consistentMultimapBuilder()).andReturn(
176 new TestConsistentMultimap.Builder<>()).anyTimes();
Charles Chand66d6712018-03-29 16:03:41 -0700177 replay(srManager.storageService);
Charles Chan6c624992017-08-18 17:11:34 -0700178 srManager.cfgService = new NetworkConfigRegistryAdapter();
Charles Chan06f626c2018-02-05 17:20:05 -0800179 srManager.deviceConfiguration = createMock(DeviceConfiguration.class);
Charles Chan6c624992017-08-18 17:11:34 -0700180 srManager.flowObjectiveService = new MockFlowObjectiveService(BRIDGING_TABLE, NEXT_TABLE);
181 srManager.routingRulePopulator = new MockRoutingRulePopulator(srManager, ROUTING_TABLE);
Charles Chanc4d68882018-03-15 16:41:10 -0700182 srManager.defaultRoutingHandler = new MockDefaultRoutingHandler(srManager, SUBNET_TABLE, ROUTING_TABLE);
Charles Chan6c624992017-08-18 17:11:34 -0700183 srManager.interfaceService = new MockInterfaceService(INTERFACES);
184 srManager.mastershipService = new MockMastershipService(LOCAL_DEVICES);
Charles Chan910be6a2017-08-23 14:46:43 -0700185 hostService = new MockHostService(HOSTS);
186 srManager.hostService = hostService;
Charles Chan6c624992017-08-18 17:11:34 -0700187 srManager.cfgService = mockNetworkConfigRegistry;
Charles Chan7d20a4e2018-04-13 14:01:49 -0400188 srManager.routeService = new MockRouteService(ROUTE_STORE);
Charles Chan12a8a842020-02-14 13:23:57 -0800189 srManager.phasedRecoveryService = createMock(PhasedRecoveryService.class);
190 expect(srManager.phasedRecoveryService.isEnabled()).andReturn(true).anyTimes();
191 replay(srManager.phasedRecoveryService);
Charles Chan6c624992017-08-18 17:11:34 -0700192
Charles Chanfbcb8812018-04-18 18:41:05 -0700193 routeHandler = new RouteHandler(srManager);
Charles Chan6c624992017-08-18 17:11:34 -0700194
195 ROUTING_TABLE.clear();
196 BRIDGING_TABLE.clear();
197 SUBNET_TABLE.clear();
198 }
199
200 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400201 public void init() {
Charles Chan7d20a4e2018-04-13 14:01:49 -0400202 ROUTE_STORE.put(P1, Sets.newHashSet(RR1));
Charles Chan910be6a2017-08-23 14:46:43 -0700203
Charles Chan6c624992017-08-18 17:11:34 -0700204 routeHandler.init(CP1.deviceId());
205
206 assertEquals(1, ROUTING_TABLE.size());
Charles Chanf0ae41e2017-08-23 13:55:39 -0700207 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
208 assertEquals(M1, rtv1.macAddress);
209 assertEquals(V1, rtv1.vlanId);
210 assertEquals(CP1.port(), rtv1.portNumber);
211
Charles Chan6c624992017-08-18 17:11:34 -0700212 assertEquals(1, SUBNET_TABLE.size());
Charles Chan6c624992017-08-18 17:11:34 -0700213 }
214
215 @Test
Charles Chan7d20a4e2018-04-13 14:01:49 -0400216 public void initTwoNextHops() {
217 ROUTE_STORE.put(P1, Sets.newHashSet(RR1, RR2));
218
219 routeHandler.init(CP1.deviceId());
220
221 assertEquals(2, ROUTING_TABLE.size());
222 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
223 assertEquals(M1, rtv1.macAddress);
224 assertEquals(V1, rtv1.vlanId);
225 assertEquals(CP1.port(), rtv1.portNumber);
226 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
227 assertEquals(M2, rtv2.macAddress);
228 assertEquals(V2, rtv2.vlanId);
229 assertEquals(CP2.port(), rtv2.portNumber);
230
231 assertEquals(2, SUBNET_TABLE.size());
Charles Chan12a8a842020-02-14 13:23:57 -0800232 }
233
234 // Only one of two dual-homed next hops present.
235 // Expect one routing table to be programmed with direct flow.
236 // The other is not programmed, not even for subnet
237 @Test
238 public void initDhcpRouteSingleDualHomeNextHop() {
239 ROUTE_STORE.put(P1, Sets.newHashSet(DHCP_RR1));
240
241 routeHandler.init(CP1.deviceId());
242
243 assertEquals(1, ROUTING_TABLE.size());
244 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
245 assertEquals(M1, rtv1.macAddress);
246 assertEquals(V1, rtv1.vlanId);
247 assertEquals(CP1.port(), rtv1.portNumber);
248
249 assertEquals(1, SUBNET_TABLE.size());
250 }
251
252 // Both dual-homed next hops present.
253 // Expect both routing table to be programmed with direct flow
254 @Test
255 public void initDhcpRouteBothDualHomeNextHop() {
256 ROUTE_STORE.put(P1, Sets.newHashSet(DHCP_RR3));
257
258 routeHandler.init(CP1.deviceId());
259
260 assertEquals(2, ROUTING_TABLE.size());
261 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
262 assertEquals(M3, rtv1.macAddress);
263 assertEquals(V3, rtv1.vlanId);
264 assertEquals(CP1.port(), rtv1.portNumber);
265
266 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
267 assertEquals(M3, rtv2.macAddress);
268 assertEquals(V3, rtv2.vlanId);
269 assertEquals(CP2.port(), rtv2.portNumber);
270
271 assertEquals(2, SUBNET_TABLE.size());
Charles Chan7d20a4e2018-04-13 14:01:49 -0400272 }
273
274 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400275 public void processRouteAdded() {
Charles Chan06f626c2018-02-05 17:20:05 -0800276 reset(srManager.deviceConfiguration);
277 srManager.deviceConfiguration.addSubnet(CP1, P1);
278 expectLastCall().once();
279 replay(srManager.deviceConfiguration);
280
Charles Chan910be6a2017-08-23 14:46:43 -0700281 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1));
Charles Chan6c624992017-08-18 17:11:34 -0700282 routeHandler.processRouteAdded(re);
283
284 assertEquals(1, ROUTING_TABLE.size());
Charles Chanf0ae41e2017-08-23 13:55:39 -0700285 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
286 assertEquals(M1, rtv1.macAddress);
287 assertEquals(V1, rtv1.vlanId);
288 assertEquals(CP1.port(), rtv1.portNumber);
289
Charles Chan6c624992017-08-18 17:11:34 -0700290 assertEquals(1, SUBNET_TABLE.size());
291 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800292
293 verify(srManager.deviceConfiguration);
Charles Chan6c624992017-08-18 17:11:34 -0700294 }
295
296 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400297 public void processRouteUpdated() {
Charles Chan6c624992017-08-18 17:11:34 -0700298 processRouteAdded();
299
Charles Chan06f626c2018-02-05 17:20:05 -0800300 reset(srManager.deviceConfiguration);
301 srManager.deviceConfiguration.removeSubnet(CP1, P1);
302 expectLastCall().once();
303 srManager.deviceConfiguration.addSubnet(CP2, P1);
304 expectLastCall().once();
305 replay(srManager.deviceConfiguration);
306
Charles Chan910be6a2017-08-23 14:46:43 -0700307 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_UPDATED, RR2, RR1, Sets.newHashSet(RR2),
308 Sets.newHashSet(RR1));
Charles Chan6c624992017-08-18 17:11:34 -0700309 routeHandler.processRouteUpdated(re);
310
Charles Chan06f626c2018-02-05 17:20:05 -0800311 // Note: We shouldn't remove the old nexthop during the occasion of route update
312 // since the populate subnet will take care of it and point it to an ECMP group
313 assertEquals(2, ROUTING_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700314 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
Charles Chanf0ae41e2017-08-23 13:55:39 -0700315 assertEquals(M2, rtv2.macAddress);
316 assertEquals(V2, rtv2.vlanId);
317 assertEquals(CP2.port(), rtv2.portNumber);
318
Charles Chan6c624992017-08-18 17:11:34 -0700319 assertEquals(1, SUBNET_TABLE.size());
320 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800321
322 verify(srManager.deviceConfiguration);
Charles Chan6c624992017-08-18 17:11:34 -0700323 }
324
325 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400326 public void processRouteRemoved() {
Charles Chan6c624992017-08-18 17:11:34 -0700327 processRouteAdded();
328
Charles Chan06f626c2018-02-05 17:20:05 -0800329 reset(srManager.deviceConfiguration);
330 srManager.deviceConfiguration.removeSubnet(CP1, P1);
331 expectLastCall().once();
332 replay(srManager.deviceConfiguration);
333
Charles Chan910be6a2017-08-23 14:46:43 -0700334 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1));
335 routeHandler.processRouteRemoved(re);
336
337 assertEquals(0, ROUTING_TABLE.size());
338 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800339
340 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700341 }
342
343 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400344 public void testTwoSingleHomedAdded() {
Charles Chan06f626c2018-02-05 17:20:05 -0800345 reset(srManager.deviceConfiguration);
346 srManager.deviceConfiguration.addSubnet(CP1, P1);
347 expectLastCall().once();
348 srManager.deviceConfiguration.addSubnet(CP2, P1);
349 expectLastCall().once();
350 replay(srManager.deviceConfiguration);
351
Charles Chan910be6a2017-08-23 14:46:43 -0700352 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
353 routeHandler.processRouteAdded(re);
354
355 assertEquals(2, ROUTING_TABLE.size());
356 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
357 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
358 assertEquals(M1, rtv1.macAddress);
359 assertEquals(M2, rtv2.macAddress);
360 assertEquals(V1, rtv1.vlanId);
361 assertEquals(V2, rtv2.vlanId);
362 assertEquals(CP1.port(), rtv1.portNumber);
363 assertEquals(CP2.port(), rtv2.portNumber);
364
365 assertEquals(2, SUBNET_TABLE.size());
366 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
367 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800368
369 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700370 }
371
372 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400373 public void testOneDualHomedAdded() {
Charles Chan06f626c2018-02-05 17:20:05 -0800374 reset(srManager.deviceConfiguration);
375 srManager.deviceConfiguration.addSubnet(CP1, P1);
376 expectLastCall().once();
377 srManager.deviceConfiguration.addSubnet(CP2, P1);
378 expectLastCall().once();
379 replay(srManager.deviceConfiguration);
380
Charles Chan910be6a2017-08-23 14:46:43 -0700381 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR3, Sets.newHashSet(RR3));
382 routeHandler.processRouteAdded(re);
383
384 assertEquals(2, ROUTING_TABLE.size());
385 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
386 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
387 assertEquals(M3, rtv1.macAddress);
388 assertEquals(M3, rtv2.macAddress);
389 assertEquals(V3, rtv1.vlanId);
390 assertEquals(V3, rtv2.vlanId);
391 assertEquals(CP1.port(), rtv1.portNumber);
392 assertEquals(CP2.port(), rtv2.portNumber);
393
394 assertEquals(2, SUBNET_TABLE.size());
395 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
396 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800397
398 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700399 }
400
401 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400402 public void testOneSingleHomedToTwoSingleHomed() {
Charles Chan910be6a2017-08-23 14:46:43 -0700403 processRouteAdded();
404
Charles Chan06f626c2018-02-05 17:20:05 -0800405 reset(srManager.deviceConfiguration);
406 srManager.deviceConfiguration.addSubnet(CP2, P1);
407 expectLastCall().once();
408 replay(srManager.deviceConfiguration);
409
Charles Chan910be6a2017-08-23 14:46:43 -0700410 RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
411 Sets.newHashSet(RR1, RR2), Sets.newHashSet(RR1));
412 routeHandler.processAlternativeRoutesChanged(re);
413
414 assertEquals(2, ROUTING_TABLE.size());
415 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
416 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
417 assertEquals(M1, rtv1.macAddress);
418 assertEquals(M2, rtv2.macAddress);
419 assertEquals(V1, rtv1.vlanId);
420 assertEquals(V2, rtv2.vlanId);
421 assertEquals(CP1.port(), rtv1.portNumber);
422 assertEquals(CP2.port(), rtv2.portNumber);
423
424 assertEquals(2, SUBNET_TABLE.size());
425 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
426 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800427
428 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700429 }
430
431 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400432 public void testTwoSingleHomedToOneSingleHomed() {
Charles Chan910be6a2017-08-23 14:46:43 -0700433 testTwoSingleHomedAdded();
434
Charles Chan06f626c2018-02-05 17:20:05 -0800435 reset(srManager.deviceConfiguration);
436 srManager.deviceConfiguration.removeSubnet(CP2, P1);
437 expectLastCall().once();
438 replay(srManager.deviceConfiguration);
439
Charles Chan910be6a2017-08-23 14:46:43 -0700440 RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
441 Sets.newHashSet(RR1), Sets.newHashSet(RR1, RR2));
442 routeHandler.processAlternativeRoutesChanged(re);
443
Charles Chan06f626c2018-02-05 17:20:05 -0800444 // Note: We shouldn't remove the old nexthop during the occasion of route update
445 // since the populate subnet will take care of it and point it to an ECMP group
446 assertEquals(2, ROUTING_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700447 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
448 assertEquals(M1, rtv1.macAddress);
449 assertEquals(V1, rtv1.vlanId);
450 assertEquals(CP1.port(), rtv1.portNumber);
451
452 assertEquals(1, SUBNET_TABLE.size());
453 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan06f626c2018-02-05 17:20:05 -0800454
455 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700456 }
457
Charles Chan06f626c2018-02-05 17:20:05 -0800458 // TODO Add test cases for two single homed next hop at same location
459
Charles Chan910be6a2017-08-23 14:46:43 -0700460 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400461 public void testDualHomedSingleLocationFail() {
Charles Chan910be6a2017-08-23 14:46:43 -0700462 testOneDualHomedAdded();
463
Charles Chan7d20a4e2018-04-13 14:01:49 -0400464 ROUTE_STORE.put(P1, Sets.newHashSet(RR3));
465
Charles Chan07203792018-07-17 16:33:11 -0700466 reset(srManager.deviceConfiguration);
Charles Chan5eec3b12019-04-18 14:30:41 -0700467 expect(srManager.deviceConfiguration.getBatchedSubnets(H3D.id()))
468 .andReturn(Lists.<Set<IpPrefix>>newArrayList(Sets.newHashSet(P1)));
Charles Chan07203792018-07-17 16:33:11 -0700469 srManager.deviceConfiguration.removeSubnet(CP2, P1);
470 expectLastCall().once();
471 replay(srManager.deviceConfiguration);
472
Charles Chan910be6a2017-08-23 14:46:43 -0700473 HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3S, H3D);
474 routeHandler.processHostMovedEvent(he);
475
Charles Chan4dcd5102019-02-28 15:40:57 -0800476 // We do not remove the route on CP2. Instead, we let the subnet population overrides it
477 assertEquals(2, ROUTING_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700478 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
Charles Chan910be6a2017-08-23 14:46:43 -0700479 assertEquals(M3, rtv1.macAddress);
Charles Chan910be6a2017-08-23 14:46:43 -0700480 assertEquals(V3, rtv1.vlanId);
Charles Chan910be6a2017-08-23 14:46:43 -0700481 assertEquals(CP1.port(), rtv1.portNumber);
Charles Chan910be6a2017-08-23 14:46:43 -0700482
483 // ECMP route table hasn't changed
Charles Chan07203792018-07-17 16:33:11 -0700484 assertEquals(1, SUBNET_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700485 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
Charles Chan07203792018-07-17 16:33:11 -0700486
487 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700488 }
489
490 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400491 public void testDualHomedBothLocationFail() {
Charles Chan910be6a2017-08-23 14:46:43 -0700492 testDualHomedSingleLocationFail();
493
494 hostService = new MockHostService(HOSTS_ONE_FAIL);
495
Charles Chan06f626c2018-02-05 17:20:05 -0800496 reset(srManager.deviceConfiguration);
497 srManager.deviceConfiguration.removeSubnet(CP1, P1);
498 expectLastCall().once();
499 srManager.deviceConfiguration.removeSubnet(CP2, P1);
500 expectLastCall().once();
501 replay(srManager.deviceConfiguration);
502
Charles Chan910be6a2017-08-23 14:46:43 -0700503 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
504 routeHandler.processRouteRemoved(re);
505
506 assertEquals(0, ROUTING_TABLE.size());
507 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800508
509 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700510 }
511
512 @Test
Charles Chan07203792018-07-17 16:33:11 -0700513 public void testSingleHomedToDualHomed() {
514 testDualHomedSingleLocationFail();
515
516 reset(srManager.deviceConfiguration);
Charles Chan5eec3b12019-04-18 14:30:41 -0700517 expect(srManager.deviceConfiguration.getBatchedSubnets(H3S.id()))
518 .andReturn(Lists.<Set<IpPrefix>>newArrayList(Sets.newHashSet(P1)));
Charles Chan07203792018-07-17 16:33:11 -0700519 srManager.deviceConfiguration.addSubnet(CP2, P1);
520 expectLastCall().once();
521 replay(srManager.deviceConfiguration);
522
523 HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3D, H3S);
524 routeHandler.processHostMovedEvent(he);
525
526 assertEquals(2, ROUTING_TABLE.size());
527 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
528 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
529 assertEquals(M3, rtv1.macAddress);
530 assertEquals(M3, rtv2.macAddress);
531 assertEquals(V3, rtv1.vlanId);
532 assertEquals(V3, rtv2.vlanId);
533 assertEquals(CP1.port(), rtv1.portNumber);
534 assertEquals(CP2.port(), rtv2.portNumber);
535
536 assertEquals(2, SUBNET_TABLE.size());
537 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
538 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
539
540 verify(srManager.deviceConfiguration);
541 }
542
543 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400544 public void testTwoSingleHomedRemoved() {
Charles Chan910be6a2017-08-23 14:46:43 -0700545 testTwoSingleHomedAdded();
546
547 hostService = new MockHostService(HOSTS_BOTH_FAIL);
548
Charles Chan06f626c2018-02-05 17:20:05 -0800549 reset(srManager.deviceConfiguration);
550 srManager.deviceConfiguration.removeSubnet(CP1, P1);
551 expectLastCall().once();
552 srManager.deviceConfiguration.removeSubnet(CP2, P1);
553 expectLastCall().once();
554 replay(srManager.deviceConfiguration);
555
Charles Chan910be6a2017-08-23 14:46:43 -0700556 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1, RR2));
557 routeHandler.processRouteRemoved(re);
558
559 assertEquals(0, ROUTING_TABLE.size());
560 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800561
562 verify(srManager.deviceConfiguration);
Charles Chan910be6a2017-08-23 14:46:43 -0700563 }
564
565 @Test
Charles Chan482b6422018-04-09 11:52:08 -0400566 public void testOneDualHomeRemoved() {
Charles Chan910be6a2017-08-23 14:46:43 -0700567 testOneDualHomedAdded();
568
Charles Chan06f626c2018-02-05 17:20:05 -0800569 reset(srManager.deviceConfiguration);
570 srManager.deviceConfiguration.removeSubnet(CP1, P1);
571 expectLastCall().once();
572 srManager.deviceConfiguration.removeSubnet(CP2, P1);
573 expectLastCall().once();
574 replay(srManager.deviceConfiguration);
575
Charles Chan910be6a2017-08-23 14:46:43 -0700576 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
Charles Chan6c624992017-08-18 17:11:34 -0700577 routeHandler.processRouteRemoved(re);
578
579 assertEquals(0, ROUTING_TABLE.size());
580 assertEquals(0, SUBNET_TABLE.size());
Charles Chan06f626c2018-02-05 17:20:05 -0800581
582 verify(srManager.deviceConfiguration);
Charles Chan6c624992017-08-18 17:11:34 -0700583 }
Charles Chan482b6422018-04-09 11:52:08 -0400584
585 @Test
586 public void testMoreThanTwoNextHop() {
587 // next hop = CP1, CP2
588 reset(srManager.deviceConfiguration);
589 srManager.deviceConfiguration.addSubnet(CP1, P1);
590 srManager.deviceConfiguration.addSubnet(CP2, P1);
591 expectLastCall().once();
592 replay(srManager.deviceConfiguration);
593
594 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
595 routeHandler.processRouteAdded(re);
596
597 assertEquals(2, ROUTING_TABLE.size());
598 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
599 assertEquals(M1, rtv1.macAddress);
600 assertEquals(V1, rtv1.vlanId);
601 assertEquals(CP1.port(), rtv1.portNumber);
602 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
603 assertEquals(M2, rtv2.macAddress);
604 assertEquals(V2, rtv2.vlanId);
605 assertEquals(CP2.port(), rtv2.portNumber);
606
607 assertEquals(2, SUBNET_TABLE.size());
608 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
609 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
610
611 verify(srManager.deviceConfiguration);
612
613 // next hop = CP1, CP2, CP4 (invalid)
614 re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
615 Sets.newHashSet(RR1, RR2, RR4), Sets.newHashSet(RR1, RR2));
616 routeHandler.processAlternativeRoutesChanged(re);
617
618 assertEquals(2, ROUTING_TABLE.size());
619 rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
620 assertEquals(M1, rtv1.macAddress);
621 assertEquals(V1, rtv1.vlanId);
622 assertEquals(CP1.port(), rtv1.portNumber);
623 rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
624 assertEquals(M2, rtv2.macAddress);
625 assertEquals(V2, rtv2.vlanId);
626 assertEquals(CP2.port(), rtv2.portNumber);
627
628 assertEquals(2, SUBNET_TABLE.size());
629 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
630 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
631
632 // next hop = CP2, CP4
633 reset(srManager.deviceConfiguration);
634 srManager.deviceConfiguration.addSubnet(CP2, P1);
635 srManager.deviceConfiguration.addSubnet(CP4, P1);
636 expectLastCall().once();
637 replay(srManager.deviceConfiguration);
638
639 re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
640 Sets.newHashSet(RR2, RR4), Sets.newHashSet(RR1, RR2, RR4));
641 routeHandler.processAlternativeRoutesChanged(re);
642
643 assertEquals(2, ROUTING_TABLE.size());
644 rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
645 assertEquals(M2, rtv1.macAddress);
646 assertEquals(V2, rtv1.vlanId);
647 assertEquals(CP2.port(), rtv1.portNumber);
648 rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP4.deviceId(), P1));
649 assertEquals(M4, rtv2.macAddress);
650 assertEquals(V4, rtv2.vlanId);
651 assertEquals(CP4.port(), rtv2.portNumber);
652
653 assertEquals(2, SUBNET_TABLE.size());
654 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
655 assertTrue(SUBNET_TABLE.get(CP4).contains(P1));
656
657 verify(srManager.deviceConfiguration);
658 }
Ruchi Sahota71bcb4e2019-01-28 01:08:18 +0000659}