blob: 5cfb1bb3f716eca507ed2b63f3ccae362184071e [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
Shudong Zhoudf510a82012-08-03 18:08:40 -070026#@var fs_config Local copy of global configuration data
27fs_config = None
28
29# TODO: ovs has problems with VLAN id?
30WILDCARD_VALUES = [ofp.OFPFW_IN_PORT,
31 # (ofp.OFPFW_DL_VLAN | ofp.OFPFW_DL_VLAN_PCP),
32 ofp.OFPFW_DL_SRC,
33 ofp.OFPFW_DL_DST,
34 (ofp.OFPFW_DL_TYPE | ofp.OFPFW_NW_SRC_ALL |
35 ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS | ofp.OFPFW_NW_PROTO |
36 ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
37 (ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
38 ofp.OFPFW_TP_SRC,
39 ofp.OFPFW_TP_DST,
40 ofp.OFPFW_NW_SRC_MASK,
41 ofp.OFPFW_NW_DST_MASK,
42 ofp.OFPFW_DL_VLAN_PCP,
43 ofp.OFPFW_NW_TOS]
44
45def test_set_init(config):
46 """
47 Set up function for packet action test classes
48
49 @param config The configuration dictionary; see oft
50 """
51
52 basic.test_set_init(config)
53
54 global fs_port_map
Shudong Zhoudf510a82012-08-03 18:08:40 -070055 global fs_config
56
Shudong Zhoudf510a82012-08-03 18:08:40 -070057 fs_port_map = config["port_map"]
58 fs_config = config
59
60def sendPacket(obj, pkt, ingress_port, egress_port, test_timeout):
61
Rich Lane9a003812012-10-04 17:17:59 -070062 logging.info("Sending packet to dp port " + str(ingress_port) +
Shudong Zhoudf510a82012-08-03 18:08:40 -070063 ", expecting output on " + str(egress_port))
64 obj.dataplane.send(ingress_port, str(pkt))
65
66 exp_pkt_arg = None
67 exp_port = None
68 if fs_config["relax"]:
69 exp_pkt_arg = pkt
70 exp_port = egress_port
71
72 (rcv_port, rcv_pkt, pkt_time) = obj.dataplane.poll(port_number=exp_port,
73 exp_pkt=exp_pkt_arg)
74 obj.assertTrue(rcv_pkt is not None,
75 "Packet not received on port " + str(egress_port))
Rich Lane9a003812012-10-04 17:17:59 -070076 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Shudong Zhoudf510a82012-08-03 18:08:40 -070077 str(rcv_port))
78 obj.assertEqual(rcv_port, egress_port,
79 "Packet received on port " + str(rcv_port) +
80 ", expected port " + str(egress_port))
81 obj.assertEqual(str(pkt), str(rcv_pkt),
82 'Response packet does not match send packet')
83
Shudong Zhou50051c72012-08-06 16:53:46 -070084def getStats(obj, port):
85 stat_req = message.port_stats_request()
86 stat_req.port_no = port
87
Rich Lane9a003812012-10-04 17:17:59 -070088 logging.info("Sending stats request")
Shudong Zhou50051c72012-08-06 16:53:46 -070089 response, pkt = obj.controller.transact(stat_req, timeout=2)
90 obj.assertTrue(response is not None,
91 "No response to stats request")
92 obj.assertTrue(len(response.stats) == 1,
93 "Did not receive port stats reply")
94 for item in response.stats:
Rich Lane9a003812012-10-04 17:17:59 -070095 logging.info("Sent " + str(item.tx_packets) + " packets")
Shudong Zhou50051c72012-08-06 16:53:46 -070096 packet_sent = item.tx_packets
97 packet_recv = item.rx_packets
Rich Lane9a003812012-10-04 17:17:59 -070098 logging.info("Port %d stats count: tx %d rx %d" % (port, packet_sent, packet_recv))
Shudong Zhou50051c72012-08-06 16:53:46 -070099 return packet_sent, packet_recv
100
101def verifyStats(obj, port, test_timeout, packet_sent, packet_recv):
102 stat_req = message.port_stats_request()
103 stat_req.port_no = port
104
105 all_packets_received = 0
106 all_packets_sent = 0
107 sent = recv = 0
108 for i in range(0,test_timeout):
Rich Lane9a003812012-10-04 17:17:59 -0700109 logging.info("Sending stats request")
Shudong Zhou50051c72012-08-06 16:53:46 -0700110 response, pkt = obj.controller.transact(stat_req,
111 timeout=test_timeout)
112 obj.assertTrue(response is not None,
113 "No response to stats request")
114 obj.assertTrue(len(response.stats) == 1,
115 "Did not receive port stats reply")
116 for item in response.stats:
117 sent = item.tx_packets
118 recv = item.rx_packets
Rich Lane9a003812012-10-04 17:17:59 -0700119 logging.info("Sent " + str(item.tx_packets) + " packets")
Shudong Zhou50051c72012-08-06 16:53:46 -0700120 if item.tx_packets == packet_sent:
121 all_packets_sent = 1
Rich Lane9a003812012-10-04 17:17:59 -0700122 logging.info("Received " + str(item.rx_packets) + " packets")
Shudong Zhou50051c72012-08-06 16:53:46 -0700123 if item.rx_packets == packet_recv:
124 all_packets_received = 1
125
126 if all_packets_received and all_packets_sent:
127 break
128 sleep(1)
129
Rich Lane9a003812012-10-04 17:17:59 -0700130 logging.info("Expected port %d stats count: tx %d rx %d" % (port, packet_sent, packet_recv))
131 logging.info("Actual port %d stats count: tx %d rx %d" % (port, sent, recv))
Shudong Zhou50051c72012-08-06 16:53:46 -0700132 obj.assertTrue(all_packets_sent,
133 "Packet sent does not match number sent")
134 obj.assertTrue(all_packets_received,
135 "Packet received does not match number sent")
136
Shudong Zhoudf510a82012-08-03 18:08:40 -0700137class SingleFlowStats(basic.SimpleDataPlane):
138 """
139 Verify flow stats are properly retrieved.
140
141 Generate a packet
Shudong Zhou1d423922012-08-04 16:45:02 -0700142 Generate and install a flow from port 1 to 2
Shudong Zhoudf510a82012-08-03 18:08:40 -0700143 Send the packet
Shudong Zhou1d423922012-08-04 16:45:02 -0700144 Send port stats request to port 1 & 2
Shudong Zhoudf510a82012-08-03 18:08:40 -0700145 Verify that the packet counter has incremented
146 """
147
Shudong Zhoudf510a82012-08-03 18:08:40 -0700148 def runTest(self):
149 global fs_port_map
150
151 # TODO: set from command-line parameter
152 test_timeout = 60
153
154 of_ports = fs_port_map.keys()
155 of_ports.sort()
156 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
157
Rich Lane9a003812012-10-04 17:17:59 -0700158 rc = delete_all_flows(self.controller)
Shudong Zhoudf510a82012-08-03 18:08:40 -0700159 self.assertEqual(rc, 0, "Failed to delete all flows")
160
161 # build packet
162 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700163 match = packet_to_flow_match(self, pkt)
Shudong Zhoudf510a82012-08-03 18:08:40 -0700164 match.wildcards &= ~ofp.OFPFW_IN_PORT
165 self.assertTrue(match is not None,
166 "Could not generate flow match from pkt")
167 act = action.action_output()
168
169 # build flow
170 ingress_port = of_ports[0];
171 egress_port = of_ports[1];
Rich Lane9a003812012-10-04 17:17:59 -0700172 logging.info("Ingress " + str(ingress_port) +
Shudong Zhoudf510a82012-08-03 18:08:40 -0700173 " to egress " + str(egress_port))
174 match.in_port = ingress_port
175 flow_mod_msg = message.flow_mod()
176 flow_mod_msg.match = match
177 flow_mod_msg.cookie = random.randint(0,9007199254740992)
178 flow_mod_msg.buffer_id = 0xffffffff
179 flow_mod_msg.idle_timeout = 0
180 flow_mod_msg.hard_timeout = 0
181 act.port = egress_port
182 self.assertTrue(flow_mod_msg.actions.add(act), "Could not add action")
183
184 # send flow
Rich Lane9a003812012-10-04 17:17:59 -0700185 logging.info("Inserting flow")
Shudong Zhoudf510a82012-08-03 18:08:40 -0700186 rv = self.controller.message_send(flow_mod_msg)
187 self.assertTrue(rv != -1, "Error installing flow mod")
188 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
189
Shudong Zhou50051c72012-08-06 16:53:46 -0700190 # get initial port stats count
191 initTxInPort, initRxInPort = getStats(self, ingress_port)
192 initTxOutPort, initRxOutPort = getStats(self, egress_port)
Shudong Zhoudf510a82012-08-03 18:08:40 -0700193
194 # send packet N times
195 num_sends = random.randint(10,20)
Rich Lane9a003812012-10-04 17:17:59 -0700196 logging.info("Sending " + str(num_sends) + " test packets")
Shudong Zhoudf510a82012-08-03 18:08:40 -0700197 for i in range(0,num_sends):
198 sendPacket(self, pkt, ingress_port, egress_port,
199 test_timeout)
200
Shudong Zhou50051c72012-08-06 16:53:46 -0700201 verifyStats(self, ingress_port, test_timeout, initTxInPort, initRxInPort + num_sends)
202 verifyStats(self, egress_port, test_timeout, initTxOutPort + num_sends, initRxOutPort)
Shudong Zhou1d423922012-08-04 16:45:02 -0700203
204
205class MultiFlowStats(basic.SimpleDataPlane):
206 """
207 Verify flow stats are properly retrieved.
208
209 Generate two packets and install two matching flows
210 Send some number of packets
211 Send a port stats request to get packet count
212 Verify that the packet counter has incremented
213 """
214
215 def buildFlowModMsg(self, pkt, ingress_port, egress_port):
Ed Swierk99a74de2012-08-22 06:40:54 -0700216 match = packet_to_flow_match(self, pkt)
Shudong Zhou1d423922012-08-04 16:45:02 -0700217 match.wildcards &= ~ofp.OFPFW_IN_PORT
218 self.assertTrue(match is not None,
219 "Could not generate flow match from pkt")
220 match.in_port = ingress_port
221
222 flow_mod_msg = message.flow_mod()
223 flow_mod_msg.match = match
224 flow_mod_msg.cookie = random.randint(0,9007199254740992)
225 flow_mod_msg.buffer_id = 0xffffffff
226 flow_mod_msg.idle_timeout = 0
227 flow_mod_msg.hard_timeout = 0
228 act = action.action_output()
229 act.port = egress_port
230 self.assertTrue(flow_mod_msg.actions.add(act), "Could not add action")
231
Rich Lane9a003812012-10-04 17:17:59 -0700232 logging.info("Ingress " + str(ingress_port) +
Shudong Zhou1d423922012-08-04 16:45:02 -0700233 " to egress " + str(egress_port))
234
235 return flow_mod_msg
236
Shudong Zhou1d423922012-08-04 16:45:02 -0700237 def runTest(self):
238 global fs_port_map
239
240 # TODO: set from command-line parameter
241 test_timeout = 60
242
243 of_ports = fs_port_map.keys()
244 of_ports.sort()
245 self.assertTrue(len(of_ports) >= 3, "Not enough ports for test")
246 ingress_port = of_ports[0];
247 egress_port1 = of_ports[1];
248 egress_port2 = of_ports[2];
249
Rich Lane9a003812012-10-04 17:17:59 -0700250 rc = delete_all_flows(self.controller)
Shudong Zhou1d423922012-08-04 16:45:02 -0700251 self.assertEqual(rc, 0, "Failed to delete all flows")
252
253 pkt1 = simple_tcp_packet()
254 flow_mod_msg1 = self.buildFlowModMsg(pkt1, ingress_port, egress_port1)
255
256 pkt2 = simple_tcp_packet(dl_src='0:7:7:7:7:7')
257 flow_mod_msg2 = self.buildFlowModMsg(pkt2, ingress_port, egress_port2)
258
Rich Lane9a003812012-10-04 17:17:59 -0700259 logging.info("Inserting flow1")
Shudong Zhou1d423922012-08-04 16:45:02 -0700260 rv = self.controller.message_send(flow_mod_msg1)
261 self.assertTrue(rv != -1, "Error installing flow mod")
Rich Lane9a003812012-10-04 17:17:59 -0700262 logging.info("Inserting flow2")
Shudong Zhou1d423922012-08-04 16:45:02 -0700263 rv = self.controller.message_send(flow_mod_msg2)
264 self.assertTrue(rv != -1, "Error installing flow mod")
265 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
266
Shudong Zhou50051c72012-08-06 16:53:46 -0700267 # get initial port stats count
268 initTxInPort, initRxInPort = getStats(self, ingress_port)
269 initTxOutPort1, initRxOutPort1 = getStats(self, egress_port1)
270 initTxOutPort2, initRxOutPort2 = getStats(self, egress_port2)
271
Shudong Zhou1d423922012-08-04 16:45:02 -0700272 num_pkt1s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700273 logging.info("Sending " + str(num_pkt1s) + " pkt1s")
Shudong Zhou1d423922012-08-04 16:45:02 -0700274 num_pkt2s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700275 logging.info("Sending " + str(num_pkt2s) + " pkt2s")
Shudong Zhou1d423922012-08-04 16:45:02 -0700276 for i in range(0,num_pkt1s):
277 sendPacket(self, pkt1, ingress_port, egress_port1, test_timeout)
278 for i in range(0,num_pkt2s):
279 sendPacket(self, pkt2, ingress_port, egress_port2, test_timeout)
Shudong Zhou50051c72012-08-06 16:53:46 -0700280
281 verifyStats(self, ingress_port, test_timeout,
282 initTxInPort, initRxInPort + num_pkt1s + num_pkt2s)
283 verifyStats(self, egress_port1, test_timeout,
284 initTxOutPort1 + num_pkt1s, initRxOutPort1)
285 verifyStats(self, egress_port2, test_timeout,
286 initTxOutPort2 + num_pkt2s, initRxOutPort2)