blob: 1c25e758ffe1c4429569c569c16b84d73bbfb0c3 [file] [log] [blame]
Jonathan Hart23701d12014-04-03 10:45:48 -07001package net.onrc.onos.core.flowprogrammer;
Naoki Shiota75b7dd62013-12-03 18:09:21 -08002
Jonathan Harta88fd242014-04-03 11:24:54 -07003import static org.junit.Assert.assertEquals;
4import static org.junit.Assert.assertNotNull;
5import static org.junit.Assert.assertTrue;
6import static org.junit.Assert.fail;
Naoki Shiota75b7dd62013-12-03 18:09:21 -08007
8import java.io.IOException;
9import java.util.ArrayList;
10import java.util.HashMap;
11import java.util.List;
12import java.util.Map;
13import java.util.concurrent.ScheduledExecutorService;
14import java.util.concurrent.TimeUnit;
15
16import net.floodlightcontroller.core.FloodlightContext;
17import net.floodlightcontroller.core.IFloodlightProviderService;
18import net.floodlightcontroller.core.IOFSwitch;
19import net.floodlightcontroller.core.module.FloodlightModuleContext;
20import net.floodlightcontroller.threadpool.IThreadPoolService;
21import net.floodlightcontroller.util.OFMessageDamper;
Jonathan Hart23701d12014-04-03 10:45:48 -070022import net.onrc.onos.core.util.Dpid;
23import net.onrc.onos.core.util.FlowEntry;
24import net.onrc.onos.core.util.FlowEntryActions;
25import net.onrc.onos.core.util.FlowEntryErrorState;
26import net.onrc.onos.core.util.FlowEntryId;
27import net.onrc.onos.core.util.FlowEntryMatch;
28import net.onrc.onos.core.util.FlowEntryUserState;
29import net.onrc.onos.core.util.FlowId;
30import net.onrc.onos.core.util.Port;
Naoki Shiota75b7dd62013-12-03 18:09:21 -080031
32import org.easymock.EasyMock;
33import org.easymock.IAnswer;
Naoki Shiota75b7dd62013-12-03 18:09:21 -080034import org.junit.Test;
35import org.openflow.protocol.OFBarrierRequest;
36import org.openflow.protocol.OFFlowMod;
37import org.openflow.protocol.OFMatch;
38import org.openflow.protocol.OFMessage;
39import org.openflow.protocol.OFType;
40import org.openflow.protocol.action.OFAction;
41import org.openflow.protocol.factory.BasicFactory;
42
43public class FlowPusherTest {
Ray Milkey269ffb92014-04-03 14:43:30 -070044 private FlowPusher pusher;
45 private FloodlightContext context;
46 private FloodlightModuleContext modContext;
47 private BasicFactory factory;
48 private OFMessageDamper damper;
49 private IFloodlightProviderService flProviderService;
50 private IThreadPoolService threadPoolService;
Naoki Shiota75b7dd62013-12-03 18:09:21 -080051
Ray Milkey269ffb92014-04-03 14:43:30 -070052 /**
53 * Test single OFMessage is correctly sent to single switch via MessageDamper.
54 */
55 @Test
56 public void testAddMessage() {
57 beginInitMock();
Naoki Shiota75b7dd62013-12-03 18:09:21 -080058
Ray Milkey269ffb92014-04-03 14:43:30 -070059 OFMessage msg = EasyMock.createMock(OFMessage.class);
60 EasyMock.expect(msg.getXid()).andReturn(1).anyTimes();
61 EasyMock.expect(msg.getLength()).andReturn((short) 100).anyTimes();
62 EasyMock.replay(msg);
Naoki Shiota75b7dd62013-12-03 18:09:21 -080063
Ray Milkey269ffb92014-04-03 14:43:30 -070064 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
65 EasyMock.expect(sw.getId()).andReturn((long) 1).anyTimes();
66 sw.flush();
67 EasyMock.expectLastCall().once();
68 EasyMock.replay(sw);
Naoki Shiotad6ef3b32014-03-13 18:42:23 -070069
Ray Milkey269ffb92014-04-03 14:43:30 -070070 try {
71 EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
72 .andReturn(true).once();
73 } catch (IOException e1) {
74 fail("Failed in OFMessageDamper#write()");
75 }
Naoki Shiota75b7dd62013-12-03 18:09:21 -080076
Ray Milkey269ffb92014-04-03 14:43:30 -070077 endInitMock();
78 initPusher(1);
Naoki Shiotad6ef3b32014-03-13 18:42:23 -070079
Ray Milkey269ffb92014-04-03 14:43:30 -070080 boolean add_result = pusher.add(sw, msg);
81 assertTrue(add_result);
Naoki Shiota75b7dd62013-12-03 18:09:21 -080082
Ray Milkey269ffb92014-04-03 14:43:30 -070083 try {
84 // wait until message is processed.
85 Thread.sleep(1000);
86 } catch (InterruptedException e) {
87 fail("Failed in Thread.sleep()");
88 }
89 EasyMock.verify(msg);
90 EasyMock.verify(sw);
91 verifyAll();
Naoki Shiota75b7dd62013-12-03 18:09:21 -080092
Ray Milkey269ffb92014-04-03 14:43:30 -070093 pusher.stop();
94 }
Naoki Shiota75b7dd62013-12-03 18:09:21 -080095
Ray Milkey269ffb92014-04-03 14:43:30 -070096 /**
97 * Test bunch of OFMessages are correctly sent to single switch via MessageDamper.
98 */
99 @Test
100 public void testMassiveAddMessage() {
101 final int NUM_MSG = 10000;
Naoki Shiotad6ef3b32014-03-13 18:42:23 -0700102
Ray Milkey269ffb92014-04-03 14:43:30 -0700103 beginInitMock();
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800104
Ray Milkey269ffb92014-04-03 14:43:30 -0700105 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
106 EasyMock.expect(sw.getId()).andReturn((long) 1).anyTimes();
107 sw.flush();
108 EasyMock.expectLastCall().atLeastOnce();
109 EasyMock.replay(sw);
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800110
Ray Milkey269ffb92014-04-03 14:43:30 -0700111 List<OFMessage> messages = new ArrayList<OFMessage>();
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800112
Ray Milkey269ffb92014-04-03 14:43:30 -0700113 for (int i = 0; i < NUM_MSG; ++i) {
114 OFMessage msg = EasyMock.createMock(OFMessage.class);
115 EasyMock.expect(msg.getXid()).andReturn(i).anyTimes();
116 EasyMock.expect(msg.getLength()).andReturn((short) 100).anyTimes();
117 EasyMock.replay(msg);
118 messages.add(msg);
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800119
Ray Milkey269ffb92014-04-03 14:43:30 -0700120 try {
121 EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
122 .andReturn(true).once();
123 } catch (IOException e1) {
124 fail("Failed in OFMessageDamper#write()");
125 }
126 }
Naoki Shiotad6ef3b32014-03-13 18:42:23 -0700127
Ray Milkey269ffb92014-04-03 14:43:30 -0700128 endInitMock();
129 initPusher(1);
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800130
Ray Milkey269ffb92014-04-03 14:43:30 -0700131 for (OFMessage msg : messages) {
132 boolean add_result = pusher.add(sw, msg);
133 assertTrue(add_result);
134 }
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800135
Ray Milkey269ffb92014-04-03 14:43:30 -0700136 try {
137 // wait until message is processed.
138 Thread.sleep(5000);
139 } catch (InterruptedException e) {
140 fail("Failed in Thread.sleep()");
141 }
Naoki Shiotad6ef3b32014-03-13 18:42:23 -0700142
Ray Milkey269ffb92014-04-03 14:43:30 -0700143 for (OFMessage msg : messages) {
144 EasyMock.verify(msg);
145 }
146 EasyMock.verify(sw);
147 verifyAll();
148
149 pusher.stop();
150 }
151
152 /**
153 * Test bunch of OFMessages are correctly sent to multiple switches with single threads.
154 */
155 @Test
156 public void testMultiSwitchAddMessage() {
157 final int NUM_SWITCH = 10;
158 final int NUM_MSG = 100; // messages per thread
159
160 beginInitMock();
161
162 Map<IOFSwitch, List<OFMessage>> sw_map = new HashMap<IOFSwitch, List<OFMessage>>();
163 for (int i = 0; i < NUM_SWITCH; ++i) {
164 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
165 EasyMock.expect(sw.getId()).andReturn((long) i).anyTimes();
166 sw.flush();
167 EasyMock.expectLastCall().atLeastOnce();
168 EasyMock.replay(sw);
169
170 List<OFMessage> messages = new ArrayList<OFMessage>();
171
172 for (int j = 0; j < NUM_MSG; ++j) {
173 OFMessage msg = EasyMock.createMock(OFMessage.class);
174 EasyMock.expect(msg.getXid()).andReturn(j).anyTimes();
175 EasyMock.expect(msg.getLength()).andReturn((short) 100).anyTimes();
176 EasyMock.replay(msg);
177 messages.add(msg);
178
179 try {
180 EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
181 .andReturn(true).once();
182 } catch (IOException e1) {
183 fail("Failed in OFMessageDamper#write()");
184 }
185 }
186 sw_map.put(sw, messages);
187 }
188
189 endInitMock();
190 initPusher(1);
191
192 for (IOFSwitch sw : sw_map.keySet()) {
193 for (OFMessage msg : sw_map.get(sw)) {
194 boolean add_result = pusher.add(sw, msg);
195 assertTrue(add_result);
196 }
197 }
198
199 try {
200 // wait until message is processed.
201 Thread.sleep(1000);
202 } catch (InterruptedException e) {
203 fail("Failed in Thread.sleep()");
204 }
205
206 for (IOFSwitch sw : sw_map.keySet()) {
207 for (OFMessage msg : sw_map.get(sw)) {
208 EasyMock.verify(msg);
209 }
210
211 EasyMock.verify(sw);
212 }
213 verifyAll();
214
215 pusher.stop();
216 }
217
218 /**
219 * Test bunch of OFMessages are correctly sent to multiple switches using multiple threads.
220 */
221 @Test
222 public void testMultiThreadedAddMessage() {
223 final int NUM_THREAD = 10;
224 final int NUM_MSG = 100; // messages per thread
225
226 beginInitMock();
227
228 Map<IOFSwitch, List<OFMessage>> sw_map = new HashMap<IOFSwitch, List<OFMessage>>();
229 for (int i = 0; i < NUM_THREAD; ++i) {
230 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
231 EasyMock.expect(sw.getId()).andReturn((long) i).anyTimes();
232 sw.flush();
233 EasyMock.expectLastCall().atLeastOnce();
234 EasyMock.replay(sw);
235
236 List<OFMessage> messages = new ArrayList<OFMessage>();
237
238 for (int j = 0; j < NUM_MSG; ++j) {
239 OFMessage msg = EasyMock.createMock(OFMessage.class);
240 EasyMock.expect(msg.getXid()).andReturn(j).anyTimes();
241 EasyMock.expect(msg.getLength()).andReturn((short) 100).anyTimes();
242 EasyMock.replay(msg);
243 messages.add(msg);
244
245 try {
246 EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
247 .andReturn(true).once();
248 } catch (IOException e1) {
249 fail("Failed in OFMessageDamper#write()");
250 }
251 }
252 sw_map.put(sw, messages);
253 }
254
255 endInitMock();
256 initPusher(NUM_THREAD);
257
258 for (IOFSwitch sw : sw_map.keySet()) {
259 for (OFMessage msg : sw_map.get(sw)) {
260 boolean add_result = pusher.add(sw, msg);
261 assertTrue(add_result);
262 }
263 }
264
265 try {
266 // wait until message is processed.
267 Thread.sleep(1000);
268 } catch (InterruptedException e) {
269 fail("Failed in Thread.sleep()");
270 }
271
272 for (IOFSwitch sw : sw_map.keySet()) {
273 for (OFMessage msg : sw_map.get(sw)) {
274 EasyMock.verify(msg);
275 }
276
277 EasyMock.verify(sw);
278 }
279 verifyAll();
280
281 pusher.stop();
282 }
283
284 private long barrierTime = 0;
285
286 /**
287 * Test rate limitation of messages works correctly.
288 */
289 @Test
290 public void testRateLimitedAddMessage() {
291 final long LIMIT_RATE = 100; // [bytes/ms]
292 final int NUM_MSG = 1000;
293
294 // Accuracy of FlowPusher's rate calculation can't be measured by unit test
295 // because switch doesn't return BARRIER_REPLY.
296 // In unit test we use approximate way to measure rate. This value is
297 // acceptable margin of measured rate.
298 final double ACCEPTABLE_RATE = LIMIT_RATE * 1.2;
299
300 beginInitMock();
301
302 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
303 EasyMock.expect(sw.getId()).andReturn((long) 1).anyTimes();
304 sw.flush();
305 EasyMock.expectLastCall().atLeastOnce();
306 prepareBarrier(sw);
307 EasyMock.replay(sw);
308
309 List<OFMessage> messages = new ArrayList<OFMessage>();
310
311 for (int i = 0; i < NUM_MSG; ++i) {
312 OFMessage msg = EasyMock.createMock(OFMessage.class);
313 EasyMock.expect(msg.getXid()).andReturn(1).anyTimes();
314 EasyMock.expect(msg.getLength()).andReturn((short) 100).anyTimes();
315 EasyMock.expect(msg.getLengthU()).andReturn(100).anyTimes();
316 EasyMock.replay(msg);
317 messages.add(msg);
318
319 try {
320 EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
321 .andReturn(true).once();
322 } catch (IOException e) {
323 fail("Failed in OFMessageDamper#write()");
324 }
325 }
326
327 try {
328 EasyMock.expect(damper.write(EasyMock.eq(sw), (OFMessage) EasyMock.anyObject(), EasyMock.eq(context)))
329 .andAnswer(new IAnswer<Boolean>() {
330 @Override
331 public Boolean answer() throws Throwable {
332 OFMessage msg = (OFMessage) EasyMock.getCurrentArguments()[1];
333 if (msg.getType() == OFType.BARRIER_REQUEST) {
334 barrierTime = System.currentTimeMillis();
335 }
336 return true;
337 }
338 }).once();
339 } catch (IOException e1) {
340 fail("Failed in OFMessageDamper#write()");
341 }
342
343 endInitMock();
344 initPusher(1);
345
346 pusher.createQueue(sw);
347 pusher.setRate(sw, LIMIT_RATE);
348
349 long beginTime = System.currentTimeMillis();
350 for (OFMessage msg : messages) {
351 boolean add_result = pusher.add(sw, msg);
352 assertTrue(add_result);
353 }
354
355 pusher.barrierAsync(sw);
356
357 try {
358 do {
359 Thread.sleep(1000);
360 } while (barrierTime == 0);
361 } catch (InterruptedException e) {
362 fail("Failed to sleep");
363 }
364
365 double measured_rate = NUM_MSG * 100 / (barrierTime - beginTime);
366 assertTrue(measured_rate < ACCEPTABLE_RATE);
367
368 for (OFMessage msg : messages) {
369 EasyMock.verify(msg);
370 }
371 EasyMock.verify(sw);
372 verifyAll();
373
374 pusher.stop();
375 }
376
377 /**
378 * Test barrier message is correctly sent to a switch.
379 */
380 @Test
381 public void testBarrierMessage() {
382 beginInitMock();
383
384 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
385 EasyMock.expect(sw.getId()).andReturn((long) 1).anyTimes();
386 sw.flush();
387 EasyMock.expectLastCall().atLeastOnce();
388 prepareBarrier(sw);
389 EasyMock.replay(sw);
390
391 try {
392 EasyMock.expect(damper.write(EasyMock.eq(sw), (OFMessage) EasyMock.anyObject(), EasyMock.eq(context)))
393 .andReturn(true).once();
394 } catch (IOException e1) {
395 fail("Failed in OFMessageDamper#write()");
396 }
397
398 endInitMock();
399 initPusher(1);
400
401 OFBarrierReplyFuture future = pusher.barrierAsync(sw);
402
403 assertNotNull(future);
404
405 try {
406 Thread.sleep(1000);
407 } catch (InterruptedException e) {
408 fail("Failed to sleep");
409 }
410
411 verifyAll();
412
413 pusher.stop();
414 }
415
416 static final int XID_TO_VERIFY = 100;
417 static final long DPID_TO_VERIFY = 10;
418
419 /**
420 * Test FlowObject is correctly converted to message and is sent to a switch.
421 */
422 @SuppressWarnings("unchecked")
423 @Test
424 public void testAddFlow() {
425 // instantiate required objects
426 FlowEntry flowEntry1 = new FlowEntry();
427 flowEntry1.setDpid(new Dpid(DPID_TO_VERIFY));
428 flowEntry1.setFlowId(new FlowId(1));
429 flowEntry1.setInPort(new Port((short) 1));
430 flowEntry1.setOutPort(new Port((short) 11));
431 flowEntry1.setFlowEntryId(new FlowEntryId(1));
432 flowEntry1.setFlowEntryMatch(new FlowEntryMatch());
433 flowEntry1.setFlowEntryActions(new FlowEntryActions());
434 flowEntry1.setFlowEntryErrorState(new FlowEntryErrorState());
435 flowEntry1.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
436
437 beginInitMock();
438
439 OFFlowMod msg = EasyMock.createMock(OFFlowMod.class);
440 EasyMock.expect(msg.setIdleTimeout(EasyMock.anyShort())).andReturn(msg);
441 EasyMock.expect(msg.setHardTimeout(EasyMock.anyShort())).andReturn(msg);
442 EasyMock.expect(msg.setPriority(EasyMock.anyShort())).andReturn(msg);
443 EasyMock.expect(msg.setBufferId(EasyMock.anyInt())).andReturn(msg);
444 EasyMock.expect(msg.setCookie(EasyMock.anyLong())).andReturn(msg);
445 EasyMock.expect(msg.setCommand(EasyMock.anyShort())).andReturn(msg);
446 EasyMock.expect(msg.setMatch(EasyMock.anyObject(OFMatch.class))).andReturn(msg);
447 EasyMock.expect(msg.setActions((List<OFAction>) EasyMock.anyObject())).andReturn(msg);
448 EasyMock.expect(msg.setLengthU(EasyMock.anyShort())).andReturn(msg);
449 EasyMock.expect(msg.setOutPort(EasyMock.anyShort())).andReturn(msg).atLeastOnce();
450 EasyMock.expect(msg.getXid()).andReturn(XID_TO_VERIFY).anyTimes();
451 EasyMock.expect(msg.getType()).andReturn(OFType.FLOW_MOD).anyTimes();
452 EasyMock.expect(msg.getLength()).andReturn((short) 100).anyTimes();
453 EasyMock.replay(msg);
454
455 EasyMock.expect(factory.getMessage(EasyMock.eq(OFType.FLOW_MOD))).andReturn(msg);
456
457 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
458 EasyMock.expect(sw.getId()).andReturn(DPID_TO_VERIFY).anyTimes();
459 EasyMock.expect(sw.getStringId()).andReturn("1").anyTimes();
460 sw.flush();
461 EasyMock.expectLastCall().once();
462
463 try {
464 EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.anyObject(OFMessage.class), EasyMock.eq(context)))
465 .andAnswer(new IAnswer<Boolean>() {
466 @Override
467 public Boolean answer() throws Throwable {
468 OFMessage msg = (OFMessage) EasyMock.getCurrentArguments()[1];
469 if (msg.getType() == OFType.FLOW_MOD) {
470 assertEquals(msg.getXid(), XID_TO_VERIFY);
471 }
472 return true;
473 }
474 }).atLeastOnce();
475 } catch (IOException e1) {
476 fail("Failed in OFMessageDamper#write()");
477 }
478
479 EasyMock.replay(sw);
480
481 endInitMock();
482 initPusher(1);
483
484 pusher.pushFlowEntry(sw, flowEntry1);
485
486 try {
487 Thread.sleep(1000);
488 } catch (InterruptedException e) {
489 fail("Failed to sleep");
490 }
491
492 EasyMock.verify(sw);
493 verifyAll();
494
495 pusher.stop();
496 }
497
498 private void beginInitMock() {
499 context = EasyMock.createMock(FloodlightContext.class);
500 modContext = EasyMock.createMock(FloodlightModuleContext.class);
501 factory = EasyMock.createMock(BasicFactory.class);
502 damper = EasyMock.createMock(OFMessageDamper.class);
503 flProviderService = EasyMock.createMock(IFloodlightProviderService.class);
504 threadPoolService = EasyMock.createMock(IThreadPoolService.class);
505
506 EasyMock.expect(modContext.getServiceImpl(EasyMock.eq(IThreadPoolService.class)))
507 .andReturn(threadPoolService).once();
508 EasyMock.expect(modContext.getServiceImpl(EasyMock.eq(IFloodlightProviderService.class)))
509 .andReturn(flProviderService).once();
510 flProviderService.addOFMessageListener(EasyMock.eq(OFType.BARRIER_REPLY),
511 (FlowPusher) EasyMock.anyObject());
512 EasyMock.expectLastCall().once();
513
514 ScheduledExecutorService executor = EasyMock.createMock(ScheduledExecutorService.class);
515 EasyMock.expect(executor.schedule((Runnable) EasyMock.anyObject(), EasyMock.anyLong(),
516 (TimeUnit) EasyMock.anyObject())).andReturn(null).once();
517 EasyMock.replay(executor);
518 EasyMock.expect(threadPoolService.getScheduledExecutor()).andReturn(executor).anyTimes();
519 }
520
521 private void endInitMock() {
522 EasyMock.replay(threadPoolService);
523 EasyMock.replay(flProviderService);
524 EasyMock.replay(damper);
525 EasyMock.replay(factory);
526 EasyMock.replay(modContext);
527 EasyMock.replay(context);
528 }
529
530 private void verifyAll() {
531 EasyMock.verify(threadPoolService);
532 EasyMock.verify(flProviderService);
533 EasyMock.verify(damper);
534 EasyMock.verify(factory);
535 EasyMock.verify(modContext);
536 EasyMock.verify(context);
537 }
538
539 private void initPusher(int num_thread) {
540 pusher = new FlowPusher(num_thread);
541 pusher.init(context, modContext, factory, damper);
542 pusher.start();
543 }
544
545 private void prepareBarrier(IOFSwitch sw) {
546 OFBarrierRequest req = EasyMock.createMock(OFBarrierRequest.class);
547 req.setXid(EasyMock.anyInt());
548 EasyMock.expectLastCall().once();
549 EasyMock.expect(req.getXid()).andReturn(1).anyTimes();
550 EasyMock.expect(req.getType()).andReturn(OFType.BARRIER_REQUEST).anyTimes();
551 EasyMock.expect(req.getLength()).andReturn((short) 100).anyTimes();
552 EasyMock.replay(req);
553 EasyMock.expect(factory.getMessage(EasyMock.eq(OFType.BARRIER_REQUEST))).andReturn(req).anyTimes();
554 EasyMock.expect(sw.getNextTransactionId()).andReturn(1);
555 }
556
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800557}