blob: 37f9adcdb9022fa435a682964fa14582a90c9b94 [file] [log] [blame]
Howard Pershc7963582012-03-29 10:02:59 -07001"""
2Flow query test case.
3
4Attempts to fill switch to capacity with randomized flows, and ensure that they all are read back correctly.
5"""
Howard Persh680b92a2012-03-31 13:34:35 -07006import math
Howard Pershc7963582012-03-29 10:02:59 -07007
8import logging
9
10import unittest
11import random
12
13import 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.action_list as action_list
19import oftest.parse as parse
20import pktact
21import basic
22
23from testutils import *
24from time import sleep
25
26#@var port_map Local copy of the configuration map from OF port
27# numbers to OS interfaces
28pa_port_map = None
29#@var pa_logger Local logger object
30pa_logger = None
31#@var pa_config Local copy of global configuration data
32pa_config = None
33
rootf6af1672012-04-06 09:46:29 -070034# For test priority
35test_prio = {}
36
37
Howard Pershc7963582012-03-29 10:02:59 -070038def test_set_init(config):
39 """
40 Set up function for packet action test classes
41
42 @param config The configuration dictionary; see oft
43 """
44
45 basic.test_set_init(config)
46
47 global pa_port_map
48 global pa_logger
49 global pa_config
50
51 pa_logger = logging.getLogger("pkt_act")
52 pa_logger.info("Initializing test set")
53 pa_port_map = config["port_map"]
54 pa_config = config
55
root2843d2b2012-04-06 10:27:46 -070056 # TBD - Doesn't seem to take effect at the right time...
57 if test_param_get(pa_config, "dut", "") == "ovs":
58 # Disable this test by default, since the flow capacity reported by OVS is bogus.
59 test_prio["Flow_Add_6"] = -1
60
Howard Pershc7963582012-03-29 10:02:59 -070061
rootf6af1672012-04-06 09:46:29 -070062def flip_coin():
63 return random.randint(1, 100) <= 50
64
65
Howard Pershc7963582012-03-29 10:02:59 -070066def shuffle(list):
67 n = len(list)
68 lim = n * n
69 i = 0
70 while i < lim:
71 a = random.randint(0, n - 1)
72 b = random.randint(0, n - 1)
73 temp = list[a]
74 list[a] = list[b]
75 list[b] = temp
76 i = i + 1
77 return list
78
79
Howard Persh680b92a2012-03-31 13:34:35 -070080def rand_pick(list):
81 return list[random.randint(0, len(list) - 1)]
Howard Pershc7963582012-03-29 10:02:59 -070082
Howard Persh680b92a2012-03-31 13:34:35 -070083def rand_dl_addr():
84 return [random.randint(0, 255) & ~1,
85 random.randint(0, 255),
86 random.randint(0, 255),
87 random.randint(0, 255),
88 random.randint(0, 255),
89 random.randint(0, 255)
90 ]
Howard Pershc7963582012-03-29 10:02:59 -070091
92def rand_nw_addr():
93 return random.randint(0, (1 << 32) - 1)
94
95
rootf6af1672012-04-06 09:46:29 -070096class Flow_Info:
Howard Persh680b92a2012-03-31 13:34:35 -070097 # Members:
98 # priorities - list of flow priorities
99 # dl_addrs - list of MAC addresses
100 # vlans - list of VLAN ids
101 # ethertypes - list of Ethertypes
102 # ip_addrs - list of IP addresses
103 # ip_tos - list of IP TOS values
104 # ip_protos - list of IP protocols
105 # l4_ports - list of L4 ports
106
107 def __init__(self):
108 priorities = []
109 dl_addrs = []
110 vlans = []
111 ethertypes = []
112 ip_addrs = []
113 ip_tos = []
114 ip_protos = []
115 l4_ports = []
116
117 def rand(self, n):
118 self.priorities = []
119 i = 0
120 while i < n:
121 self.priorities.append(random.randint(1, 65534))
122 i = i + 1
123
124 self.dl_addrs = []
125 i = 0
126 while i < n:
127 self.dl_addrs.append(rand_dl_addr())
128 i = i + 1
129
130 self.vlans = []
131 i = 0
132 while i < n:
133 self.vlans.append(random.randint(1, 4094))
134 i = i + 1
135
rootf6af1672012-04-06 09:46:29 -0700136 self.ethertypes = [0x0800, 0x0806]
Howard Persh680b92a2012-03-31 13:34:35 -0700137 i = 0
138 while i < n:
139 self.ethertypes.append(random.randint(0, (1 << 16) - 1))
140 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700141 self.ethertypes = shuffle(self.ethertypes)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700142
143 self.ip_addrs = []
144 i = 0
145 while i < n:
146 self.ip_addrs.append(rand_nw_addr())
147 i = i + 1
148
149 self.ip_tos = []
150 i = 0
151 while i < n:
152 self.ip_tos.append(random.randint(0, (1 << 8) - 1) & ~3)
153 i = i + 1
154
rootf6af1672012-04-06 09:46:29 -0700155 self.ip_protos = [1, 6, 17]
Howard Persh680b92a2012-03-31 13:34:35 -0700156 i = 0
157 while i < n:
158 self.ip_protos.append(random.randint(0, (1 << 8) - 1))
159 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700160 self.ip_protos = shuffle(self.ip_protos)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700161
162 self.l4_ports = []
163 i = 0
164 while i < n:
165 self.l4_ports.append(random.randint(0, (1 << 16) - 1))
166 i = i + 1
167
168 def rand_priority(self):
169 return rand_pick(self.priorities)
170
171 def rand_dl_addr(self):
172 return rand_pick(self.dl_addrs)
173
174 def rand_vlan(self):
175 return rand_pick(self.vlans)
176
177 def rand_ethertype(self):
178 return rand_pick(self.ethertypes)
179
180 def rand_ip_addr(self):
181 return rand_pick(self.ip_addrs)
182
183 def rand_ip_tos(self):
184 return rand_pick(self.ip_tos)
185
186 def rand_ip_proto(self):
187 return rand_pick(self.ip_protos)
188
189 def rand_l4_port(self):
190 return rand_pick(self.l4_ports)
191
192
Howard Pershc7963582012-03-29 10:02:59 -0700193# TBD - These don't belong here
194
Howard Persh680b92a2012-03-31 13:34:35 -0700195all_wildcards_list = [ofp.OFPFW_IN_PORT,
Howard Persh680b92a2012-03-31 13:34:35 -0700196 ofp.OFPFW_DL_DST,
rootf6af1672012-04-06 09:46:29 -0700197 ofp.OFPFW_DL_SRC,
198 ofp.OFPFW_DL_VLAN,
199 ofp.OFPFW_DL_VLAN_PCP,
Howard Persh680b92a2012-03-31 13:34:35 -0700200 ofp.OFPFW_DL_TYPE,
rootf6af1672012-04-06 09:46:29 -0700201 ofp.OFPFW_NW_TOS,
Howard Persh680b92a2012-03-31 13:34:35 -0700202 ofp.OFPFW_NW_PROTO,
Howard Persh680b92a2012-03-31 13:34:35 -0700203 ofp.OFPFW_NW_SRC_MASK,
204 ofp.OFPFW_NW_DST_MASK,
rootf6af1672012-04-06 09:46:29 -0700205 ofp.OFPFW_TP_SRC,
206 ofp.OFPFW_TP_DST
Howard Persh680b92a2012-03-31 13:34:35 -0700207 ]
Howard Pershc7963582012-03-29 10:02:59 -0700208
rootf6af1672012-04-06 09:46:29 -0700209# TBD - Need this because there are duplicates in ofp.ofp_flow_wildcards_map -- FIX
210all_wildcard_names = {
211 1 : 'OFPFW_IN_PORT',
212 2 : 'OFPFW_DL_VLAN',
213 4 : 'OFPFW_DL_SRC',
214 8 : 'OFPFW_DL_DST',
215 16 : 'OFPFW_DL_TYPE',
216 32 : 'OFPFW_NW_PROTO',
217 64 : 'OFPFW_TP_SRC',
218 128 : 'OFPFW_TP_DST',
219 1048576 : 'OFPFW_DL_VLAN_PCP',
220 2097152 : 'OFPFW_NW_TOS'
221}
222
223
224def wildcard_set(x, w, val):
225 result = x
226 if w == ofp.OFPFW_NW_SRC_MASK:
227 result = (result & ~ofp.OFPFW_NW_SRC_MASK) | (val << ofp.OFPFW_NW_SRC_SHIFT)
228 elif w == ofp.OFPFW_NW_DST_MASK:
229 result = (result & ~ofp.OFPFW_NW_DST_MASK) | (val << ofp.OFPFW_NW_DST_SHIFT)
230 elif val == 0:
231 result = result & ~w
232 else:
233 result = result | w
234 return result
235
236def wildcard_get(x, w):
237 if w == ofp.OFPFW_NW_SRC_MASK:
238 return (x & ofp.OFPFW_NW_SRC_MASK) >> ofp.OFPFW_NW_SRC_SHIFT
239 if w == ofp.OFPFW_NW_DST_MASK:
240 return (x & ofp.OFPFW_NW_DST_MASK) >> ofp.OFPFW_NW_DST_SHIFT
241 return 1 if (x & w) != 0 else 0
242
Howard Pershc7963582012-03-29 10:02:59 -0700243
Howard Persh680b92a2012-03-31 13:34:35 -0700244all_actions_list = [ofp.OFPAT_OUTPUT,
245 ofp.OFPAT_SET_VLAN_VID,
246 ofp.OFPAT_SET_VLAN_PCP,
247 ofp.OFPAT_STRIP_VLAN,
248 ofp.OFPAT_SET_DL_SRC,
249 ofp.OFPAT_SET_DL_DST,
250 ofp.OFPAT_SET_NW_SRC,
251 ofp.OFPAT_SET_NW_DST,
252 ofp.OFPAT_SET_NW_TOS,
253 ofp.OFPAT_SET_TP_SRC,
254 ofp.OFPAT_SET_TP_DST,
255 ofp.OFPAT_ENQUEUE
256 ]
257
258def dl_addr_to_str(a):
259 return "%x:%x:%x:%x:%x:%x" % tuple(a)
260
261def ip_addr_to_str(a, n):
rootf6af1672012-04-06 09:46:29 -0700262 if n is not None:
263 a = a & ~((1 << (32 - n)) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700264 result = "%d.%d.%d.%d" % (a >> 24, \
265 (a >> 16) & 0xff, \
266 (a >> 8) & 0xff, \
267 a & 0xff \
268 )
269 if n is not None:
270 result = result + ("/%d" % (n))
271 return result
272
Howard Pershc7963582012-03-29 10:02:59 -0700273
rootf6af1672012-04-06 09:46:29 -0700274class Flow_Cfg:
Howard Pershc7963582012-03-29 10:02:59 -0700275 # Members:
276 # - match
277 # - idle_timeout
278 # - hard_timeout
279 # - priority
280 # - action_list
281
282 def __init__(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700283 self.priority = 0
Howard Pershc7963582012-03-29 10:02:59 -0700284 self.match = parse.ofp_match()
285 self.match.wildcards = ofp.OFPFW_ALL
286 self.idle_timeout = 0
287 self.hard_timeout = 0
Howard Pershc7963582012-03-29 10:02:59 -0700288 self.actions = action_list.action_list()
289
rootf6af1672012-04-06 09:46:29 -0700290 # {pri, match} is considered a flow key
291 def key_equal(self, x):
Howard Persh680b92a2012-03-31 13:34:35 -0700292 if self.priority != x.priority:
293 return False
294 # TBD - Should this logic be moved to ofp_match.__eq__()?
295 if self.match.wildcards != x.match.wildcards:
296 return False
rootf6af1672012-04-06 09:46:29 -0700297 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700298 and self.match.in_port != x.match.in_port:
299 return False
rootf6af1672012-04-06 09:46:29 -0700300 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700301 and self.match.dl_dst != x.match.dl_dst:
302 return False
rootf6af1672012-04-06 09:46:29 -0700303 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0 \
304 and self.match.dl_src != x.match.dl_src:
305 return False
306 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700307 and self.match.dl_vlan != x.match.dl_vlan:
308 return False
rootf6af1672012-04-06 09:46:29 -0700309 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700310 and self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
311 return False
rootf6af1672012-04-06 09:46:29 -0700312 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700313 and self.match.dl_type != x.match.dl_type:
314 return False
rootf6af1672012-04-06 09:46:29 -0700315 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700316 and self.match.nw_tos != x.match.nw_tos:
317 return False
rootf6af1672012-04-06 09:46:29 -0700318 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700319 and self.match.nw_proto != x.match.nw_proto:
320 return False
rootf6af1672012-04-06 09:46:29 -0700321 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
322 if n < 32:
323 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700324 if (self.match.nw_src & m) != (x.match.nw_src & m):
325 return False
rootf6af1672012-04-06 09:46:29 -0700326 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
327 if n < 32:
328 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700329 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
330 return False
rootf6af1672012-04-06 09:46:29 -0700331 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0 \
332 and self.match.tp_src != x.match.tp_src:
Howard Persh680b92a2012-03-31 13:34:35 -0700333 return False
rootf6af1672012-04-06 09:46:29 -0700334 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0 \
335 and self.match.tp_dst != x.match.tp_dst:
336 return False
337 return True
338
339 def non_key_equal(self, x):
340 if self.cookie != x.cookie:
Howard Pershc7963582012-03-29 10:02:59 -0700341 return False
342 if self.idle_timeout != x.idle_timeout:
343 return False
344 if self.hard_timeout != x.hard_timeout:
345 return False
root2843d2b2012-04-06 10:27:46 -0700346 if test_param_get(pa_config, "dut", "") == "argon":
347 # Compare actions lists as unordered, since Argon may re-order action lists.
348 # This is in apparent violation of the spec.
349 aa = copy.deepcopy(x.actions.actions)
350 for a in self.actions.actions:
351 i = 0
352 while i < len(aa):
353 if a == aa[i]:
354 break
355 i = i + 1
356 if i < len(aa):
357 aa.pop(i)
358 else:
359 return False
360 return aa == []
361 else:
362 return self.actions == x.actions
rootf6af1672012-04-06 09:46:29 -0700363
root2843d2b2012-04-06 10:27:46 -0700364 def key_str(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700365 result = "priority=%d" % self.priority
366 # TBD - Would be nice if ofp_match.show() was better behaved
367 # (no newlines), and more intuitive (things in hex where approprate), etc.
rootf6af1672012-04-06 09:46:29 -0700368 result = result + (", wildcards=0x%x={" % (self.match.wildcards))
Howard Persh680b92a2012-03-31 13:34:35 -0700369 sep = ""
rootf6af1672012-04-06 09:46:29 -0700370 for w in all_wildcards_list:
371 if (self.match.wildcards & w) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700372 continue
373 if w == ofp.OFPFW_NW_SRC_MASK:
rootf6af1672012-04-06 09:46:29 -0700374 n = wildcard_get(self.match.wildcards, w)
375 if n > 0:
376 result = result + sep + ("OFPFW_NW_SRC(%d)" % (n))
Howard Persh680b92a2012-03-31 13:34:35 -0700377 elif w == ofp.OFPFW_NW_DST_MASK:
rootf6af1672012-04-06 09:46:29 -0700378 n = wildcard_get(self.match.wildcards, w)
379 if n > 0:
380 result = result + sep + ("OFPFW_NW_DST(%d)" % (n))
Howard Persh680b92a2012-03-31 13:34:35 -0700381 else:
rootf6af1672012-04-06 09:46:29 -0700382 result = result + sep + all_wildcard_names[w]
Howard Persh680b92a2012-03-31 13:34:35 -0700383 sep = ", "
384 result = result +"}"
rootf6af1672012-04-06 09:46:29 -0700385 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700386 result = result + (", in_port=%d" % (self.match.in_port))
rootf6af1672012-04-06 09:46:29 -0700387 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700388 result = result + (", dl_dst=%s" % (dl_addr_to_str(self.match.dl_dst)))
rootf6af1672012-04-06 09:46:29 -0700389 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
390 result = result + (", dl_src=%s" % (dl_addr_to_str(self.match.dl_src)))
391 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700392 result = result + (", dl_vlan=%d" % (self.match.dl_vlan))
rootf6af1672012-04-06 09:46:29 -0700393 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700394 result = result + (", dl_vlan_pcp=%d" % (self.match.dl_vlan_pcp))
rootf6af1672012-04-06 09:46:29 -0700395 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700396 result = result + (", dl_type=0x%x" % (self.match.dl_type))
rootf6af1672012-04-06 09:46:29 -0700397 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700398 result = result + (", nw_tos=0x%x" % (self.match.nw_tos))
rootf6af1672012-04-06 09:46:29 -0700399 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700400 result = result + (", nw_proto=%d" % (self.match.nw_proto))
rootf6af1672012-04-06 09:46:29 -0700401 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700402 if n < 32:
rootf6af1672012-04-06 09:46:29 -0700403 result = result + (", nw_src=%s" % (ip_addr_to_str(self.match.nw_src, 32 - n)))
404 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700405 if n < 32:
rootf6af1672012-04-06 09:46:29 -0700406 result = result + (", nw_dst=%s" % (ip_addr_to_str(self.match.nw_dst, 32 - n)))
407 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700408 result = result + (", tp_src=%d" % self.match.tp_src)
rootf6af1672012-04-06 09:46:29 -0700409 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700410 result = result + (", tp_dst=%d" % self.match.tp_dst)
rootf6af1672012-04-06 09:46:29 -0700411 return result
412
413 def __eq__(self, x):
414 return (self.key_equal(x) and self.non_key_equal(x))
415
416 def __str__(self):
root2843d2b2012-04-06 10:27:46 -0700417 result = self.key_str()
418 result = result + (", cookie=%d" % self.cookie)
Howard Persh680b92a2012-03-31 13:34:35 -0700419 result = result + (", idle_timeout=%d" % self.idle_timeout)
420 result = result + (", hard_timeout=%d" % self.hard_timeout)
Howard Persh680b92a2012-03-31 13:34:35 -0700421 for a in self.actions.actions:
422 result = result + (", action=%s" % ofp.ofp_action_type_map[a.type])
423 if a.type == ofp.OFPAT_OUTPUT:
424 result = result + ("(%d)" % (a.port))
425 elif a.type == ofp.OFPAT_SET_VLAN_VID:
426 result = result + ("(%d)" % (a.vlan_vid))
427 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
428 result = result + ("(%d)" % (a.vlan_pcp))
429 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
430 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
431 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
432 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
433 elif a.type == ofp.OFPAT_SET_NW_TOS:
434 result = result + ("(0x%x)" % (a.nw_tos))
435 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
436 result = result + ("(%d)" % (a.tp_port))
437 elif a.type == ofp.OFPAT_ENQUEUE:
438 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
439 return result
Howard Pershc7963582012-03-29 10:02:59 -0700440
rootf6af1672012-04-06 09:46:29 -0700441 # Randomize flow data for flow modifies
442 def rand_mod(self, fi, valid_actions, valid_ports):
443 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700444
Howard Persh680b92a2012-03-31 13:34:35 -0700445 # Action lists are ordered, so pick an ordered random subset of
446 # supported actions
447 supported_actions = []
448 for a in all_actions_list:
449 if ((1 << a) & valid_actions) != 0:
450 supported_actions.append(a)
451
452 supported_actions = shuffle(supported_actions)
453 supported_actions \
454 = supported_actions[0 : random.randint(1, len(supported_actions))]
Howard Pershc7963582012-03-29 10:02:59 -0700455
456 self.actions = action_list.action_list()
Howard Persh680b92a2012-03-31 13:34:35 -0700457 for a in supported_actions:
Howard Pershc7963582012-03-29 10:02:59 -0700458 if a == ofp.OFPAT_OUTPUT:
459 # TBD - Output actions are clustered in list, spread them out?
460 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700461 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700462 for pi in port_idxs:
463 act = action.action_output()
Howard Persh680b92a2012-03-31 13:34:35 -0700464 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700465 self.actions.add(act)
466 elif a == ofp.OFPAT_SET_VLAN_VID:
467 act = action.action_set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700468 act.vlan_vid = fi.rand_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700469 self.actions.add(act)
470 elif a == ofp.OFPAT_SET_VLAN_PCP:
root2843d2b2012-04-06 10:27:46 -0700471 if test_param_get(pa_config, "dut", "") == "indigo":
472 # Temporaily removed, broken in Indigo
473 pass
474 else:
475 act = action.action_set_vlan_pcp()
476 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700477 elif a == ofp.OFPAT_STRIP_VLAN:
478 act = action.action_strip_vlan()
479 self.actions.add(act)
480 elif a == ofp.OFPAT_SET_DL_SRC:
481 act = action.action_set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700482 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700483 self.actions.add(act)
484 elif a == ofp.OFPAT_SET_DL_DST:
485 act = action.action_set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700486 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700487 self.actions.add(act)
488 elif a == ofp.OFPAT_SET_NW_SRC:
489 act = action.action_set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700490 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700491 self.actions.add(act)
492 elif a == ofp.OFPAT_SET_NW_DST:
493 act = action.action_set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700494 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700495 self.actions.add(act)
496 elif a == ofp.OFPAT_SET_NW_TOS:
497 act = action.action_set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700498 act.nw_tos = fi.rand_ip_tos()
Howard Pershc7963582012-03-29 10:02:59 -0700499 self.actions.add(act)
500 elif a == ofp.OFPAT_SET_TP_SRC:
501 act = action.action_set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700502 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700503 self.actions.add(act)
504 elif a == ofp.OFPAT_SET_TP_DST:
505 act = action.action_set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700506 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700507 self.actions.add(act)
508 elif a == ofp.OFPAT_ENQUEUE:
509 # TBD - Enqueue actions are clustered in list, spread them out?
510 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700511 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700512 for pi in port_idxs:
513 act = action.action_enqueue()
Howard Persh680b92a2012-03-31 13:34:35 -0700514 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700515 # TBD - Limits for queue number?
516 act.queue_id = random.randint(0, 7)
517 self.actions.add(act)
518
519 return self
520
rootf6af1672012-04-06 09:46:29 -0700521 # Randomize flow cfg
522 def rand(self, fi, valid_wildcards, valid_actions, valid_ports):
523 # Start with no wildcards, i.e. everything specified
524 self.match.wildcards = 0
525
526 # Make approx. 5% of flows exact
527 exact = (random.randint(1, 100) <= 5)
528
529 # For each qualifier Q,
530 # if (wildcarding is not supported for Q,
531 # or an exact flow is specified
532 # or a coin toss comes up heads),
533 # specify Q
534 # else
535 # wildcard Q
536
537 if wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
538 or exact \
539 or flip_coin():
540 self.match.in_port = rand_pick(valid_ports)
541 else:
542 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_IN_PORT, 1)
543
544 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
545 or exact \
546 or flip_coin():
547 self.match.dl_dst = fi.rand_dl_addr()
548 else:
549 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_DST, 1)
550
551 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
552 or exact \
553 or flip_coin():
554 self.match.dl_src = fi.rand_dl_addr()
555 else:
556 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_SRC, 1)
557
558 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
559 or exact \
560 or flip_coin():
561 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
562 else:
563 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP, 1)
564
565 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
566 or exact \
567 or flip_coin():
568 self.match.dl_vlan = fi.rand_vlan()
569 else:
570 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_VLAN, 1)
571
572 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
573 or exact \
574 or flip_coin():
575 self.match.dl_type = fi.rand_ethertype()
576 else:
577 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_TYPE, 1)
578
579 if exact or flip_coin():
580 n = 0
581 else:
582 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
583 if n > 32:
584 n = 32
585 n = random.randint(0, n)
586 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK, n)
587 if n < 32:
588 self.match.nw_src = fi.rand_ip_addr() & ~((1 << n) - 1)
589 # Specifying any IP address match other than all bits
590 # don't care requires that Ethertype is one of {IP, ARP}
591 if flip_coin():
592 self.match.dl_type = rand_pick([0x0800, 0x0806])
593 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_TYPE, 0)
594
595 if exact or flip_coin():
596 n = 0
597 else:
598 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
599 if n > 32:
600 n = 32
601 n = random.randint(0, n)
602 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_NW_DST_MASK, n)
603 if n < 32:
604 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
605 # Specifying any IP address match other than all bits
606 # don't care requires that Ethertype is one of {IP, ARP}
607 if flip_coin():
608 self.match.dl_type = rand_pick([0x0800, 0x0806])
609 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_TYPE, 0)
610
611 if wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
612 or exact \
613 or flip_coin():
614 self.match.nw_tos = fi.rand_ip_tos()
615 # Specifying a TOS value requires that Ethertype is IP
616 if flip_coin():
617 self.match.dl_type = 0x0800
618 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_TYPE, 0)
619 else:
620 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_NW_TOS, 1)
621
root2843d2b2012-04-06 10:27:46 -0700622 if test_param_get(pa_config, "dut", "") == "ovs":
623 # Due to a bug in OVS, don't specify nw_proto on it's own.
624 # OVS will allow specifying a value for nw_proto, even if dl_type is not
625 # specified as IP.
626 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_NW_PROTO, 1)
627 else:
628 if wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
629 or exact \
630 or flip_coin():
631 self.match.nw_proto = fi.rand_ip_proto()
632 # Specifying an IP protocol requires that Ethertype is IP
633 if flip_coin():
634 self.match.dl_type = 0x0800
635 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_TYPE, 0)
636 else:
637 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_NW_PROTO, 1)
rootf6af1672012-04-06 09:46:29 -0700638
639 if wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
640 or exact\
641 or flip_coin():
642 self.match.tp_src = fi.rand_l4_port()
643 # Specifying a L4 port requires that IP protcol is
644 # one of {ICMP, TCP, UDP}
645 if flip_coin():
646 self.match.nw_proto = rand_pick([1, 6, 17])
647 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_NW_PROTO, 0)
648 # Specifying a L4 port requirues that Ethertype is IP
649 self.match.dl_type = 0x0800
650 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_TYPE, 0)
651 if self.match.nw_proto == 1:
652 self.match.tp_src = self.match.tp_src & 0xff
653 else:
654 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_TP_SRC, 1)
655
656 if wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
657 or exact \
658 or flip_coin():
659 self.match.tp_dst = fi.rand_l4_port()
660 # Specifying a L4 port requires that IP protcol is
661 # one of {ICMP, TCP, UDP}
662 if flip_coin():
663 self.match.nw_proto = rand_pick([1, 6, 17])
664 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_NW_PROTO, 0)
665 # Specifying a L4 port requirues that Ethertype is IP
666 self.match.dl_type = 0x0800
667 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_TYPE, 0)
668 if self.match.nw_proto == 1:
669 self.match.tp_dst = self.match.tp_dst & 0xff
670 else:
671 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_TP_DST, 1)
672
673 # If nothing is wildcarded, it is an exact flow spec -- some switches
674 # (Open vSwitch, for one) *require* that exact flow specs have priority 65535.
675 self.priority = 65535 if self.match.wildcards == 0 else fi.rand_priority()
676
677 # N.B. Don't make the timeout too short, else the flow might
678 # disappear before we get a chance to check for it.
679 t = random.randint(0, 65535)
680 self.idle_timeout = 0 if t < 60 else t
681 t = random.randint(0, 65535)
682 self.hard_timeout = 0 if t < 60 else t
683
684 self.rand_mod(fi, valid_actions, valid_ports)
685
686 return self
687
688 # Return flow cfg in canonical form
689 # - There are dependencies between flow qualifiers, e.g. it only makes sense to qualify nw_proto if dl_type is qualified to be 0x0800 (IP).
690 # The canonical form of flow match criteria will "wildcard out" all such cases.
691 def canonical(self):
692 result = copy.deepcopy(self)
693 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
694 or result.match.dl_type not in [0x0800, 0x0806]:
695 # dl_tyoe is wildcarded, or specified as something other than IP or ARP
696 # => nw_src and nw_dst cannot be specified, must be wildcarded
697 result.match.wildcards = wildcard_set(result.match.wildcards, ofp.OFPFW_NW_SRC_MASK, 32)
698 result.match.wildcards = wildcard_set(result.match.wildcards, ofp.OFPFW_NW_DST_MASK, 32)
699 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
700 or result.match.dl_type != 0x0800:
701 # dl_type is wildcarded, or specified as something other than IP
702 # => nw_proto, nw_tos, tp_src and tp_dst cannot be specified, must be wildcarded
703 result.match.wildcards = wildcard_set(result.match.wildcards, ofp.OFPFW_NW_PROTO, 1)
704 result.match.wildcards = wildcard_set(result.match.wildcards, ofp.OFPFW_NW_TOS, 1)
705 result.match.wildcards = wildcard_set(result.match.wildcards, ofp.OFPFW_TP_SRC, 1)
706 result.match.wildcards = wildcard_set(result.match.wildcards, ofp.OFPFW_TP_DST, 1)
707 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
708 or result.match.nw_proto not in [1, 6, 17]:
709 # nw_proto is wildcarded, or specified as something other than ICMP, TCP or UDP
710 # => tp_src and tp_dst cannot be specified, must be wildcarded
711 result.match.wildcards = wildcard_set(result.match.wildcards, ofp.OFPFW_TP_SRC, 1)
712 result.match.wildcards = wildcard_set(result.match.wildcards, ofp.OFPFW_TP_DST, 1)
713 return result
714
Howard Persh680b92a2012-03-31 13:34:35 -0700715 # Overlap check
716 # delf == True <=> Check for delete overlap, else add overlap
717 # "Add overlap" is defined as there exists a packet that could match both the
718 # receiver and argument flowspecs
719 # "Delete overlap" is defined as the specificity of the argument flowspec
720 # is greater than or equal to the specificity of the receiver flowspec
721 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -0700722 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
723 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700724 if self.match.in_port != x.match.in_port:
725 return False # Both specified, and not equal
726 elif delf:
727 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700728 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
729 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700730 if self.match.dl_vlan != x.match.dl_vlan:
731 return False # Both specified, and not equal
732 elif delf:
733 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700734 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
735 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700736 if self.match.dl_src != x.match.dl_src:
737 return False # Both specified, and not equal
738 elif delf:
739 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700740 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
741 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700742 if self.match.dl_dst != x.match.dl_dst:
743 return False # Both specified, and not equal
744 elif delf:
745 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700746 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
747 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700748 if self.match.dl_type != x.match.dl_type:
749 return False # Both specified, and not equal
750 elif delf:
751 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -0700752 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
753 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700754 if self.match.nw_proto != x.match.nw_proto:
755 return False # Both specified, and not equal
756 elif delf:
757 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700758 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
759 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700760 if self.match.tp_src != x.match.tp_src:
761 return False # Both specified, and not equal
762 elif delf:
763 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700764 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
765 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700766 if self.match.tp_dst != x.match.tp_dst:
767 return False # Both specified, and not equal
768 elif delf:
769 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700770 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
771 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700772 if delf and na < nb:
773 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -0700774 if (na < 32 and nb < 32):
775 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
776 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -0700777 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -0700778 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
779 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700780 if delf and na < nb:
781 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -0700782 if (na < 32 and nb < 32):
783 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
784 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
rootf6af1672012-04-06 09:46:29 -0700785 return False # Overlapping bits not equal
786 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
787 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700788 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
789 return False # Both specified, and not equal
790 elif delf:
791 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700792 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
793 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700794 if self.match.nw_tos != x.match.nw_tos:
795 return False # Both specified, and not equal
796 elif delf:
797 return False # Receiver more specific
798 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -0700799
800 def to_flow_mod_msg(self, msg):
801 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -0700802 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -0700803 msg.idle_timeout = self.idle_timeout
804 msg.hard_timeout = self.hard_timeout
805 msg.priority = self.priority
806 msg.actions = self.actions
807 return msg
808
809 def from_flow_stat(self, msg):
810 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -0700811 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -0700812 self.idle_timeout = msg.idle_timeout
813 self.hard_timeout = msg.hard_timeout
814 self.priority = msg.priority
815 self.actions = msg.actions
816
rootf6af1672012-04-06 09:46:29 -0700817 def from_flow_rem(self, msg):
818 self.match = msg.match
819 self.idle_timeout = msg.idle_timeout
820 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -0700821
Howard Pershc7963582012-03-29 10:02:59 -0700822
rootf6af1672012-04-06 09:46:29 -0700823class Flow_Tbl:
824 def clear(self):
825 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -0700826
rootf6af1672012-04-06 09:46:29 -0700827 def __init__(self):
828 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -0700829
rootf6af1672012-04-06 09:46:29 -0700830 def find(self, f):
root2843d2b2012-04-06 10:27:46 -0700831 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -0700832
833 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -0700834 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -0700835
836 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -0700837 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -0700838
839 def values(self):
840 return self.dict.values()
841
842 def count(self):
843 return len(self.dict)
844
845 def rand(self, sw, fi, num_flows):
846 self.clear()
847 i = 0
848 tbl = 0
849 j = 0
850 while i < num_flows:
851 fc = Flow_Cfg()
852 fc.rand(fi, \
853 sw.tbl_stats.stats[tbl].wildcards, \
854 sw.sw_features.actions, \
855 sw.valid_ports \
856 )
857 fc = fc.canonical()
858 if self.find(fc):
859 continue
860 fc.send_rem = False
861 self.insert(fc)
862 i = i + 1
863 j = j + 1
864 if j >= sw.tbl_stats.stats[tbl].max_entries:
865 tbl = tbl + 1
866 j = 0
867
868
869class Switch:
870 # Members:
871 # controller - switch's test controller
872 # sw_features - switch's OFPT_FEATURES_REPLY message
873 # valid_ports - list of valid port numbers
874 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
875 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
876 # flow_tbl - (test's idea of) switch's flow table
877
878 def __init__(self):
879 self.controller = None
880 self.sw_features = None
881 self.valid_ports = []
882 self.tbl_stats = None
883 self.flow_stats = None
884 self.flow_tbl = Flow_Tbl()
885
886 def features_get(self):
887 # Get switch features
888 request = message.features_request()
889 (self.sw_features, pkt) = self.controller.transact(request, timeout=2)
890 if self.sw_features is None:
891 return False
892 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
893 return True
894
895 def tbl_stats_get(self):
896 # Get table stats
Howard Persh680b92a2012-03-31 13:34:35 -0700897 request = message.table_stats_request()
rootf6af1672012-04-06 09:46:29 -0700898 (self.tbl_stats, pkt) = self.controller.transact(request, timeout=2)
899 return (self.tbl_stats is not None)
Howard Persh680b92a2012-03-31 13:34:35 -0700900
rootf6af1672012-04-06 09:46:29 -0700901 def flow_stats_get(self):
902 request = message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -0700903 query_match = ofp.ofp_match()
904 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -0700905 request.match = query_match
906 request.table_id = 0xff
907 request.out_port = ofp.OFPP_NONE;
908 (self.flow_stats, pkt) = self.controller.transact(request, timeout=2)
909 return (self.flow_stats is not None)
Howard Persh680b92a2012-03-31 13:34:35 -0700910
rootf6af1672012-04-06 09:46:29 -0700911 def flow_add(self, flow_cfg, overlapf = False):
Howard Persh680b92a2012-03-31 13:34:35 -0700912 flow_mod_msg = message.flow_mod()
913 flow_mod_msg.command = ofp.OFPFC_ADD
914 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -0700915 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -0700916 if overlapf:
917 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -0700918 if flow_cfg.send_rem:
919 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
920 return (self.controller.message_send(flow_mod_msg) != -1)
Howard Persh680b92a2012-03-31 13:34:35 -0700921
rootf6af1672012-04-06 09:46:29 -0700922 def flow_mod(self, flow_cfg, strictf):
Howard Persh680b92a2012-03-31 13:34:35 -0700923 flow_mod_msg = message.flow_mod()
rootf6af1672012-04-06 09:46:29 -0700924 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -0700925 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -0700926 flow_cfg.to_flow_mod_msg(flow_mod_msg)
927 return (self.controller.message_send(flow_mod_msg) != -1)
928
929 def flow_del(self, flow_cfg, strictf):
930 flow_mod_msg = message.flow_mod()
931 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf else ofp.OFPFC_DELETE
932 flow_mod_msg.buffer_id = 0xffffffff
933 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -0700934 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -0700935 flow_cfg.to_flow_mod_msg(flow_mod_msg)
936 return (self.controller.message_send(flow_mod_msg) != -1)
937
938 def barrier(self):
939 barrier = message.barrier_request()
940 (resp, pkt) = self.controller.transact(barrier, 5)
941 return (resp is not None)
942
943 def errors_verify(self, num, type = 0, code = 0):
944 pa_logger.debug("Expecting %d error messages" % (num))
945 if num > 0:
946 pa_logger.debug("with type=%d code=%d" % (type, code))
947 result = True
948 n = 0
949 while True:
950 (errmsg, pkt) = self.controller.poll(ofp.OFPT_ERROR, 1)
951 if errmsg is None:
952 break
953 pa_logger.debug("Got error message, type=%d, code=%d" \
954 % (errmsg.type, errmsg.code) \
Howard Persh680b92a2012-03-31 13:34:35 -0700955 )
rootf6af1672012-04-06 09:46:29 -0700956 if num == 0 or errmsg.type != type or errmsg.code != code:
957 pa_logger.debug("Unexpected error message")
958 result = False
959 n = n + 1
960 if n != num:
961 pa_logger.error("Received %d error messages" % (n))
962 result = False
963 return result
964
965 def flow_tbl_verify(self):
966 result = True
967
968 # Verify flow count in switch
969 pa_logger.debug("Reading table stats")
970 pa_logger.debug("Expecting %d flows" % (self.flow_tbl.count()))
971 if not self.tbl_stats_get():
972 pa_logger.error("Get table stats failed")
973 return False
974 n = 0
975 for ts in self.tbl_stats.stats:
976 n = n + ts.active_count
977 pa_logger.debug("Table stats reported %d active flows" \
978 % (n) \
979 )
980 if n != self.flow_tbl.count():
981 pa_logger.error("Incorrect number of active flows reported")
982 result = False
983
984 # Read flows from switch
985 pa_logger.debug("Retrieving flows from switch")
986 pa_logger.debug("Expecting %d flows" % (self.flow_tbl.count()))
987 if not self.flow_stats_get():
988 pa_logger.error("Get flow stats failed")
989 return False
990 pa_logger.debug("Retrieved %d flows" % (len(self.flow_stats.stats)))
991
992 # Verify flows returned by switch
993
994 if len(self.flow_stats.stats) != self.flow_tbl.count():
995 pa_logger.error("Switch reported incorrect number of flows")
996 result = False
997
998 pa_logger.debug("Verifying received flows")
999 for fc in self.flow_tbl.values():
1000 fc.matched = False
1001 for fs in self.flow_stats.stats:
1002 flow_in = Flow_Cfg()
1003 flow_in.from_flow_stat(fs)
1004 pa_logger.debug("Received flow:")
1005 pa_logger.debug(str(flow_in))
1006 fc = self.flow_tbl.find(flow_in)
1007 if fc is None:
1008 pa_logger.error("does not match any defined flow")
1009 result = False
1010 elif fc.matched:
1011 pa_logger.error("re-matches defined flow:")
1012 pa_logger.debug(str(fc))
1013 result = False
1014 else:
1015 pa_logger.debug("matched")
1016 if not flow_in == fc:
1017 pa_logger.error("Non-key portions of flow do not match")
1018 result = False
1019 fc.matched = True
1020 for fc in self.flow_tbl.values():
1021 if not fc.matched:
1022 pa_logger.error("Defined flow:")
1023 pa_logger.error(str(fc))
1024 pa_logger.error("was not returned by switch")
1025 result = False
1026
1027 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001028
1029
rootf6af1672012-04-06 09:46:29 -07001030class Flow_Add_5(basic.SimpleProtocol):
1031 """
1032 Test FLOW_ADD_5 from draft top-half test plan
1033
1034 INPUTS
1035 num_flows - Number of flows to generate
1036 """
Howard Persh680b92a2012-03-31 13:34:35 -07001037
rootf6af1672012-04-06 09:46:29 -07001038 def runTest(self):
1039 pa_logger.debug("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001040
rootf6af1672012-04-06 09:46:29 -07001041 num_flows = test_param_get(pa_config, "num_flows", 100)
1042
Howard Pershc7963582012-03-29 10:02:59 -07001043 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001044
1045 pa_logger.debug("Deleting all flows from switch")
Howard Pershc7963582012-03-29 10:02:59 -07001046 rc = delete_all_flows(self.controller, pa_logger)
1047 self.assertEqual(rc, 0, "Failed to delete all flows")
1048
rootf6af1672012-04-06 09:46:29 -07001049 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001050
rootf6af1672012-04-06 09:46:29 -07001051 pa_logger.debug("Getting switch capabilities")
1052 sw = Switch()
1053 sw.controller = self.controller
1054 self.assertTrue(sw.features_get(), "Get switch features failed")
1055 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
Howard Pershc7963582012-03-29 10:02:59 -07001056
rootf6af1672012-04-06 09:46:29 -07001057 if num_flows == 0:
1058 # Number of flows requested was 0
1059 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001060
rootf6af1672012-04-06 09:46:29 -07001061 for ts in sw.tbl_stats.stats:
1062 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001063
rootf6af1672012-04-06 09:46:29 -07001064 pa_logger.debug("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001065
1066 # Dream up some flow information, i.e. space to chose from for
1067 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001068
rootf6af1672012-04-06 09:46:29 -07001069 fi = Flow_Info()
1070 fi.rand(2 * int(math.log(num_flows)))
Howard Pershc7963582012-03-29 10:02:59 -07001071
rootf6af1672012-04-06 09:46:29 -07001072 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001073
rootf6af1672012-04-06 09:46:29 -07001074 ft = Flow_Tbl()
1075 ft.rand(sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001076
rootf6af1672012-04-06 09:46:29 -07001077 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001078
rootf6af1672012-04-06 09:46:29 -07001079 pa_logger.debug("Sending flow adds to switch")
1080 for fc in ft.values(): # Randomizes order of sending
1081 pa_logger.debug("Adding flow:")
1082 pa_logger.debug(str(fc));
1083 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001084
rootf6af1672012-04-06 09:46:29 -07001085 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001086
rootf6af1672012-04-06 09:46:29 -07001087 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001088
rootf6af1672012-04-06 09:46:29 -07001089 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001090
rootf6af1672012-04-06 09:46:29 -07001091 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001092
rootf6af1672012-04-06 09:46:29 -07001093 if not sw.errors_verify(0):
1094 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001095
rootf6af1672012-04-06 09:46:29 -07001096 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001097
rootf6af1672012-04-06 09:46:29 -07001098 sw.flow_tbl = ft
1099 if not sw.flow_tbl_verify():
1100 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001101
rootf6af1672012-04-06 09:46:29 -07001102 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
1103 pa_logger.debug("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001104
Howard Pershc7963582012-03-29 10:02:59 -07001105
rootf6af1672012-04-06 09:46:29 -07001106class Flow_Add_5_1(basic.SimpleProtocol):
1107 """
1108 Test FLOW_ADD_5.1 from draft top-half test plan
1109
1110 INPUTS
1111 None
1112 """
1113
1114 def runTest(self):
1115 pa_logger.debug("Flow_Add_5_1 TEST BEGIN")
1116
1117 num_flows = test_param_get(pa_config, "num_flows", 100)
1118
1119 # Clear all flows from switch
1120
1121 pa_logger.debug("Deleting all flows from switch")
1122 rc = delete_all_flows(self.controller, pa_logger)
1123 self.assertEqual(rc, 0, "Failed to delete all flows")
1124
1125 # Get switch capabilites
1126
1127 pa_logger.debug("Getting switch capabilities")
1128 sw = Switch()
1129 sw.controller = self.controller
1130 self.assertTrue(sw.features_get(), "Get switch features failed")
1131 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1132
1133 # Dream up some flow information, i.e. space to chose from for
1134 # random flow parameter generation
1135
1136 fi = Flow_Info()
1137 fi.rand(10)
1138
1139 # Dream up a flow config that will be canonicalized by the switch
1140
1141 while True:
1142 fc = Flow_Cfg()
1143 fc.rand(fi, \
1144 sw.tbl_stats.stats[0].wildcards, \
1145 sw.sw_features.actions, \
1146 sw.valid_ports \
1147 )
1148 fcc = fc.canonical()
1149 if fcc != fc:
1150 break
1151
1152 ft = Flow_Tbl()
1153 ft.insert(fcc)
1154
1155 # Send it to the switch
1156
1157 pa_logger.debug("Sending flow add to switch:")
1158 pa_logger.debug(str(fc))
1159 pa_logger.debug("should be canonicalized as:")
1160 pa_logger.debug(str(fcc))
1161 fc.send_rem = False
1162 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1163
1164 # Do barrier, to make sure all flows are in
1165
1166 self.assertTrue(sw.barrier(), "Barrier failed")
1167
1168 result = True
1169
1170 # Check for any error messages
1171
1172 if not sw.errors_verify(0):
1173 result = False
1174
1175 # Verify flow table
1176
1177 sw.flow_tbl = ft
1178 if not sw.flow_tbl_verify():
1179 result = False
1180
1181 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
1182 pa_logger.debug("Flow_Add_5_1 TEST PASSED")
1183
1184
rootf6af1672012-04-06 09:46:29 -07001185class Flow_Add_6(basic.SimpleProtocol):
1186 """
1187 Test FLOW_ADD_6 from draft top-half test plan
1188
1189 INPUTS
1190 num_flows - Number of flows to generate
1191 """
Howard Pershc7963582012-03-29 10:02:59 -07001192
1193 def runTest(self):
rootf6af1672012-04-06 09:46:29 -07001194 pa_logger.debug("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001195
rootf6af1672012-04-06 09:46:29 -07001196 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001197
rootf6af1672012-04-06 09:46:29 -07001198 pa_logger.debug("Deleting all flows from switch")
1199 rc = delete_all_flows(self.controller, pa_logger)
1200 self.assertEqual(rc, 0, "Failed to delete all flows")
1201
1202 # Get switch capabilites
1203
1204 pa_logger.debug("Getting switch capabilities")
1205 sw = Switch()
1206 sw.controller = self.controller
1207 self.assertTrue(sw.features_get(), "Get switch features failed")
1208 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1209
root2843d2b2012-04-06 10:27:46 -07001210 num_flows = 0
rootf6af1672012-04-06 09:46:29 -07001211 for ts in sw.tbl_stats.stats:
1212 num_flows = num_flows + ts.max_entries
1213
1214 pa_logger.debug("Switch capacity is %d flows" % (num_flows))
1215 pa_logger.debug("Generating %d flows" % (num_flows))
1216
1217 # Dream up some flow information, i.e. space to chose from for
1218 # random flow parameter generation
1219
1220 fi = Flow_Info()
1221 fi.rand(2 * int(math.log(num_flows)))
1222
1223 # Create a flow table, to switch's capacity
1224
1225 ft = Flow_Tbl()
1226 ft.rand(sw, fi, num_flows)
1227
1228 # Send flow table to switch
1229
1230 pa_logger.debug("Sending flow adds to switch")
1231 for fc in ft.values(): # Randomizes order of sending
1232 pa_logger.debug("Adding flow:")
1233 pa_logger.debug(str(fc));
1234 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1235
1236 # Do barrier, to make sure all flows are in
1237
1238 self.assertTrue(sw.barrier(), "Barrier failed")
1239
1240 result = True
1241
1242 # Check for any error messages
1243
1244 if not sw.errors_verify(0):
1245 result = False
1246
1247 # Dream up one more flow
1248
1249 pa_logger.debug("Creating one more flow")
1250 while True:
1251 fc = Flow_Cfg()
1252 fc.rand(fi, \
1253 sw.tbl_stats.stats[tbl].wildcards, \
1254 sw.sw_features.actions, \
1255 sw.valid_ports \
1256 )
1257 fc = fc.canonical()
1258 if ft.find(fc):
1259 continue
1260
1261 # Send one-more flow
1262
1263 fc.send_rem = False
1264 pa_logger.debug("Sending flow add switch")
1265 pa_logger.debug(str(fc));
1266 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1267
1268 # Do barrier, to make sure all flows are in
1269
1270 self.assertTrue(sw.barrier(), "Barrier failed")
1271
1272 # Check for expected error message
1273
1274 if not sw.errors_verify(1, \
1275 ofp.OFPET_FLOW_MOD_FAILED, \
1276 ofp.OFPFMFC_ALL_TABLES_FULL \
1277 ):
1278 result = False
1279
1280 # Verify flow table
1281
1282 sw.flow_tbl = ft
1283 if not sw.flow_tbl_verify():
1284 result = False
1285
1286 self.assertTrue(result, "Flow_add_6 TEST FAILED")
1287 pa_logger.debug("Flow_add_6 TEST PASSED")
1288
1289
1290class Flow_Add_7(basic.SimpleProtocol):
1291 """
1292 Test FLOW_ADD_7 from draft top-half test plan
1293
1294 INPUTS
1295 None
1296 """
1297
1298 def runTest(self):
1299 pa_logger.debug("Flow_Add_7 TEST BEGIN")
1300
1301 # Clear all flows from switch
1302
1303 pa_logger.debug("Deleting all flows from switch")
1304 rc = delete_all_flows(self.controller, pa_logger)
1305 self.assertEqual(rc, 0, "Failed to delete all flows")
1306
1307 # Get switch capabilites
1308
1309 pa_logger.debug("Getting switch capabilities")
1310 sw = Switch()
1311 sw.controller = self.controller
1312 self.assertTrue(sw.features_get(), "Get switch features failed")
1313 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1314
1315 # Dream up some flow information, i.e. space to chose from for
1316 # random flow parameter generation
1317
1318 fi = Flow_Info()
1319 fi.rand(10)
1320
1321 # Dream up a flow config
1322
1323 fc = Flow_Cfg()
1324 fc.rand(fi, \
1325 sw.tbl_stats.stats[0].wildcards, \
1326 sw.sw_features.actions, \
1327 sw.valid_ports \
1328 )
1329 fc = fc.canonical()
1330
1331 # Send it to the switch
1332
1333 pa_logger.debug("Sending flow add to switch:")
1334 pa_logger.debug(str(fc))
1335 ft = Flow_Tbl()
1336 fc.send_rem = False
1337 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1338 ft.insert(fc)
1339
1340 # Dream up some different actions, with the same flow key
1341
1342 fc2 = copy.deepcopy(fc)
1343 while True:
1344 fc2.rand_mod(fi, \
1345 sw.sw_features.actions, \
1346 sw.valid_ports \
1347 )
1348 if fc2 != fc:
1349 break
1350
1351 # Send that to the switch
1352
1353 pa_logger.debug("Sending flow add to switch:")
1354 pa_logger.debug(str(fc2))
1355 fc2.send_rem = False
1356 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
1357 ft.insert(fc2)
1358
1359 # Do barrier, to make sure all flows are in
1360
1361 self.assertTrue(sw.barrier(), "Barrier failed")
1362
1363 result = True
1364
1365 # Check for any error messages
1366
1367 if not sw.errors_verify(0):
1368 result = False
1369
1370 # Verify flow table
1371
1372 sw.flow_tbl = ft
1373 if not sw.flow_tbl_verify():
1374 result = False
1375
1376 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
1377 pa_logger.debug("Flow_Add_7 TEST PASSED")
1378
1379
1380class Flow_Add_8(basic.SimpleProtocol):
1381 """
1382 Test FLOW_ADD_8 from draft top-half test plan
1383
1384 INPUTS
1385 None
1386 """
1387
1388 def runTest(self):
1389 pa_logger.debug("Flow_Add_8 TEST BEGIN")
1390
1391 # Clear all flows from switch
1392
1393 pa_logger.debug("Deleting all flows from switch")
1394 rc = delete_all_flows(self.controller, pa_logger)
1395 self.assertEqual(rc, 0, "Failed to delete all flows")
1396
1397 # Get switch capabilites
1398
1399 pa_logger.debug("Getting switch capabilities")
1400 sw = Switch()
1401 sw.controller = self.controller
1402 self.assertTrue(sw.features_get(), "Get switch features failed")
1403 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1404
1405 # Dream up some flow information, i.e. space to chose from for
1406 # random flow parameter generation
1407
1408 fi = Flow_Info()
1409 fi.rand(10)
1410
1411 # Dream up a flow config, with at least 1 qualifier specified
1412
1413 fc = Flow_Cfg()
1414 while True:
1415 fc.rand(fi, \
1416 sw.tbl_stats.stats[0].wildcards, \
1417 sw.sw_features.actions, \
1418 sw.valid_ports \
1419 )
1420 fc = fc.canonical()
1421 if fc.match.wildcards != ofp.OFPFW_ALL:
1422 break
1423
1424 # Send it to the switch
1425
1426 pa_logger.debug("Sending flow add to switch:")
1427 pa_logger.debug(str(fc))
1428 ft = Flow_Tbl()
1429 fc.send_rem = False
1430 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1431 ft.insert(fc)
1432
1433 # Wildcard out one qualifier that was specified, to create an
1434 # overlapping flow
1435
1436 fc2 = copy.deepcopy(fc)
1437 for wi in shuffle(range(len(all_wildcards_list))):
1438 w = all_wildcards_list[wi]
1439 if (fc2.match.wildcards & w) == 0:
1440 break
1441 if w == ofp.OFPFW_NW_SRC_MASK:
1442 w = ofp.OFPFW_NW_SRC_ALL
1443 wn = "OFPFW_NW_SRC"
1444 elif w == ofp.OFPFW_NW_DST_MASK:
1445 w = ofp.OFPFW_NW_DST_ALL
1446 wn = "OFPFW_NW_DST"
1447 else:
1448 wn = all_wildcard_names[w]
1449 pa_logger.debug("Wildcarding out %s" % (wn))
1450 fc2.match.wildcards = fc2.match.wildcards | w
1451
1452 # Send that to the switch, with overlap checking
1453
1454 pa_logger.debug("Sending flow add to switch:")
1455 pa_logger.debug(str(fc2))
1456 fc2.send_rem = False
1457 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
1458
1459 # Do barrier, to make sure all flows are in
1460 self.assertTrue(sw.barrier(), "Barrier failed")
1461
1462 result = True
1463
1464 # Check for expected error message
1465
1466 if not sw.errors_verify(1, \
1467 ofp.OFPET_FLOW_MOD_FAILED, \
1468 ofp.OFPFMFC_OVERLAP \
1469 ):
1470 result = False
1471
1472 # Verify flow table
1473
1474 sw.flow_tbl = ft
1475 if not sw.flow_tbl_verify():
1476 result = False
1477
1478 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
1479 pa_logger.debug("Flow_Add_8 TEST PASSED")
1480
1481
1482class Flow_Mod_1(basic.SimpleProtocol):
1483 """
1484 Test FLOW_MOD_1 from draft top-half test plan
1485
1486 INPUTS
1487 None
1488 """
1489
1490 def runTest(self):
1491 pa_logger.debug("Flow_Mod_1 TEST BEGIN")
1492
1493 # Clear all flows from switch
1494
1495 pa_logger.debug("Deleting all flows from switch")
1496 rc = delete_all_flows(self.controller, pa_logger)
1497 self.assertEqual(rc, 0, "Failed to delete all flows")
1498
1499 # Get switch capabilites
1500
1501 pa_logger.debug("Getting switch capabilities")
1502 sw = Switch()
1503 sw.controller = self.controller
1504 self.assertTrue(sw.features_get(), "Get switch features failed")
1505 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1506
1507 # Dream up some flow information, i.e. space to chose from for
1508 # random flow parameter generation
1509
1510 fi = Flow_Info()
1511 fi.rand(10)
1512
1513 # Dream up a flow config
1514
1515 fc = Flow_Cfg()
1516 fc.rand(fi, \
1517 sw.tbl_stats.stats[0].wildcards, \
1518 sw.sw_features.actions, \
1519 sw.valid_ports \
1520 )
1521 fc = fc.canonical()
1522
1523 # Send it to the switch
1524
1525 pa_logger.debug("Sending flow add to switch:")
1526 pa_logger.debug(str(fc))
1527 ft = Flow_Tbl()
1528 fc.send_rem = False
1529 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1530 ft.insert(fc)
1531
1532 # Dream up some different actions, with the same flow key
1533
1534 fc2 = copy.deepcopy(fc)
1535 while True:
1536 fc2.rand_mod(fi, \
1537 sw.sw_features.actions, \
1538 sw.valid_ports \
1539 )
1540 if fc2 != fc:
1541 break
1542
1543 # Send that to the switch
1544
1545 pa_logger.debug("Sending strict flow mod to switch:")
1546 pa_logger.debug(str(fc2))
1547 fc2.send_rem = False
1548 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
1549 ft.insert(fc2)
1550
1551 # Do barrier, to make sure all flows are in
1552
1553 self.assertTrue(sw.barrier(), "Barrier failed")
1554
1555 result = True
1556
1557 # Check for any error messages
1558
1559 if not sw.errors_verify(0):
1560 result = False
1561
1562 # Verify flow table
1563
1564 sw.flow_tbl = ft
1565 if not sw.flow_tbl_verify():
1566 result = False
1567
1568 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
1569 pa_logger.debug("Flow_Mod_1 TEST PASSED")
1570
1571
1572class Flow_Mod_2(basic.SimpleProtocol):
1573 """
1574 Test FLOW_MOD_2 from draft top-half test plan
1575
1576 INPUTS
1577 None
1578 """
1579
1580 def runTest(self):
1581 pa_logger.debug("Flow_Mod_2 TEST BEGIN")
1582
1583 num_flows = test_param_get(pa_config, "num_flows", 100)
1584
1585 # Clear all flows from switch
1586
1587 pa_logger.debug("Deleting all flows from switch")
1588 rc = delete_all_flows(self.controller, pa_logger)
1589 self.assertEqual(rc, 0, "Failed to delete all flows")
1590
1591 # Get switch capabilites
1592
1593 pa_logger.debug("Getting switch capabilities")
1594 sw = Switch()
1595 sw.controller = self.controller
1596 self.assertTrue(sw.features_get(), "Get switch features failed")
1597 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1598
1599 # Dream up some flow information, i.e. space to chose from for
1600 # random flow parameter generation
1601
1602 fi = Flow_Info()
1603 fi.rand(int(math.log(num_flows)) / 2) # Shrunk, to increase chance of meta-matches
1604
1605 # Dream up some flows
1606
1607 ft = Flow_Tbl()
1608 ft.rand(sw, fi, num_flows)
1609
1610 # Send flow table to switch
1611
1612 pa_logger.debug("Sending flow adds to switch")
1613 for fc in ft.values(): # Randomizes order of sending
1614 pa_logger.debug("Adding flow:")
1615 pa_logger.debug(str(fc));
1616 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1617
1618 # Do barrier, to make sure all flows are in
1619
1620 self.assertTrue(sw.barrier(), "Barrier failed")
1621
1622 result = True
1623
1624 # Check for any error messages
1625
1626 if not sw.errors_verify(0):
1627 result = False
1628
1629 # Verify flow table
1630
1631 sw.flow_tbl = ft
1632 if not sw.flow_tbl_verify():
1633 result = False
1634
1635 # Pick a random flow as a basis
1636
1637 mfc = copy.deepcopy(ft.values()[0])
1638 mfc.rand_mod(fi, sw.sw_features.actions, sw.valid_ports)
1639
1640 # Repeatedly wildcard qualifiers
1641
1642 for wi in shuffle(range(len(all_wildcards_list))):
1643 w = all_wildcards_list[wi]
1644 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
1645 n = wildcard_get(mfc.match.wildcards, w)
1646 if n < 32:
1647 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, random.randint(n + 1, 32))
1648 else:
1649 continue
1650 else:
1651 if wildcard_get(mfc.match.wildcards, w) == 0:
1652 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
1653 else:
1654 continue
1655 mfc = mfc.canonical()
1656
1657 # Count the number of flows that would be modified
1658
1659 n = 0
1660 for fc in ft.values():
1661 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
1662 n = n + 1
1663
1664 # If more than 1, we found our loose delete flow spec
1665 if n > 1:
1666 break
1667
1668 pa_logger.debug("Modifying %d flows" % (n))
1669 pa_logger.debug("Sending flow mod to switch:")
1670 pa_logger.debug(str(mfc))
1671 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
1672
1673 # Do barrier, to make sure all flows are in
1674 self.assertTrue(sw.barrier(), "Barrier failed")
1675
1676 # Check for error message
1677
1678 if not sw.errors_verify(0):
1679 result = False
1680
1681 # Apply flow mod to local flow table
1682
1683 for fc in ft.values():
1684 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07001685 fc.cookie = mfc.cookie
1686 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07001687
1688 # Verify flow table
1689
1690 sw.flow_tbl = ft
1691 if not sw.flow_tbl_verify():
1692 result = False
1693
1694 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
1695 pa_logger.debug("Flow_Mod_2 TEST PASSED")
1696
1697
1698class Flow_Mod_3(basic.SimpleProtocol):
1699 """
1700 Test FLOW_MOD_3 from draft top-half test plan
1701
1702 INPUTS
1703 None
1704 """
1705
1706 def runTest(self):
1707 pa_logger.debug("Flow_Mod_3 TEST BEGIN")
1708
1709 # Clear all flows from switch
1710
1711 pa_logger.debug("Deleting all flows from switch")
1712 rc = delete_all_flows(self.controller, pa_logger)
1713 self.assertEqual(rc, 0, "Failed to delete all flows")
1714
1715 # Get switch capabilites
1716
1717 pa_logger.debug("Getting switch capabilities")
1718 sw = Switch()
1719 sw.controller = self.controller
1720 self.assertTrue(sw.features_get(), "Get switch features failed")
1721 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1722
1723 # Dream up some flow information, i.e. space to chose from for
1724 # random flow parameter generation
1725
1726 fi = Flow_Info()
1727 fi.rand(10)
1728
1729 # Dream up a flow config
1730
1731 fc = Flow_Cfg()
1732 fc.rand(fi, \
1733 sw.tbl_stats.stats[0].wildcards, \
1734 sw.sw_features.actions, \
1735 sw.valid_ports \
1736 )
1737 fc = fc.canonical()
1738
1739 # Send it to the switch
1740
1741 pa_logger.debug("Sending flow mod to switch:")
1742 pa_logger.debug(str(fc))
1743 ft = Flow_Tbl()
1744 fc.send_rem = False
1745 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
1746 ft.insert(fc)
1747
1748 # Do barrier, to make sure all flows are in
1749
1750 self.assertTrue(sw.barrier(), "Barrier failed")
1751
1752 result = True
1753
1754 # Check for any error messages
1755
1756 if not sw.errors_verify(0):
1757 result = False
1758
1759 # Verify flow table
1760
1761 sw.flow_tbl = ft
1762 if not sw.flow_tbl_verify():
1763 result = False
1764
1765 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
1766 pa_logger.debug("Flow_Mod_3 TEST PASSED")
1767
1768
1769class Flow_Del_1(basic.SimpleProtocol):
1770 """
1771 Test FLOW_DEL_1 from draft top-half test plan
1772
1773 INPUTS
1774 None
1775 """
1776
1777 def runTest(self):
1778 pa_logger.debug("Flow_Del_1 TEST BEGIN")
1779
1780 # Clear all flows from switch
1781
1782 pa_logger.debug("Deleting all flows from switch")
1783 rc = delete_all_flows(self.controller, pa_logger)
1784 self.assertEqual(rc, 0, "Failed to delete all flows")
1785
1786 # Get switch capabilites
1787
1788 pa_logger.debug("Getting switch capabilities")
1789 sw = Switch()
1790 sw.controller = self.controller
1791 self.assertTrue(sw.features_get(), "Get switch features failed")
1792 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1793
1794 # Dream up some flow information, i.e. space to chose from for
1795 # random flow parameter generation
1796
1797 fi = Flow_Info()
1798 fi.rand(10)
1799
1800 # Dream up a flow config
1801
1802 fc = Flow_Cfg()
1803 fc.rand(fi, \
1804 sw.tbl_stats.stats[0].wildcards, \
1805 sw.sw_features.actions, \
1806 sw.valid_ports \
1807 )
1808 fc = fc.canonical()
1809
1810 # Send it to the switch
1811
1812 pa_logger.debug("Sending flow add to switch:")
1813 pa_logger.debug(str(fc))
1814 ft = Flow_Tbl()
1815 fc.send_rem = False
1816 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1817 ft.insert(fc)
1818
1819 # Dream up some different actions, with the same flow key
1820
1821 fc2 = copy.deepcopy(fc)
1822 while True:
1823 fc2.rand_mod(fi, \
1824 sw.sw_features.actions, \
1825 sw.valid_ports \
1826 )
1827 if fc2 != fc:
1828 break
1829
1830 # Delete strictly
1831
1832 pa_logger.debug("Sending strict flow del to switch:")
1833 pa_logger.debug(str(fc2))
1834 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
1835 ft.delete(fc)
1836
1837 # Do barrier, to make sure all flows are in
1838
1839 self.assertTrue(sw.barrier(), "Barrier failed")
1840
1841 result = True
1842
1843 # Check for any error messages
1844
1845 if not sw.errors_verify(0):
1846 result = False
1847
1848 # Verify flow table
1849
1850 sw.flow_tbl = ft
1851 if not sw.flow_tbl_verify():
1852 result = False
1853
1854 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
1855 pa_logger.debug("Flow_Del_1 TEST PASSED")
1856
1857
1858class Flow_Del_2(basic.SimpleProtocol):
1859 """
1860 Test FLOW_DEL_2 from draft top-half test plan
1861
1862 INPUTS
1863 None
1864 """
1865
1866 def runTest(self):
1867 pa_logger.debug("Flow_Del_2 TEST BEGIN")
1868
1869 num_flows = test_param_get(pa_config, "num_flows", 100)
1870
1871 # Clear all flows from switch
1872
1873 pa_logger.debug("Deleting all flows from switch")
1874 rc = delete_all_flows(self.controller, pa_logger)
1875 self.assertEqual(rc, 0, "Failed to delete all flows")
1876
1877 # Get switch capabilites
1878
1879 pa_logger.debug("Getting switch capabilities")
1880 sw = Switch()
1881 sw.controller = self.controller
1882 self.assertTrue(sw.features_get(), "Get switch features failed")
1883 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1884
1885 # Dream up some flow information, i.e. space to chose from for
1886 # random flow parameter generation
1887
1888 fi = Flow_Info()
1889 fi.rand(int(math.log(num_flows)) / 2) # Shrunk, to increase chance of meta-matches
1890
1891 # Dream up some flows
1892
1893 ft = Flow_Tbl()
1894 ft.rand(sw, fi, num_flows)
1895
1896 # Send flow table to switch
1897
1898 pa_logger.debug("Sending flow adds to switch")
1899 for fc in ft.values(): # Randomizes order of sending
1900 pa_logger.debug("Adding flow:")
1901 pa_logger.debug(str(fc));
1902 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1903
1904 # Do barrier, to make sure all flows are in
1905
1906 self.assertTrue(sw.barrier(), "Barrier failed")
1907
1908 result = True
1909
1910 # Check for any error messages
1911
1912 if not sw.errors_verify(0):
1913 result = False
1914
1915 # Verify flow table
1916
1917 sw.flow_tbl = ft
1918 if not sw.flow_tbl_verify():
1919 result = False
1920
1921 # Pick a random flow as a basis
1922
1923 dfc = copy.deepcopy(ft.values()[0])
1924 dfc.rand_mod(fi, sw.sw_features.actions, sw.valid_ports)
1925
1926 # Repeatedly wildcard qualifiers
1927
1928 for wi in shuffle(range(len(all_wildcards_list))):
1929 w = all_wildcards_list[wi]
1930 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
1931 n = wildcard_get(dfc.match.wildcards, w)
1932 if n < 32:
1933 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, random.randint(n + 1, 32))
1934 else:
1935 continue
1936 else:
1937 if wildcard_get(dfc.match.wildcards, w) == 0:
1938 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
1939 else:
1940 continue
1941 dfc = dfc.canonical()
1942
1943 # Count the number of flows that would be deleted
1944
1945 n = 0
1946 for fc in ft.values():
1947 if dfc.overlaps(fc, True):
1948 n = n + 1
1949
1950 # If more than 1, we found our loose delete flow spec
1951 if n > 1:
1952 break
1953
1954 pa_logger.debug("Deleting %d flows" % (n))
1955 pa_logger.debug("Sending flow del to switch:")
1956 pa_logger.debug(str(dfc))
1957 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
1958
1959 # Do barrier, to make sure all flows are in
1960 self.assertTrue(sw.barrier(), "Barrier failed")
1961
1962 # Check for error message
1963
1964 if not sw.errors_verify(0):
1965 result = False
1966
1967 # Apply flow mod to local flow table
1968
1969 for fc in ft.values():
1970 if dfc.overlaps(fc, True):
1971 ft.delete(fc)
1972
1973 # Verify flow table
1974
1975 sw.flow_tbl = ft
1976 if not sw.flow_tbl_verify():
1977 result = False
1978
1979 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
1980 pa_logger.debug("Flow_Del_2 TEST PASSED")
1981
1982
1983# Disable this test by default, there seems to be an issue with error message reporting
1984test_prio["Flow_Del_4"] = -1
1985
1986class Flow_Del_4(basic.SimpleProtocol):
1987 """
1988 Test FLOW_DEL_4 from draft top-half test plan
1989
1990 INPUTS
1991 None
1992 """
1993
1994 def runTest(self):
1995 pa_logger.debug("Flow_Del_4 TEST BEGIN")
1996
1997 # Clear all flows from switch
1998
1999 pa_logger.debug("Deleting all flows from switch")
2000 rc = delete_all_flows(self.controller, pa_logger)
2001 self.assertEqual(rc, 0, "Failed to delete all flows")
2002
2003 # Get switch capabilites
2004
2005 pa_logger.debug("Getting switch capabilities")
2006 sw = Switch()
2007 sw.controller = self.controller
2008 self.assertTrue(sw.features_get(), "Get switch features failed")
2009 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2010
2011 # Dream up some flow information, i.e. space to chose from for
2012 # random flow parameter generation
2013
2014 fi = Flow_Info()
2015 fi.rand(10)
2016
2017 # Dream up a flow config
2018
2019 fc = Flow_Cfg()
2020 fc.rand(fi, \
2021 sw.tbl_stats.stats[0].wildcards, \
2022 sw.sw_features.actions, \
2023 sw.valid_ports \
2024 )
2025 fc = fc.canonical()
2026
2027 # Send it to the switch. with "notify on removed"
2028
2029 pa_logger.debug("Sending flow add to switch:")
2030 pa_logger.debug(str(fc))
2031 ft = Flow_Tbl()
2032 fc.send_rem = True
2033 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2034 ft.insert(fc)
2035
2036 # Dream up some different actions, with the same flow key
2037
2038 fc2 = copy.deepcopy(fc)
2039 while True:
2040 fc2.rand_mod(fi, \
2041 sw.sw_features.actions, \
2042 sw.valid_ports \
2043 )
2044 if fc2 != fc:
2045 break
2046
2047 # Delete strictly
2048
2049 pa_logger.debug("Sending strict flow del to switch:")
2050 pa_logger.debug(str(fc2))
2051 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2052 ft.delete(fc)
2053
2054 # Do barrier, to make sure all flows are in
2055
2056 self.assertTrue(sw.barrier(), "Barrier failed")
2057
2058 result = True
2059
2060 # Check for expected "removed" message
2061
2062 if not sw.errors_verify(1, \
2063 ofp.OFPT_FLOW_REMOVED, \
2064 ofp.OFPRR_DELETE \
2065 ):
2066 result = False
2067
2068 # Verify flow table
2069
2070 sw.flow_tbl = ft
2071 if not sw.flow_tbl_verify():
2072 result = False
2073
2074 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
2075 pa_logger.debug("Flow_Del_4 TEST PASSED")
2076