blob: a22c267e975f6fd7da6a246be4a5e18ec9133b9b [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
94 Generate and install a matching flow
95 Send the packet
96 Send a flow stats request to match the flow and retrieve stats
97 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)