blob: 6044758b5f78ed48e4745c80be8153c5a16ba466 [file] [log] [blame]
Howard Pershc7963582012-03-29 10:02:59 -07001"""
2Flow query test case.
3
Howard Persh3340d452012-04-06 16:45:21 -07004Attempts to fill switch to capacity with randomized flows, and ensure that
5they all are read back correctly.
Howard Pershc7963582012-03-29 10:02:59 -07006"""
Howard Persh07d99e62012-04-09 15:26:57 -07007
8# COMMON TEST PARAMETERS
9#
10# Name: wildcards
11# Type: number
12# Description:
13# Overrides bitmap of supported wildcards reported by switch
14# Default: none
15#
Howard Pershc1199d52012-04-11 14:21:32 -070016# Name: wildcards_force
17# Type: number
18# Description:
19# Bitmap of wildcards to always be set
20# Default: none
21#
Howard Persh07d99e62012-04-09 15:26:57 -070022# Name: actions
23# Type: number
24# Description:
25# Overrides bitmap of supported actions reported by switch
26# Default: none
27#
Howard Pershc1199d52012-04-11 14:21:32 -070028# Name: actions_force
29# Type: number
30# Description:
31# Bitmap of actions to always be used
32# Default: none
33#
34# Name: ports
35# Type: list of OF port numbers
36# Description:
37# Override list of OF port numbers reported by switch
38# Default: none
39#
Howard Persh8d21c1f2012-04-20 15:57:29 -070040# Name: queues
41# Type: list of OF (port-number, queue-id) pairs
42# Description:
43# Override list of OF (port-number, queue-id) pairs returned by switch
44# Default: none
45#
Howard Pershb10a47a2012-08-21 13:54:47 -070046# Name: vlans
47# Type: list of VLAN ids
48# Description:
49# Override VLAN ids used in tests to given list
50# Default: []
51#
Howard Persh07d99e62012-04-09 15:26:57 -070052# Name: conservative_ordered_actions
53# Type: boolean (True or False)
54# Description:
55# Compare flow actions lists as unordered
56# Default: True
57
58
Howard Persh680b92a2012-03-31 13:34:35 -070059import math
Howard Pershc7963582012-03-29 10:02:59 -070060
61import logging
62
63import unittest
64import random
65
66import oftest.controller as controller
67import oftest.cstruct as ofp
68import oftest.message as message
69import oftest.dataplane as dataplane
70import oftest.action as action
71import oftest.action_list as action_list
72import oftest.parse as parse
73import pktact
74import basic
75
76from testutils import *
77from time import sleep
78
79#@var port_map Local copy of the configuration map from OF port
80# numbers to OS interfaces
Dan Talayco910a8282012-04-07 00:05:20 -070081fq_port_map = None
82#@var fq_logger Local logger object
83fq_logger = None
84#@var fq_config Local copy of global configuration data
85fq_config = None
Howard Pershc7963582012-03-29 10:02:59 -070086
rootf6af1672012-04-06 09:46:29 -070087# For test priority
88test_prio = {}
89
90
Howard Pershc7963582012-03-29 10:02:59 -070091def test_set_init(config):
92 """
93 Set up function for packet action test classes
94
95 @param config The configuration dictionary; see oft
96 """
97
98 basic.test_set_init(config)
99
Dan Talayco910a8282012-04-07 00:05:20 -0700100 global fq_port_map
101 global fq_logger
102 global fq_config
Howard Pershc7963582012-03-29 10:02:59 -0700103
Dan Talayco910a8282012-04-07 00:05:20 -0700104 fq_logger = logging.getLogger("flowq")
105 fq_logger.info("Initializing test set")
106 fq_port_map = config["port_map"]
107 fq_config = config
root2843d2b2012-04-06 10:27:46 -0700108
Howard Pershc7963582012-03-29 10:02:59 -0700109
rootf6af1672012-04-06 09:46:29 -0700110def flip_coin():
111 return random.randint(1, 100) <= 50
112
113
Howard Pershc7963582012-03-29 10:02:59 -0700114def shuffle(list):
115 n = len(list)
116 lim = n * n
117 i = 0
118 while i < lim:
119 a = random.randint(0, n - 1)
120 b = random.randint(0, n - 1)
121 temp = list[a]
122 list[a] = list[b]
123 list[b] = temp
124 i = i + 1
125 return list
126
127
Howard Persh680b92a2012-03-31 13:34:35 -0700128def rand_pick(list):
129 return list[random.randint(0, len(list) - 1)]
Howard Pershc7963582012-03-29 10:02:59 -0700130
Howard Persh680b92a2012-03-31 13:34:35 -0700131def rand_dl_addr():
132 return [random.randint(0, 255) & ~1,
133 random.randint(0, 255),
134 random.randint(0, 255),
135 random.randint(0, 255),
136 random.randint(0, 255),
137 random.randint(0, 255)
138 ]
Howard Pershc7963582012-03-29 10:02:59 -0700139
140def rand_nw_addr():
141 return random.randint(0, (1 << 32) - 1)
142
143
rootf6af1672012-04-06 09:46:29 -0700144class Flow_Info:
Howard Persh680b92a2012-03-31 13:34:35 -0700145 # Members:
146 # priorities - list of flow priorities
147 # dl_addrs - list of MAC addresses
148 # vlans - list of VLAN ids
149 # ethertypes - list of Ethertypes
150 # ip_addrs - list of IP addresses
151 # ip_tos - list of IP TOS values
152 # ip_protos - list of IP protocols
153 # l4_ports - list of L4 ports
154
155 def __init__(self):
156 priorities = []
157 dl_addrs = []
158 vlans = []
159 ethertypes = []
160 ip_addrs = []
161 ip_tos = []
162 ip_protos = []
163 l4_ports = []
164
165 def rand(self, n):
166 self.priorities = []
167 i = 0
168 while i < n:
169 self.priorities.append(random.randint(1, 65534))
170 i = i + 1
171
172 self.dl_addrs = []
173 i = 0
174 while i < n:
175 self.dl_addrs.append(rand_dl_addr())
176 i = i + 1
177
Howard Pershb10a47a2012-08-21 13:54:47 -0700178 if test_param_get(fq_config, "vlans", []) != []:
179 self.vlans = test_param_get(fq_config, "vlans", [])
180
181 fq_logger.info("Overriding VLAN ids to:")
182 fq_logger.info(self.vlans)
183 else:
184 self.vlans = []
185 i = 0
186 while i < n:
187 self.vlans.append(random.randint(1, 4094))
188 i = i + 1
Howard Persh680b92a2012-03-31 13:34:35 -0700189
rootf6af1672012-04-06 09:46:29 -0700190 self.ethertypes = [0x0800, 0x0806]
Howard Persh680b92a2012-03-31 13:34:35 -0700191 i = 0
192 while i < n:
193 self.ethertypes.append(random.randint(0, (1 << 16) - 1))
194 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700195 self.ethertypes = shuffle(self.ethertypes)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700196
197 self.ip_addrs = []
198 i = 0
199 while i < n:
200 self.ip_addrs.append(rand_nw_addr())
201 i = i + 1
202
203 self.ip_tos = []
204 i = 0
205 while i < n:
206 self.ip_tos.append(random.randint(0, (1 << 8) - 1) & ~3)
207 i = i + 1
208
rootf6af1672012-04-06 09:46:29 -0700209 self.ip_protos = [1, 6, 17]
Howard Persh680b92a2012-03-31 13:34:35 -0700210 i = 0
211 while i < n:
212 self.ip_protos.append(random.randint(0, (1 << 8) - 1))
213 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700214 self.ip_protos = shuffle(self.ip_protos)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700215
216 self.l4_ports = []
217 i = 0
218 while i < n:
219 self.l4_ports.append(random.randint(0, (1 << 16) - 1))
220 i = i + 1
221
222 def rand_priority(self):
223 return rand_pick(self.priorities)
224
225 def rand_dl_addr(self):
226 return rand_pick(self.dl_addrs)
227
228 def rand_vlan(self):
229 return rand_pick(self.vlans)
230
231 def rand_ethertype(self):
232 return rand_pick(self.ethertypes)
233
234 def rand_ip_addr(self):
235 return rand_pick(self.ip_addrs)
236
237 def rand_ip_tos(self):
238 return rand_pick(self.ip_tos)
239
240 def rand_ip_proto(self):
241 return rand_pick(self.ip_protos)
242
243 def rand_l4_port(self):
244 return rand_pick(self.l4_ports)
245
246
Howard Pershc7963582012-03-29 10:02:59 -0700247# TBD - These don't belong here
248
Howard Persh680b92a2012-03-31 13:34:35 -0700249all_wildcards_list = [ofp.OFPFW_IN_PORT,
Howard Persh680b92a2012-03-31 13:34:35 -0700250 ofp.OFPFW_DL_DST,
rootf6af1672012-04-06 09:46:29 -0700251 ofp.OFPFW_DL_SRC,
252 ofp.OFPFW_DL_VLAN,
253 ofp.OFPFW_DL_VLAN_PCP,
Howard Persh680b92a2012-03-31 13:34:35 -0700254 ofp.OFPFW_DL_TYPE,
rootf6af1672012-04-06 09:46:29 -0700255 ofp.OFPFW_NW_TOS,
Howard Persh680b92a2012-03-31 13:34:35 -0700256 ofp.OFPFW_NW_PROTO,
Howard Persh680b92a2012-03-31 13:34:35 -0700257 ofp.OFPFW_NW_SRC_MASK,
258 ofp.OFPFW_NW_DST_MASK,
rootf6af1672012-04-06 09:46:29 -0700259 ofp.OFPFW_TP_SRC,
260 ofp.OFPFW_TP_DST
Howard Persh680b92a2012-03-31 13:34:35 -0700261 ]
Howard Pershc7963582012-03-29 10:02:59 -0700262
Howard Persh3340d452012-04-06 16:45:21 -0700263# TBD - Need this because there are duplicates in ofp.ofp_flow_wildcards_map
264# -- FIX
rootf6af1672012-04-06 09:46:29 -0700265all_wildcard_names = {
266 1 : 'OFPFW_IN_PORT',
267 2 : 'OFPFW_DL_VLAN',
268 4 : 'OFPFW_DL_SRC',
269 8 : 'OFPFW_DL_DST',
270 16 : 'OFPFW_DL_TYPE',
271 32 : 'OFPFW_NW_PROTO',
272 64 : 'OFPFW_TP_SRC',
273 128 : 'OFPFW_TP_DST',
274 1048576 : 'OFPFW_DL_VLAN_PCP',
275 2097152 : 'OFPFW_NW_TOS'
276}
277
rootf6af1672012-04-06 09:46:29 -0700278def wildcard_set(x, w, val):
279 result = x
280 if w == ofp.OFPFW_NW_SRC_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700281 result = (result & ~ofp.OFPFW_NW_SRC_MASK) \
282 | (val << ofp.OFPFW_NW_SRC_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700283 elif w == ofp.OFPFW_NW_DST_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700284 result = (result & ~ofp.OFPFW_NW_DST_MASK) \
285 | (val << ofp.OFPFW_NW_DST_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700286 elif val == 0:
287 result = result & ~w
288 else:
289 result = result | w
290 return result
291
292def wildcard_get(x, w):
293 if w == ofp.OFPFW_NW_SRC_MASK:
294 return (x & ofp.OFPFW_NW_SRC_MASK) >> ofp.OFPFW_NW_SRC_SHIFT
295 if w == ofp.OFPFW_NW_DST_MASK:
296 return (x & ofp.OFPFW_NW_DST_MASK) >> ofp.OFPFW_NW_DST_SHIFT
297 return 1 if (x & w) != 0 else 0
298
Howard Persh8d21c1f2012-04-20 15:57:29 -0700299def wildcards_to_str(wildcards):
300 result = "{"
301 sep = ""
302 for w in all_wildcards_list:
303 if (wildcards & w) == 0:
304 continue
305 if w == ofp.OFPFW_NW_SRC_MASK:
306 n = wildcard_get(wildcards, w)
307 if n > 0:
308 result = result + sep + ("OFPFW_NW_SRC(%d)" % (n))
309 elif w == ofp.OFPFW_NW_DST_MASK:
310 n = wildcard_get(wildcards, w)
311 if n > 0:
312 result = result + sep + ("OFPFW_NW_DST(%d)" % (n))
313 else:
314 result = result + sep + all_wildcard_names[w]
315 sep = ", "
316 result = result +"}"
317 return result
Howard Pershc7963582012-03-29 10:02:59 -0700318
Howard Persh680b92a2012-03-31 13:34:35 -0700319all_actions_list = [ofp.OFPAT_OUTPUT,
320 ofp.OFPAT_SET_VLAN_VID,
321 ofp.OFPAT_SET_VLAN_PCP,
322 ofp.OFPAT_STRIP_VLAN,
323 ofp.OFPAT_SET_DL_SRC,
324 ofp.OFPAT_SET_DL_DST,
325 ofp.OFPAT_SET_NW_SRC,
326 ofp.OFPAT_SET_NW_DST,
327 ofp.OFPAT_SET_NW_TOS,
328 ofp.OFPAT_SET_TP_SRC,
329 ofp.OFPAT_SET_TP_DST,
330 ofp.OFPAT_ENQUEUE
331 ]
332
Howard Persh8d21c1f2012-04-20 15:57:29 -0700333def actions_bmap_to_str(bm):
334 result = "{"
335 sep = ""
336 for a in all_actions_list:
337 if ((1 << a) & bm) != 0:
338 result = result + sep + ofp.ofp_action_type_map[a]
339 sep = ", "
340 result = result + "}"
341 return result
342
Howard Persh680b92a2012-03-31 13:34:35 -0700343def dl_addr_to_str(a):
344 return "%x:%x:%x:%x:%x:%x" % tuple(a)
345
346def ip_addr_to_str(a, n):
rootf6af1672012-04-06 09:46:29 -0700347 if n is not None:
348 a = a & ~((1 << (32 - n)) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700349 result = "%d.%d.%d.%d" % (a >> 24, \
350 (a >> 16) & 0xff, \
351 (a >> 8) & 0xff, \
352 a & 0xff \
353 )
354 if n is not None:
355 result = result + ("/%d" % (n))
356 return result
357
Howard Pershc7963582012-03-29 10:02:59 -0700358
rootf6af1672012-04-06 09:46:29 -0700359class Flow_Cfg:
Howard Pershc7963582012-03-29 10:02:59 -0700360 # Members:
361 # - match
362 # - idle_timeout
363 # - hard_timeout
364 # - priority
365 # - action_list
366
367 def __init__(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700368 self.priority = 0
Howard Pershc7963582012-03-29 10:02:59 -0700369 self.match = parse.ofp_match()
370 self.match.wildcards = ofp.OFPFW_ALL
371 self.idle_timeout = 0
372 self.hard_timeout = 0
Howard Pershc7963582012-03-29 10:02:59 -0700373 self.actions = action_list.action_list()
374
rootf6af1672012-04-06 09:46:29 -0700375 # {pri, match} is considered a flow key
376 def key_equal(self, x):
Howard Persh680b92a2012-03-31 13:34:35 -0700377 if self.priority != x.priority:
378 return False
379 # TBD - Should this logic be moved to ofp_match.__eq__()?
380 if self.match.wildcards != x.match.wildcards:
381 return False
rootf6af1672012-04-06 09:46:29 -0700382 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700383 and self.match.in_port != x.match.in_port:
384 return False
rootf6af1672012-04-06 09:46:29 -0700385 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700386 and self.match.dl_dst != x.match.dl_dst:
387 return False
rootf6af1672012-04-06 09:46:29 -0700388 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0 \
389 and self.match.dl_src != x.match.dl_src:
390 return False
391 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700392 and self.match.dl_vlan != x.match.dl_vlan:
393 return False
rootf6af1672012-04-06 09:46:29 -0700394 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700395 and self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
396 return False
rootf6af1672012-04-06 09:46:29 -0700397 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700398 and self.match.dl_type != x.match.dl_type:
399 return False
rootf6af1672012-04-06 09:46:29 -0700400 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700401 and self.match.nw_tos != x.match.nw_tos:
402 return False
rootf6af1672012-04-06 09:46:29 -0700403 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700404 and self.match.nw_proto != x.match.nw_proto:
405 return False
rootf6af1672012-04-06 09:46:29 -0700406 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
407 if n < 32:
408 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700409 if (self.match.nw_src & m) != (x.match.nw_src & m):
410 return False
rootf6af1672012-04-06 09:46:29 -0700411 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
412 if n < 32:
413 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700414 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
415 return False
rootf6af1672012-04-06 09:46:29 -0700416 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0 \
417 and self.match.tp_src != x.match.tp_src:
Howard Persh680b92a2012-03-31 13:34:35 -0700418 return False
rootf6af1672012-04-06 09:46:29 -0700419 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0 \
420 and self.match.tp_dst != x.match.tp_dst:
421 return False
422 return True
423
Howard Persh5f3c83f2012-04-13 09:57:10 -0700424 def actions_equal(self, x):
425 if test_param_get(fq_config, "conservative_ordered_actions", True):
426 # Compare actions lists as unordered
427
root2843d2b2012-04-06 10:27:46 -0700428 aa = copy.deepcopy(x.actions.actions)
429 for a in self.actions.actions:
430 i = 0
431 while i < len(aa):
432 if a == aa[i]:
433 break
434 i = i + 1
435 if i < len(aa):
436 aa.pop(i)
437 else:
438 return False
439 return aa == []
440 else:
441 return self.actions == x.actions
Howard Persh5f3c83f2012-04-13 09:57:10 -0700442
443 def non_key_equal(self, x):
444 if self.cookie != x.cookie:
445 return False
446 if self.idle_timeout != x.idle_timeout:
447 return False
448 if self.hard_timeout != x.hard_timeout:
449 return False
450 return self.actions_equal(x)
rootf6af1672012-04-06 09:46:29 -0700451
root2843d2b2012-04-06 10:27:46 -0700452 def key_str(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700453 result = "priority=%d" % self.priority
454 # TBD - Would be nice if ofp_match.show() was better behaved
455 # (no newlines), and more intuitive (things in hex where approprate), etc.
Howard Persh8d21c1f2012-04-20 15:57:29 -0700456 result = result + (", wildcards=0x%x=%s" \
457 % (self.match.wildcards, \
458 wildcards_to_str(self.match.wildcards) \
459 )
460 )
rootf6af1672012-04-06 09:46:29 -0700461 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700462 result = result + (", in_port=%d" % (self.match.in_port))
rootf6af1672012-04-06 09:46:29 -0700463 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700464 result = result + (", dl_dst=%s" \
465 % (dl_addr_to_str(self.match.dl_dst)) \
466 )
rootf6af1672012-04-06 09:46:29 -0700467 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700468 result = result + (", dl_src=%s" \
469 % (dl_addr_to_str(self.match.dl_src)) \
470 )
rootf6af1672012-04-06 09:46:29 -0700471 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700472 result = result + (", dl_vlan=%d" % (self.match.dl_vlan))
rootf6af1672012-04-06 09:46:29 -0700473 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700474 result = result + (", dl_vlan_pcp=%d" % (self.match.dl_vlan_pcp))
rootf6af1672012-04-06 09:46:29 -0700475 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700476 result = result + (", dl_type=0x%x" % (self.match.dl_type))
rootf6af1672012-04-06 09:46:29 -0700477 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700478 result = result + (", nw_tos=0x%x" % (self.match.nw_tos))
rootf6af1672012-04-06 09:46:29 -0700479 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700480 result = result + (", nw_proto=%d" % (self.match.nw_proto))
rootf6af1672012-04-06 09:46:29 -0700481 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700482 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700483 result = result + (", nw_src=%s" % \
484 (ip_addr_to_str(self.match.nw_src, 32 - n)) \
485 )
rootf6af1672012-04-06 09:46:29 -0700486 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700487 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700488 result = result + (", nw_dst=%s" % \
489 (ip_addr_to_str(self.match.nw_dst, 32 - n)) \
490 )
rootf6af1672012-04-06 09:46:29 -0700491 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700492 result = result + (", tp_src=%d" % self.match.tp_src)
rootf6af1672012-04-06 09:46:29 -0700493 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700494 result = result + (", tp_dst=%d" % self.match.tp_dst)
rootf6af1672012-04-06 09:46:29 -0700495 return result
496
497 def __eq__(self, x):
498 return (self.key_equal(x) and self.non_key_equal(x))
499
500 def __str__(self):
root2843d2b2012-04-06 10:27:46 -0700501 result = self.key_str()
502 result = result + (", cookie=%d" % self.cookie)
Howard Persh680b92a2012-03-31 13:34:35 -0700503 result = result + (", idle_timeout=%d" % self.idle_timeout)
504 result = result + (", hard_timeout=%d" % self.hard_timeout)
Howard Persh680b92a2012-03-31 13:34:35 -0700505 for a in self.actions.actions:
506 result = result + (", action=%s" % ofp.ofp_action_type_map[a.type])
507 if a.type == ofp.OFPAT_OUTPUT:
508 result = result + ("(%d)" % (a.port))
509 elif a.type == ofp.OFPAT_SET_VLAN_VID:
510 result = result + ("(%d)" % (a.vlan_vid))
511 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
512 result = result + ("(%d)" % (a.vlan_pcp))
513 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
514 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
515 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
516 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
517 elif a.type == ofp.OFPAT_SET_NW_TOS:
518 result = result + ("(0x%x)" % (a.nw_tos))
519 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
520 result = result + ("(%d)" % (a.tp_port))
521 elif a.type == ofp.OFPAT_ENQUEUE:
522 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
523 return result
Howard Pershc7963582012-03-29 10:02:59 -0700524
Howard Persh8d21c1f2012-04-20 15:57:29 -0700525 def rand_actions_ordered(self, fi, valid_actions, valid_ports, valid_queues):
Howard Persh3340d452012-04-06 16:45:21 -0700526 # Action lists are ordered, so pick an ordered random subset of
527 # supported actions
Howard Pershc1199d52012-04-11 14:21:32 -0700528
529 actions_force = test_param_get(fq_config, "actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700530 if actions_force != 0:
531 fq_logger.info("Forced actions:")
532 fq_logger.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700533
Dan Talayco910a8282012-04-07 00:05:20 -0700534 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh3340d452012-04-06 16:45:21 -0700535 supported_actions = []
536 for a in all_actions_list:
537 if ((1 << a) & valid_actions) != 0:
538 supported_actions.append(a)
539
Howard Pershc1199d52012-04-11 14:21:32 -0700540 actions \
541 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
542
543 for a in all_actions_list:
544 if ((1 << a) & actions_force) != 0:
545 actions.append(a)
546
547 actions = shuffle(actions)
Howard Persh3340d452012-04-06 16:45:21 -0700548
Howard Persh6a3698d2012-08-21 14:26:39 -0700549 set_vlanf = False
550 strip_vlanf = False
Howard Persh3340d452012-04-06 16:45:21 -0700551 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700552 for a in actions:
Dan Talayco910a8282012-04-07 00:05:20 -0700553 act = None
Howard Persh3340d452012-04-06 16:45:21 -0700554 if a == ofp.OFPAT_OUTPUT:
555 pass # OUTPUT actions must come last
556 elif a == ofp.OFPAT_SET_VLAN_VID:
Howard Persh6a3698d2012-08-21 14:26:39 -0700557 if not strip_vlanf:
558 act = action.action_set_vlan_vid()
559 act.vlan_vid = fi.rand_vlan()
560 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700561 elif a == ofp.OFPAT_SET_VLAN_PCP:
Howard Persh6a3698d2012-08-21 14:26:39 -0700562 if not strip_vlanf:
563 act = action.action_set_vlan_pcp()
564 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
565 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700566 elif a == ofp.OFPAT_STRIP_VLAN:
Howard Persh6a3698d2012-08-21 14:26:39 -0700567 if not set_vlanf:
568 act = action.action_strip_vlan()
569 strip_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700570 elif a == ofp.OFPAT_SET_DL_SRC:
571 act = action.action_set_dl_src()
572 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700573 elif a == ofp.OFPAT_SET_DL_DST:
574 act = action.action_set_dl_dst()
575 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700576 elif a == ofp.OFPAT_SET_NW_SRC:
577 act = action.action_set_nw_src()
578 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700579 elif a == ofp.OFPAT_SET_NW_DST:
580 act = action.action_set_nw_dst()
581 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700582 elif a == ofp.OFPAT_SET_NW_TOS:
583 act = action.action_set_nw_tos()
584 act.nw_tos = fi.rand_ip_tos()
Howard Persh3340d452012-04-06 16:45:21 -0700585 elif a == ofp.OFPAT_SET_TP_SRC:
586 act = action.action_set_tp_src()
587 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700588 elif a == ofp.OFPAT_SET_TP_DST:
589 act = action.action_set_tp_dst()
590 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700591 elif a == ofp.OFPAT_ENQUEUE:
592 pass # Enqueue actions must come last
Dan Talayco910a8282012-04-07 00:05:20 -0700593 if act:
594 act.max_len = ACTION_MAX_LEN
595 self.actions.add(act)
596
Howard Persh3340d452012-04-06 16:45:21 -0700597 p = random.randint(1, 100)
Howard Pershc1199d52012-04-11 14:21:32 -0700598 if (((1 << ofp.OFPAT_ENQUEUE) & actions_force) != 0 or p <= 33) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700599 and len(valid_queues) > 0 \
600 and ofp.OFPAT_ENQUEUE in actions:
Howard Pershc1199d52012-04-11 14:21:32 -0700601 # In not forecd, one third of the time, include ENQUEUE actions
602 # at end of list
Howard Persh3340d452012-04-06 16:45:21 -0700603 # At most 1 ENQUEUE action
604 act = action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700605 (act.port, act.queue_id) = rand_pick(valid_queues)
Dan Talayco910a8282012-04-07 00:05:20 -0700606 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700607 self.actions.add(act)
Howard Pershc1199d52012-04-11 14:21:32 -0700608 if (((1 << ofp.OFPAT_OUTPUT) & actions_force) != 0 \
609 or (p > 33 and p <= 66) \
610 ) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700611 and len(valid_ports) > 0 \
Howard Pershc1199d52012-04-11 14:21:32 -0700612 and ofp.OFPAT_OUTPUT in actions:
Howard Persh3340d452012-04-06 16:45:21 -0700613 # One third of the time, include OUTPUT actions at end of list
614 port_idxs = shuffle(range(len(valid_ports)))
615 # Only 1 output action allowed if IN_PORT wildcarded
616 n = 1 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) != 0 \
617 else random.randint(1, len(valid_ports))
618 port_idxs = port_idxs[0 : n]
619 for pi in port_idxs:
620 act = action.action_output()
621 act.port = valid_ports[pi]
Dan Talayco910a8282012-04-07 00:05:20 -0700622 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700623 if act.port != ofp.OFPP_IN_PORT \
624 or wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
625 # OUTPUT(IN_PORT) only valid if OFPFW_IN_PORT not wildcarded
626 self.actions.add(act)
627 else:
628 # One third of the time, include neither
629 pass
630
631
632 # Randomize flow data for flow modifies (i.e. cookie and actions)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700633 def rand_mod(self, fi, valid_actions, valid_ports, valid_queues):
rootf6af1672012-04-06 09:46:29 -0700634 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700635
Dan Talayco910a8282012-04-07 00:05:20 -0700636 # By default, test with conservative ordering conventions
637 # This should probably be indicated in a profile
638 if test_param_get(fq_config, "conservative_ordered_actions", True):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700639 self.rand_actions_ordered(fi, valid_actions, valid_ports, valid_queues)
Howard Persh3340d452012-04-06 16:45:21 -0700640 return self
641
Howard Pershc1199d52012-04-11 14:21:32 -0700642 actions_force = test_param_get(fq_config, "actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700643 if actions_force != 0:
644 fq_logger.info("Forced actions:")
645 fq_logger.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700646
647 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh680b92a2012-03-31 13:34:35 -0700648 supported_actions = []
649 for a in all_actions_list:
650 if ((1 << a) & valid_actions) != 0:
651 supported_actions.append(a)
652
Howard Pershc1199d52012-04-11 14:21:32 -0700653 actions \
654 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
655
656 for a in all_actions_list:
657 if ((1 << a) & actions_force) != 0:
658 actions.append(a)
659
660 actions = shuffle(actions)
Howard Pershc7963582012-03-29 10:02:59 -0700661
662 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700663 for a in actions:
Howard Pershc7963582012-03-29 10:02:59 -0700664 if a == ofp.OFPAT_OUTPUT:
665 # TBD - Output actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700666 if len(valid_ports) == 0:
667 continue
Howard Pershc7963582012-03-29 10:02:59 -0700668 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700669 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700670 for pi in port_idxs:
671 act = action.action_output()
Howard Persh680b92a2012-03-31 13:34:35 -0700672 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700673 self.actions.add(act)
674 elif a == ofp.OFPAT_SET_VLAN_VID:
675 act = action.action_set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700676 act.vlan_vid = fi.rand_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700677 self.actions.add(act)
678 elif a == ofp.OFPAT_SET_VLAN_PCP:
Dan Talayco910a8282012-04-07 00:05:20 -0700679 act = action.action_set_vlan_pcp()
680 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700681 elif a == ofp.OFPAT_STRIP_VLAN:
682 act = action.action_strip_vlan()
683 self.actions.add(act)
684 elif a == ofp.OFPAT_SET_DL_SRC:
685 act = action.action_set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700686 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700687 self.actions.add(act)
688 elif a == ofp.OFPAT_SET_DL_DST:
689 act = action.action_set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700690 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700691 self.actions.add(act)
692 elif a == ofp.OFPAT_SET_NW_SRC:
693 act = action.action_set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700694 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700695 self.actions.add(act)
696 elif a == ofp.OFPAT_SET_NW_DST:
697 act = action.action_set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700698 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700699 self.actions.add(act)
700 elif a == ofp.OFPAT_SET_NW_TOS:
701 act = action.action_set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700702 act.nw_tos = fi.rand_ip_tos()
Howard Pershc7963582012-03-29 10:02:59 -0700703 self.actions.add(act)
704 elif a == ofp.OFPAT_SET_TP_SRC:
705 act = action.action_set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700706 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700707 self.actions.add(act)
708 elif a == ofp.OFPAT_SET_TP_DST:
709 act = action.action_set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700710 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700711 self.actions.add(act)
712 elif a == ofp.OFPAT_ENQUEUE:
713 # TBD - Enqueue actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700714 if len(valid_queues) == 0:
715 continue
716 qidxs = shuffle(range(len(valid_queues)))
717 qidxs = qidxs[0 : random.randint(1, len(valid_queues))]
718 for qi in qidxs:
Howard Pershc7963582012-03-29 10:02:59 -0700719 act = action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700720 (act.port, act.queue_id) = valid_queues[qi]
Howard Pershc7963582012-03-29 10:02:59 -0700721 self.actions.add(act)
722
723 return self
724
rootf6af1672012-04-06 09:46:29 -0700725 # Randomize flow cfg
Ed Swierk99a74de2012-08-22 06:40:54 -0700726 def rand(self, fi, wildcards_force, valid_wildcards, valid_actions, valid_ports,
727 valid_queues):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700728 if wildcards_force != 0:
729 fq_logger.info("Wildcards forced:")
730 fq_logger.info(wildcards_to_str(wildcards_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700731
rootf6af1672012-04-06 09:46:29 -0700732 # Start with no wildcards, i.e. everything specified
733 self.match.wildcards = 0
Howard Pershc1199d52012-04-11 14:21:32 -0700734
735 if wildcards_force != 0:
736 exact = False
737 else:
738 # Make approx. 5% of flows exact
739 exact = (random.randint(1, 100) <= 5)
rootf6af1672012-04-06 09:46:29 -0700740
741 # For each qualifier Q,
742 # if (wildcarding is not supported for Q,
743 # or an exact flow is specified
744 # or a coin toss comes up heads),
745 # specify Q
746 # else
747 # wildcard Q
748
Howard Pershc1199d52012-04-11 14:21:32 -0700749 if wildcard_get(wildcards_force, ofp.OFPFW_IN_PORT) == 0 \
750 and (wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
751 or exact \
752 or flip_coin() \
753 ):
rootf6af1672012-04-06 09:46:29 -0700754 self.match.in_port = rand_pick(valid_ports)
755 else:
Howard Persh3340d452012-04-06 16:45:21 -0700756 self.match.wildcards = wildcard_set(self.match.wildcards, \
757 ofp.OFPFW_IN_PORT, \
758 1 \
759 )
rootf6af1672012-04-06 09:46:29 -0700760
Howard Pershc1199d52012-04-11 14:21:32 -0700761 if wildcard_get(wildcards_force, ofp.OFPFW_DL_DST) == 0 \
762 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
763 or exact \
764 or flip_coin() \
765 ):
rootf6af1672012-04-06 09:46:29 -0700766 self.match.dl_dst = fi.rand_dl_addr()
767 else:
Howard Persh3340d452012-04-06 16:45:21 -0700768 self.match.wildcards = wildcard_set(self.match.wildcards, \
769 ofp.OFPFW_DL_DST, \
770 1 \
771 )
rootf6af1672012-04-06 09:46:29 -0700772
Howard Pershc1199d52012-04-11 14:21:32 -0700773 if wildcard_get(wildcards_force, ofp.OFPFW_DL_SRC) == 0 \
774 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
775 or exact \
776 or flip_coin() \
777 ):
rootf6af1672012-04-06 09:46:29 -0700778 self.match.dl_src = fi.rand_dl_addr()
779 else:
Howard Persh3340d452012-04-06 16:45:21 -0700780 self.match.wildcards = wildcard_set(self.match.wildcards, \
781 ofp.OFPFW_DL_SRC, \
782 1 \
783 )
rootf6af1672012-04-06 09:46:29 -0700784
Howard Pershc1199d52012-04-11 14:21:32 -0700785 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN) == 0 \
786 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
787 or exact \
788 or flip_coin() \
789 ):
rootf6af1672012-04-06 09:46:29 -0700790 self.match.dl_vlan = fi.rand_vlan()
791 else:
Howard Persh3340d452012-04-06 16:45:21 -0700792 self.match.wildcards = wildcard_set(self.match.wildcards, \
793 ofp.OFPFW_DL_VLAN, \
794 1 \
795 )
rootf6af1672012-04-06 09:46:29 -0700796
Howard Pershc1199d52012-04-11 14:21:32 -0700797 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN_PCP) == 0 \
798 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
799 or exact \
800 or flip_coin() \
801 ):
802 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
803 else:
804 self.match.wildcards = wildcard_set(self.match.wildcards, \
805 ofp.OFPFW_DL_VLAN_PCP, \
806 1 \
807 )
808
809 if wildcard_get(wildcards_force, ofp.OFPFW_DL_TYPE) == 0 \
810 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
811 or exact \
812 or flip_coin() \
813 ):
rootf6af1672012-04-06 09:46:29 -0700814 self.match.dl_type = fi.rand_ethertype()
815 else:
Howard Persh3340d452012-04-06 16:45:21 -0700816 self.match.wildcards = wildcard_set(self.match.wildcards, \
817 ofp.OFPFW_DL_TYPE, \
818 1 \
819 )
rootf6af1672012-04-06 09:46:29 -0700820
Howard Pershc1199d52012-04-11 14:21:32 -0700821 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_SRC_MASK)
822 if n == 0:
823 if exact or flip_coin():
824 n = 0
825 else:
826 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
827 if n > 32:
828 n = 32
829 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700830 self.match.wildcards = wildcard_set(self.match.wildcards, \
831 ofp.OFPFW_NW_SRC_MASK, \
832 n \
833 )
rootf6af1672012-04-06 09:46:29 -0700834 if n < 32:
835 self.match.nw_src = fi.rand_ip_addr() & ~((1 << n) - 1)
836 # Specifying any IP address match other than all bits
837 # don't care requires that Ethertype is one of {IP, ARP}
838 if flip_coin():
839 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700840 self.match.wildcards = wildcard_set(self.match.wildcards, \
841 ofp.OFPFW_DL_TYPE, \
842 0 \
843 )
rootf6af1672012-04-06 09:46:29 -0700844
Howard Pershc1199d52012-04-11 14:21:32 -0700845 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_DST_MASK)
846 if n == 0:
847 if exact or flip_coin():
848 n = 0
849 else:
850 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
851 if n > 32:
852 n = 32
853 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700854 self.match.wildcards = wildcard_set(self.match.wildcards, \
855 ofp.OFPFW_NW_DST_MASK, \
856 n \
857 )
rootf6af1672012-04-06 09:46:29 -0700858 if n < 32:
859 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
860 # Specifying any IP address match other than all bits
861 # don't care requires that Ethertype is one of {IP, ARP}
862 if flip_coin():
863 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700864 self.match.wildcards = wildcard_set(self.match.wildcards, \
865 ofp.OFPFW_DL_TYPE, \
866 0 \
867 )
rootf6af1672012-04-06 09:46:29 -0700868
Howard Pershc1199d52012-04-11 14:21:32 -0700869 if wildcard_get(wildcards_force, ofp.OFPFW_NW_TOS) == 0 \
870 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
871 or exact \
872 or flip_coin() \
873 ):
rootf6af1672012-04-06 09:46:29 -0700874 self.match.nw_tos = fi.rand_ip_tos()
875 # Specifying a TOS value requires that Ethertype is IP
876 if flip_coin():
877 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700878 self.match.wildcards = wildcard_set(self.match.wildcards, \
879 ofp.OFPFW_DL_TYPE, \
880 0 \
881 )
rootf6af1672012-04-06 09:46:29 -0700882 else:
Howard Persh3340d452012-04-06 16:45:21 -0700883 self.match.wildcards = wildcard_set(self.match.wildcards, \
884 ofp.OFPFW_NW_TOS, \
885 1 \
886 )
rootf6af1672012-04-06 09:46:29 -0700887
Dan Talayco910a8282012-04-07 00:05:20 -0700888 # Known issue on OVS with specifying nw_proto w/o dl_type as IP
Howard Pershc1199d52012-04-11 14:21:32 -0700889 if wildcard_get(wildcards_force, ofp.OFPFW_NW_PROTO) == 0 \
890 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
891 or exact \
892 or flip_coin() \
893 ):
Dan Talayco910a8282012-04-07 00:05:20 -0700894 self.match.nw_proto = fi.rand_ip_proto()
895 # Specifying an IP protocol requires that Ethertype is IP
896 if flip_coin():
897 self.match.dl_type = 0x0800
898 self.match.wildcards = wildcard_set(self.match.wildcards, \
899 ofp.OFPFW_DL_TYPE, \
900 0 \
901 )
902 else:
Howard Persh3340d452012-04-06 16:45:21 -0700903 self.match.wildcards = wildcard_set(self.match.wildcards, \
904 ofp.OFPFW_NW_PROTO, \
905 1 \
906 )
Dan Talayco910a8282012-04-07 00:05:20 -0700907
Howard Pershc1199d52012-04-11 14:21:32 -0700908 if wildcard_get(wildcards_force, ofp.OFPFW_TP_SRC) == 0 \
909 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
910 or exact\
911 or flip_coin() \
912 ):
rootf6af1672012-04-06 09:46:29 -0700913 self.match.tp_src = fi.rand_l4_port()
914 # Specifying a L4 port requires that IP protcol is
915 # one of {ICMP, TCP, UDP}
916 if flip_coin():
917 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700918 self.match.wildcards = wildcard_set(self.match.wildcards, \
919 ofp.OFPFW_NW_PROTO, \
920 0 \
921 )
rootf6af1672012-04-06 09:46:29 -0700922 # Specifying a L4 port requirues that Ethertype is IP
923 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700924 self.match.wildcards = wildcard_set(self.match.wildcards, \
925 ofp.OFPFW_DL_TYPE, \
926 0 \
927 )
rootf6af1672012-04-06 09:46:29 -0700928 if self.match.nw_proto == 1:
929 self.match.tp_src = self.match.tp_src & 0xff
930 else:
Howard Persh3340d452012-04-06 16:45:21 -0700931 self.match.wildcards = wildcard_set(self.match.wildcards, \
932 ofp.OFPFW_TP_SRC, \
933 1 \
934 )
rootf6af1672012-04-06 09:46:29 -0700935
Howard Pershc1199d52012-04-11 14:21:32 -0700936 if wildcard_get(wildcards_force, ofp.OFPFW_TP_DST) == 0 \
937 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
938 or exact \
939 or flip_coin() \
940 ):
rootf6af1672012-04-06 09:46:29 -0700941 self.match.tp_dst = fi.rand_l4_port()
942 # Specifying a L4 port requires that IP protcol is
943 # one of {ICMP, TCP, UDP}
944 if flip_coin():
945 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700946 self.match.wildcards = wildcard_set(self.match.wildcards, \
947 ofp.OFPFW_NW_PROTO, \
948 0 \
949 )
rootf6af1672012-04-06 09:46:29 -0700950 # Specifying a L4 port requirues that Ethertype is IP
951 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700952 self.match.wildcards = wildcard_set(self.match.wildcards, \
953 ofp.OFPFW_DL_TYPE, \
954 0 \
955 )
rootf6af1672012-04-06 09:46:29 -0700956 if self.match.nw_proto == 1:
957 self.match.tp_dst = self.match.tp_dst & 0xff
958 else:
Howard Persh3340d452012-04-06 16:45:21 -0700959 self.match.wildcards = wildcard_set(self.match.wildcards, \
960 ofp.OFPFW_TP_DST, \
961 1 \
962 )
rootf6af1672012-04-06 09:46:29 -0700963
964 # If nothing is wildcarded, it is an exact flow spec -- some switches
Howard Persh3340d452012-04-06 16:45:21 -0700965 # (Open vSwitch, for one) *require* that exact flow specs
966 # have priority 65535.
967 self.priority = 65535 if self.match.wildcards == 0 \
968 else fi.rand_priority()
rootf6af1672012-04-06 09:46:29 -0700969
970 # N.B. Don't make the timeout too short, else the flow might
971 # disappear before we get a chance to check for it.
972 t = random.randint(0, 65535)
973 self.idle_timeout = 0 if t < 60 else t
974 t = random.randint(0, 65535)
975 self.hard_timeout = 0 if t < 60 else t
976
Howard Persh8d21c1f2012-04-20 15:57:29 -0700977 self.rand_mod(fi, valid_actions, valid_ports, valid_queues)
rootf6af1672012-04-06 09:46:29 -0700978
979 return self
980
981 # Return flow cfg in canonical form
Howard Persh3340d452012-04-06 16:45:21 -0700982 # - There are dependencies between flow qualifiers, e.g. it only makes
983 # sense to qualify nw_proto if dl_type is qualified to be 0x0800 (IP).
984 # The canonical form of flow match criteria will "wildcard out"
985 # all such cases.
rootf6af1672012-04-06 09:46:29 -0700986 def canonical(self):
987 result = copy.deepcopy(self)
Howard Persh07d99e62012-04-09 15:26:57 -0700988
989 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_VLAN) != 0:
990 result.match.wildcards = wildcard_set(result.match.wildcards, \
991 ofp.OFPFW_DL_VLAN_PCP, \
992 1 \
993 )
994
rootf6af1672012-04-06 09:46:29 -0700995 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
996 or result.match.dl_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700997 # dl_tyoe is wildcarded, or specified as something other
998 # than IP or ARP
Howard Persh07d99e62012-04-09 15:26:57 -0700999 # => nw_src, nw_dst, nw_proto cannot be specified,
1000 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001001 result.match.wildcards = wildcard_set(result.match.wildcards, \
1002 ofp.OFPFW_NW_SRC_MASK, \
1003 32 \
1004 )
1005 result.match.wildcards = wildcard_set(result.match.wildcards, \
1006 ofp.OFPFW_NW_DST_MASK, \
1007 32 \
1008 )
Howard Persh3340d452012-04-06 16:45:21 -07001009 result.match.wildcards = wildcard_set(result.match.wildcards, \
1010 ofp.OFPFW_NW_PROTO, \
1011 1 \
1012 )
Howard Persh07d99e62012-04-09 15:26:57 -07001013
1014 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
1015 or result.match.dl_type != 0x0800:
1016 # dl_type is wildcarded, or specified as something other than IP
1017 # => nw_tos, tp_src and tp_dst cannot be specified,
1018 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001019 result.match.wildcards = wildcard_set(result.match.wildcards, \
1020 ofp.OFPFW_NW_TOS, \
1021 1 \
1022 )
1023 result.match.wildcards = wildcard_set(result.match.wildcards, \
1024 ofp.OFPFW_TP_SRC, \
1025 1 \
1026 )
1027 result.match.wildcards = wildcard_set(result.match.wildcards, \
1028 ofp.OFPFW_TP_DST, \
1029 1 \
1030 )
Howard Persh07d99e62012-04-09 15:26:57 -07001031 result.match.wildcards = wildcard_set(result.match.wildcards, \
1032 ofp.OFPFW_NW_SRC_MASK, \
1033 32 \
1034 )
1035 result.match.wildcards = wildcard_set(result.match.wildcards, \
1036 ofp.OFPFW_NW_DST_MASK, \
1037 32 \
1038 )
1039 result.match.wildcards = wildcard_set(result.match.wildcards, \
1040 ofp.OFPFW_NW_PROTO, \
1041 1 \
1042 )
1043
rootf6af1672012-04-06 09:46:29 -07001044 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
1045 or result.match.nw_proto not in [1, 6, 17]:
Howard Persh3340d452012-04-06 16:45:21 -07001046 # nw_proto is wildcarded, or specified as something other than ICMP,
1047 # TCP or UDP
rootf6af1672012-04-06 09:46:29 -07001048 # => tp_src and tp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001049 result.match.wildcards = wildcard_set(result.match.wildcards, \
1050 ofp.OFPFW_TP_SRC, \
1051 1 \
1052 )
1053 result.match.wildcards = wildcard_set(result.match.wildcards, \
1054 ofp.OFPFW_TP_DST, \
1055 1 \
1056 )
rootf6af1672012-04-06 09:46:29 -07001057 return result
1058
Howard Persh680b92a2012-03-31 13:34:35 -07001059 # Overlap check
1060 # delf == True <=> Check for delete overlap, else add overlap
1061 # "Add overlap" is defined as there exists a packet that could match both the
1062 # receiver and argument flowspecs
1063 # "Delete overlap" is defined as the specificity of the argument flowspec
1064 # is greater than or equal to the specificity of the receiver flowspec
1065 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -07001066 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
1067 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001068 if self.match.in_port != x.match.in_port:
1069 return False # Both specified, and not equal
1070 elif delf:
1071 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001072 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
1073 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001074 if self.match.dl_vlan != x.match.dl_vlan:
1075 return False # Both specified, and not equal
1076 elif delf:
1077 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001078 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
1079 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001080 if self.match.dl_src != x.match.dl_src:
1081 return False # Both specified, and not equal
1082 elif delf:
1083 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001084 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
1085 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001086 if self.match.dl_dst != x.match.dl_dst:
1087 return False # Both specified, and not equal
1088 elif delf:
1089 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001090 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
1091 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001092 if self.match.dl_type != x.match.dl_type:
1093 return False # Both specified, and not equal
1094 elif delf:
1095 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -07001096 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
1097 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001098 if self.match.nw_proto != x.match.nw_proto:
1099 return False # Both specified, and not equal
1100 elif delf:
1101 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001102 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
1103 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001104 if self.match.tp_src != x.match.tp_src:
1105 return False # Both specified, and not equal
1106 elif delf:
1107 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001108 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
1109 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001110 if self.match.tp_dst != x.match.tp_dst:
1111 return False # Both specified, and not equal
1112 elif delf:
1113 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001114 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
1115 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001116 if delf and na < nb:
1117 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001118 if (na < 32 and nb < 32):
1119 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1120 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -07001121 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -07001122 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
1123 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001124 if delf and na < nb:
1125 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001126 if (na < 32 and nb < 32):
1127 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1128 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
rootf6af1672012-04-06 09:46:29 -07001129 return False # Overlapping bits not equal
1130 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
1131 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001132 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
1133 return False # Both specified, and not equal
1134 elif delf:
1135 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001136 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
1137 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001138 if self.match.nw_tos != x.match.nw_tos:
1139 return False # Both specified, and not equal
1140 elif delf:
1141 return False # Receiver more specific
1142 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -07001143
1144 def to_flow_mod_msg(self, msg):
1145 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -07001146 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001147 msg.idle_timeout = self.idle_timeout
1148 msg.hard_timeout = self.hard_timeout
1149 msg.priority = self.priority
1150 msg.actions = self.actions
1151 return msg
1152
1153 def from_flow_stat(self, msg):
1154 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -07001155 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001156 self.idle_timeout = msg.idle_timeout
1157 self.hard_timeout = msg.hard_timeout
1158 self.priority = msg.priority
1159 self.actions = msg.actions
1160
rootf6af1672012-04-06 09:46:29 -07001161 def from_flow_rem(self, msg):
1162 self.match = msg.match
1163 self.idle_timeout = msg.idle_timeout
1164 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -07001165
Howard Pershc7963582012-03-29 10:02:59 -07001166
rootf6af1672012-04-06 09:46:29 -07001167class Flow_Tbl:
1168 def clear(self):
1169 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001170
rootf6af1672012-04-06 09:46:29 -07001171 def __init__(self):
1172 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001173
rootf6af1672012-04-06 09:46:29 -07001174 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001175 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001176
1177 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001178 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001179
1180 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001181 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001182
1183 def values(self):
1184 return self.dict.values()
1185
1186 def count(self):
1187 return len(self.dict)
1188
Ed Swierk99a74de2012-08-22 06:40:54 -07001189 def rand(self, wildcards_force, sw, fi, num_flows):
rootf6af1672012-04-06 09:46:29 -07001190 self.clear()
1191 i = 0
1192 tbl = 0
1193 j = 0
1194 while i < num_flows:
1195 fc = Flow_Cfg()
1196 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001197 wildcards_force, \
rootf6af1672012-04-06 09:46:29 -07001198 sw.tbl_stats.stats[tbl].wildcards, \
1199 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001200 sw.valid_ports, \
1201 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001202 )
1203 fc = fc.canonical()
1204 if self.find(fc):
1205 continue
1206 fc.send_rem = False
1207 self.insert(fc)
1208 i = i + 1
1209 j = j + 1
1210 if j >= sw.tbl_stats.stats[tbl].max_entries:
1211 tbl = tbl + 1
1212 j = 0
1213
1214
1215class Switch:
1216 # Members:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001217 # controller - switch's test controller
1218 # sw_features - switch's OFPT_FEATURES_REPLY message
1219 # valid_ports - list of valid port numbers
1220 # valid_queues - list of valid [port, queue] pairs
1221 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1222 # queue_stats - switch's OFPT_STATS_REPLY message, for queue stats request
1223 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1224 # flow_tbl - (test's idea of) switch's flow table
rootf6af1672012-04-06 09:46:29 -07001225
1226 def __init__(self):
Howard Persh8d21c1f2012-04-20 15:57:29 -07001227 self.controller = None
1228 self.sw_features = None
1229 self.valid_ports = []
1230 self.valid_queues = []
1231 self.tbl_stats = None
1232 self.flow_stats = None
1233 self.flow_tbl = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001234 self.error_msgs = []
1235 self.removed_msgs = []
1236
1237 def error_handler(self, controller, msg, rawmsg):
1238 fq_logger.info("Got an ERROR message, type=%d, code=%d" \
1239 % (msg.type, msg.code) \
1240 )
1241 fq_logger.info("Message header:")
1242 fq_logger.info(msg.header.show())
1243 self.error_msgs.append(msg)
1244
1245 def removed_handler(self, controller, msg, rawmsg):
1246 fq_logger.info("Got a REMOVED message")
1247 fq_logger.info("Message header:")
1248 fq_logger.info(msg.header.show())
1249 self.removed_msgs.append(msg)
rootf6af1672012-04-06 09:46:29 -07001250
Howard Persh3340d452012-04-06 16:45:21 -07001251 def controller_set(self, controller):
1252 self.controller = controller
1253 # Register error message handler
Ed Swierk99a74de2012-08-22 06:40:54 -07001254 self.error_msgs = []
1255 self.removed_msgs = []
1256 controller.register(ofp.OFPT_ERROR, self.error_handler)
1257 controller.register(ofp.OFPT_FLOW_REMOVED, self.removed_handler)
Howard Persh3340d452012-04-06 16:45:21 -07001258
rootf6af1672012-04-06 09:46:29 -07001259 def features_get(self):
1260 # Get switch features
1261 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001262 (self.sw_features, pkt) = self.controller.transact(request)
rootf6af1672012-04-06 09:46:29 -07001263 if self.sw_features is None:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001264 fq_logger.error("Get switch features failed")
rootf6af1672012-04-06 09:46:29 -07001265 return False
1266 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001267 fq_logger.info("Ports reported by switch:")
1268 fq_logger.info(self.valid_ports)
1269 ports_override = test_param_get(fq_config, "ports", [])
1270 if ports_override != []:
1271 fq_logger.info("Overriding ports to:")
1272 fq_logger.info(ports_override)
1273 self.valid_ports = ports_override
1274
Howard Persh3340d452012-04-06 16:45:21 -07001275 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1276 # is that universal?
1277
1278 # TBD - There seems to be variability in which switches support which
1279 # ports; need to sort that out
1280 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1281# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1282# ofp.OFPP_NORMAL, \
1283# ofp.OFPP_FLOOD, \
1284# ofp.OFPP_ALL, \
1285# ofp.OFPP_CONTROLLER \
1286# ] \
1287# )
Howard Persh8d21c1f2012-04-20 15:57:29 -07001288 fq_logger.info("Supported actions reported by switch:")
1289 fq_logger.info("0x%x=%s" \
1290 % (self.sw_features.actions, \
1291 actions_bmap_to_str(self.sw_features.actions) \
1292 ) \
1293 )
Howard Persh07d99e62012-04-09 15:26:57 -07001294 actions_override = test_param_get(fq_config, "actions", -1)
1295 if actions_override != -1:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001296 fq_logger.info("Overriding supported actions to:")
1297 fq_logger.info(actions_bmap_to_str(actions_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001298 self.sw_features.actions = actions_override
rootf6af1672012-04-06 09:46:29 -07001299 return True
1300
1301 def tbl_stats_get(self):
1302 # Get table stats
Howard Persh680b92a2012-03-31 13:34:35 -07001303 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001304 (self.tbl_stats, pkt) = self.controller.transact(request)
Howard Persh07d99e62012-04-09 15:26:57 -07001305 if self.tbl_stats is None:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001306 fq_logger.error("Get table stats failed")
Howard Persh07d99e62012-04-09 15:26:57 -07001307 return False
Howard Persh8d21c1f2012-04-20 15:57:29 -07001308 i = 0
Howard Persh07d99e62012-04-09 15:26:57 -07001309 for ts in self.tbl_stats.stats:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001310 fq_logger.info("Supported wildcards for table %d reported by switch:"
1311 % (i)
1312 )
1313 fq_logger.info("0x%x=%s" \
1314 % (ts.wildcards, \
1315 wildcards_to_str(ts.wildcards) \
1316 ) \
1317 )
Howard Persh07d99e62012-04-09 15:26:57 -07001318 wildcards_override = test_param_get(fq_config, "wildcards", -1)
1319 if wildcards_override != -1:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001320 fq_logger.info("Overriding supported wildcards for table %d to:"
1321 % (i)
1322 )
1323 fq_logger.info(wildcards_to_str(wildcards_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001324 ts.wildcards = wildcards_override
Howard Persh8d21c1f2012-04-20 15:57:29 -07001325 i = i + 1
Howard Persh07d99e62012-04-09 15:26:57 -07001326 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001327
Howard Persh8d21c1f2012-04-20 15:57:29 -07001328 def queue_stats_get(self):
1329 # Get queue stats
1330 request = message.queue_stats_request()
1331 request.port_no = ofp.OFPP_ALL
1332 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001333 (self.queue_stats, pkt) = self.controller.transact(request)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001334 if self.queue_stats is None:
1335 fq_logger.error("Get queue stats failed")
1336 return False
1337 self.valid_queues = map(lambda x: (x.port_no, x.queue_id), \
1338 self.queue_stats.stats \
1339 )
1340 fq_logger.info("(Port, queue) pairs reported by switch:")
1341 fq_logger.info(self.valid_queues)
1342 queues_override = test_param_get(fq_config, "queues", [])
1343 if queues_override != []:
1344 fq_logger.info("Overriding (port, queue) pairs to:")
1345 fq_logger.info(queues_override)
1346 self.valid_queues = queues_override
1347 return True
1348
1349 def connect(self, controller):
1350 # Connect to controller, and get all switch capabilities
1351 self.controller_set(controller)
1352 return (self.features_get() \
1353 and self.tbl_stats_get() \
1354 and self.queue_stats_get() \
1355 )
1356
Howard Pershc1199d52012-04-11 14:21:32 -07001357 def flow_stats_get(self, limit = 10000):
rootf6af1672012-04-06 09:46:29 -07001358 request = message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -07001359 query_match = ofp.ofp_match()
1360 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001361 request.match = query_match
1362 request.table_id = 0xff
1363 request.out_port = ofp.OFPP_NONE;
Howard Persh3340d452012-04-06 16:45:21 -07001364 if self.controller.message_send(request) == -1:
1365 return False
1366 # <TBD>
1367 # Glue together successive reponse messages for stats reply.
1368 # Looking at the "more" flag and performing re-assembly
1369 # should be a part of the infrastructure.
1370 # </TBD>
1371 n = 0
1372 while True:
Howard Persh07d99e62012-04-09 15:26:57 -07001373 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY, 4)
Howard Persh3340d452012-04-06 16:45:21 -07001374 if resp is None:
Howard Pershc1199d52012-04-11 14:21:32 -07001375 return False # Did not get expected response
Howard Persh3340d452012-04-06 16:45:21 -07001376 if n == 0:
1377 self.flow_stats = resp
1378 else:
1379 self.flow_stats.stats.extend(resp.stats)
1380 n = n + 1
Howard Pershc1199d52012-04-11 14:21:32 -07001381 if len(self.flow_stats.stats) > limit:
1382 fq_logger.error("Too many flows returned")
1383 return False
1384 if (resp.flags & 1) == 0:
1385 break # No more responses expected
Howard Persh3340d452012-04-06 16:45:21 -07001386 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001387
rootf6af1672012-04-06 09:46:29 -07001388 def flow_add(self, flow_cfg, overlapf = False):
Howard Persh680b92a2012-03-31 13:34:35 -07001389 flow_mod_msg = message.flow_mod()
1390 flow_mod_msg.command = ofp.OFPFC_ADD
1391 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001392 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001393 if overlapf:
1394 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001395 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001396 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Howard Persh07d99e62012-04-09 15:26:57 -07001397 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001398 fq_logger.info("Sending flow_mod(add), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001399 % (flow_mod_msg.header.xid)
1400 )
rootf6af1672012-04-06 09:46:29 -07001401 return (self.controller.message_send(flow_mod_msg) != -1)
Howard Persh680b92a2012-03-31 13:34:35 -07001402
rootf6af1672012-04-06 09:46:29 -07001403 def flow_mod(self, flow_cfg, strictf):
Howard Persh680b92a2012-03-31 13:34:35 -07001404 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001405 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf \
1406 else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -07001407 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001408 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001409 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001410 fq_logger.info("Sending flow_mod(mod), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001411 % (flow_mod_msg.header.xid)
1412 )
rootf6af1672012-04-06 09:46:29 -07001413 return (self.controller.message_send(flow_mod_msg) != -1)
1414
1415 def flow_del(self, flow_cfg, strictf):
1416 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001417 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf \
1418 else ofp.OFPFC_DELETE
rootf6af1672012-04-06 09:46:29 -07001419 flow_mod_msg.buffer_id = 0xffffffff
1420 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001421 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001422 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001423 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001424 fq_logger.info("Sending flow_mod(del), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001425 % (flow_mod_msg.header.xid)
1426 )
rootf6af1672012-04-06 09:46:29 -07001427 return (self.controller.message_send(flow_mod_msg) != -1)
1428
1429 def barrier(self):
1430 barrier = message.barrier_request()
Howard Persh07d99e62012-04-09 15:26:57 -07001431 (resp, pkt) = self.controller.transact(barrier, 20)
rootf6af1672012-04-06 09:46:29 -07001432 return (resp is not None)
1433
Howard Persh3340d452012-04-06 16:45:21 -07001434 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001435 result = True
Howard Persh5f3c83f2012-04-13 09:57:10 -07001436 fq_logger.info("Expecting %d error messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001437 num_got = len(self.error_msgs)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001438 fq_logger.info("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001439 if num_got != num_exp:
Dan Talayco910a8282012-04-07 00:05:20 -07001440 fq_logger.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001441 result = False
1442 if num_exp == 0:
1443 return result
1444 elif num_exp == 1:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001445 fq_logger.info("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001446 % (type, code) \
1447 )
1448 f = False
Ed Swierk99a74de2012-08-22 06:40:54 -07001449 for e in self.error_msgs:
Howard Persh3340d452012-04-06 16:45:21 -07001450 if e.type == type and e.code == code:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001451 fq_logger.info("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001452 f = True
1453 if not f:
Dan Talayco910a8282012-04-07 00:05:20 -07001454 fq_logger.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001455 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001456 else:
Dan Talayco910a8282012-04-07 00:05:20 -07001457 fq_logger.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001458 result = False
1459 return result
1460
Howard Persh3340d452012-04-06 16:45:21 -07001461 def removed_verify(self, num_exp):
1462 result = True
Howard Persh5f3c83f2012-04-13 09:57:10 -07001463 fq_logger.info("Expecting %d removed messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001464 num_got = len(self.removed_msgs)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001465 fq_logger.info("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001466 if num_got != num_exp:
Dan Talayco910a8282012-04-07 00:05:20 -07001467 fq_logger.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001468 result = False
1469 if num_exp < 2:
1470 return result
Dan Talayco910a8282012-04-07 00:05:20 -07001471 fq_logger.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001472 return False
1473
Howard Persh5f3c83f2012-04-13 09:57:10 -07001474 # modf == True <=> Verify for flow modify, else for add/delete
1475 def flow_tbl_verify(self, modf = False):
rootf6af1672012-04-06 09:46:29 -07001476 result = True
1477
1478 # Verify flow count in switch
Howard Persh5f3c83f2012-04-13 09:57:10 -07001479 fq_logger.info("Reading table stats")
1480 fq_logger.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001481 if not self.tbl_stats_get():
Dan Talayco910a8282012-04-07 00:05:20 -07001482 fq_logger.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001483 return False
1484 n = 0
1485 for ts in self.tbl_stats.stats:
1486 n = n + ts.active_count
Howard Persh5f3c83f2012-04-13 09:57:10 -07001487 fq_logger.info("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001488 % (n) \
1489 )
1490 if n != self.flow_tbl.count():
Dan Talayco910a8282012-04-07 00:05:20 -07001491 fq_logger.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001492 result = False
1493
1494 # Read flows from switch
Howard Persh5f3c83f2012-04-13 09:57:10 -07001495 fq_logger.info("Retrieving flows from switch")
1496 fq_logger.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001497 if not self.flow_stats_get():
Dan Talayco910a8282012-04-07 00:05:20 -07001498 fq_logger.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001499 return False
Howard Persh5f3c83f2012-04-13 09:57:10 -07001500 fq_logger.info("Retrieved %d flows" % (len(self.flow_stats.stats)))
rootf6af1672012-04-06 09:46:29 -07001501
1502 # Verify flows returned by switch
1503
1504 if len(self.flow_stats.stats) != self.flow_tbl.count():
Dan Talayco910a8282012-04-07 00:05:20 -07001505 fq_logger.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001506 result = False
1507
Howard Persh5f3c83f2012-04-13 09:57:10 -07001508 fq_logger.info("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001509 for fc in self.flow_tbl.values():
1510 fc.matched = False
1511 for fs in self.flow_stats.stats:
1512 flow_in = Flow_Cfg()
1513 flow_in.from_flow_stat(fs)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001514 fq_logger.info("Received flow:")
1515 fq_logger.info(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001516 fc = self.flow_tbl.find(flow_in)
1517 if fc is None:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001518 fq_logger.error("Received flow:")
1519 fq_logger.error(str(flow_in))
Dan Talayco910a8282012-04-07 00:05:20 -07001520 fq_logger.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001521 result = False
1522 elif fc.matched:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001523 fq_logger.error("Received flow:")
1524 fq_logger.error(str(flow_in))
Dan Talayco910a8282012-04-07 00:05:20 -07001525 fq_logger.error("re-matches defined flow:")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001526 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001527 result = False
1528 else:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001529 fq_logger.info("matched")
1530 if modf:
1531 # Check for modify
1532
1533 if flow_in.cookie != fc.cookie:
1534 fq_logger.warning("Defined flow:")
1535 fq_logger.warning(str(fc))
1536 fq_logger.warning("Received flow:")
1537 fq_logger.warning(str(flow_in))
1538 fq_logger.warning("cookies do not match")
1539 if not flow_in.actions_equal(fc):
1540 fq_logger.error("Defined flow:")
1541 fq_logger.error(str(fc))
1542 fq_logger.error("Received flow:")
1543 fq_logger.error(str(flow_in))
1544 fq_logger.error("actions do not match")
1545 else:
1546 # Check for add/delete
1547
1548 if not flow_in == fc:
1549 fq_logger.error("Defined flow:")
1550 fq_logger.error(str(fc))
1551 fq_logger.error("Received flow:")
1552 fq_logger.error(str(flow_in))
1553 fq_logger.error("non-key portions of flow do not match")
1554 result = False
rootf6af1672012-04-06 09:46:29 -07001555 fc.matched = True
1556 for fc in self.flow_tbl.values():
1557 if not fc.matched:
Dan Talayco910a8282012-04-07 00:05:20 -07001558 fq_logger.error("Defined flow:")
1559 fq_logger.error(str(fc))
1560 fq_logger.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001561 result = False
1562
1563 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001564
Howard Persh07d99e62012-04-09 15:26:57 -07001565# FLOW ADD 5
1566#
1567# OVERVIEW
1568# Add flows to switch, read back and verify flow configurations
1569#
1570# PURPOSE
1571# - Test acceptance of flow adds
1572# - Test ability of switch to process additions to flow table in random
1573# priority order
1574# - Test correctness of flow configuration responses
1575#
1576# PARAMETERS
1577#
1578# Name: num_flows
1579# Type: number
1580# Description:
1581# Number of flows to define; 0 => maximum number of flows, as determined
1582# from switch capabilities
1583# Default: 100
1584#
1585# PROCESS
1586# 1. Delete all flows from switch
1587# 2. Generate <num_flows> distinct flow configurations
1588# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1589# 4. Verify that no OFPT_ERROR responses were generated by switch
1590# 5. Retrieve flow stats from switch
1591# 6. Compare flow configurations returned by switch
1592# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1593# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001594
rootf6af1672012-04-06 09:46:29 -07001595class Flow_Add_5(basic.SimpleProtocol):
1596 """
1597 Test FLOW_ADD_5 from draft top-half test plan
1598
1599 INPUTS
1600 num_flows - Number of flows to generate
1601 """
Howard Persh680b92a2012-03-31 13:34:35 -07001602
rootf6af1672012-04-06 09:46:29 -07001603 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001604 fq_logger.info("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001605
Dan Talayco910a8282012-04-07 00:05:20 -07001606 num_flows = test_param_get(fq_config, "num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001607
Howard Pershc7963582012-03-29 10:02:59 -07001608 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001609
Howard Persh5f3c83f2012-04-13 09:57:10 -07001610 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001611 rc = delete_all_flows(self.controller, fq_logger)
Howard Pershc7963582012-03-29 10:02:59 -07001612 self.assertEqual(rc, 0, "Failed to delete all flows")
1613
rootf6af1672012-04-06 09:46:29 -07001614 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001615
rootf6af1672012-04-06 09:46:29 -07001616 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001617 self.assertTrue(sw.connect(self.controller), \
1618 "Failed to connect to switch" \
1619 )
Howard Pershc7963582012-03-29 10:02:59 -07001620
rootf6af1672012-04-06 09:46:29 -07001621 if num_flows == 0:
1622 # Number of flows requested was 0
1623 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001624
rootf6af1672012-04-06 09:46:29 -07001625 for ts in sw.tbl_stats.stats:
1626 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001627
Howard Persh5f3c83f2012-04-13 09:57:10 -07001628 fq_logger.info("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001629
1630 # Dream up some flow information, i.e. space to chose from for
1631 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001632
rootf6af1672012-04-06 09:46:29 -07001633 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001634 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001635
rootf6af1672012-04-06 09:46:29 -07001636 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001637
rootf6af1672012-04-06 09:46:29 -07001638 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001639 ft.rand(required_wildcards(self), sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001640
rootf6af1672012-04-06 09:46:29 -07001641 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001642
Howard Persh5f3c83f2012-04-13 09:57:10 -07001643 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001644 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07001645 fq_logger.info("Adding flow:")
1646 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001647 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001648
rootf6af1672012-04-06 09:46:29 -07001649 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001650
rootf6af1672012-04-06 09:46:29 -07001651 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001652
rootf6af1672012-04-06 09:46:29 -07001653 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001654
rootf6af1672012-04-06 09:46:29 -07001655 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001656
rootf6af1672012-04-06 09:46:29 -07001657 if not sw.errors_verify(0):
1658 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001659
rootf6af1672012-04-06 09:46:29 -07001660 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001661
rootf6af1672012-04-06 09:46:29 -07001662 sw.flow_tbl = ft
1663 if not sw.flow_tbl_verify():
1664 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001665
rootf6af1672012-04-06 09:46:29 -07001666 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001667 fq_logger.info("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001668
Howard Pershc7963582012-03-29 10:02:59 -07001669
Howard Persh07d99e62012-04-09 15:26:57 -07001670# FLOW ADD 5_1
1671#
1672# OVERVIEW
1673# Verify handling of non-canonical flows
1674#
1675# PURPOSE
1676# - Test that switch detects and correctly responds to a non-canonical flow
1677# definition. A canonical flow is one that satisfies all match qualifier
1678# dependencies; a non-canonical flow is one that does not.
1679#
1680# PARAMETERS
1681# - None
1682#
1683# PROCESS
1684# 1. Delete all flows from switch
1685# 2. Generate 1 flow definition, which is different from its canonicalization
1686# 3. Send flow to switch
1687# 4. Retrieve flow from switch
1688# 5. Compare returned flow to canonical form of defined flow
1689# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1690
1691# Disabled.
1692# Should be DUT dependent.
1693test_prio["Flow_Add_5_1"] = -1
1694
rootf6af1672012-04-06 09:46:29 -07001695class Flow_Add_5_1(basic.SimpleProtocol):
1696 """
1697 Test FLOW_ADD_5.1 from draft top-half test plan
1698
1699 INPUTS
1700 None
1701 """
1702
1703 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001704 fq_logger.info("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001705
Dan Talayco910a8282012-04-07 00:05:20 -07001706 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001707
1708 # Clear all flows from switch
1709
Howard Persh5f3c83f2012-04-13 09:57:10 -07001710 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001711 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001712 self.assertEqual(rc, 0, "Failed to delete all flows")
1713
1714 # Get switch capabilites
1715
rootf6af1672012-04-06 09:46:29 -07001716 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001717 self.assertTrue(sw.connect(self.controller), \
1718 "Failed to connect to switch" \
1719 )
rootf6af1672012-04-06 09:46:29 -07001720
1721 # Dream up some flow information, i.e. space to chose from for
1722 # random flow parameter generation
1723
1724 fi = Flow_Info()
1725 fi.rand(10)
1726
1727 # Dream up a flow config that will be canonicalized by the switch
1728
1729 while True:
1730 fc = Flow_Cfg()
1731 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001732 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07001733 sw.tbl_stats.stats[0].wildcards, \
1734 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001735 sw.valid_ports, \
1736 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001737 )
1738 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001739 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001740 break
1741
1742 ft = Flow_Tbl()
1743 ft.insert(fcc)
1744
1745 # Send it to the switch
1746
Howard Persh5f3c83f2012-04-13 09:57:10 -07001747 fq_logger.info("Sending flow add to switch:")
1748 fq_logger.info(str(fc))
1749 fq_logger.info("should be canonicalized as:")
1750 fq_logger.info(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001751 fc.send_rem = False
1752 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1753
1754 # Do barrier, to make sure all flows are in
1755
1756 self.assertTrue(sw.barrier(), "Barrier failed")
1757
1758 result = True
1759
1760 # Check for any error messages
1761
1762 if not sw.errors_verify(0):
1763 result = False
1764
1765 # Verify flow table
1766
1767 sw.flow_tbl = ft
1768 if not sw.flow_tbl_verify():
1769 result = False
1770
1771 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001772 fq_logger.info("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001773
1774
Howard Persh07d99e62012-04-09 15:26:57 -07001775# FLOW ADD 6
1776#
1777# OVERVIEW
1778# Test flow table capacity
1779#
1780# PURPOSE
1781# - Test switch can accept as many flow definitions as it claims
1782# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1783# - Test that attempting to create flows beyond capacity does not corrupt
1784# flow table
1785#
1786# PARAMETERS
1787# None
1788#
1789# PROCESS
1790# 1. Delete all flows from switch
1791# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1792# to determine flow table size, N
1793# 3. Generate (N + 1) distinct flow configurations
1794# 4. Send N flow adds to switch, for flows generated in step 3 above
1795# 5. Verify flow table in switch
1796# 6. Send one more flow add to switch
1797# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1798# response was generated by switch, for last flow mod sent
1799# 7. Retrieve flow stats from switch
1800# 8. Verify flow table in switch
1801# 9. Test PASSED iff:
1802# - error message received, for correct flow
1803# - last flow definition sent to switch is not in flow table
1804# else test FAILED
1805
Howard Persh3340d452012-04-06 16:45:21 -07001806# Disabled because of bogus capacity reported by OVS.
1807# Should be DUT dependent.
1808test_prio["Flow_Add_6"] = -1
1809
rootf6af1672012-04-06 09:46:29 -07001810class Flow_Add_6(basic.SimpleProtocol):
1811 """
1812 Test FLOW_ADD_6 from draft top-half test plan
1813
1814 INPUTS
1815 num_flows - Number of flows to generate
1816 """
Howard Pershc7963582012-03-29 10:02:59 -07001817
1818 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001819 fq_logger.info("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001820
rootf6af1672012-04-06 09:46:29 -07001821 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001822
Howard Persh5f3c83f2012-04-13 09:57:10 -07001823 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001824 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001825 self.assertEqual(rc, 0, "Failed to delete all flows")
1826
1827 # Get switch capabilites
1828
rootf6af1672012-04-06 09:46:29 -07001829 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001830 self.assertTrue(sw.connect(self.controller), \
1831 "Failed to connect to switch" \
1832 )
rootf6af1672012-04-06 09:46:29 -07001833
root2843d2b2012-04-06 10:27:46 -07001834 num_flows = 0
rootf6af1672012-04-06 09:46:29 -07001835 for ts in sw.tbl_stats.stats:
1836 num_flows = num_flows + ts.max_entries
1837
Howard Persh5f3c83f2012-04-13 09:57:10 -07001838 fq_logger.info("Switch capacity is %d flows" % (num_flows))
1839 fq_logger.info("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001840
1841 # Dream up some flow information, i.e. space to chose from for
1842 # random flow parameter generation
1843
1844 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001845 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001846
1847 # Create a flow table, to switch's capacity
1848
1849 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001850 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07001851
1852 # Send flow table to switch
1853
Howard Persh5f3c83f2012-04-13 09:57:10 -07001854 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001855 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07001856 fq_logger.info("Adding flow:")
1857 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001858 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1859
1860 # Do barrier, to make sure all flows are in
1861
1862 self.assertTrue(sw.barrier(), "Barrier failed")
1863
1864 result = True
1865
1866 # Check for any error messages
1867
1868 if not sw.errors_verify(0):
1869 result = False
1870
1871 # Dream up one more flow
1872
Howard Persh5f3c83f2012-04-13 09:57:10 -07001873 fq_logger.info("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001874 while True:
1875 fc = Flow_Cfg()
1876 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001877 required_wildcards(self), \
Howard Persh07d99e62012-04-09 15:26:57 -07001878 sw.tbl_stats.stats[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001879 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001880 sw.valid_ports, \
1881 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001882 )
1883 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001884 if not ft.find(fc):
1885 break
rootf6af1672012-04-06 09:46:29 -07001886
1887 # Send one-more flow
1888
1889 fc.send_rem = False
Howard Persh5f3c83f2012-04-13 09:57:10 -07001890 fq_logger.info("Sending flow add switch")
1891 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001892 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1893
1894 # Do barrier, to make sure all flows are in
1895
1896 self.assertTrue(sw.barrier(), "Barrier failed")
1897
1898 # Check for expected error message
1899
1900 if not sw.errors_verify(1, \
1901 ofp.OFPET_FLOW_MOD_FAILED, \
1902 ofp.OFPFMFC_ALL_TABLES_FULL \
1903 ):
1904 result = False
1905
1906 # Verify flow table
1907
1908 sw.flow_tbl = ft
1909 if not sw.flow_tbl_verify():
1910 result = False
1911
1912 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001913 fq_logger.info("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001914
1915
Howard Persh07d99e62012-04-09 15:26:57 -07001916# FLOW ADD 7
1917#
1918# OVERVIEW
1919# Test flow redefinition
1920#
1921# PURPOSE
1922# Verify that successive flow adds with same priority and match criteria
1923# overwrite in flow table
1924#
1925# PARAMETERS
1926# None
1927#
1928# PROCESS
1929# 1. Delete all flows from switch
1930# 2. Generate flow definition F1
1931# 3. Generate flow definition F2, with same key (priority and match) as F1,
1932# but with different actions
1933# 4. Send flow adds for F1 and F2 to switch
1934# 5. Verify flow definitions in switch
1935# 6. Test PASSED iff 1 flow returned by switch, matching configuration of F2;
1936# else test FAILED
1937
rootf6af1672012-04-06 09:46:29 -07001938class Flow_Add_7(basic.SimpleProtocol):
1939 """
1940 Test FLOW_ADD_7 from draft top-half test plan
1941
1942 INPUTS
1943 None
1944 """
1945
1946 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001947 fq_logger.info("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001948
1949 # Clear all flows from switch
1950
Howard Persh5f3c83f2012-04-13 09:57:10 -07001951 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001952 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001953 self.assertEqual(rc, 0, "Failed to delete all flows")
1954
1955 # Get switch capabilites
1956
rootf6af1672012-04-06 09:46:29 -07001957 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001958 self.assertTrue(sw.connect(self.controller), \
1959 "Failed to connect to switch" \
1960 )
rootf6af1672012-04-06 09:46:29 -07001961
1962 # Dream up some flow information, i.e. space to chose from for
1963 # random flow parameter generation
1964
1965 fi = Flow_Info()
1966 fi.rand(10)
1967
1968 # Dream up a flow config
1969
1970 fc = Flow_Cfg()
1971 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001972 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07001973 sw.tbl_stats.stats[0].wildcards, \
1974 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001975 sw.valid_ports, \
1976 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001977 )
1978 fc = fc.canonical()
1979
1980 # Send it to the switch
1981
Howard Persh5f3c83f2012-04-13 09:57:10 -07001982 fq_logger.info("Sending flow add to switch:")
1983 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001984 ft = Flow_Tbl()
1985 fc.send_rem = False
1986 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1987 ft.insert(fc)
1988
1989 # Dream up some different actions, with the same flow key
1990
1991 fc2 = copy.deepcopy(fc)
1992 while True:
1993 fc2.rand_mod(fi, \
1994 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001995 sw.valid_ports, \
1996 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001997 )
1998 if fc2 != fc:
1999 break
2000
2001 # Send that to the switch
2002
Howard Persh5f3c83f2012-04-13 09:57:10 -07002003 fq_logger.info("Sending flow add to switch:")
2004 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002005 fc2.send_rem = False
2006 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
2007 ft.insert(fc2)
2008
2009 # Do barrier, to make sure all flows are in
2010
2011 self.assertTrue(sw.barrier(), "Barrier failed")
2012
2013 result = True
2014
2015 # Check for any error messages
2016
2017 if not sw.errors_verify(0):
2018 result = False
2019
2020 # Verify flow table
2021
2022 sw.flow_tbl = ft
2023 if not sw.flow_tbl_verify():
2024 result = False
2025
2026 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002027 fq_logger.info("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002028
2029
Howard Persh07d99e62012-04-09 15:26:57 -07002030# FLOW ADD 8
2031#
2032# OVERVIEW
2033# Add overlapping flows to switch, verify that overlapping flows are rejected
2034#
2035# PURPOSE
2036# - Test detection of overlapping flows by switch
2037# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
2038# - Test rejection of overlapping flows
2039# - Test defining overlapping flows does not corrupt flow table
2040#
2041# PARAMETERS
2042# None
2043#
2044# PROCESS
2045# 1. Delete all flows from switch
2046# 2. Generate flow definition F1
2047# 3. Generate flow definition F2, with key overlapping F1
2048# 4. Send flow add to switch, for F1
2049# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
2050# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
2051# was generated by switch
2052# 7. Verifiy flows configured in swtich
2053# 8. Test PASSED iff:
2054# - error message received, for overlapping flow
2055# - overlapping flow is not in flow table
2056# else test FAILED
2057
rootf6af1672012-04-06 09:46:29 -07002058class Flow_Add_8(basic.SimpleProtocol):
2059 """
2060 Test FLOW_ADD_8 from draft top-half test plan
2061
2062 INPUTS
2063 None
2064 """
2065
2066 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002067 fq_logger.info("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002068
2069 # Clear all flows from switch
2070
Howard Persh5f3c83f2012-04-13 09:57:10 -07002071 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002072 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002073 self.assertEqual(rc, 0, "Failed to delete all flows")
2074
2075 # Get switch capabilites
2076
rootf6af1672012-04-06 09:46:29 -07002077 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002078 self.assertTrue(sw.connect(self.controller), \
2079 "Failed to connect to switch" \
2080 )
rootf6af1672012-04-06 09:46:29 -07002081
2082 # Dream up some flow information, i.e. space to chose from for
2083 # random flow parameter generation
2084
2085 fi = Flow_Info()
2086 fi.rand(10)
2087
2088 # Dream up a flow config, with at least 1 qualifier specified
2089
2090 fc = Flow_Cfg()
2091 while True:
2092 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002093 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002094 sw.tbl_stats.stats[0].wildcards, \
2095 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002096 sw.valid_ports, \
2097 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002098 )
2099 fc = fc.canonical()
2100 if fc.match.wildcards != ofp.OFPFW_ALL:
2101 break
2102
2103 # Send it to the switch
2104
Howard Persh5f3c83f2012-04-13 09:57:10 -07002105 fq_logger.info("Sending flow add to switch:")
2106 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002107 ft = Flow_Tbl()
2108 fc.send_rem = False
2109 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2110 ft.insert(fc)
2111
2112 # Wildcard out one qualifier that was specified, to create an
2113 # overlapping flow
2114
2115 fc2 = copy.deepcopy(fc)
2116 for wi in shuffle(range(len(all_wildcards_list))):
2117 w = all_wildcards_list[wi]
2118 if (fc2.match.wildcards & w) == 0:
2119 break
2120 if w == ofp.OFPFW_NW_SRC_MASK:
2121 w = ofp.OFPFW_NW_SRC_ALL
2122 wn = "OFPFW_NW_SRC"
2123 elif w == ofp.OFPFW_NW_DST_MASK:
2124 w = ofp.OFPFW_NW_DST_ALL
2125 wn = "OFPFW_NW_DST"
2126 else:
2127 wn = all_wildcard_names[w]
Howard Persh5f3c83f2012-04-13 09:57:10 -07002128 fq_logger.info("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07002129 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07002130 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07002131
2132 # Send that to the switch, with overlap checking
2133
Howard Persh5f3c83f2012-04-13 09:57:10 -07002134 fq_logger.info("Sending flow add to switch:")
2135 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002136 fc2.send_rem = False
2137 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
2138
2139 # Do barrier, to make sure all flows are in
2140 self.assertTrue(sw.barrier(), "Barrier failed")
2141
2142 result = True
2143
2144 # Check for expected error message
2145
2146 if not sw.errors_verify(1, \
2147 ofp.OFPET_FLOW_MOD_FAILED, \
2148 ofp.OFPFMFC_OVERLAP \
2149 ):
2150 result = False
2151
2152 # Verify flow table
2153
2154 sw.flow_tbl = ft
2155 if not sw.flow_tbl_verify():
2156 result = False
2157
2158 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002159 fq_logger.info("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002160
2161
Howard Persh07d99e62012-04-09 15:26:57 -07002162# FLOW MODIFY 1
2163#
2164# OVERVIEW
2165# Strict modify of single existing flow
2166#
2167# PURPOSE
2168# - Verify that strict flow modify operates only on specified flow
2169# - Verify that flow is correctly modified
2170#
2171# PARAMETERS
2172# None
2173#
2174# PROCESS
2175# 1. Delete all flows from switch
2176# 2. Generate 1 flow F
2177# 3. Send flow add to switch, for flow F
2178# 4. Generate new action list for flow F, yielding F'
2179# 5. Send strict flow modify to switch, for flow F'
2180# 6. Verify flow table in switch
2181# 7. Test PASSED iff flow returned by switch is F'; else FAILED
2182
rootf6af1672012-04-06 09:46:29 -07002183class Flow_Mod_1(basic.SimpleProtocol):
2184 """
2185 Test FLOW_MOD_1 from draft top-half test plan
2186
2187 INPUTS
2188 None
2189 """
2190
2191 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002192 fq_logger.info("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002193
2194 # Clear all flows from switch
2195
Howard Persh5f3c83f2012-04-13 09:57:10 -07002196 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002197 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002198 self.assertEqual(rc, 0, "Failed to delete all flows")
2199
2200 # Get switch capabilites
2201
rootf6af1672012-04-06 09:46:29 -07002202 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002203 self.assertTrue(sw.connect(self.controller), \
2204 "Failed to connect to switch" \
2205 )
rootf6af1672012-04-06 09:46:29 -07002206
2207 # Dream up some flow information, i.e. space to chose from for
2208 # random flow parameter generation
2209
2210 fi = Flow_Info()
2211 fi.rand(10)
2212
2213 # Dream up a flow config
2214
2215 fc = Flow_Cfg()
2216 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002217 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002218 sw.tbl_stats.stats[0].wildcards, \
2219 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002220 sw.valid_ports, \
2221 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002222 )
2223 fc = fc.canonical()
2224
2225 # Send it to the switch
2226
Howard Persh5f3c83f2012-04-13 09:57:10 -07002227 fq_logger.info("Sending flow add to switch:")
2228 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002229 ft = Flow_Tbl()
2230 fc.send_rem = False
2231 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2232 ft.insert(fc)
2233
2234 # Dream up some different actions, with the same flow key
2235
2236 fc2 = copy.deepcopy(fc)
2237 while True:
2238 fc2.rand_mod(fi, \
2239 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002240 sw.valid_ports, \
2241 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002242 )
2243 if fc2 != fc:
2244 break
2245
2246 # Send that to the switch
2247
Howard Persh5f3c83f2012-04-13 09:57:10 -07002248 fq_logger.info("Sending strict flow mod to switch:")
2249 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002250 fc2.send_rem = False
2251 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2252 ft.insert(fc2)
2253
2254 # Do barrier, to make sure all flows are in
2255
2256 self.assertTrue(sw.barrier(), "Barrier failed")
2257
2258 result = True
2259
2260 # Check for any error messages
2261
2262 if not sw.errors_verify(0):
2263 result = False
2264
2265 # Verify flow table
2266
2267 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002268 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002269 result = False
2270
2271 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002272 fq_logger.info("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002273
Howard Persh07d99e62012-04-09 15:26:57 -07002274
2275# FLOW MODIFY 2
2276#
2277# OVERVIEW
2278# Loose modify of mutiple flows
2279#
2280# PURPOSE
2281# - Verify that loose flow modify operates only on matching flows
2282# - Verify that matching flows are correctly modified
2283#
2284# PARAMETERS
2285# Name: num_flows
2286# Type: number
2287# Description:
2288# Number of flows to define
2289# Default: 100
2290#
2291# PROCESS
2292# 1. Delete all flows from switch
2293# 2. Generate <num_flows> distinct flow configurations
2294# 3. Send <num_flows> flow adds to switch
2295# 4. Pick 1 defined flow F at random
2296# 5. Create overlapping loose flow mod match criteria by repeatedly
2297# wildcarding out qualifiers in match of F => F',
2298# and create new actions list A' for F'
2299# 6. Send loose flow modify for F' to switch
2300# 7. Verify flow table in swtich
2301# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2302# are returned in step 7 above, each with correct (original or modified)
2303# action list;
2304# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002305
2306class Flow_Mod_2(basic.SimpleProtocol):
2307 """
2308 Test FLOW_MOD_2 from draft top-half test plan
2309
2310 INPUTS
2311 None
2312 """
2313
2314 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002315 fq_logger.info("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002316
Dan Talayco910a8282012-04-07 00:05:20 -07002317 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002318
2319 # Clear all flows from switch
2320
Howard Persh5f3c83f2012-04-13 09:57:10 -07002321 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002322 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002323 self.assertEqual(rc, 0, "Failed to delete all flows")
2324
2325 # Get switch capabilites
2326
rootf6af1672012-04-06 09:46:29 -07002327 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002328 self.assertTrue(sw.connect(self.controller), \
2329 "Failed to connect to switch" \
2330 )
rootf6af1672012-04-06 09:46:29 -07002331
2332 # Dream up some flow information, i.e. space to chose from for
2333 # random flow parameter generation
2334
2335 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002336 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002337 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002338
2339 # Dream up some flows
2340
2341 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002342 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002343
2344 # Send flow table to switch
2345
Howard Persh5f3c83f2012-04-13 09:57:10 -07002346 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002347 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07002348 fq_logger.info("Adding flow:")
2349 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002350 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2351
2352 # Do barrier, to make sure all flows are in
2353
2354 self.assertTrue(sw.barrier(), "Barrier failed")
2355
2356 result = True
2357
2358 # Check for any error messages
2359
2360 if not sw.errors_verify(0):
2361 result = False
2362
2363 # Verify flow table
2364
2365 sw.flow_tbl = ft
2366 if not sw.flow_tbl_verify():
2367 result = False
2368
2369 # Pick a random flow as a basis
Howard Persh5f3c83f2012-04-13 09:57:10 -07002370
2371 mfc = copy.deepcopy((ft.values())[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002372 mfc.rand_mod(fi, \
2373 sw.sw_features.actions, \
2374 sw.valid_ports, \
2375 sw.valid_queues \
2376 )
rootf6af1672012-04-06 09:46:29 -07002377
2378 # Repeatedly wildcard qualifiers
2379
2380 for wi in shuffle(range(len(all_wildcards_list))):
2381 w = all_wildcards_list[wi]
2382 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2383 n = wildcard_get(mfc.match.wildcards, w)
2384 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002385 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2386 w, \
2387 random.randint(n + 1, 32) \
2388 )
rootf6af1672012-04-06 09:46:29 -07002389 else:
2390 continue
2391 else:
2392 if wildcard_get(mfc.match.wildcards, w) == 0:
2393 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2394 else:
2395 continue
2396 mfc = mfc.canonical()
2397
2398 # Count the number of flows that would be modified
2399
2400 n = 0
2401 for fc in ft.values():
2402 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2403 n = n + 1
2404
2405 # If more than 1, we found our loose delete flow spec
2406 if n > 1:
2407 break
2408
Howard Persh5f3c83f2012-04-13 09:57:10 -07002409 fq_logger.info("Modifying %d flows" % (n))
2410 fq_logger.info("Sending flow mod to switch:")
2411 fq_logger.info(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002412 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2413
2414 # Do barrier, to make sure all flows are in
2415 self.assertTrue(sw.barrier(), "Barrier failed")
2416
2417 # Check for error message
2418
2419 if not sw.errors_verify(0):
2420 result = False
2421
2422 # Apply flow mod to local flow table
2423
2424 for fc in ft.values():
2425 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002426 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002427
2428 # Verify flow table
2429
2430 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002431 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002432 result = False
2433
2434 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002435 fq_logger.info("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002436
2437
Howard Persh07d99e62012-04-09 15:26:57 -07002438# FLOW MODIFY 3
2439
2440# OVERVIEW
2441# Strict modify of non-existent flow
2442#
2443# PURPOSE
2444# Verify that strict modify of a non-existent flow is equivalent to a flow add
2445#
2446# PARAMETERS
2447# None
2448#
2449# PROCESS
2450# 1. Delete all flows from switch
2451# 2. Send single flow mod, as strict modify, to switch
2452# 3. Verify flow table in switch
2453# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2454
rootf6af1672012-04-06 09:46:29 -07002455class Flow_Mod_3(basic.SimpleProtocol):
2456 """
2457 Test FLOW_MOD_3 from draft top-half test plan
2458
2459 INPUTS
2460 None
2461 """
2462
2463 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002464 fq_logger.info("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002465
2466 # Clear all flows from switch
2467
Howard Persh5f3c83f2012-04-13 09:57:10 -07002468 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002469 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002470 self.assertEqual(rc, 0, "Failed to delete all flows")
2471
2472 # Get switch capabilites
2473
rootf6af1672012-04-06 09:46:29 -07002474 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002475 self.assertTrue(sw.connect(self.controller), \
2476 "Failed to connect to switch" \
2477 )
rootf6af1672012-04-06 09:46:29 -07002478
2479 # Dream up some flow information, i.e. space to chose from for
2480 # random flow parameter generation
2481
2482 fi = Flow_Info()
2483 fi.rand(10)
2484
2485 # Dream up a flow config
2486
2487 fc = Flow_Cfg()
2488 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002489 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002490 sw.tbl_stats.stats[0].wildcards, \
2491 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002492 sw.valid_ports, \
2493 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002494 )
2495 fc = fc.canonical()
2496
2497 # Send it to the switch
2498
Howard Persh5f3c83f2012-04-13 09:57:10 -07002499 fq_logger.info("Sending flow mod to switch:")
2500 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002501 ft = Flow_Tbl()
2502 fc.send_rem = False
2503 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2504 ft.insert(fc)
2505
2506 # Do barrier, to make sure all flows are in
2507
2508 self.assertTrue(sw.barrier(), "Barrier failed")
2509
2510 result = True
2511
2512 # Check for any error messages
2513
2514 if not sw.errors_verify(0):
2515 result = False
2516
2517 # Verify flow table
2518
2519 sw.flow_tbl = ft
2520 if not sw.flow_tbl_verify():
2521 result = False
2522
2523 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002524 fq_logger.info("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002525
2526
Howard Persh8d21c1f2012-04-20 15:57:29 -07002527# FLOW MODIFY 3_1
2528
2529# OVERVIEW
2530# No-op modify
2531#
2532# PURPOSE
2533# Verify that modify of a flow with new actions same as old ones operates correctly
2534#
2535# PARAMETERS
2536# None
2537#
2538# PROCESS
2539# 1. Delete all flows from switch
2540# 2. Send single flow mod, as strict modify, to switch
2541# 3. Verify flow table in switch
2542# 4. Send same flow mod, as strict modify, to switch
2543# 5. Verify flow table in switch
2544# 6. Test PASSED iff flow defined in step 2 and 4 above verified; else FAILED
2545
2546class Flow_Mod_3_1(basic.SimpleProtocol):
2547 """
2548 Test FLOW_MOD_3_1 from draft top-half test plan
2549
2550 INPUTS
2551 None
2552 """
2553
2554 def runTest(self):
2555 fq_logger.info("Flow_Mod_3_1 TEST BEGIN")
2556
2557 # Clear all flows from switch
2558
2559 fq_logger.info("Deleting all flows from switch")
2560 rc = delete_all_flows(self.controller, fq_logger)
2561 self.assertEqual(rc, 0, "Failed to delete all flows")
2562
2563 # Get switch capabilites
2564
2565 sw = Switch()
2566 self.assertTrue(sw.connect(self.controller), \
2567 "Failed to connect to switch" \
2568 )
2569
2570 # Dream up some flow information, i.e. space to chose from for
2571 # random flow parameter generation
2572
2573 fi = Flow_Info()
2574 fi.rand(10)
2575
2576 # Dream up a flow config
2577
2578 fc = Flow_Cfg()
2579 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002580 required_wildcards(self), \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002581 sw.tbl_stats.stats[0].wildcards, \
2582 sw.sw_features.actions, \
2583 sw.valid_ports, \
2584 sw.valid_queues \
2585 )
2586 fc = fc.canonical()
2587
2588 # Send it to the switch
2589
2590 fq_logger.info("Sending flow mod to switch:")
2591 fq_logger.info(str(fc))
2592 ft = Flow_Tbl()
2593 fc.send_rem = False
2594 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2595 ft.insert(fc)
2596
2597 # Do barrier, to make sure all flows are in
2598
2599 self.assertTrue(sw.barrier(), "Barrier failed")
2600
2601 result = True
2602
2603 # Check for any error messages
2604
2605 if not sw.errors_verify(0):
2606 result = False
2607
2608 # Verify flow table
2609
2610 sw.flow_tbl = ft
2611 if not sw.flow_tbl_verify():
2612 result = False
2613
2614 # Send same flow to the switch again
2615
2616 fq_logger.info("Sending flow mod to switch:")
2617 fq_logger.info(str(fc))
2618 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2619
2620 # Do barrier, to make sure all flows are in
2621
2622 self.assertTrue(sw.barrier(), "Barrier failed")
2623
2624 # Check for any error messages
2625
2626 if not sw.errors_verify(0):
2627 result = False
2628
2629 # Verify flow table
2630
2631 if not sw.flow_tbl_verify():
2632 result = False
2633
2634 self.assertTrue(result, "Flow_Mod_3_1 TEST FAILED")
2635 fq_logger.info("Flow_Mod_3_1 TEST PASSED")
2636
2637
Howard Persh07d99e62012-04-09 15:26:57 -07002638# FLOW DELETE 1
2639#
2640# OVERVIEW
2641# Strict delete of single flow
2642#
2643# PURPOSE
2644# Verify correct operation of strict delete of single defined flow
2645#
2646# PARAMETERS
2647# None
2648#
2649# PROCESS
2650# 1. Delete all flows from switch
2651# 2. Send flow F to switch
2652# 3. Send strict flow delete for F to switch
2653# 4. Verify flow table in swtich
2654# 6. Test PASSED iff all flows sent to switch in step 2 above,
2655# less flow removed in step 3 above, are returned in step 4 above;
2656# else test FAILED
2657
rootf6af1672012-04-06 09:46:29 -07002658class Flow_Del_1(basic.SimpleProtocol):
2659 """
2660 Test FLOW_DEL_1 from draft top-half test plan
2661
2662 INPUTS
2663 None
2664 """
2665
2666 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002667 fq_logger.info("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002668
2669 # Clear all flows from switch
2670
Howard Persh5f3c83f2012-04-13 09:57:10 -07002671 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002672 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002673 self.assertEqual(rc, 0, "Failed to delete all flows")
2674
2675 # Get switch capabilites
2676
rootf6af1672012-04-06 09:46:29 -07002677 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002678 self.assertTrue(sw.connect(self.controller), \
2679 "Failed to connect to switch" \
2680 )
rootf6af1672012-04-06 09:46:29 -07002681
2682 # Dream up some flow information, i.e. space to chose from for
2683 # random flow parameter generation
2684
2685 fi = Flow_Info()
2686 fi.rand(10)
2687
2688 # Dream up a flow config
2689
2690 fc = Flow_Cfg()
2691 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002692 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002693 sw.tbl_stats.stats[0].wildcards, \
2694 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002695 sw.valid_ports, \
2696 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002697 )
2698 fc = fc.canonical()
2699
2700 # Send it to the switch
2701
Howard Persh5f3c83f2012-04-13 09:57:10 -07002702 fq_logger.info("Sending flow add to switch:")
2703 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002704 ft = Flow_Tbl()
2705 fc.send_rem = False
2706 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2707 ft.insert(fc)
2708
2709 # Dream up some different actions, with the same flow key
2710
2711 fc2 = copy.deepcopy(fc)
2712 while True:
2713 fc2.rand_mod(fi, \
2714 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002715 sw.valid_ports, \
2716 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002717 )
2718 if fc2 != fc:
2719 break
2720
2721 # Delete strictly
2722
Howard Persh5f3c83f2012-04-13 09:57:10 -07002723 fq_logger.info("Sending strict flow del to switch:")
2724 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002725 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2726 ft.delete(fc)
2727
2728 # Do barrier, to make sure all flows are in
2729
2730 self.assertTrue(sw.barrier(), "Barrier failed")
2731
2732 result = True
2733
2734 # Check for any error messages
2735
2736 if not sw.errors_verify(0):
2737 result = False
2738
2739 # Verify flow table
2740
2741 sw.flow_tbl = ft
2742 if not sw.flow_tbl_verify():
2743 result = False
2744
2745 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002746 fq_logger.info("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002747
2748
Howard Persh07d99e62012-04-09 15:26:57 -07002749# FLOW DELETE 2
2750#
2751# OVERVIEW
2752# Loose delete of multiple flows
2753#
2754# PURPOSE
2755# - Verify correct operation of loose delete of multiple flows
2756#
2757# PARAMETERS
2758# Name: num_flows
2759# Type: number
2760# Description:
2761# Number of flows to define
2762# Default: 100
2763#
2764# PROCESS
2765# 1. Delete all flows from switch
2766# 2. Generate <num_flows> distinct flow configurations
2767# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2768# 4. Pick 1 defined flow F at random
2769# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2770# F' will match more than 1 existing flow key
2771# 6. Send loose flow delete for F' to switch
2772# 7. Verify flow table in switch
2773# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2774# removed in step 6 above (i.e. those that match F'), are returned
2775# in step 7 above;
2776# else test FAILED
2777
rootf6af1672012-04-06 09:46:29 -07002778class Flow_Del_2(basic.SimpleProtocol):
2779 """
2780 Test FLOW_DEL_2 from draft top-half test plan
2781
2782 INPUTS
2783 None
2784 """
2785
2786 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002787 fq_logger.info("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002788
Dan Talayco910a8282012-04-07 00:05:20 -07002789 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002790
2791 # Clear all flows from switch
2792
Howard Persh5f3c83f2012-04-13 09:57:10 -07002793 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002794 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002795 self.assertEqual(rc, 0, "Failed to delete all flows")
2796
2797 # Get switch capabilites
2798
rootf6af1672012-04-06 09:46:29 -07002799 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002800 self.assertTrue(sw.connect(self.controller), \
2801 "Failed to connect to switch" \
2802 )
rootf6af1672012-04-06 09:46:29 -07002803
2804 # Dream up some flow information, i.e. space to chose from for
2805 # random flow parameter generation
2806
2807 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002808 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002809 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002810
2811 # Dream up some flows
2812
2813 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002814 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002815
2816 # Send flow table to switch
2817
Howard Persh5f3c83f2012-04-13 09:57:10 -07002818 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002819 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07002820 fq_logger.info("Adding flow:")
2821 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002822 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2823
2824 # Do barrier, to make sure all flows are in
2825
2826 self.assertTrue(sw.barrier(), "Barrier failed")
2827
2828 result = True
2829
2830 # Check for any error messages
2831
2832 if not sw.errors_verify(0):
2833 result = False
2834
2835 # Verify flow table
2836
2837 sw.flow_tbl = ft
2838 if not sw.flow_tbl_verify():
2839 result = False
2840
2841 # Pick a random flow as a basis
2842
2843 dfc = copy.deepcopy(ft.values()[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002844 dfc.rand_mod(fi, \
2845 sw.sw_features.actions, \
2846 sw.valid_ports, \
2847 sw.valid_queues \
2848 )
rootf6af1672012-04-06 09:46:29 -07002849
2850 # Repeatedly wildcard qualifiers
2851
2852 for wi in shuffle(range(len(all_wildcards_list))):
2853 w = all_wildcards_list[wi]
2854 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2855 n = wildcard_get(dfc.match.wildcards, w)
2856 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002857 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2858 w, \
2859 random.randint(n + 1, 32) \
2860 )
rootf6af1672012-04-06 09:46:29 -07002861 else:
2862 continue
2863 else:
2864 if wildcard_get(dfc.match.wildcards, w) == 0:
2865 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2866 else:
2867 continue
2868 dfc = dfc.canonical()
2869
2870 # Count the number of flows that would be deleted
2871
2872 n = 0
2873 for fc in ft.values():
2874 if dfc.overlaps(fc, True):
2875 n = n + 1
2876
2877 # If more than 1, we found our loose delete flow spec
2878 if n > 1:
2879 break
2880
Howard Persh5f3c83f2012-04-13 09:57:10 -07002881 fq_logger.info("Deleting %d flows" % (n))
2882 fq_logger.info("Sending flow del to switch:")
2883 fq_logger.info(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002884 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2885
2886 # Do barrier, to make sure all flows are in
2887 self.assertTrue(sw.barrier(), "Barrier failed")
2888
2889 # Check for error message
2890
2891 if not sw.errors_verify(0):
2892 result = False
2893
2894 # Apply flow mod to local flow table
2895
2896 for fc in ft.values():
2897 if dfc.overlaps(fc, True):
2898 ft.delete(fc)
2899
2900 # Verify flow table
2901
2902 sw.flow_tbl = ft
2903 if not sw.flow_tbl_verify():
2904 result = False
2905
2906 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002907 fq_logger.info("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002908
2909
Howard Persh07d99e62012-04-09 15:26:57 -07002910# FLOW DELETE 4
2911#
2912# OVERVIEW
2913# Flow removed messages
2914#
2915# PURPOSE
2916# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2917# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2918#
2919# PARAMETERS
2920# None
2921#
2922# PROCESS
2923# 1. Delete all flows from switch
2924# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2925# 3. Send strict flow delete of flow to switch
2926# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2927# 5. Verify flow table in switch
2928# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2929# removed in step 3 above, are returned in step 5 above, and that
2930# asynch message was received; else test FAILED
2931
2932
rootf6af1672012-04-06 09:46:29 -07002933class Flow_Del_4(basic.SimpleProtocol):
2934 """
2935 Test FLOW_DEL_4 from draft top-half test plan
2936
2937 INPUTS
2938 None
2939 """
2940
2941 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002942 fq_logger.info("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002943
2944 # Clear all flows from switch
2945
Howard Persh5f3c83f2012-04-13 09:57:10 -07002946 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002947 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002948 self.assertEqual(rc, 0, "Failed to delete all flows")
2949
2950 # Get switch capabilites
2951
rootf6af1672012-04-06 09:46:29 -07002952 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002953 self.assertTrue(sw.connect(self.controller), \
2954 "Failed to connect to switch" \
2955 )
rootf6af1672012-04-06 09:46:29 -07002956
2957 # Dream up some flow information, i.e. space to chose from for
2958 # random flow parameter generation
2959
2960 fi = Flow_Info()
2961 fi.rand(10)
2962
2963 # Dream up a flow config
2964
2965 fc = Flow_Cfg()
2966 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002967 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002968 sw.tbl_stats.stats[0].wildcards, \
2969 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002970 sw.valid_ports, \
2971 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002972 )
2973 fc = fc.canonical()
2974
2975 # Send it to the switch. with "notify on removed"
2976
Howard Persh5f3c83f2012-04-13 09:57:10 -07002977 fq_logger.info("Sending flow add to switch:")
2978 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002979 ft = Flow_Tbl()
2980 fc.send_rem = True
2981 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2982 ft.insert(fc)
2983
2984 # Dream up some different actions, with the same flow key
2985
2986 fc2 = copy.deepcopy(fc)
2987 while True:
2988 fc2.rand_mod(fi, \
2989 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002990 sw.valid_ports, \
2991 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002992 )
2993 if fc2 != fc:
2994 break
2995
2996 # Delete strictly
2997
Howard Persh5f3c83f2012-04-13 09:57:10 -07002998 fq_logger.info("Sending strict flow del to switch:")
2999 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07003000 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
3001 ft.delete(fc)
3002
3003 # Do barrier, to make sure all flows are in
3004
3005 self.assertTrue(sw.barrier(), "Barrier failed")
3006
3007 result = True
3008
3009 # Check for expected "removed" message
3010
Howard Persh3340d452012-04-06 16:45:21 -07003011 if not sw.errors_verify(0):
3012 result = False
3013
3014 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07003015 result = False
3016
3017 # Verify flow table
3018
3019 sw.flow_tbl = ft
3020 if not sw.flow_tbl_verify():
3021 result = False
3022
3023 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07003024 fq_logger.info("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07003025