blob: 158f78799187ea4f608daf56b217ecee19dda685 [file] [log] [blame]
ShreyaPandita9306c772012-09-28 12:21:40 -04001"""These tests fall under Conformance Test-Suite (OF-SWITCH-1.0.0 TestCases).
2 Refer Documentation -- Detailed testing methodology
3 <Some of test-cases are directly taken from oftest> """
4
5"Test Suite 3 --> Detailed Controller to switch messages"
6
7import logging
8
9import unittest
10import random
11
12import oftest.controller as controller
13import oftest.cstruct as ofp
14import oftest.message as message
15import oftest.dataplane as dataplane
16import oftest.action as action
17import oftest.parse as parse
18import basic
19
20from testutils import *
21from time import sleep
22from FuncUtils import *
23
24cs_port_map = None
25cs_logger = None
26cs_config = None
27
28def test_set_init(config):
29
30
31 basic.test_set_init(config)
32
33 global cs_port_map
34 global cs_logger
35 global cs_config
36
37 cs_logger = logging.getLogger("Detailed controller to switch messages")
38 cs_logger.info("Initializing test set")
39 cs_port_map = config["port_map"]
40 cs_config = config
41
42
43class OverlapChecking(basic.SimpleDataPlane):
44
45 """Verify that if overlap check flag is set in the flow entry and an overlapping flow is inserted then an error
46 is generated and switch refuses flow entry"""
47
48 def runTest(self):
49
50 cs_logger.info("Running Overlap_Checking test")
51
52 of_ports = cs_port_map.keys()
53 of_ports.sort()
54 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
55
56 #Clear Switch State
57 rc = delete_all_flows(self.controller, cs_logger)
58 self.assertEqual(rc, 0, "Failed to delete all flows")
59
60 cs_logger.info("Inserting two overlapping flows")
61 cs_logger.info("Expecting switch to return an error")
62
63 #Insert a flow F with wildcarded all fields
64 (pkt,match) = Wildcard_All(self,of_ports)
65
66 #Verify flow is active
67 Verify_TableStats(self,active_entries=1)
68
69 # Build a overlapping flow F'-- Wildcard All except ingress with check overlap bit set
70 Pkt_MatchIngress = simple_tcp_packet()
71 match3 = parse.packet_to_flow_match(Pkt_MatchIngress)
72 self.assertTrue(match3 is not None, "Could not generate flow match from pkt")
73 match3.wildcards = ofp.OFPFW_ALL-ofp.OFPFW_IN_PORT
74 match3.in_port = of_ports[0]
75
76 msg3 = message.flow_mod()
77 msg3.command = ofp.OFPFC_ADD
78 msg3.match = match3
79 msg3.flags |= ofp.OFPFF_CHECK_OVERLAP
80 msg3.cookie = random.randint(0,9007199254740992)
81 msg3.buffer_id = 0xffffffff
82
83 act3 = action.action_output()
84 act3.port = of_ports[1]
85 self.assertTrue(msg3.actions.add(act3), "could not add action")
86 rv = self.controller.message_send(msg3)
87 self.assertTrue(rv != -1, "Error installing flow mod")
88 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
89
90 # Verify Flow does not get inserted
91 Verify_TableStats(self,active_entries=1)
92
93 #Verify OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error is recieved on the control plane
94 (response, pkt) = self.controller.poll(exp_msg=ofp.OFPT_ERROR,
95 timeout=5)
96 self.assertTrue(response is not None,
97 'Switch did not reply with error message')
98 self.assertTrue(response.type==ofp.OFPET_FLOW_MOD_FAILED,
99 'Error message type is not flow mod failed ')
100 self.assertTrue(response.code==ofp.OFPFMFC_OVERLAP,
101 'Error Message code is not overlap')
102
103
104class NoOverlapChecking(basic.SimpleDataPlane):
105
106 """Verify that without overlap check flag set, overlapping flows can be created."""
107
108 def runTest(self):
109
110 cs_logger.info("Running No_Overlap_Checking test")
111
112 of_ports = cs_port_map.keys()
113 of_ports.sort()
114 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
115
116 #Clear Switch State
117 rc = delete_all_flows(self.controller, cs_logger)
118 self.assertEqual(rc, 0, "Failed to delete all flows")
119
120 cs_logger.info("Inserting two overlapping flows")
121 cs_logger.info("Expecting switch to insert the flows without generating errors")
122
123 #Build a flow F with wildcarded all fields.
124 (pkt,match) = Wildcard_All(self,of_ports)
125
126 #Verify flow is active
127 Verify_TableStats(self,active_entries=1)
128
129 # Build a overlapping flow F' without check overlap bit set.
130 Wildcard_All_Except_Ingress(self,of_ports)
131
132 # Verify Flow gets inserted
133 Verify_TableStats(self,active_entries=2)
134
135
136class IdenticalFlows(basic.SimpleDataPlane):
137
138 """Verify that adding two identical flows overwrites the existing one and clears counters"""
139
140 def runTest(self):
141
142 cs_logger.info("Running Identical_Flows test ")
143
144 of_ports = cs_port_map.keys()
145 of_ports.sort()
146 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
147
148 #Clear switch state
149 rc = delete_all_flows(self.controller, cs_logger)
150 self.assertEqual(rc, 0, "Failed to delete all flows")
151
152 cs_logger.info("Inserting two identical flows one by one")
153 cs_logger.info("Expecting switch to overwrite the first flow and clear the counters associated with it ")
154
155 # Create and add flow-1, check on dataplane it is active.
156 (pkt,match) = Wildcard_All(self,of_ports)
157
158 # Verify active_entries in table_stats_request =1
159 Verify_TableStats(self,active_entries=1)
160
161 # Send Packet (to increment counters like byte_count and packet_count)
162 SendPacket(self,pkt,of_ports[0],of_ports[1])
163
164 # Verify Flow counters have incremented
165 Verify_FlowStats(self,match,byte_count=len(str(pkt)),packet_count=1)
166
167 #Send Identical flow
168 (pkt1,match1) = Wildcard_All(self,of_ports)
169
170 # Verify active_entries in table_stats_request =1
171 Verify_TableStats(self,active_entries=1)
172
173 # Verify Flow counters reset
174 Verify_FlowStats(self,match,byte_count=0,packet_count=0)
175
176
177class EmerFlowTimeout(basic.SimpleProtocol):
178
179 """Timeout values are not allowed for emergency flows"""
180
181 def runTest(self):
182
183 cs_logger.info("Running Emergency_Flow_Timeout test")
184
185 of_ports = cs_port_map.keys()
186 of_ports.sort()
187 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
188
189 #Clear switch state
190 rc = delete_all_flows(self.controller, cs_logger)
191 self.assertEqual(rc, 0, "Failed to delete all flows")
192
193 cs_logger.info("Inserting an emergency flow with timeout values")
194 cs_logger.info("Expecting switch to generate error ")
195
196 #Insert an emergency flow
197 pkt = simple_tcp_packet()
198 match = parse.packet_to_flow_match(pkt)
199 match.in_port = of_ports[0]
200
201 request = message.flow_mod()
202 request.match = match
203 request.command = ofp.OFPFC_ADD
204 request.flags = request.flags|ofp.OFPFF_EMERG
205 request.hard_timeout =9
206 request.idle_timeout =9
207
208 act = action.action_output()
209 act.port = of_ports[1]
210
211 request.actions.add(act)
212 cs_logger.info("Inserting flow")
213 rv = self.controller.message_send(request)
214 self.assertTrue(rv != -1, "Flow addition did not fail.")
215
216 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
217
218 #Verify OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error is recieved on the control plane
219 (response, pkt) = self.controller.poll(exp_msg=ofp.OFPT_ERROR,
220 timeout=5)
221 self.assertTrue(response is not None,
222 'Switch did not reply with error message')
223 self.assertTrue(response.type==ofp.OFPET_FLOW_MOD_FAILED,
224 'Error message type is not flow mod failed ')
225 self.assertTrue(response.code==ofp.OFPFMFC_BAD_EMERG_TIMEOUT,
226 'Error Message code is not bad emergency timeout')
227
228
229class MissingModifyAdd(basic.SimpleDataPlane):
230
231 """If a modify does not match an existing flow, the flow gets added """
232
233 def runTest(self):
234
235 cs_logger.info("Running Missing_Modify_Add test")
236
237 of_ports = cs_port_map.keys()
238 of_ports.sort()
239 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
240
241 cs_logger.info("Inserting a flow-modify that does not match an existing flow")
242 cs_logger.info("Expecting flow to get added i.e OFPFC_MODIFY command should be taken as OFPFC_ADD ")
243
244 #Clear Switch State
245 rc = delete_all_flows(self.controller, cs_logger)
246 self.assertEqual(rc, 0, "Failed to delete all flows")
247
248 #Generate a flow-mod,command OFPC_MODIFY
249
250 request = message.flow_mod()
251 request.command = ofp.OFPFC_MODIFY
252 request.match.wildcards = ofp.OFPFW_ALL-ofp.OFPFW_IN_PORT
253 request.match.in_port = of_ports[0]
254 request.cookie = random.randint(0,9007199254740992)
255 request.buffer_id = 0xffffffff
256 act3 = action.action_output()
257 act3.port = of_ports[1]
258 self.assertTrue(request.actions.add(act3), "could not add action")
259
260 cs_logger.info("Inserting flow")
261 rv = self.controller.message_send(request)
262 self.assertTrue(rv != -1, "Error installing flow mod")
263 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
264
265 #Verify the flow gets added i.e. active_count= 1
266 Verify_TableStats(self,active_entries=1)
267
268
269class ModifyAction(basic.SimpleDataPlane):
270
271 """A modified flow preserves counters"""
272
273 def runTest(self):
274
275 cs_logger.info("Running Modify_Action test ")
276
277 of_ports = cs_port_map.keys()
278 of_ports.sort()
279 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
280
281 #Clear switch state
282 rc = delete_all_flows(self.controller, cs_logger)
283 self.assertEqual(rc, 0, "Failed to delete all flows")
284
285 cs_logger.info("Inserting a Flow and incrementing flow counters. Modifying the flow action")
286 cs_logger.info("Expecting the flow action to be modified , but the flow-counters should be preserved")
287
288 #Create and add flow-1 Match on all, except one wildcarded (src adddress).Action A , output to of_port[1]
289 (pkt,match) = Match_All_Except_Source_Address(self,of_ports)
290
291 #Send Packet matching the flow thus incrementing counters like packet_count,byte_count
292 SendPacket(self,pkt,of_ports[0],of_ports[1])
293
294 #Verify flow counters
295 Verify_FlowStats(self,match,byte_count=len(str(pkt)),packet_count=1)
296
297 #Modify flow- 1
298 Modify_Flow_Action(self,of_ports,match)
299
300 # Send Packet matching the flow-1 i.e ingress_port=port[0] and verify it is recieved on corret dataplane port i.e port[2]
301 SendPacket(self,pkt,of_ports[0],of_ports[2])
302
303 #Verify flow counters are preserved
304 Verify_FlowStats(self,match,byte_count=(2*len(str(pkt))),packet_count=2)
305
306
307class StrictModifyAction(basic.SimpleDataPlane):
308
309 """Strict Modify Flow also changes action preserves counters"""
310
311 def runTest(self):
312
313 cs_logger.info("Running Strict_Modify_Action test")
314
315 of_ports = cs_port_map.keys()
316 of_ports.sort()
317 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
318
319 #Clear switch state
320 rc = delete_all_flows(self.controller, cs_logger)
321 self.assertEqual(rc, 0, "Failed to delete all flows")
322
323 cs_logger.info("Inserting Flows and incrementing flow counters. Strict Modify the flow action ")
324 cs_logger.info("Expecting the flow action to be modified , but the flow-counters should be preserved")
325
326 #Create and add flow-1 Match on all, except one wildcarded (src adddress).Action A
327 (pkt,match) = Match_All_Except_Source_Address(self,of_ports,priority=100)
328
329 #Create and add flow-2 , Match on ingress_port only, Action A
330 (pkt1,match1) = Wildcard_All_Except_Ingress(self,of_ports,priority=10)
331
332 # Verify both the flows are active
333 Verify_TableStats(self,active_entries=2)
334
335 #Send a packet matching the flows, thus incrementing flow-counters (packet matches the flow F-1 with higher priority)
336 SendPacket(self,pkt,of_ports[0],of_ports[1])
337
338 # Verify flow counters of the flow-1
339 Verify_FlowStats(self,match,byte_count=len(str(pkt)),packet_count=1)
340
341 # Strict-Modify flow- 1
342 Strict_Modify_Flow_Action(self,of_ports[2],match,priority=100)
343
344 # Send Packet matching the flow-1 i.e ingress_port=port[0] and verify it is recieved on corret dataplane port i.e port[2]
345 SendPacket(self,pkt,of_ports[0],of_ports[2])
346
347 # Verify flow counters are preserved
348 Verify_FlowStats(self,match,byte_count=(2*len(str(pkt))),packet_count=2)
349
350
351class DeleteNonexistingFlow(basic.SimpleDataPlane):
352
353 """Request deletion of non-existing flow"""
354
355 def runTest(self):
356
357 cs_logger.info("Delete_NonExisting_Flow test begins")
358
359 of_ports = cs_port_map.keys()
360 of_ports.sort()
361 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
362
363 #Clear switch state
364 rc = delete_all_flows(self.controller, cs_logger)
365 self.assertEqual(rc, 0, "Failed to delete all flows")
366
367 cs_logger.info("Deleting a non-existing flow")
368 cs_logger.info("Expecting switch to ignore the command , without generating errors")
369
370 # Issue a delete command
371 msg = message.flow_mod()
372 msg.match.wildcards = ofp.OFPFW_ALL
373 msg.out_port = ofp.OFPP_NONE
374 msg.command = ofp.OFPFC_DELETE
375 msg.buffer_id = 0xffffffff
376
377 # Verify no message or error is generated by polling the the control plane
378 (response, pkt) = self.controller.poll(exp_msg=ofp.OFPT_ERROR,
379 timeout=2)
380 self.assertTrue(response is None,
381 'Recieved Error for deleting non-exiting flow ')
382
383
384
385class SendFlowRem(basic.SimpleDataPlane):
386
387 """Check deletion of flows happens and generates messages as configured.
388 If Send Flow removed message Flag is set in the flow entry, the flow deletion of that respective flow should generate the flow removed message,
389 vice versa also exists """
390
391 def runTest(self):
392
393 cs_logger.info("Running Send_Flow_Rem test ")
394
395 of_ports = cs_port_map.keys()
396 of_ports.sort()
397 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
398
399 #Clear swicth state
400 rc = delete_all_flows(self.controller, cs_logger)
401 self.assertEqual(rc, 0, "Failed to delete all flows")
402
403 cs_logger.info("Inserting flows F1 and F2 without and with send_flow_removed_message flag set ")
404 cs_logger.info("Deleting the flows")
405 cs_logger.info("Expecting flow removed message only for F2")
406
407 # Insert flow-1 with F without OFPFF_SEND_FLOW_REM flag set.
408 (pkt,match) = Wildcard_All_Except_Ingress(self,of_ports)
409
410 # Verify flow is inserted
411 Verify_TableStats(self,active_entries=1)
412
413 #Delete the flow-1
414 NonStrict_Delete(self,match,priority=0)
415
416 # Verify no flow removed message is generated for the FLOW-1
417
418 (response1, pkt1) = self.controller.poll(exp_msg=ofp.OFPT_FLOW_REMOVED,
419 timeout=2)
420 self.assertTrue(response1 is None,
421 'Received flow removed message for the flow with flow_rem flag not set')
422
423 # Insert another flow F' with OFPFF_SEND_FLOW_REM flag set.
424 msg9 = message.flow_mod()
425 msg9.match.wildcards = ofp.OFPFW_ALL
426 msg9.cookie = random.randint(0,9007199254740992)
427 msg9.buffer_id = 0xffffffff
428 msg9.idle_timeout = 1
429 msg9.flags |= ofp.OFPFF_SEND_FLOW_REM
430 rv1 = self.controller.message_send(msg9)
431 self.assertTrue(rv1 != -1, "Error installing flow mod")
432 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
433
434 # Delete the flow-2
435 rc2 = delete_all_flows(self.controller, cs_logger)
436 self.assertEqual(rc2, 0, "Failed to delete all flows")
437
438 # Verify flow removed message is generated for the FLOW-2
439
440 (response2, pkt2) = self.controller.poll(exp_msg=ofp.OFPT_FLOW_REMOVED,
441 timeout=2)
442 self.assertTrue(response2 is not None,
443 'Did not receive flow removed message for this flow')
444
445
446class DeleteEmerFlow(basic.SimpleProtocol):
447
448 """Delete emergency flow and verify no message is generated.An emergency flow deletion will not generate flow-removed messages even if
449 Send Flow removed message flag was set during the emergency flow entry"""
450
451 def runTest(self):
452
453 cs_logger.info("Running Delete_Emer_Flow")
454
455 of_ports = cs_port_map.keys()
456 of_ports.sort()
457
458 #Clear switch state
459 rc = delete_all_flows(self.controller, cs_logger)
460 self.assertEqual(rc, 0, "Failed to delete all flows")
461
462 cs_logger.info("Inserting a emergency flow with send_flow_removed flag set")
463 cs_logger.info("Expecting no flow_removed_message on the deletion of the emergency flow")
464
465 # Insert a flow with emergency bit set.
466 pkt = simple_tcp_packet()
467 match = parse.packet_to_flow_match(pkt)
468 match.in_port = of_ports[0]
469 request = message.flow_mod()
470 request.match = match
471 request.command = ofp.OFPFC_ADD
472 request.flags = request.flags|ofp.OFPFF_EMERG|ofp.OFPFF_SEND_FLOW_REM
473 act = action.action_output()
474 act.port = of_ports[1]
475 request.actions.add(act)
476
477 rv = self.controller.message_send(request)
478 self.assertTrue(rv != -1, "Flow addition failed.")
479
480 # Delete the emergency flow
481
482 NonStrict_Delete(self,match)
483 (response, pkt) = self.controller.poll(exp_msg=ofp.OFPFF_SEND_FLOW_REM ,
484 timeout=2)
485 self.assertTrue(response is None,
486 'Test Failed ')
487
488
489class StrictVsNonstrict(basic.SimpleDataPlane):
490
491 """Delete and verify strict and non-strict behaviors
492 This test compares the behavior of delete strict and non-strict"""
493
494 def runTest(self):
495
496 cs_logger.info("Strict_Vs_Nonstrict test begins")
497
498 of_ports = cs_port_map.keys()
499 of_ports.sort()
500 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
501
502 #Clear switch state
503 rc = delete_all_flows(self.controller, cs_logger)
504 self.assertEqual(rc, 0, "Failed to delete all flows")
505
506 cs_logger.info("Inserting a flow with exact match")
507 cs_logger.info("Issue Strict Delete command , verify it gets deleted")
508
509 #Insert F with an exact Match
510 (pkt,match) = Exact_Match(self,of_ports)
511 Verify_TableStats(self,active_entries=1)
512
513 #Issue Strict Delete Command , verify F gets deleted.
514 Strict_Delete(self,match)
515 Verify_TableStats(self,active_entries=0)
516
517 cs_logger.info("Inserting two overlapping flows")
518 cs_logger.info("Issue Strict Delete command ")
519 cs_logger.info("Expecting only one flow gets deleted , because Strict Delete matches on wildcards as well")
520
521 #Insert Flow T with match on all , except one wildcarded ( say src adddress ).
522 (pkt,match) = Match_All_Except_Source_Address(self,of_ports)
523
524 #Insert another flow T' with match on ingress_port , wildcarded rest.
525 (pkt1,match1) = Wildcard_All_Except_Ingress(self,of_ports)
526 Verify_TableStats(self,active_entries=2)
527
528 #Issue Strict Delete matching on ingress_port. Verify only T' gets deleted
529 Strict_Delete(self,match1)
530 Verify_TableStats(self,active_entries=1)
531
532 cs_logger.info("Inserting two overlapping flows")
533 cs_logger.info("Issue Non-Strict Delete command ")
534 cs_logger.info("Expecting both the flow gets deleted , because wildcards are active")
535
536 #Insert T and T' again .
537 (pkt,match) = Match_All_Except_Source_Address(self,of_ports)
538 (pkt1,match1) = Wildcard_All_Except_Ingress(self,of_ports)
539 Verify_TableStats(self,active_entries=2)
540
541 #Issue Non-strict Delete with match on ingress_port.Verify T+T' gets deleted .
542 NonStrict_Delete(self,match1)
543 Verify_TableStats(self,active_entries=0)
544
545 cs_logger.info("Inserting three overlapping flows with different priorities")
546 cs_logger.info("Issue Non-Strict Delete command ")
547 cs_logger.info("Expecting all the flows to get deleted")
548
549 #Insert T , add Priority P (say 100 )
550 (pkt,match) = Match_All_Except_Source_Address(self,of_ports,priority=100)
551
552 #Insert T' add priority (200).
553 (pkt1,match1) = Wildcard_All_Except_Ingress(self,of_ports,priority=200)
554
555 #Insert T' again add priority 300 --> T" .
556 (pkt2,match2) = Wildcard_All_Except_Ingress(self,of_ports,priority=300)
557 Verify_TableStats(self,active_entries=3)
558
559 #Issue Non-Strict Delete and verify all getting deleted
560 NonStrict_Delete(self,match1,priority=200)
561 Verify_TableStats(self,active_entries=0)
562
563 cs_logger.info("Inserting three overlapping flows with different priorities")
564 cs_logger.info("Issue Strict Delete command ")
565 cs_logger.info("Expecting only one to get deleted because here priorities & wildcards are being matched")
566
567 #Issue Strict-Delete and verify only T'' gets deleted.
568 (pkt,match) = Match_All_Except_Source_Address(self,of_ports,priority=100)
569 (pkt1,match1) = Wildcard_All_Except_Ingress(self,of_ports,priority=200)
570 (pkt2,match2) = Wildcard_All_Except_Ingress(self,of_ports,priority=300)
571 Strict_Delete(self,match1,priority=200)
572 Verify_TableStats(self,active_entries=2)
573
574
575
576class Outport1(basic.SimpleDataPlane):
577
578 """Delete flows filtered by action outport.If the out_port field in the delete command contains a value other than OFPP_NONE,
579 it introduces a constraint when matching. This constraint is that the rule must contain an output action directed at that port."""
580
581 def runTest(self):
582
583 cs_logger.info("Outport1 test begins")
584
585 of_ports = cs_port_map.keys()
586 of_ports.sort()
587 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
588
589 #Clear switch state
590 rc = delete_all_flows(self.controller, cs_logger)
591 self.assertEqual(rc, 0, "Failed to delete all flows")
592
593 cs_logger.info("Inserting a flow with output action --> of_port[1]")
594 cs_logger.info("Deleting the flow but with out_port set to of_port[2]")
595 cs_logger.info("Expecting switch to filter the delete command")
596
597 #Build and send Flow-1 with action output to of_port[1]
598 (pkt,match) = Wildcard_All_Except_Ingress(self,of_ports)
599
600 # Verify active_entries in table_stats_request = 1
601 Verify_TableStats(self,active_entries=1)
602
603 #Send delete command matching the flow-1 but with contraint out_port = of_port[2]
604 msg7 = message.flow_mod()
605 msg7.out_port = of_ports[2]
606 msg7.command = ofp.OFPFC_DELETE
607 msg7.buffer_id = 0xffffffff
608 msg7.match = match
609
610 rv = self.controller.message_send(msg7)
611 self.assertTrue(rv != -1, "Error installing flow mod")
612 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
613
614 # Verify flow will not get deleted, active_entries in table_stats_request = 1
615 Verify_TableStats(self,active_entries=1)
616
617 cs_logger.info("Deleting the flow with out_port set to of_port[1]")
618 cs_logger.info("Expecting switch to delete the flow")
619
620 #Send Delete command with contraint out_port = of_ports[1]
621 msg7 = message.flow_mod()
622 msg7.out_port = of_ports[1]
623 msg7.command = ofp.OFPFC_DELETE
624 msg7.buffer_id = 0xffffffff
625 msg7.match = match
626
627 rv = self.controller.message_send(msg7)
628 self.assertTrue(rv != -1, "Error installing flow mod")
629 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
630
631 #Verify flow gets deleted.
632 Verify_TableStats(self,active_entries=0)
633
634
635class IdleTimeout(basic.SimpleDataPlane):
636
637 """ Verify that idle timeout is implemented"""
638
639 def runTest(self):
640
641 cs_logger.info("Running Idle_Timeout test ")
642
643 of_ports = cs_port_map.keys()
644 of_ports.sort()
645 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
646
647 #Clear switch state
648 rc = delete_all_flows(self.controller, cs_logger)
649 self.assertEqual(rc, 0, "Failed to delete all flows")
650
651 cs_logger.info("Inserting flow entry with idle_timeout set. Also send_flow_removed_message flag set")
652 cs_logger.info("Expecting the flow entry to delete with given idle_timeout")
653
654 #Insert a flow entry with idle_timeout=1.Send_Flow_Rem flag set
655 msg9 = message.flow_mod()
656 msg9.match.wildcards = ofp.OFPFW_ALL
657 msg9.cookie = random.randint(0,9007199254740992)
658 msg9.buffer_id = 0xffffffff
659 msg9.idle_timeout = 1
660 msg9.flags |= ofp.OFPFF_SEND_FLOW_REM
661 rv1 = self.controller.message_send(msg9)
662 self.assertTrue(rv1 != -1, "Error installing flow mod")
663 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
664
665 #Verify flow gets inserted
666 Verify_TableStats(self,active_entries=1)
667
668 # Verify flow removed message is recieved.
669 (response, pkt) = self.controller.poll(exp_msg=ofp.OFPT_FLOW_REMOVED,
670 timeout=5)
671 self.assertTrue(response is not None,
672 'Did not receive flow removed message ')
673 self.assertEqual(ofp.OFPRR_IDLE_TIMEOUT, response.reason,
674 'Flow table entry removal reason is not idle_timeout')
675 self.assertEqual(1, response.duration_sec,
676 'Flow was not alive for 1 sec')
677
678
679class Outport2(basic.SimpleDataPlane):
680
681 """Add, modify flows with outport set. This field is ignored by ADD, MODIFY, and MODIFY STRICT messages."""
682
683 def runTest(self):
684
685 cs_logger.info("Running Outport2 test ")
686
687 of_ports = cs_port_map.keys()
688 of_ports.sort()
689 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
690
691 #Clear switch state
692 rc = delete_all_flows(self.controller, cs_logger)
693 self.assertEqual(rc, 0, "Failed to delete all flows")
694
695 cs_logger.info("Adding and modifying flow with out_port fields set")
696 cs_logger.info("Expecting switch to ignore out_port")
697
698 # Create and add flow-1,Action A ,output to port of_port[1], out_port set to of_ports[2]
699 (pkt,match) = Wildcard_All_Except_Ingress(self,of_ports)
700
701 # Verify flow is active
702 Verify_TableStats(self,active_entries=1)
703
704 # Send Packet matching the flow
705 SendPacket(self,pkt,of_ports[0],of_ports[1])
706
707 # Insert Flow-Modify matching flow F-1 ,action A', output to port[2], out_port set to port[3]
708 Modify_Flow_Action(self,of_ports,match)
709
710 # Again verify active_entries in table_stats_request =1
711 Verify_TableStats(self,active_entries=1)
712
713 #Verify action is modified
714 SendPacket(self,pkt,of_ports[0],of_ports[2])
715
716
717
718
719class HardTimeout(basic.SimpleDataPlane):
720
721 """ Verify that hard timeout is implemented """
722
723 def runTest(self):
724
725 cs_logger.info("Running Hard_Timeout test ")
726
727 of_ports = cs_port_map.keys()
728 of_ports.sort()
729 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
730
731 #Clear switch state
732 rc = delete_all_flows(self.controller, cs_logger)
733 self.assertEqual(rc, 0, "Failed to delete all flows")
734
735 cs_logger.info("Inserting flow entry with hard_timeout set. Also send_flow_removed_message flag set")
736 cs_logger.info("Expecting the flow entry to delete with given hard_timeout")
737
738 # Insert a flow entry with hardtimeout=1 and send_flow_removed flag set
739 msg9 = message.flow_mod()
740 msg9.match.wildcards = ofp.OFPFW_ALL
741 msg9.cookie = random.randint(0,9007199254740992)
742 msg9.buffer_id = 0xffffffff
743 msg9.hard_timeout = 1
744 msg9.flags |= ofp.OFPFF_SEND_FLOW_REM
745 rv1 = self.controller.message_send(msg9)
746 self.assertTrue(rv1 != -1, "Error installing flow mod")
747 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
748
749 #Verify flow gets inserted
750 Verify_TableStats(self,active_entries=1)
751
752 # Verify flow removed message is recieved.
753 (response, pkt) = self.controller.poll(exp_msg=ofp.OFPT_FLOW_REMOVED,
754 timeout=5)
755 self.assertTrue(response is not None,
756 'Did not receive flow removed message ')
757 self.assertEqual(ofp.OFPRR_HARD_TIMEOUT, response.reason,
758 'Flow table entry removal reason is not hard_timeout')
759 self.assertEqual(1, response.duration_sec,
760 'Flow was not alive for 1 sec')
761
762
763class FlowTimeout(basic.SimpleDataPlane):
764
765 """Verify that Flow removed messages are generated as expected
766 Flow removed messages being generated when flag is set, is already tested in the above tests
767 So here, we test the vice-versa condition"""
768
769
770 def runTest(self):
771
772 cs_logger.info("Running Flow_Timeout test ")
773
774 of_ports = cs_port_map.keys()
775 of_ports.sort()
776 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
777
778 #Clear switch state
779 rc = delete_all_flows(self.controller, cs_logger)
780 self.assertEqual(rc, 0, "Failed to delete all flows")
781
782 cs_logger.info("Inserting flow entry with hard_timeout set and send_flow_removed_message flag not set")
783 cs_logger.info("Expecting the flow entry to delete, but no flow removed message")
784
785 # Insert a flow with hard_timeout = 1 but no Send_Flow_Rem flag set
786 pkt = simple_tcp_packet()
787 match3 = parse.packet_to_flow_match(pkt)
788 self.assertTrue(match3 is not None, "Could not generate flow match from pkt")
789 match3.wildcards = ofp.OFPFW_ALL-ofp.OFPFW_IN_PORT
790 match3.in_port = of_ports[0]
791 msg3 = message.flow_mod()
792 msg3.out_port = of_ports[2] # ignored by flow add,flow modify
793 msg3.command = ofp.OFPFC_ADD
794 msg3.cookie = random.randint(0,9007199254740992)
795 msg3.buffer_id = 0xffffffff
796 msg3.hard_timeout = 1
797 msg3.buffer_id = 0xffffffff
798 msg3.match = match3
799 act3 = action.action_output()
800 act3.port = of_ports[1]
801 self.assertTrue(msg3.actions.add(act3), "could not add action")
802
803 rv = self.controller.message_send(msg3)
804 self.assertTrue(rv != -1, "Error installing flow mod")
805 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
806
807 #Verify no flow removed message is generated
808 (response, pkt) = self.controller.poll(exp_msg=ofp.OFPT_FLOW_REMOVED,
809 timeout=3)
810 self.assertTrue(response is None,
811 'Recieved flow removed message ')
812
813 # Verify no entries in the table
814 Verify_TableStats(self,active_entries=0)
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837