blob: 772be685491574640728b52549e88aaed28046cf [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:
Rich Lanec42dbad2012-10-11 10:57:44 -070090 self.assertEqual(flow_mod_msg.match, obj.match,
91 "Matches do not match")
92 self.assertEqual(obj.cookie, flow_mod_msg.cookie)
93 self.assertEqual(obj.priority, flow_mod_msg.priority)
94 self.assertEqual(obj.idle_timeout, flow_mod_msg.idle_timeout)
95 self.assertEqual(obj.hard_timeout, flow_mod_msg.hard_timeout)
96 self.assertEqual(obj.actions, flow_mod_msg.actions)
Rich Lane9a003812012-10-04 17:17:59 -070097 logging.info("Received " + str(obj.packet_count) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -070098 if obj.packet_count == packet_count:
99 all_packets_received = 1
100
101 if all_packets_received:
102 break
103 sleep(1)
104
105 self.assertTrue(all_packets_received,
106 "Packet count does not match number sent")
107
Dan Talayco89d57342010-06-07 16:24:59 -0700108 def runTest(self):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700109 # TODO: set from command-line parameter
110 test_timeout = 60
111
Rich Lane477f4812012-10-04 22:49:00 -0700112 of_ports = config["port_map"].keys()
Dan Talayco89d57342010-06-07 16:24:59 -0700113 of_ports.sort()
114 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
115
Rich Lane32bf9482013-01-03 17:26:30 -0800116 delete_all_flows(self.controller)
Dan Talayco89d57342010-06-07 16:24:59 -0700117
Ken Chiang620bdcc2012-03-23 12:52:07 -0700118 # build packet
Dan Talayco89d57342010-06-07 16:24:59 -0700119 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700120 match = packet_to_flow_match(self, pkt)
Dan Talayco89d57342010-06-07 16:24:59 -0700121 match.wildcards &= ~ofp.OFPFW_IN_PORT
122 self.assertTrue(match is not None,
123 "Could not generate flow match from pkt")
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800124 act = ofp.action.output()
Dan Talayco89d57342010-06-07 16:24:59 -0700125
Ken Chiang620bdcc2012-03-23 12:52:07 -0700126 # build flow
Dan Talayco39bf6912010-07-08 14:17:52 -0700127 ingress_port = of_ports[0];
128 egress_port = of_ports[1];
Rich Lane9a003812012-10-04 17:17:59 -0700129 logging.info("Ingress " + str(ingress_port) +
Dan Talayco89d57342010-06-07 16:24:59 -0700130 " to egress " + str(egress_port))
Ken Chiang620bdcc2012-03-23 12:52:07 -0700131 match.in_port = ingress_port
Rich Laneba3f0e22013-03-11 16:43:57 -0700132 flow_mod_msg = ofp.message.flow_add()
Rich Lanec42dbad2012-10-11 10:57:44 -0700133 flow_mod_msg.match = copy.deepcopy(match)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700134 flow_mod_msg.cookie = random.randint(0,9007199254740992)
135 flow_mod_msg.buffer_id = 0xffffffff
Rich Lanec42dbad2012-10-11 10:57:44 -0700136 flow_mod_msg.idle_timeout = 60000
137 flow_mod_msg.hard_timeout = 65000
138 flow_mod_msg.priority = 100
Ken Chiang620bdcc2012-03-23 12:52:07 -0700139 act.port = egress_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800140 flow_mod_msg.actions.append(act)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700141
142 # send flow
Rich Lane9a003812012-10-04 17:17:59 -0700143 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800144 self.controller.message_send(flow_mod_msg)
Rich Lane3a261d52013-01-03 17:45:08 -0800145 do_barrier(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700146
147 # no packets sent, so zero packet count
Rich Lanec42dbad2012-10-11 10:57:44 -0700148 self.verifyStats(flow_mod_msg, match, ofp.OFPP_NONE, test_timeout, 0)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700149
150 # send packet N times
151 num_sends = random.randint(10,20)
Rich Lane9a003812012-10-04 17:17:59 -0700152 logging.info("Sending " + str(num_sends) + " test packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700153 for i in range(0,num_sends):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700154 sendPacket(self, pkt, ingress_port, egress_port,
155 test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700156
Rich Lanec42dbad2012-10-11 10:57:44 -0700157 self.verifyStats(flow_mod_msg, match, ofp.OFPP_NONE, test_timeout, num_sends)
158 self.verifyStats(flow_mod_msg, match, egress_port, test_timeout, num_sends)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700159 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -0700160 match.wildcards = required_wildcards(self) | wc
Rich Lanec42dbad2012-10-11 10:57:44 -0700161 self.verifyStats(flow_mod_msg, match, egress_port, test_timeout, num_sends)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700162
163
Rich Laneb90a1c42012-10-05 09:16:05 -0700164class TwoFlowStats(base_tests.SimpleDataPlane):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700165 """
166 Verify flow stats are properly retrieved.
167
168 Generate two packets and install two matching flows
169 Send some number of packets
170 Send a flow stats request to match the flows and retrieve stats
171 Verify that the packet counter has incremented
172
173 TODO: add a third flow, and then configure the match to exclude
174 that flow?
175 """
176
177 def buildFlowModMsg(self, pkt, ingress_port, egress_port):
Ed Swierk99a74de2012-08-22 06:40:54 -0700178 match = packet_to_flow_match(self, pkt)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700179 match.wildcards &= ~ofp.OFPFW_IN_PORT
180 self.assertTrue(match is not None,
181 "Could not generate flow match from pkt")
Dan Talayco89d57342010-06-07 16:24:59 -0700182 match.in_port = ingress_port
183
Rich Laneba3f0e22013-03-11 16:43:57 -0700184 flow_mod_msg = ofp.message.flow_add()
Dan Talayco89d57342010-06-07 16:24:59 -0700185 flow_mod_msg.match = match
186 flow_mod_msg.cookie = random.randint(0,9007199254740992)
187 flow_mod_msg.buffer_id = 0xffffffff
Ken Chiang620bdcc2012-03-23 12:52:07 -0700188 flow_mod_msg.idle_timeout = 0
189 flow_mod_msg.hard_timeout = 0
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800190 act = ofp.action.output()
Dan Talayco89d57342010-06-07 16:24:59 -0700191 act.port = egress_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800192 flow_mod_msg.actions.append(act)
Dan Talayco89d57342010-06-07 16:24:59 -0700193
Rich Lane9a003812012-10-04 17:17:59 -0700194 logging.info("Ingress " + str(ingress_port) +
Ken Chiang620bdcc2012-03-23 12:52:07 -0700195 " to egress " + str(egress_port))
Dan Talayco89d57342010-06-07 16:24:59 -0700196
Ken Chiang620bdcc2012-03-23 12:52:07 -0700197 return flow_mod_msg
Dan Talayco89d57342010-06-07 16:24:59 -0700198
Ken Chiangaa5bc062012-03-31 14:03:28 -0700199 def sumStatsReplyCounts(self, response):
200 total_packets = 0
Rich Lane5fd6faf2013-03-11 13:30:20 -0700201 for obj in response.entries:
Ken Chiangaa5bc062012-03-31 14:03:28 -0700202 #self.assertEqual(match, obj.match,
203 # "Matches do not match")
Rich Lane9a003812012-10-04 17:17:59 -0700204 logging.info("Received " + str(obj.packet_count)
Ken Chiangaa5bc062012-03-31 14:03:28 -0700205 + " packets")
206 total_packets += obj.packet_count
207 return total_packets
Ken Chiang620bdcc2012-03-23 12:52:07 -0700208
209 def verifyStats(self, match, out_port, test_timeout, packet_count):
Rich Lane28fa9272013-03-08 16:00:25 -0800210 stat_req = ofp.message.flow_stats_request()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700211 stat_req.match = match
212 stat_req.table_id = 0xff
213 stat_req.out_port = out_port
214
215 all_packets_received = 0
216 for i in range(0,test_timeout):
Rich Lane9a003812012-10-04 17:17:59 -0700217 logging.info("Sending stats request")
Ken Chiangaa5bc062012-03-31 14:03:28 -0700218 # TODO: move REPLY_MORE handling to controller.transact?
Ken Chiangfb593e72012-03-28 17:19:13 -0700219 response, pkt = self.controller.transact(stat_req,
220 timeout=test_timeout)
221 self.assertTrue(response is not None,
222 "No response to stats request")
Ken Chiangaa5bc062012-03-31 14:03:28 -0700223 total_packets = self.sumStatsReplyCounts(response)
224
225 while response.flags == ofp.OFPSF_REPLY_MORE:
226 response, pkt = self.controller.poll(exp_msg=
227 ofp.OFPT_STATS_REPLY,
228 timeout=test_timeout)
229 total_packets += self.sumStatsReplyCounts(response)
230
Ken Chiang620bdcc2012-03-23 12:52:07 -0700231 if total_packets == packet_count:
232 all_packets_received = 1
233 break
234 sleep(1)
235
236 self.assertTrue(all_packets_received,
Ken Chiangaa5bc062012-03-31 14:03:28 -0700237 "Total stats packet count " + str(total_packets) +
238 " does not match number sent " + str(packet_count))
Ken Chiang620bdcc2012-03-23 12:52:07 -0700239
240 def runTest(self):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700241 # TODO: set from command-line parameter
242 test_timeout = 60
243
Rich Lane477f4812012-10-04 22:49:00 -0700244 of_ports = config["port_map"].keys()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700245 of_ports.sort()
246 self.assertTrue(len(of_ports) >= 3, "Not enough ports for test")
247 ingress_port = of_ports[0];
248 egress_port1 = of_ports[1];
249 egress_port2 = of_ports[2];
250
Rich Lane32bf9482013-01-03 17:26:30 -0800251 delete_all_flows(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700252
253 pkt1 = simple_tcp_packet()
254 flow_mod_msg1 = self.buildFlowModMsg(pkt1, ingress_port, egress_port1)
255
Rich Laned0478ff2013-03-11 12:46:58 -0700256 pkt2 = simple_tcp_packet(eth_src='0:7:7:7:7:7')
Ken Chiang620bdcc2012-03-23 12:52:07 -0700257 flow_mod_msg2 = self.buildFlowModMsg(pkt2, ingress_port, egress_port2)
258
Rich Lane9a003812012-10-04 17:17:59 -0700259 logging.info("Inserting flow1")
Rich Lane5c3151c2013-01-03 17:15:41 -0800260 self.controller.message_send(flow_mod_msg1)
Rich Lane9a003812012-10-04 17:17:59 -0700261 logging.info("Inserting flow2")
Rich Lane5c3151c2013-01-03 17:15:41 -0800262 self.controller.message_send(flow_mod_msg2)
Rich Lane3a261d52013-01-03 17:45:08 -0800263 do_barrier(self.controller)
Dan Talayco89d57342010-06-07 16:24:59 -0700264
Ken Chiang620bdcc2012-03-23 12:52:07 -0700265 num_pkt1s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700266 logging.info("Sending " + str(num_pkt1s) + " pkt1s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700267 num_pkt2s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700268 logging.info("Sending " + str(num_pkt2s) + " pkt2s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700269 for i in range(0,num_pkt1s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700270 sendPacket(self, pkt1, ingress_port, egress_port1, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700271 for i in range(0,num_pkt2s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700272 sendPacket(self, pkt2, ingress_port, egress_port2, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700273
Ed Swierk99a74de2012-08-22 06:40:54 -0700274 match1 = packet_to_flow_match(self, pkt1)
Rich Lane9a003812012-10-04 17:17:59 -0700275 logging.info("Verifying flow1's " + str(num_pkt1s) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700276 self.verifyStats(match1, ofp.OFPP_NONE, test_timeout, num_pkt1s)
Ed Swierk99a74de2012-08-22 06:40:54 -0700277 match2 = packet_to_flow_match(self, pkt2)
Rich Lane9a003812012-10-04 17:17:59 -0700278 logging.info("Verifying flow2's " + str(num_pkt2s) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700279 self.verifyStats(match2, ofp.OFPP_NONE, test_timeout, num_pkt2s)
280 match1.wildcards |= ofp.OFPFW_DL_SRC
Rich Lane9a003812012-10-04 17:17:59 -0700281 logging.info("Verifying combined " + str(num_pkt1s+num_pkt2s) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700282 self.verifyStats(match1, ofp.OFPP_NONE, test_timeout,
283 num_pkt1s+num_pkt2s)
284 # TODO: sweep through the wildcards to verify matching?
285
286
Rich Laneb90a1c42012-10-05 09:16:05 -0700287class AggregateStats(base_tests.SimpleDataPlane):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700288 """
289 Verify aggregate flow stats are properly retrieved.
290
291 Generate two packets
292 Generate and install two matching flows
293 Send an aggregate stats request
294 Verify that aggregate stats are correct
295 Also verify out_port filtering
296 """
297
298 def buildFlowModMsg(self, pkt, ingress_port, egress_port):
Ed Swierk99a74de2012-08-22 06:40:54 -0700299 match = packet_to_flow_match(self, pkt)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700300 match.wildcards &= ~ofp.OFPFW_IN_PORT
301 self.assertTrue(match is not None,
302 "Could not generate flow match from pkt")
303 match.in_port = ingress_port
304
Rich Laneba3f0e22013-03-11 16:43:57 -0700305 flow_mod_msg = ofp.message.flow_add()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700306 flow_mod_msg.match = match
307 flow_mod_msg.cookie = random.randint(0,9007199254740992)
308 flow_mod_msg.buffer_id = 0xffffffff
309 flow_mod_msg.idle_timeout = 0
310 flow_mod_msg.hard_timeout = 0
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800311 act = ofp.action.output()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700312 act.port = egress_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800313 flow_mod_msg.actions.append(act)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700314
Rich Lane9a003812012-10-04 17:17:59 -0700315 logging.info("Ingress " + str(ingress_port) +
Ken Chiang620bdcc2012-03-23 12:52:07 -0700316 " to egress " + str(egress_port))
317
318 return flow_mod_msg
319
Ken Chiang620bdcc2012-03-23 12:52:07 -0700320 def verifyAggFlowStats(self, match, out_port, test_timeout,
321 flow_count, packet_count):
Rich Lane28fa9272013-03-08 16:00:25 -0800322 stat_req = ofp.message.aggregate_stats_request()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700323 stat_req.match = match
324 stat_req.table_id = 0xff
325 stat_req.out_port = out_port
326
327 all_packets_received = 0
328 for i in range(0,test_timeout):
Rich Lane9a003812012-10-04 17:17:59 -0700329 logging.info("Sending stats request")
Ken Chiangfb593e72012-03-28 17:19:13 -0700330 response, pkt = self.controller.transact(stat_req,
331 timeout=test_timeout)
332 self.assertTrue(response is not None,
333 "No response to stats request")
Rich Lane032669d2013-03-11 23:36:28 -0700334 self.assertTrue(response.flow_count == flow_count,
335 "Flow count " + str(response.flow_count) +
336 " does not match expected " + str(flow_count))
337 logging.info("Received " + str(response.packet_count) + " packets")
338 if response.packet_count == packet_count:
339 all_packets_received = 1
Ken Chiang620bdcc2012-03-23 12:52:07 -0700340
341 if all_packets_received:
342 break
343 sleep(1)
344
345 self.assertTrue(all_packets_received,
346 "Packet count does not match number sent")
347
348 def runTest(self):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700349 # TODO: set from command-line parameter
350 test_timeout = 60
351
Rich Lane477f4812012-10-04 22:49:00 -0700352 of_ports = config["port_map"].keys()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700353 of_ports.sort()
354 self.assertTrue(len(of_ports) >= 3, "Not enough ports for test")
355 ingress_port = of_ports[0];
356 egress_port1 = of_ports[1];
357 egress_port2 = of_ports[2];
358
Rich Lane32bf9482013-01-03 17:26:30 -0800359 delete_all_flows(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700360
361 pkt1 = simple_tcp_packet()
362 flow_mod_msg1 = self.buildFlowModMsg(pkt1, ingress_port, egress_port1)
363
Rich Laned0478ff2013-03-11 12:46:58 -0700364 pkt2 = simple_tcp_packet(eth_src='0:7:7:7:7:7')
Ken Chiang620bdcc2012-03-23 12:52:07 -0700365 flow_mod_msg2 = self.buildFlowModMsg(pkt2, ingress_port, egress_port2)
366
Rich Lane9a003812012-10-04 17:17:59 -0700367 logging.info("Inserting flow1")
Rich Lane5c3151c2013-01-03 17:15:41 -0800368 self.controller.message_send(flow_mod_msg1)
Rich Lane9a003812012-10-04 17:17:59 -0700369 logging.info("Inserting flow2")
Rich Lane5c3151c2013-01-03 17:15:41 -0800370 self.controller.message_send(flow_mod_msg2)
Rich Lane3a261d52013-01-03 17:45:08 -0800371 do_barrier(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700372
373 num_pkt1s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700374 logging.info("Sending " + str(num_pkt1s) + " pkt1s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700375 num_pkt2s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700376 logging.info("Sending " + str(num_pkt2s) + " pkt2s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700377 for i in range(0,num_pkt1s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700378 sendPacket(self, pkt1, ingress_port, egress_port1, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700379 for i in range(0,num_pkt2s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700380 sendPacket(self, pkt2, ingress_port, egress_port2, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700381
382 # loop on flow stats request until timeout
Ed Swierk99a74de2012-08-22 06:40:54 -0700383 match = packet_to_flow_match(self, pkt1)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700384 match.wildcards |= ofp.OFPFW_DL_SRC
385 self.verifyAggFlowStats(match, ofp.OFPP_NONE, test_timeout,
386 2, num_pkt1s+num_pkt2s)
387
388 # out_port filter for egress_port1
389 self.verifyAggFlowStats(match, egress_port1, test_timeout,
390 1, num_pkt1s)
391
392 # out_port filter for egress_port1
393 self.verifyAggFlowStats(match, egress_port2, test_timeout,
394 1, num_pkt2s)
Rich Lane97a5f502012-10-11 09:28:11 -0700395
Rich Lanef062b3d2012-10-11 09:53:19 -0700396class EmptyFlowStats(base_tests.SimpleDataPlane):
397 """
398 Verify the switch replies to a flow stats request when
399 the query doesn't match any flows.
400 """
401 def runTest(self):
Rich Lane32bf9482013-01-03 17:26:30 -0800402 delete_all_flows(self.controller)
Rich Lane0237baf2013-03-11 22:34:59 -0700403 match = ofp.match()
Rich Lanef062b3d2012-10-11 09:53:19 -0700404 match.wildcards = 0
Rich Lane28fa9272013-03-08 16:00:25 -0800405 stat_req = ofp.message.flow_stats_request()
Rich Lanef062b3d2012-10-11 09:53:19 -0700406 stat_req.match = match
407 stat_req.table_id = 0xff
408 stat_req.out_port = ofp.OFPP_NONE
409
410 response, pkt = self.controller.transact(stat_req)
411 self.assertTrue(response is not None,
412 "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -0700413 self.assertEquals(len(response.entries), 0)
Rich Lanef062b3d2012-10-11 09:53:19 -0700414 self.assertEquals(response.flags, 0)
415
Rich Lane97a5f502012-10-11 09:28:11 -0700416class EmptyAggregateStats(base_tests.SimpleDataPlane):
417 """
418 Verify aggregate flow stats are properly retrieved when
419 the query doesn't match any flows.
420 """
421 def runTest(self):
Rich Lane32bf9482013-01-03 17:26:30 -0800422 delete_all_flows(self.controller)
Rich Lane0237baf2013-03-11 22:34:59 -0700423 match = ofp.match()
Rich Lane97a5f502012-10-11 09:28:11 -0700424 match.wildcards = 0
Rich Lane28fa9272013-03-08 16:00:25 -0800425 stat_req = ofp.message.aggregate_stats_request()
Rich Lane97a5f502012-10-11 09:28:11 -0700426 stat_req.match = match
427 stat_req.table_id = 0xff
428 stat_req.out_port = ofp.OFPP_NONE
429
430 response, pkt = self.controller.transact(stat_req)
431 self.assertTrue(response is not None,
432 "No response to stats request")
Rich Lane032669d2013-03-11 23:36:28 -0700433 self.assertEquals(response.flow_count, 0)
434 self.assertEquals(response.packet_count, 0)
435 self.assertEquals(response.byte_count, 0)
Rich Laned10e8e02012-11-21 15:48:36 -0800436
437class DeletedFlowStats(base_tests.SimpleDataPlane):
438 """
439 Verify flow stats are properly returned when a flow is deleted.
440
441 Generate a packet
442 Generate and install a matching flow
443 Send the packet
444 Delete the flow
445 Verify that the flow_removed message has the correct stats
446 """
447
448 def runTest(self):
449 # TODO: set from command-line parameter
450 test_timeout = 60
451
452 of_ports = config["port_map"].keys()
453 of_ports.sort()
454 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
455
Rich Lane32bf9482013-01-03 17:26:30 -0800456 delete_all_flows(self.controller)
Rich Laned10e8e02012-11-21 15:48:36 -0800457
458 # build packet
459 pkt = simple_tcp_packet()
460 match = packet_to_flow_match(self, pkt)
461 match.wildcards &= ~ofp.OFPFW_IN_PORT
462 self.assertTrue(match is not None,
463 "Could not generate flow match from pkt")
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800464 act = ofp.action.output()
Rich Laned10e8e02012-11-21 15:48:36 -0800465
466 # build flow
467 ingress_port = of_ports[0];
468 egress_port = of_ports[1];
469 logging.info("Ingress " + str(ingress_port) +
470 " to egress " + str(egress_port))
471 match.in_port = ingress_port
Rich Laneba3f0e22013-03-11 16:43:57 -0700472 flow_mod_msg = ofp.message.flow_add()
Rich Laned10e8e02012-11-21 15:48:36 -0800473 flow_mod_msg.match = copy.deepcopy(match)
474 flow_mod_msg.cookie = random.randint(0,9007199254740992)
475 flow_mod_msg.buffer_id = 0xffffffff
476 flow_mod_msg.idle_timeout = 0
477 flow_mod_msg.hard_timeout = 0
478 flow_mod_msg.priority = 100
479 flow_mod_msg.flags = ofp.OFPFF_SEND_FLOW_REM
480 act.port = egress_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800481 flow_mod_msg.actions.append(act)
Rich Laned10e8e02012-11-21 15:48:36 -0800482
483 # send flow
484 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800485 self.controller.message_send(flow_mod_msg)
Rich Lane3a261d52013-01-03 17:45:08 -0800486 do_barrier(self.controller)
Rich Laned10e8e02012-11-21 15:48:36 -0800487
488 # send packet N times
489 num_sends = random.randint(10,20)
490 logging.info("Sending " + str(num_sends) + " test packets")
491 for i in range(0,num_sends):
492 sendPacket(self, pkt, ingress_port, egress_port,
493 test_timeout)
494
Ken Chiang626ce1d2013-01-09 11:58:50 -0800495 # wait some time for flow stats to be propagated
496 # FIXME timeout handling should be unified
497 sleep(test_param_get('default_timeout', default=2))
498
Rich Laned10e8e02012-11-21 15:48:36 -0800499 # delete flow
500 logging.info("Deleting flow")
Rich Lane32bf9482013-01-03 17:26:30 -0800501 delete_all_flows(self.controller)
Rich Laned10e8e02012-11-21 15:48:36 -0800502
503 # wait for flow_removed message
504 flow_removed, _ = self.controller.poll(
505 exp_msg=ofp.OFPT_FLOW_REMOVED, timeout=test_timeout)
506
507 self.assertTrue(flow_removed != None, "Did not receive flow_removed message")
Ken Chiang626ce1d2013-01-09 11:58:50 -0800508 self.assertEqual(flow_removed.cookie, flow_mod_msg.cookie,
509 "Received cookie " + str(flow_removed.cookie) +
510 " does not match expected " + str(flow_mod_msg.cookie))
511 self.assertEqual(flow_removed.reason, ofp.OFPRR_DELETE,
512 "Received reason " + str(flow_removed.reason) +
513 " does not match expected " + str(ofp.OFPRR_DELETE))
514 self.assertEqual(flow_removed.packet_count, num_sends,
515 "Received packet count " + str(flow_removed.packet_count) +
516 " does not match expected " + str(num_sends))
517 tolerance = 5 # percent
518 self.assertTrue(flow_removed.byte_count >=
519 (1-tolerance/100.0) * num_sends * len(str(pkt)) and
520 flow_removed.byte_count <=
521 (1+tolerance/100.0) * num_sends * len(str(pkt)),
522 "Received byte count " + str(flow_removed.byte_count) +
523 " is not within " + str(tolerance) + "% of expected " +
524 str(num_sends*len(str(pkt))))