blob: f84829f0bc4393fa8e726951260c783863f9580f [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
Shudong Zhoudf510a82012-08-03 18:08:40 -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
27
Rich Lane477f4812012-10-04 22:49:00 -070028from oftest import config
Shudong Zhoudf510a82012-08-03 18:08:40 -070029import oftest.controller as controller
Rich Laned7b0ffa2013-03-08 15:53:42 -080030import ofp
Shudong Zhoudf510a82012-08-03 18:08:40 -070031import oftest.dataplane as dataplane
Shudong Zhoudf510a82012-08-03 18:08:40 -070032import oftest.parse as parse
Rich Laneb90a1c42012-10-05 09:16:05 -070033import oftest.base_tests as base_tests
Shudong Zhoudf510a82012-08-03 18:08:40 -070034
Rich Laneda3b5ad2012-10-03 09:05:32 -070035from oftest.testutils import *
Shudong Zhoudf510a82012-08-03 18:08:40 -070036from time import sleep
37
Shudong Zhoudf510a82012-08-03 18:08:40 -070038# TODO: ovs has problems with VLAN id?
39WILDCARD_VALUES = [ofp.OFPFW_IN_PORT,
40 # (ofp.OFPFW_DL_VLAN | ofp.OFPFW_DL_VLAN_PCP),
41 ofp.OFPFW_DL_SRC,
42 ofp.OFPFW_DL_DST,
43 (ofp.OFPFW_DL_TYPE | ofp.OFPFW_NW_SRC_ALL |
44 ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS | ofp.OFPFW_NW_PROTO |
45 ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
46 (ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
47 ofp.OFPFW_TP_SRC,
48 ofp.OFPFW_TP_DST,
49 ofp.OFPFW_NW_SRC_MASK,
50 ofp.OFPFW_NW_DST_MASK,
51 ofp.OFPFW_DL_VLAN_PCP,
52 ofp.OFPFW_NW_TOS]
53
Shudong Zhoudf510a82012-08-03 18:08:40 -070054def sendPacket(obj, pkt, ingress_port, egress_port, test_timeout):
55
Rich Lane9a003812012-10-04 17:17:59 -070056 logging.info("Sending packet to dp port " + str(ingress_port) +
Shudong Zhoudf510a82012-08-03 18:08:40 -070057 ", expecting output on " + str(egress_port))
58 obj.dataplane.send(ingress_port, str(pkt))
59
60 exp_pkt_arg = None
61 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -070062 if config["relax"]:
Shudong Zhoudf510a82012-08-03 18:08:40 -070063 exp_pkt_arg = pkt
64 exp_port = egress_port
65
66 (rcv_port, rcv_pkt, pkt_time) = obj.dataplane.poll(port_number=exp_port,
67 exp_pkt=exp_pkt_arg)
68 obj.assertTrue(rcv_pkt is not None,
69 "Packet not received on port " + str(egress_port))
Rich Lane9a003812012-10-04 17:17:59 -070070 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Shudong Zhoudf510a82012-08-03 18:08:40 -070071 str(rcv_port))
72 obj.assertEqual(rcv_port, egress_port,
73 "Packet received on port " + str(rcv_port) +
74 ", expected port " + str(egress_port))
75 obj.assertEqual(str(pkt), str(rcv_pkt),
76 'Response packet does not match send packet')
77
Shudong Zhou50051c72012-08-06 16:53:46 -070078def getStats(obj, port):
Rich Lane0d4a5582015-04-10 12:25:39 -070079 entries = get_port_stats(obj, port)
80 for item in entries:
Rich Lane9a003812012-10-04 17:17:59 -070081 logging.info("Sent " + str(item.tx_packets) + " packets")
Shudong Zhou50051c72012-08-06 16:53:46 -070082 packet_sent = item.tx_packets
83 packet_recv = item.rx_packets
Rich Lane9a003812012-10-04 17:17:59 -070084 logging.info("Port %d stats count: tx %d rx %d" % (port, packet_sent, packet_recv))
Shudong Zhou50051c72012-08-06 16:53:46 -070085 return packet_sent, packet_recv
86
Shudong Zhou1a5b0822012-10-29 22:03:34 -070087def getAllStats(obj):
Rich Lane0d4a5582015-04-10 12:25:39 -070088 entries = get_port_stats(obj, ofp.OFPP_NONE)
Shudong Zhou1a5b0822012-10-29 22:03:34 -070089 stats = {}
Rich Lane0d4a5582015-04-10 12:25:39 -070090 for item in entries:
Shudong Zhou1a5b0822012-10-29 22:03:34 -070091 stats[ item.port_no ] = ( item.tx_packets, item.rx_packets )
92 return stats
93
Shudong Zhou50051c72012-08-06 16:53:46 -070094def verifyStats(obj, port, test_timeout, packet_sent, packet_recv):
Rich Lane28fa9272013-03-08 16:00:25 -080095 stat_req = ofp.message.port_stats_request()
Shudong Zhou50051c72012-08-06 16:53:46 -070096 stat_req.port_no = port
97
98 all_packets_received = 0
99 all_packets_sent = 0
100 sent = recv = 0
101 for i in range(0,test_timeout):
Rich Lane9a003812012-10-04 17:17:59 -0700102 logging.info("Sending stats request")
Shudong Zhou50051c72012-08-06 16:53:46 -0700103 response, pkt = obj.controller.transact(stat_req,
104 timeout=test_timeout)
105 obj.assertTrue(response is not None,
106 "No response to stats request")
Rich Lane5fd6faf2013-03-11 13:30:20 -0700107 obj.assertTrue(len(response.entries) == 1,
Shudong Zhou50051c72012-08-06 16:53:46 -0700108 "Did not receive port stats reply")
Rich Lane5fd6faf2013-03-11 13:30:20 -0700109 for item in response.entries:
Shudong Zhou50051c72012-08-06 16:53:46 -0700110 sent = item.tx_packets
111 recv = item.rx_packets
Rich Lane9a003812012-10-04 17:17:59 -0700112 logging.info("Sent " + str(item.tx_packets) + " packets")
Rich Lane6d618172015-04-10 12:22:55 -0700113 if item.tx_packets >= packet_sent:
Shudong Zhou50051c72012-08-06 16:53:46 -0700114 all_packets_sent = 1
Rich Lane9a003812012-10-04 17:17:59 -0700115 logging.info("Received " + str(item.rx_packets) + " packets")
Rich Lane6d618172015-04-10 12:22:55 -0700116 if item.rx_packets >= packet_recv:
Shudong Zhou50051c72012-08-06 16:53:46 -0700117 all_packets_received = 1
118
119 if all_packets_received and all_packets_sent:
120 break
121 sleep(1)
122
Rich Lane9a003812012-10-04 17:17:59 -0700123 logging.info("Expected port %d stats count: tx %d rx %d" % (port, packet_sent, packet_recv))
124 logging.info("Actual port %d stats count: tx %d rx %d" % (port, sent, recv))
Shudong Zhou50051c72012-08-06 16:53:46 -0700125 obj.assertTrue(all_packets_sent,
126 "Packet sent does not match number sent")
127 obj.assertTrue(all_packets_received,
128 "Packet received does not match number sent")
129
Rich Lane97e99652013-01-02 17:23:20 -0800130@group('smoke')
Rich Laneb90a1c42012-10-05 09:16:05 -0700131class SingleFlowStats(base_tests.SimpleDataPlane):
Shudong Zhoudf510a82012-08-03 18:08:40 -0700132 """
133 Verify flow stats are properly retrieved.
134
135 Generate a packet
Shudong Zhou1d423922012-08-04 16:45:02 -0700136 Generate and install a flow from port 1 to 2
Shudong Zhoudf510a82012-08-03 18:08:40 -0700137 Send the packet
Shudong Zhou1d423922012-08-04 16:45:02 -0700138 Send port stats request to port 1 & 2
Shudong Zhoudf510a82012-08-03 18:08:40 -0700139 Verify that the packet counter has incremented
140 """
141
Shudong Zhoudf510a82012-08-03 18:08:40 -0700142 def runTest(self):
Shudong Zhoudf510a82012-08-03 18:08:40 -0700143 # TODO: set from command-line parameter
144 test_timeout = 60
145
Rich Lane477f4812012-10-04 22:49:00 -0700146 of_ports = config["port_map"].keys()
Shudong Zhoudf510a82012-08-03 18:08:40 -0700147 of_ports.sort()
148 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
149
Rich Lane32bf9482013-01-03 17:26:30 -0800150 delete_all_flows(self.controller)
Shudong Zhoudf510a82012-08-03 18:08:40 -0700151
152 # build packet
153 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700154 match = packet_to_flow_match(self, pkt)
Shudong Zhoudf510a82012-08-03 18:08:40 -0700155 match.wildcards &= ~ofp.OFPFW_IN_PORT
156 self.assertTrue(match is not None,
157 "Could not generate flow match from pkt")
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800158 act = ofp.action.output()
Shudong Zhoudf510a82012-08-03 18:08:40 -0700159
160 # build flow
161 ingress_port = of_ports[0];
162 egress_port = of_ports[1];
Rich Lane9a003812012-10-04 17:17:59 -0700163 logging.info("Ingress " + str(ingress_port) +
Shudong Zhoudf510a82012-08-03 18:08:40 -0700164 " to egress " + str(egress_port))
165 match.in_port = ingress_port
Rich Laneba3f0e22013-03-11 16:43:57 -0700166 flow_mod_msg = ofp.message.flow_add()
Shudong Zhoudf510a82012-08-03 18:08:40 -0700167 flow_mod_msg.match = match
168 flow_mod_msg.cookie = random.randint(0,9007199254740992)
169 flow_mod_msg.buffer_id = 0xffffffff
170 flow_mod_msg.idle_timeout = 0
171 flow_mod_msg.hard_timeout = 0
172 act.port = egress_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800173 flow_mod_msg.actions.append(act)
Shudong Zhoudf510a82012-08-03 18:08:40 -0700174
175 # send flow
Rich Lane9a003812012-10-04 17:17:59 -0700176 logging.info("Inserting flow")
Rich Lane5c3151c2013-01-03 17:15:41 -0800177 self.controller.message_send(flow_mod_msg)
Rich Lane3a261d52013-01-03 17:45:08 -0800178 do_barrier(self.controller)
Shudong Zhoudf510a82012-08-03 18:08:40 -0700179
Shudong Zhou50051c72012-08-06 16:53:46 -0700180 # get initial port stats count
181 initTxInPort, initRxInPort = getStats(self, ingress_port)
182 initTxOutPort, initRxOutPort = getStats(self, egress_port)
Shudong Zhoudf510a82012-08-03 18:08:40 -0700183
184 # send packet N times
185 num_sends = random.randint(10,20)
Rich Lane9a003812012-10-04 17:17:59 -0700186 logging.info("Sending " + str(num_sends) + " test packets")
Shudong Zhoudf510a82012-08-03 18:08:40 -0700187 for i in range(0,num_sends):
188 sendPacket(self, pkt, ingress_port, egress_port,
189 test_timeout)
190
Shudong Zhou50051c72012-08-06 16:53:46 -0700191 verifyStats(self, ingress_port, test_timeout, initTxInPort, initRxInPort + num_sends)
192 verifyStats(self, egress_port, test_timeout, initTxOutPort + num_sends, initRxOutPort)
Shudong Zhou1d423922012-08-04 16:45:02 -0700193
Rich Laneb90a1c42012-10-05 09:16:05 -0700194class MultiFlowStats(base_tests.SimpleDataPlane):
Shudong Zhou1d423922012-08-04 16:45:02 -0700195 """
196 Verify flow stats are properly retrieved.
197
198 Generate two packets and install two matching flows
199 Send some number of packets
200 Send a port stats request to get packet count
201 Verify that the packet counter has incremented
202 """
203
204 def buildFlowModMsg(self, pkt, ingress_port, egress_port):
Ed Swierk99a74de2012-08-22 06:40:54 -0700205 match = packet_to_flow_match(self, pkt)
Shudong Zhou1d423922012-08-04 16:45:02 -0700206 match.wildcards &= ~ofp.OFPFW_IN_PORT
207 self.assertTrue(match is not None,
208 "Could not generate flow match from pkt")
209 match.in_port = ingress_port
210
Rich Laneba3f0e22013-03-11 16:43:57 -0700211 flow_mod_msg = ofp.message.flow_add()
Shudong Zhou1d423922012-08-04 16:45:02 -0700212 flow_mod_msg.match = match
213 flow_mod_msg.cookie = random.randint(0,9007199254740992)
214 flow_mod_msg.buffer_id = 0xffffffff
215 flow_mod_msg.idle_timeout = 0
216 flow_mod_msg.hard_timeout = 0
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800217 act = ofp.action.output()
Shudong Zhou1d423922012-08-04 16:45:02 -0700218 act.port = egress_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800219 flow_mod_msg.actions.append(act)
Shudong Zhou1d423922012-08-04 16:45:02 -0700220
Rich Lane9a003812012-10-04 17:17:59 -0700221 logging.info("Ingress " + str(ingress_port) +
Shudong Zhou1d423922012-08-04 16:45:02 -0700222 " to egress " + str(egress_port))
223
224 return flow_mod_msg
225
Shudong Zhou1d423922012-08-04 16:45:02 -0700226 def runTest(self):
Shudong Zhou1d423922012-08-04 16:45:02 -0700227 # TODO: set from command-line parameter
228 test_timeout = 60
229
Rich Lane477f4812012-10-04 22:49:00 -0700230 of_ports = config["port_map"].keys()
Shudong Zhou1d423922012-08-04 16:45:02 -0700231 of_ports.sort()
232 self.assertTrue(len(of_ports) >= 3, "Not enough ports for test")
233 ingress_port = of_ports[0];
234 egress_port1 = of_ports[1];
235 egress_port2 = of_ports[2];
236
Rich Lane32bf9482013-01-03 17:26:30 -0800237 delete_all_flows(self.controller)
Shudong Zhou1d423922012-08-04 16:45:02 -0700238
239 pkt1 = simple_tcp_packet()
240 flow_mod_msg1 = self.buildFlowModMsg(pkt1, ingress_port, egress_port1)
241
Rich Laned0478ff2013-03-11 12:46:58 -0700242 pkt2 = simple_tcp_packet(eth_src='0:7:7:7:7:7')
Shudong Zhou1d423922012-08-04 16:45:02 -0700243 flow_mod_msg2 = self.buildFlowModMsg(pkt2, ingress_port, egress_port2)
244
Rich Lane9a003812012-10-04 17:17:59 -0700245 logging.info("Inserting flow1")
Rich Lane5c3151c2013-01-03 17:15:41 -0800246 self.controller.message_send(flow_mod_msg1)
Rich Lane9a003812012-10-04 17:17:59 -0700247 logging.info("Inserting flow2")
Rich Lane5c3151c2013-01-03 17:15:41 -0800248 self.controller.message_send(flow_mod_msg2)
Rich Lane3a261d52013-01-03 17:45:08 -0800249 do_barrier(self.controller)
Shudong Zhou1d423922012-08-04 16:45:02 -0700250
Shudong Zhou50051c72012-08-06 16:53:46 -0700251 # get initial port stats count
252 initTxInPort, initRxInPort = getStats(self, ingress_port)
253 initTxOutPort1, initRxOutPort1 = getStats(self, egress_port1)
254 initTxOutPort2, initRxOutPort2 = getStats(self, egress_port2)
255
Shudong Zhou1d423922012-08-04 16:45:02 -0700256 num_pkt1s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700257 logging.info("Sending " + str(num_pkt1s) + " pkt1s")
Shudong Zhou1d423922012-08-04 16:45:02 -0700258 num_pkt2s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700259 logging.info("Sending " + str(num_pkt2s) + " pkt2s")
Shudong Zhou1d423922012-08-04 16:45:02 -0700260 for i in range(0,num_pkt1s):
261 sendPacket(self, pkt1, ingress_port, egress_port1, test_timeout)
262 for i in range(0,num_pkt2s):
263 sendPacket(self, pkt2, ingress_port, egress_port2, test_timeout)
Shudong Zhou50051c72012-08-06 16:53:46 -0700264
265 verifyStats(self, ingress_port, test_timeout,
266 initTxInPort, initRxInPort + num_pkt1s + num_pkt2s)
267 verifyStats(self, egress_port1, test_timeout,
268 initTxOutPort1 + num_pkt1s, initRxOutPort1)
269 verifyStats(self, egress_port2, test_timeout,
270 initTxOutPort2 + num_pkt2s, initRxOutPort2)
Shudong Zhou1a5b0822012-10-29 22:03:34 -0700271
272class AllPortStats(base_tests.SimpleDataPlane):
273 """
274 Verify all port stats are properly retrieved.
275
276 First, get stats from each port. Then get all port stats, verify
277 consistency with single port stats.
278 """
279
280 # TODO: This is copied from MultiFlowStats. Need to combine.
281 def buildFlowModMsg(self, pkt, ingress_port, egress_port):
282 match = packet_to_flow_match(self, pkt)
283 match.wildcards &= ~ofp.OFPFW_IN_PORT
284 self.assertTrue(match is not None,
285 "Could not generate flow match from pkt")
286 match.in_port = ingress_port
287
Rich Laneba3f0e22013-03-11 16:43:57 -0700288 flow_mod_msg = ofp.message.flow_add()
Shudong Zhou1a5b0822012-10-29 22:03:34 -0700289 flow_mod_msg.match = match
290 flow_mod_msg.cookie = random.randint(0,9007199254740992)
291 flow_mod_msg.buffer_id = 0xffffffff
292 flow_mod_msg.idle_timeout = 0
293 flow_mod_msg.hard_timeout = 0
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800294 act = ofp.action.output()
Shudong Zhou1a5b0822012-10-29 22:03:34 -0700295 act.port = egress_port
Rich Lanec495d9e2013-03-08 17:43:36 -0800296 flow_mod_msg.actions.append(act)
Shudong Zhou1a5b0822012-10-29 22:03:34 -0700297
298 logging.info("Ingress " + str(ingress_port) +
299 " to egress " + str(egress_port))
300
301 return flow_mod_msg
302
303 def runTest(self):
Rich Laneae68aec2015-04-08 13:58:34 -0700304 delete_all_flows(self.controller)
305 do_barrier(self.controller)
306
Shudong Zhou1a5b0822012-10-29 22:03:34 -0700307 # TODO: set from command-line parameter
308 test_timeout = 60
309
310 of_ports = config["port_map"].keys()
311 of_ports.sort()
312 self.assertTrue(len(of_ports) >= 3, "Not enough ports for test")
313 port0 = of_ports[0];
314 port1 = of_ports[1];
315 port2 = of_ports[2];
316
317 # construct some packets and flows, send to switch
318 pkt1 = simple_tcp_packet()
319 flow_mod_msg1 = self.buildFlowModMsg(pkt1, port0, port1)
320
Rich Laned0478ff2013-03-11 12:46:58 -0700321 pkt2 = simple_tcp_packet(eth_src='0:7:7:7:7:7')
Shudong Zhou1a5b0822012-10-29 22:03:34 -0700322 flow_mod_msg2 = self.buildFlowModMsg(pkt2, port0, port2)
323
324 logging.info("Inserting flow1")
Rich Lane5c3151c2013-01-03 17:15:41 -0800325 self.controller.message_send(flow_mod_msg1)
Shudong Zhou1a5b0822012-10-29 22:03:34 -0700326 logging.info("Inserting flow2")
Rich Lane5c3151c2013-01-03 17:15:41 -0800327 self.controller.message_send(flow_mod_msg2)
Rich Lane3a261d52013-01-03 17:45:08 -0800328 do_barrier(self.controller)
Shudong Zhou1a5b0822012-10-29 22:03:34 -0700329
330 num_pkt1s = random.randint(5,10)
331 logging.info("Sending " + str(num_pkt1s) + " pkt1s")
332 num_pkt2s = random.randint(10,15)
333 logging.info("Sending " + str(num_pkt2s) + " pkt2s")
334 for i in range(0,num_pkt1s):
335 sendPacket(self, pkt1, port0, port1, test_timeout)
336 for i in range(0,num_pkt2s):
337 sendPacket(self, pkt2, port0, port2, test_timeout)
338
339 # get individual port stats count
340 port_stats = {}
341 port_stats[ port0 ] = getStats(self, port0)
342 port_stats[ port1 ] = getStats(self, port1)
343 port_stats[ port2 ] = getStats(self, port2)
344
345 all_stats = getAllStats(self)
Rich Lanee53897c2012-10-30 09:40:13 -0700346 self.assertEqual(port_stats[ port0 ], all_stats[ port0 ])
347 self.assertEqual(port_stats[ port1 ], all_stats[ port1 ])
348 self.assertEqual(port_stats[ port2 ], all_stats[ port2 ])