blob: 4779b756662491e785bdcef0c170d4084edd03fe [file] [log] [blame]
Naoki Shiota75b7dd62013-12-03 18:09:21 -08001package net.onrc.onos.ofcontroller.flowprogrammer;
2
3import static org.junit.Assert.*;
Naoki Shiota75b7dd62013-12-03 18:09:21 -08004
5import java.io.IOException;
6import java.util.ArrayList;
Pavlin Radoslavov35f040f2013-12-05 13:14:06 -08007import java.util.Collection;
Naoki Shiota75b7dd62013-12-03 18:09:21 -08008import java.util.HashMap;
9import java.util.List;
10import java.util.Map;
11import java.util.concurrent.ScheduledExecutorService;
12import java.util.concurrent.TimeUnit;
13
14import net.floodlightcontroller.core.FloodlightContext;
15import net.floodlightcontroller.core.IFloodlightProviderService;
16import net.floodlightcontroller.core.IOFSwitch;
17import net.floodlightcontroller.core.module.FloodlightModuleContext;
18import net.floodlightcontroller.threadpool.IThreadPoolService;
19import net.floodlightcontroller.util.OFMessageDamper;
Naoki Shiota71fff002013-12-04 15:20:09 -080020import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
Naoki Shiota75b7dd62013-12-03 18:09:21 -080021import net.onrc.onos.ofcontroller.util.Dpid;
22import net.onrc.onos.ofcontroller.util.FlowEntry;
Naoki Shiota75b7dd62013-12-03 18:09:21 -080023import net.onrc.onos.ofcontroller.util.FlowEntryActions;
24import net.onrc.onos.ofcontroller.util.FlowEntryErrorState;
25import net.onrc.onos.ofcontroller.util.FlowEntryId;
26import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
27import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
28import net.onrc.onos.ofcontroller.util.FlowId;
Naoki Shiota75b7dd62013-12-03 18:09:21 -080029import net.onrc.onos.ofcontroller.util.Port;
Naoki Shiota75b7dd62013-12-03 18:09:21 -080030
31import org.easymock.EasyMock;
32import org.easymock.IAnswer;
Naoki Shiota75b7dd62013-12-03 18:09:21 -080033import org.junit.Test;
34import org.openflow.protocol.OFBarrierRequest;
35import org.openflow.protocol.OFFlowMod;
36import org.openflow.protocol.OFMatch;
37import org.openflow.protocol.OFMessage;
38import org.openflow.protocol.OFType;
39import org.openflow.protocol.action.OFAction;
40import org.openflow.protocol.factory.BasicFactory;
41
42public class FlowPusherTest {
43 private FlowPusher pusher;
44 private FloodlightContext context;
45 private FloodlightModuleContext modContext;
46 private BasicFactory factory;
47 private OFMessageDamper damper;
Naoki Shiota71fff002013-12-04 15:20:09 -080048 private IFloodlightProviderService flProviderService;
49 private IThreadPoolService threadPoolService;
50 private IFlowService flowService;
Naoki Shiota75b7dd62013-12-03 18:09:21 -080051
52 /**
53 * Test single OFMessage is correctly sent to single switch via MessageDamper.
54 */
55 @Test
56 public void testAddMessage() {
57 beginInitMock();
58
59 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);
63
64 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);
69
70 try {
Naoki Shiota71fff002013-12-04 15:20:09 -080071 EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
72 .andReturn(true).once();
Naoki Shiota75b7dd62013-12-03 18:09:21 -080073 } catch (IOException e1) {
74 fail("Failed in OFMessageDamper#write()");
75 }
76
77 endInitMock();
78 initPusher(1);
79
80 boolean add_result = pusher.add(sw, msg);
81 assertTrue(add_result);
82
83 try {
84 // wait until message is processed.
85 Thread.sleep(1000);
86 } catch (InterruptedException e) {
87 fail("Failed in Thread.sleep()");
88 }
89
90 EasyMock.verify(msg);
91 EasyMock.verify(sw);
92
93 pusher.stop();
94 }
95
96 /**
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;
102
103 beginInitMock();
104
105 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);
110
111 List<OFMessage> messages = new ArrayList<OFMessage>();
112
113 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);
119
120 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 }
127
128 endInitMock();
129 initPusher(1);
130
131 for (OFMessage msg : messages) {
132 boolean add_result = pusher.add(sw, msg);
133 assertTrue(add_result);
134 }
135
136 try {
137 // wait until message is processed.
138 Thread.sleep(1000);
139 } catch (InterruptedException e) {
140 fail("Failed in Thread.sleep()");
141 }
142
143 for (OFMessage msg : messages) {
144 EasyMock.verify(msg);
145 }
146 EasyMock.verify(sw);
147
148 pusher.stop();
149 }
150
151 /**
152 * Test bunch of OFMessages are correctly sent to multiple switches with single threads.
153 */
154 @Test
155 public void testMultiSwitchAddMessage() {
156 final int NUM_SWITCH = 10;
157 final int NUM_MSG = 100; // messages per thread
158
159 beginInitMock();
160
161 Map<IOFSwitch, List<OFMessage>> sw_map = new HashMap<IOFSwitch, List<OFMessage>>();
162 for (int i = 0; i < NUM_SWITCH; ++i) {
163 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
164 EasyMock.expect(sw.getId()).andReturn((long)i).anyTimes();
165 sw.flush();
166 EasyMock.expectLastCall().atLeastOnce();
167 EasyMock.replay(sw);
168
169 List<OFMessage> messages = new ArrayList<OFMessage>();
170
171 for (int j = 0; j < NUM_MSG; ++j) {
172 OFMessage msg = EasyMock.createMock(OFMessage.class);
173 EasyMock.expect(msg.getXid()).andReturn(j).anyTimes();
174 EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
175 EasyMock.replay(msg);
176 messages.add(msg);
177
178 try {
179 EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
180 .andReturn(true).once();
181 } catch (IOException e1) {
182 fail("Failed in OFMessageDamper#write()");
183 }
184 }
185 sw_map.put(sw, messages);
186 }
187
188 endInitMock();
189 initPusher(1);
190
191 for (IOFSwitch sw : sw_map.keySet()) {
192 for (OFMessage msg : sw_map.get(sw)) {
193 boolean add_result = pusher.add(sw, msg);
194 assertTrue(add_result);
195 }
196 }
197
198 try {
199 // wait until message is processed.
200 Thread.sleep(1000);
201 } catch (InterruptedException e) {
202 fail("Failed in Thread.sleep()");
203 }
204
205 for (IOFSwitch sw : sw_map.keySet()) {
206 for (OFMessage msg : sw_map.get(sw)) {
207 EasyMock.verify(msg);
208 }
209
210 EasyMock.verify(sw);
211 }
212
213 pusher.stop();
214 }
215
216 /**
217 * Test bunch of OFMessages are correctly sent to multiple switches using multiple threads.
218 */
219 @Test
220 public void testMultiThreadedAddMessage() {
221 final int NUM_THREAD = 10;
222 final int NUM_MSG = 100; // messages per thread
223
224 beginInitMock();
225
226 Map<IOFSwitch, List<OFMessage>> sw_map = new HashMap<IOFSwitch, List<OFMessage>>();
227 for (int i = 0; i < NUM_THREAD; ++i) {
228 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
229 EasyMock.expect(sw.getId()).andReturn((long)i).anyTimes();
230 sw.flush();
231 EasyMock.expectLastCall().atLeastOnce();
232 EasyMock.replay(sw);
233
234 List<OFMessage> messages = new ArrayList<OFMessage>();
235
236 for (int j = 0; j < NUM_MSG; ++j) {
237 OFMessage msg = EasyMock.createMock(OFMessage.class);
238 EasyMock.expect(msg.getXid()).andReturn(j).anyTimes();
239 EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
240 EasyMock.replay(msg);
241 messages.add(msg);
242
243 try {
244 EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
245 .andReturn(true).once();
246 } catch (IOException e1) {
247 fail("Failed in OFMessageDamper#write()");
248 }
249 }
250 sw_map.put(sw, messages);
251 }
252
253 endInitMock();
254 initPusher(NUM_THREAD);
255
256 for (IOFSwitch sw : sw_map.keySet()) {
257 for (OFMessage msg : sw_map.get(sw)) {
258 boolean add_result = pusher.add(sw, msg);
259 assertTrue(add_result);
260 }
261 }
262
263 try {
264 // wait until message is processed.
265 Thread.sleep(1000);
266 } catch (InterruptedException e) {
267 fail("Failed in Thread.sleep()");
268 }
269
270 for (IOFSwitch sw : sw_map.keySet()) {
271 for (OFMessage msg : sw_map.get(sw)) {
272 EasyMock.verify(msg);
273 }
274
275 EasyMock.verify(sw);
276 }
277
278 pusher.stop();
279 }
280
281 private long barrierTime = 0;
282 /**
283 * Test rate limitation of messages works correctly.
284 */
285 @Test
286 public void testRateLimitedAddMessage() {
287 final long LIMIT_RATE = 100; // [bytes/ms]
288 final int NUM_MSG = 1000;
289
290 // Accuracy of FlowPusher's rate calculation can't be measured by unit test
291 // because switch doesn't return BARRIER_REPLY.
292 // In unit test we use approximate way to measure rate. This value is
293 // acceptable margin of measured rate.
294 final double ACCEPTABLE_RATE = LIMIT_RATE * 1.2;
295
296 beginInitMock();
297
298 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
299 EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
300 sw.flush();
301 EasyMock.expectLastCall().atLeastOnce();
302 prepareBarrier(sw);
303 EasyMock.replay(sw);
304
305 List<OFMessage> messages = new ArrayList<OFMessage>();
306
307 for (int i = 0; i < NUM_MSG; ++i) {
308 OFMessage msg = EasyMock.createMock(OFMessage.class);
309 EasyMock.expect(msg.getXid()).andReturn(1).anyTimes();
310 EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
311 EasyMock.expect(msg.getLengthU()).andReturn(100).anyTimes();
312 EasyMock.replay(msg);
313 messages.add(msg);
314
315 try {
316 EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
317 .andReturn(true).once();
318 } catch (IOException e) {
319 fail("Failed in OFMessageDamper#write()");
320 }
321 }
322
323 try {
324 EasyMock.expect(damper.write(EasyMock.eq(sw), (OFMessage)EasyMock.anyObject(), EasyMock.eq(context)))
325 .andAnswer(new IAnswer<Boolean>() {
326 @Override
327 public Boolean answer() throws Throwable {
328 OFMessage msg = (OFMessage)EasyMock.getCurrentArguments()[1];
329 if (msg.getType() == OFType.BARRIER_REQUEST) {
330 barrierTime = System.currentTimeMillis();
331 }
332 return true;
333 }
334 }).once();
335 } catch (IOException e1) {
336 fail("Failed in OFMessageDamper#write()");
337 }
338
339 endInitMock();
340 initPusher(1);
341
342 pusher.createQueue(sw);
343 pusher.setRate(sw, LIMIT_RATE);
344
345 long beginTime = System.currentTimeMillis();
346 for (OFMessage msg : messages) {
347 boolean add_result = pusher.add(sw, msg);
348 assertTrue(add_result);
349 }
350
351 pusher.barrierAsync(sw);
352
353 try {
354 do {
355 Thread.sleep(1000);
356 } while (barrierTime == 0);
357 } catch (InterruptedException e) {
358 fail("Failed to sleep");
359 }
360
361 double measured_rate = NUM_MSG * 100 / (barrierTime - beginTime);
362 assertTrue(measured_rate < ACCEPTABLE_RATE);
363
364 for (OFMessage msg : messages) {
365 EasyMock.verify(msg);
366 }
367 EasyMock.verify(sw);
368
369 pusher.stop();
370 }
371
372 /**
373 * Test barrier message is correctly sent to a switch.
374 */
375 @Test
376 public void testBarrierMessage() {
377 beginInitMock();
378
379 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
380 EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
381 sw.flush();
382 EasyMock.expectLastCall().atLeastOnce();
383 prepareBarrier(sw);
384 EasyMock.replay(sw);
385
386 try {
387 EasyMock.expect(damper.write(EasyMock.eq(sw), (OFMessage)EasyMock.anyObject(), EasyMock.eq(context)))
388 .andReturn(true).once();
389 } catch (IOException e1) {
390 fail("Failed in OFMessageDamper#write()");
391 }
392
393 endInitMock();
394 initPusher(1);
395
396 OFBarrierReplyFuture future = pusher.barrierAsync(sw);
397
398 assertNotNull(future);
399 pusher.stop();
400 }
401
402 /**
403 * Test FlowObject is correctly converted to message and is sent to a switch.
404 */
405 @SuppressWarnings("unchecked")
406 @Test
407 public void testAddFlow() {
408 // Code below are copied from FlowManagerTest
409
410 // instantiate required objects
411 FlowEntry flowEntry1 = new FlowEntry();
412 flowEntry1.setDpid(new Dpid(1));
413 flowEntry1.setFlowId(new FlowId(1));
414 flowEntry1.setInPort(new Port((short) 1));
415 flowEntry1.setOutPort(new Port((short) 11));
416 flowEntry1.setFlowEntryId(new FlowEntryId(1));
417 flowEntry1.setFlowEntryMatch(new FlowEntryMatch());
418 flowEntry1.setFlowEntryActions(new FlowEntryActions());
419 flowEntry1.setFlowEntryErrorState(new FlowEntryErrorState());
420 flowEntry1.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
421
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800422 beginInitMock();
423
424 OFFlowMod msg = EasyMock.createMock(OFFlowMod.class);
425 EasyMock.expect(msg.setIdleTimeout(EasyMock.anyShort())).andReturn(msg);
426 EasyMock.expect(msg.setHardTimeout(EasyMock.anyShort())).andReturn(msg);
427 EasyMock.expect(msg.setPriority(EasyMock.anyShort())).andReturn(msg);
428 EasyMock.expect(msg.setBufferId(EasyMock.anyInt())).andReturn(msg);
429 EasyMock.expect(msg.setCookie(EasyMock.anyLong())).andReturn(msg);
430 EasyMock.expect(msg.setCommand(EasyMock.anyShort())).andReturn(msg);
431 EasyMock.expect(msg.setMatch(EasyMock.anyObject(OFMatch.class))).andReturn(msg);
432 EasyMock.expect(msg.setActions((List<OFAction>)EasyMock.anyObject())).andReturn(msg);
433 EasyMock.expect(msg.setLengthU(EasyMock.anyShort())).andReturn(msg);
434 EasyMock.expect(msg.setOutPort(EasyMock.anyShort())).andReturn(msg).atLeastOnce();
435 EasyMock.expect(msg.getXid()).andReturn(1).anyTimes();
436 EasyMock.expect(msg.getType()).andReturn(OFType.FLOW_MOD).anyTimes();
437 EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
438 EasyMock.replay(msg);
439
440 EasyMock.expect(factory.getMessage(EasyMock.eq(OFType.FLOW_MOD))).andReturn(msg);
441
442 ScheduledExecutorService executor = EasyMock.createMock(ScheduledExecutorService.class);
443 EasyMock.expect(executor.schedule((Runnable)EasyMock.anyObject(), EasyMock.anyLong(),
444 (TimeUnit)EasyMock.anyObject())).andReturn(null).once();
445 EasyMock.replay(executor);
Naoki Shiota71fff002013-12-04 15:20:09 -0800446 EasyMock.expect(threadPoolService.getScheduledExecutor()).andReturn(executor);
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800447
448 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
449 EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
450 EasyMock.expect(sw.getStringId()).andReturn("1").anyTimes();
451 sw.flush();
452 EasyMock.expectLastCall().once();
453 EasyMock.replay(sw);
454
455 try {
456 EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.anyObject(OFMessage.class), EasyMock.eq(context)))
457 .andAnswer(new IAnswer<Boolean>() {
458 @Override
459 public Boolean answer() throws Throwable {
460 OFMessage msg = (OFMessage)EasyMock.getCurrentArguments()[1];
461 assertEquals(msg.getType(), OFType.FLOW_MOD);
462 return true;
463 }
464 }).once();
465 } catch (IOException e1) {
466 fail("Failed in OFMessageDamper#write()");
467 }
468
469 endInitMock();
470 initPusher(1);
471
Pavlin Radoslavov24a09152013-12-05 12:35:17 -0800472 pusher.pushFlowEntry(sw, flowEntry1);
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800473
474 try {
475 Thread.sleep(1000);
476 } catch (InterruptedException e) {
477 fail("Failed to sleep");
478 }
479
480 EasyMock.verify(sw);
481
482 pusher.stop();
483 }
484
Naoki Shiotae8e83e32013-12-05 13:27:15 -0800485 @SuppressWarnings("unchecked")
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800486 private void beginInitMock() {
487 context = EasyMock.createMock(FloodlightContext.class);
488 modContext = EasyMock.createMock(FloodlightModuleContext.class);
489 factory = EasyMock.createMock(BasicFactory.class);
490 damper = EasyMock.createMock(OFMessageDamper.class);
Naoki Shiota71fff002013-12-04 15:20:09 -0800491 flProviderService = EasyMock.createMock(IFloodlightProviderService.class);
492 threadPoolService = EasyMock.createMock(IThreadPoolService.class);
493 flowService = EasyMock.createMock(IFlowService.class);
494
Pavlin Radoslavov35f040f2013-12-05 13:14:06 -0800495 flowService.flowEntriesPushedToSwitch(EasyMock.anyObject(Collection.class));
Naoki Shiota71fff002013-12-04 15:20:09 -0800496 EasyMock.expectLastCall().anyTimes();
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800497
498 EasyMock.expect(modContext.getServiceImpl(EasyMock.eq(IThreadPoolService.class)))
Naoki Shiota71fff002013-12-04 15:20:09 -0800499 .andReturn(threadPoolService).once();
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800500 EasyMock.expect(modContext.getServiceImpl(EasyMock.eq(IFloodlightProviderService.class)))
Naoki Shiota71fff002013-12-04 15:20:09 -0800501 .andReturn(flProviderService).once();
502 EasyMock.expect(modContext.getServiceImpl(EasyMock.eq(IFlowService.class)))
503 .andReturn(flowService).once();
504 flProviderService.addOFMessageListener(EasyMock.eq(OFType.BARRIER_REPLY),
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800505 (FlowPusher) EasyMock.anyObject());
506 EasyMock.expectLastCall().once();
507 }
508
509 private void endInitMock() {
Naoki Shiota71fff002013-12-04 15:20:09 -0800510 EasyMock.replay(flowService);
511 EasyMock.replay(threadPoolService);
512 EasyMock.replay(flProviderService);
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800513 EasyMock.replay(damper);
514 EasyMock.replay(factory);
515 EasyMock.replay(modContext);
516 EasyMock.replay(context);
517 }
518
519 private void initPusher(int num_thread) {
520 pusher = new FlowPusher(num_thread);
521 pusher.init(context, modContext, factory, damper);
522 pusher.start();
523 }
524
525 private void prepareBarrier(IOFSwitch sw) {
526 OFBarrierRequest req = EasyMock.createMock(OFBarrierRequest.class);
527 req.setXid(EasyMock.anyInt());
528 EasyMock.expectLastCall().once();
529 EasyMock.expect(req.getXid()).andReturn(1).anyTimes();
530 EasyMock.expect(req.getType()).andReturn(OFType.BARRIER_REQUEST).anyTimes();
531 EasyMock.expect(req.getLength()).andReturn((short)100).anyTimes();
532 EasyMock.replay(req);
533 EasyMock.expect(factory.getMessage(EasyMock.eq(OFType.BARRIER_REQUEST))).andReturn(req);
534
535 ScheduledExecutorService executor = EasyMock.createMock(ScheduledExecutorService.class);
536 EasyMock.expect(executor.schedule((Runnable)EasyMock.anyObject(), EasyMock.anyLong(),
537 (TimeUnit)EasyMock.anyObject())).andReturn(null).once();
538 EasyMock.replay(executor);
Naoki Shiota71fff002013-12-04 15:20:09 -0800539 EasyMock.expect(threadPoolService.getScheduledExecutor()).andReturn(executor);
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800540
541 EasyMock.expect(sw.getNextTransactionId()).andReturn(1);
542 }
543
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800544}