blob: 4c6636798512add04b92c28a7c260912aeb94f17 [file] [log] [blame]
Naoki Shiota75b7dd62013-12-03 18:09:21 -08001package net.onrc.onos.ofcontroller.flowprogrammer;
2
3import static org.junit.Assert.*;
4import static org.powermock.api.easymock.PowerMock.createMock;
5
6import java.io.IOException;
7import java.util.ArrayList;
8import 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;
20import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
21import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
22import net.onrc.onos.ofcontroller.util.CallerId;
23import net.onrc.onos.ofcontroller.util.DataPath;
24import net.onrc.onos.ofcontroller.util.Dpid;
25import net.onrc.onos.ofcontroller.util.FlowEntry;
26import net.onrc.onos.ofcontroller.util.FlowEntryAction;
27import net.onrc.onos.ofcontroller.util.FlowEntryActions;
28import net.onrc.onos.ofcontroller.util.FlowEntryErrorState;
29import net.onrc.onos.ofcontroller.util.FlowEntryId;
30import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
31import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
32import net.onrc.onos.ofcontroller.util.FlowId;
33import net.onrc.onos.ofcontroller.util.FlowPath;
34import net.onrc.onos.ofcontroller.util.FlowPathFlags;
35import net.onrc.onos.ofcontroller.util.FlowPathType;
36import net.onrc.onos.ofcontroller.util.FlowPathUserState;
37import net.onrc.onos.ofcontroller.util.Port;
38import net.onrc.onos.ofcontroller.util.SwitchPort;
39
40import org.easymock.EasyMock;
41import org.easymock.IAnswer;
42import org.junit.Ignore;
43import org.junit.Test;
44import org.openflow.protocol.OFBarrierRequest;
45import org.openflow.protocol.OFFlowMod;
46import org.openflow.protocol.OFMatch;
47import org.openflow.protocol.OFMessage;
48import org.openflow.protocol.OFType;
49import org.openflow.protocol.action.OFAction;
50import org.openflow.protocol.factory.BasicFactory;
51
52public class FlowPusherTest {
53 private FlowPusher pusher;
54 private FloodlightContext context;
55 private FloodlightModuleContext modContext;
56 private BasicFactory factory;
57 private OFMessageDamper damper;
58 private IFloodlightProviderService flservice;
59 private IThreadPoolService tpservice;
60
61 /**
62 * Test single OFMessage is correctly sent to single switch via MessageDamper.
63 */
64 @Test
65 public void testAddMessage() {
66 beginInitMock();
67
68 OFMessage msg = EasyMock.createMock(OFMessage.class);
69 EasyMock.expect(msg.getXid()).andReturn(1).anyTimes();
70 EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
71 EasyMock.replay(msg);
72
73 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
74 EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
75 sw.flush();
76 EasyMock.expectLastCall().once();
77 EasyMock.replay(sw);
78
79 try {
80 EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context))).andReturn(true).once();
81 } catch (IOException e1) {
82 fail("Failed in OFMessageDamper#write()");
83 }
84
85 endInitMock();
86 initPusher(1);
87
88 boolean add_result = pusher.add(sw, msg);
89 assertTrue(add_result);
90
91 try {
92 // wait until message is processed.
93 Thread.sleep(1000);
94 } catch (InterruptedException e) {
95 fail("Failed in Thread.sleep()");
96 }
97
98 EasyMock.verify(msg);
99 EasyMock.verify(sw);
100
101 pusher.stop();
102 }
103
104 /**
105 * Test bunch of OFMessages are correctly sent to single switch via MessageDamper.
106 */
107 @Test
108 public void testMassiveAddMessage() {
109 final int NUM_MSG = 10000;
110
111 beginInitMock();
112
113 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
114 EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
115 sw.flush();
116 EasyMock.expectLastCall().atLeastOnce();
117 EasyMock.replay(sw);
118
119 List<OFMessage> messages = new ArrayList<OFMessage>();
120
121 for (int i = 0; i < NUM_MSG; ++i) {
122 OFMessage msg = EasyMock.createMock(OFMessage.class);
123 EasyMock.expect(msg.getXid()).andReturn(i).anyTimes();
124 EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
125 EasyMock.replay(msg);
126 messages.add(msg);
127
128 try {
129 EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
130 .andReturn(true).once();
131 } catch (IOException e1) {
132 fail("Failed in OFMessageDamper#write()");
133 }
134 }
135
136 endInitMock();
137 initPusher(1);
138
139 for (OFMessage msg : messages) {
140 boolean add_result = pusher.add(sw, msg);
141 assertTrue(add_result);
142 }
143
144 try {
145 // wait until message is processed.
146 Thread.sleep(1000);
147 } catch (InterruptedException e) {
148 fail("Failed in Thread.sleep()");
149 }
150
151 for (OFMessage msg : messages) {
152 EasyMock.verify(msg);
153 }
154 EasyMock.verify(sw);
155
156 pusher.stop();
157 }
158
159 /**
160 * Test bunch of OFMessages are correctly sent to multiple switches with single threads.
161 */
162 @Test
163 public void testMultiSwitchAddMessage() {
164 final int NUM_SWITCH = 10;
165 final int NUM_MSG = 100; // messages per thread
166
167 beginInitMock();
168
169 Map<IOFSwitch, List<OFMessage>> sw_map = new HashMap<IOFSwitch, List<OFMessage>>();
170 for (int i = 0; i < NUM_SWITCH; ++i) {
171 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
172 EasyMock.expect(sw.getId()).andReturn((long)i).anyTimes();
173 sw.flush();
174 EasyMock.expectLastCall().atLeastOnce();
175 EasyMock.replay(sw);
176
177 List<OFMessage> messages = new ArrayList<OFMessage>();
178
179 for (int j = 0; j < NUM_MSG; ++j) {
180 OFMessage msg = EasyMock.createMock(OFMessage.class);
181 EasyMock.expect(msg.getXid()).andReturn(j).anyTimes();
182 EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
183 EasyMock.replay(msg);
184 messages.add(msg);
185
186 try {
187 EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
188 .andReturn(true).once();
189 } catch (IOException e1) {
190 fail("Failed in OFMessageDamper#write()");
191 }
192 }
193 sw_map.put(sw, messages);
194 }
195
196 endInitMock();
197 initPusher(1);
198
199 for (IOFSwitch sw : sw_map.keySet()) {
200 for (OFMessage msg : sw_map.get(sw)) {
201 boolean add_result = pusher.add(sw, msg);
202 assertTrue(add_result);
203 }
204 }
205
206 try {
207 // wait until message is processed.
208 Thread.sleep(1000);
209 } catch (InterruptedException e) {
210 fail("Failed in Thread.sleep()");
211 }
212
213 for (IOFSwitch sw : sw_map.keySet()) {
214 for (OFMessage msg : sw_map.get(sw)) {
215 EasyMock.verify(msg);
216 }
217
218 EasyMock.verify(sw);
219 }
220
221 pusher.stop();
222 }
223
224 /**
225 * Test bunch of OFMessages are correctly sent to multiple switches using multiple threads.
226 */
227 @Test
228 public void testMultiThreadedAddMessage() {
229 final int NUM_THREAD = 10;
230 final int NUM_MSG = 100; // messages per thread
231
232 beginInitMock();
233
234 Map<IOFSwitch, List<OFMessage>> sw_map = new HashMap<IOFSwitch, List<OFMessage>>();
235 for (int i = 0; i < NUM_THREAD; ++i) {
236 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
237 EasyMock.expect(sw.getId()).andReturn((long)i).anyTimes();
238 sw.flush();
239 EasyMock.expectLastCall().atLeastOnce();
240 EasyMock.replay(sw);
241
242 List<OFMessage> messages = new ArrayList<OFMessage>();
243
244 for (int j = 0; j < NUM_MSG; ++j) {
245 OFMessage msg = EasyMock.createMock(OFMessage.class);
246 EasyMock.expect(msg.getXid()).andReturn(j).anyTimes();
247 EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
248 EasyMock.replay(msg);
249 messages.add(msg);
250
251 try {
252 EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
253 .andReturn(true).once();
254 } catch (IOException e1) {
255 fail("Failed in OFMessageDamper#write()");
256 }
257 }
258 sw_map.put(sw, messages);
259 }
260
261 endInitMock();
262 initPusher(NUM_THREAD);
263
264 for (IOFSwitch sw : sw_map.keySet()) {
265 for (OFMessage msg : sw_map.get(sw)) {
266 boolean add_result = pusher.add(sw, msg);
267 assertTrue(add_result);
268 }
269 }
270
271 try {
272 // wait until message is processed.
273 Thread.sleep(1000);
274 } catch (InterruptedException e) {
275 fail("Failed in Thread.sleep()");
276 }
277
278 for (IOFSwitch sw : sw_map.keySet()) {
279 for (OFMessage msg : sw_map.get(sw)) {
280 EasyMock.verify(msg);
281 }
282
283 EasyMock.verify(sw);
284 }
285
286 pusher.stop();
287 }
288
289 private long barrierTime = 0;
290 /**
291 * Test rate limitation of messages works correctly.
292 */
293 @Test
294 public void testRateLimitedAddMessage() {
295 final long LIMIT_RATE = 100; // [bytes/ms]
296 final int NUM_MSG = 1000;
297
298 // Accuracy of FlowPusher's rate calculation can't be measured by unit test
299 // because switch doesn't return BARRIER_REPLY.
300 // In unit test we use approximate way to measure rate. This value is
301 // acceptable margin of measured rate.
302 final double ACCEPTABLE_RATE = LIMIT_RATE * 1.2;
303
304 beginInitMock();
305
306 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
307 EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
308 sw.flush();
309 EasyMock.expectLastCall().atLeastOnce();
310 prepareBarrier(sw);
311 EasyMock.replay(sw);
312
313 List<OFMessage> messages = new ArrayList<OFMessage>();
314
315 for (int i = 0; i < NUM_MSG; ++i) {
316 OFMessage msg = EasyMock.createMock(OFMessage.class);
317 EasyMock.expect(msg.getXid()).andReturn(1).anyTimes();
318 EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
319 EasyMock.expect(msg.getLengthU()).andReturn(100).anyTimes();
320 EasyMock.replay(msg);
321 messages.add(msg);
322
323 try {
324 EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
325 .andReturn(true).once();
326 } catch (IOException e) {
327 fail("Failed in OFMessageDamper#write()");
328 }
329 }
330
331 try {
332 EasyMock.expect(damper.write(EasyMock.eq(sw), (OFMessage)EasyMock.anyObject(), EasyMock.eq(context)))
333 .andAnswer(new IAnswer<Boolean>() {
334 @Override
335 public Boolean answer() throws Throwable {
336 OFMessage msg = (OFMessage)EasyMock.getCurrentArguments()[1];
337 if (msg.getType() == OFType.BARRIER_REQUEST) {
338 barrierTime = System.currentTimeMillis();
339 }
340 return true;
341 }
342 }).once();
343 } catch (IOException e1) {
344 fail("Failed in OFMessageDamper#write()");
345 }
346
347 endInitMock();
348 initPusher(1);
349
350 pusher.createQueue(sw);
351 pusher.setRate(sw, LIMIT_RATE);
352
353 long beginTime = System.currentTimeMillis();
354 for (OFMessage msg : messages) {
355 boolean add_result = pusher.add(sw, msg);
356 assertTrue(add_result);
357 }
358
359 pusher.barrierAsync(sw);
360
361 try {
362 do {
363 Thread.sleep(1000);
364 } while (barrierTime == 0);
365 } catch (InterruptedException e) {
366 fail("Failed to sleep");
367 }
368
369 double measured_rate = NUM_MSG * 100 / (barrierTime - beginTime);
370 assertTrue(measured_rate < ACCEPTABLE_RATE);
371
372 for (OFMessage msg : messages) {
373 EasyMock.verify(msg);
374 }
375 EasyMock.verify(sw);
376
377 pusher.stop();
378 }
379
380 /**
381 * Test barrier message is correctly sent to a switch.
382 */
383 @Test
384 public void testBarrierMessage() {
385 beginInitMock();
386
387 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
388 EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
389 sw.flush();
390 EasyMock.expectLastCall().atLeastOnce();
391 prepareBarrier(sw);
392 EasyMock.replay(sw);
393
394 try {
395 EasyMock.expect(damper.write(EasyMock.eq(sw), (OFMessage)EasyMock.anyObject(), EasyMock.eq(context)))
396 .andReturn(true).once();
397 } catch (IOException e1) {
398 fail("Failed in OFMessageDamper#write()");
399 }
400
401 endInitMock();
402 initPusher(1);
403
404 OFBarrierReplyFuture future = pusher.barrierAsync(sw);
405
406 assertNotNull(future);
407 pusher.stop();
408 }
409
410 /**
411 * Test FlowObject is correctly converted to message and is sent to a switch.
412 */
413 @SuppressWarnings("unchecked")
414 @Test
415 public void testAddFlow() {
416 // Code below are copied from FlowManagerTest
417
418 // instantiate required objects
419 FlowEntry flowEntry1 = new FlowEntry();
420 flowEntry1.setDpid(new Dpid(1));
421 flowEntry1.setFlowId(new FlowId(1));
422 flowEntry1.setInPort(new Port((short) 1));
423 flowEntry1.setOutPort(new Port((short) 11));
424 flowEntry1.setFlowEntryId(new FlowEntryId(1));
425 flowEntry1.setFlowEntryMatch(new FlowEntryMatch());
426 flowEntry1.setFlowEntryActions(new FlowEntryActions());
427 flowEntry1.setFlowEntryErrorState(new FlowEntryErrorState());
428 flowEntry1.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
429
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800430 beginInitMock();
431
432 OFFlowMod msg = EasyMock.createMock(OFFlowMod.class);
433 EasyMock.expect(msg.setIdleTimeout(EasyMock.anyShort())).andReturn(msg);
434 EasyMock.expect(msg.setHardTimeout(EasyMock.anyShort())).andReturn(msg);
435 EasyMock.expect(msg.setPriority(EasyMock.anyShort())).andReturn(msg);
436 EasyMock.expect(msg.setBufferId(EasyMock.anyInt())).andReturn(msg);
437 EasyMock.expect(msg.setCookie(EasyMock.anyLong())).andReturn(msg);
438 EasyMock.expect(msg.setCommand(EasyMock.anyShort())).andReturn(msg);
439 EasyMock.expect(msg.setMatch(EasyMock.anyObject(OFMatch.class))).andReturn(msg);
440 EasyMock.expect(msg.setActions((List<OFAction>)EasyMock.anyObject())).andReturn(msg);
441 EasyMock.expect(msg.setLengthU(EasyMock.anyShort())).andReturn(msg);
442 EasyMock.expect(msg.setOutPort(EasyMock.anyShort())).andReturn(msg).atLeastOnce();
443 EasyMock.expect(msg.getXid()).andReturn(1).anyTimes();
444 EasyMock.expect(msg.getType()).andReturn(OFType.FLOW_MOD).anyTimes();
445 EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
446 EasyMock.replay(msg);
447
448 EasyMock.expect(factory.getMessage(EasyMock.eq(OFType.FLOW_MOD))).andReturn(msg);
449
450 ScheduledExecutorService executor = EasyMock.createMock(ScheduledExecutorService.class);
451 EasyMock.expect(executor.schedule((Runnable)EasyMock.anyObject(), EasyMock.anyLong(),
452 (TimeUnit)EasyMock.anyObject())).andReturn(null).once();
453 EasyMock.replay(executor);
454 EasyMock.expect(tpservice.getScheduledExecutor()).andReturn(executor);
455
456 IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
457 EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
458 EasyMock.expect(sw.getStringId()).andReturn("1").anyTimes();
459 sw.flush();
460 EasyMock.expectLastCall().once();
461 EasyMock.replay(sw);
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 assertEquals(msg.getType(), OFType.FLOW_MOD);
470 return true;
471 }
472 }).once();
473 } catch (IOException e1) {
474 fail("Failed in OFMessageDamper#write()");
475 }
476
477 endInitMock();
478 initPusher(1);
479
Naoki Shiota9f9d6232013-12-03 18:21:50 -0800480 pusher.add(sw, flowEntry1);
Naoki Shiota75b7dd62013-12-03 18:09:21 -0800481
482 try {
483 Thread.sleep(1000);
484 } catch (InterruptedException e) {
485 fail("Failed to sleep");
486 }
487
488 EasyMock.verify(sw);
489
490 pusher.stop();
491 }
492
493 private void beginInitMock() {
494 context = EasyMock.createMock(FloodlightContext.class);
495 modContext = EasyMock.createMock(FloodlightModuleContext.class);
496 factory = EasyMock.createMock(BasicFactory.class);
497 damper = EasyMock.createMock(OFMessageDamper.class);
498 flservice = EasyMock.createMock(IFloodlightProviderService.class);
499 tpservice = EasyMock.createMock(IThreadPoolService.class);
500
501 EasyMock.expect(modContext.getServiceImpl(EasyMock.eq(IThreadPoolService.class)))
502 .andReturn(tpservice).once();
503 EasyMock.expect(modContext.getServiceImpl(EasyMock.eq(IFloodlightProviderService.class)))
504 .andReturn(flservice).once();
505 flservice.addOFMessageListener(EasyMock.eq(OFType.BARRIER_REPLY),
506 (FlowPusher) EasyMock.anyObject());
507 EasyMock.expectLastCall().once();
508 }
509
510 private void endInitMock() {
511 EasyMock.replay(tpservice);
512 EasyMock.replay(flservice);
513 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);
539 EasyMock.expect(tpservice.getScheduledExecutor()).andReturn(executor);
540
541 EasyMock.expect(sw.getNextTransactionId()).andReturn(1);
542 }
543
544 // Copied from FlowManagerTest
545 private IFlowPath createIFlowPathMock(long flowId, String installerID,
546 String flowPathType, String flowPathUserState,
547 long flowPathFlags, long srcDpid, int srcPort,
548 long dstDpid, int dstPort) {
549 IFlowPath iFlowPath = EasyMock.createNiceMock(IFlowPath.class);
550 EasyMock.expect(iFlowPath.getFlowId()).andReturn(new FlowId(flowId).toString()).anyTimes();
551 EasyMock.expect(iFlowPath.getInstallerId()).andReturn(installerID).anyTimes();
552 EasyMock.expect(iFlowPath.getFlowPathType()).andReturn(flowPathType).anyTimes();
553 EasyMock.expect(iFlowPath.getFlowPathUserState()).andReturn(flowPathUserState).anyTimes();
554 EasyMock.expect(iFlowPath.getFlowPathFlags()).andReturn(new Long(flowPathFlags)).anyTimes();
555 EasyMock.expect(iFlowPath.getSrcSwitch()).andReturn(new Dpid(srcDpid).toString()).anyTimes();
556 EasyMock.expect(iFlowPath.getSrcPort()).andReturn(new Short((short)srcPort)).anyTimes();
557 EasyMock.expect(iFlowPath.getDstSwitch()).andReturn(new Dpid(dstDpid).toString()).anyTimes();
558 EasyMock.expect(iFlowPath.getDstPort()).andReturn(new Short((short)dstPort)).anyTimes();
559 return iFlowPath;
560 }
561
562}