blob: 0e02c569d70bfabe9c3025f7516e876189ff9daa [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 Persh3340d452012-04-06 16:45:21 -0700549 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700550 for a in actions:
Dan Talayco910a8282012-04-07 00:05:20 -0700551 act = None
Howard Persh3340d452012-04-06 16:45:21 -0700552 if a == ofp.OFPAT_OUTPUT:
553 pass # OUTPUT actions must come last
554 elif a == ofp.OFPAT_SET_VLAN_VID:
555 act = action.action_set_vlan_vid()
556 act.vlan_vid = fi.rand_vlan()
Howard Persh3340d452012-04-06 16:45:21 -0700557 elif a == ofp.OFPAT_SET_VLAN_PCP:
558 act = action.action_set_vlan_pcp()
559 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Persh3340d452012-04-06 16:45:21 -0700560 elif a == ofp.OFPAT_STRIP_VLAN:
561 act = action.action_strip_vlan()
Howard Persh3340d452012-04-06 16:45:21 -0700562 elif a == ofp.OFPAT_SET_DL_SRC:
563 act = action.action_set_dl_src()
564 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700565 elif a == ofp.OFPAT_SET_DL_DST:
566 act = action.action_set_dl_dst()
567 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700568 elif a == ofp.OFPAT_SET_NW_SRC:
569 act = action.action_set_nw_src()
570 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700571 elif a == ofp.OFPAT_SET_NW_DST:
572 act = action.action_set_nw_dst()
573 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700574 elif a == ofp.OFPAT_SET_NW_TOS:
575 act = action.action_set_nw_tos()
576 act.nw_tos = fi.rand_ip_tos()
Howard Persh3340d452012-04-06 16:45:21 -0700577 elif a == ofp.OFPAT_SET_TP_SRC:
578 act = action.action_set_tp_src()
579 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700580 elif a == ofp.OFPAT_SET_TP_DST:
581 act = action.action_set_tp_dst()
582 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700583 elif a == ofp.OFPAT_ENQUEUE:
584 pass # Enqueue actions must come last
Dan Talayco910a8282012-04-07 00:05:20 -0700585 if act:
586 act.max_len = ACTION_MAX_LEN
587 self.actions.add(act)
588
Howard Persh3340d452012-04-06 16:45:21 -0700589 p = random.randint(1, 100)
Howard Pershc1199d52012-04-11 14:21:32 -0700590 if (((1 << ofp.OFPAT_ENQUEUE) & actions_force) != 0 or p <= 33) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700591 and len(valid_queues) > 0 \
592 and ofp.OFPAT_ENQUEUE in actions:
Howard Pershc1199d52012-04-11 14:21:32 -0700593 # In not forecd, one third of the time, include ENQUEUE actions
594 # at end of list
Howard Persh3340d452012-04-06 16:45:21 -0700595 # At most 1 ENQUEUE action
596 act = action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700597 (act.port, act.queue_id) = rand_pick(valid_queues)
Dan Talayco910a8282012-04-07 00:05:20 -0700598 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700599 self.actions.add(act)
Howard Pershc1199d52012-04-11 14:21:32 -0700600 if (((1 << ofp.OFPAT_OUTPUT) & actions_force) != 0 \
601 or (p > 33 and p <= 66) \
602 ) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700603 and len(valid_ports) > 0 \
Howard Pershc1199d52012-04-11 14:21:32 -0700604 and ofp.OFPAT_OUTPUT in actions:
Howard Persh3340d452012-04-06 16:45:21 -0700605 # One third of the time, include OUTPUT actions at end of list
606 port_idxs = shuffle(range(len(valid_ports)))
607 # Only 1 output action allowed if IN_PORT wildcarded
608 n = 1 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) != 0 \
609 else random.randint(1, len(valid_ports))
610 port_idxs = port_idxs[0 : n]
611 for pi in port_idxs:
612 act = action.action_output()
613 act.port = valid_ports[pi]
Dan Talayco910a8282012-04-07 00:05:20 -0700614 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700615 if act.port != ofp.OFPP_IN_PORT \
616 or wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
617 # OUTPUT(IN_PORT) only valid if OFPFW_IN_PORT not wildcarded
618 self.actions.add(act)
619 else:
620 # One third of the time, include neither
621 pass
622
623
624 # Randomize flow data for flow modifies (i.e. cookie and actions)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700625 def rand_mod(self, fi, valid_actions, valid_ports, valid_queues):
rootf6af1672012-04-06 09:46:29 -0700626 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700627
Dan Talayco910a8282012-04-07 00:05:20 -0700628 # By default, test with conservative ordering conventions
629 # This should probably be indicated in a profile
630 if test_param_get(fq_config, "conservative_ordered_actions", True):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700631 self.rand_actions_ordered(fi, valid_actions, valid_ports, valid_queues)
Howard Persh3340d452012-04-06 16:45:21 -0700632 return self
633
Howard Pershc1199d52012-04-11 14:21:32 -0700634 actions_force = test_param_get(fq_config, "actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700635 if actions_force != 0:
636 fq_logger.info("Forced actions:")
637 fq_logger.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700638
639 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh680b92a2012-03-31 13:34:35 -0700640 supported_actions = []
641 for a in all_actions_list:
642 if ((1 << a) & valid_actions) != 0:
643 supported_actions.append(a)
644
Howard Pershc1199d52012-04-11 14:21:32 -0700645 actions \
646 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
647
648 for a in all_actions_list:
649 if ((1 << a) & actions_force) != 0:
650 actions.append(a)
651
652 actions = shuffle(actions)
Howard Pershc7963582012-03-29 10:02:59 -0700653
654 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700655 for a in actions:
Howard Pershc7963582012-03-29 10:02:59 -0700656 if a == ofp.OFPAT_OUTPUT:
657 # TBD - Output actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700658 if len(valid_ports) == 0:
659 continue
Howard Pershc7963582012-03-29 10:02:59 -0700660 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700661 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700662 for pi in port_idxs:
663 act = action.action_output()
Howard Persh680b92a2012-03-31 13:34:35 -0700664 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700665 self.actions.add(act)
666 elif a == ofp.OFPAT_SET_VLAN_VID:
667 act = action.action_set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700668 act.vlan_vid = fi.rand_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700669 self.actions.add(act)
670 elif a == ofp.OFPAT_SET_VLAN_PCP:
Dan Talayco910a8282012-04-07 00:05:20 -0700671 act = action.action_set_vlan_pcp()
672 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700673 elif a == ofp.OFPAT_STRIP_VLAN:
674 act = action.action_strip_vlan()
675 self.actions.add(act)
676 elif a == ofp.OFPAT_SET_DL_SRC:
677 act = action.action_set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700678 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700679 self.actions.add(act)
680 elif a == ofp.OFPAT_SET_DL_DST:
681 act = action.action_set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700682 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700683 self.actions.add(act)
684 elif a == ofp.OFPAT_SET_NW_SRC:
685 act = action.action_set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700686 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700687 self.actions.add(act)
688 elif a == ofp.OFPAT_SET_NW_DST:
689 act = action.action_set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700690 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700691 self.actions.add(act)
692 elif a == ofp.OFPAT_SET_NW_TOS:
693 act = action.action_set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700694 act.nw_tos = fi.rand_ip_tos()
Howard Pershc7963582012-03-29 10:02:59 -0700695 self.actions.add(act)
696 elif a == ofp.OFPAT_SET_TP_SRC:
697 act = action.action_set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700698 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700699 self.actions.add(act)
700 elif a == ofp.OFPAT_SET_TP_DST:
701 act = action.action_set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700702 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700703 self.actions.add(act)
704 elif a == ofp.OFPAT_ENQUEUE:
705 # TBD - Enqueue actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700706 if len(valid_queues) == 0:
707 continue
708 qidxs = shuffle(range(len(valid_queues)))
709 qidxs = qidxs[0 : random.randint(1, len(valid_queues))]
710 for qi in qidxs:
Howard Pershc7963582012-03-29 10:02:59 -0700711 act = action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700712 (act.port, act.queue_id) = valid_queues[qi]
Howard Pershc7963582012-03-29 10:02:59 -0700713 self.actions.add(act)
714
715 return self
716
rootf6af1672012-04-06 09:46:29 -0700717 # Randomize flow cfg
Howard Persh8d21c1f2012-04-20 15:57:29 -0700718 def rand(self, fi, valid_wildcards, valid_actions, valid_ports, valid_queues):
Howard Pershc1199d52012-04-11 14:21:32 -0700719 wildcards_force = test_param_get(fq_config, "wildcards_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700720 if wildcards_force != 0:
721 fq_logger.info("Wildcards forced:")
722 fq_logger.info(wildcards_to_str(wildcards_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700723
rootf6af1672012-04-06 09:46:29 -0700724 # Start with no wildcards, i.e. everything specified
725 self.match.wildcards = 0
Howard Pershc1199d52012-04-11 14:21:32 -0700726
727 if wildcards_force != 0:
728 exact = False
729 else:
730 # Make approx. 5% of flows exact
731 exact = (random.randint(1, 100) <= 5)
rootf6af1672012-04-06 09:46:29 -0700732
733 # For each qualifier Q,
734 # if (wildcarding is not supported for Q,
735 # or an exact flow is specified
736 # or a coin toss comes up heads),
737 # specify Q
738 # else
739 # wildcard Q
740
Howard Pershc1199d52012-04-11 14:21:32 -0700741 if wildcard_get(wildcards_force, ofp.OFPFW_IN_PORT) == 0 \
742 and (wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
743 or exact \
744 or flip_coin() \
745 ):
rootf6af1672012-04-06 09:46:29 -0700746 self.match.in_port = rand_pick(valid_ports)
747 else:
Howard Persh3340d452012-04-06 16:45:21 -0700748 self.match.wildcards = wildcard_set(self.match.wildcards, \
749 ofp.OFPFW_IN_PORT, \
750 1 \
751 )
rootf6af1672012-04-06 09:46:29 -0700752
Howard Pershc1199d52012-04-11 14:21:32 -0700753 if wildcard_get(wildcards_force, ofp.OFPFW_DL_DST) == 0 \
754 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
755 or exact \
756 or flip_coin() \
757 ):
rootf6af1672012-04-06 09:46:29 -0700758 self.match.dl_dst = fi.rand_dl_addr()
759 else:
Howard Persh3340d452012-04-06 16:45:21 -0700760 self.match.wildcards = wildcard_set(self.match.wildcards, \
761 ofp.OFPFW_DL_DST, \
762 1 \
763 )
rootf6af1672012-04-06 09:46:29 -0700764
Howard Pershc1199d52012-04-11 14:21:32 -0700765 if wildcard_get(wildcards_force, ofp.OFPFW_DL_SRC) == 0 \
766 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
767 or exact \
768 or flip_coin() \
769 ):
rootf6af1672012-04-06 09:46:29 -0700770 self.match.dl_src = fi.rand_dl_addr()
771 else:
Howard Persh3340d452012-04-06 16:45:21 -0700772 self.match.wildcards = wildcard_set(self.match.wildcards, \
773 ofp.OFPFW_DL_SRC, \
774 1 \
775 )
rootf6af1672012-04-06 09:46:29 -0700776
Howard Pershc1199d52012-04-11 14:21:32 -0700777 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN) == 0 \
778 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
779 or exact \
780 or flip_coin() \
781 ):
rootf6af1672012-04-06 09:46:29 -0700782 self.match.dl_vlan = fi.rand_vlan()
783 else:
Howard Persh3340d452012-04-06 16:45:21 -0700784 self.match.wildcards = wildcard_set(self.match.wildcards, \
785 ofp.OFPFW_DL_VLAN, \
786 1 \
787 )
rootf6af1672012-04-06 09:46:29 -0700788
Howard Pershc1199d52012-04-11 14:21:32 -0700789 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN_PCP) == 0 \
790 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
791 or exact \
792 or flip_coin() \
793 ):
794 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
795 else:
796 self.match.wildcards = wildcard_set(self.match.wildcards, \
797 ofp.OFPFW_DL_VLAN_PCP, \
798 1 \
799 )
800
801 if wildcard_get(wildcards_force, ofp.OFPFW_DL_TYPE) == 0 \
802 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
803 or exact \
804 or flip_coin() \
805 ):
rootf6af1672012-04-06 09:46:29 -0700806 self.match.dl_type = fi.rand_ethertype()
807 else:
Howard Persh3340d452012-04-06 16:45:21 -0700808 self.match.wildcards = wildcard_set(self.match.wildcards, \
809 ofp.OFPFW_DL_TYPE, \
810 1 \
811 )
rootf6af1672012-04-06 09:46:29 -0700812
Howard Pershc1199d52012-04-11 14:21:32 -0700813 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_SRC_MASK)
814 if n == 0:
815 if exact or flip_coin():
816 n = 0
817 else:
818 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
819 if n > 32:
820 n = 32
821 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700822 self.match.wildcards = wildcard_set(self.match.wildcards, \
823 ofp.OFPFW_NW_SRC_MASK, \
824 n \
825 )
rootf6af1672012-04-06 09:46:29 -0700826 if n < 32:
827 self.match.nw_src = fi.rand_ip_addr() & ~((1 << n) - 1)
828 # Specifying any IP address match other than all bits
829 # don't care requires that Ethertype is one of {IP, ARP}
830 if flip_coin():
831 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700832 self.match.wildcards = wildcard_set(self.match.wildcards, \
833 ofp.OFPFW_DL_TYPE, \
834 0 \
835 )
rootf6af1672012-04-06 09:46:29 -0700836
Howard Pershc1199d52012-04-11 14:21:32 -0700837 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_DST_MASK)
838 if n == 0:
839 if exact or flip_coin():
840 n = 0
841 else:
842 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
843 if n > 32:
844 n = 32
845 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700846 self.match.wildcards = wildcard_set(self.match.wildcards, \
847 ofp.OFPFW_NW_DST_MASK, \
848 n \
849 )
rootf6af1672012-04-06 09:46:29 -0700850 if n < 32:
851 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
852 # Specifying any IP address match other than all bits
853 # don't care requires that Ethertype is one of {IP, ARP}
854 if flip_coin():
855 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700856 self.match.wildcards = wildcard_set(self.match.wildcards, \
857 ofp.OFPFW_DL_TYPE, \
858 0 \
859 )
rootf6af1672012-04-06 09:46:29 -0700860
Howard Pershc1199d52012-04-11 14:21:32 -0700861 if wildcard_get(wildcards_force, ofp.OFPFW_NW_TOS) == 0 \
862 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
863 or exact \
864 or flip_coin() \
865 ):
rootf6af1672012-04-06 09:46:29 -0700866 self.match.nw_tos = fi.rand_ip_tos()
867 # Specifying a TOS value requires that Ethertype is IP
868 if flip_coin():
869 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700870 self.match.wildcards = wildcard_set(self.match.wildcards, \
871 ofp.OFPFW_DL_TYPE, \
872 0 \
873 )
rootf6af1672012-04-06 09:46:29 -0700874 else:
Howard Persh3340d452012-04-06 16:45:21 -0700875 self.match.wildcards = wildcard_set(self.match.wildcards, \
876 ofp.OFPFW_NW_TOS, \
877 1 \
878 )
rootf6af1672012-04-06 09:46:29 -0700879
Dan Talayco910a8282012-04-07 00:05:20 -0700880 # Known issue on OVS with specifying nw_proto w/o dl_type as IP
Howard Pershc1199d52012-04-11 14:21:32 -0700881 if wildcard_get(wildcards_force, ofp.OFPFW_NW_PROTO) == 0 \
882 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
883 or exact \
884 or flip_coin() \
885 ):
Dan Talayco910a8282012-04-07 00:05:20 -0700886 self.match.nw_proto = fi.rand_ip_proto()
887 # Specifying an IP protocol requires that Ethertype is IP
888 if flip_coin():
889 self.match.dl_type = 0x0800
890 self.match.wildcards = wildcard_set(self.match.wildcards, \
891 ofp.OFPFW_DL_TYPE, \
892 0 \
893 )
894 else:
Howard Persh3340d452012-04-06 16:45:21 -0700895 self.match.wildcards = wildcard_set(self.match.wildcards, \
896 ofp.OFPFW_NW_PROTO, \
897 1 \
898 )
Dan Talayco910a8282012-04-07 00:05:20 -0700899
Howard Pershc1199d52012-04-11 14:21:32 -0700900 if wildcard_get(wildcards_force, ofp.OFPFW_TP_SRC) == 0 \
901 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
902 or exact\
903 or flip_coin() \
904 ):
rootf6af1672012-04-06 09:46:29 -0700905 self.match.tp_src = fi.rand_l4_port()
906 # Specifying a L4 port requires that IP protcol is
907 # one of {ICMP, TCP, UDP}
908 if flip_coin():
909 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700910 self.match.wildcards = wildcard_set(self.match.wildcards, \
911 ofp.OFPFW_NW_PROTO, \
912 0 \
913 )
rootf6af1672012-04-06 09:46:29 -0700914 # Specifying a L4 port requirues that Ethertype is IP
915 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700916 self.match.wildcards = wildcard_set(self.match.wildcards, \
917 ofp.OFPFW_DL_TYPE, \
918 0 \
919 )
rootf6af1672012-04-06 09:46:29 -0700920 if self.match.nw_proto == 1:
921 self.match.tp_src = self.match.tp_src & 0xff
922 else:
Howard Persh3340d452012-04-06 16:45:21 -0700923 self.match.wildcards = wildcard_set(self.match.wildcards, \
924 ofp.OFPFW_TP_SRC, \
925 1 \
926 )
rootf6af1672012-04-06 09:46:29 -0700927
Howard Pershc1199d52012-04-11 14:21:32 -0700928 if wildcard_get(wildcards_force, ofp.OFPFW_TP_DST) == 0 \
929 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
930 or exact \
931 or flip_coin() \
932 ):
rootf6af1672012-04-06 09:46:29 -0700933 self.match.tp_dst = fi.rand_l4_port()
934 # Specifying a L4 port requires that IP protcol is
935 # one of {ICMP, TCP, UDP}
936 if flip_coin():
937 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700938 self.match.wildcards = wildcard_set(self.match.wildcards, \
939 ofp.OFPFW_NW_PROTO, \
940 0 \
941 )
rootf6af1672012-04-06 09:46:29 -0700942 # Specifying a L4 port requirues that Ethertype is IP
943 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700944 self.match.wildcards = wildcard_set(self.match.wildcards, \
945 ofp.OFPFW_DL_TYPE, \
946 0 \
947 )
rootf6af1672012-04-06 09:46:29 -0700948 if self.match.nw_proto == 1:
949 self.match.tp_dst = self.match.tp_dst & 0xff
950 else:
Howard Persh3340d452012-04-06 16:45:21 -0700951 self.match.wildcards = wildcard_set(self.match.wildcards, \
952 ofp.OFPFW_TP_DST, \
953 1 \
954 )
rootf6af1672012-04-06 09:46:29 -0700955
956 # If nothing is wildcarded, it is an exact flow spec -- some switches
Howard Persh3340d452012-04-06 16:45:21 -0700957 # (Open vSwitch, for one) *require* that exact flow specs
958 # have priority 65535.
959 self.priority = 65535 if self.match.wildcards == 0 \
960 else fi.rand_priority()
rootf6af1672012-04-06 09:46:29 -0700961
962 # N.B. Don't make the timeout too short, else the flow might
963 # disappear before we get a chance to check for it.
964 t = random.randint(0, 65535)
965 self.idle_timeout = 0 if t < 60 else t
966 t = random.randint(0, 65535)
967 self.hard_timeout = 0 if t < 60 else t
968
Howard Persh8d21c1f2012-04-20 15:57:29 -0700969 self.rand_mod(fi, valid_actions, valid_ports, valid_queues)
rootf6af1672012-04-06 09:46:29 -0700970
971 return self
972
973 # Return flow cfg in canonical form
Howard Persh3340d452012-04-06 16:45:21 -0700974 # - There are dependencies between flow qualifiers, e.g. it only makes
975 # sense to qualify nw_proto if dl_type is qualified to be 0x0800 (IP).
976 # The canonical form of flow match criteria will "wildcard out"
977 # all such cases.
rootf6af1672012-04-06 09:46:29 -0700978 def canonical(self):
979 result = copy.deepcopy(self)
Howard Persh07d99e62012-04-09 15:26:57 -0700980
981 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_VLAN) != 0:
982 result.match.wildcards = wildcard_set(result.match.wildcards, \
983 ofp.OFPFW_DL_VLAN_PCP, \
984 1 \
985 )
986
rootf6af1672012-04-06 09:46:29 -0700987 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
988 or result.match.dl_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700989 # dl_tyoe is wildcarded, or specified as something other
990 # than IP or ARP
Howard Persh07d99e62012-04-09 15:26:57 -0700991 # => nw_src, nw_dst, nw_proto cannot be specified,
992 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700993 result.match.wildcards = wildcard_set(result.match.wildcards, \
994 ofp.OFPFW_NW_SRC_MASK, \
995 32 \
996 )
997 result.match.wildcards = wildcard_set(result.match.wildcards, \
998 ofp.OFPFW_NW_DST_MASK, \
999 32 \
1000 )
Howard Persh3340d452012-04-06 16:45:21 -07001001 result.match.wildcards = wildcard_set(result.match.wildcards, \
1002 ofp.OFPFW_NW_PROTO, \
1003 1 \
1004 )
Howard Persh07d99e62012-04-09 15:26:57 -07001005
1006 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
1007 or result.match.dl_type != 0x0800:
1008 # dl_type is wildcarded, or specified as something other than IP
1009 # => nw_tos, tp_src and tp_dst cannot be specified,
1010 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001011 result.match.wildcards = wildcard_set(result.match.wildcards, \
1012 ofp.OFPFW_NW_TOS, \
1013 1 \
1014 )
1015 result.match.wildcards = wildcard_set(result.match.wildcards, \
1016 ofp.OFPFW_TP_SRC, \
1017 1 \
1018 )
1019 result.match.wildcards = wildcard_set(result.match.wildcards, \
1020 ofp.OFPFW_TP_DST, \
1021 1 \
1022 )
Howard Persh07d99e62012-04-09 15:26:57 -07001023 result.match.wildcards = wildcard_set(result.match.wildcards, \
1024 ofp.OFPFW_NW_SRC_MASK, \
1025 32 \
1026 )
1027 result.match.wildcards = wildcard_set(result.match.wildcards, \
1028 ofp.OFPFW_NW_DST_MASK, \
1029 32 \
1030 )
1031 result.match.wildcards = wildcard_set(result.match.wildcards, \
1032 ofp.OFPFW_NW_PROTO, \
1033 1 \
1034 )
1035
rootf6af1672012-04-06 09:46:29 -07001036 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
1037 or result.match.nw_proto not in [1, 6, 17]:
Howard Persh3340d452012-04-06 16:45:21 -07001038 # nw_proto is wildcarded, or specified as something other than ICMP,
1039 # TCP or UDP
rootf6af1672012-04-06 09:46:29 -07001040 # => tp_src and tp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001041 result.match.wildcards = wildcard_set(result.match.wildcards, \
1042 ofp.OFPFW_TP_SRC, \
1043 1 \
1044 )
1045 result.match.wildcards = wildcard_set(result.match.wildcards, \
1046 ofp.OFPFW_TP_DST, \
1047 1 \
1048 )
rootf6af1672012-04-06 09:46:29 -07001049 return result
1050
Howard Persh680b92a2012-03-31 13:34:35 -07001051 # Overlap check
1052 # delf == True <=> Check for delete overlap, else add overlap
1053 # "Add overlap" is defined as there exists a packet that could match both the
1054 # receiver and argument flowspecs
1055 # "Delete overlap" is defined as the specificity of the argument flowspec
1056 # is greater than or equal to the specificity of the receiver flowspec
1057 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -07001058 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
1059 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001060 if self.match.in_port != x.match.in_port:
1061 return False # Both specified, and not equal
1062 elif delf:
1063 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001064 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
1065 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001066 if self.match.dl_vlan != x.match.dl_vlan:
1067 return False # Both specified, and not equal
1068 elif delf:
1069 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001070 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
1071 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001072 if self.match.dl_src != x.match.dl_src:
1073 return False # Both specified, and not equal
1074 elif delf:
1075 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001076 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
1077 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001078 if self.match.dl_dst != x.match.dl_dst:
1079 return False # Both specified, and not equal
1080 elif delf:
1081 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001082 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
1083 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001084 if self.match.dl_type != x.match.dl_type:
1085 return False # Both specified, and not equal
1086 elif delf:
1087 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -07001088 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
1089 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001090 if self.match.nw_proto != x.match.nw_proto:
1091 return False # Both specified, and not equal
1092 elif delf:
1093 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001094 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
1095 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001096 if self.match.tp_src != x.match.tp_src:
1097 return False # Both specified, and not equal
1098 elif delf:
1099 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001100 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
1101 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001102 if self.match.tp_dst != x.match.tp_dst:
1103 return False # Both specified, and not equal
1104 elif delf:
1105 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001106 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
1107 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001108 if delf and na < nb:
1109 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001110 if (na < 32 and nb < 32):
1111 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1112 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -07001113 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -07001114 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
1115 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_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_dst & m) != (x.match.nw_dst & m):
rootf6af1672012-04-06 09:46:29 -07001121 return False # Overlapping bits not equal
1122 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
1123 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001124 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
1125 return False # Both specified, and not equal
1126 elif delf:
1127 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001128 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
1129 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001130 if self.match.nw_tos != x.match.nw_tos:
1131 return False # Both specified, and not equal
1132 elif delf:
1133 return False # Receiver more specific
1134 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -07001135
1136 def to_flow_mod_msg(self, msg):
1137 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -07001138 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001139 msg.idle_timeout = self.idle_timeout
1140 msg.hard_timeout = self.hard_timeout
1141 msg.priority = self.priority
1142 msg.actions = self.actions
1143 return msg
1144
1145 def from_flow_stat(self, msg):
1146 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -07001147 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001148 self.idle_timeout = msg.idle_timeout
1149 self.hard_timeout = msg.hard_timeout
1150 self.priority = msg.priority
1151 self.actions = msg.actions
1152
rootf6af1672012-04-06 09:46:29 -07001153 def from_flow_rem(self, msg):
1154 self.match = msg.match
1155 self.idle_timeout = msg.idle_timeout
1156 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -07001157
Howard Pershc7963582012-03-29 10:02:59 -07001158
rootf6af1672012-04-06 09:46:29 -07001159class Flow_Tbl:
1160 def clear(self):
1161 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001162
rootf6af1672012-04-06 09:46:29 -07001163 def __init__(self):
1164 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001165
rootf6af1672012-04-06 09:46:29 -07001166 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001167 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001168
1169 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001170 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001171
1172 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001173 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001174
1175 def values(self):
1176 return self.dict.values()
1177
1178 def count(self):
1179 return len(self.dict)
1180
1181 def rand(self, sw, fi, num_flows):
1182 self.clear()
1183 i = 0
1184 tbl = 0
1185 j = 0
1186 while i < num_flows:
1187 fc = Flow_Cfg()
1188 fc.rand(fi, \
1189 sw.tbl_stats.stats[tbl].wildcards, \
1190 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001191 sw.valid_ports, \
1192 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001193 )
1194 fc = fc.canonical()
1195 if self.find(fc):
1196 continue
1197 fc.send_rem = False
1198 self.insert(fc)
1199 i = i + 1
1200 j = j + 1
1201 if j >= sw.tbl_stats.stats[tbl].max_entries:
1202 tbl = tbl + 1
1203 j = 0
1204
1205
Howard Persh3340d452012-04-06 16:45:21 -07001206error_msgs = []
1207removed_msgs = []
1208
1209def error_handler(self, msg, rawmsg):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001210 fq_logger.info("Got an ERROR message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001211 % (msg.type, msg.code) \
1212 )
Howard Persh5f3c83f2012-04-13 09:57:10 -07001213 fq_logger.info("Message header:")
1214 fq_logger.info(msg.header.show())
Howard Persh3340d452012-04-06 16:45:21 -07001215 global error_msgs
1216 error_msgs.append(msg)
1217 pass
1218
1219def removed_handler(self, msg, rawmsg):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001220 fq_logger.info("Got a REMOVED message")
1221 fq_logger.info("Message header:")
1222 fq_logger.info(msg.header.show())
Howard Persh3340d452012-04-06 16:45:21 -07001223 global removed_msgs
1224 removed_msgs.append(msg)
1225 pass
1226
rootf6af1672012-04-06 09:46:29 -07001227class Switch:
1228 # Members:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001229 # controller - switch's test controller
1230 # sw_features - switch's OFPT_FEATURES_REPLY message
1231 # valid_ports - list of valid port numbers
1232 # valid_queues - list of valid [port, queue] pairs
1233 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1234 # queue_stats - switch's OFPT_STATS_REPLY message, for queue stats request
1235 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1236 # flow_tbl - (test's idea of) switch's flow table
rootf6af1672012-04-06 09:46:29 -07001237
1238 def __init__(self):
Howard Persh8d21c1f2012-04-20 15:57:29 -07001239 self.controller = None
1240 self.sw_features = None
1241 self.valid_ports = []
1242 self.valid_queues = []
1243 self.tbl_stats = None
1244 self.flow_stats = None
1245 self.flow_tbl = Flow_Tbl()
rootf6af1672012-04-06 09:46:29 -07001246
Howard Persh3340d452012-04-06 16:45:21 -07001247 def controller_set(self, controller):
1248 self.controller = controller
1249 # Register error message handler
1250 global error_msgs
1251 error_msgs = []
1252 controller.register(ofp.OFPT_ERROR, error_handler)
1253 controller.register(ofp.OFPT_FLOW_REMOVED, removed_handler)
1254
rootf6af1672012-04-06 09:46:29 -07001255 def features_get(self):
1256 # Get switch features
1257 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001258 (self.sw_features, pkt) = self.controller.transact(request)
rootf6af1672012-04-06 09:46:29 -07001259 if self.sw_features is None:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001260 fq_logger.error("Get switch features failed")
rootf6af1672012-04-06 09:46:29 -07001261 return False
1262 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001263 fq_logger.info("Ports reported by switch:")
1264 fq_logger.info(self.valid_ports)
1265 ports_override = test_param_get(fq_config, "ports", [])
1266 if ports_override != []:
1267 fq_logger.info("Overriding ports to:")
1268 fq_logger.info(ports_override)
1269 self.valid_ports = ports_override
1270
Howard Persh3340d452012-04-06 16:45:21 -07001271 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1272 # is that universal?
1273
1274 # TBD - There seems to be variability in which switches support which
1275 # ports; need to sort that out
1276 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1277# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1278# ofp.OFPP_NORMAL, \
1279# ofp.OFPP_FLOOD, \
1280# ofp.OFPP_ALL, \
1281# ofp.OFPP_CONTROLLER \
1282# ] \
1283# )
Howard Persh8d21c1f2012-04-20 15:57:29 -07001284 fq_logger.info("Supported actions reported by switch:")
1285 fq_logger.info("0x%x=%s" \
1286 % (self.sw_features.actions, \
1287 actions_bmap_to_str(self.sw_features.actions) \
1288 ) \
1289 )
Howard Persh07d99e62012-04-09 15:26:57 -07001290 actions_override = test_param_get(fq_config, "actions", -1)
1291 if actions_override != -1:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001292 fq_logger.info("Overriding supported actions to:")
1293 fq_logger.info(actions_bmap_to_str(actions_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001294 self.sw_features.actions = actions_override
rootf6af1672012-04-06 09:46:29 -07001295 return True
1296
1297 def tbl_stats_get(self):
1298 # Get table stats
Howard Persh680b92a2012-03-31 13:34:35 -07001299 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001300 (self.tbl_stats, pkt) = self.controller.transact(request)
Howard Persh07d99e62012-04-09 15:26:57 -07001301 if self.tbl_stats is None:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001302 fq_logger.error("Get table stats failed")
Howard Persh07d99e62012-04-09 15:26:57 -07001303 return False
Howard Persh8d21c1f2012-04-20 15:57:29 -07001304 i = 0
Howard Persh07d99e62012-04-09 15:26:57 -07001305 for ts in self.tbl_stats.stats:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001306 fq_logger.info("Supported wildcards for table %d reported by switch:"
1307 % (i)
1308 )
1309 fq_logger.info("0x%x=%s" \
1310 % (ts.wildcards, \
1311 wildcards_to_str(ts.wildcards) \
1312 ) \
1313 )
Howard Persh07d99e62012-04-09 15:26:57 -07001314 wildcards_override = test_param_get(fq_config, "wildcards", -1)
1315 if wildcards_override != -1:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001316 fq_logger.info("Overriding supported wildcards for table %d to:"
1317 % (i)
1318 )
1319 fq_logger.info(wildcards_to_str(wildcards_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001320 ts.wildcards = wildcards_override
Howard Persh8d21c1f2012-04-20 15:57:29 -07001321 i = i + 1
Howard Persh07d99e62012-04-09 15:26:57 -07001322 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001323
Howard Persh8d21c1f2012-04-20 15:57:29 -07001324 def queue_stats_get(self):
1325 # Get queue stats
1326 request = message.queue_stats_request()
1327 request.port_no = ofp.OFPP_ALL
1328 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001329 (self.queue_stats, pkt) = self.controller.transact(request)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001330 if self.queue_stats is None:
1331 fq_logger.error("Get queue stats failed")
1332 return False
1333 self.valid_queues = map(lambda x: (x.port_no, x.queue_id), \
1334 self.queue_stats.stats \
1335 )
1336 fq_logger.info("(Port, queue) pairs reported by switch:")
1337 fq_logger.info(self.valid_queues)
1338 queues_override = test_param_get(fq_config, "queues", [])
1339 if queues_override != []:
1340 fq_logger.info("Overriding (port, queue) pairs to:")
1341 fq_logger.info(queues_override)
1342 self.valid_queues = queues_override
1343 return True
1344
1345 def connect(self, controller):
1346 # Connect to controller, and get all switch capabilities
1347 self.controller_set(controller)
1348 return (self.features_get() \
1349 and self.tbl_stats_get() \
1350 and self.queue_stats_get() \
1351 )
1352
Howard Pershc1199d52012-04-11 14:21:32 -07001353 def flow_stats_get(self, limit = 10000):
rootf6af1672012-04-06 09:46:29 -07001354 request = message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -07001355 query_match = ofp.ofp_match()
1356 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001357 request.match = query_match
1358 request.table_id = 0xff
1359 request.out_port = ofp.OFPP_NONE;
Howard Persh3340d452012-04-06 16:45:21 -07001360 if self.controller.message_send(request) == -1:
1361 return False
1362 # <TBD>
1363 # Glue together successive reponse messages for stats reply.
1364 # Looking at the "more" flag and performing re-assembly
1365 # should be a part of the infrastructure.
1366 # </TBD>
1367 n = 0
1368 while True:
Howard Persh07d99e62012-04-09 15:26:57 -07001369 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY, 4)
Howard Persh3340d452012-04-06 16:45:21 -07001370 if resp is None:
Howard Pershc1199d52012-04-11 14:21:32 -07001371 return False # Did not get expected response
Howard Persh3340d452012-04-06 16:45:21 -07001372 if n == 0:
1373 self.flow_stats = resp
1374 else:
1375 self.flow_stats.stats.extend(resp.stats)
1376 n = n + 1
Howard Pershc1199d52012-04-11 14:21:32 -07001377 if len(self.flow_stats.stats) > limit:
1378 fq_logger.error("Too many flows returned")
1379 return False
1380 if (resp.flags & 1) == 0:
1381 break # No more responses expected
Howard Persh3340d452012-04-06 16:45:21 -07001382 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001383
rootf6af1672012-04-06 09:46:29 -07001384 def flow_add(self, flow_cfg, overlapf = False):
Howard Persh680b92a2012-03-31 13:34:35 -07001385 flow_mod_msg = message.flow_mod()
1386 flow_mod_msg.command = ofp.OFPFC_ADD
1387 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001388 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001389 if overlapf:
1390 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001391 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001392 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Howard Persh07d99e62012-04-09 15:26:57 -07001393 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001394 fq_logger.info("Sending flow_mod(add), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001395 % (flow_mod_msg.header.xid)
1396 )
rootf6af1672012-04-06 09:46:29 -07001397 return (self.controller.message_send(flow_mod_msg) != -1)
Howard Persh680b92a2012-03-31 13:34:35 -07001398
rootf6af1672012-04-06 09:46:29 -07001399 def flow_mod(self, flow_cfg, strictf):
Howard Persh680b92a2012-03-31 13:34:35 -07001400 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001401 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf \
1402 else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -07001403 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001404 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001405 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001406 fq_logger.info("Sending flow_mod(mod), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001407 % (flow_mod_msg.header.xid)
1408 )
rootf6af1672012-04-06 09:46:29 -07001409 return (self.controller.message_send(flow_mod_msg) != -1)
1410
1411 def flow_del(self, flow_cfg, strictf):
1412 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001413 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf \
1414 else ofp.OFPFC_DELETE
rootf6af1672012-04-06 09:46:29 -07001415 flow_mod_msg.buffer_id = 0xffffffff
1416 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001417 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001418 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001419 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001420 fq_logger.info("Sending flow_mod(del), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001421 % (flow_mod_msg.header.xid)
1422 )
rootf6af1672012-04-06 09:46:29 -07001423 return (self.controller.message_send(flow_mod_msg) != -1)
1424
1425 def barrier(self):
1426 barrier = message.barrier_request()
Howard Persh07d99e62012-04-09 15:26:57 -07001427 (resp, pkt) = self.controller.transact(barrier, 20)
rootf6af1672012-04-06 09:46:29 -07001428 return (resp is not None)
1429
Howard Persh3340d452012-04-06 16:45:21 -07001430 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001431 result = True
Howard Persh3340d452012-04-06 16:45:21 -07001432 global error_msgs
Howard Persh5f3c83f2012-04-13 09:57:10 -07001433 fq_logger.info("Expecting %d error messages" % (num_exp))
Howard Persh3340d452012-04-06 16:45:21 -07001434 num_got = len(error_msgs)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001435 fq_logger.info("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001436 if num_got != num_exp:
Dan Talayco910a8282012-04-07 00:05:20 -07001437 fq_logger.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001438 result = False
1439 if num_exp == 0:
1440 return result
1441 elif num_exp == 1:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001442 fq_logger.info("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001443 % (type, code) \
1444 )
1445 f = False
1446 for e in error_msgs:
1447 if e.type == type and e.code == code:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001448 fq_logger.info("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001449 f = True
1450 if not f:
Dan Talayco910a8282012-04-07 00:05:20 -07001451 fq_logger.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001452 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001453 else:
Dan Talayco910a8282012-04-07 00:05:20 -07001454 fq_logger.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001455 result = False
1456 return result
1457
Howard Persh3340d452012-04-06 16:45:21 -07001458 def removed_verify(self, num_exp):
1459 result = True
1460 global removed_msgs
Howard Persh5f3c83f2012-04-13 09:57:10 -07001461 fq_logger.info("Expecting %d removed messages" % (num_exp))
Howard Persh3340d452012-04-06 16:45:21 -07001462 num_got = len(removed_msgs)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001463 fq_logger.info("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001464 if num_got != num_exp:
Dan Talayco910a8282012-04-07 00:05:20 -07001465 fq_logger.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001466 result = False
1467 if num_exp < 2:
1468 return result
Dan Talayco910a8282012-04-07 00:05:20 -07001469 fq_logger.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001470 return False
1471
Howard Persh5f3c83f2012-04-13 09:57:10 -07001472 # modf == True <=> Verify for flow modify, else for add/delete
1473 def flow_tbl_verify(self, modf = False):
rootf6af1672012-04-06 09:46:29 -07001474 result = True
1475
1476 # Verify flow count in switch
Howard Persh5f3c83f2012-04-13 09:57:10 -07001477 fq_logger.info("Reading table stats")
1478 fq_logger.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001479 if not self.tbl_stats_get():
Dan Talayco910a8282012-04-07 00:05:20 -07001480 fq_logger.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001481 return False
1482 n = 0
1483 for ts in self.tbl_stats.stats:
1484 n = n + ts.active_count
Howard Persh5f3c83f2012-04-13 09:57:10 -07001485 fq_logger.info("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001486 % (n) \
1487 )
1488 if n != self.flow_tbl.count():
Dan Talayco910a8282012-04-07 00:05:20 -07001489 fq_logger.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001490 result = False
1491
1492 # Read flows from switch
Howard Persh5f3c83f2012-04-13 09:57:10 -07001493 fq_logger.info("Retrieving flows from switch")
1494 fq_logger.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001495 if not self.flow_stats_get():
Dan Talayco910a8282012-04-07 00:05:20 -07001496 fq_logger.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001497 return False
Howard Persh5f3c83f2012-04-13 09:57:10 -07001498 fq_logger.info("Retrieved %d flows" % (len(self.flow_stats.stats)))
rootf6af1672012-04-06 09:46:29 -07001499
1500 # Verify flows returned by switch
1501
1502 if len(self.flow_stats.stats) != self.flow_tbl.count():
Dan Talayco910a8282012-04-07 00:05:20 -07001503 fq_logger.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001504 result = False
1505
Howard Persh5f3c83f2012-04-13 09:57:10 -07001506 fq_logger.info("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001507 for fc in self.flow_tbl.values():
1508 fc.matched = False
1509 for fs in self.flow_stats.stats:
1510 flow_in = Flow_Cfg()
1511 flow_in.from_flow_stat(fs)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001512 fq_logger.info("Received flow:")
1513 fq_logger.info(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001514 fc = self.flow_tbl.find(flow_in)
1515 if fc is None:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001516 fq_logger.error("Received flow:")
1517 fq_logger.error(str(flow_in))
Dan Talayco910a8282012-04-07 00:05:20 -07001518 fq_logger.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001519 result = False
1520 elif fc.matched:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001521 fq_logger.error("Received flow:")
1522 fq_logger.error(str(flow_in))
Dan Talayco910a8282012-04-07 00:05:20 -07001523 fq_logger.error("re-matches defined flow:")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001524 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001525 result = False
1526 else:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001527 fq_logger.info("matched")
1528 if modf:
1529 # Check for modify
1530
1531 if flow_in.cookie != fc.cookie:
1532 fq_logger.warning("Defined flow:")
1533 fq_logger.warning(str(fc))
1534 fq_logger.warning("Received flow:")
1535 fq_logger.warning(str(flow_in))
1536 fq_logger.warning("cookies do not match")
1537 if not flow_in.actions_equal(fc):
1538 fq_logger.error("Defined flow:")
1539 fq_logger.error(str(fc))
1540 fq_logger.error("Received flow:")
1541 fq_logger.error(str(flow_in))
1542 fq_logger.error("actions do not match")
1543 else:
1544 # Check for add/delete
1545
1546 if not flow_in == fc:
1547 fq_logger.error("Defined flow:")
1548 fq_logger.error(str(fc))
1549 fq_logger.error("Received flow:")
1550 fq_logger.error(str(flow_in))
1551 fq_logger.error("non-key portions of flow do not match")
1552 result = False
rootf6af1672012-04-06 09:46:29 -07001553 fc.matched = True
1554 for fc in self.flow_tbl.values():
1555 if not fc.matched:
Dan Talayco910a8282012-04-07 00:05:20 -07001556 fq_logger.error("Defined flow:")
1557 fq_logger.error(str(fc))
1558 fq_logger.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001559 result = False
1560
1561 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001562
Howard Persh07d99e62012-04-09 15:26:57 -07001563# FLOW ADD 5
1564#
1565# OVERVIEW
1566# Add flows to switch, read back and verify flow configurations
1567#
1568# PURPOSE
1569# - Test acceptance of flow adds
1570# - Test ability of switch to process additions to flow table in random
1571# priority order
1572# - Test correctness of flow configuration responses
1573#
1574# PARAMETERS
1575#
1576# Name: num_flows
1577# Type: number
1578# Description:
1579# Number of flows to define; 0 => maximum number of flows, as determined
1580# from switch capabilities
1581# Default: 100
1582#
1583# PROCESS
1584# 1. Delete all flows from switch
1585# 2. Generate <num_flows> distinct flow configurations
1586# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1587# 4. Verify that no OFPT_ERROR responses were generated by switch
1588# 5. Retrieve flow stats from switch
1589# 6. Compare flow configurations returned by switch
1590# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1591# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001592
rootf6af1672012-04-06 09:46:29 -07001593class Flow_Add_5(basic.SimpleProtocol):
1594 """
1595 Test FLOW_ADD_5 from draft top-half test plan
1596
1597 INPUTS
1598 num_flows - Number of flows to generate
1599 """
Howard Persh680b92a2012-03-31 13:34:35 -07001600
rootf6af1672012-04-06 09:46:29 -07001601 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001602 fq_logger.info("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001603
Dan Talayco910a8282012-04-07 00:05:20 -07001604 num_flows = test_param_get(fq_config, "num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001605
Howard Pershc7963582012-03-29 10:02:59 -07001606 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001607
Howard Persh5f3c83f2012-04-13 09:57:10 -07001608 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001609 rc = delete_all_flows(self.controller, fq_logger)
Howard Pershc7963582012-03-29 10:02:59 -07001610 self.assertEqual(rc, 0, "Failed to delete all flows")
1611
rootf6af1672012-04-06 09:46:29 -07001612 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001613
rootf6af1672012-04-06 09:46:29 -07001614 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001615 self.assertTrue(sw.connect(self.controller), \
1616 "Failed to connect to switch" \
1617 )
Howard Pershc7963582012-03-29 10:02:59 -07001618
rootf6af1672012-04-06 09:46:29 -07001619 if num_flows == 0:
1620 # Number of flows requested was 0
1621 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001622
rootf6af1672012-04-06 09:46:29 -07001623 for ts in sw.tbl_stats.stats:
1624 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001625
Howard Persh5f3c83f2012-04-13 09:57:10 -07001626 fq_logger.info("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001627
1628 # Dream up some flow information, i.e. space to chose from for
1629 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001630
rootf6af1672012-04-06 09:46:29 -07001631 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001632 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001633
rootf6af1672012-04-06 09:46:29 -07001634 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001635
rootf6af1672012-04-06 09:46:29 -07001636 ft = Flow_Tbl()
1637 ft.rand(sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001638
rootf6af1672012-04-06 09:46:29 -07001639 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001640
Howard Persh5f3c83f2012-04-13 09:57:10 -07001641 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001642 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07001643 fq_logger.info("Adding flow:")
1644 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001645 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001646
rootf6af1672012-04-06 09:46:29 -07001647 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001648
rootf6af1672012-04-06 09:46:29 -07001649 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001650
rootf6af1672012-04-06 09:46:29 -07001651 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001652
rootf6af1672012-04-06 09:46:29 -07001653 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001654
rootf6af1672012-04-06 09:46:29 -07001655 if not sw.errors_verify(0):
1656 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001657
rootf6af1672012-04-06 09:46:29 -07001658 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001659
rootf6af1672012-04-06 09:46:29 -07001660 sw.flow_tbl = ft
1661 if not sw.flow_tbl_verify():
1662 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001663
rootf6af1672012-04-06 09:46:29 -07001664 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001665 fq_logger.info("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001666
Howard Pershc7963582012-03-29 10:02:59 -07001667
Howard Persh07d99e62012-04-09 15:26:57 -07001668# FLOW ADD 5_1
1669#
1670# OVERVIEW
1671# Verify handling of non-canonical flows
1672#
1673# PURPOSE
1674# - Test that switch detects and correctly responds to a non-canonical flow
1675# definition. A canonical flow is one that satisfies all match qualifier
1676# dependencies; a non-canonical flow is one that does not.
1677#
1678# PARAMETERS
1679# - None
1680#
1681# PROCESS
1682# 1. Delete all flows from switch
1683# 2. Generate 1 flow definition, which is different from its canonicalization
1684# 3. Send flow to switch
1685# 4. Retrieve flow from switch
1686# 5. Compare returned flow to canonical form of defined flow
1687# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1688
1689# Disabled.
1690# Should be DUT dependent.
1691test_prio["Flow_Add_5_1"] = -1
1692
rootf6af1672012-04-06 09:46:29 -07001693class Flow_Add_5_1(basic.SimpleProtocol):
1694 """
1695 Test FLOW_ADD_5.1 from draft top-half test plan
1696
1697 INPUTS
1698 None
1699 """
1700
1701 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001702 fq_logger.info("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001703
Dan Talayco910a8282012-04-07 00:05:20 -07001704 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001705
1706 # Clear all flows from switch
1707
Howard Persh5f3c83f2012-04-13 09:57:10 -07001708 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001709 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001710 self.assertEqual(rc, 0, "Failed to delete all flows")
1711
1712 # Get switch capabilites
1713
rootf6af1672012-04-06 09:46:29 -07001714 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001715 self.assertTrue(sw.connect(self.controller), \
1716 "Failed to connect to switch" \
1717 )
rootf6af1672012-04-06 09:46:29 -07001718
1719 # Dream up some flow information, i.e. space to chose from for
1720 # random flow parameter generation
1721
1722 fi = Flow_Info()
1723 fi.rand(10)
1724
1725 # Dream up a flow config that will be canonicalized by the switch
1726
1727 while True:
1728 fc = Flow_Cfg()
1729 fc.rand(fi, \
1730 sw.tbl_stats.stats[0].wildcards, \
1731 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001732 sw.valid_ports, \
1733 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001734 )
1735 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001736 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001737 break
1738
1739 ft = Flow_Tbl()
1740 ft.insert(fcc)
1741
1742 # Send it to the switch
1743
Howard Persh5f3c83f2012-04-13 09:57:10 -07001744 fq_logger.info("Sending flow add to switch:")
1745 fq_logger.info(str(fc))
1746 fq_logger.info("should be canonicalized as:")
1747 fq_logger.info(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001748 fc.send_rem = False
1749 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1750
1751 # Do barrier, to make sure all flows are in
1752
1753 self.assertTrue(sw.barrier(), "Barrier failed")
1754
1755 result = True
1756
1757 # Check for any error messages
1758
1759 if not sw.errors_verify(0):
1760 result = False
1761
1762 # Verify flow table
1763
1764 sw.flow_tbl = ft
1765 if not sw.flow_tbl_verify():
1766 result = False
1767
1768 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001769 fq_logger.info("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001770
1771
Howard Persh07d99e62012-04-09 15:26:57 -07001772# FLOW ADD 6
1773#
1774# OVERVIEW
1775# Test flow table capacity
1776#
1777# PURPOSE
1778# - Test switch can accept as many flow definitions as it claims
1779# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1780# - Test that attempting to create flows beyond capacity does not corrupt
1781# flow table
1782#
1783# PARAMETERS
1784# None
1785#
1786# PROCESS
1787# 1. Delete all flows from switch
1788# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1789# to determine flow table size, N
1790# 3. Generate (N + 1) distinct flow configurations
1791# 4. Send N flow adds to switch, for flows generated in step 3 above
1792# 5. Verify flow table in switch
1793# 6. Send one more flow add to switch
1794# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1795# response was generated by switch, for last flow mod sent
1796# 7. Retrieve flow stats from switch
1797# 8. Verify flow table in switch
1798# 9. Test PASSED iff:
1799# - error message received, for correct flow
1800# - last flow definition sent to switch is not in flow table
1801# else test FAILED
1802
Howard Persh3340d452012-04-06 16:45:21 -07001803# Disabled because of bogus capacity reported by OVS.
1804# Should be DUT dependent.
1805test_prio["Flow_Add_6"] = -1
1806
rootf6af1672012-04-06 09:46:29 -07001807class Flow_Add_6(basic.SimpleProtocol):
1808 """
1809 Test FLOW_ADD_6 from draft top-half test plan
1810
1811 INPUTS
1812 num_flows - Number of flows to generate
1813 """
Howard Pershc7963582012-03-29 10:02:59 -07001814
1815 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001816 fq_logger.info("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001817
rootf6af1672012-04-06 09:46:29 -07001818 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001819
Howard Persh5f3c83f2012-04-13 09:57:10 -07001820 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001821 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001822 self.assertEqual(rc, 0, "Failed to delete all flows")
1823
1824 # Get switch capabilites
1825
rootf6af1672012-04-06 09:46:29 -07001826 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001827 self.assertTrue(sw.connect(self.controller), \
1828 "Failed to connect to switch" \
1829 )
rootf6af1672012-04-06 09:46:29 -07001830
root2843d2b2012-04-06 10:27:46 -07001831 num_flows = 0
rootf6af1672012-04-06 09:46:29 -07001832 for ts in sw.tbl_stats.stats:
1833 num_flows = num_flows + ts.max_entries
1834
Howard Persh5f3c83f2012-04-13 09:57:10 -07001835 fq_logger.info("Switch capacity is %d flows" % (num_flows))
1836 fq_logger.info("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001837
1838 # Dream up some flow information, i.e. space to chose from for
1839 # random flow parameter generation
1840
1841 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001842 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001843
1844 # Create a flow table, to switch's capacity
1845
1846 ft = Flow_Tbl()
1847 ft.rand(sw, fi, num_flows)
1848
1849 # Send flow table to switch
1850
Howard Persh5f3c83f2012-04-13 09:57:10 -07001851 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001852 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07001853 fq_logger.info("Adding flow:")
1854 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001855 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1856
1857 # Do barrier, to make sure all flows are in
1858
1859 self.assertTrue(sw.barrier(), "Barrier failed")
1860
1861 result = True
1862
1863 # Check for any error messages
1864
1865 if not sw.errors_verify(0):
1866 result = False
1867
1868 # Dream up one more flow
1869
Howard Persh5f3c83f2012-04-13 09:57:10 -07001870 fq_logger.info("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001871 while True:
1872 fc = Flow_Cfg()
1873 fc.rand(fi, \
Howard Persh07d99e62012-04-09 15:26:57 -07001874 sw.tbl_stats.stats[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001875 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001876 sw.valid_ports, \
1877 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001878 )
1879 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001880 if not ft.find(fc):
1881 break
rootf6af1672012-04-06 09:46:29 -07001882
1883 # Send one-more flow
1884
1885 fc.send_rem = False
Howard Persh5f3c83f2012-04-13 09:57:10 -07001886 fq_logger.info("Sending flow add switch")
1887 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001888 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1889
1890 # Do barrier, to make sure all flows are in
1891
1892 self.assertTrue(sw.barrier(), "Barrier failed")
1893
1894 # Check for expected error message
1895
1896 if not sw.errors_verify(1, \
1897 ofp.OFPET_FLOW_MOD_FAILED, \
1898 ofp.OFPFMFC_ALL_TABLES_FULL \
1899 ):
1900 result = False
1901
1902 # Verify flow table
1903
1904 sw.flow_tbl = ft
1905 if not sw.flow_tbl_verify():
1906 result = False
1907
1908 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001909 fq_logger.info("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001910
1911
Howard Persh07d99e62012-04-09 15:26:57 -07001912# FLOW ADD 7
1913#
1914# OVERVIEW
1915# Test flow redefinition
1916#
1917# PURPOSE
1918# Verify that successive flow adds with same priority and match criteria
1919# overwrite in flow table
1920#
1921# PARAMETERS
1922# None
1923#
1924# PROCESS
1925# 1. Delete all flows from switch
1926# 2. Generate flow definition F1
1927# 3. Generate flow definition F2, with same key (priority and match) as F1,
1928# but with different actions
1929# 4. Send flow adds for F1 and F2 to switch
1930# 5. Verify flow definitions in switch
1931# 6. Test PASSED iff 1 flow returned by switch, matching configuration of F2;
1932# else test FAILED
1933
rootf6af1672012-04-06 09:46:29 -07001934class Flow_Add_7(basic.SimpleProtocol):
1935 """
1936 Test FLOW_ADD_7 from draft top-half test plan
1937
1938 INPUTS
1939 None
1940 """
1941
1942 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001943 fq_logger.info("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001944
1945 # Clear all flows from switch
1946
Howard Persh5f3c83f2012-04-13 09:57:10 -07001947 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001948 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001949 self.assertEqual(rc, 0, "Failed to delete all flows")
1950
1951 # Get switch capabilites
1952
rootf6af1672012-04-06 09:46:29 -07001953 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001954 self.assertTrue(sw.connect(self.controller), \
1955 "Failed to connect to switch" \
1956 )
rootf6af1672012-04-06 09:46:29 -07001957
1958 # Dream up some flow information, i.e. space to chose from for
1959 # random flow parameter generation
1960
1961 fi = Flow_Info()
1962 fi.rand(10)
1963
1964 # Dream up a flow config
1965
1966 fc = Flow_Cfg()
1967 fc.rand(fi, \
1968 sw.tbl_stats.stats[0].wildcards, \
1969 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001970 sw.valid_ports, \
1971 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001972 )
1973 fc = fc.canonical()
1974
1975 # Send it to the switch
1976
Howard Persh5f3c83f2012-04-13 09:57:10 -07001977 fq_logger.info("Sending flow add to switch:")
1978 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001979 ft = Flow_Tbl()
1980 fc.send_rem = False
1981 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1982 ft.insert(fc)
1983
1984 # Dream up some different actions, with the same flow key
1985
1986 fc2 = copy.deepcopy(fc)
1987 while True:
1988 fc2.rand_mod(fi, \
1989 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001990 sw.valid_ports, \
1991 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001992 )
1993 if fc2 != fc:
1994 break
1995
1996 # Send that to the switch
1997
Howard Persh5f3c83f2012-04-13 09:57:10 -07001998 fq_logger.info("Sending flow add to switch:")
1999 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002000 fc2.send_rem = False
2001 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
2002 ft.insert(fc2)
2003
2004 # Do barrier, to make sure all flows are in
2005
2006 self.assertTrue(sw.barrier(), "Barrier failed")
2007
2008 result = True
2009
2010 # Check for any error messages
2011
2012 if not sw.errors_verify(0):
2013 result = False
2014
2015 # Verify flow table
2016
2017 sw.flow_tbl = ft
2018 if not sw.flow_tbl_verify():
2019 result = False
2020
2021 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002022 fq_logger.info("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002023
2024
Howard Persh07d99e62012-04-09 15:26:57 -07002025# FLOW ADD 8
2026#
2027# OVERVIEW
2028# Add overlapping flows to switch, verify that overlapping flows are rejected
2029#
2030# PURPOSE
2031# - Test detection of overlapping flows by switch
2032# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
2033# - Test rejection of overlapping flows
2034# - Test defining overlapping flows does not corrupt flow table
2035#
2036# PARAMETERS
2037# None
2038#
2039# PROCESS
2040# 1. Delete all flows from switch
2041# 2. Generate flow definition F1
2042# 3. Generate flow definition F2, with key overlapping F1
2043# 4. Send flow add to switch, for F1
2044# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
2045# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
2046# was generated by switch
2047# 7. Verifiy flows configured in swtich
2048# 8. Test PASSED iff:
2049# - error message received, for overlapping flow
2050# - overlapping flow is not in flow table
2051# else test FAILED
2052
rootf6af1672012-04-06 09:46:29 -07002053class Flow_Add_8(basic.SimpleProtocol):
2054 """
2055 Test FLOW_ADD_8 from draft top-half test plan
2056
2057 INPUTS
2058 None
2059 """
2060
2061 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002062 fq_logger.info("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002063
2064 # Clear all flows from switch
2065
Howard Persh5f3c83f2012-04-13 09:57:10 -07002066 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002067 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002068 self.assertEqual(rc, 0, "Failed to delete all flows")
2069
2070 # Get switch capabilites
2071
rootf6af1672012-04-06 09:46:29 -07002072 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002073 self.assertTrue(sw.connect(self.controller), \
2074 "Failed to connect to switch" \
2075 )
rootf6af1672012-04-06 09:46:29 -07002076
2077 # Dream up some flow information, i.e. space to chose from for
2078 # random flow parameter generation
2079
2080 fi = Flow_Info()
2081 fi.rand(10)
2082
2083 # Dream up a flow config, with at least 1 qualifier specified
2084
2085 fc = Flow_Cfg()
2086 while True:
2087 fc.rand(fi, \
2088 sw.tbl_stats.stats[0].wildcards, \
2089 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002090 sw.valid_ports, \
2091 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002092 )
2093 fc = fc.canonical()
2094 if fc.match.wildcards != ofp.OFPFW_ALL:
2095 break
2096
2097 # Send it to the switch
2098
Howard Persh5f3c83f2012-04-13 09:57:10 -07002099 fq_logger.info("Sending flow add to switch:")
2100 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002101 ft = Flow_Tbl()
2102 fc.send_rem = False
2103 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2104 ft.insert(fc)
2105
2106 # Wildcard out one qualifier that was specified, to create an
2107 # overlapping flow
2108
2109 fc2 = copy.deepcopy(fc)
2110 for wi in shuffle(range(len(all_wildcards_list))):
2111 w = all_wildcards_list[wi]
2112 if (fc2.match.wildcards & w) == 0:
2113 break
2114 if w == ofp.OFPFW_NW_SRC_MASK:
2115 w = ofp.OFPFW_NW_SRC_ALL
2116 wn = "OFPFW_NW_SRC"
2117 elif w == ofp.OFPFW_NW_DST_MASK:
2118 w = ofp.OFPFW_NW_DST_ALL
2119 wn = "OFPFW_NW_DST"
2120 else:
2121 wn = all_wildcard_names[w]
Howard Persh5f3c83f2012-04-13 09:57:10 -07002122 fq_logger.info("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07002123 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07002124 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07002125
2126 # Send that to the switch, with overlap checking
2127
Howard Persh5f3c83f2012-04-13 09:57:10 -07002128 fq_logger.info("Sending flow add to switch:")
2129 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002130 fc2.send_rem = False
2131 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
2132
2133 # Do barrier, to make sure all flows are in
2134 self.assertTrue(sw.barrier(), "Barrier failed")
2135
2136 result = True
2137
2138 # Check for expected error message
2139
2140 if not sw.errors_verify(1, \
2141 ofp.OFPET_FLOW_MOD_FAILED, \
2142 ofp.OFPFMFC_OVERLAP \
2143 ):
2144 result = False
2145
2146 # Verify flow table
2147
2148 sw.flow_tbl = ft
2149 if not sw.flow_tbl_verify():
2150 result = False
2151
2152 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002153 fq_logger.info("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002154
2155
Howard Persh07d99e62012-04-09 15:26:57 -07002156# FLOW MODIFY 1
2157#
2158# OVERVIEW
2159# Strict modify of single existing flow
2160#
2161# PURPOSE
2162# - Verify that strict flow modify operates only on specified flow
2163# - Verify that flow is correctly modified
2164#
2165# PARAMETERS
2166# None
2167#
2168# PROCESS
2169# 1. Delete all flows from switch
2170# 2. Generate 1 flow F
2171# 3. Send flow add to switch, for flow F
2172# 4. Generate new action list for flow F, yielding F'
2173# 5. Send strict flow modify to switch, for flow F'
2174# 6. Verify flow table in switch
2175# 7. Test PASSED iff flow returned by switch is F'; else FAILED
2176
rootf6af1672012-04-06 09:46:29 -07002177class Flow_Mod_1(basic.SimpleProtocol):
2178 """
2179 Test FLOW_MOD_1 from draft top-half test plan
2180
2181 INPUTS
2182 None
2183 """
2184
2185 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002186 fq_logger.info("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002187
2188 # Clear all flows from switch
2189
Howard Persh5f3c83f2012-04-13 09:57:10 -07002190 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002191 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002192 self.assertEqual(rc, 0, "Failed to delete all flows")
2193
2194 # Get switch capabilites
2195
rootf6af1672012-04-06 09:46:29 -07002196 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002197 self.assertTrue(sw.connect(self.controller), \
2198 "Failed to connect to switch" \
2199 )
rootf6af1672012-04-06 09:46:29 -07002200
2201 # Dream up some flow information, i.e. space to chose from for
2202 # random flow parameter generation
2203
2204 fi = Flow_Info()
2205 fi.rand(10)
2206
2207 # Dream up a flow config
2208
2209 fc = Flow_Cfg()
2210 fc.rand(fi, \
2211 sw.tbl_stats.stats[0].wildcards, \
2212 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002213 sw.valid_ports, \
2214 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002215 )
2216 fc = fc.canonical()
2217
2218 # Send it to the switch
2219
Howard Persh5f3c83f2012-04-13 09:57:10 -07002220 fq_logger.info("Sending flow add to switch:")
2221 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002222 ft = Flow_Tbl()
2223 fc.send_rem = False
2224 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2225 ft.insert(fc)
2226
2227 # Dream up some different actions, with the same flow key
2228
2229 fc2 = copy.deepcopy(fc)
2230 while True:
2231 fc2.rand_mod(fi, \
2232 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002233 sw.valid_ports, \
2234 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002235 )
2236 if fc2 != fc:
2237 break
2238
2239 # Send that to the switch
2240
Howard Persh5f3c83f2012-04-13 09:57:10 -07002241 fq_logger.info("Sending strict flow mod to switch:")
2242 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002243 fc2.send_rem = False
2244 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2245 ft.insert(fc2)
2246
2247 # Do barrier, to make sure all flows are in
2248
2249 self.assertTrue(sw.barrier(), "Barrier failed")
2250
2251 result = True
2252
2253 # Check for any error messages
2254
2255 if not sw.errors_verify(0):
2256 result = False
2257
2258 # Verify flow table
2259
2260 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002261 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002262 result = False
2263
2264 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002265 fq_logger.info("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002266
Howard Persh07d99e62012-04-09 15:26:57 -07002267
2268# FLOW MODIFY 2
2269#
2270# OVERVIEW
2271# Loose modify of mutiple flows
2272#
2273# PURPOSE
2274# - Verify that loose flow modify operates only on matching flows
2275# - Verify that matching flows are correctly modified
2276#
2277# PARAMETERS
2278# Name: num_flows
2279# Type: number
2280# Description:
2281# Number of flows to define
2282# Default: 100
2283#
2284# PROCESS
2285# 1. Delete all flows from switch
2286# 2. Generate <num_flows> distinct flow configurations
2287# 3. Send <num_flows> flow adds to switch
2288# 4. Pick 1 defined flow F at random
2289# 5. Create overlapping loose flow mod match criteria by repeatedly
2290# wildcarding out qualifiers in match of F => F',
2291# and create new actions list A' for F'
2292# 6. Send loose flow modify for F' to switch
2293# 7. Verify flow table in swtich
2294# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2295# are returned in step 7 above, each with correct (original or modified)
2296# action list;
2297# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002298
2299class Flow_Mod_2(basic.SimpleProtocol):
2300 """
2301 Test FLOW_MOD_2 from draft top-half test plan
2302
2303 INPUTS
2304 None
2305 """
2306
2307 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002308 fq_logger.info("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002309
Dan Talayco910a8282012-04-07 00:05:20 -07002310 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002311
2312 # Clear all flows from switch
2313
Howard Persh5f3c83f2012-04-13 09:57:10 -07002314 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002315 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002316 self.assertEqual(rc, 0, "Failed to delete all flows")
2317
2318 # Get switch capabilites
2319
rootf6af1672012-04-06 09:46:29 -07002320 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002321 self.assertTrue(sw.connect(self.controller), \
2322 "Failed to connect to switch" \
2323 )
rootf6af1672012-04-06 09:46:29 -07002324
2325 # Dream up some flow information, i.e. space to chose from for
2326 # random flow parameter generation
2327
2328 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002329 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002330 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002331
2332 # Dream up some flows
2333
2334 ft = Flow_Tbl()
2335 ft.rand(sw, fi, num_flows)
2336
2337 # Send flow table to switch
2338
Howard Persh5f3c83f2012-04-13 09:57:10 -07002339 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002340 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07002341 fq_logger.info("Adding flow:")
2342 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002343 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2344
2345 # Do barrier, to make sure all flows are in
2346
2347 self.assertTrue(sw.barrier(), "Barrier failed")
2348
2349 result = True
2350
2351 # Check for any error messages
2352
2353 if not sw.errors_verify(0):
2354 result = False
2355
2356 # Verify flow table
2357
2358 sw.flow_tbl = ft
2359 if not sw.flow_tbl_verify():
2360 result = False
2361
2362 # Pick a random flow as a basis
Howard Persh5f3c83f2012-04-13 09:57:10 -07002363
2364 mfc = copy.deepcopy((ft.values())[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002365 mfc.rand_mod(fi, \
2366 sw.sw_features.actions, \
2367 sw.valid_ports, \
2368 sw.valid_queues \
2369 )
rootf6af1672012-04-06 09:46:29 -07002370
2371 # Repeatedly wildcard qualifiers
2372
2373 for wi in shuffle(range(len(all_wildcards_list))):
2374 w = all_wildcards_list[wi]
2375 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2376 n = wildcard_get(mfc.match.wildcards, w)
2377 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002378 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2379 w, \
2380 random.randint(n + 1, 32) \
2381 )
rootf6af1672012-04-06 09:46:29 -07002382 else:
2383 continue
2384 else:
2385 if wildcard_get(mfc.match.wildcards, w) == 0:
2386 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2387 else:
2388 continue
2389 mfc = mfc.canonical()
2390
2391 # Count the number of flows that would be modified
2392
2393 n = 0
2394 for fc in ft.values():
2395 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2396 n = n + 1
2397
2398 # If more than 1, we found our loose delete flow spec
2399 if n > 1:
2400 break
2401
Howard Persh5f3c83f2012-04-13 09:57:10 -07002402 fq_logger.info("Modifying %d flows" % (n))
2403 fq_logger.info("Sending flow mod to switch:")
2404 fq_logger.info(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002405 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2406
2407 # Do barrier, to make sure all flows are in
2408 self.assertTrue(sw.barrier(), "Barrier failed")
2409
2410 # Check for error message
2411
2412 if not sw.errors_verify(0):
2413 result = False
2414
2415 # Apply flow mod to local flow table
2416
2417 for fc in ft.values():
2418 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002419 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002420
2421 # Verify flow table
2422
2423 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002424 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002425 result = False
2426
2427 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002428 fq_logger.info("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002429
2430
Howard Persh07d99e62012-04-09 15:26:57 -07002431# FLOW MODIFY 3
2432
2433# OVERVIEW
2434# Strict modify of non-existent flow
2435#
2436# PURPOSE
2437# Verify that strict modify of a non-existent flow is equivalent to a flow add
2438#
2439# PARAMETERS
2440# None
2441#
2442# PROCESS
2443# 1. Delete all flows from switch
2444# 2. Send single flow mod, as strict modify, to switch
2445# 3. Verify flow table in switch
2446# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2447
rootf6af1672012-04-06 09:46:29 -07002448class Flow_Mod_3(basic.SimpleProtocol):
2449 """
2450 Test FLOW_MOD_3 from draft top-half test plan
2451
2452 INPUTS
2453 None
2454 """
2455
2456 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002457 fq_logger.info("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002458
2459 # Clear all flows from switch
2460
Howard Persh5f3c83f2012-04-13 09:57:10 -07002461 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002462 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002463 self.assertEqual(rc, 0, "Failed to delete all flows")
2464
2465 # Get switch capabilites
2466
rootf6af1672012-04-06 09:46:29 -07002467 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002468 self.assertTrue(sw.connect(self.controller), \
2469 "Failed to connect to switch" \
2470 )
rootf6af1672012-04-06 09:46:29 -07002471
2472 # Dream up some flow information, i.e. space to chose from for
2473 # random flow parameter generation
2474
2475 fi = Flow_Info()
2476 fi.rand(10)
2477
2478 # Dream up a flow config
2479
2480 fc = Flow_Cfg()
2481 fc.rand(fi, \
2482 sw.tbl_stats.stats[0].wildcards, \
2483 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002484 sw.valid_ports, \
2485 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002486 )
2487 fc = fc.canonical()
2488
2489 # Send it to the switch
2490
Howard Persh5f3c83f2012-04-13 09:57:10 -07002491 fq_logger.info("Sending flow mod to switch:")
2492 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002493 ft = Flow_Tbl()
2494 fc.send_rem = False
2495 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2496 ft.insert(fc)
2497
2498 # Do barrier, to make sure all flows are in
2499
2500 self.assertTrue(sw.barrier(), "Barrier failed")
2501
2502 result = True
2503
2504 # Check for any error messages
2505
2506 if not sw.errors_verify(0):
2507 result = False
2508
2509 # Verify flow table
2510
2511 sw.flow_tbl = ft
2512 if not sw.flow_tbl_verify():
2513 result = False
2514
2515 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002516 fq_logger.info("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002517
2518
Howard Persh8d21c1f2012-04-20 15:57:29 -07002519# FLOW MODIFY 3_1
2520
2521# OVERVIEW
2522# No-op modify
2523#
2524# PURPOSE
2525# Verify that modify of a flow with new actions same as old ones operates correctly
2526#
2527# PARAMETERS
2528# None
2529#
2530# PROCESS
2531# 1. Delete all flows from switch
2532# 2. Send single flow mod, as strict modify, to switch
2533# 3. Verify flow table in switch
2534# 4. Send same flow mod, as strict modify, to switch
2535# 5. Verify flow table in switch
2536# 6. Test PASSED iff flow defined in step 2 and 4 above verified; else FAILED
2537
2538class Flow_Mod_3_1(basic.SimpleProtocol):
2539 """
2540 Test FLOW_MOD_3_1 from draft top-half test plan
2541
2542 INPUTS
2543 None
2544 """
2545
2546 def runTest(self):
2547 fq_logger.info("Flow_Mod_3_1 TEST BEGIN")
2548
2549 # Clear all flows from switch
2550
2551 fq_logger.info("Deleting all flows from switch")
2552 rc = delete_all_flows(self.controller, fq_logger)
2553 self.assertEqual(rc, 0, "Failed to delete all flows")
2554
2555 # Get switch capabilites
2556
2557 sw = Switch()
2558 self.assertTrue(sw.connect(self.controller), \
2559 "Failed to connect to switch" \
2560 )
2561
2562 # Dream up some flow information, i.e. space to chose from for
2563 # random flow parameter generation
2564
2565 fi = Flow_Info()
2566 fi.rand(10)
2567
2568 # Dream up a flow config
2569
2570 fc = Flow_Cfg()
2571 fc.rand(fi, \
2572 sw.tbl_stats.stats[0].wildcards, \
2573 sw.sw_features.actions, \
2574 sw.valid_ports, \
2575 sw.valid_queues \
2576 )
2577 fc = fc.canonical()
2578
2579 # Send it to the switch
2580
2581 fq_logger.info("Sending flow mod to switch:")
2582 fq_logger.info(str(fc))
2583 ft = Flow_Tbl()
2584 fc.send_rem = False
2585 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2586 ft.insert(fc)
2587
2588 # Do barrier, to make sure all flows are in
2589
2590 self.assertTrue(sw.barrier(), "Barrier failed")
2591
2592 result = True
2593
2594 # Check for any error messages
2595
2596 if not sw.errors_verify(0):
2597 result = False
2598
2599 # Verify flow table
2600
2601 sw.flow_tbl = ft
2602 if not sw.flow_tbl_verify():
2603 result = False
2604
2605 # Send same flow to the switch again
2606
2607 fq_logger.info("Sending flow mod to switch:")
2608 fq_logger.info(str(fc))
2609 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2610
2611 # Do barrier, to make sure all flows are in
2612
2613 self.assertTrue(sw.barrier(), "Barrier failed")
2614
2615 # Check for any error messages
2616
2617 if not sw.errors_verify(0):
2618 result = False
2619
2620 # Verify flow table
2621
2622 if not sw.flow_tbl_verify():
2623 result = False
2624
2625 self.assertTrue(result, "Flow_Mod_3_1 TEST FAILED")
2626 fq_logger.info("Flow_Mod_3_1 TEST PASSED")
2627
2628
Howard Persh07d99e62012-04-09 15:26:57 -07002629# FLOW DELETE 1
2630#
2631# OVERVIEW
2632# Strict delete of single flow
2633#
2634# PURPOSE
2635# Verify correct operation of strict delete of single defined flow
2636#
2637# PARAMETERS
2638# None
2639#
2640# PROCESS
2641# 1. Delete all flows from switch
2642# 2. Send flow F to switch
2643# 3. Send strict flow delete for F to switch
2644# 4. Verify flow table in swtich
2645# 6. Test PASSED iff all flows sent to switch in step 2 above,
2646# less flow removed in step 3 above, are returned in step 4 above;
2647# else test FAILED
2648
rootf6af1672012-04-06 09:46:29 -07002649class Flow_Del_1(basic.SimpleProtocol):
2650 """
2651 Test FLOW_DEL_1 from draft top-half test plan
2652
2653 INPUTS
2654 None
2655 """
2656
2657 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002658 fq_logger.info("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002659
2660 # Clear all flows from switch
2661
Howard Persh5f3c83f2012-04-13 09:57:10 -07002662 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002663 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002664 self.assertEqual(rc, 0, "Failed to delete all flows")
2665
2666 # Get switch capabilites
2667
rootf6af1672012-04-06 09:46:29 -07002668 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002669 self.assertTrue(sw.connect(self.controller), \
2670 "Failed to connect to switch" \
2671 )
rootf6af1672012-04-06 09:46:29 -07002672
2673 # Dream up some flow information, i.e. space to chose from for
2674 # random flow parameter generation
2675
2676 fi = Flow_Info()
2677 fi.rand(10)
2678
2679 # Dream up a flow config
2680
2681 fc = Flow_Cfg()
2682 fc.rand(fi, \
2683 sw.tbl_stats.stats[0].wildcards, \
2684 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002685 sw.valid_ports, \
2686 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002687 )
2688 fc = fc.canonical()
2689
2690 # Send it to the switch
2691
Howard Persh5f3c83f2012-04-13 09:57:10 -07002692 fq_logger.info("Sending flow add to switch:")
2693 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002694 ft = Flow_Tbl()
2695 fc.send_rem = False
2696 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2697 ft.insert(fc)
2698
2699 # Dream up some different actions, with the same flow key
2700
2701 fc2 = copy.deepcopy(fc)
2702 while True:
2703 fc2.rand_mod(fi, \
2704 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002705 sw.valid_ports, \
2706 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002707 )
2708 if fc2 != fc:
2709 break
2710
2711 # Delete strictly
2712
Howard Persh5f3c83f2012-04-13 09:57:10 -07002713 fq_logger.info("Sending strict flow del to switch:")
2714 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002715 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2716 ft.delete(fc)
2717
2718 # Do barrier, to make sure all flows are in
2719
2720 self.assertTrue(sw.barrier(), "Barrier failed")
2721
2722 result = True
2723
2724 # Check for any error messages
2725
2726 if not sw.errors_verify(0):
2727 result = False
2728
2729 # Verify flow table
2730
2731 sw.flow_tbl = ft
2732 if not sw.flow_tbl_verify():
2733 result = False
2734
2735 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002736 fq_logger.info("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002737
2738
Howard Persh07d99e62012-04-09 15:26:57 -07002739# FLOW DELETE 2
2740#
2741# OVERVIEW
2742# Loose delete of multiple flows
2743#
2744# PURPOSE
2745# - Verify correct operation of loose delete of multiple flows
2746#
2747# PARAMETERS
2748# Name: num_flows
2749# Type: number
2750# Description:
2751# Number of flows to define
2752# Default: 100
2753#
2754# PROCESS
2755# 1. Delete all flows from switch
2756# 2. Generate <num_flows> distinct flow configurations
2757# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2758# 4. Pick 1 defined flow F at random
2759# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2760# F' will match more than 1 existing flow key
2761# 6. Send loose flow delete for F' to switch
2762# 7. Verify flow table in switch
2763# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2764# removed in step 6 above (i.e. those that match F'), are returned
2765# in step 7 above;
2766# else test FAILED
2767
rootf6af1672012-04-06 09:46:29 -07002768class Flow_Del_2(basic.SimpleProtocol):
2769 """
2770 Test FLOW_DEL_2 from draft top-half test plan
2771
2772 INPUTS
2773 None
2774 """
2775
2776 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002777 fq_logger.info("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002778
Dan Talayco910a8282012-04-07 00:05:20 -07002779 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002780
2781 # Clear all flows from switch
2782
Howard Persh5f3c83f2012-04-13 09:57:10 -07002783 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002784 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002785 self.assertEqual(rc, 0, "Failed to delete all flows")
2786
2787 # Get switch capabilites
2788
rootf6af1672012-04-06 09:46:29 -07002789 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002790 self.assertTrue(sw.connect(self.controller), \
2791 "Failed to connect to switch" \
2792 )
rootf6af1672012-04-06 09:46:29 -07002793
2794 # Dream up some flow information, i.e. space to chose from for
2795 # random flow parameter generation
2796
2797 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002798 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002799 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002800
2801 # Dream up some flows
2802
2803 ft = Flow_Tbl()
2804 ft.rand(sw, fi, num_flows)
2805
2806 # Send flow table to switch
2807
Howard Persh5f3c83f2012-04-13 09:57:10 -07002808 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002809 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07002810 fq_logger.info("Adding flow:")
2811 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002812 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2813
2814 # Do barrier, to make sure all flows are in
2815
2816 self.assertTrue(sw.barrier(), "Barrier failed")
2817
2818 result = True
2819
2820 # Check for any error messages
2821
2822 if not sw.errors_verify(0):
2823 result = False
2824
2825 # Verify flow table
2826
2827 sw.flow_tbl = ft
2828 if not sw.flow_tbl_verify():
2829 result = False
2830
2831 # Pick a random flow as a basis
2832
2833 dfc = copy.deepcopy(ft.values()[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002834 dfc.rand_mod(fi, \
2835 sw.sw_features.actions, \
2836 sw.valid_ports, \
2837 sw.valid_queues \
2838 )
rootf6af1672012-04-06 09:46:29 -07002839
2840 # Repeatedly wildcard qualifiers
2841
2842 for wi in shuffle(range(len(all_wildcards_list))):
2843 w = all_wildcards_list[wi]
2844 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2845 n = wildcard_get(dfc.match.wildcards, w)
2846 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002847 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2848 w, \
2849 random.randint(n + 1, 32) \
2850 )
rootf6af1672012-04-06 09:46:29 -07002851 else:
2852 continue
2853 else:
2854 if wildcard_get(dfc.match.wildcards, w) == 0:
2855 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2856 else:
2857 continue
2858 dfc = dfc.canonical()
2859
2860 # Count the number of flows that would be deleted
2861
2862 n = 0
2863 for fc in ft.values():
2864 if dfc.overlaps(fc, True):
2865 n = n + 1
2866
2867 # If more than 1, we found our loose delete flow spec
2868 if n > 1:
2869 break
2870
Howard Persh5f3c83f2012-04-13 09:57:10 -07002871 fq_logger.info("Deleting %d flows" % (n))
2872 fq_logger.info("Sending flow del to switch:")
2873 fq_logger.info(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002874 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2875
2876 # Do barrier, to make sure all flows are in
2877 self.assertTrue(sw.barrier(), "Barrier failed")
2878
2879 # Check for error message
2880
2881 if not sw.errors_verify(0):
2882 result = False
2883
2884 # Apply flow mod to local flow table
2885
2886 for fc in ft.values():
2887 if dfc.overlaps(fc, True):
2888 ft.delete(fc)
2889
2890 # Verify flow table
2891
2892 sw.flow_tbl = ft
2893 if not sw.flow_tbl_verify():
2894 result = False
2895
2896 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002897 fq_logger.info("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002898
2899
Howard Persh07d99e62012-04-09 15:26:57 -07002900# FLOW DELETE 4
2901#
2902# OVERVIEW
2903# Flow removed messages
2904#
2905# PURPOSE
2906# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2907# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2908#
2909# PARAMETERS
2910# None
2911#
2912# PROCESS
2913# 1. Delete all flows from switch
2914# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2915# 3. Send strict flow delete of flow to switch
2916# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2917# 5. Verify flow table in switch
2918# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2919# removed in step 3 above, are returned in step 5 above, and that
2920# asynch message was received; else test FAILED
2921
2922
rootf6af1672012-04-06 09:46:29 -07002923class Flow_Del_4(basic.SimpleProtocol):
2924 """
2925 Test FLOW_DEL_4 from draft top-half test plan
2926
2927 INPUTS
2928 None
2929 """
2930
2931 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002932 fq_logger.info("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002933
2934 # Clear all flows from switch
2935
Howard Persh5f3c83f2012-04-13 09:57:10 -07002936 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002937 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002938 self.assertEqual(rc, 0, "Failed to delete all flows")
2939
2940 # Get switch capabilites
2941
rootf6af1672012-04-06 09:46:29 -07002942 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002943 self.assertTrue(sw.connect(self.controller), \
2944 "Failed to connect to switch" \
2945 )
rootf6af1672012-04-06 09:46:29 -07002946
2947 # Dream up some flow information, i.e. space to chose from for
2948 # random flow parameter generation
2949
2950 fi = Flow_Info()
2951 fi.rand(10)
2952
2953 # Dream up a flow config
2954
2955 fc = Flow_Cfg()
2956 fc.rand(fi, \
2957 sw.tbl_stats.stats[0].wildcards, \
2958 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002959 sw.valid_ports, \
2960 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002961 )
2962 fc = fc.canonical()
2963
2964 # Send it to the switch. with "notify on removed"
2965
Howard Persh5f3c83f2012-04-13 09:57:10 -07002966 fq_logger.info("Sending flow add to switch:")
2967 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002968 ft = Flow_Tbl()
2969 fc.send_rem = True
2970 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2971 ft.insert(fc)
2972
2973 # Dream up some different actions, with the same flow key
2974
2975 fc2 = copy.deepcopy(fc)
2976 while True:
2977 fc2.rand_mod(fi, \
2978 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002979 sw.valid_ports, \
2980 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002981 )
2982 if fc2 != fc:
2983 break
2984
2985 # Delete strictly
2986
Howard Persh5f3c83f2012-04-13 09:57:10 -07002987 fq_logger.info("Sending strict flow del to switch:")
2988 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002989 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2990 ft.delete(fc)
2991
2992 # Do barrier, to make sure all flows are in
2993
2994 self.assertTrue(sw.barrier(), "Barrier failed")
2995
2996 result = True
2997
2998 # Check for expected "removed" message
2999
Howard Persh3340d452012-04-06 16:45:21 -07003000 if not sw.errors_verify(0):
3001 result = False
3002
3003 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07003004 result = False
3005
3006 # Verify flow table
3007
3008 sw.flow_tbl = ft
3009 if not sw.flow_tbl_verify():
3010 result = False
3011
3012 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07003013 fq_logger.info("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07003014