blob: b4389c8a2a55e0bf57aea71543a655fd2d7a813a [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;
52import org.onlab.onos.net.intent.IntentService;
53import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
54import org.onlab.onos.net.provider.ProviderId;
55import org.onlab.onos.sdnip.Router.InternalHostListener;
56import org.onlab.onos.sdnip.config.BgpPeer;
57import org.onlab.onos.sdnip.config.Interface;
58import org.onlab.onos.sdnip.config.SdnIpConfigService;
59import org.onlab.packet.Ethernet;
60import org.onlab.packet.IpAddress;
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080061import org.onlab.packet.Ip4Address;
Pingpingfc584672014-10-23 10:51:19 -070062import org.onlab.packet.IpPrefix;
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080063import org.onlab.packet.Ip4Prefix;
Pingpingfc584672014-10-23 10:51:19 -070064import org.onlab.packet.MacAddress;
65import org.onlab.packet.VlanId;
66
67import com.google.common.collect.Sets;
68import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
69import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
70import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
71
72/**
73 * This class tests adding a route, updating a route, deleting a route, and
74 * the ARP module answers the MAC address asynchronously.
75 */
76public class RouterTestWithAsyncArp {
77
78 private SdnIpConfigService sdnIpConfigService;
79 private InterfaceService interfaceService;
80 private IntentService intentService;
81 private HostService hostService;
82
83 private static final ConnectPoint SW1_ETH1 = new ConnectPoint(
84 DeviceId.deviceId("of:0000000000000001"),
85 PortNumber.portNumber(1));
86
87 private static final ConnectPoint SW2_ETH1 = new ConnectPoint(
88 DeviceId.deviceId("of:0000000000000002"),
89 PortNumber.portNumber(1));
90
91 private static final ConnectPoint SW3_ETH1 = new ConnectPoint(
92 DeviceId.deviceId("of:0000000000000003"),
93 PortNumber.portNumber(1));
94
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -080095 private IntentSynchronizer intentSynchronizer;
Pingpingfc584672014-10-23 10:51:19 -070096 private Router router;
97 private InternalHostListener internalHostListener;
98
99 private static final ApplicationId APPID = new ApplicationId() {
100 @Override
101 public short id() {
102 return 1;
103 }
104
105 @Override
106 public String name() {
107 return "SDNIP";
108 }
109 };
110
111 @Before
112 public void setUp() throws Exception {
113 setUpSdnIpConfigService();
114 setUpInterfaceService();
115 hostService = createMock(HostService.class);
116 intentService = createMock(IntentService.class);
117
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800118 intentSynchronizer = new IntentSynchronizer(APPID, intentService);
119 router = new Router(APPID, intentSynchronizer,
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800120 sdnIpConfigService, interfaceService, hostService);
Pingpingfc584672014-10-23 10:51:19 -0700121 internalHostListener = router.new InternalHostListener();
122 }
123
124 /**
125 * Sets up SdnIpConfigService.
126 */
127 private void setUpSdnIpConfigService() {
128
129 sdnIpConfigService = createMock(SdnIpConfigService.class);
130
131 Map<IpAddress, BgpPeer> peers = new HashMap<>();
132
133 String peerSw1Eth1 = "192.168.10.1";
134 peers.put(IpAddress.valueOf(peerSw1Eth1),
135 new BgpPeer("00:00:00:00:00:00:00:01", 1, peerSw1Eth1));
136
137 // Two BGP peers are connected to switch 2 port 1.
138 String peer1Sw2Eth1 = "192.168.20.1";
139 peers.put(IpAddress.valueOf(peer1Sw2Eth1),
140 new BgpPeer("00:00:00:00:00:00:00:02", 1, peer1Sw2Eth1));
141
142 String peer2Sw2Eth1 = "192.168.20.2";
143 peers.put(IpAddress.valueOf(peer2Sw2Eth1),
144 new BgpPeer("00:00:00:00:00:00:00:02", 1, peer2Sw2Eth1));
145
146 expect(sdnIpConfigService.getBgpPeers()).andReturn(peers).anyTimes();
147 replay(sdnIpConfigService);
148 }
149
150 /**
151 * Sets up InterfaceService.
152 */
153 private void setUpInterfaceService() {
154
155 interfaceService = createMock(InterfaceService.class);
156
157 Set<Interface> interfaces = Sets.newHashSet();
158
159 Set<InterfaceIpAddress> interfaceIpAddresses1 = Sets.newHashSet();
160 interfaceIpAddresses1.add(new InterfaceIpAddress(
161 IpAddress.valueOf("192.168.10.101"),
162 IpPrefix.valueOf("192.168.10.0/24")));
163 Interface sw1Eth1 = new Interface(SW1_ETH1,
164 interfaceIpAddresses1, MacAddress.valueOf("00:00:00:00:00:01"));
165 interfaces.add(sw1Eth1);
166
167 Set<InterfaceIpAddress> interfaceIpAddresses2 = Sets.newHashSet();
168 interfaceIpAddresses2.add(new InterfaceIpAddress(
169 IpAddress.valueOf("192.168.20.101"),
170 IpPrefix.valueOf("192.168.20.0/24")));
171 Interface sw2Eth1 = new Interface(SW2_ETH1,
172 interfaceIpAddresses2, MacAddress.valueOf("00:00:00:00:00:02"));
173 interfaces.add(sw2Eth1);
174
175 Set<InterfaceIpAddress> interfaceIpAddresses3 = Sets.newHashSet();
176 interfaceIpAddresses3.add(new InterfaceIpAddress(
177 IpAddress.valueOf("192.168.30.101"),
178 IpPrefix.valueOf("192.168.30.0/24")));
179 Interface sw3Eth1 = new Interface(SW3_ETH1,
180 interfaceIpAddresses3, MacAddress.valueOf("00:00:00:00:00:03"));
181 interfaces.add(sw3Eth1);
182
183 expect(interfaceService.getInterface(SW1_ETH1)).andReturn(sw1Eth1).anyTimes();
184 expect(interfaceService.getInterface(SW2_ETH1)).andReturn(sw2Eth1).anyTimes();
185 expect(interfaceService.getInterface(SW3_ETH1)).andReturn(sw3Eth1).anyTimes();
186 expect(interfaceService.getInterfaces()).andReturn(interfaces).anyTimes();
187 replay(interfaceService);
188 }
189
190 /**
191 * This method tests adding a route entry.
192 */
193 @Test
194 public void testProcessRouteAdd() throws TestUtilsException {
195
196 // Construct a route entry
197 RouteEntry routeEntry = new RouteEntry(
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800198 Ip4Prefix.valueOf("1.1.1.0/24"),
199 Ip4Address.valueOf("192.168.10.1"));
Pingpingfc584672014-10-23 10:51:19 -0700200
201 // Construct a route intent
202 MultiPointToSinglePointIntent intent = staticIntentBuilder();
203
204 // Set up test expectation
205 reset(hostService);
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700206 expect(hostService.getHostsByIp(anyObject(IpAddress.class))).andReturn(
Pingpingfc584672014-10-23 10:51:19 -0700207 new HashSet<Host>()).anyTimes();
208 hostService.startMonitoringIp(IpAddress.valueOf("192.168.10.1"));
209 replay(hostService);
210
211 reset(intentService);
212 intentService.submit(intent);
213 replay(intentService);
214
215 // Call the processRouteAdd() method in Router class
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800216 intentSynchronizer.leaderChanged(true);
217 TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
Pingpingfc584672014-10-23 10:51:19 -0700218 router.processRouteAdd(routeEntry);
219
220 Host host = new DefaultHost(ProviderId.NONE, HostId.NONE,
221 MacAddress.valueOf("00:00:00:00:00:01"), VlanId.NONE,
222 new HostLocation(
223 SW1_ETH1.deviceId(),
224 SW1_ETH1.port(), 1),
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700225 Sets.newHashSet(IpAddress.valueOf("192.168.10.1")));
Pingpingfc584672014-10-23 10:51:19 -0700226 internalHostListener.event(
227 new HostEvent(HostEvent.Type.HOST_ADDED, host));
228
229 // Verify
230 assertEquals(router.getRoutes().size(), 1);
231 assertTrue(router.getRoutes().contains(routeEntry));
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800232 assertEquals(intentSynchronizer.getRouteIntents().size(), 1);
233 assertEquals(intentSynchronizer.getRouteIntents().iterator().next(),
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800234 intent);
Pingpingfc584672014-10-23 10:51:19 -0700235 verify(intentService);
236 verify(hostService);
237
238 }
239
240 /**
241 * This method tests updating a route entry.
242 *
243 * @throws TestUtilsException
244 */
245 @Test
246 public void testRouteUpdate() throws TestUtilsException {
247
248 // Construct the existing route entry
249 RouteEntry routeEntry = new RouteEntry(
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800250 Ip4Prefix.valueOf("1.1.1.0/24"),
251 Ip4Address.valueOf("192.168.10.1"));
Pingpingfc584672014-10-23 10:51:19 -0700252
253 // Construct the existing MultiPointToSinglePointIntent intent
254 MultiPointToSinglePointIntent intent = staticIntentBuilder();
255
256 // Set up the bgpRoutes field of Router class with existing route, and
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800257 // routeIntents field with the corresponding existing intent
Pingpingfc584672014-10-23 10:51:19 -0700258 setBgpRoutesField(routeEntry);
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800259 setRouteIntentsField(routeEntry, intent);
Pingpingfc584672014-10-23 10:51:19 -0700260
261 // Start to construct a new route entry and new intent
262 RouteEntry routeEntryUpdate = new RouteEntry(
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800263 Ip4Prefix.valueOf("1.1.1.0/24"),
264 Ip4Address.valueOf("192.168.20.1"));
Pingpingfc584672014-10-23 10:51:19 -0700265
266 // Construct a new MultiPointToSinglePointIntent intent
267 TrafficSelector.Builder selectorBuilderNew =
268 DefaultTrafficSelector.builder();
269 selectorBuilderNew.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
270 routeEntryUpdate.prefix());
271
272 TrafficTreatment.Builder treatmentBuilderNew =
273 DefaultTrafficTreatment.builder();
274 treatmentBuilderNew.setEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
275
276 Set<ConnectPoint> ingressPointsNew = new HashSet<ConnectPoint>();
277 ingressPointsNew.add(SW1_ETH1);
278 ingressPointsNew.add(SW3_ETH1);
279
280 MultiPointToSinglePointIntent intentNew =
281 new MultiPointToSinglePointIntent(APPID,
282 selectorBuilderNew.build(),
283 treatmentBuilderNew.build(),
284 ingressPointsNew, SW2_ETH1);
285
286 // Set up test expectation
287 reset(hostService);
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700288 expect(hostService.getHostsByIp(anyObject(IpAddress.class))).andReturn(
Pingpingfc584672014-10-23 10:51:19 -0700289 new HashSet<Host>()).anyTimes();
290 hostService.startMonitoringIp(IpAddress.valueOf("192.168.20.1"));
291 replay(hostService);
292
293 reset(intentService);
294 intentService.withdraw(intent);
295 intentService.submit(intentNew);
296 replay(intentService);
297
298 // Call the processRouteAdd() method in Router class
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800299 intentSynchronizer.leaderChanged(true);
300 TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
Pingpingfc584672014-10-23 10:51:19 -0700301 router.processRouteAdd(routeEntryUpdate);
302
303 Host host = new DefaultHost(ProviderId.NONE, HostId.NONE,
304 MacAddress.valueOf("00:00:00:00:00:02"), VlanId.NONE,
305 new HostLocation(
306 SW2_ETH1.deviceId(),
307 SW2_ETH1.port(), 1),
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700308 Sets.newHashSet(IpAddress.valueOf("192.168.20.1")));
Pingpingfc584672014-10-23 10:51:19 -0700309 internalHostListener.event(
310 new HostEvent(HostEvent.Type.HOST_ADDED, host));
311
312 // Verify
313 assertEquals(router.getRoutes().size(), 1);
314 assertTrue(router.getRoutes().contains(routeEntryUpdate));
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800315 assertEquals(intentSynchronizer.getRouteIntents().size(), 1);
316 assertEquals(intentSynchronizer.getRouteIntents().iterator().next(),
Pingpingfc584672014-10-23 10:51:19 -0700317 intentNew);
318 verify(intentService);
319 verify(hostService);
320 }
321
322 /**
323 * This method tests deleting a route entry.
324 */
325 @Test
326 public void testProcessRouteDelete() throws TestUtilsException {
327
328 // Construct the existing route entry
329 RouteEntry routeEntry = new RouteEntry(
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800330 Ip4Prefix.valueOf("1.1.1.0/24"),
331 Ip4Address.valueOf("192.168.10.1"));
Pingpingfc584672014-10-23 10:51:19 -0700332
333 // Construct the existing MultiPointToSinglePointIntent intent
334 MultiPointToSinglePointIntent intent = staticIntentBuilder();
335
336 // Set up the bgpRoutes field of Router class with existing route, and
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800337 // routeIntents field with the corresponding existing intent
Pingpingfc584672014-10-23 10:51:19 -0700338 setBgpRoutesField(routeEntry);
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800339 setRouteIntentsField(routeEntry, intent);
Pingpingfc584672014-10-23 10:51:19 -0700340
341 // Set up expectation
342 reset(intentService);
343 intentService.withdraw(intent);
344 replay(intentService);
345
346 // Call route deleting method in Router class
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800347 intentSynchronizer.leaderChanged(true);
348 TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
Pingpingfc584672014-10-23 10:51:19 -0700349 router.processRouteDelete(routeEntry);
350
351 // Verify
352 assertEquals(router.getRoutes().size(), 0);
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800353 assertEquals(intentSynchronizer.getRouteIntents().size(), 0);
Pingpingfc584672014-10-23 10:51:19 -0700354 verify(intentService);
355 }
356
357 /**
358 * Constructs a static MultiPointToSinglePointIntent.
359 */
360 private MultiPointToSinglePointIntent staticIntentBuilder() {
361
362 TrafficSelector.Builder selectorBuilder =
363 DefaultTrafficSelector.builder();
364 selectorBuilder.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
365 IpPrefix.valueOf("1.1.1.0/24"));
366
367 TrafficTreatment.Builder treatmentBuilder =
368 DefaultTrafficTreatment.builder();
369 treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:01"));
370
371 Set<ConnectPoint> ingressPoints = new HashSet<ConnectPoint>();
372 ingressPoints.add(SW2_ETH1);
373 ingressPoints.add(SW3_ETH1);
374
375 MultiPointToSinglePointIntent intent =
376 new MultiPointToSinglePointIntent(APPID,
377 selectorBuilder.build(), treatmentBuilder.build(),
378 ingressPoints, SW1_ETH1);
379
380 return intent;
381 }
382
383 /**
384 * Sets bgpRoutesField in Router class.
385 *
386 * @throws TestUtilsException
387 */
388 private void setBgpRoutesField(RouteEntry routeEntry)
389 throws TestUtilsException {
390
391 InvertedRadixTree<RouteEntry> bgpRoutes =
392 new ConcurrentInvertedRadixTree<>(
393 new DefaultByteArrayNodeFactory());
394 bgpRoutes.put(RouteEntry.createBinaryString(routeEntry.prefix()),
395 routeEntry);
396 TestUtils.setField(router, "bgpRoutes", bgpRoutes);
397 }
398
399 /**
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800400 * Sets routeIntentsField in IntentSynchronizer class.
Pingpingfc584672014-10-23 10:51:19 -0700401 *
402 * @throws TestUtilsException
403 */
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800404 private void setRouteIntentsField(RouteEntry routeEntry,
Pingpingfc584672014-10-23 10:51:19 -0700405 MultiPointToSinglePointIntent intent)
406 throws TestUtilsException {
407
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800408 ConcurrentHashMap<Ip4Prefix, MultiPointToSinglePointIntent>
Pavlin Radoslavova7243cc2014-11-22 21:38:02 -0800409 routeIntents = new ConcurrentHashMap<>();
410 routeIntents.put(routeEntry.prefix(), intent);
411 TestUtils.setField(intentSynchronizer, "routeIntents", routeIntents);
Pingpingfc584672014-10-23 10:51:19 -0700412 }
413}