blob: facef3ee51fc8907141a1157d6decd41e459c2b5 [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
20from testutils import *
21from 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
89class SingleFlowStats(basic.SimpleDataPlane):
90 """
91 Verify flow stats are properly retrieved.
92
93 Generate a packet
Shudong Zhou1d423922012-08-04 16:45:02 -070094 Generate and install a flow from port 1 to 2
Shudong Zhoudf510a82012-08-03 18:08:40 -070095 Send the packet
Shudong Zhou1d423922012-08-04 16:45:02 -070096 Send port stats request to port 1 & 2
Shudong Zhoudf510a82012-08-03 18:08:40 -070097 Verify that the packet counter has incremented
98 """
99
100 def verifyStats(self, port, test_timeout, packet_sent, packet_recv):
101 stat_req = message.port_stats_request()
102 stat_req.port_no = port
103
104 all_packets_received = 0
105 all_packets_sent = 0
106 for i in range(0,test_timeout):
107 fs_logger.info("Sending stats request")
108 response, pkt = self.controller.transact(stat_req,
109 timeout=test_timeout)
110 self.assertTrue(response is not None,
111 "No response to stats request")
112 self.assertTrue(len(response.stats) == 1,
113 "Did not receive port stats reply")
114 for obj in response.stats:
115 fs_logger.info("Sent " + str(obj.tx_packets) + " packets")
116 if obj.tx_packets == packet_sent:
117 all_packets_sent = 1
118 fs_logger.info("Received " + str(obj.rx_packets) + " packets")
119 if obj.rx_packets == packet_recv:
120 all_packets_received = 1
121
122 if all_packets_received and all_packets_sent:
123 break
124 sleep(1)
125
126 self.assertTrue(all_packets_sent,
127 "Packet sent does not match number sent")
128 self.assertTrue(all_packets_received,
129 "Packet received does not match number sent")
130
131 def runTest(self):
132 global fs_port_map
133
134 # TODO: set from command-line parameter
135 test_timeout = 60
136
137 of_ports = fs_port_map.keys()
138 of_ports.sort()
139 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
140
141 rc = delete_all_flows(self.controller, fs_logger)
142 self.assertEqual(rc, 0, "Failed to delete all flows")
143
144 # build packet
145 pkt = simple_tcp_packet()
146 match = parse.packet_to_flow_match(pkt)
147 match.wildcards &= ~ofp.OFPFW_IN_PORT
148 self.assertTrue(match is not None,
149 "Could not generate flow match from pkt")
150 act = action.action_output()
151
152 # build flow
153 ingress_port = of_ports[0];
154 egress_port = of_ports[1];
155 fs_logger.info("Ingress " + str(ingress_port) +
156 " to egress " + str(egress_port))
157 match.in_port = ingress_port
158 flow_mod_msg = message.flow_mod()
159 flow_mod_msg.match = match
160 flow_mod_msg.cookie = random.randint(0,9007199254740992)
161 flow_mod_msg.buffer_id = 0xffffffff
162 flow_mod_msg.idle_timeout = 0
163 flow_mod_msg.hard_timeout = 0
164 act.port = egress_port
165 self.assertTrue(flow_mod_msg.actions.add(act), "Could not add action")
166
167 # send flow
168 fs_logger.info("Inserting flow")
169 rv = self.controller.message_send(flow_mod_msg)
170 self.assertTrue(rv != -1, "Error installing flow mod")
171 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
172
173 # no packets sent, so zero packet count
174 self.verifyStats(ingress_port, test_timeout, 0, 0)
175 self.verifyStats(egress_port, test_timeout, 0, 0)
176
177 # send packet N times
178 num_sends = random.randint(10,20)
179 fs_logger.info("Sending " + str(num_sends) + " test packets")
180 for i in range(0,num_sends):
181 sendPacket(self, pkt, ingress_port, egress_port,
182 test_timeout)
183
184 self.verifyStats(ingress_port, test_timeout, 0, num_sends)
185 self.verifyStats(egress_port, test_timeout, num_sends, 0)
Shudong Zhou1d423922012-08-04 16:45:02 -0700186
187
188class MultiFlowStats(basic.SimpleDataPlane):
189 """
190 Verify flow stats are properly retrieved.
191
192 Generate two packets and install two matching flows
193 Send some number of packets
194 Send a port stats request to get packet count
195 Verify that the packet counter has incremented
196 """
197
198 def buildFlowModMsg(self, pkt, ingress_port, egress_port):
199 match = parse.packet_to_flow_match(pkt)
200 match.wildcards &= ~ofp.OFPFW_IN_PORT
201 self.assertTrue(match is not None,
202 "Could not generate flow match from pkt")
203 match.in_port = ingress_port
204
205 flow_mod_msg = message.flow_mod()
206 flow_mod_msg.match = match
207 flow_mod_msg.cookie = random.randint(0,9007199254740992)
208 flow_mod_msg.buffer_id = 0xffffffff
209 flow_mod_msg.idle_timeout = 0
210 flow_mod_msg.hard_timeout = 0
211 act = action.action_output()
212 act.port = egress_port
213 self.assertTrue(flow_mod_msg.actions.add(act), "Could not add action")
214
215 fs_logger.info("Ingress " + str(ingress_port) +
216 " to egress " + str(egress_port))
217
218 return flow_mod_msg
219
220 def verifyStats(self, port, test_timeout, packet_sent, packet_recv):
221 stat_req = message.port_stats_request()
222 stat_req.port_no = port
223
224 all_packets_received = 0
225 all_packets_sent = 0
226 for i in range(0,test_timeout):
227 fs_logger.info("Sending stats request")
228 response, pkt = self.controller.transact(stat_req,
229 timeout=test_timeout)
230 self.assertTrue(response is not None,
231 "No response to stats request")
232 self.assertTrue(len(response.stats) == 1,
233 "Did not receive port stats reply")
234 for obj in response.stats:
235 fs_logger.info("Sent " + str(obj.tx_packets) + " packets")
236 if obj.tx_packets == packet_sent:
237 all_packets_sent = 1
238 fs_logger.info("Received " + str(obj.rx_packets) + " packets")
239 if obj.rx_packets == packet_recv:
240 all_packets_received = 1
241
242 if all_packets_received and all_packets_sent:
243 break
244 sleep(1)
245
246 self.assertTrue(all_packets_sent,
247 "Packet sent does not match number sent")
248 self.assertTrue(all_packets_received,
249 "Packet received does not match number sent")
250
251 def runTest(self):
252 global fs_port_map
253
254 # TODO: set from command-line parameter
255 test_timeout = 60
256
257 of_ports = fs_port_map.keys()
258 of_ports.sort()
259 self.assertTrue(len(of_ports) >= 3, "Not enough ports for test")
260 ingress_port = of_ports[0];
261 egress_port1 = of_ports[1];
262 egress_port2 = of_ports[2];
263
264 rc = delete_all_flows(self.controller, fs_logger)
265 self.assertEqual(rc, 0, "Failed to delete all flows")
266
267 pkt1 = simple_tcp_packet()
268 flow_mod_msg1 = self.buildFlowModMsg(pkt1, ingress_port, egress_port1)
269
270 pkt2 = simple_tcp_packet(dl_src='0:7:7:7:7:7')
271 flow_mod_msg2 = self.buildFlowModMsg(pkt2, ingress_port, egress_port2)
272
273 fs_logger.info("Inserting flow1")
274 rv = self.controller.message_send(flow_mod_msg1)
275 self.assertTrue(rv != -1, "Error installing flow mod")
276 fs_logger.info("Inserting flow2")
277 rv = self.controller.message_send(flow_mod_msg2)
278 self.assertTrue(rv != -1, "Error installing flow mod")
279 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
280
281 num_pkt1s = random.randint(10,30)
282 fs_logger.info("Sending " + str(num_pkt1s) + " pkt1s")
283 num_pkt2s = random.randint(10,30)
284 fs_logger.info("Sending " + str(num_pkt2s) + " pkt2s")
285 for i in range(0,num_pkt1s):
286 sendPacket(self, pkt1, ingress_port, egress_port1, test_timeout)
287 for i in range(0,num_pkt2s):
288 sendPacket(self, pkt2, ingress_port, egress_port2, test_timeout)
289
290 self.verifyStats(ingress_port, test_timeout, 0, num_pkt1s + num_pkt2s)
291 self.verifyStats(egress_port1, test_timeout, num_pkt1s, 0)
292 self.verifyStats(egress_port2, test_timeout, num_pkt2s, 0)