blob: bad4749fc1619d81d23fadb9ab7e94ecde274678 [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
Howard Persh9cab4822012-09-11 17:08:40 -070065import time
Howard Pershc7963582012-03-29 10:02:59 -070066
67import oftest.controller as controller
68import oftest.cstruct as ofp
69import oftest.message as message
70import oftest.dataplane as dataplane
71import oftest.action as action
72import oftest.action_list as action_list
73import oftest.parse as parse
74import pktact
75import basic
76
77from testutils import *
78from time import sleep
79
80#@var port_map Local copy of the configuration map from OF port
81# numbers to OS interfaces
Dan Talayco910a8282012-04-07 00:05:20 -070082fq_port_map = None
83#@var fq_logger Local logger object
84fq_logger = None
85#@var fq_config Local copy of global configuration data
86fq_config = None
Howard Pershc7963582012-03-29 10:02:59 -070087
rootf6af1672012-04-06 09:46:29 -070088# For test priority
89test_prio = {}
90
91
Howard Pershc7963582012-03-29 10:02:59 -070092def test_set_init(config):
93 """
94 Set up function for packet action test classes
95
96 @param config The configuration dictionary; see oft
97 """
98
99 basic.test_set_init(config)
100
Dan Talayco910a8282012-04-07 00:05:20 -0700101 global fq_port_map
102 global fq_logger
103 global fq_config
Howard Pershc7963582012-03-29 10:02:59 -0700104
Dan Talayco910a8282012-04-07 00:05:20 -0700105 fq_logger = logging.getLogger("flowq")
106 fq_logger.info("Initializing test set")
107 fq_port_map = config["port_map"]
108 fq_config = config
root2843d2b2012-04-06 10:27:46 -0700109
Howard Pershc7963582012-03-29 10:02:59 -0700110
rootf6af1672012-04-06 09:46:29 -0700111def flip_coin():
112 return random.randint(1, 100) <= 50
113
114
Howard Pershc7963582012-03-29 10:02:59 -0700115def shuffle(list):
116 n = len(list)
117 lim = n * n
118 i = 0
119 while i < lim:
120 a = random.randint(0, n - 1)
121 b = random.randint(0, n - 1)
122 temp = list[a]
123 list[a] = list[b]
124 list[b] = temp
125 i = i + 1
126 return list
127
128
Howard Persh680b92a2012-03-31 13:34:35 -0700129def rand_pick(list):
130 return list[random.randint(0, len(list) - 1)]
Howard Pershc7963582012-03-29 10:02:59 -0700131
Howard Persh680b92a2012-03-31 13:34:35 -0700132def rand_dl_addr():
133 return [random.randint(0, 255) & ~1,
134 random.randint(0, 255),
135 random.randint(0, 255),
136 random.randint(0, 255),
137 random.randint(0, 255),
138 random.randint(0, 255)
139 ]
Howard Pershc7963582012-03-29 10:02:59 -0700140
141def rand_nw_addr():
142 return random.randint(0, (1 << 32) - 1)
143
144
rootf6af1672012-04-06 09:46:29 -0700145class Flow_Info:
Howard Persh680b92a2012-03-31 13:34:35 -0700146 # Members:
147 # priorities - list of flow priorities
148 # dl_addrs - list of MAC addresses
149 # vlans - list of VLAN ids
150 # ethertypes - list of Ethertypes
151 # ip_addrs - list of IP addresses
152 # ip_tos - list of IP TOS values
153 # ip_protos - list of IP protocols
154 # l4_ports - list of L4 ports
155
156 def __init__(self):
157 priorities = []
158 dl_addrs = []
159 vlans = []
160 ethertypes = []
161 ip_addrs = []
162 ip_tos = []
163 ip_protos = []
164 l4_ports = []
165
166 def rand(self, n):
167 self.priorities = []
168 i = 0
169 while i < n:
170 self.priorities.append(random.randint(1, 65534))
171 i = i + 1
172
173 self.dl_addrs = []
174 i = 0
175 while i < n:
176 self.dl_addrs.append(rand_dl_addr())
177 i = i + 1
178
Howard Pershb10a47a2012-08-21 13:54:47 -0700179 if test_param_get(fq_config, "vlans", []) != []:
180 self.vlans = test_param_get(fq_config, "vlans", [])
181
182 fq_logger.info("Overriding VLAN ids to:")
183 fq_logger.info(self.vlans)
184 else:
185 self.vlans = []
186 i = 0
187 while i < n:
188 self.vlans.append(random.randint(1, 4094))
189 i = i + 1
Howard Persh680b92a2012-03-31 13:34:35 -0700190
rootf6af1672012-04-06 09:46:29 -0700191 self.ethertypes = [0x0800, 0x0806]
Howard Persh680b92a2012-03-31 13:34:35 -0700192 i = 0
193 while i < n:
194 self.ethertypes.append(random.randint(0, (1 << 16) - 1))
195 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700196 self.ethertypes = shuffle(self.ethertypes)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700197
198 self.ip_addrs = []
199 i = 0
200 while i < n:
201 self.ip_addrs.append(rand_nw_addr())
202 i = i + 1
203
204 self.ip_tos = []
205 i = 0
206 while i < n:
207 self.ip_tos.append(random.randint(0, (1 << 8) - 1) & ~3)
208 i = i + 1
209
rootf6af1672012-04-06 09:46:29 -0700210 self.ip_protos = [1, 6, 17]
Howard Persh680b92a2012-03-31 13:34:35 -0700211 i = 0
212 while i < n:
213 self.ip_protos.append(random.randint(0, (1 << 8) - 1))
214 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700215 self.ip_protos = shuffle(self.ip_protos)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700216
217 self.l4_ports = []
218 i = 0
219 while i < n:
220 self.l4_ports.append(random.randint(0, (1 << 16) - 1))
221 i = i + 1
222
223 def rand_priority(self):
224 return rand_pick(self.priorities)
225
226 def rand_dl_addr(self):
227 return rand_pick(self.dl_addrs)
228
229 def rand_vlan(self):
230 return rand_pick(self.vlans)
231
232 def rand_ethertype(self):
233 return rand_pick(self.ethertypes)
234
235 def rand_ip_addr(self):
236 return rand_pick(self.ip_addrs)
237
238 def rand_ip_tos(self):
239 return rand_pick(self.ip_tos)
240
241 def rand_ip_proto(self):
242 return rand_pick(self.ip_protos)
243
244 def rand_l4_port(self):
245 return rand_pick(self.l4_ports)
246
247
Howard Pershc7963582012-03-29 10:02:59 -0700248# TBD - These don't belong here
249
Howard Persh680b92a2012-03-31 13:34:35 -0700250all_wildcards_list = [ofp.OFPFW_IN_PORT,
Howard Persh680b92a2012-03-31 13:34:35 -0700251 ofp.OFPFW_DL_DST,
rootf6af1672012-04-06 09:46:29 -0700252 ofp.OFPFW_DL_SRC,
253 ofp.OFPFW_DL_VLAN,
254 ofp.OFPFW_DL_VLAN_PCP,
Howard Persh680b92a2012-03-31 13:34:35 -0700255 ofp.OFPFW_DL_TYPE,
rootf6af1672012-04-06 09:46:29 -0700256 ofp.OFPFW_NW_TOS,
Howard Persh680b92a2012-03-31 13:34:35 -0700257 ofp.OFPFW_NW_PROTO,
Howard Persh680b92a2012-03-31 13:34:35 -0700258 ofp.OFPFW_NW_SRC_MASK,
259 ofp.OFPFW_NW_DST_MASK,
rootf6af1672012-04-06 09:46:29 -0700260 ofp.OFPFW_TP_SRC,
261 ofp.OFPFW_TP_DST
Howard Persh680b92a2012-03-31 13:34:35 -0700262 ]
Howard Pershc7963582012-03-29 10:02:59 -0700263
Howard Persh3340d452012-04-06 16:45:21 -0700264# TBD - Need this because there are duplicates in ofp.ofp_flow_wildcards_map
265# -- FIX
rootf6af1672012-04-06 09:46:29 -0700266all_wildcard_names = {
267 1 : 'OFPFW_IN_PORT',
268 2 : 'OFPFW_DL_VLAN',
269 4 : 'OFPFW_DL_SRC',
270 8 : 'OFPFW_DL_DST',
271 16 : 'OFPFW_DL_TYPE',
272 32 : 'OFPFW_NW_PROTO',
273 64 : 'OFPFW_TP_SRC',
274 128 : 'OFPFW_TP_DST',
275 1048576 : 'OFPFW_DL_VLAN_PCP',
276 2097152 : 'OFPFW_NW_TOS'
277}
278
rootf6af1672012-04-06 09:46:29 -0700279def wildcard_set(x, w, val):
280 result = x
281 if w == ofp.OFPFW_NW_SRC_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700282 result = (result & ~ofp.OFPFW_NW_SRC_MASK) \
283 | (val << ofp.OFPFW_NW_SRC_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700284 elif w == ofp.OFPFW_NW_DST_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700285 result = (result & ~ofp.OFPFW_NW_DST_MASK) \
286 | (val << ofp.OFPFW_NW_DST_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700287 elif val == 0:
288 result = result & ~w
289 else:
290 result = result | w
291 return result
292
293def wildcard_get(x, w):
294 if w == ofp.OFPFW_NW_SRC_MASK:
295 return (x & ofp.OFPFW_NW_SRC_MASK) >> ofp.OFPFW_NW_SRC_SHIFT
296 if w == ofp.OFPFW_NW_DST_MASK:
297 return (x & ofp.OFPFW_NW_DST_MASK) >> ofp.OFPFW_NW_DST_SHIFT
298 return 1 if (x & w) != 0 else 0
299
Howard Persh8d21c1f2012-04-20 15:57:29 -0700300def wildcards_to_str(wildcards):
301 result = "{"
302 sep = ""
303 for w in all_wildcards_list:
304 if (wildcards & w) == 0:
305 continue
306 if w == ofp.OFPFW_NW_SRC_MASK:
307 n = wildcard_get(wildcards, w)
308 if n > 0:
309 result = result + sep + ("OFPFW_NW_SRC(%d)" % (n))
310 elif w == ofp.OFPFW_NW_DST_MASK:
311 n = wildcard_get(wildcards, w)
312 if n > 0:
313 result = result + sep + ("OFPFW_NW_DST(%d)" % (n))
314 else:
315 result = result + sep + all_wildcard_names[w]
316 sep = ", "
317 result = result +"}"
318 return result
Howard Pershc7963582012-03-29 10:02:59 -0700319
Howard Persh680b92a2012-03-31 13:34:35 -0700320all_actions_list = [ofp.OFPAT_OUTPUT,
321 ofp.OFPAT_SET_VLAN_VID,
322 ofp.OFPAT_SET_VLAN_PCP,
323 ofp.OFPAT_STRIP_VLAN,
324 ofp.OFPAT_SET_DL_SRC,
325 ofp.OFPAT_SET_DL_DST,
326 ofp.OFPAT_SET_NW_SRC,
327 ofp.OFPAT_SET_NW_DST,
328 ofp.OFPAT_SET_NW_TOS,
329 ofp.OFPAT_SET_TP_SRC,
330 ofp.OFPAT_SET_TP_DST,
331 ofp.OFPAT_ENQUEUE
332 ]
333
Howard Persh8d21c1f2012-04-20 15:57:29 -0700334def actions_bmap_to_str(bm):
335 result = "{"
336 sep = ""
337 for a in all_actions_list:
338 if ((1 << a) & bm) != 0:
339 result = result + sep + ofp.ofp_action_type_map[a]
340 sep = ", "
341 result = result + "}"
342 return result
343
Howard Persh680b92a2012-03-31 13:34:35 -0700344def dl_addr_to_str(a):
345 return "%x:%x:%x:%x:%x:%x" % tuple(a)
346
347def ip_addr_to_str(a, n):
rootf6af1672012-04-06 09:46:29 -0700348 if n is not None:
349 a = a & ~((1 << (32 - n)) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700350 result = "%d.%d.%d.%d" % (a >> 24, \
351 (a >> 16) & 0xff, \
352 (a >> 8) & 0xff, \
353 a & 0xff \
354 )
355 if n is not None:
356 result = result + ("/%d" % (n))
357 return result
358
Howard Pershc7963582012-03-29 10:02:59 -0700359
rootf6af1672012-04-06 09:46:29 -0700360class Flow_Cfg:
Howard Pershc7963582012-03-29 10:02:59 -0700361 # Members:
362 # - match
363 # - idle_timeout
364 # - hard_timeout
365 # - priority
366 # - action_list
367
368 def __init__(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700369 self.priority = 0
Howard Pershc7963582012-03-29 10:02:59 -0700370 self.match = parse.ofp_match()
371 self.match.wildcards = ofp.OFPFW_ALL
372 self.idle_timeout = 0
373 self.hard_timeout = 0
Howard Pershc7963582012-03-29 10:02:59 -0700374 self.actions = action_list.action_list()
375
rootf6af1672012-04-06 09:46:29 -0700376 # {pri, match} is considered a flow key
377 def key_equal(self, x):
Howard Persh680b92a2012-03-31 13:34:35 -0700378 if self.priority != x.priority:
379 return False
380 # TBD - Should this logic be moved to ofp_match.__eq__()?
381 if self.match.wildcards != x.match.wildcards:
382 return False
rootf6af1672012-04-06 09:46:29 -0700383 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700384 and self.match.in_port != x.match.in_port:
385 return False
rootf6af1672012-04-06 09:46:29 -0700386 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700387 and self.match.dl_dst != x.match.dl_dst:
388 return False
rootf6af1672012-04-06 09:46:29 -0700389 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0 \
390 and self.match.dl_src != x.match.dl_src:
391 return False
392 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700393 and self.match.dl_vlan != x.match.dl_vlan:
394 return False
rootf6af1672012-04-06 09:46:29 -0700395 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700396 and self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
397 return False
rootf6af1672012-04-06 09:46:29 -0700398 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700399 and self.match.dl_type != x.match.dl_type:
400 return False
rootf6af1672012-04-06 09:46:29 -0700401 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700402 and self.match.nw_tos != x.match.nw_tos:
403 return False
rootf6af1672012-04-06 09:46:29 -0700404 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700405 and self.match.nw_proto != x.match.nw_proto:
406 return False
rootf6af1672012-04-06 09:46:29 -0700407 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
408 if n < 32:
409 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700410 if (self.match.nw_src & m) != (x.match.nw_src & m):
411 return False
rootf6af1672012-04-06 09:46:29 -0700412 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
413 if n < 32:
414 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700415 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
416 return False
rootf6af1672012-04-06 09:46:29 -0700417 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0 \
418 and self.match.tp_src != x.match.tp_src:
Howard Persh680b92a2012-03-31 13:34:35 -0700419 return False
rootf6af1672012-04-06 09:46:29 -0700420 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0 \
421 and self.match.tp_dst != x.match.tp_dst:
422 return False
423 return True
424
Howard Persh5f3c83f2012-04-13 09:57:10 -0700425 def actions_equal(self, x):
426 if test_param_get(fq_config, "conservative_ordered_actions", True):
427 # Compare actions lists as unordered
428
root2843d2b2012-04-06 10:27:46 -0700429 aa = copy.deepcopy(x.actions.actions)
430 for a in self.actions.actions:
431 i = 0
432 while i < len(aa):
433 if a == aa[i]:
434 break
435 i = i + 1
436 if i < len(aa):
437 aa.pop(i)
438 else:
439 return False
440 return aa == []
441 else:
442 return self.actions == x.actions
Howard Persh5f3c83f2012-04-13 09:57:10 -0700443
444 def non_key_equal(self, x):
445 if self.cookie != x.cookie:
446 return False
447 if self.idle_timeout != x.idle_timeout:
448 return False
449 if self.hard_timeout != x.hard_timeout:
450 return False
451 return self.actions_equal(x)
rootf6af1672012-04-06 09:46:29 -0700452
root2843d2b2012-04-06 10:27:46 -0700453 def key_str(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700454 result = "priority=%d" % self.priority
455 # TBD - Would be nice if ofp_match.show() was better behaved
456 # (no newlines), and more intuitive (things in hex where approprate), etc.
Howard Persh8d21c1f2012-04-20 15:57:29 -0700457 result = result + (", wildcards=0x%x=%s" \
458 % (self.match.wildcards, \
459 wildcards_to_str(self.match.wildcards) \
460 )
461 )
rootf6af1672012-04-06 09:46:29 -0700462 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700463 result = result + (", in_port=%d" % (self.match.in_port))
rootf6af1672012-04-06 09:46:29 -0700464 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700465 result = result + (", dl_dst=%s" \
466 % (dl_addr_to_str(self.match.dl_dst)) \
467 )
rootf6af1672012-04-06 09:46:29 -0700468 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700469 result = result + (", dl_src=%s" \
470 % (dl_addr_to_str(self.match.dl_src)) \
471 )
rootf6af1672012-04-06 09:46:29 -0700472 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700473 result = result + (", dl_vlan=%d" % (self.match.dl_vlan))
rootf6af1672012-04-06 09:46:29 -0700474 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700475 result = result + (", dl_vlan_pcp=%d" % (self.match.dl_vlan_pcp))
rootf6af1672012-04-06 09:46:29 -0700476 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700477 result = result + (", dl_type=0x%x" % (self.match.dl_type))
rootf6af1672012-04-06 09:46:29 -0700478 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700479 result = result + (", nw_tos=0x%x" % (self.match.nw_tos))
rootf6af1672012-04-06 09:46:29 -0700480 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700481 result = result + (", nw_proto=%d" % (self.match.nw_proto))
rootf6af1672012-04-06 09:46:29 -0700482 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700483 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700484 result = result + (", nw_src=%s" % \
485 (ip_addr_to_str(self.match.nw_src, 32 - n)) \
486 )
rootf6af1672012-04-06 09:46:29 -0700487 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700488 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700489 result = result + (", nw_dst=%s" % \
490 (ip_addr_to_str(self.match.nw_dst, 32 - n)) \
491 )
rootf6af1672012-04-06 09:46:29 -0700492 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700493 result = result + (", tp_src=%d" % self.match.tp_src)
rootf6af1672012-04-06 09:46:29 -0700494 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700495 result = result + (", tp_dst=%d" % self.match.tp_dst)
rootf6af1672012-04-06 09:46:29 -0700496 return result
497
498 def __eq__(self, x):
499 return (self.key_equal(x) and self.non_key_equal(x))
500
501 def __str__(self):
root2843d2b2012-04-06 10:27:46 -0700502 result = self.key_str()
503 result = result + (", cookie=%d" % self.cookie)
Howard Persh680b92a2012-03-31 13:34:35 -0700504 result = result + (", idle_timeout=%d" % self.idle_timeout)
505 result = result + (", hard_timeout=%d" % self.hard_timeout)
Howard Persh680b92a2012-03-31 13:34:35 -0700506 for a in self.actions.actions:
507 result = result + (", action=%s" % ofp.ofp_action_type_map[a.type])
508 if a.type == ofp.OFPAT_OUTPUT:
509 result = result + ("(%d)" % (a.port))
510 elif a.type == ofp.OFPAT_SET_VLAN_VID:
511 result = result + ("(%d)" % (a.vlan_vid))
512 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
513 result = result + ("(%d)" % (a.vlan_pcp))
514 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
515 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
516 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
517 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
518 elif a.type == ofp.OFPAT_SET_NW_TOS:
519 result = result + ("(0x%x)" % (a.nw_tos))
520 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
521 result = result + ("(%d)" % (a.tp_port))
522 elif a.type == ofp.OFPAT_ENQUEUE:
523 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
524 return result
Howard Pershc7963582012-03-29 10:02:59 -0700525
Howard Persh8d21c1f2012-04-20 15:57:29 -0700526 def rand_actions_ordered(self, fi, valid_actions, valid_ports, valid_queues):
Howard Persh3340d452012-04-06 16:45:21 -0700527 # Action lists are ordered, so pick an ordered random subset of
528 # supported actions
Howard Pershc1199d52012-04-11 14:21:32 -0700529
530 actions_force = test_param_get(fq_config, "actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700531 if actions_force != 0:
532 fq_logger.info("Forced actions:")
533 fq_logger.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700534
Dan Talayco910a8282012-04-07 00:05:20 -0700535 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh3340d452012-04-06 16:45:21 -0700536 supported_actions = []
537 for a in all_actions_list:
538 if ((1 << a) & valid_actions) != 0:
539 supported_actions.append(a)
540
Howard Pershc1199d52012-04-11 14:21:32 -0700541 actions \
542 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
543
544 for a in all_actions_list:
545 if ((1 << a) & actions_force) != 0:
546 actions.append(a)
547
548 actions = shuffle(actions)
Howard Persh3340d452012-04-06 16:45:21 -0700549
Howard Persh6a3698d2012-08-21 14:26:39 -0700550 set_vlanf = False
551 strip_vlanf = False
Howard Persh3340d452012-04-06 16:45:21 -0700552 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700553 for a in actions:
Dan Talayco910a8282012-04-07 00:05:20 -0700554 act = None
Howard Persh3340d452012-04-06 16:45:21 -0700555 if a == ofp.OFPAT_OUTPUT:
556 pass # OUTPUT actions must come last
557 elif a == ofp.OFPAT_SET_VLAN_VID:
Howard Persh6a3698d2012-08-21 14:26:39 -0700558 if not strip_vlanf:
559 act = action.action_set_vlan_vid()
560 act.vlan_vid = fi.rand_vlan()
561 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700562 elif a == ofp.OFPAT_SET_VLAN_PCP:
Howard Persh6a3698d2012-08-21 14:26:39 -0700563 if not strip_vlanf:
564 act = action.action_set_vlan_pcp()
565 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
566 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700567 elif a == ofp.OFPAT_STRIP_VLAN:
Howard Persh6a3698d2012-08-21 14:26:39 -0700568 if not set_vlanf:
569 act = action.action_strip_vlan()
570 strip_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700571 elif a == ofp.OFPAT_SET_DL_SRC:
572 act = action.action_set_dl_src()
573 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700574 elif a == ofp.OFPAT_SET_DL_DST:
575 act = action.action_set_dl_dst()
576 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700577 elif a == ofp.OFPAT_SET_NW_SRC:
578 act = action.action_set_nw_src()
579 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700580 elif a == ofp.OFPAT_SET_NW_DST:
581 act = action.action_set_nw_dst()
582 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700583 elif a == ofp.OFPAT_SET_NW_TOS:
584 act = action.action_set_nw_tos()
585 act.nw_tos = fi.rand_ip_tos()
Howard Persh3340d452012-04-06 16:45:21 -0700586 elif a == ofp.OFPAT_SET_TP_SRC:
587 act = action.action_set_tp_src()
588 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700589 elif a == ofp.OFPAT_SET_TP_DST:
590 act = action.action_set_tp_dst()
591 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700592 elif a == ofp.OFPAT_ENQUEUE:
593 pass # Enqueue actions must come last
Dan Talayco910a8282012-04-07 00:05:20 -0700594 if act:
595 act.max_len = ACTION_MAX_LEN
596 self.actions.add(act)
597
Howard Persh3340d452012-04-06 16:45:21 -0700598 p = random.randint(1, 100)
Howard Pershc1199d52012-04-11 14:21:32 -0700599 if (((1 << ofp.OFPAT_ENQUEUE) & actions_force) != 0 or p <= 33) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700600 and len(valid_queues) > 0 \
601 and ofp.OFPAT_ENQUEUE in actions:
Howard Pershc1199d52012-04-11 14:21:32 -0700602 # In not forecd, one third of the time, include ENQUEUE actions
603 # at end of list
Howard Persh3340d452012-04-06 16:45:21 -0700604 # At most 1 ENQUEUE action
605 act = action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700606 (act.port, act.queue_id) = rand_pick(valid_queues)
Dan Talayco910a8282012-04-07 00:05:20 -0700607 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700608 self.actions.add(act)
Howard Pershc1199d52012-04-11 14:21:32 -0700609 if (((1 << ofp.OFPAT_OUTPUT) & actions_force) != 0 \
610 or (p > 33 and p <= 66) \
611 ) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700612 and len(valid_ports) > 0 \
Howard Pershc1199d52012-04-11 14:21:32 -0700613 and ofp.OFPAT_OUTPUT in actions:
Howard Persh3340d452012-04-06 16:45:21 -0700614 # One third of the time, include OUTPUT actions at end of list
615 port_idxs = shuffle(range(len(valid_ports)))
616 # Only 1 output action allowed if IN_PORT wildcarded
617 n = 1 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) != 0 \
618 else random.randint(1, len(valid_ports))
619 port_idxs = port_idxs[0 : n]
620 for pi in port_idxs:
621 act = action.action_output()
622 act.port = valid_ports[pi]
Dan Talayco910a8282012-04-07 00:05:20 -0700623 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700624 if act.port != ofp.OFPP_IN_PORT \
625 or wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
626 # OUTPUT(IN_PORT) only valid if OFPFW_IN_PORT not wildcarded
627 self.actions.add(act)
628 else:
629 # One third of the time, include neither
630 pass
631
632
633 # Randomize flow data for flow modifies (i.e. cookie and actions)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700634 def rand_mod(self, fi, valid_actions, valid_ports, valid_queues):
rootf6af1672012-04-06 09:46:29 -0700635 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700636
Dan Talayco910a8282012-04-07 00:05:20 -0700637 # By default, test with conservative ordering conventions
638 # This should probably be indicated in a profile
639 if test_param_get(fq_config, "conservative_ordered_actions", True):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700640 self.rand_actions_ordered(fi, valid_actions, valid_ports, valid_queues)
Howard Persh3340d452012-04-06 16:45:21 -0700641 return self
642
Howard Pershc1199d52012-04-11 14:21:32 -0700643 actions_force = test_param_get(fq_config, "actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700644 if actions_force != 0:
645 fq_logger.info("Forced actions:")
646 fq_logger.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700647
648 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh680b92a2012-03-31 13:34:35 -0700649 supported_actions = []
650 for a in all_actions_list:
651 if ((1 << a) & valid_actions) != 0:
652 supported_actions.append(a)
653
Howard Pershc1199d52012-04-11 14:21:32 -0700654 actions \
655 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
656
657 for a in all_actions_list:
658 if ((1 << a) & actions_force) != 0:
659 actions.append(a)
660
661 actions = shuffle(actions)
Howard Pershc7963582012-03-29 10:02:59 -0700662
663 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700664 for a in actions:
Howard Pershc7963582012-03-29 10:02:59 -0700665 if a == ofp.OFPAT_OUTPUT:
666 # TBD - Output actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700667 if len(valid_ports) == 0:
668 continue
Howard Pershc7963582012-03-29 10:02:59 -0700669 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700670 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700671 for pi in port_idxs:
672 act = action.action_output()
Howard Persh680b92a2012-03-31 13:34:35 -0700673 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700674 self.actions.add(act)
675 elif a == ofp.OFPAT_SET_VLAN_VID:
676 act = action.action_set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700677 act.vlan_vid = fi.rand_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700678 self.actions.add(act)
679 elif a == ofp.OFPAT_SET_VLAN_PCP:
Dan Talayco910a8282012-04-07 00:05:20 -0700680 act = action.action_set_vlan_pcp()
681 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700682 elif a == ofp.OFPAT_STRIP_VLAN:
683 act = action.action_strip_vlan()
684 self.actions.add(act)
685 elif a == ofp.OFPAT_SET_DL_SRC:
686 act = action.action_set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700687 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700688 self.actions.add(act)
689 elif a == ofp.OFPAT_SET_DL_DST:
690 act = action.action_set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700691 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700692 self.actions.add(act)
693 elif a == ofp.OFPAT_SET_NW_SRC:
694 act = action.action_set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700695 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700696 self.actions.add(act)
697 elif a == ofp.OFPAT_SET_NW_DST:
698 act = action.action_set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700699 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700700 self.actions.add(act)
701 elif a == ofp.OFPAT_SET_NW_TOS:
702 act = action.action_set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700703 act.nw_tos = fi.rand_ip_tos()
Howard Pershc7963582012-03-29 10:02:59 -0700704 self.actions.add(act)
705 elif a == ofp.OFPAT_SET_TP_SRC:
706 act = action.action_set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700707 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700708 self.actions.add(act)
709 elif a == ofp.OFPAT_SET_TP_DST:
710 act = action.action_set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700711 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700712 self.actions.add(act)
713 elif a == ofp.OFPAT_ENQUEUE:
714 # TBD - Enqueue actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700715 if len(valid_queues) == 0:
716 continue
717 qidxs = shuffle(range(len(valid_queues)))
718 qidxs = qidxs[0 : random.randint(1, len(valid_queues))]
719 for qi in qidxs:
Howard Pershc7963582012-03-29 10:02:59 -0700720 act = action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700721 (act.port, act.queue_id) = valid_queues[qi]
Howard Pershc7963582012-03-29 10:02:59 -0700722 self.actions.add(act)
723
724 return self
725
rootf6af1672012-04-06 09:46:29 -0700726 # Randomize flow cfg
Ed Swierk99a74de2012-08-22 06:40:54 -0700727 def rand(self, fi, wildcards_force, valid_wildcards, valid_actions, valid_ports,
728 valid_queues):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700729 if wildcards_force != 0:
730 fq_logger.info("Wildcards forced:")
731 fq_logger.info(wildcards_to_str(wildcards_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700732
rootf6af1672012-04-06 09:46:29 -0700733 # Start with no wildcards, i.e. everything specified
734 self.match.wildcards = 0
Howard Pershc1199d52012-04-11 14:21:32 -0700735
736 if wildcards_force != 0:
737 exact = False
738 else:
739 # Make approx. 5% of flows exact
740 exact = (random.randint(1, 100) <= 5)
rootf6af1672012-04-06 09:46:29 -0700741
742 # For each qualifier Q,
743 # if (wildcarding is not supported for Q,
744 # or an exact flow is specified
745 # or a coin toss comes up heads),
746 # specify Q
747 # else
748 # wildcard Q
749
Howard Pershc1199d52012-04-11 14:21:32 -0700750 if wildcard_get(wildcards_force, ofp.OFPFW_IN_PORT) == 0 \
751 and (wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
752 or exact \
753 or flip_coin() \
754 ):
rootf6af1672012-04-06 09:46:29 -0700755 self.match.in_port = rand_pick(valid_ports)
756 else:
Howard Persh3340d452012-04-06 16:45:21 -0700757 self.match.wildcards = wildcard_set(self.match.wildcards, \
758 ofp.OFPFW_IN_PORT, \
759 1 \
760 )
rootf6af1672012-04-06 09:46:29 -0700761
Howard Pershc1199d52012-04-11 14:21:32 -0700762 if wildcard_get(wildcards_force, ofp.OFPFW_DL_DST) == 0 \
763 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
764 or exact \
765 or flip_coin() \
766 ):
rootf6af1672012-04-06 09:46:29 -0700767 self.match.dl_dst = fi.rand_dl_addr()
768 else:
Howard Persh3340d452012-04-06 16:45:21 -0700769 self.match.wildcards = wildcard_set(self.match.wildcards, \
770 ofp.OFPFW_DL_DST, \
771 1 \
772 )
rootf6af1672012-04-06 09:46:29 -0700773
Howard Pershc1199d52012-04-11 14:21:32 -0700774 if wildcard_get(wildcards_force, ofp.OFPFW_DL_SRC) == 0 \
775 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
776 or exact \
777 or flip_coin() \
778 ):
rootf6af1672012-04-06 09:46:29 -0700779 self.match.dl_src = fi.rand_dl_addr()
780 else:
Howard Persh3340d452012-04-06 16:45:21 -0700781 self.match.wildcards = wildcard_set(self.match.wildcards, \
782 ofp.OFPFW_DL_SRC, \
783 1 \
784 )
rootf6af1672012-04-06 09:46:29 -0700785
Howard Pershc1199d52012-04-11 14:21:32 -0700786 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN) == 0 \
787 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
788 or exact \
789 or flip_coin() \
790 ):
rootf6af1672012-04-06 09:46:29 -0700791 self.match.dl_vlan = fi.rand_vlan()
792 else:
Howard Persh3340d452012-04-06 16:45:21 -0700793 self.match.wildcards = wildcard_set(self.match.wildcards, \
794 ofp.OFPFW_DL_VLAN, \
795 1 \
796 )
rootf6af1672012-04-06 09:46:29 -0700797
Howard Pershc1199d52012-04-11 14:21:32 -0700798 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN_PCP) == 0 \
799 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
800 or exact \
801 or flip_coin() \
802 ):
803 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
804 else:
805 self.match.wildcards = wildcard_set(self.match.wildcards, \
806 ofp.OFPFW_DL_VLAN_PCP, \
807 1 \
808 )
809
810 if wildcard_get(wildcards_force, ofp.OFPFW_DL_TYPE) == 0 \
811 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
812 or exact \
813 or flip_coin() \
814 ):
rootf6af1672012-04-06 09:46:29 -0700815 self.match.dl_type = fi.rand_ethertype()
816 else:
Howard Persh3340d452012-04-06 16:45:21 -0700817 self.match.wildcards = wildcard_set(self.match.wildcards, \
818 ofp.OFPFW_DL_TYPE, \
819 1 \
820 )
rootf6af1672012-04-06 09:46:29 -0700821
Howard Pershc1199d52012-04-11 14:21:32 -0700822 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_SRC_MASK)
823 if n == 0:
824 if exact or flip_coin():
825 n = 0
826 else:
827 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
828 if n > 32:
829 n = 32
830 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700831 self.match.wildcards = wildcard_set(self.match.wildcards, \
832 ofp.OFPFW_NW_SRC_MASK, \
833 n \
834 )
rootf6af1672012-04-06 09:46:29 -0700835 if n < 32:
836 self.match.nw_src = fi.rand_ip_addr() & ~((1 << n) - 1)
837 # Specifying any IP address match other than all bits
838 # don't care requires that Ethertype is one of {IP, ARP}
839 if flip_coin():
840 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700841 self.match.wildcards = wildcard_set(self.match.wildcards, \
842 ofp.OFPFW_DL_TYPE, \
843 0 \
844 )
rootf6af1672012-04-06 09:46:29 -0700845
Howard Pershc1199d52012-04-11 14:21:32 -0700846 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_DST_MASK)
847 if n == 0:
848 if exact or flip_coin():
849 n = 0
850 else:
851 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
852 if n > 32:
853 n = 32
854 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700855 self.match.wildcards = wildcard_set(self.match.wildcards, \
856 ofp.OFPFW_NW_DST_MASK, \
857 n \
858 )
rootf6af1672012-04-06 09:46:29 -0700859 if n < 32:
860 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
861 # Specifying any IP address match other than all bits
862 # don't care requires that Ethertype is one of {IP, ARP}
863 if flip_coin():
864 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700865 self.match.wildcards = wildcard_set(self.match.wildcards, \
866 ofp.OFPFW_DL_TYPE, \
867 0 \
868 )
rootf6af1672012-04-06 09:46:29 -0700869
Howard Pershc1199d52012-04-11 14:21:32 -0700870 if wildcard_get(wildcards_force, ofp.OFPFW_NW_TOS) == 0 \
871 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
872 or exact \
873 or flip_coin() \
874 ):
rootf6af1672012-04-06 09:46:29 -0700875 self.match.nw_tos = fi.rand_ip_tos()
876 # Specifying a TOS value requires that Ethertype is IP
877 if flip_coin():
878 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700879 self.match.wildcards = wildcard_set(self.match.wildcards, \
880 ofp.OFPFW_DL_TYPE, \
881 0 \
882 )
rootf6af1672012-04-06 09:46:29 -0700883 else:
Howard Persh3340d452012-04-06 16:45:21 -0700884 self.match.wildcards = wildcard_set(self.match.wildcards, \
885 ofp.OFPFW_NW_TOS, \
886 1 \
887 )
rootf6af1672012-04-06 09:46:29 -0700888
Dan Talayco910a8282012-04-07 00:05:20 -0700889 # Known issue on OVS with specifying nw_proto w/o dl_type as IP
Howard Pershc1199d52012-04-11 14:21:32 -0700890 if wildcard_get(wildcards_force, ofp.OFPFW_NW_PROTO) == 0 \
891 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
892 or exact \
893 or flip_coin() \
894 ):
Dan Talayco910a8282012-04-07 00:05:20 -0700895 self.match.nw_proto = fi.rand_ip_proto()
896 # Specifying an IP protocol requires that Ethertype is IP
897 if flip_coin():
898 self.match.dl_type = 0x0800
899 self.match.wildcards = wildcard_set(self.match.wildcards, \
900 ofp.OFPFW_DL_TYPE, \
901 0 \
902 )
903 else:
Howard Persh3340d452012-04-06 16:45:21 -0700904 self.match.wildcards = wildcard_set(self.match.wildcards, \
905 ofp.OFPFW_NW_PROTO, \
906 1 \
907 )
Dan Talayco910a8282012-04-07 00:05:20 -0700908
Howard Pershc1199d52012-04-11 14:21:32 -0700909 if wildcard_get(wildcards_force, ofp.OFPFW_TP_SRC) == 0 \
910 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
911 or exact\
912 or flip_coin() \
913 ):
rootf6af1672012-04-06 09:46:29 -0700914 self.match.tp_src = fi.rand_l4_port()
915 # Specifying a L4 port requires that IP protcol is
916 # one of {ICMP, TCP, UDP}
917 if flip_coin():
918 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700919 self.match.wildcards = wildcard_set(self.match.wildcards, \
920 ofp.OFPFW_NW_PROTO, \
921 0 \
922 )
rootf6af1672012-04-06 09:46:29 -0700923 # Specifying a L4 port requirues that Ethertype is IP
924 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700925 self.match.wildcards = wildcard_set(self.match.wildcards, \
926 ofp.OFPFW_DL_TYPE, \
927 0 \
928 )
rootf6af1672012-04-06 09:46:29 -0700929 if self.match.nw_proto == 1:
930 self.match.tp_src = self.match.tp_src & 0xff
931 else:
Howard Persh3340d452012-04-06 16:45:21 -0700932 self.match.wildcards = wildcard_set(self.match.wildcards, \
933 ofp.OFPFW_TP_SRC, \
934 1 \
935 )
rootf6af1672012-04-06 09:46:29 -0700936
Howard Pershc1199d52012-04-11 14:21:32 -0700937 if wildcard_get(wildcards_force, ofp.OFPFW_TP_DST) == 0 \
938 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
939 or exact \
940 or flip_coin() \
941 ):
rootf6af1672012-04-06 09:46:29 -0700942 self.match.tp_dst = fi.rand_l4_port()
943 # Specifying a L4 port requires that IP protcol is
944 # one of {ICMP, TCP, UDP}
945 if flip_coin():
946 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700947 self.match.wildcards = wildcard_set(self.match.wildcards, \
948 ofp.OFPFW_NW_PROTO, \
949 0 \
950 )
rootf6af1672012-04-06 09:46:29 -0700951 # Specifying a L4 port requirues that Ethertype is IP
952 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700953 self.match.wildcards = wildcard_set(self.match.wildcards, \
954 ofp.OFPFW_DL_TYPE, \
955 0 \
956 )
rootf6af1672012-04-06 09:46:29 -0700957 if self.match.nw_proto == 1:
958 self.match.tp_dst = self.match.tp_dst & 0xff
959 else:
Howard Persh3340d452012-04-06 16:45:21 -0700960 self.match.wildcards = wildcard_set(self.match.wildcards, \
961 ofp.OFPFW_TP_DST, \
962 1 \
963 )
rootf6af1672012-04-06 09:46:29 -0700964
965 # If nothing is wildcarded, it is an exact flow spec -- some switches
Howard Persh3340d452012-04-06 16:45:21 -0700966 # (Open vSwitch, for one) *require* that exact flow specs
967 # have priority 65535.
968 self.priority = 65535 if self.match.wildcards == 0 \
969 else fi.rand_priority()
rootf6af1672012-04-06 09:46:29 -0700970
971 # N.B. Don't make the timeout too short, else the flow might
972 # disappear before we get a chance to check for it.
973 t = random.randint(0, 65535)
974 self.idle_timeout = 0 if t < 60 else t
975 t = random.randint(0, 65535)
976 self.hard_timeout = 0 if t < 60 else t
977
Howard Persh8d21c1f2012-04-20 15:57:29 -0700978 self.rand_mod(fi, valid_actions, valid_ports, valid_queues)
rootf6af1672012-04-06 09:46:29 -0700979
980 return self
981
982 # Return flow cfg in canonical form
Howard Persh3340d452012-04-06 16:45:21 -0700983 # - There are dependencies between flow qualifiers, e.g. it only makes
984 # sense to qualify nw_proto if dl_type is qualified to be 0x0800 (IP).
985 # The canonical form of flow match criteria will "wildcard out"
986 # all such cases.
rootf6af1672012-04-06 09:46:29 -0700987 def canonical(self):
988 result = copy.deepcopy(self)
Howard Persh07d99e62012-04-09 15:26:57 -0700989
990 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_VLAN) != 0:
991 result.match.wildcards = wildcard_set(result.match.wildcards, \
992 ofp.OFPFW_DL_VLAN_PCP, \
993 1 \
994 )
995
rootf6af1672012-04-06 09:46:29 -0700996 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
997 or result.match.dl_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700998 # dl_tyoe is wildcarded, or specified as something other
999 # than IP or ARP
Howard Persh07d99e62012-04-09 15:26:57 -07001000 # => nw_src, nw_dst, nw_proto cannot be specified,
1001 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001002 result.match.wildcards = wildcard_set(result.match.wildcards, \
1003 ofp.OFPFW_NW_SRC_MASK, \
1004 32 \
1005 )
1006 result.match.wildcards = wildcard_set(result.match.wildcards, \
1007 ofp.OFPFW_NW_DST_MASK, \
1008 32 \
1009 )
Howard Persh3340d452012-04-06 16:45:21 -07001010 result.match.wildcards = wildcard_set(result.match.wildcards, \
1011 ofp.OFPFW_NW_PROTO, \
1012 1 \
1013 )
Howard Persh07d99e62012-04-09 15:26:57 -07001014
1015 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
1016 or result.match.dl_type != 0x0800:
1017 # dl_type is wildcarded, or specified as something other than IP
1018 # => nw_tos, tp_src and tp_dst cannot be specified,
1019 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001020 result.match.wildcards = wildcard_set(result.match.wildcards, \
1021 ofp.OFPFW_NW_TOS, \
1022 1 \
1023 )
1024 result.match.wildcards = wildcard_set(result.match.wildcards, \
1025 ofp.OFPFW_TP_SRC, \
1026 1 \
1027 )
1028 result.match.wildcards = wildcard_set(result.match.wildcards, \
1029 ofp.OFPFW_TP_DST, \
1030 1 \
1031 )
Howard Persh07d99e62012-04-09 15:26:57 -07001032 result.match.wildcards = wildcard_set(result.match.wildcards, \
1033 ofp.OFPFW_NW_SRC_MASK, \
1034 32 \
1035 )
1036 result.match.wildcards = wildcard_set(result.match.wildcards, \
1037 ofp.OFPFW_NW_DST_MASK, \
1038 32 \
1039 )
1040 result.match.wildcards = wildcard_set(result.match.wildcards, \
1041 ofp.OFPFW_NW_PROTO, \
1042 1 \
1043 )
1044
rootf6af1672012-04-06 09:46:29 -07001045 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
1046 or result.match.nw_proto not in [1, 6, 17]:
Howard Persh3340d452012-04-06 16:45:21 -07001047 # nw_proto is wildcarded, or specified as something other than ICMP,
1048 # TCP or UDP
rootf6af1672012-04-06 09:46:29 -07001049 # => tp_src and tp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001050 result.match.wildcards = wildcard_set(result.match.wildcards, \
1051 ofp.OFPFW_TP_SRC, \
1052 1 \
1053 )
1054 result.match.wildcards = wildcard_set(result.match.wildcards, \
1055 ofp.OFPFW_TP_DST, \
1056 1 \
1057 )
rootf6af1672012-04-06 09:46:29 -07001058 return result
1059
Howard Persh680b92a2012-03-31 13:34:35 -07001060 # Overlap check
1061 # delf == True <=> Check for delete overlap, else add overlap
1062 # "Add overlap" is defined as there exists a packet that could match both the
1063 # receiver and argument flowspecs
1064 # "Delete overlap" is defined as the specificity of the argument flowspec
1065 # is greater than or equal to the specificity of the receiver flowspec
1066 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -07001067 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
1068 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001069 if self.match.in_port != x.match.in_port:
1070 return False # Both specified, and not equal
1071 elif delf:
1072 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001073 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
1074 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001075 if self.match.dl_vlan != x.match.dl_vlan:
1076 return False # Both specified, and not equal
1077 elif delf:
1078 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001079 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
1080 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001081 if self.match.dl_src != x.match.dl_src:
1082 return False # Both specified, and not equal
1083 elif delf:
1084 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001085 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
1086 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001087 if self.match.dl_dst != x.match.dl_dst:
1088 return False # Both specified, and not equal
1089 elif delf:
1090 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001091 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
1092 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001093 if self.match.dl_type != x.match.dl_type:
1094 return False # Both specified, and not equal
1095 elif delf:
1096 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -07001097 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
1098 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001099 if self.match.nw_proto != x.match.nw_proto:
1100 return False # Both specified, and not equal
1101 elif delf:
1102 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001103 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
1104 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001105 if self.match.tp_src != x.match.tp_src:
1106 return False # Both specified, and not equal
1107 elif delf:
1108 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001109 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
1110 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001111 if self.match.tp_dst != x.match.tp_dst:
1112 return False # Both specified, and not equal
1113 elif delf:
1114 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001115 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
1116 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001117 if delf and na < nb:
1118 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001119 if (na < 32 and nb < 32):
1120 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1121 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -07001122 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -07001123 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
1124 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001125 if delf and na < nb:
1126 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001127 if (na < 32 and nb < 32):
1128 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1129 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
rootf6af1672012-04-06 09:46:29 -07001130 return False # Overlapping bits not equal
1131 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
1132 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001133 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
1134 return False # Both specified, and not equal
1135 elif delf:
1136 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001137 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
1138 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001139 if self.match.nw_tos != x.match.nw_tos:
1140 return False # Both specified, and not equal
1141 elif delf:
1142 return False # Receiver more specific
1143 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -07001144
1145 def to_flow_mod_msg(self, msg):
1146 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -07001147 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001148 msg.idle_timeout = self.idle_timeout
1149 msg.hard_timeout = self.hard_timeout
1150 msg.priority = self.priority
1151 msg.actions = self.actions
1152 return msg
1153
1154 def from_flow_stat(self, msg):
1155 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -07001156 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001157 self.idle_timeout = msg.idle_timeout
1158 self.hard_timeout = msg.hard_timeout
1159 self.priority = msg.priority
1160 self.actions = msg.actions
1161
rootf6af1672012-04-06 09:46:29 -07001162 def from_flow_rem(self, msg):
1163 self.match = msg.match
1164 self.idle_timeout = msg.idle_timeout
1165 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -07001166
Howard Pershc7963582012-03-29 10:02:59 -07001167
rootf6af1672012-04-06 09:46:29 -07001168class Flow_Tbl:
1169 def clear(self):
1170 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001171
rootf6af1672012-04-06 09:46:29 -07001172 def __init__(self):
1173 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001174
rootf6af1672012-04-06 09:46:29 -07001175 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001176 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001177
1178 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001179 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001180
1181 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001182 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001183
1184 def values(self):
1185 return self.dict.values()
1186
1187 def count(self):
1188 return len(self.dict)
1189
Ed Swierk99a74de2012-08-22 06:40:54 -07001190 def rand(self, wildcards_force, sw, fi, num_flows):
rootf6af1672012-04-06 09:46:29 -07001191 self.clear()
1192 i = 0
1193 tbl = 0
1194 j = 0
1195 while i < num_flows:
1196 fc = Flow_Cfg()
1197 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001198 wildcards_force, \
rootf6af1672012-04-06 09:46:29 -07001199 sw.tbl_stats.stats[tbl].wildcards, \
1200 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001201 sw.valid_ports, \
1202 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001203 )
1204 fc = fc.canonical()
1205 if self.find(fc):
1206 continue
1207 fc.send_rem = False
1208 self.insert(fc)
1209 i = i + 1
1210 j = j + 1
1211 if j >= sw.tbl_stats.stats[tbl].max_entries:
1212 tbl = tbl + 1
1213 j = 0
1214
1215
1216class Switch:
1217 # Members:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001218 # controller - switch's test controller
1219 # sw_features - switch's OFPT_FEATURES_REPLY message
1220 # valid_ports - list of valid port numbers
1221 # valid_queues - list of valid [port, queue] pairs
1222 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1223 # queue_stats - switch's OFPT_STATS_REPLY message, for queue stats request
1224 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1225 # flow_tbl - (test's idea of) switch's flow table
rootf6af1672012-04-06 09:46:29 -07001226
1227 def __init__(self):
Howard Persh8d21c1f2012-04-20 15:57:29 -07001228 self.controller = None
1229 self.sw_features = None
1230 self.valid_ports = []
1231 self.valid_queues = []
1232 self.tbl_stats = None
1233 self.flow_stats = None
1234 self.flow_tbl = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001235 self.error_msgs = []
1236 self.removed_msgs = []
1237
1238 def error_handler(self, controller, msg, rawmsg):
1239 fq_logger.info("Got an ERROR message, type=%d, code=%d" \
1240 % (msg.type, msg.code) \
1241 )
1242 fq_logger.info("Message header:")
1243 fq_logger.info(msg.header.show())
1244 self.error_msgs.append(msg)
1245
1246 def removed_handler(self, controller, msg, rawmsg):
1247 fq_logger.info("Got a REMOVED message")
1248 fq_logger.info("Message header:")
1249 fq_logger.info(msg.header.show())
1250 self.removed_msgs.append(msg)
rootf6af1672012-04-06 09:46:29 -07001251
Howard Persh3340d452012-04-06 16:45:21 -07001252 def controller_set(self, controller):
1253 self.controller = controller
1254 # Register error message handler
Ed Swierk99a74de2012-08-22 06:40:54 -07001255 self.error_msgs = []
1256 self.removed_msgs = []
1257 controller.register(ofp.OFPT_ERROR, self.error_handler)
1258 controller.register(ofp.OFPT_FLOW_REMOVED, self.removed_handler)
Howard Persh3340d452012-04-06 16:45:21 -07001259
rootf6af1672012-04-06 09:46:29 -07001260 def features_get(self):
1261 # Get switch features
1262 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001263 (self.sw_features, pkt) = self.controller.transact(request)
rootf6af1672012-04-06 09:46:29 -07001264 if self.sw_features is None:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001265 fq_logger.error("Get switch features failed")
rootf6af1672012-04-06 09:46:29 -07001266 return False
1267 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001268 fq_logger.info("Ports reported by switch:")
1269 fq_logger.info(self.valid_ports)
1270 ports_override = test_param_get(fq_config, "ports", [])
1271 if ports_override != []:
1272 fq_logger.info("Overriding ports to:")
1273 fq_logger.info(ports_override)
1274 self.valid_ports = ports_override
1275
Howard Persh3340d452012-04-06 16:45:21 -07001276 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1277 # is that universal?
1278
1279 # TBD - There seems to be variability in which switches support which
1280 # ports; need to sort that out
1281 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1282# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1283# ofp.OFPP_NORMAL, \
1284# ofp.OFPP_FLOOD, \
1285# ofp.OFPP_ALL, \
1286# ofp.OFPP_CONTROLLER \
1287# ] \
1288# )
Howard Persh8d21c1f2012-04-20 15:57:29 -07001289 fq_logger.info("Supported actions reported by switch:")
1290 fq_logger.info("0x%x=%s" \
1291 % (self.sw_features.actions, \
1292 actions_bmap_to_str(self.sw_features.actions) \
1293 ) \
1294 )
Howard Persh07d99e62012-04-09 15:26:57 -07001295 actions_override = test_param_get(fq_config, "actions", -1)
1296 if actions_override != -1:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001297 fq_logger.info("Overriding supported actions to:")
1298 fq_logger.info(actions_bmap_to_str(actions_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001299 self.sw_features.actions = actions_override
rootf6af1672012-04-06 09:46:29 -07001300 return True
1301
1302 def tbl_stats_get(self):
1303 # Get table stats
Howard Persh680b92a2012-03-31 13:34:35 -07001304 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001305 (self.tbl_stats, pkt) = self.controller.transact(request)
Howard Persh07d99e62012-04-09 15:26:57 -07001306 if self.tbl_stats is None:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001307 fq_logger.error("Get table stats failed")
Howard Persh07d99e62012-04-09 15:26:57 -07001308 return False
Howard Persh8d21c1f2012-04-20 15:57:29 -07001309 i = 0
Howard Persh07d99e62012-04-09 15:26:57 -07001310 for ts in self.tbl_stats.stats:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001311 fq_logger.info("Supported wildcards for table %d reported by switch:"
1312 % (i)
1313 )
1314 fq_logger.info("0x%x=%s" \
1315 % (ts.wildcards, \
1316 wildcards_to_str(ts.wildcards) \
1317 ) \
1318 )
Howard Persh07d99e62012-04-09 15:26:57 -07001319 wildcards_override = test_param_get(fq_config, "wildcards", -1)
1320 if wildcards_override != -1:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001321 fq_logger.info("Overriding supported wildcards for table %d to:"
1322 % (i)
1323 )
1324 fq_logger.info(wildcards_to_str(wildcards_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001325 ts.wildcards = wildcards_override
Howard Persh8d21c1f2012-04-20 15:57:29 -07001326 i = i + 1
Howard Persh07d99e62012-04-09 15:26:57 -07001327 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001328
Howard Persh8d21c1f2012-04-20 15:57:29 -07001329 def queue_stats_get(self):
1330 # Get queue stats
1331 request = message.queue_stats_request()
1332 request.port_no = ofp.OFPP_ALL
1333 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001334 (self.queue_stats, pkt) = self.controller.transact(request)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001335 if self.queue_stats is None:
1336 fq_logger.error("Get queue stats failed")
1337 return False
1338 self.valid_queues = map(lambda x: (x.port_no, x.queue_id), \
1339 self.queue_stats.stats \
1340 )
1341 fq_logger.info("(Port, queue) pairs reported by switch:")
1342 fq_logger.info(self.valid_queues)
1343 queues_override = test_param_get(fq_config, "queues", [])
1344 if queues_override != []:
1345 fq_logger.info("Overriding (port, queue) pairs to:")
1346 fq_logger.info(queues_override)
1347 self.valid_queues = queues_override
1348 return True
1349
1350 def connect(self, controller):
1351 # Connect to controller, and get all switch capabilities
1352 self.controller_set(controller)
1353 return (self.features_get() \
1354 and self.tbl_stats_get() \
1355 and self.queue_stats_get() \
1356 )
1357
Howard Pershc1199d52012-04-11 14:21:32 -07001358 def flow_stats_get(self, limit = 10000):
rootf6af1672012-04-06 09:46:29 -07001359 request = message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -07001360 query_match = ofp.ofp_match()
1361 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001362 request.match = query_match
1363 request.table_id = 0xff
1364 request.out_port = ofp.OFPP_NONE;
Howard Persh3340d452012-04-06 16:45:21 -07001365 if self.controller.message_send(request) == -1:
1366 return False
1367 # <TBD>
1368 # Glue together successive reponse messages for stats reply.
1369 # Looking at the "more" flag and performing re-assembly
1370 # should be a part of the infrastructure.
1371 # </TBD>
1372 n = 0
1373 while True:
Howard Persh07d99e62012-04-09 15:26:57 -07001374 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY, 4)
Howard Persh3340d452012-04-06 16:45:21 -07001375 if resp is None:
Howard Pershc1199d52012-04-11 14:21:32 -07001376 return False # Did not get expected response
Howard Persh3340d452012-04-06 16:45:21 -07001377 if n == 0:
1378 self.flow_stats = resp
1379 else:
1380 self.flow_stats.stats.extend(resp.stats)
1381 n = n + 1
Howard Pershc1199d52012-04-11 14:21:32 -07001382 if len(self.flow_stats.stats) > limit:
1383 fq_logger.error("Too many flows returned")
1384 return False
1385 if (resp.flags & 1) == 0:
1386 break # No more responses expected
Howard Persh3340d452012-04-06 16:45:21 -07001387 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001388
rootf6af1672012-04-06 09:46:29 -07001389 def flow_add(self, flow_cfg, overlapf = False):
Howard Persh680b92a2012-03-31 13:34:35 -07001390 flow_mod_msg = message.flow_mod()
1391 flow_mod_msg.command = ofp.OFPFC_ADD
1392 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001393 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001394 if overlapf:
1395 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001396 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001397 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Howard Persh07d99e62012-04-09 15:26:57 -07001398 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001399 fq_logger.info("Sending flow_mod(add), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001400 % (flow_mod_msg.header.xid)
1401 )
rootf6af1672012-04-06 09:46:29 -07001402 return (self.controller.message_send(flow_mod_msg) != -1)
Howard Persh680b92a2012-03-31 13:34:35 -07001403
rootf6af1672012-04-06 09:46:29 -07001404 def flow_mod(self, flow_cfg, strictf):
Howard Persh680b92a2012-03-31 13:34:35 -07001405 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001406 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf \
1407 else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -07001408 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001409 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001410 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001411 fq_logger.info("Sending flow_mod(mod), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001412 % (flow_mod_msg.header.xid)
1413 )
rootf6af1672012-04-06 09:46:29 -07001414 return (self.controller.message_send(flow_mod_msg) != -1)
1415
1416 def flow_del(self, flow_cfg, strictf):
1417 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001418 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf \
1419 else ofp.OFPFC_DELETE
rootf6af1672012-04-06 09:46:29 -07001420 flow_mod_msg.buffer_id = 0xffffffff
1421 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001422 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001423 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001424 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001425 fq_logger.info("Sending flow_mod(del), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001426 % (flow_mod_msg.header.xid)
1427 )
rootf6af1672012-04-06 09:46:29 -07001428 return (self.controller.message_send(flow_mod_msg) != -1)
1429
1430 def barrier(self):
1431 barrier = message.barrier_request()
Howard Persh07d99e62012-04-09 15:26:57 -07001432 (resp, pkt) = self.controller.transact(barrier, 20)
rootf6af1672012-04-06 09:46:29 -07001433 return (resp is not None)
1434
Howard Persh3340d452012-04-06 16:45:21 -07001435 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001436 result = True
Howard Persh5f3c83f2012-04-13 09:57:10 -07001437 fq_logger.info("Expecting %d error messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001438 num_got = len(self.error_msgs)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001439 fq_logger.info("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001440 if num_got != num_exp:
Dan Talayco910a8282012-04-07 00:05:20 -07001441 fq_logger.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001442 result = False
1443 if num_exp == 0:
1444 return result
1445 elif num_exp == 1:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001446 fq_logger.info("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001447 % (type, code) \
1448 )
1449 f = False
Ed Swierk99a74de2012-08-22 06:40:54 -07001450 for e in self.error_msgs:
Howard Persh3340d452012-04-06 16:45:21 -07001451 if e.type == type and e.code == code:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001452 fq_logger.info("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001453 f = True
1454 if not f:
Dan Talayco910a8282012-04-07 00:05:20 -07001455 fq_logger.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001456 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001457 else:
Dan Talayco910a8282012-04-07 00:05:20 -07001458 fq_logger.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001459 result = False
1460 return result
1461
Howard Persh3340d452012-04-06 16:45:21 -07001462 def removed_verify(self, num_exp):
1463 result = True
Howard Persh5f3c83f2012-04-13 09:57:10 -07001464 fq_logger.info("Expecting %d removed messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001465 num_got = len(self.removed_msgs)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001466 fq_logger.info("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001467 if num_got != num_exp:
Dan Talayco910a8282012-04-07 00:05:20 -07001468 fq_logger.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001469 result = False
1470 if num_exp < 2:
1471 return result
Dan Talayco910a8282012-04-07 00:05:20 -07001472 fq_logger.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001473 return False
1474
Howard Persh5f3c83f2012-04-13 09:57:10 -07001475 # modf == True <=> Verify for flow modify, else for add/delete
1476 def flow_tbl_verify(self, modf = False):
rootf6af1672012-04-06 09:46:29 -07001477 result = True
1478
1479 # Verify flow count in switch
Howard Persh5f3c83f2012-04-13 09:57:10 -07001480 fq_logger.info("Reading table stats")
1481 fq_logger.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001482 if not self.tbl_stats_get():
Dan Talayco910a8282012-04-07 00:05:20 -07001483 fq_logger.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001484 return False
1485 n = 0
1486 for ts in self.tbl_stats.stats:
1487 n = n + ts.active_count
Howard Persh5f3c83f2012-04-13 09:57:10 -07001488 fq_logger.info("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001489 % (n) \
1490 )
1491 if n != self.flow_tbl.count():
Dan Talayco910a8282012-04-07 00:05:20 -07001492 fq_logger.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001493 result = False
1494
1495 # Read flows from switch
Howard Persh5f3c83f2012-04-13 09:57:10 -07001496 fq_logger.info("Retrieving flows from switch")
1497 fq_logger.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001498 if not self.flow_stats_get():
Dan Talayco910a8282012-04-07 00:05:20 -07001499 fq_logger.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001500 return False
Howard Persh5f3c83f2012-04-13 09:57:10 -07001501 fq_logger.info("Retrieved %d flows" % (len(self.flow_stats.stats)))
rootf6af1672012-04-06 09:46:29 -07001502
1503 # Verify flows returned by switch
1504
1505 if len(self.flow_stats.stats) != self.flow_tbl.count():
Dan Talayco910a8282012-04-07 00:05:20 -07001506 fq_logger.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001507 result = False
1508
Howard Persh5f3c83f2012-04-13 09:57:10 -07001509 fq_logger.info("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001510 for fc in self.flow_tbl.values():
1511 fc.matched = False
1512 for fs in self.flow_stats.stats:
1513 flow_in = Flow_Cfg()
1514 flow_in.from_flow_stat(fs)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001515 fq_logger.info("Received flow:")
1516 fq_logger.info(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001517 fc = self.flow_tbl.find(flow_in)
1518 if fc is None:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001519 fq_logger.error("Received flow:")
1520 fq_logger.error(str(flow_in))
Dan Talayco910a8282012-04-07 00:05:20 -07001521 fq_logger.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001522 result = False
1523 elif fc.matched:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001524 fq_logger.error("Received flow:")
1525 fq_logger.error(str(flow_in))
Dan Talayco910a8282012-04-07 00:05:20 -07001526 fq_logger.error("re-matches defined flow:")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001527 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001528 result = False
1529 else:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001530 fq_logger.info("matched")
1531 if modf:
1532 # Check for modify
1533
1534 if flow_in.cookie != fc.cookie:
1535 fq_logger.warning("Defined flow:")
1536 fq_logger.warning(str(fc))
1537 fq_logger.warning("Received flow:")
1538 fq_logger.warning(str(flow_in))
1539 fq_logger.warning("cookies do not match")
1540 if not flow_in.actions_equal(fc):
1541 fq_logger.error("Defined flow:")
1542 fq_logger.error(str(fc))
1543 fq_logger.error("Received flow:")
1544 fq_logger.error(str(flow_in))
1545 fq_logger.error("actions do not match")
1546 else:
1547 # Check for add/delete
1548
1549 if not flow_in == fc:
1550 fq_logger.error("Defined flow:")
1551 fq_logger.error(str(fc))
1552 fq_logger.error("Received flow:")
1553 fq_logger.error(str(flow_in))
1554 fq_logger.error("non-key portions of flow do not match")
1555 result = False
rootf6af1672012-04-06 09:46:29 -07001556 fc.matched = True
1557 for fc in self.flow_tbl.values():
1558 if not fc.matched:
Dan Talayco910a8282012-04-07 00:05:20 -07001559 fq_logger.error("Defined flow:")
1560 fq_logger.error(str(fc))
1561 fq_logger.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001562 result = False
1563
1564 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001565
Howard Persh9cab4822012-09-11 17:08:40 -07001566 def settle(self):
1567 time.sleep(2)
1568
Howard Persh07d99e62012-04-09 15:26:57 -07001569# FLOW ADD 5
1570#
1571# OVERVIEW
1572# Add flows to switch, read back and verify flow configurations
1573#
1574# PURPOSE
1575# - Test acceptance of flow adds
1576# - Test ability of switch to process additions to flow table in random
1577# priority order
1578# - Test correctness of flow configuration responses
1579#
1580# PARAMETERS
1581#
1582# Name: num_flows
1583# Type: number
1584# Description:
1585# Number of flows to define; 0 => maximum number of flows, as determined
1586# from switch capabilities
1587# Default: 100
1588#
1589# PROCESS
1590# 1. Delete all flows from switch
1591# 2. Generate <num_flows> distinct flow configurations
1592# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1593# 4. Verify that no OFPT_ERROR responses were generated by switch
1594# 5. Retrieve flow stats from switch
1595# 6. Compare flow configurations returned by switch
1596# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1597# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001598
rootf6af1672012-04-06 09:46:29 -07001599class Flow_Add_5(basic.SimpleProtocol):
1600 """
1601 Test FLOW_ADD_5 from draft top-half test plan
1602
1603 INPUTS
1604 num_flows - Number of flows to generate
1605 """
Howard Persh680b92a2012-03-31 13:34:35 -07001606
rootf6af1672012-04-06 09:46:29 -07001607 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001608 fq_logger.info("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001609
Dan Talayco910a8282012-04-07 00:05:20 -07001610 num_flows = test_param_get(fq_config, "num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001611
Howard Pershc7963582012-03-29 10:02:59 -07001612 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001613
Howard Persh5f3c83f2012-04-13 09:57:10 -07001614 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001615 rc = delete_all_flows(self.controller, fq_logger)
Howard Pershc7963582012-03-29 10:02:59 -07001616 self.assertEqual(rc, 0, "Failed to delete all flows")
1617
rootf6af1672012-04-06 09:46:29 -07001618 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001619
rootf6af1672012-04-06 09:46:29 -07001620 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001621 self.assertTrue(sw.connect(self.controller), \
1622 "Failed to connect to switch" \
1623 )
Howard Pershc7963582012-03-29 10:02:59 -07001624
rootf6af1672012-04-06 09:46:29 -07001625 if num_flows == 0:
1626 # Number of flows requested was 0
1627 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001628
rootf6af1672012-04-06 09:46:29 -07001629 for ts in sw.tbl_stats.stats:
1630 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001631
Howard Persh5f3c83f2012-04-13 09:57:10 -07001632 fq_logger.info("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001633
1634 # Dream up some flow information, i.e. space to chose from for
1635 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001636
rootf6af1672012-04-06 09:46:29 -07001637 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001638 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001639
rootf6af1672012-04-06 09:46:29 -07001640 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001641
rootf6af1672012-04-06 09:46:29 -07001642 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001643 ft.rand(required_wildcards(self), sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001644
rootf6af1672012-04-06 09:46:29 -07001645 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001646
Howard Persh5f3c83f2012-04-13 09:57:10 -07001647 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001648 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07001649 fq_logger.info("Adding flow:")
1650 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001651 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001652
rootf6af1672012-04-06 09:46:29 -07001653 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001654
rootf6af1672012-04-06 09:46:29 -07001655 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001656
rootf6af1672012-04-06 09:46:29 -07001657 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001658
Howard Persh9cab4822012-09-11 17:08:40 -07001659 sw.settle() # Allow switch to settle and generate any notifications
1660
rootf6af1672012-04-06 09:46:29 -07001661 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001662
rootf6af1672012-04-06 09:46:29 -07001663 if not sw.errors_verify(0):
1664 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001665
rootf6af1672012-04-06 09:46:29 -07001666 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001667
rootf6af1672012-04-06 09:46:29 -07001668 sw.flow_tbl = ft
1669 if not sw.flow_tbl_verify():
1670 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001671
rootf6af1672012-04-06 09:46:29 -07001672 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001673 fq_logger.info("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001674
Howard Pershc7963582012-03-29 10:02:59 -07001675
Howard Persh07d99e62012-04-09 15:26:57 -07001676# FLOW ADD 5_1
1677#
1678# OVERVIEW
1679# Verify handling of non-canonical flows
1680#
1681# PURPOSE
1682# - Test that switch detects and correctly responds to a non-canonical flow
1683# definition. A canonical flow is one that satisfies all match qualifier
1684# dependencies; a non-canonical flow is one that does not.
1685#
1686# PARAMETERS
1687# - None
1688#
1689# PROCESS
1690# 1. Delete all flows from switch
1691# 2. Generate 1 flow definition, which is different from its canonicalization
1692# 3. Send flow to switch
1693# 4. Retrieve flow from switch
1694# 5. Compare returned flow to canonical form of defined flow
1695# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1696
1697# Disabled.
1698# Should be DUT dependent.
1699test_prio["Flow_Add_5_1"] = -1
1700
rootf6af1672012-04-06 09:46:29 -07001701class Flow_Add_5_1(basic.SimpleProtocol):
1702 """
1703 Test FLOW_ADD_5.1 from draft top-half test plan
1704
1705 INPUTS
1706 None
1707 """
1708
1709 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001710 fq_logger.info("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001711
Dan Talayco910a8282012-04-07 00:05:20 -07001712 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001713
1714 # Clear all flows from switch
1715
Howard Persh5f3c83f2012-04-13 09:57:10 -07001716 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001717 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001718 self.assertEqual(rc, 0, "Failed to delete all flows")
1719
1720 # Get switch capabilites
1721
rootf6af1672012-04-06 09:46:29 -07001722 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001723 self.assertTrue(sw.connect(self.controller), \
1724 "Failed to connect to switch" \
1725 )
rootf6af1672012-04-06 09:46:29 -07001726
1727 # Dream up some flow information, i.e. space to chose from for
1728 # random flow parameter generation
1729
1730 fi = Flow_Info()
1731 fi.rand(10)
1732
1733 # Dream up a flow config that will be canonicalized by the switch
1734
1735 while True:
1736 fc = Flow_Cfg()
1737 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001738 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07001739 sw.tbl_stats.stats[0].wildcards, \
1740 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001741 sw.valid_ports, \
1742 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001743 )
1744 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001745 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001746 break
1747
1748 ft = Flow_Tbl()
1749 ft.insert(fcc)
1750
1751 # Send it to the switch
1752
Howard Persh5f3c83f2012-04-13 09:57:10 -07001753 fq_logger.info("Sending flow add to switch:")
1754 fq_logger.info(str(fc))
1755 fq_logger.info("should be canonicalized as:")
1756 fq_logger.info(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001757 fc.send_rem = False
1758 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1759
1760 # Do barrier, to make sure all flows are in
1761
1762 self.assertTrue(sw.barrier(), "Barrier failed")
1763
1764 result = True
1765
Howard Persh9cab4822012-09-11 17:08:40 -07001766 sw.settle() # Allow switch to settle and generate any notifications
1767
rootf6af1672012-04-06 09:46:29 -07001768 # Check for any error messages
1769
1770 if not sw.errors_verify(0):
1771 result = False
1772
1773 # Verify flow table
1774
1775 sw.flow_tbl = ft
1776 if not sw.flow_tbl_verify():
1777 result = False
1778
1779 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001780 fq_logger.info("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001781
1782
Howard Persh07d99e62012-04-09 15:26:57 -07001783# FLOW ADD 6
1784#
1785# OVERVIEW
1786# Test flow table capacity
1787#
1788# PURPOSE
1789# - Test switch can accept as many flow definitions as it claims
1790# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1791# - Test that attempting to create flows beyond capacity does not corrupt
1792# flow table
1793#
1794# PARAMETERS
1795# None
1796#
1797# PROCESS
1798# 1. Delete all flows from switch
1799# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1800# to determine flow table size, N
1801# 3. Generate (N + 1) distinct flow configurations
1802# 4. Send N flow adds to switch, for flows generated in step 3 above
1803# 5. Verify flow table in switch
1804# 6. Send one more flow add to switch
1805# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1806# response was generated by switch, for last flow mod sent
1807# 7. Retrieve flow stats from switch
1808# 8. Verify flow table in switch
1809# 9. Test PASSED iff:
1810# - error message received, for correct flow
1811# - last flow definition sent to switch is not in flow table
1812# else test FAILED
1813
Howard Persh3340d452012-04-06 16:45:21 -07001814# Disabled because of bogus capacity reported by OVS.
1815# Should be DUT dependent.
1816test_prio["Flow_Add_6"] = -1
1817
rootf6af1672012-04-06 09:46:29 -07001818class Flow_Add_6(basic.SimpleProtocol):
1819 """
1820 Test FLOW_ADD_6 from draft top-half test plan
1821
1822 INPUTS
1823 num_flows - Number of flows to generate
1824 """
Howard Pershc7963582012-03-29 10:02:59 -07001825
1826 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001827 fq_logger.info("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001828
rootf6af1672012-04-06 09:46:29 -07001829 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001830
Howard Persh5f3c83f2012-04-13 09:57:10 -07001831 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001832 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001833 self.assertEqual(rc, 0, "Failed to delete all flows")
1834
1835 # Get switch capabilites
1836
rootf6af1672012-04-06 09:46:29 -07001837 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001838 self.assertTrue(sw.connect(self.controller), \
1839 "Failed to connect to switch" \
1840 )
rootf6af1672012-04-06 09:46:29 -07001841
root2843d2b2012-04-06 10:27:46 -07001842 num_flows = 0
rootf6af1672012-04-06 09:46:29 -07001843 for ts in sw.tbl_stats.stats:
1844 num_flows = num_flows + ts.max_entries
1845
Howard Persh5f3c83f2012-04-13 09:57:10 -07001846 fq_logger.info("Switch capacity is %d flows" % (num_flows))
1847 fq_logger.info("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001848
1849 # Dream up some flow information, i.e. space to chose from for
1850 # random flow parameter generation
1851
1852 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001853 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001854
1855 # Create a flow table, to switch's capacity
1856
1857 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001858 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07001859
1860 # Send flow table to switch
1861
Howard Persh5f3c83f2012-04-13 09:57:10 -07001862 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001863 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07001864 fq_logger.info("Adding flow:")
1865 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001866 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1867
1868 # Do barrier, to make sure all flows are in
1869
1870 self.assertTrue(sw.barrier(), "Barrier failed")
1871
1872 result = True
1873
Howard Persh9cab4822012-09-11 17:08:40 -07001874 sw.settle() # Allow switch to settle and generate any notifications
1875
rootf6af1672012-04-06 09:46:29 -07001876 # Check for any error messages
1877
1878 if not sw.errors_verify(0):
1879 result = False
1880
1881 # Dream up one more flow
1882
Howard Persh5f3c83f2012-04-13 09:57:10 -07001883 fq_logger.info("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001884 while True:
1885 fc = Flow_Cfg()
1886 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001887 required_wildcards(self), \
Howard Persh07d99e62012-04-09 15:26:57 -07001888 sw.tbl_stats.stats[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001889 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001890 sw.valid_ports, \
1891 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001892 )
1893 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001894 if not ft.find(fc):
1895 break
rootf6af1672012-04-06 09:46:29 -07001896
1897 # Send one-more flow
1898
1899 fc.send_rem = False
Howard Persh5f3c83f2012-04-13 09:57:10 -07001900 fq_logger.info("Sending flow add switch")
1901 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001902 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1903
1904 # Do barrier, to make sure all flows are in
1905
1906 self.assertTrue(sw.barrier(), "Barrier failed")
1907
Howard Persh9cab4822012-09-11 17:08:40 -07001908 sw.settle() # Allow switch to settle and generate any notifications
1909
rootf6af1672012-04-06 09:46:29 -07001910 # Check for expected error message
1911
1912 if not sw.errors_verify(1, \
1913 ofp.OFPET_FLOW_MOD_FAILED, \
1914 ofp.OFPFMFC_ALL_TABLES_FULL \
1915 ):
1916 result = False
1917
1918 # Verify flow table
1919
1920 sw.flow_tbl = ft
1921 if not sw.flow_tbl_verify():
1922 result = False
1923
1924 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001925 fq_logger.info("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001926
1927
Howard Persh07d99e62012-04-09 15:26:57 -07001928# FLOW ADD 7
1929#
1930# OVERVIEW
1931# Test flow redefinition
1932#
1933# PURPOSE
1934# Verify that successive flow adds with same priority and match criteria
1935# overwrite in flow table
1936#
1937# PARAMETERS
1938# None
1939#
1940# PROCESS
1941# 1. Delete all flows from switch
1942# 2. Generate flow definition F1
1943# 3. Generate flow definition F2, with same key (priority and match) as F1,
1944# but with different actions
1945# 4. Send flow adds for F1 and F2 to switch
1946# 5. Verify flow definitions in switch
1947# 6. Test PASSED iff 1 flow returned by switch, matching configuration of F2;
1948# else test FAILED
1949
rootf6af1672012-04-06 09:46:29 -07001950class Flow_Add_7(basic.SimpleProtocol):
1951 """
1952 Test FLOW_ADD_7 from draft top-half test plan
1953
1954 INPUTS
1955 None
1956 """
1957
1958 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001959 fq_logger.info("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001960
1961 # Clear all flows from switch
1962
Howard Persh5f3c83f2012-04-13 09:57:10 -07001963 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001964 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001965 self.assertEqual(rc, 0, "Failed to delete all flows")
1966
1967 # Get switch capabilites
1968
rootf6af1672012-04-06 09:46:29 -07001969 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001970 self.assertTrue(sw.connect(self.controller), \
1971 "Failed to connect to switch" \
1972 )
rootf6af1672012-04-06 09:46:29 -07001973
1974 # Dream up some flow information, i.e. space to chose from for
1975 # random flow parameter generation
1976
1977 fi = Flow_Info()
1978 fi.rand(10)
1979
1980 # Dream up a flow config
1981
1982 fc = Flow_Cfg()
1983 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001984 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07001985 sw.tbl_stats.stats[0].wildcards, \
1986 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001987 sw.valid_ports, \
1988 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001989 )
1990 fc = fc.canonical()
1991
1992 # Send it to the switch
1993
Howard Persh5f3c83f2012-04-13 09:57:10 -07001994 fq_logger.info("Sending flow add to switch:")
1995 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001996 ft = Flow_Tbl()
1997 fc.send_rem = False
1998 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1999 ft.insert(fc)
2000
2001 # Dream up some different actions, with the same flow key
2002
2003 fc2 = copy.deepcopy(fc)
2004 while True:
2005 fc2.rand_mod(fi, \
2006 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002007 sw.valid_ports, \
2008 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002009 )
2010 if fc2 != fc:
2011 break
2012
2013 # Send that to the switch
2014
Howard Persh5f3c83f2012-04-13 09:57:10 -07002015 fq_logger.info("Sending flow add to switch:")
2016 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002017 fc2.send_rem = False
2018 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
2019 ft.insert(fc2)
2020
2021 # Do barrier, to make sure all flows are in
2022
2023 self.assertTrue(sw.barrier(), "Barrier failed")
2024
2025 result = True
2026
Howard Persh9cab4822012-09-11 17:08:40 -07002027 sw.settle() # Allow switch to settle and generate any notifications
2028
rootf6af1672012-04-06 09:46:29 -07002029 # Check for any error messages
2030
2031 if not sw.errors_verify(0):
2032 result = False
2033
2034 # Verify flow table
2035
2036 sw.flow_tbl = ft
2037 if not sw.flow_tbl_verify():
2038 result = False
2039
2040 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002041 fq_logger.info("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002042
2043
Howard Persh07d99e62012-04-09 15:26:57 -07002044# FLOW ADD 8
2045#
2046# OVERVIEW
2047# Add overlapping flows to switch, verify that overlapping flows are rejected
2048#
2049# PURPOSE
2050# - Test detection of overlapping flows by switch
2051# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
2052# - Test rejection of overlapping flows
2053# - Test defining overlapping flows does not corrupt flow table
2054#
2055# PARAMETERS
2056# None
2057#
2058# PROCESS
2059# 1. Delete all flows from switch
2060# 2. Generate flow definition F1
2061# 3. Generate flow definition F2, with key overlapping F1
2062# 4. Send flow add to switch, for F1
2063# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
2064# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
2065# was generated by switch
2066# 7. Verifiy flows configured in swtich
2067# 8. Test PASSED iff:
2068# - error message received, for overlapping flow
2069# - overlapping flow is not in flow table
2070# else test FAILED
2071
rootf6af1672012-04-06 09:46:29 -07002072class Flow_Add_8(basic.SimpleProtocol):
2073 """
2074 Test FLOW_ADD_8 from draft top-half test plan
2075
2076 INPUTS
2077 None
2078 """
2079
2080 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002081 fq_logger.info("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002082
2083 # Clear all flows from switch
2084
Howard Persh5f3c83f2012-04-13 09:57:10 -07002085 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002086 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002087 self.assertEqual(rc, 0, "Failed to delete all flows")
2088
2089 # Get switch capabilites
2090
rootf6af1672012-04-06 09:46:29 -07002091 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002092 self.assertTrue(sw.connect(self.controller), \
2093 "Failed to connect to switch" \
2094 )
rootf6af1672012-04-06 09:46:29 -07002095
2096 # Dream up some flow information, i.e. space to chose from for
2097 # random flow parameter generation
2098
2099 fi = Flow_Info()
2100 fi.rand(10)
2101
2102 # Dream up a flow config, with at least 1 qualifier specified
2103
2104 fc = Flow_Cfg()
2105 while True:
2106 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002107 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002108 sw.tbl_stats.stats[0].wildcards, \
2109 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002110 sw.valid_ports, \
2111 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002112 )
2113 fc = fc.canonical()
2114 if fc.match.wildcards != ofp.OFPFW_ALL:
2115 break
2116
2117 # Send it to the switch
2118
Howard Persh5f3c83f2012-04-13 09:57:10 -07002119 fq_logger.info("Sending flow add to switch:")
2120 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002121 ft = Flow_Tbl()
2122 fc.send_rem = False
2123 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2124 ft.insert(fc)
2125
2126 # Wildcard out one qualifier that was specified, to create an
2127 # overlapping flow
2128
2129 fc2 = copy.deepcopy(fc)
2130 for wi in shuffle(range(len(all_wildcards_list))):
2131 w = all_wildcards_list[wi]
2132 if (fc2.match.wildcards & w) == 0:
2133 break
2134 if w == ofp.OFPFW_NW_SRC_MASK:
2135 w = ofp.OFPFW_NW_SRC_ALL
2136 wn = "OFPFW_NW_SRC"
2137 elif w == ofp.OFPFW_NW_DST_MASK:
2138 w = ofp.OFPFW_NW_DST_ALL
2139 wn = "OFPFW_NW_DST"
2140 else:
2141 wn = all_wildcard_names[w]
Howard Persh5f3c83f2012-04-13 09:57:10 -07002142 fq_logger.info("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07002143 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07002144 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07002145
2146 # Send that to the switch, with overlap checking
2147
Howard Persh5f3c83f2012-04-13 09:57:10 -07002148 fq_logger.info("Sending flow add to switch:")
2149 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002150 fc2.send_rem = False
2151 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
2152
2153 # Do barrier, to make sure all flows are in
2154 self.assertTrue(sw.barrier(), "Barrier failed")
2155
2156 result = True
2157
Howard Persh9cab4822012-09-11 17:08:40 -07002158 sw.settle() # Allow switch to settle and generate any notifications
2159
rootf6af1672012-04-06 09:46:29 -07002160 # Check for expected error message
2161
2162 if not sw.errors_verify(1, \
2163 ofp.OFPET_FLOW_MOD_FAILED, \
2164 ofp.OFPFMFC_OVERLAP \
2165 ):
2166 result = False
2167
2168 # Verify flow table
2169
2170 sw.flow_tbl = ft
2171 if not sw.flow_tbl_verify():
2172 result = False
2173
2174 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002175 fq_logger.info("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002176
2177
Howard Persh07d99e62012-04-09 15:26:57 -07002178# FLOW MODIFY 1
2179#
2180# OVERVIEW
2181# Strict modify of single existing flow
2182#
2183# PURPOSE
2184# - Verify that strict flow modify operates only on specified flow
2185# - Verify that flow is correctly modified
2186#
2187# PARAMETERS
2188# None
2189#
2190# PROCESS
2191# 1. Delete all flows from switch
2192# 2. Generate 1 flow F
2193# 3. Send flow add to switch, for flow F
2194# 4. Generate new action list for flow F, yielding F'
2195# 5. Send strict flow modify to switch, for flow F'
2196# 6. Verify flow table in switch
2197# 7. Test PASSED iff flow returned by switch is F'; else FAILED
2198
rootf6af1672012-04-06 09:46:29 -07002199class Flow_Mod_1(basic.SimpleProtocol):
2200 """
2201 Test FLOW_MOD_1 from draft top-half test plan
2202
2203 INPUTS
2204 None
2205 """
2206
2207 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002208 fq_logger.info("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002209
2210 # Clear all flows from switch
2211
Howard Persh5f3c83f2012-04-13 09:57:10 -07002212 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002213 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002214 self.assertEqual(rc, 0, "Failed to delete all flows")
2215
2216 # Get switch capabilites
2217
rootf6af1672012-04-06 09:46:29 -07002218 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002219 self.assertTrue(sw.connect(self.controller), \
2220 "Failed to connect to switch" \
2221 )
rootf6af1672012-04-06 09:46:29 -07002222
2223 # Dream up some flow information, i.e. space to chose from for
2224 # random flow parameter generation
2225
2226 fi = Flow_Info()
2227 fi.rand(10)
2228
2229 # Dream up a flow config
2230
2231 fc = Flow_Cfg()
2232 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002233 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002234 sw.tbl_stats.stats[0].wildcards, \
2235 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002236 sw.valid_ports, \
2237 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002238 )
2239 fc = fc.canonical()
2240
2241 # Send it to the switch
2242
Howard Persh5f3c83f2012-04-13 09:57:10 -07002243 fq_logger.info("Sending flow add to switch:")
2244 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002245 ft = Flow_Tbl()
2246 fc.send_rem = False
2247 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2248 ft.insert(fc)
2249
2250 # Dream up some different actions, with the same flow key
2251
2252 fc2 = copy.deepcopy(fc)
2253 while True:
2254 fc2.rand_mod(fi, \
2255 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002256 sw.valid_ports, \
2257 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002258 )
2259 if fc2 != fc:
2260 break
2261
2262 # Send that to the switch
2263
Howard Persh5f3c83f2012-04-13 09:57:10 -07002264 fq_logger.info("Sending strict flow mod to switch:")
2265 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002266 fc2.send_rem = False
2267 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2268 ft.insert(fc2)
2269
2270 # Do barrier, to make sure all flows are in
2271
2272 self.assertTrue(sw.barrier(), "Barrier failed")
2273
2274 result = True
2275
Howard Persh9cab4822012-09-11 17:08:40 -07002276 sw.settle() # Allow switch to settle and generate any notifications
2277
rootf6af1672012-04-06 09:46:29 -07002278 # Check for any error messages
2279
2280 if not sw.errors_verify(0):
2281 result = False
2282
2283 # Verify flow table
2284
2285 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002286 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002287 result = False
2288
2289 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002290 fq_logger.info("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002291
Howard Persh07d99e62012-04-09 15:26:57 -07002292
2293# FLOW MODIFY 2
2294#
2295# OVERVIEW
2296# Loose modify of mutiple flows
2297#
2298# PURPOSE
2299# - Verify that loose flow modify operates only on matching flows
2300# - Verify that matching flows are correctly modified
2301#
2302# PARAMETERS
2303# Name: num_flows
2304# Type: number
2305# Description:
2306# Number of flows to define
2307# Default: 100
2308#
2309# PROCESS
2310# 1. Delete all flows from switch
2311# 2. Generate <num_flows> distinct flow configurations
2312# 3. Send <num_flows> flow adds to switch
2313# 4. Pick 1 defined flow F at random
2314# 5. Create overlapping loose flow mod match criteria by repeatedly
2315# wildcarding out qualifiers in match of F => F',
2316# and create new actions list A' for F'
2317# 6. Send loose flow modify for F' to switch
2318# 7. Verify flow table in swtich
2319# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2320# are returned in step 7 above, each with correct (original or modified)
2321# action list;
2322# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002323
2324class Flow_Mod_2(basic.SimpleProtocol):
2325 """
2326 Test FLOW_MOD_2 from draft top-half test plan
2327
2328 INPUTS
2329 None
2330 """
2331
2332 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002333 fq_logger.info("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002334
Dan Talayco910a8282012-04-07 00:05:20 -07002335 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002336
2337 # Clear all flows from switch
2338
Howard Persh5f3c83f2012-04-13 09:57:10 -07002339 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002340 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002341 self.assertEqual(rc, 0, "Failed to delete all flows")
2342
2343 # Get switch capabilites
2344
rootf6af1672012-04-06 09:46:29 -07002345 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002346 self.assertTrue(sw.connect(self.controller), \
2347 "Failed to connect to switch" \
2348 )
rootf6af1672012-04-06 09:46:29 -07002349
2350 # Dream up some flow information, i.e. space to chose from for
2351 # random flow parameter generation
2352
2353 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002354 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002355 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002356
2357 # Dream up some flows
2358
2359 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002360 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002361
2362 # Send flow table to switch
2363
Howard Persh5f3c83f2012-04-13 09:57:10 -07002364 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002365 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07002366 fq_logger.info("Adding flow:")
2367 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002368 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2369
2370 # Do barrier, to make sure all flows are in
2371
2372 self.assertTrue(sw.barrier(), "Barrier failed")
2373
2374 result = True
2375
Howard Persh9cab4822012-09-11 17:08:40 -07002376 sw.settle() # Allow switch to settle and generate any notifications
2377
rootf6af1672012-04-06 09:46:29 -07002378 # Check for any error messages
2379
2380 if not sw.errors_verify(0):
2381 result = False
2382
2383 # Verify flow table
2384
2385 sw.flow_tbl = ft
2386 if not sw.flow_tbl_verify():
2387 result = False
2388
2389 # Pick a random flow as a basis
Howard Persh5f3c83f2012-04-13 09:57:10 -07002390
2391 mfc = copy.deepcopy((ft.values())[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002392 mfc.rand_mod(fi, \
2393 sw.sw_features.actions, \
2394 sw.valid_ports, \
2395 sw.valid_queues \
2396 )
rootf6af1672012-04-06 09:46:29 -07002397
2398 # Repeatedly wildcard qualifiers
2399
2400 for wi in shuffle(range(len(all_wildcards_list))):
2401 w = all_wildcards_list[wi]
2402 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2403 n = wildcard_get(mfc.match.wildcards, w)
2404 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002405 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2406 w, \
2407 random.randint(n + 1, 32) \
2408 )
rootf6af1672012-04-06 09:46:29 -07002409 else:
2410 continue
2411 else:
2412 if wildcard_get(mfc.match.wildcards, w) == 0:
2413 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2414 else:
2415 continue
2416 mfc = mfc.canonical()
2417
2418 # Count the number of flows that would be modified
2419
2420 n = 0
2421 for fc in ft.values():
2422 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2423 n = n + 1
2424
2425 # If more than 1, we found our loose delete flow spec
2426 if n > 1:
2427 break
2428
Howard Persh5f3c83f2012-04-13 09:57:10 -07002429 fq_logger.info("Modifying %d flows" % (n))
2430 fq_logger.info("Sending flow mod to switch:")
2431 fq_logger.info(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002432 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2433
2434 # Do barrier, to make sure all flows are in
2435 self.assertTrue(sw.barrier(), "Barrier failed")
2436
Howard Persh9cab4822012-09-11 17:08:40 -07002437 sw.settle() # Allow switch to settle and generate any notifications
2438
rootf6af1672012-04-06 09:46:29 -07002439 # Check for error message
2440
2441 if not sw.errors_verify(0):
2442 result = False
2443
2444 # Apply flow mod to local flow table
2445
2446 for fc in ft.values():
2447 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002448 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002449
2450 # Verify flow table
2451
2452 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002453 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002454 result = False
2455
2456 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002457 fq_logger.info("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002458
2459
Howard Persh07d99e62012-04-09 15:26:57 -07002460# FLOW MODIFY 3
2461
2462# OVERVIEW
2463# Strict modify of non-existent flow
2464#
2465# PURPOSE
2466# Verify that strict modify of a non-existent flow is equivalent to a flow add
2467#
2468# PARAMETERS
2469# None
2470#
2471# PROCESS
2472# 1. Delete all flows from switch
2473# 2. Send single flow mod, as strict modify, to switch
2474# 3. Verify flow table in switch
2475# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2476
rootf6af1672012-04-06 09:46:29 -07002477class Flow_Mod_3(basic.SimpleProtocol):
2478 """
2479 Test FLOW_MOD_3 from draft top-half test plan
2480
2481 INPUTS
2482 None
2483 """
2484
2485 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002486 fq_logger.info("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002487
2488 # Clear all flows from switch
2489
Howard Persh5f3c83f2012-04-13 09:57:10 -07002490 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002491 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002492 self.assertEqual(rc, 0, "Failed to delete all flows")
2493
2494 # Get switch capabilites
2495
rootf6af1672012-04-06 09:46:29 -07002496 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002497 self.assertTrue(sw.connect(self.controller), \
2498 "Failed to connect to switch" \
2499 )
rootf6af1672012-04-06 09:46:29 -07002500
2501 # Dream up some flow information, i.e. space to chose from for
2502 # random flow parameter generation
2503
2504 fi = Flow_Info()
2505 fi.rand(10)
2506
2507 # Dream up a flow config
2508
2509 fc = Flow_Cfg()
2510 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002511 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002512 sw.tbl_stats.stats[0].wildcards, \
2513 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002514 sw.valid_ports, \
2515 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002516 )
2517 fc = fc.canonical()
2518
2519 # Send it to the switch
2520
Howard Persh5f3c83f2012-04-13 09:57:10 -07002521 fq_logger.info("Sending flow mod to switch:")
2522 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002523 ft = Flow_Tbl()
2524 fc.send_rem = False
2525 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2526 ft.insert(fc)
2527
2528 # Do barrier, to make sure all flows are in
2529
2530 self.assertTrue(sw.barrier(), "Barrier failed")
2531
2532 result = True
2533
Howard Persh9cab4822012-09-11 17:08:40 -07002534 sw.settle() # Allow switch to settle and generate any notifications
2535
rootf6af1672012-04-06 09:46:29 -07002536 # Check for any error messages
2537
2538 if not sw.errors_verify(0):
2539 result = False
2540
2541 # Verify flow table
2542
2543 sw.flow_tbl = ft
2544 if not sw.flow_tbl_verify():
2545 result = False
2546
2547 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002548 fq_logger.info("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002549
2550
Howard Persh8d21c1f2012-04-20 15:57:29 -07002551# FLOW MODIFY 3_1
2552
2553# OVERVIEW
2554# No-op modify
2555#
2556# PURPOSE
2557# Verify that modify of a flow with new actions same as old ones operates correctly
2558#
2559# PARAMETERS
2560# None
2561#
2562# PROCESS
2563# 1. Delete all flows from switch
2564# 2. Send single flow mod, as strict modify, to switch
2565# 3. Verify flow table in switch
2566# 4. Send same flow mod, as strict modify, to switch
2567# 5. Verify flow table in switch
2568# 6. Test PASSED iff flow defined in step 2 and 4 above verified; else FAILED
2569
2570class Flow_Mod_3_1(basic.SimpleProtocol):
2571 """
2572 Test FLOW_MOD_3_1 from draft top-half test plan
2573
2574 INPUTS
2575 None
2576 """
2577
2578 def runTest(self):
2579 fq_logger.info("Flow_Mod_3_1 TEST BEGIN")
2580
2581 # Clear all flows from switch
2582
2583 fq_logger.info("Deleting all flows from switch")
2584 rc = delete_all_flows(self.controller, fq_logger)
2585 self.assertEqual(rc, 0, "Failed to delete all flows")
2586
2587 # Get switch capabilites
2588
2589 sw = Switch()
2590 self.assertTrue(sw.connect(self.controller), \
2591 "Failed to connect to switch" \
2592 )
2593
2594 # Dream up some flow information, i.e. space to chose from for
2595 # random flow parameter generation
2596
2597 fi = Flow_Info()
2598 fi.rand(10)
2599
2600 # Dream up a flow config
2601
2602 fc = Flow_Cfg()
2603 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002604 required_wildcards(self), \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002605 sw.tbl_stats.stats[0].wildcards, \
2606 sw.sw_features.actions, \
2607 sw.valid_ports, \
2608 sw.valid_queues \
2609 )
2610 fc = fc.canonical()
2611
2612 # Send it to the switch
2613
2614 fq_logger.info("Sending flow mod to switch:")
2615 fq_logger.info(str(fc))
2616 ft = Flow_Tbl()
2617 fc.send_rem = False
2618 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2619 ft.insert(fc)
2620
2621 # Do barrier, to make sure all flows are in
2622
2623 self.assertTrue(sw.barrier(), "Barrier failed")
2624
2625 result = True
2626
Howard Persh9cab4822012-09-11 17:08:40 -07002627 sw.settle() # Allow switch to settle and generate any notifications
2628
Howard Persh8d21c1f2012-04-20 15:57:29 -07002629 # Check for any error messages
2630
2631 if not sw.errors_verify(0):
2632 result = False
2633
2634 # Verify flow table
2635
2636 sw.flow_tbl = ft
2637 if not sw.flow_tbl_verify():
2638 result = False
2639
2640 # Send same flow to the switch again
2641
2642 fq_logger.info("Sending flow mod to switch:")
2643 fq_logger.info(str(fc))
2644 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2645
2646 # Do barrier, to make sure all flows are in
2647
2648 self.assertTrue(sw.barrier(), "Barrier failed")
2649
Howard Persh9cab4822012-09-11 17:08:40 -07002650 sw.settle() # Allow switch to settle and generate any notifications
2651
Howard Persh8d21c1f2012-04-20 15:57:29 -07002652 # Check for any error messages
2653
2654 if not sw.errors_verify(0):
2655 result = False
2656
2657 # Verify flow table
2658
2659 if not sw.flow_tbl_verify():
2660 result = False
2661
2662 self.assertTrue(result, "Flow_Mod_3_1 TEST FAILED")
2663 fq_logger.info("Flow_Mod_3_1 TEST PASSED")
2664
2665
Howard Persh07d99e62012-04-09 15:26:57 -07002666# FLOW DELETE 1
2667#
2668# OVERVIEW
2669# Strict delete of single flow
2670#
2671# PURPOSE
2672# Verify correct operation of strict delete of single defined flow
2673#
2674# PARAMETERS
2675# None
2676#
2677# PROCESS
2678# 1. Delete all flows from switch
2679# 2. Send flow F to switch
2680# 3. Send strict flow delete for F to switch
2681# 4. Verify flow table in swtich
2682# 6. Test PASSED iff all flows sent to switch in step 2 above,
2683# less flow removed in step 3 above, are returned in step 4 above;
2684# else test FAILED
2685
rootf6af1672012-04-06 09:46:29 -07002686class Flow_Del_1(basic.SimpleProtocol):
2687 """
2688 Test FLOW_DEL_1 from draft top-half test plan
2689
2690 INPUTS
2691 None
2692 """
2693
2694 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002695 fq_logger.info("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002696
2697 # Clear all flows from switch
2698
Howard Persh5f3c83f2012-04-13 09:57:10 -07002699 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002700 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002701 self.assertEqual(rc, 0, "Failed to delete all flows")
2702
2703 # Get switch capabilites
2704
rootf6af1672012-04-06 09:46:29 -07002705 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002706 self.assertTrue(sw.connect(self.controller), \
2707 "Failed to connect to switch" \
2708 )
rootf6af1672012-04-06 09:46:29 -07002709
2710 # Dream up some flow information, i.e. space to chose from for
2711 # random flow parameter generation
2712
2713 fi = Flow_Info()
2714 fi.rand(10)
2715
2716 # Dream up a flow config
2717
2718 fc = Flow_Cfg()
2719 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002720 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002721 sw.tbl_stats.stats[0].wildcards, \
2722 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002723 sw.valid_ports, \
2724 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002725 )
2726 fc = fc.canonical()
2727
2728 # Send it to the switch
2729
Howard Persh5f3c83f2012-04-13 09:57:10 -07002730 fq_logger.info("Sending flow add to switch:")
2731 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002732 ft = Flow_Tbl()
2733 fc.send_rem = False
2734 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2735 ft.insert(fc)
2736
2737 # Dream up some different actions, with the same flow key
2738
2739 fc2 = copy.deepcopy(fc)
2740 while True:
2741 fc2.rand_mod(fi, \
2742 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002743 sw.valid_ports, \
2744 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002745 )
2746 if fc2 != fc:
2747 break
2748
2749 # Delete strictly
2750
Howard Persh5f3c83f2012-04-13 09:57:10 -07002751 fq_logger.info("Sending strict flow del to switch:")
2752 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002753 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2754 ft.delete(fc)
2755
2756 # Do barrier, to make sure all flows are in
2757
2758 self.assertTrue(sw.barrier(), "Barrier failed")
2759
2760 result = True
2761
Howard Persh9cab4822012-09-11 17:08:40 -07002762 sw.settle() # Allow switch to settle and generate any notifications
2763
rootf6af1672012-04-06 09:46:29 -07002764 # Check for any error messages
2765
2766 if not sw.errors_verify(0):
2767 result = False
2768
2769 # Verify flow table
2770
2771 sw.flow_tbl = ft
2772 if not sw.flow_tbl_verify():
2773 result = False
2774
2775 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002776 fq_logger.info("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002777
2778
Howard Persh07d99e62012-04-09 15:26:57 -07002779# FLOW DELETE 2
2780#
2781# OVERVIEW
2782# Loose delete of multiple flows
2783#
2784# PURPOSE
2785# - Verify correct operation of loose delete of multiple flows
2786#
2787# PARAMETERS
2788# Name: num_flows
2789# Type: number
2790# Description:
2791# Number of flows to define
2792# Default: 100
2793#
2794# PROCESS
2795# 1. Delete all flows from switch
2796# 2. Generate <num_flows> distinct flow configurations
2797# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2798# 4. Pick 1 defined flow F at random
2799# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2800# F' will match more than 1 existing flow key
2801# 6. Send loose flow delete for F' to switch
2802# 7. Verify flow table in switch
2803# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2804# removed in step 6 above (i.e. those that match F'), are returned
2805# in step 7 above;
2806# else test FAILED
2807
rootf6af1672012-04-06 09:46:29 -07002808class Flow_Del_2(basic.SimpleProtocol):
2809 """
2810 Test FLOW_DEL_2 from draft top-half test plan
2811
2812 INPUTS
2813 None
2814 """
2815
2816 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002817 fq_logger.info("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002818
Dan Talayco910a8282012-04-07 00:05:20 -07002819 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002820
2821 # Clear all flows from switch
2822
Howard Persh5f3c83f2012-04-13 09:57:10 -07002823 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002824 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002825 self.assertEqual(rc, 0, "Failed to delete all flows")
2826
2827 # Get switch capabilites
2828
rootf6af1672012-04-06 09:46:29 -07002829 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002830 self.assertTrue(sw.connect(self.controller), \
2831 "Failed to connect to switch" \
2832 )
rootf6af1672012-04-06 09:46:29 -07002833
2834 # Dream up some flow information, i.e. space to chose from for
2835 # random flow parameter generation
2836
2837 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002838 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002839 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002840
2841 # Dream up some flows
2842
2843 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002844 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002845
2846 # Send flow table to switch
2847
Howard Persh5f3c83f2012-04-13 09:57:10 -07002848 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002849 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07002850 fq_logger.info("Adding flow:")
2851 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002852 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2853
2854 # Do barrier, to make sure all flows are in
2855
2856 self.assertTrue(sw.barrier(), "Barrier failed")
2857
2858 result = True
2859
Howard Persh9cab4822012-09-11 17:08:40 -07002860 sw.settle() # Allow switch to settle and generate any notifications
2861
rootf6af1672012-04-06 09:46:29 -07002862 # Check for any error messages
2863
2864 if not sw.errors_verify(0):
2865 result = False
2866
2867 # Verify flow table
2868
2869 sw.flow_tbl = ft
2870 if not sw.flow_tbl_verify():
2871 result = False
2872
2873 # Pick a random flow as a basis
2874
2875 dfc = copy.deepcopy(ft.values()[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002876 dfc.rand_mod(fi, \
2877 sw.sw_features.actions, \
2878 sw.valid_ports, \
2879 sw.valid_queues \
2880 )
rootf6af1672012-04-06 09:46:29 -07002881
2882 # Repeatedly wildcard qualifiers
2883
2884 for wi in shuffle(range(len(all_wildcards_list))):
2885 w = all_wildcards_list[wi]
2886 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2887 n = wildcard_get(dfc.match.wildcards, w)
2888 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002889 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2890 w, \
2891 random.randint(n + 1, 32) \
2892 )
rootf6af1672012-04-06 09:46:29 -07002893 else:
2894 continue
2895 else:
2896 if wildcard_get(dfc.match.wildcards, w) == 0:
2897 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2898 else:
2899 continue
2900 dfc = dfc.canonical()
2901
2902 # Count the number of flows that would be deleted
2903
2904 n = 0
2905 for fc in ft.values():
2906 if dfc.overlaps(fc, True):
2907 n = n + 1
2908
2909 # If more than 1, we found our loose delete flow spec
2910 if n > 1:
2911 break
2912
Howard Persh5f3c83f2012-04-13 09:57:10 -07002913 fq_logger.info("Deleting %d flows" % (n))
2914 fq_logger.info("Sending flow del to switch:")
2915 fq_logger.info(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002916 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2917
2918 # Do barrier, to make sure all flows are in
2919 self.assertTrue(sw.barrier(), "Barrier failed")
2920
Howard Persh9cab4822012-09-11 17:08:40 -07002921 sw.settle() # Allow switch to settle and generate any notifications
2922
rootf6af1672012-04-06 09:46:29 -07002923 # Check for error message
2924
2925 if not sw.errors_verify(0):
2926 result = False
2927
2928 # Apply flow mod to local flow table
2929
2930 for fc in ft.values():
2931 if dfc.overlaps(fc, True):
2932 ft.delete(fc)
2933
2934 # Verify flow table
2935
2936 sw.flow_tbl = ft
2937 if not sw.flow_tbl_verify():
2938 result = False
2939
2940 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002941 fq_logger.info("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002942
2943
Howard Persh07d99e62012-04-09 15:26:57 -07002944# FLOW DELETE 4
2945#
2946# OVERVIEW
2947# Flow removed messages
2948#
2949# PURPOSE
2950# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2951# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2952#
2953# PARAMETERS
2954# None
2955#
2956# PROCESS
2957# 1. Delete all flows from switch
2958# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2959# 3. Send strict flow delete of flow to switch
2960# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2961# 5. Verify flow table in switch
2962# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2963# removed in step 3 above, are returned in step 5 above, and that
2964# asynch message was received; else test FAILED
2965
2966
rootf6af1672012-04-06 09:46:29 -07002967class Flow_Del_4(basic.SimpleProtocol):
2968 """
2969 Test FLOW_DEL_4 from draft top-half test plan
2970
2971 INPUTS
2972 None
2973 """
2974
2975 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002976 fq_logger.info("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002977
2978 # Clear all flows from switch
2979
Howard Persh5f3c83f2012-04-13 09:57:10 -07002980 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002981 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002982 self.assertEqual(rc, 0, "Failed to delete all flows")
2983
2984 # Get switch capabilites
2985
rootf6af1672012-04-06 09:46:29 -07002986 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002987 self.assertTrue(sw.connect(self.controller), \
2988 "Failed to connect to switch" \
2989 )
rootf6af1672012-04-06 09:46:29 -07002990
2991 # Dream up some flow information, i.e. space to chose from for
2992 # random flow parameter generation
2993
2994 fi = Flow_Info()
2995 fi.rand(10)
2996
2997 # Dream up a flow config
2998
2999 fc = Flow_Cfg()
3000 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07003001 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07003002 sw.tbl_stats.stats[0].wildcards, \
3003 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07003004 sw.valid_ports, \
3005 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07003006 )
3007 fc = fc.canonical()
3008
3009 # Send it to the switch. with "notify on removed"
3010
Howard Persh5f3c83f2012-04-13 09:57:10 -07003011 fq_logger.info("Sending flow add to switch:")
3012 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07003013 ft = Flow_Tbl()
3014 fc.send_rem = True
3015 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
3016 ft.insert(fc)
3017
3018 # Dream up some different actions, with the same flow key
3019
3020 fc2 = copy.deepcopy(fc)
3021 while True:
3022 fc2.rand_mod(fi, \
3023 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07003024 sw.valid_ports, \
3025 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07003026 )
3027 if fc2 != fc:
3028 break
3029
3030 # Delete strictly
3031
Howard Persh5f3c83f2012-04-13 09:57:10 -07003032 fq_logger.info("Sending strict flow del to switch:")
3033 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07003034 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
3035 ft.delete(fc)
3036
3037 # Do barrier, to make sure all flows are in
3038
3039 self.assertTrue(sw.barrier(), "Barrier failed")
3040
3041 result = True
3042
Howard Persh9cab4822012-09-11 17:08:40 -07003043 sw.settle() # Allow switch to settle and generate any notifications
3044
rootf6af1672012-04-06 09:46:29 -07003045 # Check for expected "removed" message
3046
Howard Persh3340d452012-04-06 16:45:21 -07003047 if not sw.errors_verify(0):
3048 result = False
3049
3050 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07003051 result = False
3052
3053 # Verify flow table
3054
3055 sw.flow_tbl = ft
3056 if not sw.flow_tbl_verify():
3057 result = False
3058
3059 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07003060 fq_logger.info("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07003061