blob: 2ea5f17f506e8e6cb9fa35f2dcd6a9a943f706c9 [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;
61import org.onlab.packet.IpPrefix;
62import org.onlab.packet.MacAddress;
63import org.onlab.packet.VlanId;
64
65import com.google.common.collect.Sets;
66import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
67import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
68import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
69
70/**
71 * This class tests adding a route, updating a route, deleting a route, and
72 * the ARP module answers the MAC address asynchronously.
73 */
74public class RouterTestWithAsyncArp {
75
76 private SdnIpConfigService sdnIpConfigService;
77 private InterfaceService interfaceService;
78 private IntentService intentService;
79 private HostService hostService;
80
81 private static final ConnectPoint SW1_ETH1 = new ConnectPoint(
82 DeviceId.deviceId("of:0000000000000001"),
83 PortNumber.portNumber(1));
84
85 private static final ConnectPoint SW2_ETH1 = new ConnectPoint(
86 DeviceId.deviceId("of:0000000000000002"),
87 PortNumber.portNumber(1));
88
89 private static final ConnectPoint SW3_ETH1 = new ConnectPoint(
90 DeviceId.deviceId("of:0000000000000003"),
91 PortNumber.portNumber(1));
92
93 private Router router;
94 private InternalHostListener internalHostListener;
95
96 private static final ApplicationId APPID = new ApplicationId() {
97 @Override
98 public short id() {
99 return 1;
100 }
101
102 @Override
103 public String name() {
104 return "SDNIP";
105 }
106 };
107
108 @Before
109 public void setUp() throws Exception {
110 setUpSdnIpConfigService();
111 setUpInterfaceService();
112 hostService = createMock(HostService.class);
113 intentService = createMock(IntentService.class);
114
115 router = new Router(APPID, intentService,
116 hostService, sdnIpConfigService, interfaceService);
117 internalHostListener = router.new InternalHostListener();
118 }
119
120 /**
121 * Sets up SdnIpConfigService.
122 */
123 private void setUpSdnIpConfigService() {
124
125 sdnIpConfigService = createMock(SdnIpConfigService.class);
126
127 Map<IpAddress, BgpPeer> peers = new HashMap<>();
128
129 String peerSw1Eth1 = "192.168.10.1";
130 peers.put(IpAddress.valueOf(peerSw1Eth1),
131 new BgpPeer("00:00:00:00:00:00:00:01", 1, peerSw1Eth1));
132
133 // Two BGP peers are connected to switch 2 port 1.
134 String peer1Sw2Eth1 = "192.168.20.1";
135 peers.put(IpAddress.valueOf(peer1Sw2Eth1),
136 new BgpPeer("00:00:00:00:00:00:00:02", 1, peer1Sw2Eth1));
137
138 String peer2Sw2Eth1 = "192.168.20.2";
139 peers.put(IpAddress.valueOf(peer2Sw2Eth1),
140 new BgpPeer("00:00:00:00:00:00:00:02", 1, peer2Sw2Eth1));
141
142 expect(sdnIpConfigService.getBgpPeers()).andReturn(peers).anyTimes();
143 replay(sdnIpConfigService);
144 }
145
146 /**
147 * Sets up InterfaceService.
148 */
149 private void setUpInterfaceService() {
150
151 interfaceService = createMock(InterfaceService.class);
152
153 Set<Interface> interfaces = Sets.newHashSet();
154
155 Set<InterfaceIpAddress> interfaceIpAddresses1 = Sets.newHashSet();
156 interfaceIpAddresses1.add(new InterfaceIpAddress(
157 IpAddress.valueOf("192.168.10.101"),
158 IpPrefix.valueOf("192.168.10.0/24")));
159 Interface sw1Eth1 = new Interface(SW1_ETH1,
160 interfaceIpAddresses1, MacAddress.valueOf("00:00:00:00:00:01"));
161 interfaces.add(sw1Eth1);
162
163 Set<InterfaceIpAddress> interfaceIpAddresses2 = Sets.newHashSet();
164 interfaceIpAddresses2.add(new InterfaceIpAddress(
165 IpAddress.valueOf("192.168.20.101"),
166 IpPrefix.valueOf("192.168.20.0/24")));
167 Interface sw2Eth1 = new Interface(SW2_ETH1,
168 interfaceIpAddresses2, MacAddress.valueOf("00:00:00:00:00:02"));
169 interfaces.add(sw2Eth1);
170
171 Set<InterfaceIpAddress> interfaceIpAddresses3 = Sets.newHashSet();
172 interfaceIpAddresses3.add(new InterfaceIpAddress(
173 IpAddress.valueOf("192.168.30.101"),
174 IpPrefix.valueOf("192.168.30.0/24")));
175 Interface sw3Eth1 = new Interface(SW3_ETH1,
176 interfaceIpAddresses3, MacAddress.valueOf("00:00:00:00:00:03"));
177 interfaces.add(sw3Eth1);
178
179 expect(interfaceService.getInterface(SW1_ETH1)).andReturn(sw1Eth1).anyTimes();
180 expect(interfaceService.getInterface(SW2_ETH1)).andReturn(sw2Eth1).anyTimes();
181 expect(interfaceService.getInterface(SW3_ETH1)).andReturn(sw3Eth1).anyTimes();
182 expect(interfaceService.getInterfaces()).andReturn(interfaces).anyTimes();
183 replay(interfaceService);
184 }
185
186 /**
187 * This method tests adding a route entry.
188 */
189 @Test
190 public void testProcessRouteAdd() throws TestUtilsException {
191
192 // Construct a route entry
193 RouteEntry routeEntry = new RouteEntry(
194 IpPrefix.valueOf("1.1.1.0/24"),
195 IpAddress.valueOf("192.168.10.1"));
196
197 // Construct a route intent
198 MultiPointToSinglePointIntent intent = staticIntentBuilder();
199
200 // Set up test expectation
201 reset(hostService);
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700202 expect(hostService.getHostsByIp(anyObject(IpAddress.class))).andReturn(
Pingpingfc584672014-10-23 10:51:19 -0700203 new HashSet<Host>()).anyTimes();
204 hostService.startMonitoringIp(IpAddress.valueOf("192.168.10.1"));
205 replay(hostService);
206
207 reset(intentService);
208 intentService.submit(intent);
209 replay(intentService);
210
211 // Call the processRouteAdd() method in Router class
212 router.leaderChanged(true);
213 TestUtils.setField(router, "isActivatedLeader", true);
214 router.processRouteAdd(routeEntry);
215
216 Host host = new DefaultHost(ProviderId.NONE, HostId.NONE,
217 MacAddress.valueOf("00:00:00:00:00:01"), VlanId.NONE,
218 new HostLocation(
219 SW1_ETH1.deviceId(),
220 SW1_ETH1.port(), 1),
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700221 Sets.newHashSet(IpAddress.valueOf("192.168.10.1")));
Pingpingfc584672014-10-23 10:51:19 -0700222 internalHostListener.event(
223 new HostEvent(HostEvent.Type.HOST_ADDED, host));
224
225 // Verify
226 assertEquals(router.getRoutes().size(), 1);
227 assertTrue(router.getRoutes().contains(routeEntry));
228 assertEquals(router.getPushedRouteIntents().size(), 1);
229 assertEquals(router.getPushedRouteIntents().iterator().next(),
230 intent);
231 verify(intentService);
232 verify(hostService);
233
234 }
235
236 /**
237 * This method tests updating a route entry.
238 *
239 * @throws TestUtilsException
240 */
241 @Test
242 public void testRouteUpdate() throws TestUtilsException {
243
244 // Construct the existing route entry
245 RouteEntry routeEntry = new RouteEntry(
246 IpPrefix.valueOf("1.1.1.0/24"),
247 IpAddress.valueOf("192.168.10.1"));
248
249 // Construct the existing MultiPointToSinglePointIntent intent
250 MultiPointToSinglePointIntent intent = staticIntentBuilder();
251
252 // Set up the bgpRoutes field of Router class with existing route, and
253 // pushedRouteIntents field with the corresponding existing intent
254 setBgpRoutesField(routeEntry);
255 setPushedRouteIntentsField(routeEntry, intent);
256
257 // Start to construct a new route entry and new intent
258 RouteEntry routeEntryUpdate = new RouteEntry(
259 IpPrefix.valueOf("1.1.1.0/24"),
260 IpAddress.valueOf("192.168.20.1"));
261
262 // Construct a new MultiPointToSinglePointIntent intent
263 TrafficSelector.Builder selectorBuilderNew =
264 DefaultTrafficSelector.builder();
265 selectorBuilderNew.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
266 routeEntryUpdate.prefix());
267
268 TrafficTreatment.Builder treatmentBuilderNew =
269 DefaultTrafficTreatment.builder();
270 treatmentBuilderNew.setEthDst(MacAddress.valueOf("00:00:00:00:00:02"));
271
272 Set<ConnectPoint> ingressPointsNew = new HashSet<ConnectPoint>();
273 ingressPointsNew.add(SW1_ETH1);
274 ingressPointsNew.add(SW3_ETH1);
275
276 MultiPointToSinglePointIntent intentNew =
277 new MultiPointToSinglePointIntent(APPID,
278 selectorBuilderNew.build(),
279 treatmentBuilderNew.build(),
280 ingressPointsNew, SW2_ETH1);
281
282 // Set up test expectation
283 reset(hostService);
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700284 expect(hostService.getHostsByIp(anyObject(IpAddress.class))).andReturn(
Pingpingfc584672014-10-23 10:51:19 -0700285 new HashSet<Host>()).anyTimes();
286 hostService.startMonitoringIp(IpAddress.valueOf("192.168.20.1"));
287 replay(hostService);
288
289 reset(intentService);
290 intentService.withdraw(intent);
291 intentService.submit(intentNew);
292 replay(intentService);
293
294 // Call the processRouteAdd() method in Router class
295 router.leaderChanged(true);
296 TestUtils.setField(router, "isActivatedLeader", true);
297 router.processRouteAdd(routeEntryUpdate);
298
299 Host host = new DefaultHost(ProviderId.NONE, HostId.NONE,
300 MacAddress.valueOf("00:00:00:00:00:02"), VlanId.NONE,
301 new HostLocation(
302 SW2_ETH1.deviceId(),
303 SW2_ETH1.port(), 1),
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700304 Sets.newHashSet(IpAddress.valueOf("192.168.20.1")));
Pingpingfc584672014-10-23 10:51:19 -0700305 internalHostListener.event(
306 new HostEvent(HostEvent.Type.HOST_ADDED, host));
307
308 // Verify
309 assertEquals(router.getRoutes().size(), 1);
310 assertTrue(router.getRoutes().contains(routeEntryUpdate));
311 assertEquals(router.getPushedRouteIntents().size(), 1);
312 assertEquals(router.getPushedRouteIntents().iterator().next(),
313 intentNew);
314 verify(intentService);
315 verify(hostService);
316 }
317
318 /**
319 * This method tests deleting a route entry.
320 */
321 @Test
322 public void testProcessRouteDelete() throws TestUtilsException {
323
324 // Construct the existing route entry
325 RouteEntry routeEntry = new RouteEntry(
326 IpPrefix.valueOf("1.1.1.0/24"),
327 IpAddress.valueOf("192.168.10.1"));
328
329 // Construct the existing MultiPointToSinglePointIntent intent
330 MultiPointToSinglePointIntent intent = staticIntentBuilder();
331
332 // Set up the bgpRoutes field of Router class with existing route, and
333 // pushedRouteIntents field with the corresponding existing intent
334 setBgpRoutesField(routeEntry);
335 setPushedRouteIntentsField(routeEntry, intent);
336
337 // Set up expectation
338 reset(intentService);
339 intentService.withdraw(intent);
340 replay(intentService);
341
342 // Call route deleting method in Router class
343 router.leaderChanged(true);
344 TestUtils.setField(router, "isActivatedLeader", true);
345 router.processRouteDelete(routeEntry);
346
347 // Verify
348 assertEquals(router.getRoutes().size(), 0);
349 assertEquals(router.getPushedRouteIntents().size(), 0);
350 verify(intentService);
351 }
352
353 /**
354 * Constructs a static MultiPointToSinglePointIntent.
355 */
356 private MultiPointToSinglePointIntent staticIntentBuilder() {
357
358 TrafficSelector.Builder selectorBuilder =
359 DefaultTrafficSelector.builder();
360 selectorBuilder.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(
361 IpPrefix.valueOf("1.1.1.0/24"));
362
363 TrafficTreatment.Builder treatmentBuilder =
364 DefaultTrafficTreatment.builder();
365 treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:01"));
366
367 Set<ConnectPoint> ingressPoints = new HashSet<ConnectPoint>();
368 ingressPoints.add(SW2_ETH1);
369 ingressPoints.add(SW3_ETH1);
370
371 MultiPointToSinglePointIntent intent =
372 new MultiPointToSinglePointIntent(APPID,
373 selectorBuilder.build(), treatmentBuilder.build(),
374 ingressPoints, SW1_ETH1);
375
376 return intent;
377 }
378
379 /**
380 * Sets bgpRoutesField in Router class.
381 *
382 * @throws TestUtilsException
383 */
384 private void setBgpRoutesField(RouteEntry routeEntry)
385 throws TestUtilsException {
386
387 InvertedRadixTree<RouteEntry> bgpRoutes =
388 new ConcurrentInvertedRadixTree<>(
389 new DefaultByteArrayNodeFactory());
390 bgpRoutes.put(RouteEntry.createBinaryString(routeEntry.prefix()),
391 routeEntry);
392 TestUtils.setField(router, "bgpRoutes", bgpRoutes);
393 }
394
395 /**
396 * Sets pushedRouteIntentsField in Router class.
397 *
398 * @throws TestUtilsException
399 */
400 private void setPushedRouteIntentsField(RouteEntry routeEntry,
401 MultiPointToSinglePointIntent intent)
402 throws TestUtilsException {
403
404 ConcurrentHashMap<IpPrefix, MultiPointToSinglePointIntent>
405 pushedRouteIntents = new ConcurrentHashMap<>();
406 pushedRouteIntents.put(routeEntry.prefix(), intent);
407 TestUtils.setField(router, "pushedRouteIntents", pushedRouteIntents);
408 }
409}