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