blob: 3398aaf3a84758af8da036a200d822e8221621f4 [file] [log] [blame]
Matteo Scandoloa229eca2017-08-08 13:05:28 -07001
2# Copyright 2017-present Open Networking Foundation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16
Dan Talayco89d57342010-06-07 16:24:59 -070017"""
18Flow stats test case.
19Similar to Flow stats test case in the perl test harness.
20
21"""
22
23import logging
24
25import unittest
26import random
Rich Lanec42dbad2012-10-11 10:57:44 -070027import copy
Dan Talayco89d57342010-06-07 16:24:59 -070028
Rich Lane477f4812012-10-04 22:49:00 -070029from oftest import config
Dan Talayco89d57342010-06-07 16:24:59 -070030import oftest.controller as controller
Rich Laned7b0ffa2013-03-08 15:53:42 -080031import ofp
Dan Talayco89d57342010-06-07 16:24:59 -070032import oftest.dataplane as dataplane
Dan Talayco89d57342010-06-07 16:24:59 -070033import oftest.parse as parse
Rich Laneb90a1c42012-10-05 09:16:05 -070034import oftest.base_tests as base_tests
Dan Talayco89d57342010-06-07 16:24:59 -070035
Rich Laneda3b5ad2012-10-03 09:05:32 -070036from oftest.testutils import *
Dan Talayco89d57342010-06-07 16:24:59 -070037from time import sleep
38
Ken Chiang620bdcc2012-03-23 12:52:07 -070039# TODO: ovs has problems with VLAN id?
40WILDCARD_VALUES = [ofp.OFPFW_IN_PORT,
Dan Talayco488fbc52012-04-09 16:30:41 -070041 # (ofp.OFPFW_DL_VLAN | ofp.OFPFW_DL_VLAN_PCP),
Ken Chiang620bdcc2012-03-23 12:52:07 -070042 ofp.OFPFW_DL_SRC,
43 ofp.OFPFW_DL_DST,
Dan Talayco488fbc52012-04-09 16:30:41 -070044 (ofp.OFPFW_DL_TYPE | ofp.OFPFW_NW_SRC_ALL |
45 ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS | ofp.OFPFW_NW_PROTO |
46 ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
47 (ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
Ken Chiang620bdcc2012-03-23 12:52:07 -070048 ofp.OFPFW_TP_SRC,
49 ofp.OFPFW_TP_DST,
Dan Talayco488fbc52012-04-09 16:30:41 -070050 ofp.OFPFW_NW_SRC_MASK,
51 ofp.OFPFW_NW_DST_MASK,
Ken Chiang620bdcc2012-03-23 12:52:07 -070052 ofp.OFPFW_DL_VLAN_PCP,
53 ofp.OFPFW_NW_TOS]
54
Ken Chiangaa5bc062012-03-31 14:03:28 -070055def sendPacket(obj, pkt, ingress_port, egress_port, test_timeout):
56
Rich Lane9a003812012-10-04 17:17:59 -070057 logging.info("Sending packet to dp port " + str(ingress_port) +
Ken Chiangaa5bc062012-03-31 14:03:28 -070058 ", expecting output on " + str(egress_port))
59 obj.dataplane.send(ingress_port, str(pkt))
60
61 exp_pkt_arg = None
62 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -070063 if config["relax"]:
Ken Chiangaa5bc062012-03-31 14:03:28 -070064 exp_pkt_arg = pkt
65 exp_port = egress_port
66
Rich Lanec8aaa3e2012-07-26 19:28:02 -070067 (rcv_port, rcv_pkt, pkt_time) = obj.dataplane.poll(port_number=exp_port,
Ken Chiangaa5bc062012-03-31 14:03:28 -070068 exp_pkt=exp_pkt_arg)
69 obj.assertTrue(rcv_pkt is not None,
70 "Packet not received on port " + str(egress_port))
Rich Lane9a003812012-10-04 17:17:59 -070071 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Ken Chiangaa5bc062012-03-31 14:03:28 -070072 str(rcv_port))
73 obj.assertEqual(rcv_port, egress_port,
74 "Packet received on port " + str(rcv_port) +
75 ", expected port " + str(egress_port))
76 obj.assertEqual(str(pkt), str(rcv_pkt),
77 'Response packet does not match send packet')
78
Rich Laneb90a1c42012-10-05 09:16:05 -070079class SingleFlowStats(base_tests.SimpleDataPlane):
Dan Talayco89d57342010-06-07 16:24:59 -070080 """
81 Verify flow stats are properly retrieved.
82
83 Generate a packet
Ken Chiang620bdcc2012-03-23 12:52:07 -070084 Generate and install a matching flow
85 Send the packet
86 Send a flow stats request to match the flow and retrieve stats
87 Verify that the packet counter has incremented
Dan Talayco89d57342010-06-07 16:24:59 -070088 """
Ken Chiang620bdcc2012-03-23 12:52:07 -070089
Rich Lanec42dbad2012-10-11 10:57:44 -070090 def verifyStats(self, flow_mod_msg, match, out_port, test_timeout, packet_count):
Rich Lane28fa9272013-03-08 16:00:25 -080091 stat_req = ofp.message.flow_stats_request()
Ken Chiang620bdcc2012-03-23 12:52:07 -070092 stat_req.match = match
93 stat_req.table_id = 0xff
94 stat_req.out_port = out_port
95
96 all_packets_received = 0
97 for i in range(0,test_timeout):
Rich Lane9a003812012-10-04 17:17:59 -070098 logging.info("Sending stats request")
Ken Chiangfb593e72012-03-28 17:19:13 -070099 response, pkt = self.controller.transact(stat_req,
100 timeout=test_timeout)
101 self.assertTrue(response is not None,
102 "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -0700103 self.assertTrue(len(response.entries) == 1,
Ken Chiangfb593e72012-03-28 17:19:13 -0700104 "Did not receive flow stats reply")
Rich Lane5fd6faf2013-03-11 13:30:20 -0700105 for obj in response.entries:
Rich Lanec42dbad2012-10-11 10:57:44 -0700106 self.assertEqual(flow_mod_msg.match, obj.match,
107 "Matches do not match")
108 self.assertEqual(obj.cookie, flow_mod_msg.cookie)
109 self.assertEqual(obj.priority, flow_mod_msg.priority)
110 self.assertEqual(obj.idle_timeout, flow_mod_msg.idle_timeout)
111 self.assertEqual(obj.hard_timeout, flow_mod_msg.hard_timeout)
112 self.assertEqual(obj.actions, flow_mod_msg.actions)
Rich Lane9a003812012-10-04 17:17:59 -0700113 logging.info("Received " + str(obj.packet_count) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700114 if obj.packet_count == packet_count:
115 all_packets_received = 1
116
117 if all_packets_received:
118 break
119 sleep(1)
120
121 self.assertTrue(all_packets_received,
122 "Packet count does not match number sent")
123
Dan Talayco89d57342010-06-07 16:24:59 -0700124 def runTest(self):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700125 # TODO: set from command-line parameter
126 test_timeout = 60
127
Rich Lane477f4812012-10-04 22:49:00 -0700128 of_ports = config["port_map"].keys()
Dan Talayco89d57342010-06-07 16:24:59 -0700129 of_ports.sort()
130 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
131
Rich Lane32bf9482013-01-03 17:26:30 -0800132 delete_all_flows(self.controller)
Dan Talayco89d57342010-06-07 16:24:59 -0700133
Ken Chiang620bdcc2012-03-23 12:52:07 -0700134 # build packet
Dan Talayco89d57342010-06-07 16:24:59 -0700135 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700136 match = packet_to_flow_match(self, pkt)
Dan Talayco89d57342010-06-07 16:24:59 -0700137 match.wildcards &= ~ofp.OFPFW_IN_PORT
138 self.assertTrue(match is not None,
139 "Could not generate flow match from pkt")
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800140 act = ofp.action.output()
Dan Talayco89d57342010-06-07 16:24:59 -0700141
Ken Chiang620bdcc2012-03-23 12:52:07 -0700142 # build flow
Dan Talayco39bf6912010-07-08 14:17:52 -0700143 ingress_port = of_ports[0];
144 egress_port = of_ports[1];
Rich Lane9a003812012-10-04 17:17:59 -0700145 logging.info("Ingress " + str(ingress_port) +
Dan Talayco89d57342010-06-07 16:24:59 -0700146 " to egress " + str(egress_port))
Ken Chiang620bdcc2012-03-23 12:52:07 -0700147 match.in_port = ingress_port
Rich Laneba3f0e22013-03-11 16:43:57 -0700148 flow_mod_msg = ofp.message.flow_add()
Rich Lanec42dbad2012-10-11 10:57:44 -0700149 flow_mod_msg.match = copy.deepcopy(match)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700150 flow_mod_msg.cookie = random.randint(0,9007199254740992)
151 flow_mod_msg.buffer_id = 0xffffffff
Rich Lanec42dbad2012-10-11 10:57:44 -0700152 flow_mod_msg.idle_timeout = 60000
153 flow_mod_msg.hard_timeout = 65000
154 flow_mod_msg.priority = 100
Ken Chiang620bdcc2012-03-23 12:52:07 -0700155 act.port = egress_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800156 flow_mod_msg.actions.append(act)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700157
158 # send flow
Rich Lane9a003812012-10-04 17:17:59 -0700159 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800160 self.controller.message_send(flow_mod_msg)
Rich Lane3a261d52013-01-03 17:45:08 -0800161 do_barrier(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700162
163 # no packets sent, so zero packet count
Rich Lanec42dbad2012-10-11 10:57:44 -0700164 self.verifyStats(flow_mod_msg, match, ofp.OFPP_NONE, test_timeout, 0)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700165
166 # send packet N times
167 num_sends = random.randint(10,20)
Rich Lane9a003812012-10-04 17:17:59 -0700168 logging.info("Sending " + str(num_sends) + " test packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700169 for i in range(0,num_sends):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700170 sendPacket(self, pkt, ingress_port, egress_port,
171 test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700172
Rich Lanec42dbad2012-10-11 10:57:44 -0700173 self.verifyStats(flow_mod_msg, match, ofp.OFPP_NONE, test_timeout, num_sends)
174 self.verifyStats(flow_mod_msg, match, egress_port, test_timeout, num_sends)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700175 for wc in WILDCARD_VALUES:
Ed Swierk99a74de2012-08-22 06:40:54 -0700176 match.wildcards = required_wildcards(self) | wc
Rich Lanec42dbad2012-10-11 10:57:44 -0700177 self.verifyStats(flow_mod_msg, match, egress_port, test_timeout, num_sends)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700178
179
Rich Laneb90a1c42012-10-05 09:16:05 -0700180class TwoFlowStats(base_tests.SimpleDataPlane):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700181 """
182 Verify flow stats are properly retrieved.
183
184 Generate two packets and install two matching flows
185 Send some number of packets
186 Send a flow stats request to match the flows and retrieve stats
187 Verify that the packet counter has incremented
188
189 TODO: add a third flow, and then configure the match to exclude
190 that flow?
191 """
192
193 def buildFlowModMsg(self, pkt, ingress_port, egress_port):
Ed Swierk99a74de2012-08-22 06:40:54 -0700194 match = packet_to_flow_match(self, pkt)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700195 match.wildcards &= ~ofp.OFPFW_IN_PORT
196 self.assertTrue(match is not None,
197 "Could not generate flow match from pkt")
Dan Talayco89d57342010-06-07 16:24:59 -0700198 match.in_port = ingress_port
199
Rich Laneba3f0e22013-03-11 16:43:57 -0700200 flow_mod_msg = ofp.message.flow_add()
Dan Talayco89d57342010-06-07 16:24:59 -0700201 flow_mod_msg.match = match
202 flow_mod_msg.cookie = random.randint(0,9007199254740992)
203 flow_mod_msg.buffer_id = 0xffffffff
Ken Chiang620bdcc2012-03-23 12:52:07 -0700204 flow_mod_msg.idle_timeout = 0
205 flow_mod_msg.hard_timeout = 0
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800206 act = ofp.action.output()
Dan Talayco89d57342010-06-07 16:24:59 -0700207 act.port = egress_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800208 flow_mod_msg.actions.append(act)
Dan Talayco89d57342010-06-07 16:24:59 -0700209
Rich Lane9a003812012-10-04 17:17:59 -0700210 logging.info("Ingress " + str(ingress_port) +
Ken Chiang620bdcc2012-03-23 12:52:07 -0700211 " to egress " + str(egress_port))
Dan Talayco89d57342010-06-07 16:24:59 -0700212
Ken Chiang620bdcc2012-03-23 12:52:07 -0700213 return flow_mod_msg
Dan Talayco89d57342010-06-07 16:24:59 -0700214
Ken Chiangaa5bc062012-03-31 14:03:28 -0700215 def sumStatsReplyCounts(self, response):
216 total_packets = 0
Rich Lane5fd6faf2013-03-11 13:30:20 -0700217 for obj in response.entries:
Ken Chiangaa5bc062012-03-31 14:03:28 -0700218 #self.assertEqual(match, obj.match,
219 # "Matches do not match")
Rich Lane9a003812012-10-04 17:17:59 -0700220 logging.info("Received " + str(obj.packet_count)
Ken Chiangaa5bc062012-03-31 14:03:28 -0700221 + " packets")
222 total_packets += obj.packet_count
223 return total_packets
Ken Chiang620bdcc2012-03-23 12:52:07 -0700224
225 def verifyStats(self, match, out_port, test_timeout, packet_count):
Rich Lane28fa9272013-03-08 16:00:25 -0800226 stat_req = ofp.message.flow_stats_request()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700227 stat_req.match = match
228 stat_req.table_id = 0xff
229 stat_req.out_port = out_port
230
231 all_packets_received = 0
232 for i in range(0,test_timeout):
Rich Lane9a003812012-10-04 17:17:59 -0700233 logging.info("Sending stats request")
Ken Chiangaa5bc062012-03-31 14:03:28 -0700234 # TODO: move REPLY_MORE handling to controller.transact?
Ken Chiangfb593e72012-03-28 17:19:13 -0700235 response, pkt = self.controller.transact(stat_req,
236 timeout=test_timeout)
237 self.assertTrue(response is not None,
238 "No response to stats request")
Ken Chiangaa5bc062012-03-31 14:03:28 -0700239 total_packets = self.sumStatsReplyCounts(response)
240
241 while response.flags == ofp.OFPSF_REPLY_MORE:
242 response, pkt = self.controller.poll(exp_msg=
243 ofp.OFPT_STATS_REPLY,
244 timeout=test_timeout)
245 total_packets += self.sumStatsReplyCounts(response)
246
Ken Chiang620bdcc2012-03-23 12:52:07 -0700247 if total_packets == packet_count:
248 all_packets_received = 1
249 break
250 sleep(1)
251
252 self.assertTrue(all_packets_received,
Ken Chiangaa5bc062012-03-31 14:03:28 -0700253 "Total stats packet count " + str(total_packets) +
254 " does not match number sent " + str(packet_count))
Ken Chiang620bdcc2012-03-23 12:52:07 -0700255
256 def runTest(self):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700257 # TODO: set from command-line parameter
258 test_timeout = 60
259
Rich Lane477f4812012-10-04 22:49:00 -0700260 of_ports = config["port_map"].keys()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700261 of_ports.sort()
262 self.assertTrue(len(of_ports) >= 3, "Not enough ports for test")
263 ingress_port = of_ports[0];
264 egress_port1 = of_ports[1];
265 egress_port2 = of_ports[2];
266
Rich Lane32bf9482013-01-03 17:26:30 -0800267 delete_all_flows(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700268
269 pkt1 = simple_tcp_packet()
270 flow_mod_msg1 = self.buildFlowModMsg(pkt1, ingress_port, egress_port1)
271
Rich Laned0478ff2013-03-11 12:46:58 -0700272 pkt2 = simple_tcp_packet(eth_src='0:7:7:7:7:7')
Ken Chiang620bdcc2012-03-23 12:52:07 -0700273 flow_mod_msg2 = self.buildFlowModMsg(pkt2, ingress_port, egress_port2)
274
Rich Lane9a003812012-10-04 17:17:59 -0700275 logging.info("Inserting flow1")
Rich Lane5c3151c2013-01-03 17:15:41 -0800276 self.controller.message_send(flow_mod_msg1)
Rich Lane9a003812012-10-04 17:17:59 -0700277 logging.info("Inserting flow2")
Rich Lane5c3151c2013-01-03 17:15:41 -0800278 self.controller.message_send(flow_mod_msg2)
Rich Lane3a261d52013-01-03 17:45:08 -0800279 do_barrier(self.controller)
Dan Talayco89d57342010-06-07 16:24:59 -0700280
Ken Chiang620bdcc2012-03-23 12:52:07 -0700281 num_pkt1s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700282 logging.info("Sending " + str(num_pkt1s) + " pkt1s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700283 num_pkt2s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700284 logging.info("Sending " + str(num_pkt2s) + " pkt2s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700285 for i in range(0,num_pkt1s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700286 sendPacket(self, pkt1, ingress_port, egress_port1, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700287 for i in range(0,num_pkt2s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700288 sendPacket(self, pkt2, ingress_port, egress_port2, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700289
Ed Swierk99a74de2012-08-22 06:40:54 -0700290 match1 = packet_to_flow_match(self, pkt1)
Rich Lane9a003812012-10-04 17:17:59 -0700291 logging.info("Verifying flow1's " + str(num_pkt1s) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700292 self.verifyStats(match1, ofp.OFPP_NONE, test_timeout, num_pkt1s)
Ed Swierk99a74de2012-08-22 06:40:54 -0700293 match2 = packet_to_flow_match(self, pkt2)
Rich Lane9a003812012-10-04 17:17:59 -0700294 logging.info("Verifying flow2's " + str(num_pkt2s) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700295 self.verifyStats(match2, ofp.OFPP_NONE, test_timeout, num_pkt2s)
296 match1.wildcards |= ofp.OFPFW_DL_SRC
Rich Lane9a003812012-10-04 17:17:59 -0700297 logging.info("Verifying combined " + str(num_pkt1s+num_pkt2s) + " packets")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700298 self.verifyStats(match1, ofp.OFPP_NONE, test_timeout,
299 num_pkt1s+num_pkt2s)
300 # TODO: sweep through the wildcards to verify matching?
301
302
Rich Laneb90a1c42012-10-05 09:16:05 -0700303class AggregateStats(base_tests.SimpleDataPlane):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700304 """
305 Verify aggregate flow stats are properly retrieved.
306
307 Generate two packets
308 Generate and install two matching flows
309 Send an aggregate stats request
310 Verify that aggregate stats are correct
311 Also verify out_port filtering
312 """
313
314 def buildFlowModMsg(self, pkt, ingress_port, egress_port):
Ed Swierk99a74de2012-08-22 06:40:54 -0700315 match = packet_to_flow_match(self, pkt)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700316 match.wildcards &= ~ofp.OFPFW_IN_PORT
317 self.assertTrue(match is not None,
318 "Could not generate flow match from pkt")
319 match.in_port = ingress_port
320
Rich Laneba3f0e22013-03-11 16:43:57 -0700321 flow_mod_msg = ofp.message.flow_add()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700322 flow_mod_msg.match = match
323 flow_mod_msg.cookie = random.randint(0,9007199254740992)
324 flow_mod_msg.buffer_id = 0xffffffff
325 flow_mod_msg.idle_timeout = 0
326 flow_mod_msg.hard_timeout = 0
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800327 act = ofp.action.output()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700328 act.port = egress_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800329 flow_mod_msg.actions.append(act)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700330
Rich Lane9a003812012-10-04 17:17:59 -0700331 logging.info("Ingress " + str(ingress_port) +
Ken Chiang620bdcc2012-03-23 12:52:07 -0700332 " to egress " + str(egress_port))
333
334 return flow_mod_msg
335
Ken Chiang620bdcc2012-03-23 12:52:07 -0700336 def verifyAggFlowStats(self, match, out_port, test_timeout,
337 flow_count, packet_count):
Rich Lane28fa9272013-03-08 16:00:25 -0800338 stat_req = ofp.message.aggregate_stats_request()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700339 stat_req.match = match
340 stat_req.table_id = 0xff
341 stat_req.out_port = out_port
342
343 all_packets_received = 0
344 for i in range(0,test_timeout):
Rich Lane9a003812012-10-04 17:17:59 -0700345 logging.info("Sending stats request")
Ken Chiangfb593e72012-03-28 17:19:13 -0700346 response, pkt = self.controller.transact(stat_req,
347 timeout=test_timeout)
348 self.assertTrue(response is not None,
349 "No response to stats request")
Rich Lane032669d2013-03-11 23:36:28 -0700350 self.assertTrue(response.flow_count == flow_count,
351 "Flow count " + str(response.flow_count) +
352 " does not match expected " + str(flow_count))
353 logging.info("Received " + str(response.packet_count) + " packets")
354 if response.packet_count == packet_count:
355 all_packets_received = 1
Ken Chiang620bdcc2012-03-23 12:52:07 -0700356
357 if all_packets_received:
358 break
359 sleep(1)
360
361 self.assertTrue(all_packets_received,
362 "Packet count does not match number sent")
363
364 def runTest(self):
Ken Chiang620bdcc2012-03-23 12:52:07 -0700365 # TODO: set from command-line parameter
366 test_timeout = 60
367
Rich Lane477f4812012-10-04 22:49:00 -0700368 of_ports = config["port_map"].keys()
Ken Chiang620bdcc2012-03-23 12:52:07 -0700369 of_ports.sort()
370 self.assertTrue(len(of_ports) >= 3, "Not enough ports for test")
371 ingress_port = of_ports[0];
372 egress_port1 = of_ports[1];
373 egress_port2 = of_ports[2];
374
Rich Lane32bf9482013-01-03 17:26:30 -0800375 delete_all_flows(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700376
377 pkt1 = simple_tcp_packet()
378 flow_mod_msg1 = self.buildFlowModMsg(pkt1, ingress_port, egress_port1)
379
Rich Laned0478ff2013-03-11 12:46:58 -0700380 pkt2 = simple_tcp_packet(eth_src='0:7:7:7:7:7')
Ken Chiang620bdcc2012-03-23 12:52:07 -0700381 flow_mod_msg2 = self.buildFlowModMsg(pkt2, ingress_port, egress_port2)
382
Rich Lane9a003812012-10-04 17:17:59 -0700383 logging.info("Inserting flow1")
Rich Lane5c3151c2013-01-03 17:15:41 -0800384 self.controller.message_send(flow_mod_msg1)
Rich Lane9a003812012-10-04 17:17:59 -0700385 logging.info("Inserting flow2")
Rich Lane5c3151c2013-01-03 17:15:41 -0800386 self.controller.message_send(flow_mod_msg2)
Rich Lane3a261d52013-01-03 17:45:08 -0800387 do_barrier(self.controller)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700388
389 num_pkt1s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700390 logging.info("Sending " + str(num_pkt1s) + " pkt1s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700391 num_pkt2s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700392 logging.info("Sending " + str(num_pkt2s) + " pkt2s")
Ken Chiang620bdcc2012-03-23 12:52:07 -0700393 for i in range(0,num_pkt1s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700394 sendPacket(self, pkt1, ingress_port, egress_port1, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700395 for i in range(0,num_pkt2s):
Ken Chiangaa5bc062012-03-31 14:03:28 -0700396 sendPacket(self, pkt2, ingress_port, egress_port2, test_timeout)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700397
398 # loop on flow stats request until timeout
Ed Swierk99a74de2012-08-22 06:40:54 -0700399 match = packet_to_flow_match(self, pkt1)
Ken Chiang620bdcc2012-03-23 12:52:07 -0700400 match.wildcards |= ofp.OFPFW_DL_SRC
401 self.verifyAggFlowStats(match, ofp.OFPP_NONE, test_timeout,
402 2, num_pkt1s+num_pkt2s)
403
404 # out_port filter for egress_port1
405 self.verifyAggFlowStats(match, egress_port1, test_timeout,
406 1, num_pkt1s)
407
408 # out_port filter for egress_port1
409 self.verifyAggFlowStats(match, egress_port2, test_timeout,
410 1, num_pkt2s)
Rich Lane97a5f502012-10-11 09:28:11 -0700411
Rich Lanef062b3d2012-10-11 09:53:19 -0700412class EmptyFlowStats(base_tests.SimpleDataPlane):
413 """
414 Verify the switch replies to a flow stats request when
415 the query doesn't match any flows.
416 """
417 def runTest(self):
Rich Lane32bf9482013-01-03 17:26:30 -0800418 delete_all_flows(self.controller)
Rich Lane0237baf2013-03-11 22:34:59 -0700419 match = ofp.match()
Rich Lanef062b3d2012-10-11 09:53:19 -0700420 match.wildcards = 0
Rich Lane28fa9272013-03-08 16:00:25 -0800421 stat_req = ofp.message.flow_stats_request()
Rich Lanef062b3d2012-10-11 09:53:19 -0700422 stat_req.match = match
423 stat_req.table_id = 0xff
424 stat_req.out_port = ofp.OFPP_NONE
425
426 response, pkt = self.controller.transact(stat_req)
427 self.assertTrue(response is not None,
428 "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -0700429 self.assertEquals(len(response.entries), 0)
Rich Lanef062b3d2012-10-11 09:53:19 -0700430 self.assertEquals(response.flags, 0)
431
Rich Lane97a5f502012-10-11 09:28:11 -0700432class EmptyAggregateStats(base_tests.SimpleDataPlane):
433 """
434 Verify aggregate flow stats are properly retrieved when
435 the query doesn't match any flows.
436 """
437 def runTest(self):
Rich Lane32bf9482013-01-03 17:26:30 -0800438 delete_all_flows(self.controller)
Rich Lane0237baf2013-03-11 22:34:59 -0700439 match = ofp.match()
Rich Lane97a5f502012-10-11 09:28:11 -0700440 match.wildcards = 0
Rich Lane28fa9272013-03-08 16:00:25 -0800441 stat_req = ofp.message.aggregate_stats_request()
Rich Lane97a5f502012-10-11 09:28:11 -0700442 stat_req.match = match
443 stat_req.table_id = 0xff
444 stat_req.out_port = ofp.OFPP_NONE
445
446 response, pkt = self.controller.transact(stat_req)
447 self.assertTrue(response is not None,
448 "No response to stats request")
Rich Lane032669d2013-03-11 23:36:28 -0700449 self.assertEquals(response.flow_count, 0)
450 self.assertEquals(response.packet_count, 0)
451 self.assertEquals(response.byte_count, 0)
Rich Laned10e8e02012-11-21 15:48:36 -0800452
453class DeletedFlowStats(base_tests.SimpleDataPlane):
454 """
455 Verify flow stats are properly returned when a flow is deleted.
456
457 Generate a packet
458 Generate and install a matching flow
459 Send the packet
460 Delete the flow
461 Verify that the flow_removed message has the correct stats
462 """
463
464 def runTest(self):
465 # TODO: set from command-line parameter
466 test_timeout = 60
467
468 of_ports = config["port_map"].keys()
469 of_ports.sort()
470 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
471
Rich Lane32bf9482013-01-03 17:26:30 -0800472 delete_all_flows(self.controller)
Rich Laned10e8e02012-11-21 15:48:36 -0800473
474 # build packet
475 pkt = simple_tcp_packet()
476 match = packet_to_flow_match(self, pkt)
477 match.wildcards &= ~ofp.OFPFW_IN_PORT
478 self.assertTrue(match is not None,
479 "Could not generate flow match from pkt")
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800480 act = ofp.action.output()
Rich Laned10e8e02012-11-21 15:48:36 -0800481
482 # build flow
483 ingress_port = of_ports[0];
484 egress_port = of_ports[1];
485 logging.info("Ingress " + str(ingress_port) +
486 " to egress " + str(egress_port))
487 match.in_port = ingress_port
Rich Laneba3f0e22013-03-11 16:43:57 -0700488 flow_mod_msg = ofp.message.flow_add()
Rich Laned10e8e02012-11-21 15:48:36 -0800489 flow_mod_msg.match = copy.deepcopy(match)
490 flow_mod_msg.cookie = random.randint(0,9007199254740992)
491 flow_mod_msg.buffer_id = 0xffffffff
492 flow_mod_msg.idle_timeout = 0
493 flow_mod_msg.hard_timeout = 0
494 flow_mod_msg.priority = 100
495 flow_mod_msg.flags = ofp.OFPFF_SEND_FLOW_REM
496 act.port = egress_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800497 flow_mod_msg.actions.append(act)
Rich Laned10e8e02012-11-21 15:48:36 -0800498
499 # send flow
500 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800501 self.controller.message_send(flow_mod_msg)
Rich Lane3a261d52013-01-03 17:45:08 -0800502 do_barrier(self.controller)
Rich Laned10e8e02012-11-21 15:48:36 -0800503
504 # send packet N times
505 num_sends = random.randint(10,20)
506 logging.info("Sending " + str(num_sends) + " test packets")
507 for i in range(0,num_sends):
508 sendPacket(self, pkt, ingress_port, egress_port,
509 test_timeout)
510
Ken Chiang626ce1d2013-01-09 11:58:50 -0800511 # wait some time for flow stats to be propagated
512 # FIXME timeout handling should be unified
513 sleep(test_param_get('default_timeout', default=2))
514
Rich Laned10e8e02012-11-21 15:48:36 -0800515 # delete flow
516 logging.info("Deleting flow")
Rich Lane32bf9482013-01-03 17:26:30 -0800517 delete_all_flows(self.controller)
Rich Laned10e8e02012-11-21 15:48:36 -0800518
519 # wait for flow_removed message
520 flow_removed, _ = self.controller.poll(
521 exp_msg=ofp.OFPT_FLOW_REMOVED, timeout=test_timeout)
522
523 self.assertTrue(flow_removed != None, "Did not receive flow_removed message")
Ken Chiang626ce1d2013-01-09 11:58:50 -0800524 self.assertEqual(flow_removed.cookie, flow_mod_msg.cookie,
525 "Received cookie " + str(flow_removed.cookie) +
526 " does not match expected " + str(flow_mod_msg.cookie))
527 self.assertEqual(flow_removed.reason, ofp.OFPRR_DELETE,
528 "Received reason " + str(flow_removed.reason) +
529 " does not match expected " + str(ofp.OFPRR_DELETE))
530 self.assertEqual(flow_removed.packet_count, num_sends,
531 "Received packet count " + str(flow_removed.packet_count) +
532 " does not match expected " + str(num_sends))
533 tolerance = 5 # percent
534 self.assertTrue(flow_removed.byte_count >=
535 (1-tolerance/100.0) * num_sends * len(str(pkt)) and
536 flow_removed.byte_count <=
537 (1+tolerance/100.0) * num_sends * len(str(pkt)),
538 "Received byte count " + str(flow_removed.byte_count) +
539 " is not within " + str(tolerance) + "% of expected " +
540 str(num_sends*len(str(pkt))))