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