blob: 0de8de5f6b6fc9c1f04cf44408587e320ba55ae7 [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
Rich Lane477f4812012-10-04 22:49:00 -070012from oftest import config
Shudong Zhoudf510a82012-08-03 18:08:40 -070013import oftest.controller as controller
14import oftest.cstruct as ofp
15import oftest.message as message
16import oftest.dataplane as dataplane
17import oftest.action as action
18import oftest.parse as parse
19import basic
20
Rich Laneda3b5ad2012-10-03 09:05:32 -070021from oftest.testutils import *
Shudong Zhoudf510a82012-08-03 18:08:40 -070022from time import sleep
23
Shudong Zhoudf510a82012-08-03 18:08:40 -070024# TODO: ovs has problems with VLAN id?
25WILDCARD_VALUES = [ofp.OFPFW_IN_PORT,
26 # (ofp.OFPFW_DL_VLAN | ofp.OFPFW_DL_VLAN_PCP),
27 ofp.OFPFW_DL_SRC,
28 ofp.OFPFW_DL_DST,
29 (ofp.OFPFW_DL_TYPE | ofp.OFPFW_NW_SRC_ALL |
30 ofp.OFPFW_NW_DST_ALL | ofp.OFPFW_NW_TOS | ofp.OFPFW_NW_PROTO |
31 ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
32 (ofp.OFPFW_NW_PROTO | ofp.OFPFW_TP_SRC | ofp.OFPFW_TP_DST),
33 ofp.OFPFW_TP_SRC,
34 ofp.OFPFW_TP_DST,
35 ofp.OFPFW_NW_SRC_MASK,
36 ofp.OFPFW_NW_DST_MASK,
37 ofp.OFPFW_DL_VLAN_PCP,
38 ofp.OFPFW_NW_TOS]
39
Shudong Zhoudf510a82012-08-03 18:08:40 -070040def sendPacket(obj, pkt, ingress_port, egress_port, test_timeout):
41
Rich Lane9a003812012-10-04 17:17:59 -070042 logging.info("Sending packet to dp port " + str(ingress_port) +
Shudong Zhoudf510a82012-08-03 18:08:40 -070043 ", expecting output on " + str(egress_port))
44 obj.dataplane.send(ingress_port, str(pkt))
45
46 exp_pkt_arg = None
47 exp_port = None
Rich Lane477f4812012-10-04 22:49:00 -070048 if config["relax"]:
Shudong Zhoudf510a82012-08-03 18:08:40 -070049 exp_pkt_arg = pkt
50 exp_port = egress_port
51
52 (rcv_port, rcv_pkt, pkt_time) = obj.dataplane.poll(port_number=exp_port,
53 exp_pkt=exp_pkt_arg)
54 obj.assertTrue(rcv_pkt is not None,
55 "Packet not received on port " + str(egress_port))
Rich Lane9a003812012-10-04 17:17:59 -070056 logging.debug("Packet len " + str(len(rcv_pkt)) + " in on " +
Shudong Zhoudf510a82012-08-03 18:08:40 -070057 str(rcv_port))
58 obj.assertEqual(rcv_port, egress_port,
59 "Packet received on port " + str(rcv_port) +
60 ", expected port " + str(egress_port))
61 obj.assertEqual(str(pkt), str(rcv_pkt),
62 'Response packet does not match send packet')
63
Shudong Zhou50051c72012-08-06 16:53:46 -070064def getStats(obj, port):
65 stat_req = message.port_stats_request()
66 stat_req.port_no = port
67
Rich Lane9a003812012-10-04 17:17:59 -070068 logging.info("Sending stats request")
Shudong Zhou50051c72012-08-06 16:53:46 -070069 response, pkt = obj.controller.transact(stat_req, timeout=2)
70 obj.assertTrue(response is not None,
71 "No response to stats request")
72 obj.assertTrue(len(response.stats) == 1,
73 "Did not receive port stats reply")
74 for item in response.stats:
Rich Lane9a003812012-10-04 17:17:59 -070075 logging.info("Sent " + str(item.tx_packets) + " packets")
Shudong Zhou50051c72012-08-06 16:53:46 -070076 packet_sent = item.tx_packets
77 packet_recv = item.rx_packets
Rich Lane9a003812012-10-04 17:17:59 -070078 logging.info("Port %d stats count: tx %d rx %d" % (port, packet_sent, packet_recv))
Shudong Zhou50051c72012-08-06 16:53:46 -070079 return packet_sent, packet_recv
80
81def verifyStats(obj, port, test_timeout, packet_sent, packet_recv):
82 stat_req = message.port_stats_request()
83 stat_req.port_no = port
84
85 all_packets_received = 0
86 all_packets_sent = 0
87 sent = recv = 0
88 for i in range(0,test_timeout):
Rich Lane9a003812012-10-04 17:17:59 -070089 logging.info("Sending stats request")
Shudong Zhou50051c72012-08-06 16:53:46 -070090 response, pkt = obj.controller.transact(stat_req,
91 timeout=test_timeout)
92 obj.assertTrue(response is not None,
93 "No response to stats request")
94 obj.assertTrue(len(response.stats) == 1,
95 "Did not receive port stats reply")
96 for item in response.stats:
97 sent = item.tx_packets
98 recv = item.rx_packets
Rich Lane9a003812012-10-04 17:17:59 -070099 logging.info("Sent " + str(item.tx_packets) + " packets")
Shudong Zhou50051c72012-08-06 16:53:46 -0700100 if item.tx_packets == packet_sent:
101 all_packets_sent = 1
Rich Lane9a003812012-10-04 17:17:59 -0700102 logging.info("Received " + str(item.rx_packets) + " packets")
Shudong Zhou50051c72012-08-06 16:53:46 -0700103 if item.rx_packets == packet_recv:
104 all_packets_received = 1
105
106 if all_packets_received and all_packets_sent:
107 break
108 sleep(1)
109
Rich Lane9a003812012-10-04 17:17:59 -0700110 logging.info("Expected port %d stats count: tx %d rx %d" % (port, packet_sent, packet_recv))
111 logging.info("Actual port %d stats count: tx %d rx %d" % (port, sent, recv))
Shudong Zhou50051c72012-08-06 16:53:46 -0700112 obj.assertTrue(all_packets_sent,
113 "Packet sent does not match number sent")
114 obj.assertTrue(all_packets_received,
115 "Packet received does not match number sent")
116
Shudong Zhoudf510a82012-08-03 18:08:40 -0700117class SingleFlowStats(basic.SimpleDataPlane):
118 """
119 Verify flow stats are properly retrieved.
120
121 Generate a packet
Shudong Zhou1d423922012-08-04 16:45:02 -0700122 Generate and install a flow from port 1 to 2
Shudong Zhoudf510a82012-08-03 18:08:40 -0700123 Send the packet
Shudong Zhou1d423922012-08-04 16:45:02 -0700124 Send port stats request to port 1 & 2
Shudong Zhoudf510a82012-08-03 18:08:40 -0700125 Verify that the packet counter has incremented
126 """
127
Shudong Zhoudf510a82012-08-03 18:08:40 -0700128 def runTest(self):
Shudong Zhoudf510a82012-08-03 18:08:40 -0700129 # TODO: set from command-line parameter
130 test_timeout = 60
131
Rich Lane477f4812012-10-04 22:49:00 -0700132 of_ports = config["port_map"].keys()
Shudong Zhoudf510a82012-08-03 18:08:40 -0700133 of_ports.sort()
134 self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
135
Rich Lane9a003812012-10-04 17:17:59 -0700136 rc = delete_all_flows(self.controller)
Shudong Zhoudf510a82012-08-03 18:08:40 -0700137 self.assertEqual(rc, 0, "Failed to delete all flows")
138
139 # build packet
140 pkt = simple_tcp_packet()
Ed Swierk99a74de2012-08-22 06:40:54 -0700141 match = packet_to_flow_match(self, pkt)
Shudong Zhoudf510a82012-08-03 18:08:40 -0700142 match.wildcards &= ~ofp.OFPFW_IN_PORT
143 self.assertTrue(match is not None,
144 "Could not generate flow match from pkt")
145 act = action.action_output()
146
147 # build flow
148 ingress_port = of_ports[0];
149 egress_port = of_ports[1];
Rich Lane9a003812012-10-04 17:17:59 -0700150 logging.info("Ingress " + str(ingress_port) +
Shudong Zhoudf510a82012-08-03 18:08:40 -0700151 " to egress " + str(egress_port))
152 match.in_port = ingress_port
153 flow_mod_msg = message.flow_mod()
154 flow_mod_msg.match = match
155 flow_mod_msg.cookie = random.randint(0,9007199254740992)
156 flow_mod_msg.buffer_id = 0xffffffff
157 flow_mod_msg.idle_timeout = 0
158 flow_mod_msg.hard_timeout = 0
159 act.port = egress_port
160 self.assertTrue(flow_mod_msg.actions.add(act), "Could not add action")
161
162 # send flow
Rich Lane9a003812012-10-04 17:17:59 -0700163 logging.info("Inserting flow")
Shudong Zhoudf510a82012-08-03 18:08:40 -0700164 rv = self.controller.message_send(flow_mod_msg)
165 self.assertTrue(rv != -1, "Error installing flow mod")
166 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
167
Shudong Zhou50051c72012-08-06 16:53:46 -0700168 # get initial port stats count
169 initTxInPort, initRxInPort = getStats(self, ingress_port)
170 initTxOutPort, initRxOutPort = getStats(self, egress_port)
Shudong Zhoudf510a82012-08-03 18:08:40 -0700171
172 # send packet N times
173 num_sends = random.randint(10,20)
Rich Lane9a003812012-10-04 17:17:59 -0700174 logging.info("Sending " + str(num_sends) + " test packets")
Shudong Zhoudf510a82012-08-03 18:08:40 -0700175 for i in range(0,num_sends):
176 sendPacket(self, pkt, ingress_port, egress_port,
177 test_timeout)
178
Shudong Zhou50051c72012-08-06 16:53:46 -0700179 verifyStats(self, ingress_port, test_timeout, initTxInPort, initRxInPort + num_sends)
180 verifyStats(self, egress_port, test_timeout, initTxOutPort + num_sends, initRxOutPort)
Shudong Zhou1d423922012-08-04 16:45:02 -0700181
182
183class MultiFlowStats(basic.SimpleDataPlane):
184 """
185 Verify flow stats are properly retrieved.
186
187 Generate two packets and install two matching flows
188 Send some number of packets
189 Send a port stats request to get packet count
190 Verify that the packet counter has incremented
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)
Shudong Zhou1d423922012-08-04 16:45:02 -0700195 match.wildcards &= ~ofp.OFPFW_IN_PORT
196 self.assertTrue(match is not None,
197 "Could not generate flow match from pkt")
198 match.in_port = ingress_port
199
200 flow_mod_msg = message.flow_mod()
201 flow_mod_msg.match = match
202 flow_mod_msg.cookie = random.randint(0,9007199254740992)
203 flow_mod_msg.buffer_id = 0xffffffff
204 flow_mod_msg.idle_timeout = 0
205 flow_mod_msg.hard_timeout = 0
206 act = action.action_output()
207 act.port = egress_port
208 self.assertTrue(flow_mod_msg.actions.add(act), "Could not add action")
209
Rich Lane9a003812012-10-04 17:17:59 -0700210 logging.info("Ingress " + str(ingress_port) +
Shudong Zhou1d423922012-08-04 16:45:02 -0700211 " to egress " + str(egress_port))
212
213 return flow_mod_msg
214
Shudong Zhou1d423922012-08-04 16:45:02 -0700215 def runTest(self):
Shudong Zhou1d423922012-08-04 16:45:02 -0700216 # TODO: set from command-line parameter
217 test_timeout = 60
218
Rich Lane477f4812012-10-04 22:49:00 -0700219 of_ports = config["port_map"].keys()
Shudong Zhou1d423922012-08-04 16:45:02 -0700220 of_ports.sort()
221 self.assertTrue(len(of_ports) >= 3, "Not enough ports for test")
222 ingress_port = of_ports[0];
223 egress_port1 = of_ports[1];
224 egress_port2 = of_ports[2];
225
Rich Lane9a003812012-10-04 17:17:59 -0700226 rc = delete_all_flows(self.controller)
Shudong Zhou1d423922012-08-04 16:45:02 -0700227 self.assertEqual(rc, 0, "Failed to delete all flows")
228
229 pkt1 = simple_tcp_packet()
230 flow_mod_msg1 = self.buildFlowModMsg(pkt1, ingress_port, egress_port1)
231
232 pkt2 = simple_tcp_packet(dl_src='0:7:7:7:7:7')
233 flow_mod_msg2 = self.buildFlowModMsg(pkt2, ingress_port, egress_port2)
234
Rich Lane9a003812012-10-04 17:17:59 -0700235 logging.info("Inserting flow1")
Shudong Zhou1d423922012-08-04 16:45:02 -0700236 rv = self.controller.message_send(flow_mod_msg1)
237 self.assertTrue(rv != -1, "Error installing flow mod")
Rich Lane9a003812012-10-04 17:17:59 -0700238 logging.info("Inserting flow2")
Shudong Zhou1d423922012-08-04 16:45:02 -0700239 rv = self.controller.message_send(flow_mod_msg2)
240 self.assertTrue(rv != -1, "Error installing flow mod")
241 self.assertEqual(do_barrier(self.controller), 0, "Barrier failed")
242
Shudong Zhou50051c72012-08-06 16:53:46 -0700243 # get initial port stats count
244 initTxInPort, initRxInPort = getStats(self, ingress_port)
245 initTxOutPort1, initRxOutPort1 = getStats(self, egress_port1)
246 initTxOutPort2, initRxOutPort2 = getStats(self, egress_port2)
247
Shudong Zhou1d423922012-08-04 16:45:02 -0700248 num_pkt1s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700249 logging.info("Sending " + str(num_pkt1s) + " pkt1s")
Shudong Zhou1d423922012-08-04 16:45:02 -0700250 num_pkt2s = random.randint(10,30)
Rich Lane9a003812012-10-04 17:17:59 -0700251 logging.info("Sending " + str(num_pkt2s) + " pkt2s")
Shudong Zhou1d423922012-08-04 16:45:02 -0700252 for i in range(0,num_pkt1s):
253 sendPacket(self, pkt1, ingress_port, egress_port1, test_timeout)
254 for i in range(0,num_pkt2s):
255 sendPacket(self, pkt2, ingress_port, egress_port2, test_timeout)
Shudong Zhou50051c72012-08-06 16:53:46 -0700256
257 verifyStats(self, ingress_port, test_timeout,
258 initTxInPort, initRxInPort + num_pkt1s + num_pkt2s)
259 verifyStats(self, egress_port1, test_timeout,
260 initTxOutPort1 + num_pkt1s, initRxOutPort1)
261 verifyStats(self, egress_port2, test_timeout,
262 initTxOutPort2 + num_pkt2s, initRxOutPort2)