blob: 7c049286bebc255e23ccb6263d4e4023ebd80690 [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
Howard Persh8d21c1f2012-04-20 15:57:29 -0700726 def rand(self, fi, valid_wildcards, valid_actions, valid_ports, valid_queues):
Howard Pershc1199d52012-04-11 14:21:32 -0700727 wildcards_force = test_param_get(fq_config, "wildcards_force", 0)
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
1189 def rand(self, sw, fi, num_flows):
1190 self.clear()
1191 i = 0
1192 tbl = 0
1193 j = 0
1194 while i < num_flows:
1195 fc = Flow_Cfg()
1196 fc.rand(fi, \
1197 sw.tbl_stats.stats[tbl].wildcards, \
1198 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001199 sw.valid_ports, \
1200 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001201 )
1202 fc = fc.canonical()
1203 if self.find(fc):
1204 continue
1205 fc.send_rem = False
1206 self.insert(fc)
1207 i = i + 1
1208 j = j + 1
1209 if j >= sw.tbl_stats.stats[tbl].max_entries:
1210 tbl = tbl + 1
1211 j = 0
1212
1213
Howard Persh3340d452012-04-06 16:45:21 -07001214error_msgs = []
1215removed_msgs = []
1216
1217def error_handler(self, msg, rawmsg):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001218 fq_logger.info("Got an ERROR message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001219 % (msg.type, msg.code) \
1220 )
Howard Persh5f3c83f2012-04-13 09:57:10 -07001221 fq_logger.info("Message header:")
1222 fq_logger.info(msg.header.show())
Howard Persh3340d452012-04-06 16:45:21 -07001223 global error_msgs
1224 error_msgs.append(msg)
1225 pass
1226
1227def removed_handler(self, msg, rawmsg):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001228 fq_logger.info("Got a REMOVED message")
1229 fq_logger.info("Message header:")
1230 fq_logger.info(msg.header.show())
Howard Persh3340d452012-04-06 16:45:21 -07001231 global removed_msgs
1232 removed_msgs.append(msg)
1233 pass
1234
rootf6af1672012-04-06 09:46:29 -07001235class Switch:
1236 # Members:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001237 # controller - switch's test controller
1238 # sw_features - switch's OFPT_FEATURES_REPLY message
1239 # valid_ports - list of valid port numbers
1240 # valid_queues - list of valid [port, queue] pairs
1241 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1242 # queue_stats - switch's OFPT_STATS_REPLY message, for queue stats request
1243 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1244 # flow_tbl - (test's idea of) switch's flow table
rootf6af1672012-04-06 09:46:29 -07001245
1246 def __init__(self):
Howard Persh8d21c1f2012-04-20 15:57:29 -07001247 self.controller = None
1248 self.sw_features = None
1249 self.valid_ports = []
1250 self.valid_queues = []
1251 self.tbl_stats = None
1252 self.flow_stats = None
1253 self.flow_tbl = Flow_Tbl()
rootf6af1672012-04-06 09:46:29 -07001254
Howard Persh3340d452012-04-06 16:45:21 -07001255 def controller_set(self, controller):
1256 self.controller = controller
1257 # Register error message handler
1258 global error_msgs
1259 error_msgs = []
1260 controller.register(ofp.OFPT_ERROR, error_handler)
1261 controller.register(ofp.OFPT_FLOW_REMOVED, removed_handler)
1262
rootf6af1672012-04-06 09:46:29 -07001263 def features_get(self):
1264 # Get switch features
1265 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001266 (self.sw_features, pkt) = self.controller.transact(request)
rootf6af1672012-04-06 09:46:29 -07001267 if self.sw_features is None:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001268 fq_logger.error("Get switch features failed")
rootf6af1672012-04-06 09:46:29 -07001269 return False
1270 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001271 fq_logger.info("Ports reported by switch:")
1272 fq_logger.info(self.valid_ports)
1273 ports_override = test_param_get(fq_config, "ports", [])
1274 if ports_override != []:
1275 fq_logger.info("Overriding ports to:")
1276 fq_logger.info(ports_override)
1277 self.valid_ports = ports_override
1278
Howard Persh3340d452012-04-06 16:45:21 -07001279 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1280 # is that universal?
1281
1282 # TBD - There seems to be variability in which switches support which
1283 # ports; need to sort that out
1284 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1285# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1286# ofp.OFPP_NORMAL, \
1287# ofp.OFPP_FLOOD, \
1288# ofp.OFPP_ALL, \
1289# ofp.OFPP_CONTROLLER \
1290# ] \
1291# )
Howard Persh8d21c1f2012-04-20 15:57:29 -07001292 fq_logger.info("Supported actions reported by switch:")
1293 fq_logger.info("0x%x=%s" \
1294 % (self.sw_features.actions, \
1295 actions_bmap_to_str(self.sw_features.actions) \
1296 ) \
1297 )
Howard Persh07d99e62012-04-09 15:26:57 -07001298 actions_override = test_param_get(fq_config, "actions", -1)
1299 if actions_override != -1:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001300 fq_logger.info("Overriding supported actions to:")
1301 fq_logger.info(actions_bmap_to_str(actions_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001302 self.sw_features.actions = actions_override
rootf6af1672012-04-06 09:46:29 -07001303 return True
1304
1305 def tbl_stats_get(self):
1306 # Get table stats
Howard Persh680b92a2012-03-31 13:34:35 -07001307 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001308 (self.tbl_stats, pkt) = self.controller.transact(request)
Howard Persh07d99e62012-04-09 15:26:57 -07001309 if self.tbl_stats is None:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001310 fq_logger.error("Get table stats failed")
Howard Persh07d99e62012-04-09 15:26:57 -07001311 return False
Howard Persh8d21c1f2012-04-20 15:57:29 -07001312 i = 0
Howard Persh07d99e62012-04-09 15:26:57 -07001313 for ts in self.tbl_stats.stats:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001314 fq_logger.info("Supported wildcards for table %d reported by switch:"
1315 % (i)
1316 )
1317 fq_logger.info("0x%x=%s" \
1318 % (ts.wildcards, \
1319 wildcards_to_str(ts.wildcards) \
1320 ) \
1321 )
Howard Persh07d99e62012-04-09 15:26:57 -07001322 wildcards_override = test_param_get(fq_config, "wildcards", -1)
1323 if wildcards_override != -1:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001324 fq_logger.info("Overriding supported wildcards for table %d to:"
1325 % (i)
1326 )
1327 fq_logger.info(wildcards_to_str(wildcards_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001328 ts.wildcards = wildcards_override
Howard Persh8d21c1f2012-04-20 15:57:29 -07001329 i = i + 1
Howard Persh07d99e62012-04-09 15:26:57 -07001330 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001331
Howard Persh8d21c1f2012-04-20 15:57:29 -07001332 def queue_stats_get(self):
1333 # Get queue stats
1334 request = message.queue_stats_request()
1335 request.port_no = ofp.OFPP_ALL
1336 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001337 (self.queue_stats, pkt) = self.controller.transact(request)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001338 if self.queue_stats is None:
1339 fq_logger.error("Get queue stats failed")
1340 return False
1341 self.valid_queues = map(lambda x: (x.port_no, x.queue_id), \
1342 self.queue_stats.stats \
1343 )
1344 fq_logger.info("(Port, queue) pairs reported by switch:")
1345 fq_logger.info(self.valid_queues)
1346 queues_override = test_param_get(fq_config, "queues", [])
1347 if queues_override != []:
1348 fq_logger.info("Overriding (port, queue) pairs to:")
1349 fq_logger.info(queues_override)
1350 self.valid_queues = queues_override
1351 return True
1352
1353 def connect(self, controller):
1354 # Connect to controller, and get all switch capabilities
1355 self.controller_set(controller)
1356 return (self.features_get() \
1357 and self.tbl_stats_get() \
1358 and self.queue_stats_get() \
1359 )
1360
Howard Pershc1199d52012-04-11 14:21:32 -07001361 def flow_stats_get(self, limit = 10000):
rootf6af1672012-04-06 09:46:29 -07001362 request = message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -07001363 query_match = ofp.ofp_match()
1364 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001365 request.match = query_match
1366 request.table_id = 0xff
1367 request.out_port = ofp.OFPP_NONE;
Howard Persh3340d452012-04-06 16:45:21 -07001368 if self.controller.message_send(request) == -1:
1369 return False
1370 # <TBD>
1371 # Glue together successive reponse messages for stats reply.
1372 # Looking at the "more" flag and performing re-assembly
1373 # should be a part of the infrastructure.
1374 # </TBD>
1375 n = 0
1376 while True:
Howard Persh07d99e62012-04-09 15:26:57 -07001377 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY, 4)
Howard Persh3340d452012-04-06 16:45:21 -07001378 if resp is None:
Howard Pershc1199d52012-04-11 14:21:32 -07001379 return False # Did not get expected response
Howard Persh3340d452012-04-06 16:45:21 -07001380 if n == 0:
1381 self.flow_stats = resp
1382 else:
1383 self.flow_stats.stats.extend(resp.stats)
1384 n = n + 1
Howard Pershc1199d52012-04-11 14:21:32 -07001385 if len(self.flow_stats.stats) > limit:
1386 fq_logger.error("Too many flows returned")
1387 return False
1388 if (resp.flags & 1) == 0:
1389 break # No more responses expected
Howard Persh3340d452012-04-06 16:45:21 -07001390 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001391
rootf6af1672012-04-06 09:46:29 -07001392 def flow_add(self, flow_cfg, overlapf = False):
Howard Persh680b92a2012-03-31 13:34:35 -07001393 flow_mod_msg = message.flow_mod()
1394 flow_mod_msg.command = ofp.OFPFC_ADD
1395 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001396 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001397 if overlapf:
1398 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001399 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001400 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Howard Persh07d99e62012-04-09 15:26:57 -07001401 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001402 fq_logger.info("Sending flow_mod(add), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001403 % (flow_mod_msg.header.xid)
1404 )
rootf6af1672012-04-06 09:46:29 -07001405 return (self.controller.message_send(flow_mod_msg) != -1)
Howard Persh680b92a2012-03-31 13:34:35 -07001406
rootf6af1672012-04-06 09:46:29 -07001407 def flow_mod(self, flow_cfg, strictf):
Howard Persh680b92a2012-03-31 13:34:35 -07001408 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001409 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf \
1410 else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -07001411 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001412 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001413 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001414 fq_logger.info("Sending flow_mod(mod), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001415 % (flow_mod_msg.header.xid)
1416 )
rootf6af1672012-04-06 09:46:29 -07001417 return (self.controller.message_send(flow_mod_msg) != -1)
1418
1419 def flow_del(self, flow_cfg, strictf):
1420 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001421 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf \
1422 else ofp.OFPFC_DELETE
rootf6af1672012-04-06 09:46:29 -07001423 flow_mod_msg.buffer_id = 0xffffffff
1424 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001425 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001426 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001427 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001428 fq_logger.info("Sending flow_mod(del), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001429 % (flow_mod_msg.header.xid)
1430 )
rootf6af1672012-04-06 09:46:29 -07001431 return (self.controller.message_send(flow_mod_msg) != -1)
1432
1433 def barrier(self):
1434 barrier = message.barrier_request()
Howard Persh07d99e62012-04-09 15:26:57 -07001435 (resp, pkt) = self.controller.transact(barrier, 20)
rootf6af1672012-04-06 09:46:29 -07001436 return (resp is not None)
1437
Howard Persh3340d452012-04-06 16:45:21 -07001438 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001439 result = True
Howard Persh3340d452012-04-06 16:45:21 -07001440 global error_msgs
Howard Persh5f3c83f2012-04-13 09:57:10 -07001441 fq_logger.info("Expecting %d error messages" % (num_exp))
Howard Persh3340d452012-04-06 16:45:21 -07001442 num_got = len(error_msgs)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001443 fq_logger.info("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001444 if num_got != num_exp:
Dan Talayco910a8282012-04-07 00:05:20 -07001445 fq_logger.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001446 result = False
1447 if num_exp == 0:
1448 return result
1449 elif num_exp == 1:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001450 fq_logger.info("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001451 % (type, code) \
1452 )
1453 f = False
1454 for e in error_msgs:
1455 if e.type == type and e.code == code:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001456 fq_logger.info("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001457 f = True
1458 if not f:
Dan Talayco910a8282012-04-07 00:05:20 -07001459 fq_logger.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001460 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001461 else:
Dan Talayco910a8282012-04-07 00:05:20 -07001462 fq_logger.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001463 result = False
1464 return result
1465
Howard Persh3340d452012-04-06 16:45:21 -07001466 def removed_verify(self, num_exp):
1467 result = True
1468 global removed_msgs
Howard Persh5f3c83f2012-04-13 09:57:10 -07001469 fq_logger.info("Expecting %d removed messages" % (num_exp))
Howard Persh3340d452012-04-06 16:45:21 -07001470 num_got = len(removed_msgs)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001471 fq_logger.info("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001472 if num_got != num_exp:
Dan Talayco910a8282012-04-07 00:05:20 -07001473 fq_logger.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001474 result = False
1475 if num_exp < 2:
1476 return result
Dan Talayco910a8282012-04-07 00:05:20 -07001477 fq_logger.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001478 return False
1479
Howard Persh5f3c83f2012-04-13 09:57:10 -07001480 # modf == True <=> Verify for flow modify, else for add/delete
1481 def flow_tbl_verify(self, modf = False):
rootf6af1672012-04-06 09:46:29 -07001482 result = True
1483
1484 # Verify flow count in switch
Howard Persh5f3c83f2012-04-13 09:57:10 -07001485 fq_logger.info("Reading table stats")
1486 fq_logger.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001487 if not self.tbl_stats_get():
Dan Talayco910a8282012-04-07 00:05:20 -07001488 fq_logger.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001489 return False
1490 n = 0
1491 for ts in self.tbl_stats.stats:
1492 n = n + ts.active_count
Howard Persh5f3c83f2012-04-13 09:57:10 -07001493 fq_logger.info("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001494 % (n) \
1495 )
1496 if n != self.flow_tbl.count():
Dan Talayco910a8282012-04-07 00:05:20 -07001497 fq_logger.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001498 result = False
1499
1500 # Read flows from switch
Howard Persh5f3c83f2012-04-13 09:57:10 -07001501 fq_logger.info("Retrieving flows from switch")
1502 fq_logger.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001503 if not self.flow_stats_get():
Dan Talayco910a8282012-04-07 00:05:20 -07001504 fq_logger.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001505 return False
Howard Persh5f3c83f2012-04-13 09:57:10 -07001506 fq_logger.info("Retrieved %d flows" % (len(self.flow_stats.stats)))
rootf6af1672012-04-06 09:46:29 -07001507
1508 # Verify flows returned by switch
1509
1510 if len(self.flow_stats.stats) != self.flow_tbl.count():
Dan Talayco910a8282012-04-07 00:05:20 -07001511 fq_logger.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001512 result = False
1513
Howard Persh5f3c83f2012-04-13 09:57:10 -07001514 fq_logger.info("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001515 for fc in self.flow_tbl.values():
1516 fc.matched = False
1517 for fs in self.flow_stats.stats:
1518 flow_in = Flow_Cfg()
1519 flow_in.from_flow_stat(fs)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001520 fq_logger.info("Received flow:")
1521 fq_logger.info(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001522 fc = self.flow_tbl.find(flow_in)
1523 if fc is None:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001524 fq_logger.error("Received flow:")
1525 fq_logger.error(str(flow_in))
Dan Talayco910a8282012-04-07 00:05:20 -07001526 fq_logger.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001527 result = False
1528 elif fc.matched:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001529 fq_logger.error("Received flow:")
1530 fq_logger.error(str(flow_in))
Dan Talayco910a8282012-04-07 00:05:20 -07001531 fq_logger.error("re-matches defined flow:")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001532 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001533 result = False
1534 else:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001535 fq_logger.info("matched")
1536 if modf:
1537 # Check for modify
1538
1539 if flow_in.cookie != fc.cookie:
1540 fq_logger.warning("Defined flow:")
1541 fq_logger.warning(str(fc))
1542 fq_logger.warning("Received flow:")
1543 fq_logger.warning(str(flow_in))
1544 fq_logger.warning("cookies do not match")
1545 if not flow_in.actions_equal(fc):
1546 fq_logger.error("Defined flow:")
1547 fq_logger.error(str(fc))
1548 fq_logger.error("Received flow:")
1549 fq_logger.error(str(flow_in))
1550 fq_logger.error("actions do not match")
1551 else:
1552 # Check for add/delete
1553
1554 if not flow_in == fc:
1555 fq_logger.error("Defined flow:")
1556 fq_logger.error(str(fc))
1557 fq_logger.error("Received flow:")
1558 fq_logger.error(str(flow_in))
1559 fq_logger.error("non-key portions of flow do not match")
1560 result = False
rootf6af1672012-04-06 09:46:29 -07001561 fc.matched = True
1562 for fc in self.flow_tbl.values():
1563 if not fc.matched:
Dan Talayco910a8282012-04-07 00:05:20 -07001564 fq_logger.error("Defined flow:")
1565 fq_logger.error(str(fc))
1566 fq_logger.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001567 result = False
1568
1569 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001570
Howard Persh07d99e62012-04-09 15:26:57 -07001571# FLOW ADD 5
1572#
1573# OVERVIEW
1574# Add flows to switch, read back and verify flow configurations
1575#
1576# PURPOSE
1577# - Test acceptance of flow adds
1578# - Test ability of switch to process additions to flow table in random
1579# priority order
1580# - Test correctness of flow configuration responses
1581#
1582# PARAMETERS
1583#
1584# Name: num_flows
1585# Type: number
1586# Description:
1587# Number of flows to define; 0 => maximum number of flows, as determined
1588# from switch capabilities
1589# Default: 100
1590#
1591# PROCESS
1592# 1. Delete all flows from switch
1593# 2. Generate <num_flows> distinct flow configurations
1594# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1595# 4. Verify that no OFPT_ERROR responses were generated by switch
1596# 5. Retrieve flow stats from switch
1597# 6. Compare flow configurations returned by switch
1598# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1599# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001600
rootf6af1672012-04-06 09:46:29 -07001601class Flow_Add_5(basic.SimpleProtocol):
1602 """
1603 Test FLOW_ADD_5 from draft top-half test plan
1604
1605 INPUTS
1606 num_flows - Number of flows to generate
1607 """
Howard Persh680b92a2012-03-31 13:34:35 -07001608
rootf6af1672012-04-06 09:46:29 -07001609 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001610 fq_logger.info("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001611
Dan Talayco910a8282012-04-07 00:05:20 -07001612 num_flows = test_param_get(fq_config, "num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001613
Howard Pershc7963582012-03-29 10:02:59 -07001614 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001615
Howard Persh5f3c83f2012-04-13 09:57:10 -07001616 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001617 rc = delete_all_flows(self.controller, fq_logger)
Howard Pershc7963582012-03-29 10:02:59 -07001618 self.assertEqual(rc, 0, "Failed to delete all flows")
1619
rootf6af1672012-04-06 09:46:29 -07001620 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001621
rootf6af1672012-04-06 09:46:29 -07001622 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001623 self.assertTrue(sw.connect(self.controller), \
1624 "Failed to connect to switch" \
1625 )
Howard Pershc7963582012-03-29 10:02:59 -07001626
rootf6af1672012-04-06 09:46:29 -07001627 if num_flows == 0:
1628 # Number of flows requested was 0
1629 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001630
rootf6af1672012-04-06 09:46:29 -07001631 for ts in sw.tbl_stats.stats:
1632 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001633
Howard Persh5f3c83f2012-04-13 09:57:10 -07001634 fq_logger.info("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001635
1636 # Dream up some flow information, i.e. space to chose from for
1637 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001638
rootf6af1672012-04-06 09:46:29 -07001639 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001640 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001641
rootf6af1672012-04-06 09:46:29 -07001642 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001643
rootf6af1672012-04-06 09:46:29 -07001644 ft = Flow_Tbl()
1645 ft.rand(sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001646
rootf6af1672012-04-06 09:46:29 -07001647 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001648
Howard Persh5f3c83f2012-04-13 09:57:10 -07001649 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001650 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07001651 fq_logger.info("Adding flow:")
1652 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001653 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001654
rootf6af1672012-04-06 09:46:29 -07001655 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001656
rootf6af1672012-04-06 09:46:29 -07001657 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001658
rootf6af1672012-04-06 09:46:29 -07001659 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001660
rootf6af1672012-04-06 09:46:29 -07001661 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001662
rootf6af1672012-04-06 09:46:29 -07001663 if not sw.errors_verify(0):
1664 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001665
rootf6af1672012-04-06 09:46:29 -07001666 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001667
rootf6af1672012-04-06 09:46:29 -07001668 sw.flow_tbl = ft
1669 if not sw.flow_tbl_verify():
1670 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001671
rootf6af1672012-04-06 09:46:29 -07001672 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001673 fq_logger.info("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001674
Howard Pershc7963582012-03-29 10:02:59 -07001675
Howard Persh07d99e62012-04-09 15:26:57 -07001676# FLOW ADD 5_1
1677#
1678# OVERVIEW
1679# Verify handling of non-canonical flows
1680#
1681# PURPOSE
1682# - Test that switch detects and correctly responds to a non-canonical flow
1683# definition. A canonical flow is one that satisfies all match qualifier
1684# dependencies; a non-canonical flow is one that does not.
1685#
1686# PARAMETERS
1687# - None
1688#
1689# PROCESS
1690# 1. Delete all flows from switch
1691# 2. Generate 1 flow definition, which is different from its canonicalization
1692# 3. Send flow to switch
1693# 4. Retrieve flow from switch
1694# 5. Compare returned flow to canonical form of defined flow
1695# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1696
1697# Disabled.
1698# Should be DUT dependent.
1699test_prio["Flow_Add_5_1"] = -1
1700
rootf6af1672012-04-06 09:46:29 -07001701class Flow_Add_5_1(basic.SimpleProtocol):
1702 """
1703 Test FLOW_ADD_5.1 from draft top-half test plan
1704
1705 INPUTS
1706 None
1707 """
1708
1709 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001710 fq_logger.info("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001711
Dan Talayco910a8282012-04-07 00:05:20 -07001712 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001713
1714 # Clear all flows from switch
1715
Howard Persh5f3c83f2012-04-13 09:57:10 -07001716 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001717 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001718 self.assertEqual(rc, 0, "Failed to delete all flows")
1719
1720 # Get switch capabilites
1721
rootf6af1672012-04-06 09:46:29 -07001722 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001723 self.assertTrue(sw.connect(self.controller), \
1724 "Failed to connect to switch" \
1725 )
rootf6af1672012-04-06 09:46:29 -07001726
1727 # Dream up some flow information, i.e. space to chose from for
1728 # random flow parameter generation
1729
1730 fi = Flow_Info()
1731 fi.rand(10)
1732
1733 # Dream up a flow config that will be canonicalized by the switch
1734
1735 while True:
1736 fc = Flow_Cfg()
1737 fc.rand(fi, \
1738 sw.tbl_stats.stats[0].wildcards, \
1739 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001740 sw.valid_ports, \
1741 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001742 )
1743 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001744 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001745 break
1746
1747 ft = Flow_Tbl()
1748 ft.insert(fcc)
1749
1750 # Send it to the switch
1751
Howard Persh5f3c83f2012-04-13 09:57:10 -07001752 fq_logger.info("Sending flow add to switch:")
1753 fq_logger.info(str(fc))
1754 fq_logger.info("should be canonicalized as:")
1755 fq_logger.info(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001756 fc.send_rem = False
1757 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1758
1759 # Do barrier, to make sure all flows are in
1760
1761 self.assertTrue(sw.barrier(), "Barrier failed")
1762
1763 result = True
1764
1765 # Check for any error messages
1766
1767 if not sw.errors_verify(0):
1768 result = False
1769
1770 # Verify flow table
1771
1772 sw.flow_tbl = ft
1773 if not sw.flow_tbl_verify():
1774 result = False
1775
1776 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001777 fq_logger.info("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001778
1779
Howard Persh07d99e62012-04-09 15:26:57 -07001780# FLOW ADD 6
1781#
1782# OVERVIEW
1783# Test flow table capacity
1784#
1785# PURPOSE
1786# - Test switch can accept as many flow definitions as it claims
1787# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1788# - Test that attempting to create flows beyond capacity does not corrupt
1789# flow table
1790#
1791# PARAMETERS
1792# None
1793#
1794# PROCESS
1795# 1. Delete all flows from switch
1796# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1797# to determine flow table size, N
1798# 3. Generate (N + 1) distinct flow configurations
1799# 4. Send N flow adds to switch, for flows generated in step 3 above
1800# 5. Verify flow table in switch
1801# 6. Send one more flow add to switch
1802# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1803# response was generated by switch, for last flow mod sent
1804# 7. Retrieve flow stats from switch
1805# 8. Verify flow table in switch
1806# 9. Test PASSED iff:
1807# - error message received, for correct flow
1808# - last flow definition sent to switch is not in flow table
1809# else test FAILED
1810
Howard Persh3340d452012-04-06 16:45:21 -07001811# Disabled because of bogus capacity reported by OVS.
1812# Should be DUT dependent.
1813test_prio["Flow_Add_6"] = -1
1814
rootf6af1672012-04-06 09:46:29 -07001815class Flow_Add_6(basic.SimpleProtocol):
1816 """
1817 Test FLOW_ADD_6 from draft top-half test plan
1818
1819 INPUTS
1820 num_flows - Number of flows to generate
1821 """
Howard Pershc7963582012-03-29 10:02:59 -07001822
1823 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001824 fq_logger.info("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001825
rootf6af1672012-04-06 09:46:29 -07001826 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001827
Howard Persh5f3c83f2012-04-13 09:57:10 -07001828 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001829 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001830 self.assertEqual(rc, 0, "Failed to delete all flows")
1831
1832 # Get switch capabilites
1833
rootf6af1672012-04-06 09:46:29 -07001834 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001835 self.assertTrue(sw.connect(self.controller), \
1836 "Failed to connect to switch" \
1837 )
rootf6af1672012-04-06 09:46:29 -07001838
root2843d2b2012-04-06 10:27:46 -07001839 num_flows = 0
rootf6af1672012-04-06 09:46:29 -07001840 for ts in sw.tbl_stats.stats:
1841 num_flows = num_flows + ts.max_entries
1842
Howard Persh5f3c83f2012-04-13 09:57:10 -07001843 fq_logger.info("Switch capacity is %d flows" % (num_flows))
1844 fq_logger.info("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001845
1846 # Dream up some flow information, i.e. space to chose from for
1847 # random flow parameter generation
1848
1849 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001850 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001851
1852 # Create a flow table, to switch's capacity
1853
1854 ft = Flow_Tbl()
1855 ft.rand(sw, fi, num_flows)
1856
1857 # Send flow table to switch
1858
Howard Persh5f3c83f2012-04-13 09:57:10 -07001859 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001860 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07001861 fq_logger.info("Adding flow:")
1862 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001863 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1864
1865 # Do barrier, to make sure all flows are in
1866
1867 self.assertTrue(sw.barrier(), "Barrier failed")
1868
1869 result = True
1870
1871 # Check for any error messages
1872
1873 if not sw.errors_verify(0):
1874 result = False
1875
1876 # Dream up one more flow
1877
Howard Persh5f3c83f2012-04-13 09:57:10 -07001878 fq_logger.info("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001879 while True:
1880 fc = Flow_Cfg()
1881 fc.rand(fi, \
Howard Persh07d99e62012-04-09 15:26:57 -07001882 sw.tbl_stats.stats[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001883 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001884 sw.valid_ports, \
1885 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001886 )
1887 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001888 if not ft.find(fc):
1889 break
rootf6af1672012-04-06 09:46:29 -07001890
1891 # Send one-more flow
1892
1893 fc.send_rem = False
Howard Persh5f3c83f2012-04-13 09:57:10 -07001894 fq_logger.info("Sending flow add switch")
1895 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001896 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1897
1898 # Do barrier, to make sure all flows are in
1899
1900 self.assertTrue(sw.barrier(), "Barrier failed")
1901
1902 # Check for expected error message
1903
1904 if not sw.errors_verify(1, \
1905 ofp.OFPET_FLOW_MOD_FAILED, \
1906 ofp.OFPFMFC_ALL_TABLES_FULL \
1907 ):
1908 result = False
1909
1910 # Verify flow table
1911
1912 sw.flow_tbl = ft
1913 if not sw.flow_tbl_verify():
1914 result = False
1915
1916 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001917 fq_logger.info("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001918
1919
Howard Persh07d99e62012-04-09 15:26:57 -07001920# FLOW ADD 7
1921#
1922# OVERVIEW
1923# Test flow redefinition
1924#
1925# PURPOSE
1926# Verify that successive flow adds with same priority and match criteria
1927# overwrite in flow table
1928#
1929# PARAMETERS
1930# None
1931#
1932# PROCESS
1933# 1. Delete all flows from switch
1934# 2. Generate flow definition F1
1935# 3. Generate flow definition F2, with same key (priority and match) as F1,
1936# but with different actions
1937# 4. Send flow adds for F1 and F2 to switch
1938# 5. Verify flow definitions in switch
1939# 6. Test PASSED iff 1 flow returned by switch, matching configuration of F2;
1940# else test FAILED
1941
rootf6af1672012-04-06 09:46:29 -07001942class Flow_Add_7(basic.SimpleProtocol):
1943 """
1944 Test FLOW_ADD_7 from draft top-half test plan
1945
1946 INPUTS
1947 None
1948 """
1949
1950 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001951 fq_logger.info("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001952
1953 # Clear all flows from switch
1954
Howard Persh5f3c83f2012-04-13 09:57:10 -07001955 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001956 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001957 self.assertEqual(rc, 0, "Failed to delete all flows")
1958
1959 # Get switch capabilites
1960
rootf6af1672012-04-06 09:46:29 -07001961 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001962 self.assertTrue(sw.connect(self.controller), \
1963 "Failed to connect to switch" \
1964 )
rootf6af1672012-04-06 09:46:29 -07001965
1966 # Dream up some flow information, i.e. space to chose from for
1967 # random flow parameter generation
1968
1969 fi = Flow_Info()
1970 fi.rand(10)
1971
1972 # Dream up a flow config
1973
1974 fc = Flow_Cfg()
1975 fc.rand(fi, \
1976 sw.tbl_stats.stats[0].wildcards, \
1977 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001978 sw.valid_ports, \
1979 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001980 )
1981 fc = fc.canonical()
1982
1983 # Send it to the switch
1984
Howard Persh5f3c83f2012-04-13 09:57:10 -07001985 fq_logger.info("Sending flow add to switch:")
1986 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001987 ft = Flow_Tbl()
1988 fc.send_rem = False
1989 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1990 ft.insert(fc)
1991
1992 # Dream up some different actions, with the same flow key
1993
1994 fc2 = copy.deepcopy(fc)
1995 while True:
1996 fc2.rand_mod(fi, \
1997 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001998 sw.valid_ports, \
1999 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002000 )
2001 if fc2 != fc:
2002 break
2003
2004 # Send that to the switch
2005
Howard Persh5f3c83f2012-04-13 09:57:10 -07002006 fq_logger.info("Sending flow add to switch:")
2007 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002008 fc2.send_rem = False
2009 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
2010 ft.insert(fc2)
2011
2012 # Do barrier, to make sure all flows are in
2013
2014 self.assertTrue(sw.barrier(), "Barrier failed")
2015
2016 result = True
2017
2018 # Check for any error messages
2019
2020 if not sw.errors_verify(0):
2021 result = False
2022
2023 # Verify flow table
2024
2025 sw.flow_tbl = ft
2026 if not sw.flow_tbl_verify():
2027 result = False
2028
2029 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002030 fq_logger.info("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002031
2032
Howard Persh07d99e62012-04-09 15:26:57 -07002033# FLOW ADD 8
2034#
2035# OVERVIEW
2036# Add overlapping flows to switch, verify that overlapping flows are rejected
2037#
2038# PURPOSE
2039# - Test detection of overlapping flows by switch
2040# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
2041# - Test rejection of overlapping flows
2042# - Test defining overlapping flows does not corrupt flow table
2043#
2044# PARAMETERS
2045# None
2046#
2047# PROCESS
2048# 1. Delete all flows from switch
2049# 2. Generate flow definition F1
2050# 3. Generate flow definition F2, with key overlapping F1
2051# 4. Send flow add to switch, for F1
2052# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
2053# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
2054# was generated by switch
2055# 7. Verifiy flows configured in swtich
2056# 8. Test PASSED iff:
2057# - error message received, for overlapping flow
2058# - overlapping flow is not in flow table
2059# else test FAILED
2060
rootf6af1672012-04-06 09:46:29 -07002061class Flow_Add_8(basic.SimpleProtocol):
2062 """
2063 Test FLOW_ADD_8 from draft top-half test plan
2064
2065 INPUTS
2066 None
2067 """
2068
2069 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002070 fq_logger.info("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002071
2072 # Clear all flows from switch
2073
Howard Persh5f3c83f2012-04-13 09:57:10 -07002074 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002075 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002076 self.assertEqual(rc, 0, "Failed to delete all flows")
2077
2078 # Get switch capabilites
2079
rootf6af1672012-04-06 09:46:29 -07002080 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002081 self.assertTrue(sw.connect(self.controller), \
2082 "Failed to connect to switch" \
2083 )
rootf6af1672012-04-06 09:46:29 -07002084
2085 # Dream up some flow information, i.e. space to chose from for
2086 # random flow parameter generation
2087
2088 fi = Flow_Info()
2089 fi.rand(10)
2090
2091 # Dream up a flow config, with at least 1 qualifier specified
2092
2093 fc = Flow_Cfg()
2094 while True:
2095 fc.rand(fi, \
2096 sw.tbl_stats.stats[0].wildcards, \
2097 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002098 sw.valid_ports, \
2099 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002100 )
2101 fc = fc.canonical()
2102 if fc.match.wildcards != ofp.OFPFW_ALL:
2103 break
2104
2105 # Send it to the switch
2106
Howard Persh5f3c83f2012-04-13 09:57:10 -07002107 fq_logger.info("Sending flow add to switch:")
2108 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002109 ft = Flow_Tbl()
2110 fc.send_rem = False
2111 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2112 ft.insert(fc)
2113
2114 # Wildcard out one qualifier that was specified, to create an
2115 # overlapping flow
2116
2117 fc2 = copy.deepcopy(fc)
2118 for wi in shuffle(range(len(all_wildcards_list))):
2119 w = all_wildcards_list[wi]
2120 if (fc2.match.wildcards & w) == 0:
2121 break
2122 if w == ofp.OFPFW_NW_SRC_MASK:
2123 w = ofp.OFPFW_NW_SRC_ALL
2124 wn = "OFPFW_NW_SRC"
2125 elif w == ofp.OFPFW_NW_DST_MASK:
2126 w = ofp.OFPFW_NW_DST_ALL
2127 wn = "OFPFW_NW_DST"
2128 else:
2129 wn = all_wildcard_names[w]
Howard Persh5f3c83f2012-04-13 09:57:10 -07002130 fq_logger.info("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07002131 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07002132 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07002133
2134 # Send that to the switch, with overlap checking
2135
Howard Persh5f3c83f2012-04-13 09:57:10 -07002136 fq_logger.info("Sending flow add to switch:")
2137 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002138 fc2.send_rem = False
2139 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
2140
2141 # Do barrier, to make sure all flows are in
2142 self.assertTrue(sw.barrier(), "Barrier failed")
2143
2144 result = True
2145
2146 # Check for expected error message
2147
2148 if not sw.errors_verify(1, \
2149 ofp.OFPET_FLOW_MOD_FAILED, \
2150 ofp.OFPFMFC_OVERLAP \
2151 ):
2152 result = False
2153
2154 # Verify flow table
2155
2156 sw.flow_tbl = ft
2157 if not sw.flow_tbl_verify():
2158 result = False
2159
2160 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002161 fq_logger.info("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002162
2163
Howard Persh07d99e62012-04-09 15:26:57 -07002164# FLOW MODIFY 1
2165#
2166# OVERVIEW
2167# Strict modify of single existing flow
2168#
2169# PURPOSE
2170# - Verify that strict flow modify operates only on specified flow
2171# - Verify that flow is correctly modified
2172#
2173# PARAMETERS
2174# None
2175#
2176# PROCESS
2177# 1. Delete all flows from switch
2178# 2. Generate 1 flow F
2179# 3. Send flow add to switch, for flow F
2180# 4. Generate new action list for flow F, yielding F'
2181# 5. Send strict flow modify to switch, for flow F'
2182# 6. Verify flow table in switch
2183# 7. Test PASSED iff flow returned by switch is F'; else FAILED
2184
rootf6af1672012-04-06 09:46:29 -07002185class Flow_Mod_1(basic.SimpleProtocol):
2186 """
2187 Test FLOW_MOD_1 from draft top-half test plan
2188
2189 INPUTS
2190 None
2191 """
2192
2193 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002194 fq_logger.info("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002195
2196 # Clear all flows from switch
2197
Howard Persh5f3c83f2012-04-13 09:57:10 -07002198 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002199 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002200 self.assertEqual(rc, 0, "Failed to delete all flows")
2201
2202 # Get switch capabilites
2203
rootf6af1672012-04-06 09:46:29 -07002204 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002205 self.assertTrue(sw.connect(self.controller), \
2206 "Failed to connect to switch" \
2207 )
rootf6af1672012-04-06 09:46:29 -07002208
2209 # Dream up some flow information, i.e. space to chose from for
2210 # random flow parameter generation
2211
2212 fi = Flow_Info()
2213 fi.rand(10)
2214
2215 # Dream up a flow config
2216
2217 fc = Flow_Cfg()
2218 fc.rand(fi, \
2219 sw.tbl_stats.stats[0].wildcards, \
2220 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002221 sw.valid_ports, \
2222 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002223 )
2224 fc = fc.canonical()
2225
2226 # Send it to the switch
2227
Howard Persh5f3c83f2012-04-13 09:57:10 -07002228 fq_logger.info("Sending flow add to switch:")
2229 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002230 ft = Flow_Tbl()
2231 fc.send_rem = False
2232 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2233 ft.insert(fc)
2234
2235 # Dream up some different actions, with the same flow key
2236
2237 fc2 = copy.deepcopy(fc)
2238 while True:
2239 fc2.rand_mod(fi, \
2240 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002241 sw.valid_ports, \
2242 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002243 )
2244 if fc2 != fc:
2245 break
2246
2247 # Send that to the switch
2248
Howard Persh5f3c83f2012-04-13 09:57:10 -07002249 fq_logger.info("Sending strict flow mod to switch:")
2250 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002251 fc2.send_rem = False
2252 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2253 ft.insert(fc2)
2254
2255 # Do barrier, to make sure all flows are in
2256
2257 self.assertTrue(sw.barrier(), "Barrier failed")
2258
2259 result = True
2260
2261 # Check for any error messages
2262
2263 if not sw.errors_verify(0):
2264 result = False
2265
2266 # Verify flow table
2267
2268 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002269 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002270 result = False
2271
2272 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002273 fq_logger.info("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002274
Howard Persh07d99e62012-04-09 15:26:57 -07002275
2276# FLOW MODIFY 2
2277#
2278# OVERVIEW
2279# Loose modify of mutiple flows
2280#
2281# PURPOSE
2282# - Verify that loose flow modify operates only on matching flows
2283# - Verify that matching flows are correctly modified
2284#
2285# PARAMETERS
2286# Name: num_flows
2287# Type: number
2288# Description:
2289# Number of flows to define
2290# Default: 100
2291#
2292# PROCESS
2293# 1. Delete all flows from switch
2294# 2. Generate <num_flows> distinct flow configurations
2295# 3. Send <num_flows> flow adds to switch
2296# 4. Pick 1 defined flow F at random
2297# 5. Create overlapping loose flow mod match criteria by repeatedly
2298# wildcarding out qualifiers in match of F => F',
2299# and create new actions list A' for F'
2300# 6. Send loose flow modify for F' to switch
2301# 7. Verify flow table in swtich
2302# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2303# are returned in step 7 above, each with correct (original or modified)
2304# action list;
2305# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002306
2307class Flow_Mod_2(basic.SimpleProtocol):
2308 """
2309 Test FLOW_MOD_2 from draft top-half test plan
2310
2311 INPUTS
2312 None
2313 """
2314
2315 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002316 fq_logger.info("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002317
Dan Talayco910a8282012-04-07 00:05:20 -07002318 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002319
2320 # Clear all flows from switch
2321
Howard Persh5f3c83f2012-04-13 09:57:10 -07002322 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002323 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002324 self.assertEqual(rc, 0, "Failed to delete all flows")
2325
2326 # Get switch capabilites
2327
rootf6af1672012-04-06 09:46:29 -07002328 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002329 self.assertTrue(sw.connect(self.controller), \
2330 "Failed to connect to switch" \
2331 )
rootf6af1672012-04-06 09:46:29 -07002332
2333 # Dream up some flow information, i.e. space to chose from for
2334 # random flow parameter generation
2335
2336 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002337 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002338 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002339
2340 # Dream up some flows
2341
2342 ft = Flow_Tbl()
2343 ft.rand(sw, fi, num_flows)
2344
2345 # Send flow table to switch
2346
Howard Persh5f3c83f2012-04-13 09:57:10 -07002347 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002348 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07002349 fq_logger.info("Adding flow:")
2350 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002351 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2352
2353 # Do barrier, to make sure all flows are in
2354
2355 self.assertTrue(sw.barrier(), "Barrier failed")
2356
2357 result = True
2358
2359 # Check for any error messages
2360
2361 if not sw.errors_verify(0):
2362 result = False
2363
2364 # Verify flow table
2365
2366 sw.flow_tbl = ft
2367 if not sw.flow_tbl_verify():
2368 result = False
2369
2370 # Pick a random flow as a basis
Howard Persh5f3c83f2012-04-13 09:57:10 -07002371
2372 mfc = copy.deepcopy((ft.values())[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002373 mfc.rand_mod(fi, \
2374 sw.sw_features.actions, \
2375 sw.valid_ports, \
2376 sw.valid_queues \
2377 )
rootf6af1672012-04-06 09:46:29 -07002378
2379 # Repeatedly wildcard qualifiers
2380
2381 for wi in shuffle(range(len(all_wildcards_list))):
2382 w = all_wildcards_list[wi]
2383 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2384 n = wildcard_get(mfc.match.wildcards, w)
2385 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002386 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2387 w, \
2388 random.randint(n + 1, 32) \
2389 )
rootf6af1672012-04-06 09:46:29 -07002390 else:
2391 continue
2392 else:
2393 if wildcard_get(mfc.match.wildcards, w) == 0:
2394 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2395 else:
2396 continue
2397 mfc = mfc.canonical()
2398
2399 # Count the number of flows that would be modified
2400
2401 n = 0
2402 for fc in ft.values():
2403 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2404 n = n + 1
2405
2406 # If more than 1, we found our loose delete flow spec
2407 if n > 1:
2408 break
2409
Howard Persh5f3c83f2012-04-13 09:57:10 -07002410 fq_logger.info("Modifying %d flows" % (n))
2411 fq_logger.info("Sending flow mod to switch:")
2412 fq_logger.info(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002413 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2414
2415 # Do barrier, to make sure all flows are in
2416 self.assertTrue(sw.barrier(), "Barrier failed")
2417
2418 # Check for error message
2419
2420 if not sw.errors_verify(0):
2421 result = False
2422
2423 # Apply flow mod to local flow table
2424
2425 for fc in ft.values():
2426 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002427 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002428
2429 # Verify flow table
2430
2431 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002432 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002433 result = False
2434
2435 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002436 fq_logger.info("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002437
2438
Howard Persh07d99e62012-04-09 15:26:57 -07002439# FLOW MODIFY 3
2440
2441# OVERVIEW
2442# Strict modify of non-existent flow
2443#
2444# PURPOSE
2445# Verify that strict modify of a non-existent flow is equivalent to a flow add
2446#
2447# PARAMETERS
2448# None
2449#
2450# PROCESS
2451# 1. Delete all flows from switch
2452# 2. Send single flow mod, as strict modify, to switch
2453# 3. Verify flow table in switch
2454# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2455
rootf6af1672012-04-06 09:46:29 -07002456class Flow_Mod_3(basic.SimpleProtocol):
2457 """
2458 Test FLOW_MOD_3 from draft top-half test plan
2459
2460 INPUTS
2461 None
2462 """
2463
2464 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002465 fq_logger.info("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002466
2467 # Clear all flows from switch
2468
Howard Persh5f3c83f2012-04-13 09:57:10 -07002469 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002470 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002471 self.assertEqual(rc, 0, "Failed to delete all flows")
2472
2473 # Get switch capabilites
2474
rootf6af1672012-04-06 09:46:29 -07002475 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002476 self.assertTrue(sw.connect(self.controller), \
2477 "Failed to connect to switch" \
2478 )
rootf6af1672012-04-06 09:46:29 -07002479
2480 # Dream up some flow information, i.e. space to chose from for
2481 # random flow parameter generation
2482
2483 fi = Flow_Info()
2484 fi.rand(10)
2485
2486 # Dream up a flow config
2487
2488 fc = Flow_Cfg()
2489 fc.rand(fi, \
2490 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, \
2580 sw.tbl_stats.stats[0].wildcards, \
2581 sw.sw_features.actions, \
2582 sw.valid_ports, \
2583 sw.valid_queues \
2584 )
2585 fc = fc.canonical()
2586
2587 # Send it to the switch
2588
2589 fq_logger.info("Sending flow mod to switch:")
2590 fq_logger.info(str(fc))
2591 ft = Flow_Tbl()
2592 fc.send_rem = False
2593 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2594 ft.insert(fc)
2595
2596 # Do barrier, to make sure all flows are in
2597
2598 self.assertTrue(sw.barrier(), "Barrier failed")
2599
2600 result = True
2601
2602 # Check for any error messages
2603
2604 if not sw.errors_verify(0):
2605 result = False
2606
2607 # Verify flow table
2608
2609 sw.flow_tbl = ft
2610 if not sw.flow_tbl_verify():
2611 result = False
2612
2613 # Send same flow to the switch again
2614
2615 fq_logger.info("Sending flow mod to switch:")
2616 fq_logger.info(str(fc))
2617 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2618
2619 # Do barrier, to make sure all flows are in
2620
2621 self.assertTrue(sw.barrier(), "Barrier failed")
2622
2623 # Check for any error messages
2624
2625 if not sw.errors_verify(0):
2626 result = False
2627
2628 # Verify flow table
2629
2630 if not sw.flow_tbl_verify():
2631 result = False
2632
2633 self.assertTrue(result, "Flow_Mod_3_1 TEST FAILED")
2634 fq_logger.info("Flow_Mod_3_1 TEST PASSED")
2635
2636
Howard Persh07d99e62012-04-09 15:26:57 -07002637# FLOW DELETE 1
2638#
2639# OVERVIEW
2640# Strict delete of single flow
2641#
2642# PURPOSE
2643# Verify correct operation of strict delete of single defined flow
2644#
2645# PARAMETERS
2646# None
2647#
2648# PROCESS
2649# 1. Delete all flows from switch
2650# 2. Send flow F to switch
2651# 3. Send strict flow delete for F to switch
2652# 4. Verify flow table in swtich
2653# 6. Test PASSED iff all flows sent to switch in step 2 above,
2654# less flow removed in step 3 above, are returned in step 4 above;
2655# else test FAILED
2656
rootf6af1672012-04-06 09:46:29 -07002657class Flow_Del_1(basic.SimpleProtocol):
2658 """
2659 Test FLOW_DEL_1 from draft top-half test plan
2660
2661 INPUTS
2662 None
2663 """
2664
2665 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002666 fq_logger.info("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002667
2668 # Clear all flows from switch
2669
Howard Persh5f3c83f2012-04-13 09:57:10 -07002670 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002671 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002672 self.assertEqual(rc, 0, "Failed to delete all flows")
2673
2674 # Get switch capabilites
2675
rootf6af1672012-04-06 09:46:29 -07002676 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002677 self.assertTrue(sw.connect(self.controller), \
2678 "Failed to connect to switch" \
2679 )
rootf6af1672012-04-06 09:46:29 -07002680
2681 # Dream up some flow information, i.e. space to chose from for
2682 # random flow parameter generation
2683
2684 fi = Flow_Info()
2685 fi.rand(10)
2686
2687 # Dream up a flow config
2688
2689 fc = Flow_Cfg()
2690 fc.rand(fi, \
2691 sw.tbl_stats.stats[0].wildcards, \
2692 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002693 sw.valid_ports, \
2694 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002695 )
2696 fc = fc.canonical()
2697
2698 # Send it to the switch
2699
Howard Persh5f3c83f2012-04-13 09:57:10 -07002700 fq_logger.info("Sending flow add to switch:")
2701 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002702 ft = Flow_Tbl()
2703 fc.send_rem = False
2704 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2705 ft.insert(fc)
2706
2707 # Dream up some different actions, with the same flow key
2708
2709 fc2 = copy.deepcopy(fc)
2710 while True:
2711 fc2.rand_mod(fi, \
2712 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002713 sw.valid_ports, \
2714 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002715 )
2716 if fc2 != fc:
2717 break
2718
2719 # Delete strictly
2720
Howard Persh5f3c83f2012-04-13 09:57:10 -07002721 fq_logger.info("Sending strict flow del to switch:")
2722 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002723 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2724 ft.delete(fc)
2725
2726 # Do barrier, to make sure all flows are in
2727
2728 self.assertTrue(sw.barrier(), "Barrier failed")
2729
2730 result = True
2731
2732 # Check for any error messages
2733
2734 if not sw.errors_verify(0):
2735 result = False
2736
2737 # Verify flow table
2738
2739 sw.flow_tbl = ft
2740 if not sw.flow_tbl_verify():
2741 result = False
2742
2743 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002744 fq_logger.info("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002745
2746
Howard Persh07d99e62012-04-09 15:26:57 -07002747# FLOW DELETE 2
2748#
2749# OVERVIEW
2750# Loose delete of multiple flows
2751#
2752# PURPOSE
2753# - Verify correct operation of loose delete of multiple flows
2754#
2755# PARAMETERS
2756# Name: num_flows
2757# Type: number
2758# Description:
2759# Number of flows to define
2760# Default: 100
2761#
2762# PROCESS
2763# 1. Delete all flows from switch
2764# 2. Generate <num_flows> distinct flow configurations
2765# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2766# 4. Pick 1 defined flow F at random
2767# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2768# F' will match more than 1 existing flow key
2769# 6. Send loose flow delete for F' to switch
2770# 7. Verify flow table in switch
2771# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2772# removed in step 6 above (i.e. those that match F'), are returned
2773# in step 7 above;
2774# else test FAILED
2775
rootf6af1672012-04-06 09:46:29 -07002776class Flow_Del_2(basic.SimpleProtocol):
2777 """
2778 Test FLOW_DEL_2 from draft top-half test plan
2779
2780 INPUTS
2781 None
2782 """
2783
2784 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002785 fq_logger.info("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002786
Dan Talayco910a8282012-04-07 00:05:20 -07002787 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002788
2789 # Clear all flows from switch
2790
Howard Persh5f3c83f2012-04-13 09:57:10 -07002791 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002792 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002793 self.assertEqual(rc, 0, "Failed to delete all flows")
2794
2795 # Get switch capabilites
2796
rootf6af1672012-04-06 09:46:29 -07002797 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002798 self.assertTrue(sw.connect(self.controller), \
2799 "Failed to connect to switch" \
2800 )
rootf6af1672012-04-06 09:46:29 -07002801
2802 # Dream up some flow information, i.e. space to chose from for
2803 # random flow parameter generation
2804
2805 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002806 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002807 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002808
2809 # Dream up some flows
2810
2811 ft = Flow_Tbl()
2812 ft.rand(sw, fi, num_flows)
2813
2814 # Send flow table to switch
2815
Howard Persh5f3c83f2012-04-13 09:57:10 -07002816 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002817 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07002818 fq_logger.info("Adding flow:")
2819 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002820 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2821
2822 # Do barrier, to make sure all flows are in
2823
2824 self.assertTrue(sw.barrier(), "Barrier failed")
2825
2826 result = True
2827
2828 # Check for any error messages
2829
2830 if not sw.errors_verify(0):
2831 result = False
2832
2833 # Verify flow table
2834
2835 sw.flow_tbl = ft
2836 if not sw.flow_tbl_verify():
2837 result = False
2838
2839 # Pick a random flow as a basis
2840
2841 dfc = copy.deepcopy(ft.values()[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002842 dfc.rand_mod(fi, \
2843 sw.sw_features.actions, \
2844 sw.valid_ports, \
2845 sw.valid_queues \
2846 )
rootf6af1672012-04-06 09:46:29 -07002847
2848 # Repeatedly wildcard qualifiers
2849
2850 for wi in shuffle(range(len(all_wildcards_list))):
2851 w = all_wildcards_list[wi]
2852 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2853 n = wildcard_get(dfc.match.wildcards, w)
2854 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002855 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2856 w, \
2857 random.randint(n + 1, 32) \
2858 )
rootf6af1672012-04-06 09:46:29 -07002859 else:
2860 continue
2861 else:
2862 if wildcard_get(dfc.match.wildcards, w) == 0:
2863 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2864 else:
2865 continue
2866 dfc = dfc.canonical()
2867
2868 # Count the number of flows that would be deleted
2869
2870 n = 0
2871 for fc in ft.values():
2872 if dfc.overlaps(fc, True):
2873 n = n + 1
2874
2875 # If more than 1, we found our loose delete flow spec
2876 if n > 1:
2877 break
2878
Howard Persh5f3c83f2012-04-13 09:57:10 -07002879 fq_logger.info("Deleting %d flows" % (n))
2880 fq_logger.info("Sending flow del to switch:")
2881 fq_logger.info(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002882 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2883
2884 # Do barrier, to make sure all flows are in
2885 self.assertTrue(sw.barrier(), "Barrier failed")
2886
2887 # Check for error message
2888
2889 if not sw.errors_verify(0):
2890 result = False
2891
2892 # Apply flow mod to local flow table
2893
2894 for fc in ft.values():
2895 if dfc.overlaps(fc, True):
2896 ft.delete(fc)
2897
2898 # Verify flow table
2899
2900 sw.flow_tbl = ft
2901 if not sw.flow_tbl_verify():
2902 result = False
2903
2904 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002905 fq_logger.info("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002906
2907
Howard Persh07d99e62012-04-09 15:26:57 -07002908# FLOW DELETE 4
2909#
2910# OVERVIEW
2911# Flow removed messages
2912#
2913# PURPOSE
2914# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2915# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2916#
2917# PARAMETERS
2918# None
2919#
2920# PROCESS
2921# 1. Delete all flows from switch
2922# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2923# 3. Send strict flow delete of flow to switch
2924# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2925# 5. Verify flow table in switch
2926# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2927# removed in step 3 above, are returned in step 5 above, and that
2928# asynch message was received; else test FAILED
2929
2930
rootf6af1672012-04-06 09:46:29 -07002931class Flow_Del_4(basic.SimpleProtocol):
2932 """
2933 Test FLOW_DEL_4 from draft top-half test plan
2934
2935 INPUTS
2936 None
2937 """
2938
2939 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002940 fq_logger.info("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002941
2942 # Clear all flows from switch
2943
Howard Persh5f3c83f2012-04-13 09:57:10 -07002944 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002945 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002946 self.assertEqual(rc, 0, "Failed to delete all flows")
2947
2948 # Get switch capabilites
2949
rootf6af1672012-04-06 09:46:29 -07002950 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002951 self.assertTrue(sw.connect(self.controller), \
2952 "Failed to connect to switch" \
2953 )
rootf6af1672012-04-06 09:46:29 -07002954
2955 # Dream up some flow information, i.e. space to chose from for
2956 # random flow parameter generation
2957
2958 fi = Flow_Info()
2959 fi.rand(10)
2960
2961 # Dream up a flow config
2962
2963 fc = Flow_Cfg()
2964 fc.rand(fi, \
2965 sw.tbl_stats.stats[0].wildcards, \
2966 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002967 sw.valid_ports, \
2968 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002969 )
2970 fc = fc.canonical()
2971
2972 # Send it to the switch. with "notify on removed"
2973
Howard Persh5f3c83f2012-04-13 09:57:10 -07002974 fq_logger.info("Sending flow add to switch:")
2975 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002976 ft = Flow_Tbl()
2977 fc.send_rem = True
2978 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2979 ft.insert(fc)
2980
2981 # Dream up some different actions, with the same flow key
2982
2983 fc2 = copy.deepcopy(fc)
2984 while True:
2985 fc2.rand_mod(fi, \
2986 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002987 sw.valid_ports, \
2988 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002989 )
2990 if fc2 != fc:
2991 break
2992
2993 # Delete strictly
2994
Howard Persh5f3c83f2012-04-13 09:57:10 -07002995 fq_logger.info("Sending strict flow del to switch:")
2996 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002997 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2998 ft.delete(fc)
2999
3000 # Do barrier, to make sure all flows are in
3001
3002 self.assertTrue(sw.barrier(), "Barrier failed")
3003
3004 result = True
3005
3006 # Check for expected "removed" message
3007
Howard Persh3340d452012-04-06 16:45:21 -07003008 if not sw.errors_verify(0):
3009 result = False
3010
3011 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07003012 result = False
3013
3014 # Verify flow table
3015
3016 sw.flow_tbl = ft
3017 if not sw.flow_tbl_verify():
3018 result = False
3019
3020 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07003021 fq_logger.info("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07003022