blob: 96d3cc5123655eb50ee1e06d8aec59bcd0f5e988 [file] [log] [blame]
Shudong Zhoudf510a82012-08-03 18:08:40 -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
11
12import oftest.controller as controller
13import oftest.cstruct as ofp
14import oftest.message as message
15import oftest.dataplane as dataplane
16import oftest.action as action
17import oftest.parse as parse
18import basic
19
Rich Laneda3b5ad2012-10-03 09:05:32 -070020from oftest.testutils import *
Shudong Zhoudf510a82012-08-03 18:08:40 -070021from time import sleep
22
23#@var fs_port_map Local copy of the configuration map from OF port
24# numbers to OS interfaces
25fs_port_map = None
26#@var fs_logger Local logger object
27fs_logger = None
28#@var fs_config Local copy of global configuration data
29fs_config = None
30
31# TODO: ovs has problems with VLAN id?
32WILDCARD_VALUES = [ofp.OFPFW_IN_PORT,
33 # (ofp.OFPFW_DL_VLAN | ofp.OFPFW_DL_VLAN_PCP),
34 ofp.OFPFW_DL_SRC,
35 ofp.OFPFW_DL_DST,
36 (ofp.OFPFW_DL_TYPE | ofp.OFPFW_NW_SRC_ALL |
37 ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS | ofp.OFPFW_NW_PROTO |
38 ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
39 (ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
40 ofp.OFPFW_TP_SRC,
41 ofp.OFPFW_TP_DST,
42 ofp.OFPFW_NW_SRC_MASK,
43 ofp.OFPFW_NW_DST_MASK,
44 ofp.OFPFW_DL_VLAN_PCP,
45 ofp.OFPFW_NW_TOS]
46
47def test_set_init(config):
48 """
49 Set up function for packet action test classes
50
51 @param config The configuration dictionary; see oft
52 """
53
54 basic.test_set_init(config)
55
56 global fs_port_map
57 global fs_logger
58 global fs_config
59
60 fs_logger = logging.getLogger("flow_stats")
61 fs_logger.info("Initializing test set")
62 fs_port_map = config["port_map"]
63 fs_config = config
64
65def sendPacket(obj, pkt, ingress_port, egress_port, test_timeout):
66
67 fs_logger.info("Sending packet to dp port " + str(ingress_port) +
68 ", expecting output on " + str(egress_port))
69 obj.dataplane.send(ingress_port, str(pkt))
70
71 exp_pkt_arg = None
72 exp_port = None
73 if fs_config["relax"]:
74 exp_pkt_arg = pkt
75 exp_port = egress_port
76
77 (rcv_port, rcv_pkt, pkt_time) = obj.dataplane.poll(port_number=exp_port,
78 exp_pkt=exp_pkt_arg)
79 obj.assertTrue(rcv_pkt is not None,
80 "Packet not received on port " + str(egress_port))
81 fs_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
82 str(rcv_port))
83 obj.assertEqual(rcv_port, egress_port,
84 "Packet received on port " + str(rcv_port) +
85 ", expected port " + str(egress_port))
86 obj.assertEqual(str(pkt), str(rcv_pkt),
87 'Response packet does not match send packet')
88
Shudong Zhou50051c72012-08-06 16:53:46 -070089def getStats(obj, port):
90 stat_req = message.port_stats_request()
91 stat_req.port_no = port
92
93 fs_logger.info("Sending stats request")
94 response, pkt = obj.controller.transact(stat_req, timeout=2)
95 obj.assertTrue(response is not None,
96 "No response to stats request")
97 obj.assertTrue(len(response.stats) == 1,
98 "Did not receive port stats reply")
99 for item in response.stats:
100 fs_logger.info("Sent " + str(item.tx_packets) + " packets")
101 packet_sent = item.tx_packets
102 packet_recv = item.rx_packets
103 fs_logger.info("Port %d stats count: tx %d rx %d" % (port, packet_sent, packet_recv))
104 return packet_sent, packet_recv
105
106def verifyStats(obj, port, test_timeout, packet_sent, packet_recv):
107 stat_req = message.port_stats_request()
108 stat_req.port_no = port
109
110 all_packets_received = 0
111 all_packets_sent = 0
112 sent = recv = 0
113 for i in range(0,test_timeout):
114 fs_logger.info("Sending stats request")
115 response, pkt = obj.controller.transact(stat_req,
116 timeout=test_timeout)
117 obj.assertTrue(response is not None,
118 "No response to stats request")
119 obj.assertTrue(len(response.stats) == 1,
120 "Did not receive port stats reply")
121 for item in response.stats:
122 sent = item.tx_packets
123 recv = item.rx_packets
124 fs_logger.info("Sent " + str(item.tx_packets) + " packets")
125 if item.tx_packets == packet_sent:
126 all_packets_sent = 1
127 fs_logger.info("Received " + str(item.rx_packets) + " packets")
128 if item.rx_packets == packet_recv:
129 all_packets_received = 1
130
131 if all_packets_received and all_packets_sent:
132 break
133 sleep(1)
134
135 fs_logger.info("Expected port %d stats count: tx %d rx %d" % (port, packet_sent, packet_recv))
136 fs_logger.info("Actual port %d stats count: tx %d rx %d" % (port, sent, recv))
137 obj.assertTrue(all_packets_sent,
138 "Packet sent does not match number sent")
139 obj.assertTrue(all_packets_received,
140 "Packet received does not match number sent")
141
Shudong Zhoudf510a82012-08-03 18:08:40 -0700142class SingleFlowStats(basic.SimpleDataPlane):
143 """
144 Verify flow stats are properly retrieved.
145
146 Generate a packet
Shudong Zhou1d423922012-08-04 16:45:02 -0700147 Generate and install a flow from port 1 to 2
Shudong Zhoudf510a82012-08-03 18:08:40 -0700148 Send the packet
Shudong Zhou1d423922012-08-04 16:45:02 -0700149 Send port stats request to port 1 & 2
Shudong Zhoudf510a82012-08-03 18:08:40 -0700150 Verify that the packet counter has incremented
151 """
152
Shudong Zhoudf510a82012-08-03 18:08:40 -0700153 def runTest(self):
154 global fs_port_map
155
156 # TODO: set from command-line parameter
157 test_timeout = 60
158
159 of_ports = fs_port_map.keys()
160 of_ports.sort()
161 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
162
163 rc = delete_all_flows(self.controller, fs_logger)
164 self.assertEqual(rc, 0, "Failed to delete all flows")
165
166 # build packet
167 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700168 match = packet_to_flow_match(self, pkt)
Shudong Zhoudf510a82012-08-03 18:08:40 -0700169 match.wildcards &= ~ofp.OFPFW_IN_PORT
170 self.assertTrue(match is not None,
171 "Could not generate flow match from pkt")
172 act = action.action_output()
173
174 # build flow
175 ingress_port = of_ports[0];
176 egress_port = of_ports[1];
177 fs_logger.info("Ingress " + str(ingress_port) +
178 " to egress " + str(egress_port))
179 match.in_port = ingress_port
180 flow_mod_msg = message.flow_mod()
181 flow_mod_msg.match = match
182 flow_mod_msg.cookie = random.randint(0,9007199254740992)
183 flow_mod_msg.buffer_id = 0xffffffff
184 flow_mod_msg.idle_timeout = 0
185 flow_mod_msg.hard_timeout = 0
186 act.port = egress_port
187 self.assertTrue(flow_mod_msg.actions.add(act), "Could not add action")
188
189 # send flow
190 fs_logger.info("Inserting flow")
191 rv = self.controller.message_send(flow_mod_msg)
192 self.assertTrue(rv != -1, "Error installing flow mod")
193 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
194
Shudong Zhou50051c72012-08-06 16:53:46 -0700195 # get initial port stats count
196 initTxInPort, initRxInPort = getStats(self, ingress_port)
197 initTxOutPort, initRxOutPort = getStats(self, egress_port)
Shudong Zhoudf510a82012-08-03 18:08:40 -0700198
199 # send packet N times
200 num_sends = random.randint(10,20)
201 fs_logger.info("Sending " + str(num_sends) + " test packets")
202 for i in range(0,num_sends):
203 sendPacket(self, pkt, ingress_port, egress_port,
204 test_timeout)
205
Shudong Zhou50051c72012-08-06 16:53:46 -0700206 verifyStats(self, ingress_port, test_timeout, initTxInPort, initRxInPort + num_sends)
207 verifyStats(self, egress_port, test_timeout, initTxOutPort + num_sends, initRxOutPort)
Shudong Zhou1d423922012-08-04 16:45:02 -0700208
209
210class MultiFlowStats(basic.SimpleDataPlane):
211 """
212 Verify flow stats are properly retrieved.
213
214 Generate two packets and install two matching flows
215 Send some number of packets
216 Send a port stats request to get packet count
217 Verify that the packet counter has incremented
218 """
219
220 def buildFlowModMsg(self, pkt, ingress_port, egress_port):
Ed Swierk99a74de2012-08-22 06:40:54 -0700221 match = packet_to_flow_match(self, pkt)
Shudong Zhou1d423922012-08-04 16:45:02 -0700222 match.wildcards &= ~ofp.OFPFW_IN_PORT
223 self.assertTrue(match is not None,
224 "Could not generate flow match from pkt")
225 match.in_port = ingress_port
226
227 flow_mod_msg = message.flow_mod()
228 flow_mod_msg.match = match
229 flow_mod_msg.cookie = random.randint(0,9007199254740992)
230 flow_mod_msg.buffer_id = 0xffffffff
231 flow_mod_msg.idle_timeout = 0
232 flow_mod_msg.hard_timeout = 0
233 act = action.action_output()
234 act.port = egress_port
235 self.assertTrue(flow_mod_msg.actions.add(act), "Could not add action")
236
237 fs_logger.info("Ingress " + str(ingress_port) +
238 " to egress " + str(egress_port))
239
240 return flow_mod_msg
241
Shudong Zhou1d423922012-08-04 16:45:02 -0700242 def runTest(self):
243 global fs_port_map
244
245 # TODO: set from command-line parameter
246 test_timeout = 60
247
248 of_ports = fs_port_map.keys()
249 of_ports.sort()
250 self.assertTrue(len(of_ports) >= 3, "Not enough ports for test")
251 ingress_port = of_ports[0];
252 egress_port1 = of_ports[1];
253 egress_port2 = of_ports[2];
254
255 rc = delete_all_flows(self.controller, fs_logger)
256 self.assertEqual(rc, 0, "Failed to delete all flows")
257
258 pkt1 = simple_tcp_packet()
259 flow_mod_msg1 = self.buildFlowModMsg(pkt1, ingress_port, egress_port1)
260
261 pkt2 = simple_tcp_packet(dl_src='0:7:7:7:7:7')
262 flow_mod_msg2 = self.buildFlowModMsg(pkt2, ingress_port, egress_port2)
263
264 fs_logger.info("Inserting flow1")
265 rv = self.controller.message_send(flow_mod_msg1)
266 self.assertTrue(rv != -1, "Error installing flow mod")
267 fs_logger.info("Inserting flow2")
268 rv = self.controller.message_send(flow_mod_msg2)
269 self.assertTrue(rv != -1, "Error installing flow mod")
270 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
271
Shudong Zhou50051c72012-08-06 16:53:46 -0700272 # get initial port stats count
273 initTxInPort, initRxInPort = getStats(self, ingress_port)
274 initTxOutPort1, initRxOutPort1 = getStats(self, egress_port1)
275 initTxOutPort2, initRxOutPort2 = getStats(self, egress_port2)
276
Shudong Zhou1d423922012-08-04 16:45:02 -0700277 num_pkt1s = random.randint(10,30)
278 fs_logger.info("Sending " + str(num_pkt1s) + " pkt1s")
279 num_pkt2s = random.randint(10,30)
280 fs_logger.info("Sending " + str(num_pkt2s) + " pkt2s")
281 for i in range(0,num_pkt1s):
282 sendPacket(self, pkt1, ingress_port, egress_port1, test_timeout)
283 for i in range(0,num_pkt2s):
284 sendPacket(self, pkt2, ingress_port, egress_port2, test_timeout)
Shudong Zhou50051c72012-08-06 16:53:46 -0700285
286 verifyStats(self, ingress_port, test_timeout,
287 initTxInPort, initRxInPort + num_pkt1s + num_pkt2s)
288 verifyStats(self, egress_port1, test_timeout,
289 initTxOutPort1 + num_pkt1s, initRxOutPort1)
290 verifyStats(self, egress_port2, test_timeout,
291 initTxOutPort2 + num_pkt2s, initRxOutPort2)