blob: 775e5eea02a66254c5190b794d8d82a1db871122 [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 Chan6c624992017-08-18 17:11:34 -070048
49import java.util.Map;
50import java.util.Set;
51
52import static org.junit.Assert.*;
53
54/**
55 * Unit test for {@link RouteHandler}.
56 */
57public class RouteHandlerTest {
58 private RouteHandler routeHandler;
Charles Chan910be6a2017-08-23 14:46:43 -070059 private HostService hostService;
Charles Chan6c624992017-08-18 17:11:34 -070060
61 // Mocked routing and bridging tables
62 private static final Map<MockBridgingTableKey, MockBridgingTableValue> BRIDGING_TABLE =
63 Maps.newConcurrentMap();
64 private static final Map<MockRoutingTableKey, MockRoutingTableValue> ROUTING_TABLE =
65 Maps.newConcurrentMap();
66 private static final Map<ConnectPoint, Set<IpPrefix>> SUBNET_TABLE = Maps.newConcurrentMap();
67 // Mocked Next Id
68 private static final Map<Integer, TrafficTreatment> NEXT_TABLE = Maps.newConcurrentMap();
69
70 private static final IpPrefix P1 = IpPrefix.valueOf("10.0.0.0/24");
Charles Chan910be6a2017-08-23 14:46:43 -070071
72 // Single homed router 1
Charles Chan6c624992017-08-18 17:11:34 -070073 private static final IpAddress N1 = IpAddress.valueOf("10.0.1.254");
74 private static final MacAddress M1 = MacAddress.valueOf("00:00:00:00:00:01");
75 private static final VlanId V1 = VlanId.vlanId((short) 1);
76 private static final ConnectPoint CP1 = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
77 private static final Route R1 = new Route(Route.Source.STATIC, P1, N1);
Charles Chanf0ae41e2017-08-23 13:55:39 -070078 private static final ResolvedRoute RR1 = new ResolvedRoute(R1, M1, V1);
Charles Chan6c624992017-08-18 17:11:34 -070079
Charles Chan910be6a2017-08-23 14:46:43 -070080 // Single homed router 2
Charles Chan6c624992017-08-18 17:11:34 -070081 private static final IpAddress N2 = IpAddress.valueOf("10.0.2.254");
82 private static final MacAddress M2 = MacAddress.valueOf("00:00:00:00:00:02");
83 private static final VlanId V2 = VlanId.vlanId((short) 2);
Charles Chan910be6a2017-08-23 14:46:43 -070084 private static final ConnectPoint CP2 = ConnectPoint.deviceConnectPoint("of:0000000000000002/2");
Charles Chan6c624992017-08-18 17:11:34 -070085 private static final Route R2 = new Route(Route.Source.STATIC, P1, N2);
Charles Chanf0ae41e2017-08-23 13:55:39 -070086 private static final ResolvedRoute RR2 = new ResolvedRoute(R2, M2, V2);
Charles Chan6c624992017-08-18 17:11:34 -070087
Charles Chan910be6a2017-08-23 14:46:43 -070088 // Dual homed router 1
89 private static final IpAddress N3 = IpAddress.valueOf("10.0.3.254");
90 private static final MacAddress M3 = MacAddress.valueOf("00:00:00:00:00:03");
91 private static final VlanId V3 = VlanId.vlanId((short) 3);
92 private static final Route R3 = new Route(Route.Source.STATIC, P1, N3);
93 private static final ResolvedRoute RR3 = new ResolvedRoute(R3, M3, V3);
Charles Chan6c624992017-08-18 17:11:34 -070094
Charles Chan910be6a2017-08-23 14:46:43 -070095 // Hosts
Charles Chanf0ae41e2017-08-23 13:55:39 -070096 private static final Host H1 = new DefaultHost(ProviderId.NONE, HostId.hostId(M1, V1), M1, V1,
97 Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N1), false);
98 private static final Host H2 = new DefaultHost(ProviderId.NONE, HostId.hostId(M2, V2), M2, V2,
99 Sets.newHashSet(new HostLocation(CP2, 0)), Sets.newHashSet(N2), false);
Charles Chan910be6a2017-08-23 14:46:43 -0700100 private static final Host H3D = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
101 Sets.newHashSet(new HostLocation(CP1, 0), new HostLocation(CP2, 0)), Sets.newHashSet(N3), false);
102 private static final Host H3S = new DefaultHost(ProviderId.NONE, HostId.hostId(M3, V3), M3, V3,
103 Sets.newHashSet(new HostLocation(CP1, 0)), Sets.newHashSet(N3), false);
104
105 // Pair Local Port
106 private static final PortNumber P9 = PortNumber.portNumber(9);
Charles Chanf0ae41e2017-08-23 13:55:39 -0700107
Charles Chan6c624992017-08-18 17:11:34 -0700108 // A set of hosts
Charles Chan910be6a2017-08-23 14:46:43 -0700109 private static final Set<Host> HOSTS = Sets.newHashSet(H1, H2, H3D);
110 private static final Set<Host> HOSTS_ONE_FAIL = Sets.newHashSet(H1, H2, H3S);
111 private static final Set<Host> HOSTS_BOTH_FAIL = Sets.newHashSet(H1, H2);
Charles Chan6c624992017-08-18 17:11:34 -0700112 // A set of devices of which we have mastership
Charles Chan910be6a2017-08-23 14:46:43 -0700113 private static final Set<DeviceId> LOCAL_DEVICES = Sets.newHashSet(CP1.deviceId(), CP2.deviceId());
Charles Chan6c624992017-08-18 17:11:34 -0700114 // A set of interfaces
115 private static final Set<Interface> INTERFACES = Sets.newHashSet();
Charles Chan6c624992017-08-18 17:11:34 -0700116
117 @Before
118 public void setUp() throws Exception {
Charles Chan910be6a2017-08-23 14:46:43 -0700119 ObjectMapper mapper = new ObjectMapper();
120 ConfigApplyDelegate delegate = config -> { };
121
122 SegmentRoutingDeviceConfig dev1Config = new SegmentRoutingDeviceConfig();
123 JsonNode dev1Tree = mapper.createObjectNode();
124 dev1Config.init(CP1.deviceId(), "host-handler-test", dev1Tree, mapper, delegate);
125 dev1Config.setPairDeviceId(CP2.deviceId()).setPairLocalPort(P9);
126
127 SegmentRoutingDeviceConfig dev2Config = new SegmentRoutingDeviceConfig();
128 JsonNode dev2Tree = mapper.createObjectNode();
129 dev2Config.init(CP2.deviceId(), "host-handler-test", dev2Tree, mapper, delegate);
130 dev2Config.setPairDeviceId(CP1.deviceId()).setPairLocalPort(P9);
Charles Chan6c624992017-08-18 17:11:34 -0700131
132 MockNetworkConfigRegistry mockNetworkConfigRegistry = new MockNetworkConfigRegistry();
Charles Chan910be6a2017-08-23 14:46:43 -0700133 mockNetworkConfigRegistry.applyConfig(dev1Config);
134 mockNetworkConfigRegistry.applyConfig(dev2Config);
Charles Chan6c624992017-08-18 17:11:34 -0700135
136 // Initialize Segment Routing Manager
137 SegmentRoutingManager srManager = new MockSegmentRoutingManager(NEXT_TABLE);
138 srManager.cfgService = new NetworkConfigRegistryAdapter();
139 srManager.deviceConfiguration = new DeviceConfiguration(srManager);
140 srManager.flowObjectiveService = new MockFlowObjectiveService(BRIDGING_TABLE, NEXT_TABLE);
141 srManager.routingRulePopulator = new MockRoutingRulePopulator(srManager, ROUTING_TABLE);
142 srManager.defaultRoutingHandler = new MockDefaultRoutingHandler(srManager, SUBNET_TABLE);
143 srManager.interfaceService = new MockInterfaceService(INTERFACES);
144 srManager.mastershipService = new MockMastershipService(LOCAL_DEVICES);
Charles Chan910be6a2017-08-23 14:46:43 -0700145 hostService = new MockHostService(HOSTS);
146 srManager.hostService = hostService;
Charles Chan6c624992017-08-18 17:11:34 -0700147 srManager.cfgService = mockNetworkConfigRegistry;
Charles Chan910be6a2017-08-23 14:46:43 -0700148 srManager.routeService = new MockRouteService(ROUTING_TABLE);
Charles Chan6c624992017-08-18 17:11:34 -0700149
Charles Chan910be6a2017-08-23 14:46:43 -0700150 routeHandler = new RouteHandler(srManager) {
151 // routeEventCache is not necessary for unit tests
152 @Override
153 void enqueueRouteEvent(RouteEvent routeEvent) {
154 dequeueRouteEvent(routeEvent);
155 }
156 };
Charles Chan6c624992017-08-18 17:11:34 -0700157
158 ROUTING_TABLE.clear();
159 BRIDGING_TABLE.clear();
160 SUBNET_TABLE.clear();
161 }
162
163 @Test
164 public void init() throws Exception {
Charles Chan910be6a2017-08-23 14:46:43 -0700165 MockRoutingTableKey rtk = new MockRoutingTableKey(CP1.deviceId(), P1);
166 MockRoutingTableValue rtv = new MockRoutingTableValue(CP1.port(), M1, V1);
167 ROUTING_TABLE.put(rtk, rtv);
168
Charles Chan6c624992017-08-18 17:11:34 -0700169 routeHandler.init(CP1.deviceId());
170
171 assertEquals(1, ROUTING_TABLE.size());
Charles Chanf0ae41e2017-08-23 13:55:39 -0700172 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
173 assertEquals(M1, rtv1.macAddress);
174 assertEquals(V1, rtv1.vlanId);
175 assertEquals(CP1.port(), rtv1.portNumber);
176
Charles Chan6c624992017-08-18 17:11:34 -0700177 assertEquals(1, SUBNET_TABLE.size());
178 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
179 }
180
181 @Test
182 public void processRouteAdded() throws Exception {
Charles Chan910be6a2017-08-23 14:46:43 -0700183 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1));
Charles Chan6c624992017-08-18 17:11:34 -0700184 routeHandler.processRouteAdded(re);
185
186 assertEquals(1, ROUTING_TABLE.size());
Charles Chanf0ae41e2017-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 Chan6c624992017-08-18 17:11:34 -0700192 assertEquals(1, SUBNET_TABLE.size());
193 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
194 }
195
196 @Test
197 public void processRouteUpdated() throws Exception {
198 processRouteAdded();
199
Charles Chan910be6a2017-08-23 14:46:43 -0700200 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_UPDATED, RR2, RR1, Sets.newHashSet(RR2),
201 Sets.newHashSet(RR1));
Charles Chan6c624992017-08-18 17:11:34 -0700202 routeHandler.processRouteUpdated(re);
203
204 assertEquals(1, ROUTING_TABLE.size());
Charles Chan910be6a2017-08-23 14:46:43 -0700205 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
Charles Chanf0ae41e2017-08-23 13:55:39 -0700206 assertEquals(M2, rtv2.macAddress);
207 assertEquals(V2, rtv2.vlanId);
208 assertEquals(CP2.port(), rtv2.portNumber);
209
Charles Chan6c624992017-08-18 17:11:34 -0700210 assertEquals(1, SUBNET_TABLE.size());
211 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
212 }
213
214 @Test
215 public void processRouteRemoved() throws Exception {
216 processRouteAdded();
217
Charles Chan910be6a2017-08-23 14:46:43 -0700218 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1));
219 routeHandler.processRouteRemoved(re);
220
221 assertEquals(0, ROUTING_TABLE.size());
222 assertEquals(0, SUBNET_TABLE.size());
223 }
224
225 @Test
226 public void testTwoSingleHomedAdded() throws Exception {
227 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR1, Sets.newHashSet(RR1, RR2));
228 routeHandler.processRouteAdded(re);
229
230 assertEquals(2, ROUTING_TABLE.size());
231 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
232 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
233 assertEquals(M1, rtv1.macAddress);
234 assertEquals(M2, rtv2.macAddress);
235 assertEquals(V1, rtv1.vlanId);
236 assertEquals(V2, rtv2.vlanId);
237 assertEquals(CP1.port(), rtv1.portNumber);
238 assertEquals(CP2.port(), rtv2.portNumber);
239
240 assertEquals(2, SUBNET_TABLE.size());
241 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
242 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
243 }
244
245 @Test
246 public void testOneDualHomedAdded() throws Exception {
247 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, RR3, Sets.newHashSet(RR3));
248 routeHandler.processRouteAdded(re);
249
250 assertEquals(2, ROUTING_TABLE.size());
251 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
252 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
253 assertEquals(M3, rtv1.macAddress);
254 assertEquals(M3, rtv2.macAddress);
255 assertEquals(V3, rtv1.vlanId);
256 assertEquals(V3, rtv2.vlanId);
257 assertEquals(CP1.port(), rtv1.portNumber);
258 assertEquals(CP2.port(), rtv2.portNumber);
259
260 assertEquals(2, SUBNET_TABLE.size());
261 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
262 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
263 }
264
265 @Test
266 public void testOneSingleHomedToTwoSingleHomed() throws Exception {
267 processRouteAdded();
268
269 RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
270 Sets.newHashSet(RR1, RR2), Sets.newHashSet(RR1));
271 routeHandler.processAlternativeRoutesChanged(re);
272
273 assertEquals(2, ROUTING_TABLE.size());
274 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
275 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
276 assertEquals(M1, rtv1.macAddress);
277 assertEquals(M2, rtv2.macAddress);
278 assertEquals(V1, rtv1.vlanId);
279 assertEquals(V2, rtv2.vlanId);
280 assertEquals(CP1.port(), rtv1.portNumber);
281 assertEquals(CP2.port(), rtv2.portNumber);
282
283 assertEquals(2, SUBNET_TABLE.size());
284 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
285 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
286 }
287
288 @Test
289 public void testTwoSingleHomedToOneSingleHomed() throws Exception {
290 testTwoSingleHomedAdded();
291
292 RouteEvent re = new RouteEvent(RouteEvent.Type.ALTERNATIVE_ROUTES_CHANGED, RR1, null,
293 Sets.newHashSet(RR1), Sets.newHashSet(RR1, RR2));
294 routeHandler.processAlternativeRoutesChanged(re);
295
296 assertEquals(1, ROUTING_TABLE.size());
297 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
298 assertEquals(M1, rtv1.macAddress);
299 assertEquals(V1, rtv1.vlanId);
300 assertEquals(CP1.port(), rtv1.portNumber);
301
302 assertEquals(1, SUBNET_TABLE.size());
303 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
304 }
305
306 @Test
307 public void testDualHomedSingleLocationFail() throws Exception {
308 testOneDualHomedAdded();
309
310 HostEvent he = new HostEvent(HostEvent.Type.HOST_MOVED, H3S, H3D);
311 routeHandler.processHostMovedEvent(he);
312
313 assertEquals(2, ROUTING_TABLE.size());
314 MockRoutingTableValue rtv1 = ROUTING_TABLE.get(new MockRoutingTableKey(CP1.deviceId(), P1));
315 MockRoutingTableValue rtv2 = ROUTING_TABLE.get(new MockRoutingTableKey(CP2.deviceId(), P1));
316 assertEquals(M3, rtv1.macAddress);
317 assertEquals(M3, rtv2.macAddress);
318 assertEquals(V3, rtv1.vlanId);
319 assertEquals(V3, rtv2.vlanId);
320 assertEquals(CP1.port(), rtv1.portNumber);
321 assertEquals(P9, rtv2.portNumber);
322
323 // ECMP route table hasn't changed
324 assertEquals(2, SUBNET_TABLE.size());
325 assertTrue(SUBNET_TABLE.get(CP1).contains(P1));
326 assertTrue(SUBNET_TABLE.get(CP2).contains(P1));
327 }
328
329 @Test
330 public void testDualHomedBothLocationFail() throws Exception {
331 testDualHomedSingleLocationFail();
332
333 hostService = new MockHostService(HOSTS_ONE_FAIL);
334
335 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
336 routeHandler.processRouteRemoved(re);
337
338 assertEquals(0, ROUTING_TABLE.size());
339 assertEquals(0, SUBNET_TABLE.size());
340 }
341
342 @Test
343 public void testTwoSingleHomedRemoved() throws Exception {
344 testTwoSingleHomedAdded();
345
346 hostService = new MockHostService(HOSTS_BOTH_FAIL);
347
348 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR1, Sets.newHashSet(RR1, RR2));
349 routeHandler.processRouteRemoved(re);
350
351 assertEquals(0, ROUTING_TABLE.size());
352 assertEquals(0, SUBNET_TABLE.size());
353 }
354
355 @Test
356 public void testOneDualHomeRemoved() throws Exception {
357 testOneDualHomedAdded();
358
359 RouteEvent re = new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, RR3, Sets.newHashSet(RR3));
Charles Chan6c624992017-08-18 17:11:34 -0700360 routeHandler.processRouteRemoved(re);
361
362 assertEquals(0, ROUTING_TABLE.size());
363 assertEquals(0, SUBNET_TABLE.size());
364 }
Charles Chan6c624992017-08-18 17:11:34 -0700365}