blob: da12071f983e6c7c61d25ab4906797235e1d4b93 [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")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700151 rv = self.controller.message_send(flow_mod_msg)
152 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700153 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700154
155 # no packets sent, so zero packet count
Rich Lanec42dbad2012-10-11 10:57:44 -0700156 self.verifyStats(flow_mod_msg, match, ofp.OFPP_NONE, test_timeout, 0)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700157
158 # send packet N times
159 num_sends = random.randint(10,20)
Rich Lane9a003812012-10-04 17:17:59 -0700160 logging.info("Sending " + str(num_sends) + " test packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700161 for i in range(0,num_sends):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700162 sendPacket(self, pkt, ingress_port, egress_port,
163 test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700164
Rich Lanec42dbad2012-10-11 10:57:44 -0700165 self.verifyStats(flow_mod_msg, match, ofp.OFPP_NONE, test_timeout, num_sends)
166 self.verifyStats(flow_mod_msg, match, egress_port, test_timeout, num_sends)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700167 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -0700168 match.wildcards = required_wildcards(self) | wc
Rich Lanec42dbad2012-10-11 10:57:44 -0700169 self.verifyStats(flow_mod_msg, match, egress_port, test_timeout, num_sends)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700170
171
Rich Laneb90a1c42012-10-05 09:16:05 -0700172class TwoFlowStats(base_tests.SimpleDataPlane):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700173 """
174 Verify flow stats are properly retrieved.
175
176 Generate two packets and install two matching flows
177 Send some number of packets
178 Send a flow stats request to match the flows and retrieve stats
179 Verify that the packet counter has incremented
180
181 TODO: add a third flow, and then configure the match to exclude
182 that flow?
183 """
184
185 def buildFlowModMsg(self, pkt, ingress_port, egress_port):
Ed Swierk99a74de2012-08-22 06:40:54 -0700186 match = packet_to_flow_match(self, pkt)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700187 match.wildcards &= ~ofp.OFPFW_IN_PORT
188 self.assertTrue(match is not None,
189 "Could not generate flow match from pkt")
Dan Talayco89d57342010-06-07 16:24:59 -0700190 match.in_port = ingress_port
191
192 flow_mod_msg = message.flow_mod()
193 flow_mod_msg.match = match
194 flow_mod_msg.cookie = random.randint(0,9007199254740992)
195 flow_mod_msg.buffer_id = 0xffffffff
Ken Chiang620bdcc2012-03-23 12:52:07 -0700196 flow_mod_msg.idle_timeout = 0
197 flow_mod_msg.hard_timeout = 0
198 act = action.action_output()
Dan Talayco89d57342010-06-07 16:24:59 -0700199 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800200 flow_mod_msg.actions.add(act)
Dan Talayco89d57342010-06-07 16:24:59 -0700201
Rich Lane9a003812012-10-04 17:17:59 -0700202 logging.info("Ingress " + str(ingress_port) +
Ken Chiang620bdcc2012-03-23 12:52:07 -0700203 " to egress " + str(egress_port))
Dan Talayco89d57342010-06-07 16:24:59 -0700204
Ken Chiang620bdcc2012-03-23 12:52:07 -0700205 return flow_mod_msg
Dan Talayco89d57342010-06-07 16:24:59 -0700206
Ken Chiangaa5bc062012-03-31 14:03:28 -0700207 def sumStatsReplyCounts(self, response):
208 total_packets = 0
209 for obj in response.stats:
210 # TODO: pad1 and pad2 fields may be nonzero, is this a bug?
211 # for now, just clear them so the assert is simpler
212 #obj.match.pad1 = 0
213 #obj.match.pad2 = [0, 0]
214 #self.assertEqual(match, obj.match,
215 # "Matches do not match")
Rich Lane9a003812012-10-04 17:17:59 -0700216 logging.info("Received " + str(obj.packet_count)
Ken Chiangaa5bc062012-03-31 14:03:28 -0700217 + " packets")
218 total_packets += obj.packet_count
219 return total_packets
Ken Chiang620bdcc2012-03-23 12:52:07 -0700220
221 def verifyStats(self, match, out_port, test_timeout, packet_count):
222 stat_req = message.flow_stats_request()
223 stat_req.match = match
224 stat_req.table_id = 0xff
225 stat_req.out_port = out_port
226
227 all_packets_received = 0
228 for i in range(0,test_timeout):
Rich Lane9a003812012-10-04 17:17:59 -0700229 logging.info("Sending stats request")
Ken Chiangaa5bc062012-03-31 14:03:28 -0700230 # TODO: move REPLY_MORE handling to controller.transact?
Ken Chiangfb593e72012-03-28 17:19:13 -0700231 response, pkt = self.controller.transact(stat_req,
232 timeout=test_timeout)
233 self.assertTrue(response is not None,
234 "No response to stats request")
Ken Chiangaa5bc062012-03-31 14:03:28 -0700235 total_packets = self.sumStatsReplyCounts(response)
236
237 while response.flags == ofp.OFPSF_REPLY_MORE:
238 response, pkt = self.controller.poll(exp_msg=
239 ofp.OFPT_STATS_REPLY,
240 timeout=test_timeout)
241 total_packets += self.sumStatsReplyCounts(response)
242
Ken Chiang620bdcc2012-03-23 12:52:07 -0700243 if total_packets == packet_count:
244 all_packets_received = 1
245 break
246 sleep(1)
247
248 self.assertTrue(all_packets_received,
Ken Chiangaa5bc062012-03-31 14:03:28 -0700249 "Total stats packet count " + str(total_packets) +
250 " does not match number sent " + str(packet_count))
Ken Chiang620bdcc2012-03-23 12:52:07 -0700251
252 def runTest(self):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700253 # TODO: set from command-line parameter
254 test_timeout = 60
255
Rich Lane477f4812012-10-04 22:49:00 -0700256 of_ports = config["port_map"].keys()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700257 of_ports.sort()
258 self.assertTrue(len(of_ports) >= 3, "Not enough ports for test")
259 ingress_port = of_ports[0];
260 egress_port1 = of_ports[1];
261 egress_port2 = of_ports[2];
262
Rich Lane9a003812012-10-04 17:17:59 -0700263 rc = delete_all_flows(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700264 self.assertEqual(rc, 0, "Failed to delete all flows")
265
266 pkt1 = simple_tcp_packet()
267 flow_mod_msg1 = self.buildFlowModMsg(pkt1, ingress_port, egress_port1)
268
269 pkt2 = simple_tcp_packet(dl_src='0:7:7:7:7:7')
270 flow_mod_msg2 = self.buildFlowModMsg(pkt2, ingress_port, egress_port2)
271
Rich Lane9a003812012-10-04 17:17:59 -0700272 logging.info("Inserting flow1")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700273 rv = self.controller.message_send(flow_mod_msg1)
274 self.assertTrue(rv != -1, "Error installing flow mod")
Rich Lane9a003812012-10-04 17:17:59 -0700275 logging.info("Inserting flow2")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700276 rv = self.controller.message_send(flow_mod_msg2)
277 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700278 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Dan Talayco89d57342010-06-07 16:24:59 -0700279
Ken Chiang620bdcc2012-03-23 12:52:07 -0700280 num_pkt1s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700281 logging.info("Sending " + str(num_pkt1s) + " pkt1s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700282 num_pkt2s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700283 logging.info("Sending " + str(num_pkt2s) + " pkt2s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700284 for i in range(0,num_pkt1s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700285 sendPacket(self, pkt1, ingress_port, egress_port1, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700286 for i in range(0,num_pkt2s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700287 sendPacket(self, pkt2, ingress_port, egress_port2, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700288
Ed Swierk99a74de2012-08-22 06:40:54 -0700289 match1 = packet_to_flow_match(self, pkt1)
Rich Lane9a003812012-10-04 17:17:59 -0700290 logging.info("Verifying flow1's " + str(num_pkt1s) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700291 self.verifyStats(match1, ofp.OFPP_NONE, test_timeout, num_pkt1s)
Ed Swierk99a74de2012-08-22 06:40:54 -0700292 match2 = packet_to_flow_match(self, pkt2)
Rich Lane9a003812012-10-04 17:17:59 -0700293 logging.info("Verifying flow2's " + str(num_pkt2s) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700294 self.verifyStats(match2, ofp.OFPP_NONE, test_timeout, num_pkt2s)
295 match1.wildcards |= ofp.OFPFW_DL_SRC
Rich Lane9a003812012-10-04 17:17:59 -0700296 logging.info("Verifying combined " + str(num_pkt1s+num_pkt2s) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700297 self.verifyStats(match1, ofp.OFPP_NONE, test_timeout,
298 num_pkt1s+num_pkt2s)
299 # TODO: sweep through the wildcards to verify matching?
300
301
Rich Laneb90a1c42012-10-05 09:16:05 -0700302class AggregateStats(base_tests.SimpleDataPlane):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700303 """
304 Verify aggregate flow stats are properly retrieved.
305
306 Generate two packets
307 Generate and install two matching flows
308 Send an aggregate stats request
309 Verify that aggregate stats are correct
310 Also verify out_port filtering
311 """
312
313 def buildFlowModMsg(self, pkt, ingress_port, egress_port):
Ed Swierk99a74de2012-08-22 06:40:54 -0700314 match = packet_to_flow_match(self, pkt)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700315 match.wildcards &= ~ofp.OFPFW_IN_PORT
316 self.assertTrue(match is not None,
317 "Could not generate flow match from pkt")
318 match.in_port = ingress_port
319
320 flow_mod_msg = message.flow_mod()
321 flow_mod_msg.match = match
322 flow_mod_msg.cookie = random.randint(0,9007199254740992)
323 flow_mod_msg.buffer_id = 0xffffffff
324 flow_mod_msg.idle_timeout = 0
325 flow_mod_msg.hard_timeout = 0
326 act = action.action_output()
327 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800328 flow_mod_msg.actions.add(act)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700329
Rich Lane9a003812012-10-04 17:17:59 -0700330 logging.info("Ingress " + str(ingress_port) +
Ken Chiang620bdcc2012-03-23 12:52:07 -0700331 " to egress " + str(egress_port))
332
333 return flow_mod_msg
334
Ken Chiang620bdcc2012-03-23 12:52:07 -0700335 def verifyAggFlowStats(self, match, out_port, test_timeout,
336 flow_count, packet_count):
337 stat_req = message.aggregate_stats_request()
338 stat_req.match = match
339 stat_req.table_id = 0xff
340 stat_req.out_port = out_port
341
342 all_packets_received = 0
343 for i in range(0,test_timeout):
Rich Lane9a003812012-10-04 17:17:59 -0700344 logging.info("Sending stats request")
Ken Chiangfb593e72012-03-28 17:19:13 -0700345 response, pkt = self.controller.transact(stat_req,
346 timeout=test_timeout)
347 self.assertTrue(response is not None,
348 "No response to stats request")
Dan Talaycoaff26c82012-03-25 15:06:26 -0700349 self.assertTrue(len(response.stats) == 1,
350 "Did not receive flow stats reply")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700351 for obj in response.stats:
352 self.assertTrue(obj.flow_count == flow_count,
353 "Flow count " + str(obj.flow_count) +
354 " does not match expected " + str(flow_count))
Rich Lane9a003812012-10-04 17:17:59 -0700355 logging.info("Received " + str(obj.packet_count) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700356 if obj.packet_count == packet_count:
357 all_packets_received = 1
358
359 if all_packets_received:
360 break
361 sleep(1)
362
363 self.assertTrue(all_packets_received,
364 "Packet count does not match number sent")
365
366 def runTest(self):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700367 # TODO: set from command-line parameter
368 test_timeout = 60
369
Rich Lane477f4812012-10-04 22:49:00 -0700370 of_ports = config["port_map"].keys()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700371 of_ports.sort()
372 self.assertTrue(len(of_ports) >= 3, "Not enough ports for test")
373 ingress_port = of_ports[0];
374 egress_port1 = of_ports[1];
375 egress_port2 = of_ports[2];
376
Rich Lane9a003812012-10-04 17:17:59 -0700377 rc = delete_all_flows(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700378 self.assertEqual(rc, 0, "Failed to delete all flows")
379
380 pkt1 = simple_tcp_packet()
381 flow_mod_msg1 = self.buildFlowModMsg(pkt1, ingress_port, egress_port1)
382
383 pkt2 = simple_tcp_packet(dl_src='0:7:7:7:7:7')
384 flow_mod_msg2 = self.buildFlowModMsg(pkt2, ingress_port, egress_port2)
385
Rich Lane9a003812012-10-04 17:17:59 -0700386 logging.info("Inserting flow1")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700387 rv = self.controller.message_send(flow_mod_msg1)
388 self.assertTrue(rv != -1, "Error installing flow mod")
Rich Lane9a003812012-10-04 17:17:59 -0700389 logging.info("Inserting flow2")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700390 rv = self.controller.message_send(flow_mod_msg2)
391 self.assertTrue(rv != -1, "Error installing flow mod")
Dan Talayco0fc08bd2012-04-09 16:56:18 -0700392 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700393
394 num_pkt1s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700395 logging.info("Sending " + str(num_pkt1s) + " pkt1s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700396 num_pkt2s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700397 logging.info("Sending " + str(num_pkt2s) + " pkt2s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700398 for i in range(0,num_pkt1s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700399 sendPacket(self, pkt1, ingress_port, egress_port1, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700400 for i in range(0,num_pkt2s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700401 sendPacket(self, pkt2, ingress_port, egress_port2, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700402
403 # loop on flow stats request until timeout
Ed Swierk99a74de2012-08-22 06:40:54 -0700404 match = packet_to_flow_match(self, pkt1)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700405 match.wildcards |= ofp.OFPFW_DL_SRC
406 self.verifyAggFlowStats(match, ofp.OFPP_NONE, test_timeout,
407 2, num_pkt1s+num_pkt2s)
408
409 # out_port filter for egress_port1
410 self.verifyAggFlowStats(match, egress_port1, test_timeout,
411 1, num_pkt1s)
412
413 # out_port filter for egress_port1
414 self.verifyAggFlowStats(match, egress_port2, test_timeout,
415 1, num_pkt2s)
Rich Lane97a5f502012-10-11 09:28:11 -0700416
Rich Lanef062b3d2012-10-11 09:53:19 -0700417class EmptyFlowStats(base_tests.SimpleDataPlane):
418 """
419 Verify the switch replies to a flow stats request when
420 the query doesn't match any flows.
421 """
422 def runTest(self):
423 rc = delete_all_flows(self.controller)
424 self.assertEqual(rc, 0, "Failed to delete all flows")
425 match = ofp.ofp_match()
426 match.wildcards = 0
427 stat_req = message.flow_stats_request()
428 stat_req.match = match
429 stat_req.table_id = 0xff
430 stat_req.out_port = ofp.OFPP_NONE
431
432 response, pkt = self.controller.transact(stat_req)
433 self.assertTrue(response is not None,
434 "No response to stats request")
435 self.assertEquals(len(response.stats), 0)
436 self.assertEquals(response.flags, 0)
437
Rich Lane97a5f502012-10-11 09:28:11 -0700438class EmptyAggregateStats(base_tests.SimpleDataPlane):
439 """
440 Verify aggregate flow stats are properly retrieved when
441 the query doesn't match any flows.
442 """
443 def runTest(self):
444 rc = delete_all_flows(self.controller)
445 self.assertEqual(rc, 0, "Failed to delete all flows")
446 match = ofp.ofp_match()
447 match.wildcards = 0
448 stat_req = message.aggregate_stats_request()
449 stat_req.match = match
450 stat_req.table_id = 0xff
451 stat_req.out_port = ofp.OFPP_NONE
452
453 response, pkt = self.controller.transact(stat_req)
454 self.assertTrue(response is not None,
455 "No response to stats request")
456 self.assertTrue(len(response.stats) == 1,
457 "Did not receive flow stats reply")
458 self.assertEquals(response.stats[0].flow_count, 0)
459 self.assertEquals(response.stats[0].packet_count, 0)
460 self.assertEquals(response.stats[0].byte_count, 0)
Rich Laned10e8e02012-11-21 15:48:36 -0800461
462class DeletedFlowStats(base_tests.SimpleDataPlane):
463 """
464 Verify flow stats are properly returned when a flow is deleted.
465
466 Generate a packet
467 Generate and install a matching flow
468 Send the packet
469 Delete the flow
470 Verify that the flow_removed message has the correct stats
471 """
472
473 def runTest(self):
474 # TODO: set from command-line parameter
475 test_timeout = 60
476
477 of_ports = config["port_map"].keys()
478 of_ports.sort()
479 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
480
481 rc = delete_all_flows(self.controller)
482 self.assertEqual(rc, 0, "Failed to delete all flows")
483
484 # build packet
485 pkt = simple_tcp_packet()
486 match = packet_to_flow_match(self, pkt)
487 match.wildcards &= ~ofp.OFPFW_IN_PORT
488 self.assertTrue(match is not None,
489 "Could not generate flow match from pkt")
490 act = action.action_output()
491
492 # build flow
493 ingress_port = of_ports[0];
494 egress_port = of_ports[1];
495 logging.info("Ingress " + str(ingress_port) +
496 " to egress " + str(egress_port))
497 match.in_port = ingress_port
498 flow_mod_msg = message.flow_mod()
499 flow_mod_msg.match = copy.deepcopy(match)
500 flow_mod_msg.cookie = random.randint(0,9007199254740992)
501 flow_mod_msg.buffer_id = 0xffffffff
502 flow_mod_msg.idle_timeout = 0
503 flow_mod_msg.hard_timeout = 0
504 flow_mod_msg.priority = 100
505 flow_mod_msg.flags = ofp.OFPFF_SEND_FLOW_REM
506 act.port = egress_port
Rich Lanee30455b2013-01-03 16:24:44 -0800507 flow_mod_msg.actions.add(act)
Rich Laned10e8e02012-11-21 15:48:36 -0800508
509 # send flow
510 logging.info("Inserting flow")
511 rv = self.controller.message_send(flow_mod_msg)
512 self.assertTrue(rv != -1, "Error installing flow mod")
513 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
514
515 # send packet N times
516 num_sends = random.randint(10,20)
517 logging.info("Sending " + str(num_sends) + " test packets")
518 for i in range(0,num_sends):
519 sendPacket(self, pkt, ingress_port, egress_port,
520 test_timeout)
521
522 # delete flow
523 logging.info("Deleting flow")
524 rc = delete_all_flows(self.controller)
525 self.assertEqual(rc, 0, "Failed to delete all flows")
526
527 # wait for flow_removed message
528 flow_removed, _ = self.controller.poll(
529 exp_msg=ofp.OFPT_FLOW_REMOVED, timeout=test_timeout)
530
531 self.assertTrue(flow_removed != None, "Did not receive flow_removed message")
532 self.assertEqual(flow_removed.cookie, flow_mod_msg.cookie)
533 self.assertEqual(flow_removed.reason, ofp.OFPRR_DELETE)
534 self.assertEqual(flow_removed.packet_count, num_sends)
535 self.assertEqual(flow_removed.byte_count, num_sends * len(str(pkt)))