blob: ff33948969b0e6eb7173772c46f27e4438b0d3fe [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
Rich Laned7b0ffa2013-03-08 15:53:42 -080015import ofp
Dan Talayco89d57342010-06-07 16:24:59 -070016import oftest.dataplane as dataplane
Dan Talayco89d57342010-06-07 16:24:59 -070017import oftest.parse as parse
Rich Laneb90a1c42012-10-05 09:16:05 -070018import oftest.base_tests as base_tests
Dan Talayco89d57342010-06-07 16:24:59 -070019
Rich Laneda3b5ad2012-10-03 09:05:32 -070020from oftest.testutils import *
Dan Talayco89d57342010-06-07 16:24:59 -070021from time import sleep
22
Ken Chiang620bdcc2012-03-23 12:52:07 -070023# TODO: ovs has problems with VLAN id?
24WILDCARD_VALUES = [ofp.OFPFW_IN_PORT,
Dan Talayco488fbc52012-04-09 16:30:41 -070025 # (ofp.OFPFW_DL_VLAN | ofp.OFPFW_DL_VLAN_PCP),
Ken Chiang620bdcc2012-03-23 12:52:07 -070026 ofp.OFPFW_DL_SRC,
27 ofp.OFPFW_DL_DST,
Dan Talayco488fbc52012-04-09 16:30:41 -070028 (ofp.OFPFW_DL_TYPE | ofp.OFPFW_NW_SRC_ALL |
29 ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS | ofp.OFPFW_NW_PROTO |
30 ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
31 (ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
Ken Chiang620bdcc2012-03-23 12:52:07 -070032 ofp.OFPFW_TP_SRC,
33 ofp.OFPFW_TP_DST,
Dan Talayco488fbc52012-04-09 16:30:41 -070034 ofp.OFPFW_NW_SRC_MASK,
35 ofp.OFPFW_NW_DST_MASK,
Ken Chiang620bdcc2012-03-23 12:52:07 -070036 ofp.OFPFW_DL_VLAN_PCP,
37 ofp.OFPFW_NW_TOS]
38
Ken Chiangaa5bc062012-03-31 14:03:28 -070039def sendPacket(obj, pkt, ingress_port, egress_port, test_timeout):
40
Rich Lane9a003812012-10-04 17:17:59 -070041 logging.info("Sending packet to dp port " + str(ingress_port) +
Ken Chiangaa5bc062012-03-31 14:03:28 -070042 ", expecting output on " + str(egress_port))
43 obj.dataplane.send(ingress_port, str(pkt))
44
45 exp_pkt_arg = None
46 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -070047 if config["relax"]:
Ken Chiangaa5bc062012-03-31 14:03:28 -070048 exp_pkt_arg = pkt
49 exp_port = egress_port
50
Rich Lanec8aaa3e2012-07-26 19:28:02 -070051 (rcv_port, rcv_pkt, pkt_time) = obj.dataplane.poll(port_number=exp_port,
Ken Chiangaa5bc062012-03-31 14:03:28 -070052 exp_pkt=exp_pkt_arg)
53 obj.assertTrue(rcv_pkt is not None,
54 "Packet not received on port " + str(egress_port))
Rich Lane9a003812012-10-04 17:17:59 -070055 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Ken Chiangaa5bc062012-03-31 14:03:28 -070056 str(rcv_port))
57 obj.assertEqual(rcv_port, egress_port,
58 "Packet received on port " + str(rcv_port) +
59 ", expected port " + str(egress_port))
60 obj.assertEqual(str(pkt), str(rcv_pkt),
61 'Response packet does not match send packet')
62
Rich Laneb90a1c42012-10-05 09:16:05 -070063class SingleFlowStats(base_tests.SimpleDataPlane):
Dan Talayco89d57342010-06-07 16:24:59 -070064 """
65 Verify flow stats are properly retrieved.
66
67 Generate a packet
Ken Chiang620bdcc2012-03-23 12:52:07 -070068 Generate and install a matching flow
69 Send the packet
70 Send a flow stats request to match the flow and retrieve stats
71 Verify that the packet counter has incremented
Dan Talayco89d57342010-06-07 16:24:59 -070072 """
Ken Chiang620bdcc2012-03-23 12:52:07 -070073
Rich Lanec42dbad2012-10-11 10:57:44 -070074 def verifyStats(self, flow_mod_msg, match, out_port, test_timeout, packet_count):
Rich Lane28fa9272013-03-08 16:00:25 -080075 stat_req = ofp.message.flow_stats_request()
Ken Chiang620bdcc2012-03-23 12:52:07 -070076 stat_req.match = match
77 stat_req.table_id = 0xff
78 stat_req.out_port = out_port
79
80 all_packets_received = 0
81 for i in range(0,test_timeout):
Rich Lane9a003812012-10-04 17:17:59 -070082 logging.info("Sending stats request")
Ken Chiangfb593e72012-03-28 17:19:13 -070083 response, pkt = self.controller.transact(stat_req,
84 timeout=test_timeout)
85 self.assertTrue(response is not None,
86 "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -070087 self.assertTrue(len(response.entries) == 1,
Ken Chiangfb593e72012-03-28 17:19:13 -070088 "Did not receive flow stats reply")
Rich Lane5fd6faf2013-03-11 13:30:20 -070089 for obj in response.entries:
Ken Chiang620bdcc2012-03-23 12:52:07 -070090 # TODO: pad1 and pad2 fields may be nonzero, is this a bug?
91 # for now, just clear them so the assert is simpler
Rich Lanec42dbad2012-10-11 10:57:44 -070092 obj.match.pad1 = 0
93 obj.match.pad2 = [0, 0]
94 self.assertEqual(flow_mod_msg.match, obj.match,
95 "Matches do not match")
96 self.assertEqual(obj.cookie, flow_mod_msg.cookie)
97 self.assertEqual(obj.priority, flow_mod_msg.priority)
98 self.assertEqual(obj.idle_timeout, flow_mod_msg.idle_timeout)
99 self.assertEqual(obj.hard_timeout, flow_mod_msg.hard_timeout)
100 self.assertEqual(obj.actions, flow_mod_msg.actions)
Rich Lane9a003812012-10-04 17:17:59 -0700101 logging.info("Received " + str(obj.packet_count) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700102 if obj.packet_count == packet_count:
103 all_packets_received = 1
104
105 if all_packets_received:
106 break
107 sleep(1)
108
109 self.assertTrue(all_packets_received,
110 "Packet count does not match number sent")
111
Dan Talayco89d57342010-06-07 16:24:59 -0700112 def runTest(self):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700113 # TODO: set from command-line parameter
114 test_timeout = 60
115
Rich Lane477f4812012-10-04 22:49:00 -0700116 of_ports = config["port_map"].keys()
Dan Talayco89d57342010-06-07 16:24:59 -0700117 of_ports.sort()
118 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
119
Rich Lane32bf9482013-01-03 17:26:30 -0800120 delete_all_flows(self.controller)
Dan Talayco89d57342010-06-07 16:24:59 -0700121
Ken Chiang620bdcc2012-03-23 12:52:07 -0700122 # build packet
Dan Talayco89d57342010-06-07 16:24:59 -0700123 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700124 match = packet_to_flow_match(self, pkt)
Dan Talayco89d57342010-06-07 16:24:59 -0700125 match.wildcards &= ~ofp.OFPFW_IN_PORT
126 self.assertTrue(match is not None,
127 "Could not generate flow match from pkt")
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800128 act = ofp.action.output()
Dan Talayco89d57342010-06-07 16:24:59 -0700129
Ken Chiang620bdcc2012-03-23 12:52:07 -0700130 # build flow
Dan Talayco39bf6912010-07-08 14:17:52 -0700131 ingress_port = of_ports[0];
132 egress_port = of_ports[1];
Rich Lane9a003812012-10-04 17:17:59 -0700133 logging.info("Ingress " + str(ingress_port) +
Dan Talayco89d57342010-06-07 16:24:59 -0700134 " to egress " + str(egress_port))
Ken Chiang620bdcc2012-03-23 12:52:07 -0700135 match.in_port = ingress_port
Rich Laneba3f0e22013-03-11 16:43:57 -0700136 flow_mod_msg = ofp.message.flow_add()
Rich Lanec42dbad2012-10-11 10:57:44 -0700137 flow_mod_msg.match = copy.deepcopy(match)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700138 flow_mod_msg.cookie = random.randint(0,9007199254740992)
139 flow_mod_msg.buffer_id = 0xffffffff
Rich Lanec42dbad2012-10-11 10:57:44 -0700140 flow_mod_msg.idle_timeout = 60000
141 flow_mod_msg.hard_timeout = 65000
142 flow_mod_msg.priority = 100
Ken Chiang620bdcc2012-03-23 12:52:07 -0700143 act.port = egress_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800144 flow_mod_msg.actions.append(act)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700145
146 # send flow
Rich Lane9a003812012-10-04 17:17:59 -0700147 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800148 self.controller.message_send(flow_mod_msg)
Rich Lane3a261d52013-01-03 17:45:08 -0800149 do_barrier(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700150
151 # no packets sent, so zero packet count
Rich Lanec42dbad2012-10-11 10:57:44 -0700152 self.verifyStats(flow_mod_msg, match, ofp.OFPP_NONE, test_timeout, 0)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700153
154 # send packet N times
155 num_sends = random.randint(10,20)
Rich Lane9a003812012-10-04 17:17:59 -0700156 logging.info("Sending " + str(num_sends) + " test packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700157 for i in range(0,num_sends):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700158 sendPacket(self, pkt, ingress_port, egress_port,
159 test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700160
Rich Lanec42dbad2012-10-11 10:57:44 -0700161 self.verifyStats(flow_mod_msg, match, ofp.OFPP_NONE, test_timeout, num_sends)
162 self.verifyStats(flow_mod_msg, match, egress_port, test_timeout, num_sends)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700163 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -0700164 match.wildcards = required_wildcards(self) | wc
Rich Lanec42dbad2012-10-11 10:57:44 -0700165 self.verifyStats(flow_mod_msg, match, egress_port, test_timeout, num_sends)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700166
167
Rich Laneb90a1c42012-10-05 09:16:05 -0700168class TwoFlowStats(base_tests.SimpleDataPlane):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700169 """
170 Verify flow stats are properly retrieved.
171
172 Generate two packets and install two matching flows
173 Send some number of packets
174 Send a flow stats request to match the flows and retrieve stats
175 Verify that the packet counter has incremented
176
177 TODO: add a third flow, and then configure the match to exclude
178 that flow?
179 """
180
181 def buildFlowModMsg(self, pkt, ingress_port, egress_port):
Ed Swierk99a74de2012-08-22 06:40:54 -0700182 match = packet_to_flow_match(self, pkt)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700183 match.wildcards &= ~ofp.OFPFW_IN_PORT
184 self.assertTrue(match is not None,
185 "Could not generate flow match from pkt")
Dan Talayco89d57342010-06-07 16:24:59 -0700186 match.in_port = ingress_port
187
Rich Laneba3f0e22013-03-11 16:43:57 -0700188 flow_mod_msg = ofp.message.flow_add()
Dan Talayco89d57342010-06-07 16:24:59 -0700189 flow_mod_msg.match = match
190 flow_mod_msg.cookie = random.randint(0,9007199254740992)
191 flow_mod_msg.buffer_id = 0xffffffff
Ken Chiang620bdcc2012-03-23 12:52:07 -0700192 flow_mod_msg.idle_timeout = 0
193 flow_mod_msg.hard_timeout = 0
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800194 act = ofp.action.output()
Dan Talayco89d57342010-06-07 16:24:59 -0700195 act.port = egress_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800196 flow_mod_msg.actions.append(act)
Dan Talayco89d57342010-06-07 16:24:59 -0700197
Rich Lane9a003812012-10-04 17:17:59 -0700198 logging.info("Ingress " + str(ingress_port) +
Ken Chiang620bdcc2012-03-23 12:52:07 -0700199 " to egress " + str(egress_port))
Dan Talayco89d57342010-06-07 16:24:59 -0700200
Ken Chiang620bdcc2012-03-23 12:52:07 -0700201 return flow_mod_msg
Dan Talayco89d57342010-06-07 16:24:59 -0700202
Ken Chiangaa5bc062012-03-31 14:03:28 -0700203 def sumStatsReplyCounts(self, response):
204 total_packets = 0
Rich Lane5fd6faf2013-03-11 13:30:20 -0700205 for obj in response.entries:
Ken Chiangaa5bc062012-03-31 14:03:28 -0700206 # TODO: pad1 and pad2 fields may be nonzero, is this a bug?
207 # for now, just clear them so the assert is simpler
208 #obj.match.pad1 = 0
209 #obj.match.pad2 = [0, 0]
210 #self.assertEqual(match, obj.match,
211 # "Matches do not match")
Rich Lane9a003812012-10-04 17:17:59 -0700212 logging.info("Received " + str(obj.packet_count)
Ken Chiangaa5bc062012-03-31 14:03:28 -0700213 + " packets")
214 total_packets += obj.packet_count
215 return total_packets
Ken Chiang620bdcc2012-03-23 12:52:07 -0700216
217 def verifyStats(self, match, out_port, test_timeout, packet_count):
Rich Lane28fa9272013-03-08 16:00:25 -0800218 stat_req = ofp.message.flow_stats_request()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700219 stat_req.match = match
220 stat_req.table_id = 0xff
221 stat_req.out_port = out_port
222
223 all_packets_received = 0
224 for i in range(0,test_timeout):
Rich Lane9a003812012-10-04 17:17:59 -0700225 logging.info("Sending stats request")
Ken Chiangaa5bc062012-03-31 14:03:28 -0700226 # TODO: move REPLY_MORE handling to controller.transact?
Ken Chiangfb593e72012-03-28 17:19:13 -0700227 response, pkt = self.controller.transact(stat_req,
228 timeout=test_timeout)
229 self.assertTrue(response is not None,
230 "No response to stats request")
Ken Chiangaa5bc062012-03-31 14:03:28 -0700231 total_packets = self.sumStatsReplyCounts(response)
232
233 while response.flags == ofp.OFPSF_REPLY_MORE:
234 response, pkt = self.controller.poll(exp_msg=
235 ofp.OFPT_STATS_REPLY,
236 timeout=test_timeout)
237 total_packets += self.sumStatsReplyCounts(response)
238
Ken Chiang620bdcc2012-03-23 12:52:07 -0700239 if total_packets == packet_count:
240 all_packets_received = 1
241 break
242 sleep(1)
243
244 self.assertTrue(all_packets_received,
Ken Chiangaa5bc062012-03-31 14:03:28 -0700245 "Total stats packet count " + str(total_packets) +
246 " does not match number sent " + str(packet_count))
Ken Chiang620bdcc2012-03-23 12:52:07 -0700247
248 def runTest(self):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700249 # TODO: set from command-line parameter
250 test_timeout = 60
251
Rich Lane477f4812012-10-04 22:49:00 -0700252 of_ports = config["port_map"].keys()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700253 of_ports.sort()
254 self.assertTrue(len(of_ports) >= 3, "Not enough ports for test")
255 ingress_port = of_ports[0];
256 egress_port1 = of_ports[1];
257 egress_port2 = of_ports[2];
258
Rich Lane32bf9482013-01-03 17:26:30 -0800259 delete_all_flows(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700260
261 pkt1 = simple_tcp_packet()
262 flow_mod_msg1 = self.buildFlowModMsg(pkt1, ingress_port, egress_port1)
263
Rich Laned0478ff2013-03-11 12:46:58 -0700264 pkt2 = simple_tcp_packet(eth_src='0:7:7:7:7:7')
Ken Chiang620bdcc2012-03-23 12:52:07 -0700265 flow_mod_msg2 = self.buildFlowModMsg(pkt2, ingress_port, egress_port2)
266
Rich Lane9a003812012-10-04 17:17:59 -0700267 logging.info("Inserting flow1")
Rich Lane5c3151c2013-01-03 17:15:41 -0800268 self.controller.message_send(flow_mod_msg1)
Rich Lane9a003812012-10-04 17:17:59 -0700269 logging.info("Inserting flow2")
Rich Lane5c3151c2013-01-03 17:15:41 -0800270 self.controller.message_send(flow_mod_msg2)
Rich Lane3a261d52013-01-03 17:45:08 -0800271 do_barrier(self.controller)
Dan Talayco89d57342010-06-07 16:24:59 -0700272
Ken Chiang620bdcc2012-03-23 12:52:07 -0700273 num_pkt1s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700274 logging.info("Sending " + str(num_pkt1s) + " pkt1s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700275 num_pkt2s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700276 logging.info("Sending " + str(num_pkt2s) + " pkt2s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700277 for i in range(0,num_pkt1s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700278 sendPacket(self, pkt1, ingress_port, egress_port1, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700279 for i in range(0,num_pkt2s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700280 sendPacket(self, pkt2, ingress_port, egress_port2, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700281
Ed Swierk99a74de2012-08-22 06:40:54 -0700282 match1 = packet_to_flow_match(self, pkt1)
Rich Lane9a003812012-10-04 17:17:59 -0700283 logging.info("Verifying flow1's " + str(num_pkt1s) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700284 self.verifyStats(match1, ofp.OFPP_NONE, test_timeout, num_pkt1s)
Ed Swierk99a74de2012-08-22 06:40:54 -0700285 match2 = packet_to_flow_match(self, pkt2)
Rich Lane9a003812012-10-04 17:17:59 -0700286 logging.info("Verifying flow2's " + str(num_pkt2s) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700287 self.verifyStats(match2, ofp.OFPP_NONE, test_timeout, num_pkt2s)
288 match1.wildcards |= ofp.OFPFW_DL_SRC
Rich Lane9a003812012-10-04 17:17:59 -0700289 logging.info("Verifying combined " + str(num_pkt1s+num_pkt2s) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700290 self.verifyStats(match1, ofp.OFPP_NONE, test_timeout,
291 num_pkt1s+num_pkt2s)
292 # TODO: sweep through the wildcards to verify matching?
293
294
Rich Laneb90a1c42012-10-05 09:16:05 -0700295class AggregateStats(base_tests.SimpleDataPlane):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700296 """
297 Verify aggregate flow stats are properly retrieved.
298
299 Generate two packets
300 Generate and install two matching flows
301 Send an aggregate stats request
302 Verify that aggregate stats are correct
303 Also verify out_port filtering
304 """
305
306 def buildFlowModMsg(self, pkt, ingress_port, egress_port):
Ed Swierk99a74de2012-08-22 06:40:54 -0700307 match = packet_to_flow_match(self, pkt)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700308 match.wildcards &= ~ofp.OFPFW_IN_PORT
309 self.assertTrue(match is not None,
310 "Could not generate flow match from pkt")
311 match.in_port = ingress_port
312
Rich Laneba3f0e22013-03-11 16:43:57 -0700313 flow_mod_msg = ofp.message.flow_add()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700314 flow_mod_msg.match = match
315 flow_mod_msg.cookie = random.randint(0,9007199254740992)
316 flow_mod_msg.buffer_id = 0xffffffff
317 flow_mod_msg.idle_timeout = 0
318 flow_mod_msg.hard_timeout = 0
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800319 act = ofp.action.output()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700320 act.port = egress_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800321 flow_mod_msg.actions.append(act)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700322
Rich Lane9a003812012-10-04 17:17:59 -0700323 logging.info("Ingress " + str(ingress_port) +
Ken Chiang620bdcc2012-03-23 12:52:07 -0700324 " to egress " + str(egress_port))
325
326 return flow_mod_msg
327
Ken Chiang620bdcc2012-03-23 12:52:07 -0700328 def verifyAggFlowStats(self, match, out_port, test_timeout,
329 flow_count, packet_count):
Rich Lane28fa9272013-03-08 16:00:25 -0800330 stat_req = ofp.message.aggregate_stats_request()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700331 stat_req.match = match
332 stat_req.table_id = 0xff
333 stat_req.out_port = out_port
334
335 all_packets_received = 0
336 for i in range(0,test_timeout):
Rich Lane9a003812012-10-04 17:17:59 -0700337 logging.info("Sending stats request")
Ken Chiangfb593e72012-03-28 17:19:13 -0700338 response, pkt = self.controller.transact(stat_req,
339 timeout=test_timeout)
340 self.assertTrue(response is not None,
341 "No response to stats request")
Rich Lane032669d2013-03-11 23:36:28 -0700342 self.assertTrue(response.flow_count == flow_count,
343 "Flow count " + str(response.flow_count) +
344 " does not match expected " + str(flow_count))
345 logging.info("Received " + str(response.packet_count) + " packets")
346 if response.packet_count == packet_count:
347 all_packets_received = 1
Ken Chiang620bdcc2012-03-23 12:52:07 -0700348
349 if all_packets_received:
350 break
351 sleep(1)
352
353 self.assertTrue(all_packets_received,
354 "Packet count does not match number sent")
355
356 def runTest(self):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700357 # TODO: set from command-line parameter
358 test_timeout = 60
359
Rich Lane477f4812012-10-04 22:49:00 -0700360 of_ports = config["port_map"].keys()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700361 of_ports.sort()
362 self.assertTrue(len(of_ports) >= 3, "Not enough ports for test")
363 ingress_port = of_ports[0];
364 egress_port1 = of_ports[1];
365 egress_port2 = of_ports[2];
366
Rich Lane32bf9482013-01-03 17:26:30 -0800367 delete_all_flows(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700368
369 pkt1 = simple_tcp_packet()
370 flow_mod_msg1 = self.buildFlowModMsg(pkt1, ingress_port, egress_port1)
371
Rich Laned0478ff2013-03-11 12:46:58 -0700372 pkt2 = simple_tcp_packet(eth_src='0:7:7:7:7:7')
Ken Chiang620bdcc2012-03-23 12:52:07 -0700373 flow_mod_msg2 = self.buildFlowModMsg(pkt2, ingress_port, egress_port2)
374
Rich Lane9a003812012-10-04 17:17:59 -0700375 logging.info("Inserting flow1")
Rich Lane5c3151c2013-01-03 17:15:41 -0800376 self.controller.message_send(flow_mod_msg1)
Rich Lane9a003812012-10-04 17:17:59 -0700377 logging.info("Inserting flow2")
Rich Lane5c3151c2013-01-03 17:15:41 -0800378 self.controller.message_send(flow_mod_msg2)
Rich Lane3a261d52013-01-03 17:45:08 -0800379 do_barrier(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700380
381 num_pkt1s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700382 logging.info("Sending " + str(num_pkt1s) + " pkt1s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700383 num_pkt2s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700384 logging.info("Sending " + str(num_pkt2s) + " pkt2s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700385 for i in range(0,num_pkt1s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700386 sendPacket(self, pkt1, ingress_port, egress_port1, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700387 for i in range(0,num_pkt2s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700388 sendPacket(self, pkt2, ingress_port, egress_port2, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700389
390 # loop on flow stats request until timeout
Ed Swierk99a74de2012-08-22 06:40:54 -0700391 match = packet_to_flow_match(self, pkt1)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700392 match.wildcards |= ofp.OFPFW_DL_SRC
393 self.verifyAggFlowStats(match, ofp.OFPP_NONE, test_timeout,
394 2, num_pkt1s+num_pkt2s)
395
396 # out_port filter for egress_port1
397 self.verifyAggFlowStats(match, egress_port1, test_timeout,
398 1, num_pkt1s)
399
400 # out_port filter for egress_port1
401 self.verifyAggFlowStats(match, egress_port2, test_timeout,
402 1, num_pkt2s)
Rich Lane97a5f502012-10-11 09:28:11 -0700403
Rich Lanef062b3d2012-10-11 09:53:19 -0700404class EmptyFlowStats(base_tests.SimpleDataPlane):
405 """
406 Verify the switch replies to a flow stats request when
407 the query doesn't match any flows.
408 """
409 def runTest(self):
Rich Lane32bf9482013-01-03 17:26:30 -0800410 delete_all_flows(self.controller)
Rich Lane0237baf2013-03-11 22:34:59 -0700411 match = ofp.match()
Rich Lanef062b3d2012-10-11 09:53:19 -0700412 match.wildcards = 0
Rich Lane28fa9272013-03-08 16:00:25 -0800413 stat_req = ofp.message.flow_stats_request()
Rich Lanef062b3d2012-10-11 09:53:19 -0700414 stat_req.match = match
415 stat_req.table_id = 0xff
416 stat_req.out_port = ofp.OFPP_NONE
417
418 response, pkt = self.controller.transact(stat_req)
419 self.assertTrue(response is not None,
420 "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -0700421 self.assertEquals(len(response.entries), 0)
Rich Lanef062b3d2012-10-11 09:53:19 -0700422 self.assertEquals(response.flags, 0)
423
Rich Lane97a5f502012-10-11 09:28:11 -0700424class EmptyAggregateStats(base_tests.SimpleDataPlane):
425 """
426 Verify aggregate flow stats are properly retrieved when
427 the query doesn't match any flows.
428 """
429 def runTest(self):
Rich Lane32bf9482013-01-03 17:26:30 -0800430 delete_all_flows(self.controller)
Rich Lane0237baf2013-03-11 22:34:59 -0700431 match = ofp.match()
Rich Lane97a5f502012-10-11 09:28:11 -0700432 match.wildcards = 0
Rich Lane28fa9272013-03-08 16:00:25 -0800433 stat_req = ofp.message.aggregate_stats_request()
Rich Lane97a5f502012-10-11 09:28:11 -0700434 stat_req.match = match
435 stat_req.table_id = 0xff
436 stat_req.out_port = ofp.OFPP_NONE
437
438 response, pkt = self.controller.transact(stat_req)
439 self.assertTrue(response is not None,
440 "No response to stats request")
Rich Lane032669d2013-03-11 23:36:28 -0700441 self.assertEquals(response.flow_count, 0)
442 self.assertEquals(response.packet_count, 0)
443 self.assertEquals(response.byte_count, 0)
Rich Laned10e8e02012-11-21 15:48:36 -0800444
445class DeletedFlowStats(base_tests.SimpleDataPlane):
446 """
447 Verify flow stats are properly returned when a flow is deleted.
448
449 Generate a packet
450 Generate and install a matching flow
451 Send the packet
452 Delete the flow
453 Verify that the flow_removed message has the correct stats
454 """
455
456 def runTest(self):
457 # TODO: set from command-line parameter
458 test_timeout = 60
459
460 of_ports = config["port_map"].keys()
461 of_ports.sort()
462 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
463
Rich Lane32bf9482013-01-03 17:26:30 -0800464 delete_all_flows(self.controller)
Rich Laned10e8e02012-11-21 15:48:36 -0800465
466 # build packet
467 pkt = simple_tcp_packet()
468 match = packet_to_flow_match(self, pkt)
469 match.wildcards &= ~ofp.OFPFW_IN_PORT
470 self.assertTrue(match is not None,
471 "Could not generate flow match from pkt")
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800472 act = ofp.action.output()
Rich Laned10e8e02012-11-21 15:48:36 -0800473
474 # build flow
475 ingress_port = of_ports[0];
476 egress_port = of_ports[1];
477 logging.info("Ingress " + str(ingress_port) +
478 " to egress " + str(egress_port))
479 match.in_port = ingress_port
Rich Laneba3f0e22013-03-11 16:43:57 -0700480 flow_mod_msg = ofp.message.flow_add()
Rich Laned10e8e02012-11-21 15:48:36 -0800481 flow_mod_msg.match = copy.deepcopy(match)
482 flow_mod_msg.cookie = random.randint(0,9007199254740992)
483 flow_mod_msg.buffer_id = 0xffffffff
484 flow_mod_msg.idle_timeout = 0
485 flow_mod_msg.hard_timeout = 0
486 flow_mod_msg.priority = 100
487 flow_mod_msg.flags = ofp.OFPFF_SEND_FLOW_REM
488 act.port = egress_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800489 flow_mod_msg.actions.append(act)
Rich Laned10e8e02012-11-21 15:48:36 -0800490
491 # send flow
492 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800493 self.controller.message_send(flow_mod_msg)
Rich Lane3a261d52013-01-03 17:45:08 -0800494 do_barrier(self.controller)
Rich Laned10e8e02012-11-21 15:48:36 -0800495
496 # send packet N times
497 num_sends = random.randint(10,20)
498 logging.info("Sending " + str(num_sends) + " test packets")
499 for i in range(0,num_sends):
500 sendPacket(self, pkt, ingress_port, egress_port,
501 test_timeout)
502
Ken Chiang626ce1d2013-01-09 11:58:50 -0800503 # wait some time for flow stats to be propagated
504 # FIXME timeout handling should be unified
505 sleep(test_param_get('default_timeout', default=2))
506
Rich Laned10e8e02012-11-21 15:48:36 -0800507 # delete flow
508 logging.info("Deleting flow")
Rich Lane32bf9482013-01-03 17:26:30 -0800509 delete_all_flows(self.controller)
Rich Laned10e8e02012-11-21 15:48:36 -0800510
511 # wait for flow_removed message
512 flow_removed, _ = self.controller.poll(
513 exp_msg=ofp.OFPT_FLOW_REMOVED, timeout=test_timeout)
514
515 self.assertTrue(flow_removed != None, "Did not receive flow_removed message")
Ken Chiang626ce1d2013-01-09 11:58:50 -0800516 self.assertEqual(flow_removed.cookie, flow_mod_msg.cookie,
517 "Received cookie " + str(flow_removed.cookie) +
518 " does not match expected " + str(flow_mod_msg.cookie))
519 self.assertEqual(flow_removed.reason, ofp.OFPRR_DELETE,
520 "Received reason " + str(flow_removed.reason) +
521 " does not match expected " + str(ofp.OFPRR_DELETE))
522 self.assertEqual(flow_removed.packet_count, num_sends,
523 "Received packet count " + str(flow_removed.packet_count) +
524 " does not match expected " + str(num_sends))
525 tolerance = 5 # percent
526 self.assertTrue(flow_removed.byte_count >=
527 (1-tolerance/100.0) * num_sends * len(str(pkt)) and
528 flow_removed.byte_count <=
529 (1+tolerance/100.0) * num_sends * len(str(pkt)),
530 "Received byte count " + str(flow_removed.byte_count) +
531 " is not within " + str(tolerance) + "% of expected " +
532 str(num_sends*len(str(pkt))))