blob: f8b8fb234cc6a1b05373833458969c79cd54cf15 [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 Persh07d99e62012-04-09 15:26:57 -070046# Name: conservative_ordered_actions
47# Type: boolean (True or False)
48# Description:
49# Compare flow actions lists as unordered
50# Default: True
51
52
Howard Persh680b92a2012-03-31 13:34:35 -070053import math
Howard Pershc7963582012-03-29 10:02:59 -070054
55import logging
56
57import unittest
58import random
59
60import oftest.controller as controller
61import oftest.cstruct as ofp
62import oftest.message as message
63import oftest.dataplane as dataplane
64import oftest.action as action
65import oftest.action_list as action_list
66import oftest.parse as parse
67import pktact
68import basic
69
70from testutils import *
71from time import sleep
72
73#@var port_map Local copy of the configuration map from OF port
74# numbers to OS interfaces
Dan Talayco910a8282012-04-07 00:05:20 -070075fq_port_map = None
76#@var fq_logger Local logger object
77fq_logger = None
78#@var fq_config Local copy of global configuration data
79fq_config = None
Howard Pershc7963582012-03-29 10:02:59 -070080
rootf6af1672012-04-06 09:46:29 -070081# For test priority
82test_prio = {}
83
84
Howard Pershc7963582012-03-29 10:02:59 -070085def test_set_init(config):
86 """
87 Set up function for packet action test classes
88
89 @param config The configuration dictionary; see oft
90 """
91
92 basic.test_set_init(config)
93
Dan Talayco910a8282012-04-07 00:05:20 -070094 global fq_port_map
95 global fq_logger
96 global fq_config
Howard Pershc7963582012-03-29 10:02:59 -070097
Dan Talayco910a8282012-04-07 00:05:20 -070098 fq_logger = logging.getLogger("flowq")
99 fq_logger.info("Initializing test set")
100 fq_port_map = config["port_map"]
101 fq_config = config
root2843d2b2012-04-06 10:27:46 -0700102
Howard Pershc7963582012-03-29 10:02:59 -0700103
rootf6af1672012-04-06 09:46:29 -0700104def flip_coin():
105 return random.randint(1, 100) <= 50
106
107
Howard Pershc7963582012-03-29 10:02:59 -0700108def shuffle(list):
109 n = len(list)
110 lim = n * n
111 i = 0
112 while i < lim:
113 a = random.randint(0, n - 1)
114 b = random.randint(0, n - 1)
115 temp = list[a]
116 list[a] = list[b]
117 list[b] = temp
118 i = i + 1
119 return list
120
121
Howard Persh680b92a2012-03-31 13:34:35 -0700122def rand_pick(list):
123 return list[random.randint(0, len(list) - 1)]
Howard Pershc7963582012-03-29 10:02:59 -0700124
Howard Persh680b92a2012-03-31 13:34:35 -0700125def rand_dl_addr():
126 return [random.randint(0, 255) & ~1,
127 random.randint(0, 255),
128 random.randint(0, 255),
129 random.randint(0, 255),
130 random.randint(0, 255),
131 random.randint(0, 255)
132 ]
Howard Pershc7963582012-03-29 10:02:59 -0700133
134def rand_nw_addr():
135 return random.randint(0, (1 << 32) - 1)
136
137
rootf6af1672012-04-06 09:46:29 -0700138class Flow_Info:
Howard Persh680b92a2012-03-31 13:34:35 -0700139 # Members:
140 # priorities - list of flow priorities
141 # dl_addrs - list of MAC addresses
142 # vlans - list of VLAN ids
143 # ethertypes - list of Ethertypes
144 # ip_addrs - list of IP addresses
145 # ip_tos - list of IP TOS values
146 # ip_protos - list of IP protocols
147 # l4_ports - list of L4 ports
148
149 def __init__(self):
150 priorities = []
151 dl_addrs = []
152 vlans = []
153 ethertypes = []
154 ip_addrs = []
155 ip_tos = []
156 ip_protos = []
157 l4_ports = []
158
159 def rand(self, n):
160 self.priorities = []
161 i = 0
162 while i < n:
163 self.priorities.append(random.randint(1, 65534))
164 i = i + 1
165
166 self.dl_addrs = []
167 i = 0
168 while i < n:
169 self.dl_addrs.append(rand_dl_addr())
170 i = i + 1
171
172 self.vlans = []
173 i = 0
174 while i < n:
175 self.vlans.append(random.randint(1, 4094))
176 i = i + 1
177
rootf6af1672012-04-06 09:46:29 -0700178 self.ethertypes = [0x0800, 0x0806]
Howard Persh680b92a2012-03-31 13:34:35 -0700179 i = 0
180 while i < n:
181 self.ethertypes.append(random.randint(0, (1 << 16) - 1))
182 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700183 self.ethertypes = shuffle(self.ethertypes)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700184
185 self.ip_addrs = []
186 i = 0
187 while i < n:
188 self.ip_addrs.append(rand_nw_addr())
189 i = i + 1
190
191 self.ip_tos = []
192 i = 0
193 while i < n:
194 self.ip_tos.append(random.randint(0, (1 << 8) - 1) & ~3)
195 i = i + 1
196
rootf6af1672012-04-06 09:46:29 -0700197 self.ip_protos = [1, 6, 17]
Howard Persh680b92a2012-03-31 13:34:35 -0700198 i = 0
199 while i < n:
200 self.ip_protos.append(random.randint(0, (1 << 8) - 1))
201 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700202 self.ip_protos = shuffle(self.ip_protos)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700203
204 self.l4_ports = []
205 i = 0
206 while i < n:
207 self.l4_ports.append(random.randint(0, (1 << 16) - 1))
208 i = i + 1
209
210 def rand_priority(self):
211 return rand_pick(self.priorities)
212
213 def rand_dl_addr(self):
214 return rand_pick(self.dl_addrs)
215
216 def rand_vlan(self):
217 return rand_pick(self.vlans)
218
219 def rand_ethertype(self):
220 return rand_pick(self.ethertypes)
221
222 def rand_ip_addr(self):
223 return rand_pick(self.ip_addrs)
224
225 def rand_ip_tos(self):
226 return rand_pick(self.ip_tos)
227
228 def rand_ip_proto(self):
229 return rand_pick(self.ip_protos)
230
231 def rand_l4_port(self):
232 return rand_pick(self.l4_ports)
233
234
Howard Pershc7963582012-03-29 10:02:59 -0700235# TBD - These don't belong here
236
Howard Persh680b92a2012-03-31 13:34:35 -0700237all_wildcards_list = [ofp.OFPFW_IN_PORT,
Howard Persh680b92a2012-03-31 13:34:35 -0700238 ofp.OFPFW_DL_DST,
rootf6af1672012-04-06 09:46:29 -0700239 ofp.OFPFW_DL_SRC,
240 ofp.OFPFW_DL_VLAN,
241 ofp.OFPFW_DL_VLAN_PCP,
Howard Persh680b92a2012-03-31 13:34:35 -0700242 ofp.OFPFW_DL_TYPE,
rootf6af1672012-04-06 09:46:29 -0700243 ofp.OFPFW_NW_TOS,
Howard Persh680b92a2012-03-31 13:34:35 -0700244 ofp.OFPFW_NW_PROTO,
Howard Persh680b92a2012-03-31 13:34:35 -0700245 ofp.OFPFW_NW_SRC_MASK,
246 ofp.OFPFW_NW_DST_MASK,
rootf6af1672012-04-06 09:46:29 -0700247 ofp.OFPFW_TP_SRC,
248 ofp.OFPFW_TP_DST
Howard Persh680b92a2012-03-31 13:34:35 -0700249 ]
Howard Pershc7963582012-03-29 10:02:59 -0700250
Howard Persh3340d452012-04-06 16:45:21 -0700251# TBD - Need this because there are duplicates in ofp.ofp_flow_wildcards_map
252# -- FIX
rootf6af1672012-04-06 09:46:29 -0700253all_wildcard_names = {
254 1 : 'OFPFW_IN_PORT',
255 2 : 'OFPFW_DL_VLAN',
256 4 : 'OFPFW_DL_SRC',
257 8 : 'OFPFW_DL_DST',
258 16 : 'OFPFW_DL_TYPE',
259 32 : 'OFPFW_NW_PROTO',
260 64 : 'OFPFW_TP_SRC',
261 128 : 'OFPFW_TP_DST',
262 1048576 : 'OFPFW_DL_VLAN_PCP',
263 2097152 : 'OFPFW_NW_TOS'
264}
265
rootf6af1672012-04-06 09:46:29 -0700266def wildcard_set(x, w, val):
267 result = x
268 if w == ofp.OFPFW_NW_SRC_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700269 result = (result & ~ofp.OFPFW_NW_SRC_MASK) \
270 | (val << ofp.OFPFW_NW_SRC_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700271 elif w == ofp.OFPFW_NW_DST_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700272 result = (result & ~ofp.OFPFW_NW_DST_MASK) \
273 | (val << ofp.OFPFW_NW_DST_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700274 elif val == 0:
275 result = result & ~w
276 else:
277 result = result | w
278 return result
279
280def wildcard_get(x, w):
281 if w == ofp.OFPFW_NW_SRC_MASK:
282 return (x & ofp.OFPFW_NW_SRC_MASK) >> ofp.OFPFW_NW_SRC_SHIFT
283 if w == ofp.OFPFW_NW_DST_MASK:
284 return (x & ofp.OFPFW_NW_DST_MASK) >> ofp.OFPFW_NW_DST_SHIFT
285 return 1 if (x & w) != 0 else 0
286
Howard Persh8d21c1f2012-04-20 15:57:29 -0700287def wildcards_to_str(wildcards):
288 result = "{"
289 sep = ""
290 for w in all_wildcards_list:
291 if (wildcards & w) == 0:
292 continue
293 if w == ofp.OFPFW_NW_SRC_MASK:
294 n = wildcard_get(wildcards, w)
295 if n > 0:
296 result = result + sep + ("OFPFW_NW_SRC(%d)" % (n))
297 elif w == ofp.OFPFW_NW_DST_MASK:
298 n = wildcard_get(wildcards, w)
299 if n > 0:
300 result = result + sep + ("OFPFW_NW_DST(%d)" % (n))
301 else:
302 result = result + sep + all_wildcard_names[w]
303 sep = ", "
304 result = result +"}"
305 return result
Howard Pershc7963582012-03-29 10:02:59 -0700306
Howard Persh680b92a2012-03-31 13:34:35 -0700307all_actions_list = [ofp.OFPAT_OUTPUT,
308 ofp.OFPAT_SET_VLAN_VID,
309 ofp.OFPAT_SET_VLAN_PCP,
310 ofp.OFPAT_STRIP_VLAN,
311 ofp.OFPAT_SET_DL_SRC,
312 ofp.OFPAT_SET_DL_DST,
313 ofp.OFPAT_SET_NW_SRC,
314 ofp.OFPAT_SET_NW_DST,
315 ofp.OFPAT_SET_NW_TOS,
316 ofp.OFPAT_SET_TP_SRC,
317 ofp.OFPAT_SET_TP_DST,
318 ofp.OFPAT_ENQUEUE
319 ]
320
Howard Persh8d21c1f2012-04-20 15:57:29 -0700321def actions_bmap_to_str(bm):
322 result = "{"
323 sep = ""
324 for a in all_actions_list:
325 if ((1 << a) & bm) != 0:
326 result = result + sep + ofp.ofp_action_type_map[a]
327 sep = ", "
328 result = result + "}"
329 return result
330
Howard Persh680b92a2012-03-31 13:34:35 -0700331def dl_addr_to_str(a):
332 return "%x:%x:%x:%x:%x:%x" % tuple(a)
333
334def ip_addr_to_str(a, n):
rootf6af1672012-04-06 09:46:29 -0700335 if n is not None:
336 a = a & ~((1 << (32 - n)) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700337 result = "%d.%d.%d.%d" % (a >> 24, \
338 (a >> 16) & 0xff, \
339 (a >> 8) & 0xff, \
340 a & 0xff \
341 )
342 if n is not None:
343 result = result + ("/%d" % (n))
344 return result
345
Howard Pershc7963582012-03-29 10:02:59 -0700346
rootf6af1672012-04-06 09:46:29 -0700347class Flow_Cfg:
Howard Pershc7963582012-03-29 10:02:59 -0700348 # Members:
349 # - match
350 # - idle_timeout
351 # - hard_timeout
352 # - priority
353 # - action_list
354
355 def __init__(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700356 self.priority = 0
Howard Pershc7963582012-03-29 10:02:59 -0700357 self.match = parse.ofp_match()
358 self.match.wildcards = ofp.OFPFW_ALL
359 self.idle_timeout = 0
360 self.hard_timeout = 0
Howard Pershc7963582012-03-29 10:02:59 -0700361 self.actions = action_list.action_list()
362
rootf6af1672012-04-06 09:46:29 -0700363 # {pri, match} is considered a flow key
364 def key_equal(self, x):
Howard Persh680b92a2012-03-31 13:34:35 -0700365 if self.priority != x.priority:
366 return False
367 # TBD - Should this logic be moved to ofp_match.__eq__()?
368 if self.match.wildcards != x.match.wildcards:
369 return False
rootf6af1672012-04-06 09:46:29 -0700370 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700371 and self.match.in_port != x.match.in_port:
372 return False
rootf6af1672012-04-06 09:46:29 -0700373 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700374 and self.match.dl_dst != x.match.dl_dst:
375 return False
rootf6af1672012-04-06 09:46:29 -0700376 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0 \
377 and self.match.dl_src != x.match.dl_src:
378 return False
379 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700380 and self.match.dl_vlan != x.match.dl_vlan:
381 return False
rootf6af1672012-04-06 09:46:29 -0700382 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700383 and self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
384 return False
rootf6af1672012-04-06 09:46:29 -0700385 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700386 and self.match.dl_type != x.match.dl_type:
387 return False
rootf6af1672012-04-06 09:46:29 -0700388 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700389 and self.match.nw_tos != x.match.nw_tos:
390 return False
rootf6af1672012-04-06 09:46:29 -0700391 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700392 and self.match.nw_proto != x.match.nw_proto:
393 return False
rootf6af1672012-04-06 09:46:29 -0700394 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
395 if n < 32:
396 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700397 if (self.match.nw_src & m) != (x.match.nw_src & m):
398 return False
rootf6af1672012-04-06 09:46:29 -0700399 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
400 if n < 32:
401 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700402 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
403 return False
rootf6af1672012-04-06 09:46:29 -0700404 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0 \
405 and self.match.tp_src != x.match.tp_src:
Howard Persh680b92a2012-03-31 13:34:35 -0700406 return False
rootf6af1672012-04-06 09:46:29 -0700407 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0 \
408 and self.match.tp_dst != x.match.tp_dst:
409 return False
410 return True
411
Howard Persh5f3c83f2012-04-13 09:57:10 -0700412 def actions_equal(self, x):
413 if test_param_get(fq_config, "conservative_ordered_actions", True):
414 # Compare actions lists as unordered
415
root2843d2b2012-04-06 10:27:46 -0700416 aa = copy.deepcopy(x.actions.actions)
417 for a in self.actions.actions:
418 i = 0
419 while i < len(aa):
420 if a == aa[i]:
421 break
422 i = i + 1
423 if i < len(aa):
424 aa.pop(i)
425 else:
426 return False
427 return aa == []
428 else:
429 return self.actions == x.actions
Howard Persh5f3c83f2012-04-13 09:57:10 -0700430
431 def non_key_equal(self, x):
432 if self.cookie != x.cookie:
433 return False
434 if self.idle_timeout != x.idle_timeout:
435 return False
436 if self.hard_timeout != x.hard_timeout:
437 return False
438 return self.actions_equal(x)
rootf6af1672012-04-06 09:46:29 -0700439
root2843d2b2012-04-06 10:27:46 -0700440 def key_str(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700441 result = "priority=%d" % self.priority
442 # TBD - Would be nice if ofp_match.show() was better behaved
443 # (no newlines), and more intuitive (things in hex where approprate), etc.
Howard Persh8d21c1f2012-04-20 15:57:29 -0700444 result = result + (", wildcards=0x%x=%s" \
445 % (self.match.wildcards, \
446 wildcards_to_str(self.match.wildcards) \
447 )
448 )
rootf6af1672012-04-06 09:46:29 -0700449 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700450 result = result + (", in_port=%d" % (self.match.in_port))
rootf6af1672012-04-06 09:46:29 -0700451 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700452 result = result + (", dl_dst=%s" \
453 % (dl_addr_to_str(self.match.dl_dst)) \
454 )
rootf6af1672012-04-06 09:46:29 -0700455 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700456 result = result + (", dl_src=%s" \
457 % (dl_addr_to_str(self.match.dl_src)) \
458 )
rootf6af1672012-04-06 09:46:29 -0700459 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700460 result = result + (", dl_vlan=%d" % (self.match.dl_vlan))
rootf6af1672012-04-06 09:46:29 -0700461 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700462 result = result + (", dl_vlan_pcp=%d" % (self.match.dl_vlan_pcp))
rootf6af1672012-04-06 09:46:29 -0700463 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700464 result = result + (", dl_type=0x%x" % (self.match.dl_type))
rootf6af1672012-04-06 09:46:29 -0700465 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700466 result = result + (", nw_tos=0x%x" % (self.match.nw_tos))
rootf6af1672012-04-06 09:46:29 -0700467 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700468 result = result + (", nw_proto=%d" % (self.match.nw_proto))
rootf6af1672012-04-06 09:46:29 -0700469 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700470 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700471 result = result + (", nw_src=%s" % \
472 (ip_addr_to_str(self.match.nw_src, 32 - n)) \
473 )
rootf6af1672012-04-06 09:46:29 -0700474 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700475 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700476 result = result + (", nw_dst=%s" % \
477 (ip_addr_to_str(self.match.nw_dst, 32 - n)) \
478 )
rootf6af1672012-04-06 09:46:29 -0700479 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700480 result = result + (", tp_src=%d" % self.match.tp_src)
rootf6af1672012-04-06 09:46:29 -0700481 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700482 result = result + (", tp_dst=%d" % self.match.tp_dst)
rootf6af1672012-04-06 09:46:29 -0700483 return result
484
485 def __eq__(self, x):
486 return (self.key_equal(x) and self.non_key_equal(x))
487
488 def __str__(self):
root2843d2b2012-04-06 10:27:46 -0700489 result = self.key_str()
490 result = result + (", cookie=%d" % self.cookie)
Howard Persh680b92a2012-03-31 13:34:35 -0700491 result = result + (", idle_timeout=%d" % self.idle_timeout)
492 result = result + (", hard_timeout=%d" % self.hard_timeout)
Howard Persh680b92a2012-03-31 13:34:35 -0700493 for a in self.actions.actions:
494 result = result + (", action=%s" % ofp.ofp_action_type_map[a.type])
495 if a.type == ofp.OFPAT_OUTPUT:
496 result = result + ("(%d)" % (a.port))
497 elif a.type == ofp.OFPAT_SET_VLAN_VID:
498 result = result + ("(%d)" % (a.vlan_vid))
499 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
500 result = result + ("(%d)" % (a.vlan_pcp))
501 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
502 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
503 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
504 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
505 elif a.type == ofp.OFPAT_SET_NW_TOS:
506 result = result + ("(0x%x)" % (a.nw_tos))
507 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
508 result = result + ("(%d)" % (a.tp_port))
509 elif a.type == ofp.OFPAT_ENQUEUE:
510 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
511 return result
Howard Pershc7963582012-03-29 10:02:59 -0700512
Howard Persh8d21c1f2012-04-20 15:57:29 -0700513 def rand_actions_ordered(self, fi, valid_actions, valid_ports, valid_queues):
Howard Persh3340d452012-04-06 16:45:21 -0700514 # Action lists are ordered, so pick an ordered random subset of
515 # supported actions
Howard Pershc1199d52012-04-11 14:21:32 -0700516
517 actions_force = test_param_get(fq_config, "actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700518 if actions_force != 0:
519 fq_logger.info("Forced actions:")
520 fq_logger.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700521
Dan Talayco910a8282012-04-07 00:05:20 -0700522 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh3340d452012-04-06 16:45:21 -0700523 supported_actions = []
524 for a in all_actions_list:
525 if ((1 << a) & valid_actions) != 0:
526 supported_actions.append(a)
527
Howard Pershc1199d52012-04-11 14:21:32 -0700528 actions \
529 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
530
531 for a in all_actions_list:
532 if ((1 << a) & actions_force) != 0:
533 actions.append(a)
534
535 actions = shuffle(actions)
Howard Persh3340d452012-04-06 16:45:21 -0700536
Howard Persh3340d452012-04-06 16:45:21 -0700537 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700538 for a in actions:
Dan Talayco910a8282012-04-07 00:05:20 -0700539 act = None
Howard Persh3340d452012-04-06 16:45:21 -0700540 if a == ofp.OFPAT_OUTPUT:
541 pass # OUTPUT actions must come last
542 elif a == ofp.OFPAT_SET_VLAN_VID:
543 act = action.action_set_vlan_vid()
544 act.vlan_vid = fi.rand_vlan()
Howard Persh3340d452012-04-06 16:45:21 -0700545 elif a == ofp.OFPAT_SET_VLAN_PCP:
546 act = action.action_set_vlan_pcp()
547 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Persh3340d452012-04-06 16:45:21 -0700548 elif a == ofp.OFPAT_STRIP_VLAN:
549 act = action.action_strip_vlan()
Howard Persh3340d452012-04-06 16:45:21 -0700550 elif a == ofp.OFPAT_SET_DL_SRC:
551 act = action.action_set_dl_src()
552 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700553 elif a == ofp.OFPAT_SET_DL_DST:
554 act = action.action_set_dl_dst()
555 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700556 elif a == ofp.OFPAT_SET_NW_SRC:
557 act = action.action_set_nw_src()
558 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700559 elif a == ofp.OFPAT_SET_NW_DST:
560 act = action.action_set_nw_dst()
561 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700562 elif a == ofp.OFPAT_SET_NW_TOS:
563 act = action.action_set_nw_tos()
564 act.nw_tos = fi.rand_ip_tos()
Howard Persh3340d452012-04-06 16:45:21 -0700565 elif a == ofp.OFPAT_SET_TP_SRC:
566 act = action.action_set_tp_src()
567 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700568 elif a == ofp.OFPAT_SET_TP_DST:
569 act = action.action_set_tp_dst()
570 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700571 elif a == ofp.OFPAT_ENQUEUE:
572 pass # Enqueue actions must come last
Dan Talayco910a8282012-04-07 00:05:20 -0700573 if act:
574 act.max_len = ACTION_MAX_LEN
575 self.actions.add(act)
576
Howard Persh3340d452012-04-06 16:45:21 -0700577 p = random.randint(1, 100)
Howard Pershc1199d52012-04-11 14:21:32 -0700578 if (((1 << ofp.OFPAT_ENQUEUE) & actions_force) != 0 or p <= 33) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700579 and len(valid_queues) > 0 \
580 and ofp.OFPAT_ENQUEUE in actions:
Howard Pershc1199d52012-04-11 14:21:32 -0700581 # In not forecd, one third of the time, include ENQUEUE actions
582 # at end of list
Howard Persh3340d452012-04-06 16:45:21 -0700583 # At most 1 ENQUEUE action
584 act = action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700585 (act.port, act.queue_id) = rand_pick(valid_queues)
Dan Talayco910a8282012-04-07 00:05:20 -0700586 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700587 self.actions.add(act)
Howard Pershc1199d52012-04-11 14:21:32 -0700588 if (((1 << ofp.OFPAT_OUTPUT) & actions_force) != 0 \
589 or (p > 33 and p <= 66) \
590 ) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700591 and len(valid_ports) > 0 \
Howard Pershc1199d52012-04-11 14:21:32 -0700592 and ofp.OFPAT_OUTPUT in actions:
Howard Persh3340d452012-04-06 16:45:21 -0700593 # One third of the time, include OUTPUT actions at end of list
594 port_idxs = shuffle(range(len(valid_ports)))
595 # Only 1 output action allowed if IN_PORT wildcarded
596 n = 1 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) != 0 \
597 else random.randint(1, len(valid_ports))
598 port_idxs = port_idxs[0 : n]
599 for pi in port_idxs:
600 act = action.action_output()
601 act.port = valid_ports[pi]
Dan Talayco910a8282012-04-07 00:05:20 -0700602 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700603 if act.port != ofp.OFPP_IN_PORT \
604 or wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
605 # OUTPUT(IN_PORT) only valid if OFPFW_IN_PORT not wildcarded
606 self.actions.add(act)
607 else:
608 # One third of the time, include neither
609 pass
610
611
612 # Randomize flow data for flow modifies (i.e. cookie and actions)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700613 def rand_mod(self, fi, valid_actions, valid_ports, valid_queues):
rootf6af1672012-04-06 09:46:29 -0700614 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700615
Dan Talayco910a8282012-04-07 00:05:20 -0700616 # By default, test with conservative ordering conventions
617 # This should probably be indicated in a profile
618 if test_param_get(fq_config, "conservative_ordered_actions", True):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700619 self.rand_actions_ordered(fi, valid_actions, valid_ports, valid_queues)
Howard Persh3340d452012-04-06 16:45:21 -0700620 return self
621
Howard Pershc1199d52012-04-11 14:21:32 -0700622 actions_force = test_param_get(fq_config, "actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700623 if actions_force != 0:
624 fq_logger.info("Forced actions:")
625 fq_logger.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700626
627 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh680b92a2012-03-31 13:34:35 -0700628 supported_actions = []
629 for a in all_actions_list:
630 if ((1 << a) & valid_actions) != 0:
631 supported_actions.append(a)
632
Howard Pershc1199d52012-04-11 14:21:32 -0700633 actions \
634 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
635
636 for a in all_actions_list:
637 if ((1 << a) & actions_force) != 0:
638 actions.append(a)
639
640 actions = shuffle(actions)
Howard Pershc7963582012-03-29 10:02:59 -0700641
642 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700643 for a in actions:
Howard Pershc7963582012-03-29 10:02:59 -0700644 if a == ofp.OFPAT_OUTPUT:
645 # TBD - Output actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700646 if len(valid_ports) == 0:
647 continue
Howard Pershc7963582012-03-29 10:02:59 -0700648 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700649 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700650 for pi in port_idxs:
651 act = action.action_output()
Howard Persh680b92a2012-03-31 13:34:35 -0700652 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700653 self.actions.add(act)
654 elif a == ofp.OFPAT_SET_VLAN_VID:
655 act = action.action_set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700656 act.vlan_vid = fi.rand_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700657 self.actions.add(act)
658 elif a == ofp.OFPAT_SET_VLAN_PCP:
Dan Talayco910a8282012-04-07 00:05:20 -0700659 act = action.action_set_vlan_pcp()
660 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700661 elif a == ofp.OFPAT_STRIP_VLAN:
662 act = action.action_strip_vlan()
663 self.actions.add(act)
664 elif a == ofp.OFPAT_SET_DL_SRC:
665 act = action.action_set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700666 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700667 self.actions.add(act)
668 elif a == ofp.OFPAT_SET_DL_DST:
669 act = action.action_set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700670 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700671 self.actions.add(act)
672 elif a == ofp.OFPAT_SET_NW_SRC:
673 act = action.action_set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700674 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700675 self.actions.add(act)
676 elif a == ofp.OFPAT_SET_NW_DST:
677 act = action.action_set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700678 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700679 self.actions.add(act)
680 elif a == ofp.OFPAT_SET_NW_TOS:
681 act = action.action_set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700682 act.nw_tos = fi.rand_ip_tos()
Howard Pershc7963582012-03-29 10:02:59 -0700683 self.actions.add(act)
684 elif a == ofp.OFPAT_SET_TP_SRC:
685 act = action.action_set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700686 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700687 self.actions.add(act)
688 elif a == ofp.OFPAT_SET_TP_DST:
689 act = action.action_set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700690 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700691 self.actions.add(act)
692 elif a == ofp.OFPAT_ENQUEUE:
693 # TBD - Enqueue actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700694 if len(valid_queues) == 0:
695 continue
696 qidxs = shuffle(range(len(valid_queues)))
697 qidxs = qidxs[0 : random.randint(1, len(valid_queues))]
698 for qi in qidxs:
Howard Pershc7963582012-03-29 10:02:59 -0700699 act = action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700700 (act.port, act.queue_id) = valid_queues[qi]
Howard Pershc7963582012-03-29 10:02:59 -0700701 self.actions.add(act)
702
703 return self
704
rootf6af1672012-04-06 09:46:29 -0700705 # Randomize flow cfg
Howard Persh8d21c1f2012-04-20 15:57:29 -0700706 def rand(self, fi, valid_wildcards, valid_actions, valid_ports, valid_queues):
Howard Pershc1199d52012-04-11 14:21:32 -0700707 wildcards_force = test_param_get(fq_config, "wildcards_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700708 if wildcards_force != 0:
709 fq_logger.info("Wildcards forced:")
710 fq_logger.info(wildcards_to_str(wildcards_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700711
rootf6af1672012-04-06 09:46:29 -0700712 # Start with no wildcards, i.e. everything specified
713 self.match.wildcards = 0
Howard Pershc1199d52012-04-11 14:21:32 -0700714
715 if wildcards_force != 0:
716 exact = False
717 else:
718 # Make approx. 5% of flows exact
719 exact = (random.randint(1, 100) <= 5)
rootf6af1672012-04-06 09:46:29 -0700720
721 # For each qualifier Q,
722 # if (wildcarding is not supported for Q,
723 # or an exact flow is specified
724 # or a coin toss comes up heads),
725 # specify Q
726 # else
727 # wildcard Q
728
Howard Pershc1199d52012-04-11 14:21:32 -0700729 if wildcard_get(wildcards_force, ofp.OFPFW_IN_PORT) == 0 \
730 and (wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
731 or exact \
732 or flip_coin() \
733 ):
rootf6af1672012-04-06 09:46:29 -0700734 self.match.in_port = rand_pick(valid_ports)
735 else:
Howard Persh3340d452012-04-06 16:45:21 -0700736 self.match.wildcards = wildcard_set(self.match.wildcards, \
737 ofp.OFPFW_IN_PORT, \
738 1 \
739 )
rootf6af1672012-04-06 09:46:29 -0700740
Howard Pershc1199d52012-04-11 14:21:32 -0700741 if wildcard_get(wildcards_force, ofp.OFPFW_DL_DST) == 0 \
742 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
743 or exact \
744 or flip_coin() \
745 ):
rootf6af1672012-04-06 09:46:29 -0700746 self.match.dl_dst = fi.rand_dl_addr()
747 else:
Howard Persh3340d452012-04-06 16:45:21 -0700748 self.match.wildcards = wildcard_set(self.match.wildcards, \
749 ofp.OFPFW_DL_DST, \
750 1 \
751 )
rootf6af1672012-04-06 09:46:29 -0700752
Howard Pershc1199d52012-04-11 14:21:32 -0700753 if wildcard_get(wildcards_force, ofp.OFPFW_DL_SRC) == 0 \
754 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
755 or exact \
756 or flip_coin() \
757 ):
rootf6af1672012-04-06 09:46:29 -0700758 self.match.dl_src = fi.rand_dl_addr()
759 else:
Howard Persh3340d452012-04-06 16:45:21 -0700760 self.match.wildcards = wildcard_set(self.match.wildcards, \
761 ofp.OFPFW_DL_SRC, \
762 1 \
763 )
rootf6af1672012-04-06 09:46:29 -0700764
Howard Pershc1199d52012-04-11 14:21:32 -0700765 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN) == 0 \
766 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
767 or exact \
768 or flip_coin() \
769 ):
rootf6af1672012-04-06 09:46:29 -0700770 self.match.dl_vlan = fi.rand_vlan()
771 else:
Howard Persh3340d452012-04-06 16:45:21 -0700772 self.match.wildcards = wildcard_set(self.match.wildcards, \
773 ofp.OFPFW_DL_VLAN, \
774 1 \
775 )
rootf6af1672012-04-06 09:46:29 -0700776
Howard Pershc1199d52012-04-11 14:21:32 -0700777 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN_PCP) == 0 \
778 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
779 or exact \
780 or flip_coin() \
781 ):
782 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
783 else:
784 self.match.wildcards = wildcard_set(self.match.wildcards, \
785 ofp.OFPFW_DL_VLAN_PCP, \
786 1 \
787 )
788
789 if wildcard_get(wildcards_force, ofp.OFPFW_DL_TYPE) == 0 \
790 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
791 or exact \
792 or flip_coin() \
793 ):
rootf6af1672012-04-06 09:46:29 -0700794 self.match.dl_type = fi.rand_ethertype()
795 else:
Howard Persh3340d452012-04-06 16:45:21 -0700796 self.match.wildcards = wildcard_set(self.match.wildcards, \
797 ofp.OFPFW_DL_TYPE, \
798 1 \
799 )
rootf6af1672012-04-06 09:46:29 -0700800
Howard Pershc1199d52012-04-11 14:21:32 -0700801 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_SRC_MASK)
802 if n == 0:
803 if exact or flip_coin():
804 n = 0
805 else:
806 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
807 if n > 32:
808 n = 32
809 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700810 self.match.wildcards = wildcard_set(self.match.wildcards, \
811 ofp.OFPFW_NW_SRC_MASK, \
812 n \
813 )
rootf6af1672012-04-06 09:46:29 -0700814 if n < 32:
815 self.match.nw_src = fi.rand_ip_addr() & ~((1 << n) - 1)
816 # Specifying any IP address match other than all bits
817 # don't care requires that Ethertype is one of {IP, ARP}
818 if flip_coin():
819 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700820 self.match.wildcards = wildcard_set(self.match.wildcards, \
821 ofp.OFPFW_DL_TYPE, \
822 0 \
823 )
rootf6af1672012-04-06 09:46:29 -0700824
Howard Pershc1199d52012-04-11 14:21:32 -0700825 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_DST_MASK)
826 if n == 0:
827 if exact or flip_coin():
828 n = 0
829 else:
830 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
831 if n > 32:
832 n = 32
833 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700834 self.match.wildcards = wildcard_set(self.match.wildcards, \
835 ofp.OFPFW_NW_DST_MASK, \
836 n \
837 )
rootf6af1672012-04-06 09:46:29 -0700838 if n < 32:
839 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
840 # Specifying any IP address match other than all bits
841 # don't care requires that Ethertype is one of {IP, ARP}
842 if flip_coin():
843 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700844 self.match.wildcards = wildcard_set(self.match.wildcards, \
845 ofp.OFPFW_DL_TYPE, \
846 0 \
847 )
rootf6af1672012-04-06 09:46:29 -0700848
Howard Pershc1199d52012-04-11 14:21:32 -0700849 if wildcard_get(wildcards_force, ofp.OFPFW_NW_TOS) == 0 \
850 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
851 or exact \
852 or flip_coin() \
853 ):
rootf6af1672012-04-06 09:46:29 -0700854 self.match.nw_tos = fi.rand_ip_tos()
855 # Specifying a TOS value requires that Ethertype is IP
856 if flip_coin():
857 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700858 self.match.wildcards = wildcard_set(self.match.wildcards, \
859 ofp.OFPFW_DL_TYPE, \
860 0 \
861 )
rootf6af1672012-04-06 09:46:29 -0700862 else:
Howard Persh3340d452012-04-06 16:45:21 -0700863 self.match.wildcards = wildcard_set(self.match.wildcards, \
864 ofp.OFPFW_NW_TOS, \
865 1 \
866 )
rootf6af1672012-04-06 09:46:29 -0700867
Dan Talayco910a8282012-04-07 00:05:20 -0700868 # Known issue on OVS with specifying nw_proto w/o dl_type as IP
Howard Pershc1199d52012-04-11 14:21:32 -0700869 if wildcard_get(wildcards_force, ofp.OFPFW_NW_PROTO) == 0 \
870 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
871 or exact \
872 or flip_coin() \
873 ):
Dan Talayco910a8282012-04-07 00:05:20 -0700874 self.match.nw_proto = fi.rand_ip_proto()
875 # Specifying an IP protocol requires that Ethertype is IP
876 if flip_coin():
877 self.match.dl_type = 0x0800
878 self.match.wildcards = wildcard_set(self.match.wildcards, \
879 ofp.OFPFW_DL_TYPE, \
880 0 \
881 )
882 else:
Howard Persh3340d452012-04-06 16:45:21 -0700883 self.match.wildcards = wildcard_set(self.match.wildcards, \
884 ofp.OFPFW_NW_PROTO, \
885 1 \
886 )
Dan Talayco910a8282012-04-07 00:05:20 -0700887
Howard Pershc1199d52012-04-11 14:21:32 -0700888 if wildcard_get(wildcards_force, ofp.OFPFW_TP_SRC) == 0 \
889 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
890 or exact\
891 or flip_coin() \
892 ):
rootf6af1672012-04-06 09:46:29 -0700893 self.match.tp_src = fi.rand_l4_port()
894 # Specifying a L4 port requires that IP protcol is
895 # one of {ICMP, TCP, UDP}
896 if flip_coin():
897 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700898 self.match.wildcards = wildcard_set(self.match.wildcards, \
899 ofp.OFPFW_NW_PROTO, \
900 0 \
901 )
rootf6af1672012-04-06 09:46:29 -0700902 # Specifying a L4 port requirues that Ethertype is IP
903 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700904 self.match.wildcards = wildcard_set(self.match.wildcards, \
905 ofp.OFPFW_DL_TYPE, \
906 0 \
907 )
rootf6af1672012-04-06 09:46:29 -0700908 if self.match.nw_proto == 1:
909 self.match.tp_src = self.match.tp_src & 0xff
910 else:
Howard Persh3340d452012-04-06 16:45:21 -0700911 self.match.wildcards = wildcard_set(self.match.wildcards, \
912 ofp.OFPFW_TP_SRC, \
913 1 \
914 )
rootf6af1672012-04-06 09:46:29 -0700915
Howard Pershc1199d52012-04-11 14:21:32 -0700916 if wildcard_get(wildcards_force, ofp.OFPFW_TP_DST) == 0 \
917 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
918 or exact \
919 or flip_coin() \
920 ):
rootf6af1672012-04-06 09:46:29 -0700921 self.match.tp_dst = fi.rand_l4_port()
922 # Specifying a L4 port requires that IP protcol is
923 # one of {ICMP, TCP, UDP}
924 if flip_coin():
925 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700926 self.match.wildcards = wildcard_set(self.match.wildcards, \
927 ofp.OFPFW_NW_PROTO, \
928 0 \
929 )
rootf6af1672012-04-06 09:46:29 -0700930 # Specifying a L4 port requirues that Ethertype is IP
931 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700932 self.match.wildcards = wildcard_set(self.match.wildcards, \
933 ofp.OFPFW_DL_TYPE, \
934 0 \
935 )
rootf6af1672012-04-06 09:46:29 -0700936 if self.match.nw_proto == 1:
937 self.match.tp_dst = self.match.tp_dst & 0xff
938 else:
Howard Persh3340d452012-04-06 16:45:21 -0700939 self.match.wildcards = wildcard_set(self.match.wildcards, \
940 ofp.OFPFW_TP_DST, \
941 1 \
942 )
rootf6af1672012-04-06 09:46:29 -0700943
944 # If nothing is wildcarded, it is an exact flow spec -- some switches
Howard Persh3340d452012-04-06 16:45:21 -0700945 # (Open vSwitch, for one) *require* that exact flow specs
946 # have priority 65535.
947 self.priority = 65535 if self.match.wildcards == 0 \
948 else fi.rand_priority()
rootf6af1672012-04-06 09:46:29 -0700949
950 # N.B. Don't make the timeout too short, else the flow might
951 # disappear before we get a chance to check for it.
952 t = random.randint(0, 65535)
953 self.idle_timeout = 0 if t < 60 else t
954 t = random.randint(0, 65535)
955 self.hard_timeout = 0 if t < 60 else t
956
Howard Persh8d21c1f2012-04-20 15:57:29 -0700957 self.rand_mod(fi, valid_actions, valid_ports, valid_queues)
rootf6af1672012-04-06 09:46:29 -0700958
959 return self
960
961 # Return flow cfg in canonical form
Howard Persh3340d452012-04-06 16:45:21 -0700962 # - There are dependencies between flow qualifiers, e.g. it only makes
963 # sense to qualify nw_proto if dl_type is qualified to be 0x0800 (IP).
964 # The canonical form of flow match criteria will "wildcard out"
965 # all such cases.
rootf6af1672012-04-06 09:46:29 -0700966 def canonical(self):
967 result = copy.deepcopy(self)
Howard Persh07d99e62012-04-09 15:26:57 -0700968
969 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_VLAN) != 0:
970 result.match.wildcards = wildcard_set(result.match.wildcards, \
971 ofp.OFPFW_DL_VLAN_PCP, \
972 1 \
973 )
974
rootf6af1672012-04-06 09:46:29 -0700975 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
976 or result.match.dl_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700977 # dl_tyoe is wildcarded, or specified as something other
978 # than IP or ARP
Howard Persh07d99e62012-04-09 15:26:57 -0700979 # => nw_src, nw_dst, nw_proto cannot be specified,
980 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700981 result.match.wildcards = wildcard_set(result.match.wildcards, \
982 ofp.OFPFW_NW_SRC_MASK, \
983 32 \
984 )
985 result.match.wildcards = wildcard_set(result.match.wildcards, \
986 ofp.OFPFW_NW_DST_MASK, \
987 32 \
988 )
Howard Persh3340d452012-04-06 16:45:21 -0700989 result.match.wildcards = wildcard_set(result.match.wildcards, \
990 ofp.OFPFW_NW_PROTO, \
991 1 \
992 )
Howard Persh07d99e62012-04-09 15:26:57 -0700993
994 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
995 or result.match.dl_type != 0x0800:
996 # dl_type is wildcarded, or specified as something other than IP
997 # => nw_tos, tp_src and tp_dst cannot be specified,
998 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700999 result.match.wildcards = wildcard_set(result.match.wildcards, \
1000 ofp.OFPFW_NW_TOS, \
1001 1 \
1002 )
1003 result.match.wildcards = wildcard_set(result.match.wildcards, \
1004 ofp.OFPFW_TP_SRC, \
1005 1 \
1006 )
1007 result.match.wildcards = wildcard_set(result.match.wildcards, \
1008 ofp.OFPFW_TP_DST, \
1009 1 \
1010 )
Howard Persh07d99e62012-04-09 15:26:57 -07001011 result.match.wildcards = wildcard_set(result.match.wildcards, \
1012 ofp.OFPFW_NW_SRC_MASK, \
1013 32 \
1014 )
1015 result.match.wildcards = wildcard_set(result.match.wildcards, \
1016 ofp.OFPFW_NW_DST_MASK, \
1017 32 \
1018 )
1019 result.match.wildcards = wildcard_set(result.match.wildcards, \
1020 ofp.OFPFW_NW_PROTO, \
1021 1 \
1022 )
1023
rootf6af1672012-04-06 09:46:29 -07001024 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
1025 or result.match.nw_proto not in [1, 6, 17]:
Howard Persh3340d452012-04-06 16:45:21 -07001026 # nw_proto is wildcarded, or specified as something other than ICMP,
1027 # TCP or UDP
rootf6af1672012-04-06 09:46:29 -07001028 # => tp_src and tp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001029 result.match.wildcards = wildcard_set(result.match.wildcards, \
1030 ofp.OFPFW_TP_SRC, \
1031 1 \
1032 )
1033 result.match.wildcards = wildcard_set(result.match.wildcards, \
1034 ofp.OFPFW_TP_DST, \
1035 1 \
1036 )
rootf6af1672012-04-06 09:46:29 -07001037 return result
1038
Howard Persh680b92a2012-03-31 13:34:35 -07001039 # Overlap check
1040 # delf == True <=> Check for delete overlap, else add overlap
1041 # "Add overlap" is defined as there exists a packet that could match both the
1042 # receiver and argument flowspecs
1043 # "Delete overlap" is defined as the specificity of the argument flowspec
1044 # is greater than or equal to the specificity of the receiver flowspec
1045 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -07001046 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
1047 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001048 if self.match.in_port != x.match.in_port:
1049 return False # Both specified, and not equal
1050 elif delf:
1051 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001052 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
1053 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001054 if self.match.dl_vlan != x.match.dl_vlan:
1055 return False # Both specified, and not equal
1056 elif delf:
1057 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001058 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
1059 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001060 if self.match.dl_src != x.match.dl_src:
1061 return False # Both specified, and not equal
1062 elif delf:
1063 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001064 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
1065 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001066 if self.match.dl_dst != x.match.dl_dst:
1067 return False # Both specified, and not equal
1068 elif delf:
1069 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001070 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
1071 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001072 if self.match.dl_type != x.match.dl_type:
1073 return False # Both specified, and not equal
1074 elif delf:
1075 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -07001076 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
1077 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001078 if self.match.nw_proto != x.match.nw_proto:
1079 return False # Both specified, and not equal
1080 elif delf:
1081 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001082 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
1083 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001084 if self.match.tp_src != x.match.tp_src:
1085 return False # Both specified, and not equal
1086 elif delf:
1087 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001088 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
1089 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001090 if self.match.tp_dst != x.match.tp_dst:
1091 return False # Both specified, and not equal
1092 elif delf:
1093 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001094 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
1095 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001096 if delf and na < nb:
1097 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001098 if (na < 32 and nb < 32):
1099 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1100 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -07001101 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -07001102 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
1103 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001104 if delf and na < nb:
1105 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001106 if (na < 32 and nb < 32):
1107 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1108 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
rootf6af1672012-04-06 09:46:29 -07001109 return False # Overlapping bits not equal
1110 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
1111 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001112 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
1113 return False # Both specified, and not equal
1114 elif delf:
1115 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001116 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
1117 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001118 if self.match.nw_tos != x.match.nw_tos:
1119 return False # Both specified, and not equal
1120 elif delf:
1121 return False # Receiver more specific
1122 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -07001123
1124 def to_flow_mod_msg(self, msg):
1125 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -07001126 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001127 msg.idle_timeout = self.idle_timeout
1128 msg.hard_timeout = self.hard_timeout
1129 msg.priority = self.priority
1130 msg.actions = self.actions
1131 return msg
1132
1133 def from_flow_stat(self, msg):
1134 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -07001135 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001136 self.idle_timeout = msg.idle_timeout
1137 self.hard_timeout = msg.hard_timeout
1138 self.priority = msg.priority
1139 self.actions = msg.actions
1140
rootf6af1672012-04-06 09:46:29 -07001141 def from_flow_rem(self, msg):
1142 self.match = msg.match
1143 self.idle_timeout = msg.idle_timeout
1144 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -07001145
Howard Pershc7963582012-03-29 10:02:59 -07001146
rootf6af1672012-04-06 09:46:29 -07001147class Flow_Tbl:
1148 def clear(self):
1149 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001150
rootf6af1672012-04-06 09:46:29 -07001151 def __init__(self):
1152 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001153
rootf6af1672012-04-06 09:46:29 -07001154 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001155 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001156
1157 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001158 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001159
1160 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001161 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001162
1163 def values(self):
1164 return self.dict.values()
1165
1166 def count(self):
1167 return len(self.dict)
1168
1169 def rand(self, sw, fi, num_flows):
1170 self.clear()
1171 i = 0
1172 tbl = 0
1173 j = 0
1174 while i < num_flows:
1175 fc = Flow_Cfg()
1176 fc.rand(fi, \
1177 sw.tbl_stats.stats[tbl].wildcards, \
1178 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001179 sw.valid_ports, \
1180 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001181 )
1182 fc = fc.canonical()
1183 if self.find(fc):
1184 continue
1185 fc.send_rem = False
1186 self.insert(fc)
1187 i = i + 1
1188 j = j + 1
1189 if j >= sw.tbl_stats.stats[tbl].max_entries:
1190 tbl = tbl + 1
1191 j = 0
1192
1193
Howard Persh3340d452012-04-06 16:45:21 -07001194error_msgs = []
1195removed_msgs = []
1196
1197def error_handler(self, msg, rawmsg):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001198 fq_logger.info("Got an ERROR message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001199 % (msg.type, msg.code) \
1200 )
Howard Persh5f3c83f2012-04-13 09:57:10 -07001201 fq_logger.info("Message header:")
1202 fq_logger.info(msg.header.show())
Howard Persh3340d452012-04-06 16:45:21 -07001203 global error_msgs
1204 error_msgs.append(msg)
1205 pass
1206
1207def removed_handler(self, msg, rawmsg):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001208 fq_logger.info("Got a REMOVED message")
1209 fq_logger.info("Message header:")
1210 fq_logger.info(msg.header.show())
Howard Persh3340d452012-04-06 16:45:21 -07001211 global removed_msgs
1212 removed_msgs.append(msg)
1213 pass
1214
rootf6af1672012-04-06 09:46:29 -07001215class Switch:
1216 # Members:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001217 # controller - switch's test controller
1218 # sw_features - switch's OFPT_FEATURES_REPLY message
1219 # valid_ports - list of valid port numbers
1220 # valid_queues - list of valid [port, queue] pairs
1221 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1222 # queue_stats - switch's OFPT_STATS_REPLY message, for queue stats request
1223 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1224 # flow_tbl - (test's idea of) switch's flow table
rootf6af1672012-04-06 09:46:29 -07001225
1226 def __init__(self):
Howard Persh8d21c1f2012-04-20 15:57:29 -07001227 self.controller = None
1228 self.sw_features = None
1229 self.valid_ports = []
1230 self.valid_queues = []
1231 self.tbl_stats = None
1232 self.flow_stats = None
1233 self.flow_tbl = Flow_Tbl()
rootf6af1672012-04-06 09:46:29 -07001234
Howard Persh3340d452012-04-06 16:45:21 -07001235 def controller_set(self, controller):
1236 self.controller = controller
1237 # Register error message handler
1238 global error_msgs
1239 error_msgs = []
1240 controller.register(ofp.OFPT_ERROR, error_handler)
1241 controller.register(ofp.OFPT_FLOW_REMOVED, removed_handler)
1242
rootf6af1672012-04-06 09:46:29 -07001243 def features_get(self):
1244 # Get switch features
1245 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001246 (self.sw_features, pkt) = self.controller.transact(request)
rootf6af1672012-04-06 09:46:29 -07001247 if self.sw_features is None:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001248 fq_logger.error("Get switch features failed")
rootf6af1672012-04-06 09:46:29 -07001249 return False
1250 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001251 fq_logger.info("Ports reported by switch:")
1252 fq_logger.info(self.valid_ports)
1253 ports_override = test_param_get(fq_config, "ports", [])
1254 if ports_override != []:
1255 fq_logger.info("Overriding ports to:")
1256 fq_logger.info(ports_override)
1257 self.valid_ports = ports_override
1258
Howard Persh3340d452012-04-06 16:45:21 -07001259 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1260 # is that universal?
1261
1262 # TBD - There seems to be variability in which switches support which
1263 # ports; need to sort that out
1264 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1265# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1266# ofp.OFPP_NORMAL, \
1267# ofp.OFPP_FLOOD, \
1268# ofp.OFPP_ALL, \
1269# ofp.OFPP_CONTROLLER \
1270# ] \
1271# )
Howard Persh8d21c1f2012-04-20 15:57:29 -07001272 fq_logger.info("Supported actions reported by switch:")
1273 fq_logger.info("0x%x=%s" \
1274 % (self.sw_features.actions, \
1275 actions_bmap_to_str(self.sw_features.actions) \
1276 ) \
1277 )
Howard Persh07d99e62012-04-09 15:26:57 -07001278 actions_override = test_param_get(fq_config, "actions", -1)
1279 if actions_override != -1:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001280 fq_logger.info("Overriding supported actions to:")
1281 fq_logger.info(actions_bmap_to_str(actions_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001282 self.sw_features.actions = actions_override
rootf6af1672012-04-06 09:46:29 -07001283 return True
1284
1285 def tbl_stats_get(self):
1286 # Get table stats
Howard Persh680b92a2012-03-31 13:34:35 -07001287 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001288 (self.tbl_stats, pkt) = self.controller.transact(request)
Howard Persh07d99e62012-04-09 15:26:57 -07001289 if self.tbl_stats is None:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001290 fq_logger.error("Get table stats failed")
Howard Persh07d99e62012-04-09 15:26:57 -07001291 return False
Howard Persh8d21c1f2012-04-20 15:57:29 -07001292 i = 0
Howard Persh07d99e62012-04-09 15:26:57 -07001293 for ts in self.tbl_stats.stats:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001294 fq_logger.info("Supported wildcards for table %d reported by switch:"
1295 % (i)
1296 )
1297 fq_logger.info("0x%x=%s" \
1298 % (ts.wildcards, \
1299 wildcards_to_str(ts.wildcards) \
1300 ) \
1301 )
Howard Persh07d99e62012-04-09 15:26:57 -07001302 wildcards_override = test_param_get(fq_config, "wildcards", -1)
1303 if wildcards_override != -1:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001304 fq_logger.info("Overriding supported wildcards for table %d to:"
1305 % (i)
1306 )
1307 fq_logger.info(wildcards_to_str(wildcards_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001308 ts.wildcards = wildcards_override
Howard Persh8d21c1f2012-04-20 15:57:29 -07001309 i = i + 1
Howard Persh07d99e62012-04-09 15:26:57 -07001310 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001311
Howard Persh8d21c1f2012-04-20 15:57:29 -07001312 def queue_stats_get(self):
1313 # Get queue stats
1314 request = message.queue_stats_request()
1315 request.port_no = ofp.OFPP_ALL
1316 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001317 (self.queue_stats, pkt) = self.controller.transact(request)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001318 if self.queue_stats is None:
1319 fq_logger.error("Get queue stats failed")
1320 return False
1321 self.valid_queues = map(lambda x: (x.port_no, x.queue_id), \
1322 self.queue_stats.stats \
1323 )
1324 fq_logger.info("(Port, queue) pairs reported by switch:")
1325 fq_logger.info(self.valid_queues)
1326 queues_override = test_param_get(fq_config, "queues", [])
1327 if queues_override != []:
1328 fq_logger.info("Overriding (port, queue) pairs to:")
1329 fq_logger.info(queues_override)
1330 self.valid_queues = queues_override
1331 return True
1332
1333 def connect(self, controller):
1334 # Connect to controller, and get all switch capabilities
1335 self.controller_set(controller)
1336 return (self.features_get() \
1337 and self.tbl_stats_get() \
1338 and self.queue_stats_get() \
1339 )
1340
Howard Pershc1199d52012-04-11 14:21:32 -07001341 def flow_stats_get(self, limit = 10000):
rootf6af1672012-04-06 09:46:29 -07001342 request = message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -07001343 query_match = ofp.ofp_match()
1344 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001345 request.match = query_match
1346 request.table_id = 0xff
1347 request.out_port = ofp.OFPP_NONE;
Howard Persh3340d452012-04-06 16:45:21 -07001348 if self.controller.message_send(request) == -1:
1349 return False
1350 # <TBD>
1351 # Glue together successive reponse messages for stats reply.
1352 # Looking at the "more" flag and performing re-assembly
1353 # should be a part of the infrastructure.
1354 # </TBD>
1355 n = 0
1356 while True:
Howard Persh07d99e62012-04-09 15:26:57 -07001357 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY, 4)
Howard Persh3340d452012-04-06 16:45:21 -07001358 if resp is None:
Howard Pershc1199d52012-04-11 14:21:32 -07001359 return False # Did not get expected response
Howard Persh3340d452012-04-06 16:45:21 -07001360 if n == 0:
1361 self.flow_stats = resp
1362 else:
1363 self.flow_stats.stats.extend(resp.stats)
1364 n = n + 1
Howard Pershc1199d52012-04-11 14:21:32 -07001365 if len(self.flow_stats.stats) > limit:
1366 fq_logger.error("Too many flows returned")
1367 return False
1368 if (resp.flags & 1) == 0:
1369 break # No more responses expected
Howard Persh3340d452012-04-06 16:45:21 -07001370 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001371
rootf6af1672012-04-06 09:46:29 -07001372 def flow_add(self, flow_cfg, overlapf = False):
Howard Persh680b92a2012-03-31 13:34:35 -07001373 flow_mod_msg = message.flow_mod()
1374 flow_mod_msg.command = ofp.OFPFC_ADD
1375 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001376 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001377 if overlapf:
1378 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001379 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001380 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Howard Persh07d99e62012-04-09 15:26:57 -07001381 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001382 fq_logger.info("Sending flow_mod(add), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001383 % (flow_mod_msg.header.xid)
1384 )
rootf6af1672012-04-06 09:46:29 -07001385 return (self.controller.message_send(flow_mod_msg) != -1)
Howard Persh680b92a2012-03-31 13:34:35 -07001386
rootf6af1672012-04-06 09:46:29 -07001387 def flow_mod(self, flow_cfg, strictf):
Howard Persh680b92a2012-03-31 13:34:35 -07001388 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001389 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf \
1390 else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -07001391 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001392 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001393 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001394 fq_logger.info("Sending flow_mod(mod), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001395 % (flow_mod_msg.header.xid)
1396 )
rootf6af1672012-04-06 09:46:29 -07001397 return (self.controller.message_send(flow_mod_msg) != -1)
1398
1399 def flow_del(self, flow_cfg, strictf):
1400 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001401 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf \
1402 else ofp.OFPFC_DELETE
rootf6af1672012-04-06 09:46:29 -07001403 flow_mod_msg.buffer_id = 0xffffffff
1404 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001405 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001406 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001407 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001408 fq_logger.info("Sending flow_mod(del), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001409 % (flow_mod_msg.header.xid)
1410 )
rootf6af1672012-04-06 09:46:29 -07001411 return (self.controller.message_send(flow_mod_msg) != -1)
1412
1413 def barrier(self):
1414 barrier = message.barrier_request()
Howard Persh07d99e62012-04-09 15:26:57 -07001415 (resp, pkt) = self.controller.transact(barrier, 20)
rootf6af1672012-04-06 09:46:29 -07001416 return (resp is not None)
1417
Howard Persh3340d452012-04-06 16:45:21 -07001418 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001419 result = True
Howard Persh3340d452012-04-06 16:45:21 -07001420 global error_msgs
Howard Persh5f3c83f2012-04-13 09:57:10 -07001421 fq_logger.info("Expecting %d error messages" % (num_exp))
Howard Persh3340d452012-04-06 16:45:21 -07001422 num_got = len(error_msgs)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001423 fq_logger.info("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001424 if num_got != num_exp:
Dan Talayco910a8282012-04-07 00:05:20 -07001425 fq_logger.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001426 result = False
1427 if num_exp == 0:
1428 return result
1429 elif num_exp == 1:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001430 fq_logger.info("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001431 % (type, code) \
1432 )
1433 f = False
1434 for e in error_msgs:
1435 if e.type == type and e.code == code:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001436 fq_logger.info("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001437 f = True
1438 if not f:
Dan Talayco910a8282012-04-07 00:05:20 -07001439 fq_logger.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001440 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001441 else:
Dan Talayco910a8282012-04-07 00:05:20 -07001442 fq_logger.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001443 result = False
1444 return result
1445
Howard Persh3340d452012-04-06 16:45:21 -07001446 def removed_verify(self, num_exp):
1447 result = True
1448 global removed_msgs
Howard Persh5f3c83f2012-04-13 09:57:10 -07001449 fq_logger.info("Expecting %d removed messages" % (num_exp))
Howard Persh3340d452012-04-06 16:45:21 -07001450 num_got = len(removed_msgs)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001451 fq_logger.info("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001452 if num_got != num_exp:
Dan Talayco910a8282012-04-07 00:05:20 -07001453 fq_logger.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001454 result = False
1455 if num_exp < 2:
1456 return result
Dan Talayco910a8282012-04-07 00:05:20 -07001457 fq_logger.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001458 return False
1459
Howard Persh5f3c83f2012-04-13 09:57:10 -07001460 # modf == True <=> Verify for flow modify, else for add/delete
1461 def flow_tbl_verify(self, modf = False):
rootf6af1672012-04-06 09:46:29 -07001462 result = True
1463
1464 # Verify flow count in switch
Howard Persh5f3c83f2012-04-13 09:57:10 -07001465 fq_logger.info("Reading table stats")
1466 fq_logger.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001467 if not self.tbl_stats_get():
Dan Talayco910a8282012-04-07 00:05:20 -07001468 fq_logger.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001469 return False
1470 n = 0
1471 for ts in self.tbl_stats.stats:
1472 n = n + ts.active_count
Howard Persh5f3c83f2012-04-13 09:57:10 -07001473 fq_logger.info("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001474 % (n) \
1475 )
1476 if n != self.flow_tbl.count():
Dan Talayco910a8282012-04-07 00:05:20 -07001477 fq_logger.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001478 result = False
1479
1480 # Read flows from switch
Howard Persh5f3c83f2012-04-13 09:57:10 -07001481 fq_logger.info("Retrieving flows from switch")
1482 fq_logger.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001483 if not self.flow_stats_get():
Dan Talayco910a8282012-04-07 00:05:20 -07001484 fq_logger.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001485 return False
Howard Persh5f3c83f2012-04-13 09:57:10 -07001486 fq_logger.info("Retrieved %d flows" % (len(self.flow_stats.stats)))
rootf6af1672012-04-06 09:46:29 -07001487
1488 # Verify flows returned by switch
1489
1490 if len(self.flow_stats.stats) != self.flow_tbl.count():
Dan Talayco910a8282012-04-07 00:05:20 -07001491 fq_logger.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001492 result = False
1493
Howard Persh5f3c83f2012-04-13 09:57:10 -07001494 fq_logger.info("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001495 for fc in self.flow_tbl.values():
1496 fc.matched = False
1497 for fs in self.flow_stats.stats:
1498 flow_in = Flow_Cfg()
1499 flow_in.from_flow_stat(fs)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001500 fq_logger.info("Received flow:")
1501 fq_logger.info(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001502 fc = self.flow_tbl.find(flow_in)
1503 if fc is None:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001504 fq_logger.error("Received flow:")
1505 fq_logger.error(str(flow_in))
Dan Talayco910a8282012-04-07 00:05:20 -07001506 fq_logger.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001507 result = False
1508 elif fc.matched:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001509 fq_logger.error("Received flow:")
1510 fq_logger.error(str(flow_in))
Dan Talayco910a8282012-04-07 00:05:20 -07001511 fq_logger.error("re-matches defined flow:")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001512 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001513 result = False
1514 else:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001515 fq_logger.info("matched")
1516 if modf:
1517 # Check for modify
1518
1519 if flow_in.cookie != fc.cookie:
1520 fq_logger.warning("Defined flow:")
1521 fq_logger.warning(str(fc))
1522 fq_logger.warning("Received flow:")
1523 fq_logger.warning(str(flow_in))
1524 fq_logger.warning("cookies do not match")
1525 if not flow_in.actions_equal(fc):
1526 fq_logger.error("Defined flow:")
1527 fq_logger.error(str(fc))
1528 fq_logger.error("Received flow:")
1529 fq_logger.error(str(flow_in))
1530 fq_logger.error("actions do not match")
1531 else:
1532 # Check for add/delete
1533
1534 if not flow_in == fc:
1535 fq_logger.error("Defined flow:")
1536 fq_logger.error(str(fc))
1537 fq_logger.error("Received flow:")
1538 fq_logger.error(str(flow_in))
1539 fq_logger.error("non-key portions of flow do not match")
1540 result = False
rootf6af1672012-04-06 09:46:29 -07001541 fc.matched = True
1542 for fc in self.flow_tbl.values():
1543 if not fc.matched:
Dan Talayco910a8282012-04-07 00:05:20 -07001544 fq_logger.error("Defined flow:")
1545 fq_logger.error(str(fc))
1546 fq_logger.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001547 result = False
1548
1549 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001550
Howard Persh07d99e62012-04-09 15:26:57 -07001551# FLOW ADD 5
1552#
1553# OVERVIEW
1554# Add flows to switch, read back and verify flow configurations
1555#
1556# PURPOSE
1557# - Test acceptance of flow adds
1558# - Test ability of switch to process additions to flow table in random
1559# priority order
1560# - Test correctness of flow configuration responses
1561#
1562# PARAMETERS
1563#
1564# Name: num_flows
1565# Type: number
1566# Description:
1567# Number of flows to define; 0 => maximum number of flows, as determined
1568# from switch capabilities
1569# Default: 100
1570#
1571# PROCESS
1572# 1. Delete all flows from switch
1573# 2. Generate <num_flows> distinct flow configurations
1574# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1575# 4. Verify that no OFPT_ERROR responses were generated by switch
1576# 5. Retrieve flow stats from switch
1577# 6. Compare flow configurations returned by switch
1578# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1579# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001580
rootf6af1672012-04-06 09:46:29 -07001581class Flow_Add_5(basic.SimpleProtocol):
1582 """
1583 Test FLOW_ADD_5 from draft top-half test plan
1584
1585 INPUTS
1586 num_flows - Number of flows to generate
1587 """
Howard Persh680b92a2012-03-31 13:34:35 -07001588
rootf6af1672012-04-06 09:46:29 -07001589 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001590 fq_logger.info("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001591
Dan Talayco910a8282012-04-07 00:05:20 -07001592 num_flows = test_param_get(fq_config, "num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001593
Howard Pershc7963582012-03-29 10:02:59 -07001594 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001595
Howard Persh5f3c83f2012-04-13 09:57:10 -07001596 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001597 rc = delete_all_flows(self.controller, fq_logger)
Howard Pershc7963582012-03-29 10:02:59 -07001598 self.assertEqual(rc, 0, "Failed to delete all flows")
1599
rootf6af1672012-04-06 09:46:29 -07001600 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001601
rootf6af1672012-04-06 09:46:29 -07001602 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001603 self.assertTrue(sw.connect(self.controller), \
1604 "Failed to connect to switch" \
1605 )
Howard Pershc7963582012-03-29 10:02:59 -07001606
rootf6af1672012-04-06 09:46:29 -07001607 if num_flows == 0:
1608 # Number of flows requested was 0
1609 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001610
rootf6af1672012-04-06 09:46:29 -07001611 for ts in sw.tbl_stats.stats:
1612 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001613
Howard Persh5f3c83f2012-04-13 09:57:10 -07001614 fq_logger.info("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001615
1616 # Dream up some flow information, i.e. space to chose from for
1617 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001618
rootf6af1672012-04-06 09:46:29 -07001619 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001620 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001621
rootf6af1672012-04-06 09:46:29 -07001622 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001623
rootf6af1672012-04-06 09:46:29 -07001624 ft = Flow_Tbl()
1625 ft.rand(sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001626
rootf6af1672012-04-06 09:46:29 -07001627 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001628
Howard Persh5f3c83f2012-04-13 09:57:10 -07001629 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001630 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07001631 fq_logger.info("Adding flow:")
1632 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001633 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001634
rootf6af1672012-04-06 09:46:29 -07001635 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001636
rootf6af1672012-04-06 09:46:29 -07001637 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001638
rootf6af1672012-04-06 09:46:29 -07001639 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001640
rootf6af1672012-04-06 09:46:29 -07001641 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001642
rootf6af1672012-04-06 09:46:29 -07001643 if not sw.errors_verify(0):
1644 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001645
rootf6af1672012-04-06 09:46:29 -07001646 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001647
rootf6af1672012-04-06 09:46:29 -07001648 sw.flow_tbl = ft
1649 if not sw.flow_tbl_verify():
1650 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001651
rootf6af1672012-04-06 09:46:29 -07001652 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001653 fq_logger.info("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001654
Howard Pershc7963582012-03-29 10:02:59 -07001655
Howard Persh07d99e62012-04-09 15:26:57 -07001656# FLOW ADD 5_1
1657#
1658# OVERVIEW
1659# Verify handling of non-canonical flows
1660#
1661# PURPOSE
1662# - Test that switch detects and correctly responds to a non-canonical flow
1663# definition. A canonical flow is one that satisfies all match qualifier
1664# dependencies; a non-canonical flow is one that does not.
1665#
1666# PARAMETERS
1667# - None
1668#
1669# PROCESS
1670# 1. Delete all flows from switch
1671# 2. Generate 1 flow definition, which is different from its canonicalization
1672# 3. Send flow to switch
1673# 4. Retrieve flow from switch
1674# 5. Compare returned flow to canonical form of defined flow
1675# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1676
1677# Disabled.
1678# Should be DUT dependent.
1679test_prio["Flow_Add_5_1"] = -1
1680
rootf6af1672012-04-06 09:46:29 -07001681class Flow_Add_5_1(basic.SimpleProtocol):
1682 """
1683 Test FLOW_ADD_5.1 from draft top-half test plan
1684
1685 INPUTS
1686 None
1687 """
1688
1689 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001690 fq_logger.info("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001691
Dan Talayco910a8282012-04-07 00:05:20 -07001692 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001693
1694 # Clear all flows from switch
1695
Howard Persh5f3c83f2012-04-13 09:57:10 -07001696 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001697 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001698 self.assertEqual(rc, 0, "Failed to delete all flows")
1699
1700 # Get switch capabilites
1701
rootf6af1672012-04-06 09:46:29 -07001702 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001703 self.assertTrue(sw.connect(self.controller), \
1704 "Failed to connect to switch" \
1705 )
rootf6af1672012-04-06 09:46:29 -07001706
1707 # Dream up some flow information, i.e. space to chose from for
1708 # random flow parameter generation
1709
1710 fi = Flow_Info()
1711 fi.rand(10)
1712
1713 # Dream up a flow config that will be canonicalized by the switch
1714
1715 while True:
1716 fc = Flow_Cfg()
1717 fc.rand(fi, \
1718 sw.tbl_stats.stats[0].wildcards, \
1719 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001720 sw.valid_ports, \
1721 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001722 )
1723 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001724 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001725 break
1726
1727 ft = Flow_Tbl()
1728 ft.insert(fcc)
1729
1730 # Send it to the switch
1731
Howard Persh5f3c83f2012-04-13 09:57:10 -07001732 fq_logger.info("Sending flow add to switch:")
1733 fq_logger.info(str(fc))
1734 fq_logger.info("should be canonicalized as:")
1735 fq_logger.info(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001736 fc.send_rem = False
1737 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1738
1739 # Do barrier, to make sure all flows are in
1740
1741 self.assertTrue(sw.barrier(), "Barrier failed")
1742
1743 result = True
1744
1745 # Check for any error messages
1746
1747 if not sw.errors_verify(0):
1748 result = False
1749
1750 # Verify flow table
1751
1752 sw.flow_tbl = ft
1753 if not sw.flow_tbl_verify():
1754 result = False
1755
1756 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001757 fq_logger.info("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001758
1759
Howard Persh07d99e62012-04-09 15:26:57 -07001760# FLOW ADD 6
1761#
1762# OVERVIEW
1763# Test flow table capacity
1764#
1765# PURPOSE
1766# - Test switch can accept as many flow definitions as it claims
1767# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1768# - Test that attempting to create flows beyond capacity does not corrupt
1769# flow table
1770#
1771# PARAMETERS
1772# None
1773#
1774# PROCESS
1775# 1. Delete all flows from switch
1776# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1777# to determine flow table size, N
1778# 3. Generate (N + 1) distinct flow configurations
1779# 4. Send N flow adds to switch, for flows generated in step 3 above
1780# 5. Verify flow table in switch
1781# 6. Send one more flow add to switch
1782# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1783# response was generated by switch, for last flow mod sent
1784# 7. Retrieve flow stats from switch
1785# 8. Verify flow table in switch
1786# 9. Test PASSED iff:
1787# - error message received, for correct flow
1788# - last flow definition sent to switch is not in flow table
1789# else test FAILED
1790
Howard Persh3340d452012-04-06 16:45:21 -07001791# Disabled because of bogus capacity reported by OVS.
1792# Should be DUT dependent.
1793test_prio["Flow_Add_6"] = -1
1794
rootf6af1672012-04-06 09:46:29 -07001795class Flow_Add_6(basic.SimpleProtocol):
1796 """
1797 Test FLOW_ADD_6 from draft top-half test plan
1798
1799 INPUTS
1800 num_flows - Number of flows to generate
1801 """
Howard Pershc7963582012-03-29 10:02:59 -07001802
1803 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001804 fq_logger.info("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001805
rootf6af1672012-04-06 09:46:29 -07001806 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001807
Howard Persh5f3c83f2012-04-13 09:57:10 -07001808 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001809 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001810 self.assertEqual(rc, 0, "Failed to delete all flows")
1811
1812 # Get switch capabilites
1813
rootf6af1672012-04-06 09:46:29 -07001814 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001815 self.assertTrue(sw.connect(self.controller), \
1816 "Failed to connect to switch" \
1817 )
rootf6af1672012-04-06 09:46:29 -07001818
root2843d2b2012-04-06 10:27:46 -07001819 num_flows = 0
rootf6af1672012-04-06 09:46:29 -07001820 for ts in sw.tbl_stats.stats:
1821 num_flows = num_flows + ts.max_entries
1822
Howard Persh5f3c83f2012-04-13 09:57:10 -07001823 fq_logger.info("Switch capacity is %d flows" % (num_flows))
1824 fq_logger.info("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001825
1826 # Dream up some flow information, i.e. space to chose from for
1827 # random flow parameter generation
1828
1829 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001830 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001831
1832 # Create a flow table, to switch's capacity
1833
1834 ft = Flow_Tbl()
1835 ft.rand(sw, fi, num_flows)
1836
1837 # Send flow table to switch
1838
Howard Persh5f3c83f2012-04-13 09:57:10 -07001839 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001840 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07001841 fq_logger.info("Adding flow:")
1842 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001843 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1844
1845 # Do barrier, to make sure all flows are in
1846
1847 self.assertTrue(sw.barrier(), "Barrier failed")
1848
1849 result = True
1850
1851 # Check for any error messages
1852
1853 if not sw.errors_verify(0):
1854 result = False
1855
1856 # Dream up one more flow
1857
Howard Persh5f3c83f2012-04-13 09:57:10 -07001858 fq_logger.info("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001859 while True:
1860 fc = Flow_Cfg()
1861 fc.rand(fi, \
Howard Persh07d99e62012-04-09 15:26:57 -07001862 sw.tbl_stats.stats[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001863 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001864 sw.valid_ports, \
1865 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001866 )
1867 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001868 if not ft.find(fc):
1869 break
rootf6af1672012-04-06 09:46:29 -07001870
1871 # Send one-more flow
1872
1873 fc.send_rem = False
Howard Persh5f3c83f2012-04-13 09:57:10 -07001874 fq_logger.info("Sending flow add switch")
1875 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001876 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1877
1878 # Do barrier, to make sure all flows are in
1879
1880 self.assertTrue(sw.barrier(), "Barrier failed")
1881
1882 # Check for expected error message
1883
1884 if not sw.errors_verify(1, \
1885 ofp.OFPET_FLOW_MOD_FAILED, \
1886 ofp.OFPFMFC_ALL_TABLES_FULL \
1887 ):
1888 result = False
1889
1890 # Verify flow table
1891
1892 sw.flow_tbl = ft
1893 if not sw.flow_tbl_verify():
1894 result = False
1895
1896 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001897 fq_logger.info("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001898
1899
Howard Persh07d99e62012-04-09 15:26:57 -07001900# FLOW ADD 7
1901#
1902# OVERVIEW
1903# Test flow redefinition
1904#
1905# PURPOSE
1906# Verify that successive flow adds with same priority and match criteria
1907# overwrite in flow table
1908#
1909# PARAMETERS
1910# None
1911#
1912# PROCESS
1913# 1. Delete all flows from switch
1914# 2. Generate flow definition F1
1915# 3. Generate flow definition F2, with same key (priority and match) as F1,
1916# but with different actions
1917# 4. Send flow adds for F1 and F2 to switch
1918# 5. Verify flow definitions in switch
1919# 6. Test PASSED iff 1 flow returned by switch, matching configuration of F2;
1920# else test FAILED
1921
rootf6af1672012-04-06 09:46:29 -07001922class Flow_Add_7(basic.SimpleProtocol):
1923 """
1924 Test FLOW_ADD_7 from draft top-half test plan
1925
1926 INPUTS
1927 None
1928 """
1929
1930 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001931 fq_logger.info("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001932
1933 # Clear all flows from switch
1934
Howard Persh5f3c83f2012-04-13 09:57:10 -07001935 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001936 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001937 self.assertEqual(rc, 0, "Failed to delete all flows")
1938
1939 # Get switch capabilites
1940
rootf6af1672012-04-06 09:46:29 -07001941 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001942 self.assertTrue(sw.connect(self.controller), \
1943 "Failed to connect to switch" \
1944 )
rootf6af1672012-04-06 09:46:29 -07001945
1946 # Dream up some flow information, i.e. space to chose from for
1947 # random flow parameter generation
1948
1949 fi = Flow_Info()
1950 fi.rand(10)
1951
1952 # Dream up a flow config
1953
1954 fc = Flow_Cfg()
1955 fc.rand(fi, \
1956 sw.tbl_stats.stats[0].wildcards, \
1957 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001958 sw.valid_ports, \
1959 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001960 )
1961 fc = fc.canonical()
1962
1963 # Send it to the switch
1964
Howard Persh5f3c83f2012-04-13 09:57:10 -07001965 fq_logger.info("Sending flow add to switch:")
1966 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001967 ft = Flow_Tbl()
1968 fc.send_rem = False
1969 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1970 ft.insert(fc)
1971
1972 # Dream up some different actions, with the same flow key
1973
1974 fc2 = copy.deepcopy(fc)
1975 while True:
1976 fc2.rand_mod(fi, \
1977 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001978 sw.valid_ports, \
1979 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001980 )
1981 if fc2 != fc:
1982 break
1983
1984 # Send that to the switch
1985
Howard Persh5f3c83f2012-04-13 09:57:10 -07001986 fq_logger.info("Sending flow add to switch:")
1987 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07001988 fc2.send_rem = False
1989 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
1990 ft.insert(fc2)
1991
1992 # Do barrier, to make sure all flows are in
1993
1994 self.assertTrue(sw.barrier(), "Barrier failed")
1995
1996 result = True
1997
1998 # Check for any error messages
1999
2000 if not sw.errors_verify(0):
2001 result = False
2002
2003 # Verify flow table
2004
2005 sw.flow_tbl = ft
2006 if not sw.flow_tbl_verify():
2007 result = False
2008
2009 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002010 fq_logger.info("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002011
2012
Howard Persh07d99e62012-04-09 15:26:57 -07002013# FLOW ADD 8
2014#
2015# OVERVIEW
2016# Add overlapping flows to switch, verify that overlapping flows are rejected
2017#
2018# PURPOSE
2019# - Test detection of overlapping flows by switch
2020# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
2021# - Test rejection of overlapping flows
2022# - Test defining overlapping flows does not corrupt flow table
2023#
2024# PARAMETERS
2025# None
2026#
2027# PROCESS
2028# 1. Delete all flows from switch
2029# 2. Generate flow definition F1
2030# 3. Generate flow definition F2, with key overlapping F1
2031# 4. Send flow add to switch, for F1
2032# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
2033# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
2034# was generated by switch
2035# 7. Verifiy flows configured in swtich
2036# 8. Test PASSED iff:
2037# - error message received, for overlapping flow
2038# - overlapping flow is not in flow table
2039# else test FAILED
2040
rootf6af1672012-04-06 09:46:29 -07002041class Flow_Add_8(basic.SimpleProtocol):
2042 """
2043 Test FLOW_ADD_8 from draft top-half test plan
2044
2045 INPUTS
2046 None
2047 """
2048
2049 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002050 fq_logger.info("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002051
2052 # Clear all flows from switch
2053
Howard Persh5f3c83f2012-04-13 09:57:10 -07002054 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002055 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002056 self.assertEqual(rc, 0, "Failed to delete all flows")
2057
2058 # Get switch capabilites
2059
rootf6af1672012-04-06 09:46:29 -07002060 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002061 self.assertTrue(sw.connect(self.controller), \
2062 "Failed to connect to switch" \
2063 )
rootf6af1672012-04-06 09:46:29 -07002064
2065 # Dream up some flow information, i.e. space to chose from for
2066 # random flow parameter generation
2067
2068 fi = Flow_Info()
2069 fi.rand(10)
2070
2071 # Dream up a flow config, with at least 1 qualifier specified
2072
2073 fc = Flow_Cfg()
2074 while True:
2075 fc.rand(fi, \
2076 sw.tbl_stats.stats[0].wildcards, \
2077 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002078 sw.valid_ports, \
2079 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002080 )
2081 fc = fc.canonical()
2082 if fc.match.wildcards != ofp.OFPFW_ALL:
2083 break
2084
2085 # Send it to the switch
2086
Howard Persh5f3c83f2012-04-13 09:57:10 -07002087 fq_logger.info("Sending flow add to switch:")
2088 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002089 ft = Flow_Tbl()
2090 fc.send_rem = False
2091 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2092 ft.insert(fc)
2093
2094 # Wildcard out one qualifier that was specified, to create an
2095 # overlapping flow
2096
2097 fc2 = copy.deepcopy(fc)
2098 for wi in shuffle(range(len(all_wildcards_list))):
2099 w = all_wildcards_list[wi]
2100 if (fc2.match.wildcards & w) == 0:
2101 break
2102 if w == ofp.OFPFW_NW_SRC_MASK:
2103 w = ofp.OFPFW_NW_SRC_ALL
2104 wn = "OFPFW_NW_SRC"
2105 elif w == ofp.OFPFW_NW_DST_MASK:
2106 w = ofp.OFPFW_NW_DST_ALL
2107 wn = "OFPFW_NW_DST"
2108 else:
2109 wn = all_wildcard_names[w]
Howard Persh5f3c83f2012-04-13 09:57:10 -07002110 fq_logger.info("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07002111 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07002112 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07002113
2114 # Send that to the switch, with overlap checking
2115
Howard Persh5f3c83f2012-04-13 09:57:10 -07002116 fq_logger.info("Sending flow add to switch:")
2117 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002118 fc2.send_rem = False
2119 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
2120
2121 # Do barrier, to make sure all flows are in
2122 self.assertTrue(sw.barrier(), "Barrier failed")
2123
2124 result = True
2125
2126 # Check for expected error message
2127
2128 if not sw.errors_verify(1, \
2129 ofp.OFPET_FLOW_MOD_FAILED, \
2130 ofp.OFPFMFC_OVERLAP \
2131 ):
2132 result = False
2133
2134 # Verify flow table
2135
2136 sw.flow_tbl = ft
2137 if not sw.flow_tbl_verify():
2138 result = False
2139
2140 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002141 fq_logger.info("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002142
2143
Howard Persh07d99e62012-04-09 15:26:57 -07002144# FLOW MODIFY 1
2145#
2146# OVERVIEW
2147# Strict modify of single existing flow
2148#
2149# PURPOSE
2150# - Verify that strict flow modify operates only on specified flow
2151# - Verify that flow is correctly modified
2152#
2153# PARAMETERS
2154# None
2155#
2156# PROCESS
2157# 1. Delete all flows from switch
2158# 2. Generate 1 flow F
2159# 3. Send flow add to switch, for flow F
2160# 4. Generate new action list for flow F, yielding F'
2161# 5. Send strict flow modify to switch, for flow F'
2162# 6. Verify flow table in switch
2163# 7. Test PASSED iff flow returned by switch is F'; else FAILED
2164
rootf6af1672012-04-06 09:46:29 -07002165class Flow_Mod_1(basic.SimpleProtocol):
2166 """
2167 Test FLOW_MOD_1 from draft top-half test plan
2168
2169 INPUTS
2170 None
2171 """
2172
2173 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002174 fq_logger.info("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002175
2176 # Clear all flows from switch
2177
Howard Persh5f3c83f2012-04-13 09:57:10 -07002178 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002179 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002180 self.assertEqual(rc, 0, "Failed to delete all flows")
2181
2182 # Get switch capabilites
2183
rootf6af1672012-04-06 09:46:29 -07002184 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002185 self.assertTrue(sw.connect(self.controller), \
2186 "Failed to connect to switch" \
2187 )
rootf6af1672012-04-06 09:46:29 -07002188
2189 # Dream up some flow information, i.e. space to chose from for
2190 # random flow parameter generation
2191
2192 fi = Flow_Info()
2193 fi.rand(10)
2194
2195 # Dream up a flow config
2196
2197 fc = Flow_Cfg()
2198 fc.rand(fi, \
2199 sw.tbl_stats.stats[0].wildcards, \
2200 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002201 sw.valid_ports, \
2202 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002203 )
2204 fc = fc.canonical()
2205
2206 # Send it to the switch
2207
Howard Persh5f3c83f2012-04-13 09:57:10 -07002208 fq_logger.info("Sending flow add to switch:")
2209 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002210 ft = Flow_Tbl()
2211 fc.send_rem = False
2212 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2213 ft.insert(fc)
2214
2215 # Dream up some different actions, with the same flow key
2216
2217 fc2 = copy.deepcopy(fc)
2218 while True:
2219 fc2.rand_mod(fi, \
2220 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002221 sw.valid_ports, \
2222 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002223 )
2224 if fc2 != fc:
2225 break
2226
2227 # Send that to the switch
2228
Howard Persh5f3c83f2012-04-13 09:57:10 -07002229 fq_logger.info("Sending strict flow mod to switch:")
2230 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002231 fc2.send_rem = False
2232 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2233 ft.insert(fc2)
2234
2235 # Do barrier, to make sure all flows are in
2236
2237 self.assertTrue(sw.barrier(), "Barrier failed")
2238
2239 result = True
2240
2241 # Check for any error messages
2242
2243 if not sw.errors_verify(0):
2244 result = False
2245
2246 # Verify flow table
2247
2248 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002249 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002250 result = False
2251
2252 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002253 fq_logger.info("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002254
Howard Persh07d99e62012-04-09 15:26:57 -07002255
2256# FLOW MODIFY 2
2257#
2258# OVERVIEW
2259# Loose modify of mutiple flows
2260#
2261# PURPOSE
2262# - Verify that loose flow modify operates only on matching flows
2263# - Verify that matching flows are correctly modified
2264#
2265# PARAMETERS
2266# Name: num_flows
2267# Type: number
2268# Description:
2269# Number of flows to define
2270# Default: 100
2271#
2272# PROCESS
2273# 1. Delete all flows from switch
2274# 2. Generate <num_flows> distinct flow configurations
2275# 3. Send <num_flows> flow adds to switch
2276# 4. Pick 1 defined flow F at random
2277# 5. Create overlapping loose flow mod match criteria by repeatedly
2278# wildcarding out qualifiers in match of F => F',
2279# and create new actions list A' for F'
2280# 6. Send loose flow modify for F' to switch
2281# 7. Verify flow table in swtich
2282# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2283# are returned in step 7 above, each with correct (original or modified)
2284# action list;
2285# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002286
2287class Flow_Mod_2(basic.SimpleProtocol):
2288 """
2289 Test FLOW_MOD_2 from draft top-half test plan
2290
2291 INPUTS
2292 None
2293 """
2294
2295 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002296 fq_logger.info("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002297
Dan Talayco910a8282012-04-07 00:05:20 -07002298 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002299
2300 # Clear all flows from switch
2301
Howard Persh5f3c83f2012-04-13 09:57:10 -07002302 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002303 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002304 self.assertEqual(rc, 0, "Failed to delete all flows")
2305
2306 # Get switch capabilites
2307
rootf6af1672012-04-06 09:46:29 -07002308 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002309 self.assertTrue(sw.connect(self.controller), \
2310 "Failed to connect to switch" \
2311 )
rootf6af1672012-04-06 09:46:29 -07002312
2313 # Dream up some flow information, i.e. space to chose from for
2314 # random flow parameter generation
2315
2316 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002317 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002318 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002319
2320 # Dream up some flows
2321
2322 ft = Flow_Tbl()
2323 ft.rand(sw, fi, num_flows)
2324
2325 # Send flow table to switch
2326
Howard Persh5f3c83f2012-04-13 09:57:10 -07002327 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002328 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07002329 fq_logger.info("Adding flow:")
2330 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002331 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2332
2333 # Do barrier, to make sure all flows are in
2334
2335 self.assertTrue(sw.barrier(), "Barrier failed")
2336
2337 result = True
2338
2339 # Check for any error messages
2340
2341 if not sw.errors_verify(0):
2342 result = False
2343
2344 # Verify flow table
2345
2346 sw.flow_tbl = ft
2347 if not sw.flow_tbl_verify():
2348 result = False
2349
2350 # Pick a random flow as a basis
Howard Persh5f3c83f2012-04-13 09:57:10 -07002351
2352 mfc = copy.deepcopy((ft.values())[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002353 mfc.rand_mod(fi, \
2354 sw.sw_features.actions, \
2355 sw.valid_ports, \
2356 sw.valid_queues \
2357 )
rootf6af1672012-04-06 09:46:29 -07002358
2359 # Repeatedly wildcard qualifiers
2360
2361 for wi in shuffle(range(len(all_wildcards_list))):
2362 w = all_wildcards_list[wi]
2363 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2364 n = wildcard_get(mfc.match.wildcards, w)
2365 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002366 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2367 w, \
2368 random.randint(n + 1, 32) \
2369 )
rootf6af1672012-04-06 09:46:29 -07002370 else:
2371 continue
2372 else:
2373 if wildcard_get(mfc.match.wildcards, w) == 0:
2374 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2375 else:
2376 continue
2377 mfc = mfc.canonical()
2378
2379 # Count the number of flows that would be modified
2380
2381 n = 0
2382 for fc in ft.values():
2383 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2384 n = n + 1
2385
2386 # If more than 1, we found our loose delete flow spec
2387 if n > 1:
2388 break
2389
Howard Persh5f3c83f2012-04-13 09:57:10 -07002390 fq_logger.info("Modifying %d flows" % (n))
2391 fq_logger.info("Sending flow mod to switch:")
2392 fq_logger.info(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002393 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2394
2395 # Do barrier, to make sure all flows are in
2396 self.assertTrue(sw.barrier(), "Barrier failed")
2397
2398 # Check for error message
2399
2400 if not sw.errors_verify(0):
2401 result = False
2402
2403 # Apply flow mod to local flow table
2404
2405 for fc in ft.values():
2406 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002407 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002408
2409 # Verify flow table
2410
2411 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002412 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002413 result = False
2414
2415 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002416 fq_logger.info("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002417
2418
Howard Persh07d99e62012-04-09 15:26:57 -07002419# FLOW MODIFY 3
2420
2421# OVERVIEW
2422# Strict modify of non-existent flow
2423#
2424# PURPOSE
2425# Verify that strict modify of a non-existent flow is equivalent to a flow add
2426#
2427# PARAMETERS
2428# None
2429#
2430# PROCESS
2431# 1. Delete all flows from switch
2432# 2. Send single flow mod, as strict modify, to switch
2433# 3. Verify flow table in switch
2434# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2435
rootf6af1672012-04-06 09:46:29 -07002436class Flow_Mod_3(basic.SimpleProtocol):
2437 """
2438 Test FLOW_MOD_3 from draft top-half test plan
2439
2440 INPUTS
2441 None
2442 """
2443
2444 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002445 fq_logger.info("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002446
2447 # Clear all flows from switch
2448
Howard Persh5f3c83f2012-04-13 09:57:10 -07002449 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002450 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002451 self.assertEqual(rc, 0, "Failed to delete all flows")
2452
2453 # Get switch capabilites
2454
rootf6af1672012-04-06 09:46:29 -07002455 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002456 self.assertTrue(sw.connect(self.controller), \
2457 "Failed to connect to switch" \
2458 )
rootf6af1672012-04-06 09:46:29 -07002459
2460 # Dream up some flow information, i.e. space to chose from for
2461 # random flow parameter generation
2462
2463 fi = Flow_Info()
2464 fi.rand(10)
2465
2466 # Dream up a flow config
2467
2468 fc = Flow_Cfg()
2469 fc.rand(fi, \
2470 sw.tbl_stats.stats[0].wildcards, \
2471 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002472 sw.valid_ports, \
2473 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002474 )
2475 fc = fc.canonical()
2476
2477 # Send it to the switch
2478
Howard Persh5f3c83f2012-04-13 09:57:10 -07002479 fq_logger.info("Sending flow mod to switch:")
2480 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002481 ft = Flow_Tbl()
2482 fc.send_rem = False
2483 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2484 ft.insert(fc)
2485
2486 # Do barrier, to make sure all flows are in
2487
2488 self.assertTrue(sw.barrier(), "Barrier failed")
2489
2490 result = True
2491
2492 # Check for any error messages
2493
2494 if not sw.errors_verify(0):
2495 result = False
2496
2497 # Verify flow table
2498
2499 sw.flow_tbl = ft
2500 if not sw.flow_tbl_verify():
2501 result = False
2502
2503 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002504 fq_logger.info("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002505
2506
Howard Persh8d21c1f2012-04-20 15:57:29 -07002507# FLOW MODIFY 3_1
2508
2509# OVERVIEW
2510# No-op modify
2511#
2512# PURPOSE
2513# Verify that modify of a flow with new actions same as old ones operates correctly
2514#
2515# PARAMETERS
2516# None
2517#
2518# PROCESS
2519# 1. Delete all flows from switch
2520# 2. Send single flow mod, as strict modify, to switch
2521# 3. Verify flow table in switch
2522# 4. Send same flow mod, as strict modify, to switch
2523# 5. Verify flow table in switch
2524# 6. Test PASSED iff flow defined in step 2 and 4 above verified; else FAILED
2525
2526class Flow_Mod_3_1(basic.SimpleProtocol):
2527 """
2528 Test FLOW_MOD_3_1 from draft top-half test plan
2529
2530 INPUTS
2531 None
2532 """
2533
2534 def runTest(self):
2535 fq_logger.info("Flow_Mod_3_1 TEST BEGIN")
2536
2537 # Clear all flows from switch
2538
2539 fq_logger.info("Deleting all flows from switch")
2540 rc = delete_all_flows(self.controller, fq_logger)
2541 self.assertEqual(rc, 0, "Failed to delete all flows")
2542
2543 # Get switch capabilites
2544
2545 sw = Switch()
2546 self.assertTrue(sw.connect(self.controller), \
2547 "Failed to connect to switch" \
2548 )
2549
2550 # Dream up some flow information, i.e. space to chose from for
2551 # random flow parameter generation
2552
2553 fi = Flow_Info()
2554 fi.rand(10)
2555
2556 # Dream up a flow config
2557
2558 fc = Flow_Cfg()
2559 fc.rand(fi, \
2560 sw.tbl_stats.stats[0].wildcards, \
2561 sw.sw_features.actions, \
2562 sw.valid_ports, \
2563 sw.valid_queues \
2564 )
2565 fc = fc.canonical()
2566
2567 # Send it to the switch
2568
2569 fq_logger.info("Sending flow mod to switch:")
2570 fq_logger.info(str(fc))
2571 ft = Flow_Tbl()
2572 fc.send_rem = False
2573 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2574 ft.insert(fc)
2575
2576 # Do barrier, to make sure all flows are in
2577
2578 self.assertTrue(sw.barrier(), "Barrier failed")
2579
2580 result = True
2581
2582 # Check for any error messages
2583
2584 if not sw.errors_verify(0):
2585 result = False
2586
2587 # Verify flow table
2588
2589 sw.flow_tbl = ft
2590 if not sw.flow_tbl_verify():
2591 result = False
2592
2593 # Send same flow to the switch again
2594
2595 fq_logger.info("Sending flow mod to switch:")
2596 fq_logger.info(str(fc))
2597 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2598
2599 # Do barrier, to make sure all flows are in
2600
2601 self.assertTrue(sw.barrier(), "Barrier failed")
2602
2603 # Check for any error messages
2604
2605 if not sw.errors_verify(0):
2606 result = False
2607
2608 # Verify flow table
2609
2610 if not sw.flow_tbl_verify():
2611 result = False
2612
2613 self.assertTrue(result, "Flow_Mod_3_1 TEST FAILED")
2614 fq_logger.info("Flow_Mod_3_1 TEST PASSED")
2615
2616
Howard Persh07d99e62012-04-09 15:26:57 -07002617# FLOW DELETE 1
2618#
2619# OVERVIEW
2620# Strict delete of single flow
2621#
2622# PURPOSE
2623# Verify correct operation of strict delete of single defined flow
2624#
2625# PARAMETERS
2626# None
2627#
2628# PROCESS
2629# 1. Delete all flows from switch
2630# 2. Send flow F to switch
2631# 3. Send strict flow delete for F to switch
2632# 4. Verify flow table in swtich
2633# 6. Test PASSED iff all flows sent to switch in step 2 above,
2634# less flow removed in step 3 above, are returned in step 4 above;
2635# else test FAILED
2636
rootf6af1672012-04-06 09:46:29 -07002637class Flow_Del_1(basic.SimpleProtocol):
2638 """
2639 Test FLOW_DEL_1 from draft top-half test plan
2640
2641 INPUTS
2642 None
2643 """
2644
2645 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002646 fq_logger.info("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002647
2648 # Clear all flows from switch
2649
Howard Persh5f3c83f2012-04-13 09:57:10 -07002650 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002651 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002652 self.assertEqual(rc, 0, "Failed to delete all flows")
2653
2654 # Get switch capabilites
2655
rootf6af1672012-04-06 09:46:29 -07002656 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002657 self.assertTrue(sw.connect(self.controller), \
2658 "Failed to connect to switch" \
2659 )
rootf6af1672012-04-06 09:46:29 -07002660
2661 # Dream up some flow information, i.e. space to chose from for
2662 # random flow parameter generation
2663
2664 fi = Flow_Info()
2665 fi.rand(10)
2666
2667 # Dream up a flow config
2668
2669 fc = Flow_Cfg()
2670 fc.rand(fi, \
2671 sw.tbl_stats.stats[0].wildcards, \
2672 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002673 sw.valid_ports, \
2674 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002675 )
2676 fc = fc.canonical()
2677
2678 # Send it to the switch
2679
Howard Persh5f3c83f2012-04-13 09:57:10 -07002680 fq_logger.info("Sending flow add to switch:")
2681 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002682 ft = Flow_Tbl()
2683 fc.send_rem = False
2684 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2685 ft.insert(fc)
2686
2687 # Dream up some different actions, with the same flow key
2688
2689 fc2 = copy.deepcopy(fc)
2690 while True:
2691 fc2.rand_mod(fi, \
2692 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002693 sw.valid_ports, \
2694 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002695 )
2696 if fc2 != fc:
2697 break
2698
2699 # Delete strictly
2700
Howard Persh5f3c83f2012-04-13 09:57:10 -07002701 fq_logger.info("Sending strict flow del to switch:")
2702 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002703 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2704 ft.delete(fc)
2705
2706 # Do barrier, to make sure all flows are in
2707
2708 self.assertTrue(sw.barrier(), "Barrier failed")
2709
2710 result = True
2711
2712 # Check for any error messages
2713
2714 if not sw.errors_verify(0):
2715 result = False
2716
2717 # Verify flow table
2718
2719 sw.flow_tbl = ft
2720 if not sw.flow_tbl_verify():
2721 result = False
2722
2723 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002724 fq_logger.info("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002725
2726
Howard Persh07d99e62012-04-09 15:26:57 -07002727# FLOW DELETE 2
2728#
2729# OVERVIEW
2730# Loose delete of multiple flows
2731#
2732# PURPOSE
2733# - Verify correct operation of loose delete of multiple flows
2734#
2735# PARAMETERS
2736# Name: num_flows
2737# Type: number
2738# Description:
2739# Number of flows to define
2740# Default: 100
2741#
2742# PROCESS
2743# 1. Delete all flows from switch
2744# 2. Generate <num_flows> distinct flow configurations
2745# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2746# 4. Pick 1 defined flow F at random
2747# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2748# F' will match more than 1 existing flow key
2749# 6. Send loose flow delete for F' to switch
2750# 7. Verify flow table in switch
2751# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2752# removed in step 6 above (i.e. those that match F'), are returned
2753# in step 7 above;
2754# else test FAILED
2755
rootf6af1672012-04-06 09:46:29 -07002756class Flow_Del_2(basic.SimpleProtocol):
2757 """
2758 Test FLOW_DEL_2 from draft top-half test plan
2759
2760 INPUTS
2761 None
2762 """
2763
2764 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002765 fq_logger.info("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002766
Dan Talayco910a8282012-04-07 00:05:20 -07002767 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002768
2769 # Clear all flows from switch
2770
Howard Persh5f3c83f2012-04-13 09:57:10 -07002771 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002772 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002773 self.assertEqual(rc, 0, "Failed to delete all flows")
2774
2775 # Get switch capabilites
2776
rootf6af1672012-04-06 09:46:29 -07002777 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002778 self.assertTrue(sw.connect(self.controller), \
2779 "Failed to connect to switch" \
2780 )
rootf6af1672012-04-06 09:46:29 -07002781
2782 # Dream up some flow information, i.e. space to chose from for
2783 # random flow parameter generation
2784
2785 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002786 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002787 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002788
2789 # Dream up some flows
2790
2791 ft = Flow_Tbl()
2792 ft.rand(sw, fi, num_flows)
2793
2794 # Send flow table to switch
2795
Howard Persh5f3c83f2012-04-13 09:57:10 -07002796 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002797 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07002798 fq_logger.info("Adding flow:")
2799 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002800 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2801
2802 # Do barrier, to make sure all flows are in
2803
2804 self.assertTrue(sw.barrier(), "Barrier failed")
2805
2806 result = True
2807
2808 # Check for any error messages
2809
2810 if not sw.errors_verify(0):
2811 result = False
2812
2813 # Verify flow table
2814
2815 sw.flow_tbl = ft
2816 if not sw.flow_tbl_verify():
2817 result = False
2818
2819 # Pick a random flow as a basis
2820
2821 dfc = copy.deepcopy(ft.values()[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002822 dfc.rand_mod(fi, \
2823 sw.sw_features.actions, \
2824 sw.valid_ports, \
2825 sw.valid_queues \
2826 )
rootf6af1672012-04-06 09:46:29 -07002827
2828 # Repeatedly wildcard qualifiers
2829
2830 for wi in shuffle(range(len(all_wildcards_list))):
2831 w = all_wildcards_list[wi]
2832 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2833 n = wildcard_get(dfc.match.wildcards, w)
2834 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002835 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2836 w, \
2837 random.randint(n + 1, 32) \
2838 )
rootf6af1672012-04-06 09:46:29 -07002839 else:
2840 continue
2841 else:
2842 if wildcard_get(dfc.match.wildcards, w) == 0:
2843 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2844 else:
2845 continue
2846 dfc = dfc.canonical()
2847
2848 # Count the number of flows that would be deleted
2849
2850 n = 0
2851 for fc in ft.values():
2852 if dfc.overlaps(fc, True):
2853 n = n + 1
2854
2855 # If more than 1, we found our loose delete flow spec
2856 if n > 1:
2857 break
2858
Howard Persh5f3c83f2012-04-13 09:57:10 -07002859 fq_logger.info("Deleting %d flows" % (n))
2860 fq_logger.info("Sending flow del to switch:")
2861 fq_logger.info(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002862 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2863
2864 # Do barrier, to make sure all flows are in
2865 self.assertTrue(sw.barrier(), "Barrier failed")
2866
2867 # Check for error message
2868
2869 if not sw.errors_verify(0):
2870 result = False
2871
2872 # Apply flow mod to local flow table
2873
2874 for fc in ft.values():
2875 if dfc.overlaps(fc, True):
2876 ft.delete(fc)
2877
2878 # Verify flow table
2879
2880 sw.flow_tbl = ft
2881 if not sw.flow_tbl_verify():
2882 result = False
2883
2884 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002885 fq_logger.info("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002886
2887
Howard Persh07d99e62012-04-09 15:26:57 -07002888# FLOW DELETE 4
2889#
2890# OVERVIEW
2891# Flow removed messages
2892#
2893# PURPOSE
2894# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2895# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2896#
2897# PARAMETERS
2898# None
2899#
2900# PROCESS
2901# 1. Delete all flows from switch
2902# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2903# 3. Send strict flow delete of flow to switch
2904# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2905# 5. Verify flow table in switch
2906# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2907# removed in step 3 above, are returned in step 5 above, and that
2908# asynch message was received; else test FAILED
2909
2910
rootf6af1672012-04-06 09:46:29 -07002911class Flow_Del_4(basic.SimpleProtocol):
2912 """
2913 Test FLOW_DEL_4 from draft top-half test plan
2914
2915 INPUTS
2916 None
2917 """
2918
2919 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002920 fq_logger.info("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002921
2922 # Clear all flows from switch
2923
Howard Persh5f3c83f2012-04-13 09:57:10 -07002924 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002925 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002926 self.assertEqual(rc, 0, "Failed to delete all flows")
2927
2928 # Get switch capabilites
2929
rootf6af1672012-04-06 09:46:29 -07002930 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002931 self.assertTrue(sw.connect(self.controller), \
2932 "Failed to connect to switch" \
2933 )
rootf6af1672012-04-06 09:46:29 -07002934
2935 # Dream up some flow information, i.e. space to chose from for
2936 # random flow parameter generation
2937
2938 fi = Flow_Info()
2939 fi.rand(10)
2940
2941 # Dream up a flow config
2942
2943 fc = Flow_Cfg()
2944 fc.rand(fi, \
2945 sw.tbl_stats.stats[0].wildcards, \
2946 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002947 sw.valid_ports, \
2948 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002949 )
2950 fc = fc.canonical()
2951
2952 # Send it to the switch. with "notify on removed"
2953
Howard Persh5f3c83f2012-04-13 09:57:10 -07002954 fq_logger.info("Sending flow add to switch:")
2955 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002956 ft = Flow_Tbl()
2957 fc.send_rem = True
2958 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2959 ft.insert(fc)
2960
2961 # Dream up some different actions, with the same flow key
2962
2963 fc2 = copy.deepcopy(fc)
2964 while True:
2965 fc2.rand_mod(fi, \
2966 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002967 sw.valid_ports, \
2968 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002969 )
2970 if fc2 != fc:
2971 break
2972
2973 # Delete strictly
2974
Howard Persh5f3c83f2012-04-13 09:57:10 -07002975 fq_logger.info("Sending strict flow del to switch:")
2976 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002977 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2978 ft.delete(fc)
2979
2980 # Do barrier, to make sure all flows are in
2981
2982 self.assertTrue(sw.barrier(), "Barrier failed")
2983
2984 result = True
2985
2986 # Check for expected "removed" message
2987
Howard Persh3340d452012-04-06 16:45:21 -07002988 if not sw.errors_verify(0):
2989 result = False
2990
2991 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07002992 result = False
2993
2994 # Verify flow table
2995
2996 sw.flow_tbl = ft
2997 if not sw.flow_tbl_verify():
2998 result = False
2999
3000 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07003001 fq_logger.info("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07003002