blob: 8f59ccc5b8bcb19eb374bb466d10f9f25f95d591 [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 Lane32bf9482013-01-03 17:26:30 -0800122 delete_all_flows(self.controller)
Dan Talayco89d57342010-06-07 16:24:59 -0700123
Ken Chiang620bdcc2012-03-23 12:52:07 -0700124 # build packet
Dan Talayco89d57342010-06-07 16:24:59 -0700125 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700126 match = packet_to_flow_match(self, pkt)
Dan Talayco89d57342010-06-07 16:24:59 -0700127 match.wildcards &= ~ofp.OFPFW_IN_PORT
128 self.assertTrue(match is not None,
129 "Could not generate flow match from pkt")
130 act = action.action_output()
131
Ken Chiang620bdcc2012-03-23 12:52:07 -0700132 # build flow
Dan Talayco39bf6912010-07-08 14:17:52 -0700133 ingress_port = of_ports[0];
134 egress_port = of_ports[1];
Rich Lane9a003812012-10-04 17:17:59 -0700135 logging.info("Ingress " + str(ingress_port) +
Dan Talayco89d57342010-06-07 16:24:59 -0700136 " to egress " + str(egress_port))
Ken Chiang620bdcc2012-03-23 12:52:07 -0700137 match.in_port = ingress_port
138 flow_mod_msg = message.flow_mod()
Rich Lanec42dbad2012-10-11 10:57:44 -0700139 flow_mod_msg.match = copy.deepcopy(match)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700140 flow_mod_msg.cookie = random.randint(0,9007199254740992)
141 flow_mod_msg.buffer_id = 0xffffffff
Rich Lanec42dbad2012-10-11 10:57:44 -0700142 flow_mod_msg.idle_timeout = 60000
143 flow_mod_msg.hard_timeout = 65000
144 flow_mod_msg.priority = 100
Ken Chiang620bdcc2012-03-23 12:52:07 -0700145 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800146 flow_mod_msg.actions.add(act)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700147
148 # send flow
Rich Lane9a003812012-10-04 17:17:59 -0700149 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800150 self.controller.message_send(flow_mod_msg)
Rich Lane3a261d52013-01-03 17:45:08 -0800151 do_barrier(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700152
153 # no packets sent, so zero packet count
Rich Lanec42dbad2012-10-11 10:57:44 -0700154 self.verifyStats(flow_mod_msg, match, ofp.OFPP_NONE, test_timeout, 0)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700155
156 # send packet N times
157 num_sends = random.randint(10,20)
Rich Lane9a003812012-10-04 17:17:59 -0700158 logging.info("Sending " + str(num_sends) + " test packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700159 for i in range(0,num_sends):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700160 sendPacket(self, pkt, ingress_port, egress_port,
161 test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700162
Rich Lanec42dbad2012-10-11 10:57:44 -0700163 self.verifyStats(flow_mod_msg, match, ofp.OFPP_NONE, test_timeout, num_sends)
164 self.verifyStats(flow_mod_msg, match, egress_port, test_timeout, num_sends)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700165 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -0700166 match.wildcards = required_wildcards(self) | wc
Rich Lanec42dbad2012-10-11 10:57:44 -0700167 self.verifyStats(flow_mod_msg, match, egress_port, test_timeout, num_sends)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700168
169
Rich Laneb90a1c42012-10-05 09:16:05 -0700170class TwoFlowStats(base_tests.SimpleDataPlane):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700171 """
172 Verify flow stats are properly retrieved.
173
174 Generate two packets and install two matching flows
175 Send some number of packets
176 Send a flow stats request to match the flows and retrieve stats
177 Verify that the packet counter has incremented
178
179 TODO: add a third flow, and then configure the match to exclude
180 that flow?
181 """
182
183 def buildFlowModMsg(self, pkt, ingress_port, egress_port):
Ed Swierk99a74de2012-08-22 06:40:54 -0700184 match = packet_to_flow_match(self, pkt)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700185 match.wildcards &= ~ofp.OFPFW_IN_PORT
186 self.assertTrue(match is not None,
187 "Could not generate flow match from pkt")
Dan Talayco89d57342010-06-07 16:24:59 -0700188 match.in_port = ingress_port
189
190 flow_mod_msg = message.flow_mod()
191 flow_mod_msg.match = match
192 flow_mod_msg.cookie = random.randint(0,9007199254740992)
193 flow_mod_msg.buffer_id = 0xffffffff
Ken Chiang620bdcc2012-03-23 12:52:07 -0700194 flow_mod_msg.idle_timeout = 0
195 flow_mod_msg.hard_timeout = 0
196 act = action.action_output()
Dan Talayco89d57342010-06-07 16:24:59 -0700197 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800198 flow_mod_msg.actions.add(act)
Dan Talayco89d57342010-06-07 16:24:59 -0700199
Rich Lane9a003812012-10-04 17:17:59 -0700200 logging.info("Ingress " + str(ingress_port) +
Ken Chiang620bdcc2012-03-23 12:52:07 -0700201 " to egress " + str(egress_port))
Dan Talayco89d57342010-06-07 16:24:59 -0700202
Ken Chiang620bdcc2012-03-23 12:52:07 -0700203 return flow_mod_msg
Dan Talayco89d57342010-06-07 16:24:59 -0700204
Ken Chiangaa5bc062012-03-31 14:03:28 -0700205 def sumStatsReplyCounts(self, response):
206 total_packets = 0
207 for obj in response.stats:
208 # TODO: pad1 and pad2 fields may be nonzero, is this a bug?
209 # for now, just clear them so the assert is simpler
210 #obj.match.pad1 = 0
211 #obj.match.pad2 = [0, 0]
212 #self.assertEqual(match, obj.match,
213 # "Matches do not match")
Rich Lane9a003812012-10-04 17:17:59 -0700214 logging.info("Received " + str(obj.packet_count)
Ken Chiangaa5bc062012-03-31 14:03:28 -0700215 + " packets")
216 total_packets += obj.packet_count
217 return total_packets
Ken Chiang620bdcc2012-03-23 12:52:07 -0700218
219 def verifyStats(self, match, out_port, test_timeout, packet_count):
220 stat_req = message.flow_stats_request()
221 stat_req.match = match
222 stat_req.table_id = 0xff
223 stat_req.out_port = out_port
224
225 all_packets_received = 0
226 for i in range(0,test_timeout):
Rich Lane9a003812012-10-04 17:17:59 -0700227 logging.info("Sending stats request")
Ken Chiangaa5bc062012-03-31 14:03:28 -0700228 # TODO: move REPLY_MORE handling to controller.transact?
Ken Chiangfb593e72012-03-28 17:19:13 -0700229 response, pkt = self.controller.transact(stat_req,
230 timeout=test_timeout)
231 self.assertTrue(response is not None,
232 "No response to stats request")
Ken Chiangaa5bc062012-03-31 14:03:28 -0700233 total_packets = self.sumStatsReplyCounts(response)
234
235 while response.flags == ofp.OFPSF_REPLY_MORE:
236 response, pkt = self.controller.poll(exp_msg=
237 ofp.OFPT_STATS_REPLY,
238 timeout=test_timeout)
239 total_packets += self.sumStatsReplyCounts(response)
240
Ken Chiang620bdcc2012-03-23 12:52:07 -0700241 if total_packets == packet_count:
242 all_packets_received = 1
243 break
244 sleep(1)
245
246 self.assertTrue(all_packets_received,
Ken Chiangaa5bc062012-03-31 14:03:28 -0700247 "Total stats packet count " + str(total_packets) +
248 " does not match number sent " + str(packet_count))
Ken Chiang620bdcc2012-03-23 12:52:07 -0700249
250 def runTest(self):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700251 # TODO: set from command-line parameter
252 test_timeout = 60
253
Rich Lane477f4812012-10-04 22:49:00 -0700254 of_ports = config["port_map"].keys()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700255 of_ports.sort()
256 self.assertTrue(len(of_ports) >= 3, "Not enough ports for test")
257 ingress_port = of_ports[0];
258 egress_port1 = of_ports[1];
259 egress_port2 = of_ports[2];
260
Rich Lane32bf9482013-01-03 17:26:30 -0800261 delete_all_flows(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700262
263 pkt1 = simple_tcp_packet()
264 flow_mod_msg1 = self.buildFlowModMsg(pkt1, ingress_port, egress_port1)
265
266 pkt2 = simple_tcp_packet(dl_src='0:7:7:7:7:7')
267 flow_mod_msg2 = self.buildFlowModMsg(pkt2, ingress_port, egress_port2)
268
Rich Lane9a003812012-10-04 17:17:59 -0700269 logging.info("Inserting flow1")
Rich Lane5c3151c2013-01-03 17:15:41 -0800270 self.controller.message_send(flow_mod_msg1)
Rich Lane9a003812012-10-04 17:17:59 -0700271 logging.info("Inserting flow2")
Rich Lane5c3151c2013-01-03 17:15:41 -0800272 self.controller.message_send(flow_mod_msg2)
Rich Lane3a261d52013-01-03 17:45:08 -0800273 do_barrier(self.controller)
Dan Talayco89d57342010-06-07 16:24:59 -0700274
Ken Chiang620bdcc2012-03-23 12:52:07 -0700275 num_pkt1s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700276 logging.info("Sending " + str(num_pkt1s) + " pkt1s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700277 num_pkt2s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700278 logging.info("Sending " + str(num_pkt2s) + " pkt2s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700279 for i in range(0,num_pkt1s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700280 sendPacket(self, pkt1, ingress_port, egress_port1, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700281 for i in range(0,num_pkt2s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700282 sendPacket(self, pkt2, ingress_port, egress_port2, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700283
Ed Swierk99a74de2012-08-22 06:40:54 -0700284 match1 = packet_to_flow_match(self, pkt1)
Rich Lane9a003812012-10-04 17:17:59 -0700285 logging.info("Verifying flow1's " + str(num_pkt1s) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700286 self.verifyStats(match1, ofp.OFPP_NONE, test_timeout, num_pkt1s)
Ed Swierk99a74de2012-08-22 06:40:54 -0700287 match2 = packet_to_flow_match(self, pkt2)
Rich Lane9a003812012-10-04 17:17:59 -0700288 logging.info("Verifying flow2's " + str(num_pkt2s) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700289 self.verifyStats(match2, ofp.OFPP_NONE, test_timeout, num_pkt2s)
290 match1.wildcards |= ofp.OFPFW_DL_SRC
Rich Lane9a003812012-10-04 17:17:59 -0700291 logging.info("Verifying combined " + str(num_pkt1s+num_pkt2s) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700292 self.verifyStats(match1, ofp.OFPP_NONE, test_timeout,
293 num_pkt1s+num_pkt2s)
294 # TODO: sweep through the wildcards to verify matching?
295
296
Rich Laneb90a1c42012-10-05 09:16:05 -0700297class AggregateStats(base_tests.SimpleDataPlane):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700298 """
299 Verify aggregate flow stats are properly retrieved.
300
301 Generate two packets
302 Generate and install two matching flows
303 Send an aggregate stats request
304 Verify that aggregate stats are correct
305 Also verify out_port filtering
306 """
307
308 def buildFlowModMsg(self, pkt, ingress_port, egress_port):
Ed Swierk99a74de2012-08-22 06:40:54 -0700309 match = packet_to_flow_match(self, pkt)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700310 match.wildcards &= ~ofp.OFPFW_IN_PORT
311 self.assertTrue(match is not None,
312 "Could not generate flow match from pkt")
313 match.in_port = ingress_port
314
315 flow_mod_msg = message.flow_mod()
316 flow_mod_msg.match = match
317 flow_mod_msg.cookie = random.randint(0,9007199254740992)
318 flow_mod_msg.buffer_id = 0xffffffff
319 flow_mod_msg.idle_timeout = 0
320 flow_mod_msg.hard_timeout = 0
321 act = action.action_output()
322 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800323 flow_mod_msg.actions.add(act)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700324
Rich Lane9a003812012-10-04 17:17:59 -0700325 logging.info("Ingress " + str(ingress_port) +
Ken Chiang620bdcc2012-03-23 12:52:07 -0700326 " to egress " + str(egress_port))
327
328 return flow_mod_msg
329
Ken Chiang620bdcc2012-03-23 12:52:07 -0700330 def verifyAggFlowStats(self, match, out_port, test_timeout,
331 flow_count, packet_count):
332 stat_req = message.aggregate_stats_request()
333 stat_req.match = match
334 stat_req.table_id = 0xff
335 stat_req.out_port = out_port
336
337 all_packets_received = 0
338 for i in range(0,test_timeout):
Rich Lane9a003812012-10-04 17:17:59 -0700339 logging.info("Sending stats request")
Ken Chiangfb593e72012-03-28 17:19:13 -0700340 response, pkt = self.controller.transact(stat_req,
341 timeout=test_timeout)
342 self.assertTrue(response is not None,
343 "No response to stats request")
Dan Talaycoaff26c82012-03-25 15:06:26 -0700344 self.assertTrue(len(response.stats) == 1,
345 "Did not receive flow stats reply")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700346 for obj in response.stats:
347 self.assertTrue(obj.flow_count == flow_count,
348 "Flow count " + str(obj.flow_count) +
349 " does not match expected " + str(flow_count))
Rich Lane9a003812012-10-04 17:17:59 -0700350 logging.info("Received " + str(obj.packet_count) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700351 if obj.packet_count == packet_count:
352 all_packets_received = 1
353
354 if all_packets_received:
355 break
356 sleep(1)
357
358 self.assertTrue(all_packets_received,
359 "Packet count does not match number sent")
360
361 def runTest(self):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700362 # TODO: set from command-line parameter
363 test_timeout = 60
364
Rich Lane477f4812012-10-04 22:49:00 -0700365 of_ports = config["port_map"].keys()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700366 of_ports.sort()
367 self.assertTrue(len(of_ports) >= 3, "Not enough ports for test")
368 ingress_port = of_ports[0];
369 egress_port1 = of_ports[1];
370 egress_port2 = of_ports[2];
371
Rich Lane32bf9482013-01-03 17:26:30 -0800372 delete_all_flows(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700373
374 pkt1 = simple_tcp_packet()
375 flow_mod_msg1 = self.buildFlowModMsg(pkt1, ingress_port, egress_port1)
376
377 pkt2 = simple_tcp_packet(dl_src='0:7:7:7:7:7')
378 flow_mod_msg2 = self.buildFlowModMsg(pkt2, ingress_port, egress_port2)
379
Rich Lane9a003812012-10-04 17:17:59 -0700380 logging.info("Inserting flow1")
Rich Lane5c3151c2013-01-03 17:15:41 -0800381 self.controller.message_send(flow_mod_msg1)
Rich Lane9a003812012-10-04 17:17:59 -0700382 logging.info("Inserting flow2")
Rich Lane5c3151c2013-01-03 17:15:41 -0800383 self.controller.message_send(flow_mod_msg2)
Rich Lane3a261d52013-01-03 17:45:08 -0800384 do_barrier(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700385
386 num_pkt1s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700387 logging.info("Sending " + str(num_pkt1s) + " pkt1s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700388 num_pkt2s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700389 logging.info("Sending " + str(num_pkt2s) + " pkt2s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700390 for i in range(0,num_pkt1s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700391 sendPacket(self, pkt1, ingress_port, egress_port1, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700392 for i in range(0,num_pkt2s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700393 sendPacket(self, pkt2, ingress_port, egress_port2, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700394
395 # loop on flow stats request until timeout
Ed Swierk99a74de2012-08-22 06:40:54 -0700396 match = packet_to_flow_match(self, pkt1)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700397 match.wildcards |= ofp.OFPFW_DL_SRC
398 self.verifyAggFlowStats(match, ofp.OFPP_NONE, test_timeout,
399 2, num_pkt1s+num_pkt2s)
400
401 # out_port filter for egress_port1
402 self.verifyAggFlowStats(match, egress_port1, test_timeout,
403 1, num_pkt1s)
404
405 # out_port filter for egress_port1
406 self.verifyAggFlowStats(match, egress_port2, test_timeout,
407 1, num_pkt2s)
Rich Lane97a5f502012-10-11 09:28:11 -0700408
Rich Lanef062b3d2012-10-11 09:53:19 -0700409class EmptyFlowStats(base_tests.SimpleDataPlane):
410 """
411 Verify the switch replies to a flow stats request when
412 the query doesn't match any flows.
413 """
414 def runTest(self):
Rich Lane32bf9482013-01-03 17:26:30 -0800415 delete_all_flows(self.controller)
Rich Lanef062b3d2012-10-11 09:53:19 -0700416 match = ofp.ofp_match()
417 match.wildcards = 0
418 stat_req = message.flow_stats_request()
419 stat_req.match = match
420 stat_req.table_id = 0xff
421 stat_req.out_port = ofp.OFPP_NONE
422
423 response, pkt = self.controller.transact(stat_req)
424 self.assertTrue(response is not None,
425 "No response to stats request")
426 self.assertEquals(len(response.stats), 0)
427 self.assertEquals(response.flags, 0)
428
Rich Lane97a5f502012-10-11 09:28:11 -0700429class EmptyAggregateStats(base_tests.SimpleDataPlane):
430 """
431 Verify aggregate flow stats are properly retrieved when
432 the query doesn't match any flows.
433 """
434 def runTest(self):
Rich Lane32bf9482013-01-03 17:26:30 -0800435 delete_all_flows(self.controller)
Rich Lane97a5f502012-10-11 09:28:11 -0700436 match = ofp.ofp_match()
437 match.wildcards = 0
438 stat_req = message.aggregate_stats_request()
439 stat_req.match = match
440 stat_req.table_id = 0xff
441 stat_req.out_port = ofp.OFPP_NONE
442
443 response, pkt = self.controller.transact(stat_req)
444 self.assertTrue(response is not None,
445 "No response to stats request")
446 self.assertTrue(len(response.stats) == 1,
447 "Did not receive flow stats reply")
448 self.assertEquals(response.stats[0].flow_count, 0)
449 self.assertEquals(response.stats[0].packet_count, 0)
450 self.assertEquals(response.stats[0].byte_count, 0)
Rich Laned10e8e02012-11-21 15:48:36 -0800451
452class DeletedFlowStats(base_tests.SimpleDataPlane):
453 """
454 Verify flow stats are properly returned when a flow is deleted.
455
456 Generate a packet
457 Generate and install a matching flow
458 Send the packet
459 Delete the flow
460 Verify that the flow_removed message has the correct stats
461 """
462
463 def runTest(self):
464 # TODO: set from command-line parameter
465 test_timeout = 60
466
467 of_ports = config["port_map"].keys()
468 of_ports.sort()
469 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
470
Rich Lane32bf9482013-01-03 17:26:30 -0800471 delete_all_flows(self.controller)
Rich Laned10e8e02012-11-21 15:48:36 -0800472
473 # build packet
474 pkt = simple_tcp_packet()
475 match = packet_to_flow_match(self, pkt)
476 match.wildcards &= ~ofp.OFPFW_IN_PORT
477 self.assertTrue(match is not None,
478 "Could not generate flow match from pkt")
479 act = action.action_output()
480
481 # build flow
482 ingress_port = of_ports[0];
483 egress_port = of_ports[1];
484 logging.info("Ingress " + str(ingress_port) +
485 " to egress " + str(egress_port))
486 match.in_port = ingress_port
487 flow_mod_msg = message.flow_mod()
488 flow_mod_msg.match = copy.deepcopy(match)
489 flow_mod_msg.cookie = random.randint(0,9007199254740992)
490 flow_mod_msg.buffer_id = 0xffffffff
491 flow_mod_msg.idle_timeout = 0
492 flow_mod_msg.hard_timeout = 0
493 flow_mod_msg.priority = 100
494 flow_mod_msg.flags = ofp.OFPFF_SEND_FLOW_REM
495 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800496 flow_mod_msg.actions.add(act)
Rich Laned10e8e02012-11-21 15:48:36 -0800497
498 # send flow
499 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800500 self.controller.message_send(flow_mod_msg)
Rich Lane3a261d52013-01-03 17:45:08 -0800501 do_barrier(self.controller)
Rich Laned10e8e02012-11-21 15:48:36 -0800502
503 # send packet N times
504 num_sends = random.randint(10,20)
505 logging.info("Sending " + str(num_sends) + " test packets")
506 for i in range(0,num_sends):
507 sendPacket(self, pkt, ingress_port, egress_port,
508 test_timeout)
509
510 # delete flow
511 logging.info("Deleting flow")
Rich Lane32bf9482013-01-03 17:26:30 -0800512 delete_all_flows(self.controller)
Rich Laned10e8e02012-11-21 15:48:36 -0800513
514 # wait for flow_removed message
515 flow_removed, _ = self.controller.poll(
516 exp_msg=ofp.OFPT_FLOW_REMOVED, timeout=test_timeout)
517
518 self.assertTrue(flow_removed != None, "Did not receive flow_removed message")
519 self.assertEqual(flow_removed.cookie, flow_mod_msg.cookie)
520 self.assertEqual(flow_removed.reason, ofp.OFPRR_DELETE)
521 self.assertEqual(flow_removed.packet_count, num_sends)
522 self.assertEqual(flow_removed.byte_count, num_sends * len(str(pkt)))