blob: e8322fd751a9cc9dc558a949a0e1b39ca9d3dbc8 [file] [log] [blame]
Dan Talayco89d57342010-06-07 16:24:59 -07001"""
2Flow stats test case.
3Similar to Flow stats test case in the perl test harness.
4
5"""
6
7import logging
8
9import unittest
10import random
Rich Lanec42dbad2012-10-11 10:57:44 -070011import copy
Dan Talayco89d57342010-06-07 16:24:59 -070012
Rich Lane477f4812012-10-04 22:49:00 -070013from oftest import config
Dan Talayco89d57342010-06-07 16:24:59 -070014import oftest.controller as controller
15import oftest.cstruct as ofp
16import oftest.message as message
17import oftest.dataplane as dataplane
18import oftest.action as action
19import oftest.parse as parse
Rich Laneb90a1c42012-10-05 09:16:05 -070020import oftest.base_tests as base_tests
Dan Talayco89d57342010-06-07 16:24:59 -070021
Rich Laneda3b5ad2012-10-03 09:05:32 -070022from oftest.testutils import *
Dan Talayco89d57342010-06-07 16:24:59 -070023from time import sleep
24
Ken Chiang620bdcc2012-03-23 12:52:07 -070025# TODO: ovs has problems with VLAN id?
26WILDCARD_VALUES = [ofp.OFPFW_IN_PORT,
Dan Talayco488fbc52012-04-09 16:30:41 -070027 # (ofp.OFPFW_DL_VLAN | ofp.OFPFW_DL_VLAN_PCP),
Ken Chiang620bdcc2012-03-23 12:52:07 -070028 ofp.OFPFW_DL_SRC,
29 ofp.OFPFW_DL_DST,
Dan Talayco488fbc52012-04-09 16:30:41 -070030 (ofp.OFPFW_DL_TYPE | ofp.OFPFW_NW_SRC_ALL |
31 ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS | ofp.OFPFW_NW_PROTO |
32 ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
33 (ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
Ken Chiang620bdcc2012-03-23 12:52:07 -070034 ofp.OFPFW_TP_SRC,
35 ofp.OFPFW_TP_DST,
Dan Talayco488fbc52012-04-09 16:30:41 -070036 ofp.OFPFW_NW_SRC_MASK,
37 ofp.OFPFW_NW_DST_MASK,
Ken Chiang620bdcc2012-03-23 12:52:07 -070038 ofp.OFPFW_DL_VLAN_PCP,
39 ofp.OFPFW_NW_TOS]
40
Ken Chiangaa5bc062012-03-31 14:03:28 -070041def sendPacket(obj, pkt, ingress_port, egress_port, test_timeout):
42
Rich Lane9a003812012-10-04 17:17:59 -070043 logging.info("Sending packet to dp port " + str(ingress_port) +
Ken Chiangaa5bc062012-03-31 14:03:28 -070044 ", expecting output on " + str(egress_port))
45 obj.dataplane.send(ingress_port, str(pkt))
46
47 exp_pkt_arg = None
48 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -070049 if config["relax"]:
Ken Chiangaa5bc062012-03-31 14:03:28 -070050 exp_pkt_arg = pkt
51 exp_port = egress_port
52
Rich Lanec8aaa3e2012-07-26 19:28:02 -070053 (rcv_port, rcv_pkt, pkt_time) = obj.dataplane.poll(port_number=exp_port,
Ken Chiangaa5bc062012-03-31 14:03:28 -070054 exp_pkt=exp_pkt_arg)
55 obj.assertTrue(rcv_pkt is not None,
56 "Packet not received on port " + str(egress_port))
Rich Lane9a003812012-10-04 17:17:59 -070057 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Ken Chiangaa5bc062012-03-31 14:03:28 -070058 str(rcv_port))
59 obj.assertEqual(rcv_port, egress_port,
60 "Packet received on port " + str(rcv_port) +
61 ", expected port " + str(egress_port))
62 obj.assertEqual(str(pkt), str(rcv_pkt),
63 'Response packet does not match send packet')
64
Rich Laneb90a1c42012-10-05 09:16:05 -070065class SingleFlowStats(base_tests.SimpleDataPlane):
Dan Talayco89d57342010-06-07 16:24:59 -070066 """
67 Verify flow stats are properly retrieved.
68
69 Generate a packet
Ken Chiang620bdcc2012-03-23 12:52:07 -070070 Generate and install a matching flow
71 Send the packet
72 Send a flow stats request to match the flow and retrieve stats
73 Verify that the packet counter has incremented
Dan Talayco89d57342010-06-07 16:24:59 -070074 """
Ken Chiang620bdcc2012-03-23 12:52:07 -070075
Rich Lanec42dbad2012-10-11 10:57:44 -070076 def verifyStats(self, flow_mod_msg, match, out_port, test_timeout, packet_count):
Ken Chiang620bdcc2012-03-23 12:52:07 -070077 stat_req = message.flow_stats_request()
78 stat_req.match = match
79 stat_req.table_id = 0xff
80 stat_req.out_port = out_port
81
82 all_packets_received = 0
83 for i in range(0,test_timeout):
Rich Lane9a003812012-10-04 17:17:59 -070084 logging.info("Sending stats request")
Ken Chiangfb593e72012-03-28 17:19:13 -070085 response, pkt = self.controller.transact(stat_req,
86 timeout=test_timeout)
87 self.assertTrue(response is not None,
88 "No response to stats request")
89 self.assertTrue(len(response.stats) == 1,
90 "Did not receive flow stats reply")
Ken Chiang620bdcc2012-03-23 12:52:07 -070091 for obj in response.stats:
92 # TODO: pad1 and pad2 fields may be nonzero, is this a bug?
93 # for now, just clear them so the assert is simpler
Rich Lanec42dbad2012-10-11 10:57:44 -070094 obj.match.pad1 = 0
95 obj.match.pad2 = [0, 0]
96 self.assertEqual(flow_mod_msg.match, obj.match,
97 "Matches do not match")
98 self.assertEqual(obj.cookie, flow_mod_msg.cookie)
99 self.assertEqual(obj.priority, flow_mod_msg.priority)
100 self.assertEqual(obj.idle_timeout, flow_mod_msg.idle_timeout)
101 self.assertEqual(obj.hard_timeout, flow_mod_msg.hard_timeout)
102 self.assertEqual(obj.actions, flow_mod_msg.actions)
Rich Lane9a003812012-10-04 17:17:59 -0700103 logging.info("Received " + str(obj.packet_count) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700104 if obj.packet_count == packet_count:
105 all_packets_received = 1
106
107 if all_packets_received:
108 break
109 sleep(1)
110
111 self.assertTrue(all_packets_received,
112 "Packet count does not match number sent")
113
Dan Talayco89d57342010-06-07 16:24:59 -0700114 def runTest(self):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700115 # TODO: set from command-line parameter
116 test_timeout = 60
117
Rich Lane477f4812012-10-04 22:49:00 -0700118 of_ports = config["port_map"].keys()
Dan Talayco89d57342010-06-07 16:24:59 -0700119 of_ports.sort()
120 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
121
Rich Lane9a003812012-10-04 17:17:59 -0700122 rc = delete_all_flows(self.controller)
Dan Talayco89d57342010-06-07 16:24:59 -0700123 self.assertEqual(rc, 0, "Failed to delete all flows")
124
Ken Chiang620bdcc2012-03-23 12:52:07 -0700125 # build packet
Dan Talayco89d57342010-06-07 16:24:59 -0700126 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700127 match = packet_to_flow_match(self, pkt)
Dan Talayco89d57342010-06-07 16:24:59 -0700128 match.wildcards &= ~ofp.OFPFW_IN_PORT
129 self.assertTrue(match is not None,
130 "Could not generate flow match from pkt")
131 act = action.action_output()
132
Ken Chiang620bdcc2012-03-23 12:52:07 -0700133 # build flow
Dan Talayco39bf6912010-07-08 14:17:52 -0700134 ingress_port = of_ports[0];
135 egress_port = of_ports[1];
Rich Lane9a003812012-10-04 17:17:59 -0700136 logging.info("Ingress " + str(ingress_port) +
Dan Talayco89d57342010-06-07 16:24:59 -0700137 " to egress " + str(egress_port))
Ken Chiang620bdcc2012-03-23 12:52:07 -0700138 match.in_port = ingress_port
139 flow_mod_msg = message.flow_mod()
Rich Lanec42dbad2012-10-11 10:57:44 -0700140 flow_mod_msg.match = copy.deepcopy(match)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700141 flow_mod_msg.cookie = random.randint(0,9007199254740992)
142 flow_mod_msg.buffer_id = 0xffffffff
Rich Lanec42dbad2012-10-11 10:57:44 -0700143 flow_mod_msg.idle_timeout = 60000
144 flow_mod_msg.hard_timeout = 65000
145 flow_mod_msg.priority = 100
Ken Chiang620bdcc2012-03-23 12:52:07 -0700146 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800147 flow_mod_msg.actions.add(act)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700148
149 # send flow
Rich Lane9a003812012-10-04 17:17:59 -0700150 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800151 self.controller.message_send(flow_mod_msg)
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700152 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700153
154 # no packets sent, so zero packet count
Rich Lanec42dbad2012-10-11 10:57:44 -0700155 self.verifyStats(flow_mod_msg, match, ofp.OFPP_NONE, test_timeout, 0)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700156
157 # send packet N times
158 num_sends = random.randint(10,20)
Rich Lane9a003812012-10-04 17:17:59 -0700159 logging.info("Sending " + str(num_sends) + " test packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700160 for i in range(0,num_sends):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700161 sendPacket(self, pkt, ingress_port, egress_port,
162 test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700163
Rich Lanec42dbad2012-10-11 10:57:44 -0700164 self.verifyStats(flow_mod_msg, match, ofp.OFPP_NONE, test_timeout, num_sends)
165 self.verifyStats(flow_mod_msg, match, egress_port, test_timeout, num_sends)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700166 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -0700167 match.wildcards = required_wildcards(self) | wc
Rich Lanec42dbad2012-10-11 10:57:44 -0700168 self.verifyStats(flow_mod_msg, match, egress_port, test_timeout, num_sends)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700169
170
Rich Laneb90a1c42012-10-05 09:16:05 -0700171class TwoFlowStats(base_tests.SimpleDataPlane):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700172 """
173 Verify flow stats are properly retrieved.
174
175 Generate two packets and install two matching flows
176 Send some number of packets
177 Send a flow stats request to match the flows and retrieve stats
178 Verify that the packet counter has incremented
179
180 TODO: add a third flow, and then configure the match to exclude
181 that flow?
182 """
183
184 def buildFlowModMsg(self, pkt, ingress_port, egress_port):
Ed Swierk99a74de2012-08-22 06:40:54 -0700185 match = packet_to_flow_match(self, pkt)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700186 match.wildcards &= ~ofp.OFPFW_IN_PORT
187 self.assertTrue(match is not None,
188 "Could not generate flow match from pkt")
Dan Talayco89d57342010-06-07 16:24:59 -0700189 match.in_port = ingress_port
190
191 flow_mod_msg = message.flow_mod()
192 flow_mod_msg.match = match
193 flow_mod_msg.cookie = random.randint(0,9007199254740992)
194 flow_mod_msg.buffer_id = 0xffffffff
Ken Chiang620bdcc2012-03-23 12:52:07 -0700195 flow_mod_msg.idle_timeout = 0
196 flow_mod_msg.hard_timeout = 0
197 act = action.action_output()
Dan Talayco89d57342010-06-07 16:24:59 -0700198 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800199 flow_mod_msg.actions.add(act)
Dan Talayco89d57342010-06-07 16:24:59 -0700200
Rich Lane9a003812012-10-04 17:17:59 -0700201 logging.info("Ingress " + str(ingress_port) +
Ken Chiang620bdcc2012-03-23 12:52:07 -0700202 " to egress " + str(egress_port))
Dan Talayco89d57342010-06-07 16:24:59 -0700203
Ken Chiang620bdcc2012-03-23 12:52:07 -0700204 return flow_mod_msg
Dan Talayco89d57342010-06-07 16:24:59 -0700205
Ken Chiangaa5bc062012-03-31 14:03:28 -0700206 def sumStatsReplyCounts(self, response):
207 total_packets = 0
208 for obj in response.stats:
209 # TODO: pad1 and pad2 fields may be nonzero, is this a bug?
210 # for now, just clear them so the assert is simpler
211 #obj.match.pad1 = 0
212 #obj.match.pad2 = [0, 0]
213 #self.assertEqual(match, obj.match,
214 # "Matches do not match")
Rich Lane9a003812012-10-04 17:17:59 -0700215 logging.info("Received " + str(obj.packet_count)
Ken Chiangaa5bc062012-03-31 14:03:28 -0700216 + " packets")
217 total_packets += obj.packet_count
218 return total_packets
Ken Chiang620bdcc2012-03-23 12:52:07 -0700219
220 def verifyStats(self, match, out_port, test_timeout, packet_count):
221 stat_req = message.flow_stats_request()
222 stat_req.match = match
223 stat_req.table_id = 0xff
224 stat_req.out_port = out_port
225
226 all_packets_received = 0
227 for i in range(0,test_timeout):
Rich Lane9a003812012-10-04 17:17:59 -0700228 logging.info("Sending stats request")
Ken Chiangaa5bc062012-03-31 14:03:28 -0700229 # TODO: move REPLY_MORE handling to controller.transact?
Ken Chiangfb593e72012-03-28 17:19:13 -0700230 response, pkt = self.controller.transact(stat_req,
231 timeout=test_timeout)
232 self.assertTrue(response is not None,
233 "No response to stats request")
Ken Chiangaa5bc062012-03-31 14:03:28 -0700234 total_packets = self.sumStatsReplyCounts(response)
235
236 while response.flags == ofp.OFPSF_REPLY_MORE:
237 response, pkt = self.controller.poll(exp_msg=
238 ofp.OFPT_STATS_REPLY,
239 timeout=test_timeout)
240 total_packets += self.sumStatsReplyCounts(response)
241
Ken Chiang620bdcc2012-03-23 12:52:07 -0700242 if total_packets == packet_count:
243 all_packets_received = 1
244 break
245 sleep(1)
246
247 self.assertTrue(all_packets_received,
Ken Chiangaa5bc062012-03-31 14:03:28 -0700248 "Total stats packet count " + str(total_packets) +
249 " does not match number sent " + str(packet_count))
Ken Chiang620bdcc2012-03-23 12:52:07 -0700250
251 def runTest(self):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700252 # TODO: set from command-line parameter
253 test_timeout = 60
254
Rich Lane477f4812012-10-04 22:49:00 -0700255 of_ports = config["port_map"].keys()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700256 of_ports.sort()
257 self.assertTrue(len(of_ports) >= 3, "Not enough ports for test")
258 ingress_port = of_ports[0];
259 egress_port1 = of_ports[1];
260 egress_port2 = of_ports[2];
261
Rich Lane9a003812012-10-04 17:17:59 -0700262 rc = delete_all_flows(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700263 self.assertEqual(rc, 0, "Failed to delete all flows")
264
265 pkt1 = simple_tcp_packet()
266 flow_mod_msg1 = self.buildFlowModMsg(pkt1, ingress_port, egress_port1)
267
268 pkt2 = simple_tcp_packet(dl_src='0:7:7:7:7:7')
269 flow_mod_msg2 = self.buildFlowModMsg(pkt2, ingress_port, egress_port2)
270
Rich Lane9a003812012-10-04 17:17:59 -0700271 logging.info("Inserting flow1")
Rich Lane5c3151c2013-01-03 17:15:41 -0800272 self.controller.message_send(flow_mod_msg1)
Rich Lane9a003812012-10-04 17:17:59 -0700273 logging.info("Inserting flow2")
Rich Lane5c3151c2013-01-03 17:15:41 -0800274 self.controller.message_send(flow_mod_msg2)
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700275 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco89d57342010-06-07 16:24:59 -0700276
Ken Chiang620bdcc2012-03-23 12:52:07 -0700277 num_pkt1s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700278 logging.info("Sending " + str(num_pkt1s) + " pkt1s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700279 num_pkt2s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700280 logging.info("Sending " + str(num_pkt2s) + " pkt2s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700281 for i in range(0,num_pkt1s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700282 sendPacket(self, pkt1, ingress_port, egress_port1, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700283 for i in range(0,num_pkt2s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700284 sendPacket(self, pkt2, ingress_port, egress_port2, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700285
Ed Swierk99a74de2012-08-22 06:40:54 -0700286 match1 = packet_to_flow_match(self, pkt1)
Rich Lane9a003812012-10-04 17:17:59 -0700287 logging.info("Verifying flow1's " + str(num_pkt1s) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700288 self.verifyStats(match1, ofp.OFPP_NONE, test_timeout, num_pkt1s)
Ed Swierk99a74de2012-08-22 06:40:54 -0700289 match2 = packet_to_flow_match(self, pkt2)
Rich Lane9a003812012-10-04 17:17:59 -0700290 logging.info("Verifying flow2's " + str(num_pkt2s) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700291 self.verifyStats(match2, ofp.OFPP_NONE, test_timeout, num_pkt2s)
292 match1.wildcards |= ofp.OFPFW_DL_SRC
Rich Lane9a003812012-10-04 17:17:59 -0700293 logging.info("Verifying combined " + str(num_pkt1s+num_pkt2s) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700294 self.verifyStats(match1, ofp.OFPP_NONE, test_timeout,
295 num_pkt1s+num_pkt2s)
296 # TODO: sweep through the wildcards to verify matching?
297
298
Rich Laneb90a1c42012-10-05 09:16:05 -0700299class AggregateStats(base_tests.SimpleDataPlane):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700300 """
301 Verify aggregate flow stats are properly retrieved.
302
303 Generate two packets
304 Generate and install two matching flows
305 Send an aggregate stats request
306 Verify that aggregate stats are correct
307 Also verify out_port filtering
308 """
309
310 def buildFlowModMsg(self, pkt, ingress_port, egress_port):
Ed Swierk99a74de2012-08-22 06:40:54 -0700311 match = packet_to_flow_match(self, pkt)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700312 match.wildcards &= ~ofp.OFPFW_IN_PORT
313 self.assertTrue(match is not None,
314 "Could not generate flow match from pkt")
315 match.in_port = ingress_port
316
317 flow_mod_msg = message.flow_mod()
318 flow_mod_msg.match = match
319 flow_mod_msg.cookie = random.randint(0,9007199254740992)
320 flow_mod_msg.buffer_id = 0xffffffff
321 flow_mod_msg.idle_timeout = 0
322 flow_mod_msg.hard_timeout = 0
323 act = action.action_output()
324 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800325 flow_mod_msg.actions.add(act)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700326
Rich Lane9a003812012-10-04 17:17:59 -0700327 logging.info("Ingress " + str(ingress_port) +
Ken Chiang620bdcc2012-03-23 12:52:07 -0700328 " to egress " + str(egress_port))
329
330 return flow_mod_msg
331
Ken Chiang620bdcc2012-03-23 12:52:07 -0700332 def verifyAggFlowStats(self, match, out_port, test_timeout,
333 flow_count, packet_count):
334 stat_req = message.aggregate_stats_request()
335 stat_req.match = match
336 stat_req.table_id = 0xff
337 stat_req.out_port = out_port
338
339 all_packets_received = 0
340 for i in range(0,test_timeout):
Rich Lane9a003812012-10-04 17:17:59 -0700341 logging.info("Sending stats request")
Ken Chiangfb593e72012-03-28 17:19:13 -0700342 response, pkt = self.controller.transact(stat_req,
343 timeout=test_timeout)
344 self.assertTrue(response is not None,
345 "No response to stats request")
Dan Talaycoaff26c82012-03-25 15:06:26 -0700346 self.assertTrue(len(response.stats) == 1,
347 "Did not receive flow stats reply")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700348 for obj in response.stats:
349 self.assertTrue(obj.flow_count == flow_count,
350 "Flow count " + str(obj.flow_count) +
351 " does not match expected " + str(flow_count))
Rich Lane9a003812012-10-04 17:17:59 -0700352 logging.info("Received " + str(obj.packet_count) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700353 if obj.packet_count == packet_count:
354 all_packets_received = 1
355
356 if all_packets_received:
357 break
358 sleep(1)
359
360 self.assertTrue(all_packets_received,
361 "Packet count does not match number sent")
362
363 def runTest(self):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700364 # TODO: set from command-line parameter
365 test_timeout = 60
366
Rich Lane477f4812012-10-04 22:49:00 -0700367 of_ports = config["port_map"].keys()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700368 of_ports.sort()
369 self.assertTrue(len(of_ports) >= 3, "Not enough ports for test")
370 ingress_port = of_ports[0];
371 egress_port1 = of_ports[1];
372 egress_port2 = of_ports[2];
373
Rich Lane9a003812012-10-04 17:17:59 -0700374 rc = delete_all_flows(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700375 self.assertEqual(rc, 0, "Failed to delete all flows")
376
377 pkt1 = simple_tcp_packet()
378 flow_mod_msg1 = self.buildFlowModMsg(pkt1, ingress_port, egress_port1)
379
380 pkt2 = simple_tcp_packet(dl_src='0:7:7:7:7:7')
381 flow_mod_msg2 = self.buildFlowModMsg(pkt2, ingress_port, egress_port2)
382
Rich Lane9a003812012-10-04 17:17:59 -0700383 logging.info("Inserting flow1")
Rich Lane5c3151c2013-01-03 17:15:41 -0800384 self.controller.message_send(flow_mod_msg1)
Rich Lane9a003812012-10-04 17:17:59 -0700385 logging.info("Inserting flow2")
Rich Lane5c3151c2013-01-03 17:15:41 -0800386 self.controller.message_send(flow_mod_msg2)
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700387 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700388
389 num_pkt1s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700390 logging.info("Sending " + str(num_pkt1s) + " pkt1s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700391 num_pkt2s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700392 logging.info("Sending " + str(num_pkt2s) + " pkt2s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700393 for i in range(0,num_pkt1s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700394 sendPacket(self, pkt1, ingress_port, egress_port1, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700395 for i in range(0,num_pkt2s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700396 sendPacket(self, pkt2, ingress_port, egress_port2, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700397
398 # loop on flow stats request until timeout
Ed Swierk99a74de2012-08-22 06:40:54 -0700399 match = packet_to_flow_match(self, pkt1)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700400 match.wildcards |= ofp.OFPFW_DL_SRC
401 self.verifyAggFlowStats(match, ofp.OFPP_NONE, test_timeout,
402 2, num_pkt1s+num_pkt2s)
403
404 # out_port filter for egress_port1
405 self.verifyAggFlowStats(match, egress_port1, test_timeout,
406 1, num_pkt1s)
407
408 # out_port filter for egress_port1
409 self.verifyAggFlowStats(match, egress_port2, test_timeout,
410 1, num_pkt2s)
Rich Lane97a5f502012-10-11 09:28:11 -0700411
Rich Lanef062b3d2012-10-11 09:53:19 -0700412class EmptyFlowStats(base_tests.SimpleDataPlane):
413 """
414 Verify the switch replies to a flow stats request when
415 the query doesn't match any flows.
416 """
417 def runTest(self):
418 rc = delete_all_flows(self.controller)
419 self.assertEqual(rc, 0, "Failed to delete all flows")
420 match = ofp.ofp_match()
421 match.wildcards = 0
422 stat_req = message.flow_stats_request()
423 stat_req.match = match
424 stat_req.table_id = 0xff
425 stat_req.out_port = ofp.OFPP_NONE
426
427 response, pkt = self.controller.transact(stat_req)
428 self.assertTrue(response is not None,
429 "No response to stats request")
430 self.assertEquals(len(response.stats), 0)
431 self.assertEquals(response.flags, 0)
432
Rich Lane97a5f502012-10-11 09:28:11 -0700433class EmptyAggregateStats(base_tests.SimpleDataPlane):
434 """
435 Verify aggregate flow stats are properly retrieved when
436 the query doesn't match any flows.
437 """
438 def runTest(self):
439 rc = delete_all_flows(self.controller)
440 self.assertEqual(rc, 0, "Failed to delete all flows")
441 match = ofp.ofp_match()
442 match.wildcards = 0
443 stat_req = message.aggregate_stats_request()
444 stat_req.match = match
445 stat_req.table_id = 0xff
446 stat_req.out_port = ofp.OFPP_NONE
447
448 response, pkt = self.controller.transact(stat_req)
449 self.assertTrue(response is not None,
450 "No response to stats request")
451 self.assertTrue(len(response.stats) == 1,
452 "Did not receive flow stats reply")
453 self.assertEquals(response.stats[0].flow_count, 0)
454 self.assertEquals(response.stats[0].packet_count, 0)
455 self.assertEquals(response.stats[0].byte_count, 0)
Rich Laned10e8e02012-11-21 15:48:36 -0800456
457class DeletedFlowStats(base_tests.SimpleDataPlane):
458 """
459 Verify flow stats are properly returned when a flow is deleted.
460
461 Generate a packet
462 Generate and install a matching flow
463 Send the packet
464 Delete the flow
465 Verify that the flow_removed message has the correct stats
466 """
467
468 def runTest(self):
469 # TODO: set from command-line parameter
470 test_timeout = 60
471
472 of_ports = config["port_map"].keys()
473 of_ports.sort()
474 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
475
476 rc = delete_all_flows(self.controller)
477 self.assertEqual(rc, 0, "Failed to delete all flows")
478
479 # build packet
480 pkt = simple_tcp_packet()
481 match = packet_to_flow_match(self, pkt)
482 match.wildcards &= ~ofp.OFPFW_IN_PORT
483 self.assertTrue(match is not None,
484 "Could not generate flow match from pkt")
485 act = action.action_output()
486
487 # build flow
488 ingress_port = of_ports[0];
489 egress_port = of_ports[1];
490 logging.info("Ingress " + str(ingress_port) +
491 " to egress " + str(egress_port))
492 match.in_port = ingress_port
493 flow_mod_msg = message.flow_mod()
494 flow_mod_msg.match = copy.deepcopy(match)
495 flow_mod_msg.cookie = random.randint(0,9007199254740992)
496 flow_mod_msg.buffer_id = 0xffffffff
497 flow_mod_msg.idle_timeout = 0
498 flow_mod_msg.hard_timeout = 0
499 flow_mod_msg.priority = 100
500 flow_mod_msg.flags = ofp.OFPFF_SEND_FLOW_REM
501 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800502 flow_mod_msg.actions.add(act)
Rich Laned10e8e02012-11-21 15:48:36 -0800503
504 # send flow
505 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800506 self.controller.message_send(flow_mod_msg)
Rich Laned10e8e02012-11-21 15:48:36 -0800507 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
508
509 # send packet N times
510 num_sends = random.randint(10,20)
511 logging.info("Sending " + str(num_sends) + " test packets")
512 for i in range(0,num_sends):
513 sendPacket(self, pkt, ingress_port, egress_port,
514 test_timeout)
515
516 # delete flow
517 logging.info("Deleting flow")
518 rc = delete_all_flows(self.controller)
519 self.assertEqual(rc, 0, "Failed to delete all flows")
520
521 # wait for flow_removed message
522 flow_removed, _ = self.controller.poll(
523 exp_msg=ofp.OFPT_FLOW_REMOVED, timeout=test_timeout)
524
525 self.assertTrue(flow_removed != None, "Did not receive flow_removed message")
526 self.assertEqual(flow_removed.cookie, flow_mod_msg.cookie)
527 self.assertEqual(flow_removed.reason, ofp.OFPRR_DELETE)
528 self.assertEqual(flow_removed.packet_count, num_sends)
529 self.assertEqual(flow_removed.byte_count, num_sends * len(str(pkt)))