blob: 0e1226eb2d4a6b5f5c803589c06d2782ce1f486d [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
2 * Copyright 2014 Open Networking Laboratory
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 */
Pingpingfc584672014-10-23 10:51:19 -070016package org.onlab.onos.sdnip;
17
18import static org.easymock.EasyMock.anyObject;
19import static org.easymock.EasyMock.createMock;
20import static org.easymock.EasyMock.expect;
21import static org.easymock.EasyMock.replay;
22import static org.easymock.EasyMock.reset;
23import static org.easymock.EasyMock.verify;
24import static org.junit.Assert.assertEquals;
25import static org.junit.Assert.assertTrue;
26
27import java.util.HashMap;
28import java.util.HashSet;
29import java.util.Map;
30import java.util.Set;
31import java.util.concurrent.ConcurrentHashMap;
32
33import org.junit.Before;
34import org.junit.Test;
35import org.onlab.junit.TestUtils;
36import org.onlab.junit.TestUtils.TestUtilsException;
Thomas Vachuskae0f804a2014-10-27 23:40:48 -070037import org.onlab.onos.core.ApplicationId;
Pingpingfc584672014-10-23 10:51:19 -070038import org.onlab.onos.net.ConnectPoint;
39import org.onlab.onos.net.DefaultHost;
40import org.onlab.onos.net.DeviceId;
41import org.onlab.onos.net.Host;
42import org.onlab.onos.net.HostId;
43import org.onlab.onos.net.HostLocation;
44import org.onlab.onos.net.PortNumber;
45import org.onlab.onos.net.flow.DefaultTrafficSelector;
46import org.onlab.onos.net.flow.DefaultTrafficTreatment;
47import org.onlab.onos.net.flow.TrafficSelector;
48import org.onlab.onos.net.flow.TrafficTreatment;
49import org.onlab.onos.net.host.HostEvent;
50import org.onlab.onos.net.host.HostService;
51import org.onlab.onos.net.host.InterfaceIpAddress;
Pavlin Radoslavov97e8a8b2014-11-24 17:51:28 -080052import org.onlab.onos.net.intent.Intent;
Pingpingfc584672014-10-23 10:51:19 -070053import org.onlab.onos.net.intent.IntentService;
54import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
Brian O'Connor520c0522014-11-23 23:50:47 -080055import org.onlab.onos.net.intent.AbstractIntentTest;
Pingpingfc584672014-10-23 10:51:19 -070056import org.onlab.onos.net.provider.ProviderId;
Pavlin Radoslavov97e8a8b2014-11-24 17:51:28 -080057import org.onlab.onos.sdnip.IntentSynchronizer.IntentKey;
Pingpingfc584672014-10-23 10:51:19 -070058import org.onlab.onos.sdnip.Router.InternalHostListener;
59import org.onlab.onos.sdnip.config.BgpPeer;
60import org.onlab.onos.sdnip.config.Interface;
61import org.onlab.onos.sdnip.config.SdnIpConfigService;
62import org.onlab.packet.Ethernet;
63import org.onlab.packet.IpAddress;
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080064import org.onlab.packet.Ip4Address;
Pingpingfc584672014-10-23 10:51:19 -070065import org.onlab.packet.IpPrefix;
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080066import org.onlab.packet.Ip4Prefix;
Pingpingfc584672014-10-23 10:51:19 -070067import org.onlab.packet.MacAddress;
68import org.onlab.packet.VlanId;
69
70import com.google.common.collect.Sets;
71import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
72import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
73import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
74
75/**
76 * This class tests adding a route, updating a route, deleting a route, and
77 * the ARP module answers the MAC address asynchronously.
78 */
Brian O'Connor520c0522014-11-23 23:50:47 -080079public class RouterTestWithAsyncArp extends AbstractIntentTest {
Pingpingfc584672014-10-23 10:51:19 -070080
81 private SdnIpConfigService sdnIpConfigService;
82 private InterfaceService interfaceService;
83 private IntentService intentService;
84 private HostService hostService;
85
86 private static final ConnectPoint SW1_ETH1 = new ConnectPoint(
87 DeviceId.deviceId("of:0000000000000001"),
88 PortNumber.portNumber(1));
89
90 private static final ConnectPoint SW2_ETH1 = new ConnectPoint(
91 DeviceId.deviceId("of:0000000000000002"),
92 PortNumber.portNumber(1));
93
94 private static final ConnectPoint SW3_ETH1 = new ConnectPoint(
95 DeviceId.deviceId("of:0000000000000003"),
96 PortNumber.portNumber(1));
97
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080098 private IntentSynchronizer intentSynchronizer;
Pingpingfc584672014-10-23 10:51:19 -070099 private Router router;
100 private InternalHostListener internalHostListener;
101
102 private static final ApplicationId APPID = new ApplicationId() {
103 @Override
104 public short id() {
105 return 1;
106 }
107
108 @Override
109 public String name() {
110 return "SDNIP";
111 }
112 };
113
114 @Before
115 public void setUp() throws Exception {
Brian O'Connor520c0522014-11-23 23:50:47 -0800116 super.setUp();
117
Pingpingfc584672014-10-23 10:51:19 -0700118 setUpSdnIpConfigService();
119 setUpInterfaceService();
120 hostService = createMock(HostService.class);
121 intentService = createMock(IntentService.class);
122
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800123 intentSynchronizer = new IntentSynchronizer(APPID, intentService);
124 router = new Router(APPID, intentSynchronizer,
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800125 sdnIpConfigService, interfaceService, hostService);
Pingpingfc584672014-10-23 10:51:19 -0700126 internalHostListener = router.new InternalHostListener();
127 }
128
129 /**
130 * Sets up SdnIpConfigService.
131 */
132 private void setUpSdnIpConfigService() {
133
134 sdnIpConfigService = createMock(SdnIpConfigService.class);
135
136 Map<IpAddress, BgpPeer> peers = new HashMap<>();
137
138 String peerSw1Eth1 = "192.168.10.1";
139 peers.put(IpAddress.valueOf(peerSw1Eth1),
140 new BgpPeer("00:00:00:00:00:00:00:01", 1, peerSw1Eth1));
141
142 // Two BGP peers are connected to switch 2 port 1.
143 String peer1Sw2Eth1 = "192.168.20.1";
144 peers.put(IpAddress.valueOf(peer1Sw2Eth1),
145 new BgpPeer("00:00:00:00:00:00:00:02", 1, peer1Sw2Eth1));
146
147 String peer2Sw2Eth1 = "192.168.20.2";
148 peers.put(IpAddress.valueOf(peer2Sw2Eth1),
149 new BgpPeer("00:00:00:00:00:00:00:02", 1, peer2Sw2Eth1));
150
151 expect(sdnIpConfigService.getBgpPeers()).andReturn(peers).anyTimes();
152 replay(sdnIpConfigService);
153 }
154
155 /**
156 * Sets up InterfaceService.
157 */
158 private void setUpInterfaceService() {
159
160 interfaceService = createMock(InterfaceService.class);
161
162 Set<Interface> interfaces = Sets.newHashSet();
163
164 Set<InterfaceIpAddress> interfaceIpAddresses1 = Sets.newHashSet();
165 interfaceIpAddresses1.add(new InterfaceIpAddress(
166 IpAddress.valueOf("192.168.10.101"),
167 IpPrefix.valueOf("192.168.10.0/24")));
168 Interface sw1Eth1 = new Interface(SW1_ETH1,
169 interfaceIpAddresses1, MacAddress.valueOf("00:00:00:00:00:01"));
170 interfaces.add(sw1Eth1);
171
172 Set<InterfaceIpAddress> interfaceIpAddresses2 = Sets.newHashSet();
173 interfaceIpAddresses2.add(new InterfaceIpAddress(
174 IpAddress.valueOf("192.168.20.101"),
175 IpPrefix.valueOf("192.168.20.0/24")));
176 Interface sw2Eth1 = new Interface(SW2_ETH1,
177 interfaceIpAddresses2, MacAddress.valueOf("00:00:00:00:00:02"));
178 interfaces.add(sw2Eth1);
179
180 Set<InterfaceIpAddress> interfaceIpAddresses3 = Sets.newHashSet();
181 interfaceIpAddresses3.add(new InterfaceIpAddress(
182 IpAddress.valueOf("192.168.30.101"),
183 IpPrefix.valueOf("192.168.30.0/24")));
184 Interface sw3Eth1 = new Interface(SW3_ETH1,
185 interfaceIpAddresses3, MacAddress.valueOf("00:00:00:00:00:03"));
186 interfaces.add(sw3Eth1);
187
188 expect(interfaceService.getInterface(SW1_ETH1)).andReturn(sw1Eth1).anyTimes();
189 expect(interfaceService.getInterface(SW2_ETH1)).andReturn(sw2Eth1).anyTimes();
190 expect(interfaceService.getInterface(SW3_ETH1)).andReturn(sw3Eth1).anyTimes();
191 expect(interfaceService.getInterfaces()).andReturn(interfaces).anyTimes();
192 replay(interfaceService);
193 }
194
195 /**
196 * This method tests adding a route entry.
197 */
Pavlin Radoslavov97e8a8b2014-11-24 17:51:28 -0800198 @Test
Pingpingfc584672014-10-23 10:51:19 -0700199 public void testProcessRouteAdd() throws TestUtilsException {
200
201 // Construct a route entry
202 RouteEntry routeEntry = new RouteEntry(
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800203 Ip4Prefix.valueOf("1.1.1.0/24"),
204 Ip4Address.valueOf("192.168.10.1"));
Pingpingfc584672014-10-23 10:51:19 -0700205
206 // Construct a route intent
207 MultiPointToSinglePointIntent intent = staticIntentBuilder();
208
209 // Set up test expectation
210 reset(hostService);
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700211 expect(hostService.getHostsByIp(anyObject(IpAddress.class))).andReturn(
Pingpingfc584672014-10-23 10:51:19 -0700212 new HashSet<Host>()).anyTimes();
213 hostService.startMonitoringIp(IpAddress.valueOf("192.168.10.1"));
214 replay(hostService);
215
216 reset(intentService);
Pavlin Radoslavov97e8a8b2014-11-24 17:51:28 -0800217 intentService.submit(TestIntentServiceHelper.eqExceptId(intent));
Pingpingfc584672014-10-23 10:51:19 -0700218 replay(intentService);
219
220 // Call the processRouteAdd() method in Router class
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800221 intentSynchronizer.leaderChanged(true);
222 TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
Pingpingfc584672014-10-23 10:51:19 -0700223 router.processRouteAdd(routeEntry);
224
225 Host host = new DefaultHost(ProviderId.NONE, HostId.NONE,
226 MacAddress.valueOf("00:00:00:00:00:01"), VlanId.NONE,
227 new HostLocation(
228 SW1_ETH1.deviceId(),
229 SW1_ETH1.port(), 1),
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700230 Sets.newHashSet(IpAddress.valueOf("192.168.10.1")));
Pingpingfc584672014-10-23 10:51:19 -0700231 internalHostListener.event(
232 new HostEvent(HostEvent.Type.HOST_ADDED, host));
233
234 // Verify
235 assertEquals(router.getRoutes().size(), 1);
236 assertTrue(router.getRoutes().contains(routeEntry));
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800237 assertEquals(intentSynchronizer.getRouteIntents().size(), 1);
Pavlin Radoslavov97e8a8b2014-11-24 17:51:28 -0800238 Intent firstIntent =
239 intentSynchronizer.getRouteIntents().iterator().next();
240 IntentKey firstIntentKey = new IntentKey(firstIntent);
241 IntentKey intentKey = new IntentKey(intent);
242 assertTrue(firstIntentKey.equals(intentKey));
Pingpingfc584672014-10-23 10:51:19 -0700243 verify(intentService);
244 verify(hostService);
245
246 }
247
248 /**
249 * This method tests updating a route entry.
250 *
251 * @throws TestUtilsException
252 */
Pavlin Radoslavov97e8a8b2014-11-24 17:51:28 -0800253 @Test
Pingpingfc584672014-10-23 10:51:19 -0700254 public void testRouteUpdate() throws TestUtilsException {
255
256 // Construct the existing route entry
257 RouteEntry routeEntry = new RouteEntry(
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800258 Ip4Prefix.valueOf("1.1.1.0/24"),
259 Ip4Address.valueOf("192.168.10.1"));
Pingpingfc584672014-10-23 10:51:19 -0700260
261 // Construct the existing MultiPointToSinglePointIntent intent
262 MultiPointToSinglePointIntent intent = staticIntentBuilder();
263
264 // Set up the bgpRoutes field of Router class with existing route, and
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800265 // routeIntents field with the corresponding existing intent
Pingpingfc584672014-10-23 10:51:19 -0700266 setBgpRoutesField(routeEntry);
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800267 setRouteIntentsField(routeEntry, intent);
Pingpingfc584672014-10-23 10:51:19 -0700268
269 // Start to construct a new route entry and new intent
270 RouteEntry routeEntryUpdate = new RouteEntry(
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800271 Ip4Prefix.valueOf("1.1.1.0/24"),
272 Ip4Address.valueOf("192.168.20.1"));
Pingpingfc584672014-10-23 10:51:19 -0700273
274 // Construct a new MultiPointToSinglePointIntent intent
275 TrafficSelector.Builder selectorBuilderNew =
276 DefaultTrafficSelector.builder();
277 selectorBuilderNew.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
278 routeEntryUpdate.prefix());
279
280 TrafficTreatment.Builder treatmentBuilderNew =
281 DefaultTrafficTreatment.builder();
282 treatmentBuilderNew.setEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
283
284 Set<ConnectPoint> ingressPointsNew = new HashSet<ConnectPoint>();
285 ingressPointsNew.add(SW1_ETH1);
286 ingressPointsNew.add(SW3_ETH1);
287
288 MultiPointToSinglePointIntent intentNew =
289 new MultiPointToSinglePointIntent(APPID,
290 selectorBuilderNew.build(),
291 treatmentBuilderNew.build(),
292 ingressPointsNew, SW2_ETH1);
293
294 // Set up test expectation
295 reset(hostService);
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700296 expect(hostService.getHostsByIp(anyObject(IpAddress.class))).andReturn(
Pingpingfc584672014-10-23 10:51:19 -0700297 new HashSet<Host>()).anyTimes();
298 hostService.startMonitoringIp(IpAddress.valueOf("192.168.20.1"));
299 replay(hostService);
300
301 reset(intentService);
Pavlin Radoslavov97e8a8b2014-11-24 17:51:28 -0800302 intentService.withdraw(TestIntentServiceHelper.eqExceptId(intent));
303 intentService.submit(TestIntentServiceHelper.eqExceptId(intentNew));
Pingpingfc584672014-10-23 10:51:19 -0700304 replay(intentService);
305
306 // Call the processRouteAdd() method in Router class
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800307 intentSynchronizer.leaderChanged(true);
308 TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
Pingpingfc584672014-10-23 10:51:19 -0700309 router.processRouteAdd(routeEntryUpdate);
310
311 Host host = new DefaultHost(ProviderId.NONE, HostId.NONE,
312 MacAddress.valueOf("00:00:00:00:00:02"), VlanId.NONE,
313 new HostLocation(
314 SW2_ETH1.deviceId(),
315 SW2_ETH1.port(), 1),
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700316 Sets.newHashSet(IpAddress.valueOf("192.168.20.1")));
Pingpingfc584672014-10-23 10:51:19 -0700317 internalHostListener.event(
318 new HostEvent(HostEvent.Type.HOST_ADDED, host));
319
320 // Verify
321 assertEquals(router.getRoutes().size(), 1);
322 assertTrue(router.getRoutes().contains(routeEntryUpdate));
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800323 assertEquals(intentSynchronizer.getRouteIntents().size(), 1);
Pavlin Radoslavov97e8a8b2014-11-24 17:51:28 -0800324 Intent firstIntent =
325 intentSynchronizer.getRouteIntents().iterator().next();
326 IntentKey firstIntentKey = new IntentKey(firstIntent);
327 IntentKey intentNewKey = new IntentKey(intentNew);
328 assertTrue(firstIntentKey.equals(intentNewKey));
Pingpingfc584672014-10-23 10:51:19 -0700329 verify(intentService);
330 verify(hostService);
331 }
332
333 /**
334 * This method tests deleting a route entry.
335 */
336 @Test
337 public void testProcessRouteDelete() throws TestUtilsException {
338
339 // Construct the existing route entry
340 RouteEntry routeEntry = new RouteEntry(
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800341 Ip4Prefix.valueOf("1.1.1.0/24"),
342 Ip4Address.valueOf("192.168.10.1"));
Pingpingfc584672014-10-23 10:51:19 -0700343
344 // Construct the existing MultiPointToSinglePointIntent intent
345 MultiPointToSinglePointIntent intent = staticIntentBuilder();
346
347 // Set up the bgpRoutes field of Router class with existing route, and
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800348 // routeIntents field with the corresponding existing intent
Pingpingfc584672014-10-23 10:51:19 -0700349 setBgpRoutesField(routeEntry);
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800350 setRouteIntentsField(routeEntry, intent);
Pingpingfc584672014-10-23 10:51:19 -0700351
352 // Set up expectation
353 reset(intentService);
Pavlin Radoslavov97e8a8b2014-11-24 17:51:28 -0800354 intentService.withdraw(TestIntentServiceHelper.eqExceptId(intent));
Pingpingfc584672014-10-23 10:51:19 -0700355 replay(intentService);
356
357 // Call route deleting method in Router class
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800358 intentSynchronizer.leaderChanged(true);
359 TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
Pingpingfc584672014-10-23 10:51:19 -0700360 router.processRouteDelete(routeEntry);
361
362 // Verify
363 assertEquals(router.getRoutes().size(), 0);
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800364 assertEquals(intentSynchronizer.getRouteIntents().size(), 0);
Pingpingfc584672014-10-23 10:51:19 -0700365 verify(intentService);
366 }
367
368 /**
369 * Constructs a static MultiPointToSinglePointIntent.
370 */
371 private MultiPointToSinglePointIntent staticIntentBuilder() {
372
373 TrafficSelector.Builder selectorBuilder =
374 DefaultTrafficSelector.builder();
375 selectorBuilder.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
376 IpPrefix.valueOf("1.1.1.0/24"));
377
378 TrafficTreatment.Builder treatmentBuilder =
379 DefaultTrafficTreatment.builder();
380 treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:01"));
381
382 Set<ConnectPoint> ingressPoints = new HashSet<ConnectPoint>();
383 ingressPoints.add(SW2_ETH1);
384 ingressPoints.add(SW3_ETH1);
385
386 MultiPointToSinglePointIntent intent =
387 new MultiPointToSinglePointIntent(APPID,
388 selectorBuilder.build(), treatmentBuilder.build(),
389 ingressPoints, SW1_ETH1);
390
391 return intent;
392 }
393
394 /**
395 * Sets bgpRoutesField in Router class.
396 *
397 * @throws TestUtilsException
398 */
399 private void setBgpRoutesField(RouteEntry routeEntry)
400 throws TestUtilsException {
401
402 InvertedRadixTree<RouteEntry> bgpRoutes =
403 new ConcurrentInvertedRadixTree<>(
404 new DefaultByteArrayNodeFactory());
405 bgpRoutes.put(RouteEntry.createBinaryString(routeEntry.prefix()),
406 routeEntry);
407 TestUtils.setField(router, "bgpRoutes", bgpRoutes);
408 }
409
410 /**
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800411 * Sets routeIntentsField in IntentSynchronizer class.
Pingpingfc584672014-10-23 10:51:19 -0700412 *
413 * @throws TestUtilsException
414 */
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800415 private void setRouteIntentsField(RouteEntry routeEntry,
Pingpingfc584672014-10-23 10:51:19 -0700416 MultiPointToSinglePointIntent intent)
417 throws TestUtilsException {
418
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800419 ConcurrentHashMap<Ip4Prefix, MultiPointToSinglePointIntent>
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800420 routeIntents = new ConcurrentHashMap<>();
421 routeIntents.put(routeEntry.prefix(), intent);
422 TestUtils.setField(intentSynchronizer, "routeIntents", routeIntents);
Pingpingfc584672014-10-23 10:51:19 -0700423 }
424}