blob: b205101cce779706265c62323438edb6b937e92d [file] [log] [blame]
Howard Pershc7963582012-03-29 10:02:59 -07001"""
2Flow query test case.
3
Howard Persh3340d452012-04-06 16:45:21 -07004Attempts to fill switch to capacity with randomized flows, and ensure that
5they all are read back correctly.
Howard Pershc7963582012-03-29 10:02:59 -07006"""
Howard Persh07d99e62012-04-09 15:26:57 -07007
8# COMMON TEST PARAMETERS
9#
10# Name: wildcards
11# Type: number
12# Description:
13# Overrides bitmap of supported wildcards reported by switch
14# Default: none
15#
Howard Pershc1199d52012-04-11 14:21:32 -070016# Name: wildcards_force
17# Type: number
18# Description:
19# Bitmap of wildcards to always be set
20# Default: none
21#
Howard Persh07d99e62012-04-09 15:26:57 -070022# Name: actions
23# Type: number
24# Description:
25# Overrides bitmap of supported actions reported by switch
26# Default: none
27#
Howard Pershc1199d52012-04-11 14:21:32 -070028# Name: actions_force
29# Type: number
30# Description:
31# Bitmap of actions to always be used
32# Default: none
33#
34# Name: ports
35# Type: list of OF port numbers
36# Description:
37# Override list of OF port numbers reported by switch
38# Default: none
39#
Howard Persh8d21c1f2012-04-20 15:57:29 -070040# Name: queues
41# Type: list of OF (port-number, queue-id) pairs
42# Description:
43# Override list of OF (port-number, queue-id) pairs returned by switch
44# Default: none
45#
Howard Pershb10a47a2012-08-21 13:54:47 -070046# Name: vlans
47# Type: list of VLAN ids
48# Description:
49# Override VLAN ids used in tests to given list
50# Default: []
51#
Howard Persh07d99e62012-04-09 15:26:57 -070052# Name: conservative_ordered_actions
53# Type: boolean (True or False)
54# Description:
55# Compare flow actions lists as unordered
56# Default: True
57
58
Howard Persh680b92a2012-03-31 13:34:35 -070059import math
Howard Pershc7963582012-03-29 10:02:59 -070060
61import logging
62
63import unittest
64import random
Howard Persh9cab4822012-09-11 17:08:40 -070065import time
Howard Pershc7963582012-03-29 10:02:59 -070066
Rich Lane477f4812012-10-04 22:49:00 -070067from oftest import config
Howard Pershc7963582012-03-29 10:02:59 -070068import oftest.controller as controller
69import oftest.cstruct as ofp
70import oftest.message as message
71import oftest.dataplane as dataplane
72import oftest.action as action
73import oftest.action_list as action_list
74import oftest.parse as parse
75import pktact
Rich Laneb90a1c42012-10-05 09:16:05 -070076import oftest.base_tests as base_tests
Howard Pershc7963582012-03-29 10:02:59 -070077
Rich Laneda3b5ad2012-10-03 09:05:32 -070078from oftest.testutils import *
Howard Pershc7963582012-03-29 10:02:59 -070079from time import sleep
80
Howard Pershc7963582012-03-29 10:02:59 -070081
rootf6af1672012-04-06 09:46:29 -070082def flip_coin():
83 return random.randint(1, 100) <= 50
84
85
Howard Pershc7963582012-03-29 10:02:59 -070086def shuffle(list):
87 n = len(list)
88 lim = n * n
89 i = 0
90 while i < lim:
91 a = random.randint(0, n - 1)
92 b = random.randint(0, n - 1)
93 temp = list[a]
94 list[a] = list[b]
95 list[b] = temp
96 i = i + 1
97 return list
98
99
Howard Persh680b92a2012-03-31 13:34:35 -0700100def rand_pick(list):
101 return list[random.randint(0, len(list) - 1)]
Howard Pershc7963582012-03-29 10:02:59 -0700102
Howard Persh680b92a2012-03-31 13:34:35 -0700103def rand_dl_addr():
104 return [random.randint(0, 255) & ~1,
105 random.randint(0, 255),
106 random.randint(0, 255),
107 random.randint(0, 255),
108 random.randint(0, 255),
109 random.randint(0, 255)
110 ]
Howard Pershc7963582012-03-29 10:02:59 -0700111
112def rand_nw_addr():
113 return random.randint(0, (1 << 32) - 1)
114
115
rootf6af1672012-04-06 09:46:29 -0700116class Flow_Info:
Howard Persh680b92a2012-03-31 13:34:35 -0700117 # Members:
118 # priorities - list of flow priorities
119 # dl_addrs - list of MAC addresses
120 # vlans - list of VLAN ids
121 # ethertypes - list of Ethertypes
122 # ip_addrs - list of IP addresses
123 # ip_tos - list of IP TOS values
124 # ip_protos - list of IP protocols
125 # l4_ports - list of L4 ports
126
127 def __init__(self):
128 priorities = []
129 dl_addrs = []
130 vlans = []
131 ethertypes = []
132 ip_addrs = []
133 ip_tos = []
134 ip_protos = []
135 l4_ports = []
136
137 def rand(self, n):
138 self.priorities = []
139 i = 0
140 while i < n:
141 self.priorities.append(random.randint(1, 65534))
142 i = i + 1
143
144 self.dl_addrs = []
145 i = 0
146 while i < n:
147 self.dl_addrs.append(rand_dl_addr())
148 i = i + 1
149
Rich Lane2014f9b2012-10-05 15:29:40 -0700150 if test_param_get("vlans", []) != []:
151 self.vlans = test_param_get("vlans", [])
Howard Pershb10a47a2012-08-21 13:54:47 -0700152
Rich Lane9a003812012-10-04 17:17:59 -0700153 logging.info("Overriding VLAN ids to:")
154 logging.info(self.vlans)
Howard Pershb10a47a2012-08-21 13:54:47 -0700155 else:
156 self.vlans = []
157 i = 0
158 while i < n:
159 self.vlans.append(random.randint(1, 4094))
160 i = i + 1
Howard Persh680b92a2012-03-31 13:34:35 -0700161
rootf6af1672012-04-06 09:46:29 -0700162 self.ethertypes = [0x0800, 0x0806]
Howard Persh680b92a2012-03-31 13:34:35 -0700163 i = 0
164 while i < n:
165 self.ethertypes.append(random.randint(0, (1 << 16) - 1))
166 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700167 self.ethertypes = shuffle(self.ethertypes)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700168
169 self.ip_addrs = []
170 i = 0
171 while i < n:
172 self.ip_addrs.append(rand_nw_addr())
173 i = i + 1
174
175 self.ip_tos = []
176 i = 0
177 while i < n:
178 self.ip_tos.append(random.randint(0, (1 << 8) - 1) & ~3)
179 i = i + 1
180
rootf6af1672012-04-06 09:46:29 -0700181 self.ip_protos = [1, 6, 17]
Howard Persh680b92a2012-03-31 13:34:35 -0700182 i = 0
183 while i < n:
184 self.ip_protos.append(random.randint(0, (1 << 8) - 1))
185 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700186 self.ip_protos = shuffle(self.ip_protos)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700187
188 self.l4_ports = []
189 i = 0
190 while i < n:
191 self.l4_ports.append(random.randint(0, (1 << 16) - 1))
192 i = i + 1
193
194 def rand_priority(self):
195 return rand_pick(self.priorities)
196
197 def rand_dl_addr(self):
198 return rand_pick(self.dl_addrs)
199
200 def rand_vlan(self):
201 return rand_pick(self.vlans)
202
203 def rand_ethertype(self):
204 return rand_pick(self.ethertypes)
205
206 def rand_ip_addr(self):
207 return rand_pick(self.ip_addrs)
208
209 def rand_ip_tos(self):
210 return rand_pick(self.ip_tos)
211
212 def rand_ip_proto(self):
213 return rand_pick(self.ip_protos)
214
215 def rand_l4_port(self):
216 return rand_pick(self.l4_ports)
217
218
Howard Pershc7963582012-03-29 10:02:59 -0700219# TBD - These don't belong here
220
Howard Persh680b92a2012-03-31 13:34:35 -0700221all_wildcards_list = [ofp.OFPFW_IN_PORT,
Howard Persh680b92a2012-03-31 13:34:35 -0700222 ofp.OFPFW_DL_DST,
rootf6af1672012-04-06 09:46:29 -0700223 ofp.OFPFW_DL_SRC,
224 ofp.OFPFW_DL_VLAN,
225 ofp.OFPFW_DL_VLAN_PCP,
Howard Persh680b92a2012-03-31 13:34:35 -0700226 ofp.OFPFW_DL_TYPE,
rootf6af1672012-04-06 09:46:29 -0700227 ofp.OFPFW_NW_TOS,
Howard Persh680b92a2012-03-31 13:34:35 -0700228 ofp.OFPFW_NW_PROTO,
Howard Persh680b92a2012-03-31 13:34:35 -0700229 ofp.OFPFW_NW_SRC_MASK,
230 ofp.OFPFW_NW_DST_MASK,
rootf6af1672012-04-06 09:46:29 -0700231 ofp.OFPFW_TP_SRC,
232 ofp.OFPFW_TP_DST
Howard Persh680b92a2012-03-31 13:34:35 -0700233 ]
Howard Pershc7963582012-03-29 10:02:59 -0700234
Howard Persh3340d452012-04-06 16:45:21 -0700235# TBD - Need this because there are duplicates in ofp.ofp_flow_wildcards_map
236# -- FIX
rootf6af1672012-04-06 09:46:29 -0700237all_wildcard_names = {
238 1 : 'OFPFW_IN_PORT',
239 2 : 'OFPFW_DL_VLAN',
240 4 : 'OFPFW_DL_SRC',
241 8 : 'OFPFW_DL_DST',
242 16 : 'OFPFW_DL_TYPE',
243 32 : 'OFPFW_NW_PROTO',
244 64 : 'OFPFW_TP_SRC',
245 128 : 'OFPFW_TP_DST',
246 1048576 : 'OFPFW_DL_VLAN_PCP',
247 2097152 : 'OFPFW_NW_TOS'
248}
249
rootf6af1672012-04-06 09:46:29 -0700250def wildcard_set(x, w, val):
251 result = x
252 if w == ofp.OFPFW_NW_SRC_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700253 result = (result & ~ofp.OFPFW_NW_SRC_MASK) \
254 | (val << ofp.OFPFW_NW_SRC_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700255 elif w == ofp.OFPFW_NW_DST_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700256 result = (result & ~ofp.OFPFW_NW_DST_MASK) \
257 | (val << ofp.OFPFW_NW_DST_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700258 elif val == 0:
259 result = result & ~w
260 else:
261 result = result | w
262 return result
263
264def wildcard_get(x, w):
265 if w == ofp.OFPFW_NW_SRC_MASK:
266 return (x & ofp.OFPFW_NW_SRC_MASK) >> ofp.OFPFW_NW_SRC_SHIFT
267 if w == ofp.OFPFW_NW_DST_MASK:
268 return (x & ofp.OFPFW_NW_DST_MASK) >> ofp.OFPFW_NW_DST_SHIFT
269 return 1 if (x & w) != 0 else 0
270
Howard Persh8d21c1f2012-04-20 15:57:29 -0700271def wildcards_to_str(wildcards):
272 result = "{"
273 sep = ""
274 for w in all_wildcards_list:
275 if (wildcards & w) == 0:
276 continue
277 if w == ofp.OFPFW_NW_SRC_MASK:
278 n = wildcard_get(wildcards, w)
279 if n > 0:
280 result = result + sep + ("OFPFW_NW_SRC(%d)" % (n))
281 elif w == ofp.OFPFW_NW_DST_MASK:
282 n = wildcard_get(wildcards, w)
283 if n > 0:
284 result = result + sep + ("OFPFW_NW_DST(%d)" % (n))
285 else:
286 result = result + sep + all_wildcard_names[w]
287 sep = ", "
288 result = result +"}"
289 return result
Howard Pershc7963582012-03-29 10:02:59 -0700290
Howard Persh680b92a2012-03-31 13:34:35 -0700291all_actions_list = [ofp.OFPAT_OUTPUT,
292 ofp.OFPAT_SET_VLAN_VID,
293 ofp.OFPAT_SET_VLAN_PCP,
294 ofp.OFPAT_STRIP_VLAN,
295 ofp.OFPAT_SET_DL_SRC,
296 ofp.OFPAT_SET_DL_DST,
297 ofp.OFPAT_SET_NW_SRC,
298 ofp.OFPAT_SET_NW_DST,
299 ofp.OFPAT_SET_NW_TOS,
300 ofp.OFPAT_SET_TP_SRC,
301 ofp.OFPAT_SET_TP_DST,
302 ofp.OFPAT_ENQUEUE
303 ]
304
Howard Persh8d21c1f2012-04-20 15:57:29 -0700305def actions_bmap_to_str(bm):
306 result = "{"
307 sep = ""
308 for a in all_actions_list:
309 if ((1 << a) & bm) != 0:
310 result = result + sep + ofp.ofp_action_type_map[a]
311 sep = ", "
312 result = result + "}"
313 return result
314
Howard Persh680b92a2012-03-31 13:34:35 -0700315def dl_addr_to_str(a):
316 return "%x:%x:%x:%x:%x:%x" % tuple(a)
317
318def ip_addr_to_str(a, n):
rootf6af1672012-04-06 09:46:29 -0700319 if n is not None:
320 a = a & ~((1 << (32 - n)) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700321 result = "%d.%d.%d.%d" % (a >> 24, \
322 (a >> 16) & 0xff, \
323 (a >> 8) & 0xff, \
324 a & 0xff \
325 )
326 if n is not None:
327 result = result + ("/%d" % (n))
328 return result
329
Howard Pershc7963582012-03-29 10:02:59 -0700330
rootf6af1672012-04-06 09:46:29 -0700331class Flow_Cfg:
Howard Pershc7963582012-03-29 10:02:59 -0700332 # Members:
333 # - match
334 # - idle_timeout
335 # - hard_timeout
336 # - priority
337 # - action_list
338
339 def __init__(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700340 self.priority = 0
Howard Pershc7963582012-03-29 10:02:59 -0700341 self.match = parse.ofp_match()
342 self.match.wildcards = ofp.OFPFW_ALL
343 self.idle_timeout = 0
344 self.hard_timeout = 0
Howard Pershc7963582012-03-29 10:02:59 -0700345 self.actions = action_list.action_list()
346
rootf6af1672012-04-06 09:46:29 -0700347 # {pri, match} is considered a flow key
348 def key_equal(self, x):
Howard Persh680b92a2012-03-31 13:34:35 -0700349 if self.priority != x.priority:
350 return False
351 # TBD - Should this logic be moved to ofp_match.__eq__()?
352 if self.match.wildcards != x.match.wildcards:
353 return False
rootf6af1672012-04-06 09:46:29 -0700354 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700355 and self.match.in_port != x.match.in_port:
356 return False
rootf6af1672012-04-06 09:46:29 -0700357 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700358 and self.match.dl_dst != x.match.dl_dst:
359 return False
rootf6af1672012-04-06 09:46:29 -0700360 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0 \
361 and self.match.dl_src != x.match.dl_src:
362 return False
363 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700364 and self.match.dl_vlan != x.match.dl_vlan:
365 return False
rootf6af1672012-04-06 09:46:29 -0700366 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700367 and self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
368 return False
rootf6af1672012-04-06 09:46:29 -0700369 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700370 and self.match.dl_type != x.match.dl_type:
371 return False
rootf6af1672012-04-06 09:46:29 -0700372 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700373 and self.match.nw_tos != x.match.nw_tos:
374 return False
rootf6af1672012-04-06 09:46:29 -0700375 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700376 and self.match.nw_proto != x.match.nw_proto:
377 return False
rootf6af1672012-04-06 09:46:29 -0700378 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
379 if n < 32:
380 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700381 if (self.match.nw_src & m) != (x.match.nw_src & m):
382 return False
rootf6af1672012-04-06 09:46:29 -0700383 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
384 if n < 32:
385 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700386 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
387 return False
rootf6af1672012-04-06 09:46:29 -0700388 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0 \
389 and self.match.tp_src != x.match.tp_src:
Howard Persh680b92a2012-03-31 13:34:35 -0700390 return False
rootf6af1672012-04-06 09:46:29 -0700391 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0 \
392 and self.match.tp_dst != x.match.tp_dst:
393 return False
394 return True
395
Howard Persh5f3c83f2012-04-13 09:57:10 -0700396 def actions_equal(self, x):
Rich Lane2014f9b2012-10-05 15:29:40 -0700397 if test_param_get("conservative_ordered_actions", True):
Howard Persh5f3c83f2012-04-13 09:57:10 -0700398 # Compare actions lists as unordered
399
root2843d2b2012-04-06 10:27:46 -0700400 aa = copy.deepcopy(x.actions.actions)
401 for a in self.actions.actions:
402 i = 0
403 while i < len(aa):
404 if a == aa[i]:
405 break
406 i = i + 1
407 if i < len(aa):
408 aa.pop(i)
409 else:
410 return False
411 return aa == []
412 else:
413 return self.actions == x.actions
Howard Persh5f3c83f2012-04-13 09:57:10 -0700414
415 def non_key_equal(self, x):
416 if self.cookie != x.cookie:
417 return False
418 if self.idle_timeout != x.idle_timeout:
419 return False
420 if self.hard_timeout != x.hard_timeout:
421 return False
422 return self.actions_equal(x)
rootf6af1672012-04-06 09:46:29 -0700423
root2843d2b2012-04-06 10:27:46 -0700424 def key_str(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700425 result = "priority=%d" % self.priority
426 # TBD - Would be nice if ofp_match.show() was better behaved
427 # (no newlines), and more intuitive (things in hex where approprate), etc.
Howard Persh8d21c1f2012-04-20 15:57:29 -0700428 result = result + (", wildcards=0x%x=%s" \
429 % (self.match.wildcards, \
430 wildcards_to_str(self.match.wildcards) \
431 )
432 )
rootf6af1672012-04-06 09:46:29 -0700433 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700434 result = result + (", in_port=%d" % (self.match.in_port))
rootf6af1672012-04-06 09:46:29 -0700435 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700436 result = result + (", dl_dst=%s" \
437 % (dl_addr_to_str(self.match.dl_dst)) \
438 )
rootf6af1672012-04-06 09:46:29 -0700439 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700440 result = result + (", dl_src=%s" \
441 % (dl_addr_to_str(self.match.dl_src)) \
442 )
rootf6af1672012-04-06 09:46:29 -0700443 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700444 result = result + (", dl_vlan=%d" % (self.match.dl_vlan))
rootf6af1672012-04-06 09:46:29 -0700445 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700446 result = result + (", dl_vlan_pcp=%d" % (self.match.dl_vlan_pcp))
rootf6af1672012-04-06 09:46:29 -0700447 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700448 result = result + (", dl_type=0x%x" % (self.match.dl_type))
rootf6af1672012-04-06 09:46:29 -0700449 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700450 result = result + (", nw_tos=0x%x" % (self.match.nw_tos))
rootf6af1672012-04-06 09:46:29 -0700451 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700452 result = result + (", nw_proto=%d" % (self.match.nw_proto))
rootf6af1672012-04-06 09:46:29 -0700453 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700454 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700455 result = result + (", nw_src=%s" % \
456 (ip_addr_to_str(self.match.nw_src, 32 - n)) \
457 )
rootf6af1672012-04-06 09:46:29 -0700458 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700459 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700460 result = result + (", nw_dst=%s" % \
461 (ip_addr_to_str(self.match.nw_dst, 32 - n)) \
462 )
rootf6af1672012-04-06 09:46:29 -0700463 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700464 result = result + (", tp_src=%d" % self.match.tp_src)
rootf6af1672012-04-06 09:46:29 -0700465 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700466 result = result + (", tp_dst=%d" % self.match.tp_dst)
rootf6af1672012-04-06 09:46:29 -0700467 return result
468
469 def __eq__(self, x):
470 return (self.key_equal(x) and self.non_key_equal(x))
471
472 def __str__(self):
root2843d2b2012-04-06 10:27:46 -0700473 result = self.key_str()
474 result = result + (", cookie=%d" % self.cookie)
Howard Persh680b92a2012-03-31 13:34:35 -0700475 result = result + (", idle_timeout=%d" % self.idle_timeout)
476 result = result + (", hard_timeout=%d" % self.hard_timeout)
Howard Persh680b92a2012-03-31 13:34:35 -0700477 for a in self.actions.actions:
478 result = result + (", action=%s" % ofp.ofp_action_type_map[a.type])
479 if a.type == ofp.OFPAT_OUTPUT:
480 result = result + ("(%d)" % (a.port))
481 elif a.type == ofp.OFPAT_SET_VLAN_VID:
482 result = result + ("(%d)" % (a.vlan_vid))
483 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
484 result = result + ("(%d)" % (a.vlan_pcp))
485 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
486 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
487 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
488 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
489 elif a.type == ofp.OFPAT_SET_NW_TOS:
490 result = result + ("(0x%x)" % (a.nw_tos))
491 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
492 result = result + ("(%d)" % (a.tp_port))
493 elif a.type == ofp.OFPAT_ENQUEUE:
494 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
495 return result
Howard Pershc7963582012-03-29 10:02:59 -0700496
Howard Persh8d21c1f2012-04-20 15:57:29 -0700497 def rand_actions_ordered(self, fi, valid_actions, valid_ports, valid_queues):
Howard Persh3340d452012-04-06 16:45:21 -0700498 # Action lists are ordered, so pick an ordered random subset of
499 # supported actions
Howard Pershc1199d52012-04-11 14:21:32 -0700500
Rich Lane2014f9b2012-10-05 15:29:40 -0700501 actions_force = test_param_get("actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700502 if actions_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700503 logging.info("Forced actions:")
504 logging.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700505
Dan Talayco910a8282012-04-07 00:05:20 -0700506 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh3340d452012-04-06 16:45:21 -0700507 supported_actions = []
508 for a in all_actions_list:
509 if ((1 << a) & valid_actions) != 0:
510 supported_actions.append(a)
511
Howard Pershc1199d52012-04-11 14:21:32 -0700512 actions \
513 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
514
515 for a in all_actions_list:
516 if ((1 << a) & actions_force) != 0:
517 actions.append(a)
518
519 actions = shuffle(actions)
Howard Persh3340d452012-04-06 16:45:21 -0700520
Howard Persh6a3698d2012-08-21 14:26:39 -0700521 set_vlanf = False
522 strip_vlanf = False
Howard Persh3340d452012-04-06 16:45:21 -0700523 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700524 for a in actions:
Dan Talayco910a8282012-04-07 00:05:20 -0700525 act = None
Howard Persh3340d452012-04-06 16:45:21 -0700526 if a == ofp.OFPAT_OUTPUT:
527 pass # OUTPUT actions must come last
528 elif a == ofp.OFPAT_SET_VLAN_VID:
Howard Persh6a3698d2012-08-21 14:26:39 -0700529 if not strip_vlanf:
530 act = action.action_set_vlan_vid()
531 act.vlan_vid = fi.rand_vlan()
532 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700533 elif a == ofp.OFPAT_SET_VLAN_PCP:
Howard Persh6a3698d2012-08-21 14:26:39 -0700534 if not strip_vlanf:
535 act = action.action_set_vlan_pcp()
536 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
537 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700538 elif a == ofp.OFPAT_STRIP_VLAN:
Howard Persh6a3698d2012-08-21 14:26:39 -0700539 if not set_vlanf:
540 act = action.action_strip_vlan()
541 strip_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700542 elif a == ofp.OFPAT_SET_DL_SRC:
543 act = action.action_set_dl_src()
544 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700545 elif a == ofp.OFPAT_SET_DL_DST:
546 act = action.action_set_dl_dst()
547 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700548 elif a == ofp.OFPAT_SET_NW_SRC:
549 act = action.action_set_nw_src()
550 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700551 elif a == ofp.OFPAT_SET_NW_DST:
552 act = action.action_set_nw_dst()
553 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700554 elif a == ofp.OFPAT_SET_NW_TOS:
555 act = action.action_set_nw_tos()
556 act.nw_tos = fi.rand_ip_tos()
Howard Persh3340d452012-04-06 16:45:21 -0700557 elif a == ofp.OFPAT_SET_TP_SRC:
558 act = action.action_set_tp_src()
559 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700560 elif a == ofp.OFPAT_SET_TP_DST:
561 act = action.action_set_tp_dst()
562 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700563 elif a == ofp.OFPAT_ENQUEUE:
564 pass # Enqueue actions must come last
Dan Talayco910a8282012-04-07 00:05:20 -0700565 if act:
Dan Talayco910a8282012-04-07 00:05:20 -0700566 self.actions.add(act)
567
Howard Persh3340d452012-04-06 16:45:21 -0700568 p = random.randint(1, 100)
Howard Pershc1199d52012-04-11 14:21:32 -0700569 if (((1 << ofp.OFPAT_ENQUEUE) & actions_force) != 0 or p <= 33) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700570 and len(valid_queues) > 0 \
571 and ofp.OFPAT_ENQUEUE in actions:
Howard Pershc1199d52012-04-11 14:21:32 -0700572 # In not forecd, one third of the time, include ENQUEUE actions
573 # at end of list
Howard Persh3340d452012-04-06 16:45:21 -0700574 # At most 1 ENQUEUE action
575 act = action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700576 (act.port, act.queue_id) = rand_pick(valid_queues)
Howard Persh3340d452012-04-06 16:45:21 -0700577 self.actions.add(act)
Howard Pershc1199d52012-04-11 14:21:32 -0700578 if (((1 << ofp.OFPAT_OUTPUT) & actions_force) != 0 \
579 or (p > 33 and p <= 66) \
580 ) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700581 and len(valid_ports) > 0 \
Howard Pershc1199d52012-04-11 14:21:32 -0700582 and ofp.OFPAT_OUTPUT in actions:
Howard Persh3340d452012-04-06 16:45:21 -0700583 # One third of the time, include OUTPUT actions at end of list
584 port_idxs = shuffle(range(len(valid_ports)))
585 # Only 1 output action allowed if IN_PORT wildcarded
586 n = 1 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) != 0 \
587 else random.randint(1, len(valid_ports))
588 port_idxs = port_idxs[0 : n]
589 for pi in port_idxs:
590 act = action.action_output()
591 act.port = valid_ports[pi]
Howard Persh3340d452012-04-06 16:45:21 -0700592 if act.port != ofp.OFPP_IN_PORT \
593 or wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
594 # OUTPUT(IN_PORT) only valid if OFPFW_IN_PORT not wildcarded
595 self.actions.add(act)
596 else:
597 # One third of the time, include neither
598 pass
599
600
601 # Randomize flow data for flow modifies (i.e. cookie and actions)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700602 def rand_mod(self, fi, valid_actions, valid_ports, valid_queues):
rootf6af1672012-04-06 09:46:29 -0700603 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700604
Dan Talayco910a8282012-04-07 00:05:20 -0700605 # By default, test with conservative ordering conventions
606 # This should probably be indicated in a profile
Rich Lane2014f9b2012-10-05 15:29:40 -0700607 if test_param_get("conservative_ordered_actions", True):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700608 self.rand_actions_ordered(fi, valid_actions, valid_ports, valid_queues)
Howard Persh3340d452012-04-06 16:45:21 -0700609 return self
610
Rich Lane2014f9b2012-10-05 15:29:40 -0700611 actions_force = test_param_get("actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700612 if actions_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700613 logging.info("Forced actions:")
614 logging.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700615
616 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh680b92a2012-03-31 13:34:35 -0700617 supported_actions = []
618 for a in all_actions_list:
619 if ((1 << a) & valid_actions) != 0:
620 supported_actions.append(a)
621
Howard Pershc1199d52012-04-11 14:21:32 -0700622 actions \
623 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
624
625 for a in all_actions_list:
626 if ((1 << a) & actions_force) != 0:
627 actions.append(a)
628
629 actions = shuffle(actions)
Howard Pershc7963582012-03-29 10:02:59 -0700630
631 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700632 for a in actions:
Howard Pershc7963582012-03-29 10:02:59 -0700633 if a == ofp.OFPAT_OUTPUT:
634 # TBD - Output actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700635 if len(valid_ports) == 0:
636 continue
Howard Pershc7963582012-03-29 10:02:59 -0700637 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700638 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700639 for pi in port_idxs:
640 act = action.action_output()
Howard Persh680b92a2012-03-31 13:34:35 -0700641 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700642 self.actions.add(act)
643 elif a == ofp.OFPAT_SET_VLAN_VID:
644 act = action.action_set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700645 act.vlan_vid = fi.rand_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700646 self.actions.add(act)
647 elif a == ofp.OFPAT_SET_VLAN_PCP:
Dan Talayco910a8282012-04-07 00:05:20 -0700648 act = action.action_set_vlan_pcp()
649 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700650 elif a == ofp.OFPAT_STRIP_VLAN:
651 act = action.action_strip_vlan()
652 self.actions.add(act)
653 elif a == ofp.OFPAT_SET_DL_SRC:
654 act = action.action_set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700655 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700656 self.actions.add(act)
657 elif a == ofp.OFPAT_SET_DL_DST:
658 act = action.action_set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700659 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700660 self.actions.add(act)
661 elif a == ofp.OFPAT_SET_NW_SRC:
662 act = action.action_set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700663 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700664 self.actions.add(act)
665 elif a == ofp.OFPAT_SET_NW_DST:
666 act = action.action_set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700667 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700668 self.actions.add(act)
669 elif a == ofp.OFPAT_SET_NW_TOS:
670 act = action.action_set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700671 act.nw_tos = fi.rand_ip_tos()
Howard Pershc7963582012-03-29 10:02:59 -0700672 self.actions.add(act)
673 elif a == ofp.OFPAT_SET_TP_SRC:
674 act = action.action_set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700675 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700676 self.actions.add(act)
677 elif a == ofp.OFPAT_SET_TP_DST:
678 act = action.action_set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700679 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700680 self.actions.add(act)
681 elif a == ofp.OFPAT_ENQUEUE:
682 # TBD - Enqueue actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700683 if len(valid_queues) == 0:
684 continue
685 qidxs = shuffle(range(len(valid_queues)))
686 qidxs = qidxs[0 : random.randint(1, len(valid_queues))]
687 for qi in qidxs:
Howard Pershc7963582012-03-29 10:02:59 -0700688 act = action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700689 (act.port, act.queue_id) = valid_queues[qi]
Howard Pershc7963582012-03-29 10:02:59 -0700690 self.actions.add(act)
691
692 return self
693
rootf6af1672012-04-06 09:46:29 -0700694 # Randomize flow cfg
Ed Swierk99a74de2012-08-22 06:40:54 -0700695 def rand(self, fi, wildcards_force, valid_wildcards, valid_actions, valid_ports,
696 valid_queues):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700697 if wildcards_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700698 logging.info("Wildcards forced:")
699 logging.info(wildcards_to_str(wildcards_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700700
rootf6af1672012-04-06 09:46:29 -0700701 # Start with no wildcards, i.e. everything specified
702 self.match.wildcards = 0
Howard Pershc1199d52012-04-11 14:21:32 -0700703
704 if wildcards_force != 0:
705 exact = False
706 else:
707 # Make approx. 5% of flows exact
708 exact = (random.randint(1, 100) <= 5)
rootf6af1672012-04-06 09:46:29 -0700709
710 # For each qualifier Q,
711 # if (wildcarding is not supported for Q,
712 # or an exact flow is specified
713 # or a coin toss comes up heads),
714 # specify Q
715 # else
716 # wildcard Q
717
Howard Pershc1199d52012-04-11 14:21:32 -0700718 if wildcard_get(wildcards_force, ofp.OFPFW_IN_PORT) == 0 \
719 and (wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
720 or exact \
721 or flip_coin() \
722 ):
rootf6af1672012-04-06 09:46:29 -0700723 self.match.in_port = rand_pick(valid_ports)
724 else:
Howard Persh3340d452012-04-06 16:45:21 -0700725 self.match.wildcards = wildcard_set(self.match.wildcards, \
726 ofp.OFPFW_IN_PORT, \
727 1 \
728 )
rootf6af1672012-04-06 09:46:29 -0700729
Howard Pershc1199d52012-04-11 14:21:32 -0700730 if wildcard_get(wildcards_force, ofp.OFPFW_DL_DST) == 0 \
731 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
732 or exact \
733 or flip_coin() \
734 ):
rootf6af1672012-04-06 09:46:29 -0700735 self.match.dl_dst = fi.rand_dl_addr()
736 else:
Howard Persh3340d452012-04-06 16:45:21 -0700737 self.match.wildcards = wildcard_set(self.match.wildcards, \
738 ofp.OFPFW_DL_DST, \
739 1 \
740 )
rootf6af1672012-04-06 09:46:29 -0700741
Howard Pershc1199d52012-04-11 14:21:32 -0700742 if wildcard_get(wildcards_force, ofp.OFPFW_DL_SRC) == 0 \
743 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
744 or exact \
745 or flip_coin() \
746 ):
rootf6af1672012-04-06 09:46:29 -0700747 self.match.dl_src = fi.rand_dl_addr()
748 else:
Howard Persh3340d452012-04-06 16:45:21 -0700749 self.match.wildcards = wildcard_set(self.match.wildcards, \
750 ofp.OFPFW_DL_SRC, \
751 1 \
752 )
rootf6af1672012-04-06 09:46:29 -0700753
Howard Pershc1199d52012-04-11 14:21:32 -0700754 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN) == 0 \
755 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
756 or exact \
757 or flip_coin() \
758 ):
rootf6af1672012-04-06 09:46:29 -0700759 self.match.dl_vlan = fi.rand_vlan()
760 else:
Howard Persh3340d452012-04-06 16:45:21 -0700761 self.match.wildcards = wildcard_set(self.match.wildcards, \
762 ofp.OFPFW_DL_VLAN, \
763 1 \
764 )
rootf6af1672012-04-06 09:46:29 -0700765
Howard Pershc1199d52012-04-11 14:21:32 -0700766 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN_PCP) == 0 \
767 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
768 or exact \
769 or flip_coin() \
770 ):
771 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
772 else:
773 self.match.wildcards = wildcard_set(self.match.wildcards, \
774 ofp.OFPFW_DL_VLAN_PCP, \
775 1 \
776 )
777
778 if wildcard_get(wildcards_force, ofp.OFPFW_DL_TYPE) == 0 \
779 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
780 or exact \
781 or flip_coin() \
782 ):
rootf6af1672012-04-06 09:46:29 -0700783 self.match.dl_type = fi.rand_ethertype()
784 else:
Howard Persh3340d452012-04-06 16:45:21 -0700785 self.match.wildcards = wildcard_set(self.match.wildcards, \
786 ofp.OFPFW_DL_TYPE, \
787 1 \
788 )
rootf6af1672012-04-06 09:46:29 -0700789
Howard Pershc1199d52012-04-11 14:21:32 -0700790 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_SRC_MASK)
791 if n == 0:
792 if exact or flip_coin():
793 n = 0
794 else:
795 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
796 if n > 32:
797 n = 32
798 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700799 self.match.wildcards = wildcard_set(self.match.wildcards, \
800 ofp.OFPFW_NW_SRC_MASK, \
801 n \
802 )
rootf6af1672012-04-06 09:46:29 -0700803 if n < 32:
804 self.match.nw_src = fi.rand_ip_addr() & ~((1 << n) - 1)
805 # Specifying any IP address match other than all bits
806 # don't care requires that Ethertype is one of {IP, ARP}
807 if flip_coin():
808 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700809 self.match.wildcards = wildcard_set(self.match.wildcards, \
810 ofp.OFPFW_DL_TYPE, \
811 0 \
812 )
rootf6af1672012-04-06 09:46:29 -0700813
Howard Pershc1199d52012-04-11 14:21:32 -0700814 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_DST_MASK)
815 if n == 0:
816 if exact or flip_coin():
817 n = 0
818 else:
819 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
820 if n > 32:
821 n = 32
822 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700823 self.match.wildcards = wildcard_set(self.match.wildcards, \
824 ofp.OFPFW_NW_DST_MASK, \
825 n \
826 )
rootf6af1672012-04-06 09:46:29 -0700827 if n < 32:
828 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
829 # Specifying any IP address match other than all bits
830 # don't care requires that Ethertype is one of {IP, ARP}
831 if flip_coin():
832 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700833 self.match.wildcards = wildcard_set(self.match.wildcards, \
834 ofp.OFPFW_DL_TYPE, \
835 0 \
836 )
rootf6af1672012-04-06 09:46:29 -0700837
Howard Pershc1199d52012-04-11 14:21:32 -0700838 if wildcard_get(wildcards_force, ofp.OFPFW_NW_TOS) == 0 \
839 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
840 or exact \
841 or flip_coin() \
842 ):
rootf6af1672012-04-06 09:46:29 -0700843 self.match.nw_tos = fi.rand_ip_tos()
844 # Specifying a TOS value requires that Ethertype is IP
845 if flip_coin():
846 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700847 self.match.wildcards = wildcard_set(self.match.wildcards, \
848 ofp.OFPFW_DL_TYPE, \
849 0 \
850 )
rootf6af1672012-04-06 09:46:29 -0700851 else:
Howard Persh3340d452012-04-06 16:45:21 -0700852 self.match.wildcards = wildcard_set(self.match.wildcards, \
853 ofp.OFPFW_NW_TOS, \
854 1 \
855 )
rootf6af1672012-04-06 09:46:29 -0700856
Dan Talayco910a8282012-04-07 00:05:20 -0700857 # Known issue on OVS with specifying nw_proto w/o dl_type as IP
Howard Pershc1199d52012-04-11 14:21:32 -0700858 if wildcard_get(wildcards_force, ofp.OFPFW_NW_PROTO) == 0 \
859 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
860 or exact \
861 or flip_coin() \
862 ):
Dan Talayco910a8282012-04-07 00:05:20 -0700863 self.match.nw_proto = fi.rand_ip_proto()
864 # Specifying an IP protocol requires that Ethertype is IP
865 if flip_coin():
866 self.match.dl_type = 0x0800
867 self.match.wildcards = wildcard_set(self.match.wildcards, \
868 ofp.OFPFW_DL_TYPE, \
869 0 \
870 )
871 else:
Howard Persh3340d452012-04-06 16:45:21 -0700872 self.match.wildcards = wildcard_set(self.match.wildcards, \
873 ofp.OFPFW_NW_PROTO, \
874 1 \
875 )
Dan Talayco910a8282012-04-07 00:05:20 -0700876
Howard Pershc1199d52012-04-11 14:21:32 -0700877 if wildcard_get(wildcards_force, ofp.OFPFW_TP_SRC) == 0 \
878 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
879 or exact\
880 or flip_coin() \
881 ):
rootf6af1672012-04-06 09:46:29 -0700882 self.match.tp_src = fi.rand_l4_port()
883 # Specifying a L4 port requires that IP protcol is
884 # one of {ICMP, TCP, UDP}
885 if flip_coin():
886 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700887 self.match.wildcards = wildcard_set(self.match.wildcards, \
888 ofp.OFPFW_NW_PROTO, \
889 0 \
890 )
rootf6af1672012-04-06 09:46:29 -0700891 # Specifying a L4 port requirues that Ethertype is IP
892 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700893 self.match.wildcards = wildcard_set(self.match.wildcards, \
894 ofp.OFPFW_DL_TYPE, \
895 0 \
896 )
rootf6af1672012-04-06 09:46:29 -0700897 if self.match.nw_proto == 1:
898 self.match.tp_src = self.match.tp_src & 0xff
899 else:
Howard Persh3340d452012-04-06 16:45:21 -0700900 self.match.wildcards = wildcard_set(self.match.wildcards, \
901 ofp.OFPFW_TP_SRC, \
902 1 \
903 )
rootf6af1672012-04-06 09:46:29 -0700904
Howard Pershc1199d52012-04-11 14:21:32 -0700905 if wildcard_get(wildcards_force, ofp.OFPFW_TP_DST) == 0 \
906 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
907 or exact \
908 or flip_coin() \
909 ):
rootf6af1672012-04-06 09:46:29 -0700910 self.match.tp_dst = fi.rand_l4_port()
911 # Specifying a L4 port requires that IP protcol is
912 # one of {ICMP, TCP, UDP}
913 if flip_coin():
914 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700915 self.match.wildcards = wildcard_set(self.match.wildcards, \
916 ofp.OFPFW_NW_PROTO, \
917 0 \
918 )
rootf6af1672012-04-06 09:46:29 -0700919 # Specifying a L4 port requirues that Ethertype is IP
920 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700921 self.match.wildcards = wildcard_set(self.match.wildcards, \
922 ofp.OFPFW_DL_TYPE, \
923 0 \
924 )
rootf6af1672012-04-06 09:46:29 -0700925 if self.match.nw_proto == 1:
926 self.match.tp_dst = self.match.tp_dst & 0xff
927 else:
Howard Persh3340d452012-04-06 16:45:21 -0700928 self.match.wildcards = wildcard_set(self.match.wildcards, \
929 ofp.OFPFW_TP_DST, \
930 1 \
931 )
rootf6af1672012-04-06 09:46:29 -0700932
933 # If nothing is wildcarded, it is an exact flow spec -- some switches
Howard Persh3340d452012-04-06 16:45:21 -0700934 # (Open vSwitch, for one) *require* that exact flow specs
935 # have priority 65535.
936 self.priority = 65535 if self.match.wildcards == 0 \
937 else fi.rand_priority()
rootf6af1672012-04-06 09:46:29 -0700938
939 # N.B. Don't make the timeout too short, else the flow might
940 # disappear before we get a chance to check for it.
941 t = random.randint(0, 65535)
942 self.idle_timeout = 0 if t < 60 else t
943 t = random.randint(0, 65535)
944 self.hard_timeout = 0 if t < 60 else t
945
Howard Persh8d21c1f2012-04-20 15:57:29 -0700946 self.rand_mod(fi, valid_actions, valid_ports, valid_queues)
rootf6af1672012-04-06 09:46:29 -0700947
948 return self
949
950 # Return flow cfg in canonical form
Howard Persh3340d452012-04-06 16:45:21 -0700951 # - There are dependencies between flow qualifiers, e.g. it only makes
952 # sense to qualify nw_proto if dl_type is qualified to be 0x0800 (IP).
953 # The canonical form of flow match criteria will "wildcard out"
954 # all such cases.
rootf6af1672012-04-06 09:46:29 -0700955 def canonical(self):
956 result = copy.deepcopy(self)
Howard Persh07d99e62012-04-09 15:26:57 -0700957
958 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_VLAN) != 0:
959 result.match.wildcards = wildcard_set(result.match.wildcards, \
960 ofp.OFPFW_DL_VLAN_PCP, \
961 1 \
962 )
963
rootf6af1672012-04-06 09:46:29 -0700964 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
965 or result.match.dl_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700966 # dl_tyoe is wildcarded, or specified as something other
967 # than IP or ARP
Howard Persh07d99e62012-04-09 15:26:57 -0700968 # => nw_src, nw_dst, nw_proto cannot be specified,
969 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700970 result.match.wildcards = wildcard_set(result.match.wildcards, \
971 ofp.OFPFW_NW_SRC_MASK, \
972 32 \
973 )
974 result.match.wildcards = wildcard_set(result.match.wildcards, \
975 ofp.OFPFW_NW_DST_MASK, \
976 32 \
977 )
Howard Persh3340d452012-04-06 16:45:21 -0700978 result.match.wildcards = wildcard_set(result.match.wildcards, \
979 ofp.OFPFW_NW_PROTO, \
980 1 \
981 )
Howard Persh07d99e62012-04-09 15:26:57 -0700982
983 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
984 or result.match.dl_type != 0x0800:
985 # dl_type is wildcarded, or specified as something other than IP
986 # => nw_tos, tp_src and tp_dst cannot be specified,
987 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700988 result.match.wildcards = wildcard_set(result.match.wildcards, \
989 ofp.OFPFW_NW_TOS, \
990 1 \
991 )
992 result.match.wildcards = wildcard_set(result.match.wildcards, \
993 ofp.OFPFW_TP_SRC, \
994 1 \
995 )
996 result.match.wildcards = wildcard_set(result.match.wildcards, \
997 ofp.OFPFW_TP_DST, \
998 1 \
999 )
Howard Persh07d99e62012-04-09 15:26:57 -07001000 result.match.wildcards = wildcard_set(result.match.wildcards, \
1001 ofp.OFPFW_NW_SRC_MASK, \
1002 32 \
1003 )
1004 result.match.wildcards = wildcard_set(result.match.wildcards, \
1005 ofp.OFPFW_NW_DST_MASK, \
1006 32 \
1007 )
1008 result.match.wildcards = wildcard_set(result.match.wildcards, \
1009 ofp.OFPFW_NW_PROTO, \
1010 1 \
1011 )
1012
rootf6af1672012-04-06 09:46:29 -07001013 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
1014 or result.match.nw_proto not in [1, 6, 17]:
Howard Persh3340d452012-04-06 16:45:21 -07001015 # nw_proto is wildcarded, or specified as something other than ICMP,
1016 # TCP or UDP
rootf6af1672012-04-06 09:46:29 -07001017 # => tp_src and tp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001018 result.match.wildcards = wildcard_set(result.match.wildcards, \
1019 ofp.OFPFW_TP_SRC, \
1020 1 \
1021 )
1022 result.match.wildcards = wildcard_set(result.match.wildcards, \
1023 ofp.OFPFW_TP_DST, \
1024 1 \
1025 )
rootf6af1672012-04-06 09:46:29 -07001026 return result
1027
Howard Persh680b92a2012-03-31 13:34:35 -07001028 # Overlap check
1029 # delf == True <=> Check for delete overlap, else add overlap
1030 # "Add overlap" is defined as there exists a packet that could match both the
1031 # receiver and argument flowspecs
1032 # "Delete overlap" is defined as the specificity of the argument flowspec
1033 # is greater than or equal to the specificity of the receiver flowspec
1034 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -07001035 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
1036 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001037 if self.match.in_port != x.match.in_port:
1038 return False # Both specified, and not equal
1039 elif delf:
1040 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001041 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
1042 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001043 if self.match.dl_vlan != x.match.dl_vlan:
1044 return False # Both specified, and not equal
1045 elif delf:
1046 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001047 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
1048 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001049 if self.match.dl_src != x.match.dl_src:
1050 return False # Both specified, and not equal
1051 elif delf:
1052 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001053 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
1054 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001055 if self.match.dl_dst != x.match.dl_dst:
1056 return False # Both specified, and not equal
1057 elif delf:
1058 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001059 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
1060 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001061 if self.match.dl_type != x.match.dl_type:
1062 return False # Both specified, and not equal
1063 elif delf:
1064 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -07001065 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
1066 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001067 if self.match.nw_proto != x.match.nw_proto:
1068 return False # Both specified, and not equal
1069 elif delf:
1070 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001071 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
1072 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001073 if self.match.tp_src != x.match.tp_src:
1074 return False # Both specified, and not equal
1075 elif delf:
1076 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001077 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
1078 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001079 if self.match.tp_dst != x.match.tp_dst:
1080 return False # Both specified, and not equal
1081 elif delf:
1082 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001083 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
1084 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001085 if delf and na < nb:
1086 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001087 if (na < 32 and nb < 32):
1088 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1089 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -07001090 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -07001091 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
1092 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001093 if delf and na < nb:
1094 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001095 if (na < 32 and nb < 32):
1096 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1097 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
rootf6af1672012-04-06 09:46:29 -07001098 return False # Overlapping bits not equal
1099 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
1100 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001101 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
1102 return False # Both specified, and not equal
1103 elif delf:
1104 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001105 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
1106 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001107 if self.match.nw_tos != x.match.nw_tos:
1108 return False # Both specified, and not equal
1109 elif delf:
1110 return False # Receiver more specific
1111 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -07001112
1113 def to_flow_mod_msg(self, msg):
1114 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -07001115 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001116 msg.idle_timeout = self.idle_timeout
1117 msg.hard_timeout = self.hard_timeout
1118 msg.priority = self.priority
1119 msg.actions = self.actions
1120 return msg
1121
1122 def from_flow_stat(self, msg):
1123 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -07001124 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001125 self.idle_timeout = msg.idle_timeout
1126 self.hard_timeout = msg.hard_timeout
1127 self.priority = msg.priority
1128 self.actions = msg.actions
1129
rootf6af1672012-04-06 09:46:29 -07001130 def from_flow_rem(self, msg):
1131 self.match = msg.match
1132 self.idle_timeout = msg.idle_timeout
1133 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -07001134
Howard Pershc7963582012-03-29 10:02:59 -07001135
rootf6af1672012-04-06 09:46:29 -07001136class Flow_Tbl:
1137 def clear(self):
1138 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001139
rootf6af1672012-04-06 09:46:29 -07001140 def __init__(self):
1141 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001142
rootf6af1672012-04-06 09:46:29 -07001143 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001144 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001145
1146 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001147 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001148
1149 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001150 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001151
1152 def values(self):
1153 return self.dict.values()
1154
1155 def count(self):
1156 return len(self.dict)
1157
Ed Swierk99a74de2012-08-22 06:40:54 -07001158 def rand(self, wildcards_force, sw, fi, num_flows):
rootf6af1672012-04-06 09:46:29 -07001159 self.clear()
1160 i = 0
1161 tbl = 0
1162 j = 0
1163 while i < num_flows:
1164 fc = Flow_Cfg()
1165 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001166 wildcards_force, \
rootf6af1672012-04-06 09:46:29 -07001167 sw.tbl_stats.stats[tbl].wildcards, \
1168 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001169 sw.valid_ports, \
1170 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001171 )
1172 fc = fc.canonical()
1173 if self.find(fc):
1174 continue
1175 fc.send_rem = False
1176 self.insert(fc)
1177 i = i + 1
1178 j = j + 1
1179 if j >= sw.tbl_stats.stats[tbl].max_entries:
1180 tbl = tbl + 1
1181 j = 0
1182
1183
1184class Switch:
1185 # Members:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001186 # controller - switch's test controller
1187 # sw_features - switch's OFPT_FEATURES_REPLY message
1188 # valid_ports - list of valid port numbers
1189 # valid_queues - list of valid [port, queue] pairs
1190 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1191 # queue_stats - switch's OFPT_STATS_REPLY message, for queue stats request
1192 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1193 # flow_tbl - (test's idea of) switch's flow table
rootf6af1672012-04-06 09:46:29 -07001194
1195 def __init__(self):
Howard Persh8d21c1f2012-04-20 15:57:29 -07001196 self.controller = None
1197 self.sw_features = None
1198 self.valid_ports = []
1199 self.valid_queues = []
1200 self.tbl_stats = None
1201 self.flow_stats = None
1202 self.flow_tbl = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001203 self.error_msgs = []
1204 self.removed_msgs = []
1205
1206 def error_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001207 logging.info("Got an ERROR message, type=%d, code=%d" \
Ed Swierk99a74de2012-08-22 06:40:54 -07001208 % (msg.type, msg.code) \
1209 )
Rich Lane9a003812012-10-04 17:17:59 -07001210 logging.info("Message header:")
1211 logging.info(msg.header.show())
Ed Swierk99a74de2012-08-22 06:40:54 -07001212 self.error_msgs.append(msg)
1213
1214 def removed_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001215 logging.info("Got a REMOVED message")
1216 logging.info("Message header:")
1217 logging.info(msg.header.show())
Ed Swierk99a74de2012-08-22 06:40:54 -07001218 self.removed_msgs.append(msg)
rootf6af1672012-04-06 09:46:29 -07001219
Howard Persh3340d452012-04-06 16:45:21 -07001220 def controller_set(self, controller):
1221 self.controller = controller
1222 # Register error message handler
Ed Swierk99a74de2012-08-22 06:40:54 -07001223 self.error_msgs = []
1224 self.removed_msgs = []
1225 controller.register(ofp.OFPT_ERROR, self.error_handler)
1226 controller.register(ofp.OFPT_FLOW_REMOVED, self.removed_handler)
Howard Persh3340d452012-04-06 16:45:21 -07001227
rootf6af1672012-04-06 09:46:29 -07001228 def features_get(self):
1229 # Get switch features
1230 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001231 (self.sw_features, pkt) = self.controller.transact(request)
rootf6af1672012-04-06 09:46:29 -07001232 if self.sw_features is None:
Rich Lane9a003812012-10-04 17:17:59 -07001233 logging.error("Get switch features failed")
rootf6af1672012-04-06 09:46:29 -07001234 return False
1235 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Rich Lane9a003812012-10-04 17:17:59 -07001236 logging.info("Ports reported by switch:")
1237 logging.info(self.valid_ports)
Rich Lane2014f9b2012-10-05 15:29:40 -07001238 ports_override = test_param_get("ports", [])
Howard Persh8d21c1f2012-04-20 15:57:29 -07001239 if ports_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001240 logging.info("Overriding ports to:")
1241 logging.info(ports_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001242 self.valid_ports = ports_override
1243
Howard Persh3340d452012-04-06 16:45:21 -07001244 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1245 # is that universal?
1246
1247 # TBD - There seems to be variability in which switches support which
1248 # ports; need to sort that out
1249 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1250# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1251# ofp.OFPP_NORMAL, \
1252# ofp.OFPP_FLOOD, \
1253# ofp.OFPP_ALL, \
1254# ofp.OFPP_CONTROLLER \
1255# ] \
1256# )
Rich Lane9a003812012-10-04 17:17:59 -07001257 logging.info("Supported actions reported by switch:")
1258 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001259 % (self.sw_features.actions, \
1260 actions_bmap_to_str(self.sw_features.actions) \
1261 ) \
1262 )
Rich Lane2014f9b2012-10-05 15:29:40 -07001263 actions_override = test_param_get("actions", -1)
Howard Persh07d99e62012-04-09 15:26:57 -07001264 if actions_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001265 logging.info("Overriding supported actions to:")
1266 logging.info(actions_bmap_to_str(actions_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001267 self.sw_features.actions = actions_override
rootf6af1672012-04-06 09:46:29 -07001268 return True
1269
1270 def tbl_stats_get(self):
1271 # Get table stats
Howard Persh680b92a2012-03-31 13:34:35 -07001272 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001273 (self.tbl_stats, pkt) = self.controller.transact(request)
Howard Persh07d99e62012-04-09 15:26:57 -07001274 if self.tbl_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001275 logging.error("Get table stats failed")
Howard Persh07d99e62012-04-09 15:26:57 -07001276 return False
Howard Persh8d21c1f2012-04-20 15:57:29 -07001277 i = 0
Howard Persh07d99e62012-04-09 15:26:57 -07001278 for ts in self.tbl_stats.stats:
Rich Lane9a003812012-10-04 17:17:59 -07001279 logging.info("Supported wildcards for table %d reported by switch:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001280 % (i)
1281 )
Rich Lane9a003812012-10-04 17:17:59 -07001282 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001283 % (ts.wildcards, \
1284 wildcards_to_str(ts.wildcards) \
1285 ) \
1286 )
Rich Lane2014f9b2012-10-05 15:29:40 -07001287 wildcards_override = test_param_get("wildcards", -1)
Howard Persh07d99e62012-04-09 15:26:57 -07001288 if wildcards_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001289 logging.info("Overriding supported wildcards for table %d to:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001290 % (i)
1291 )
Rich Lane9a003812012-10-04 17:17:59 -07001292 logging.info(wildcards_to_str(wildcards_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001293 ts.wildcards = wildcards_override
Howard Persh8d21c1f2012-04-20 15:57:29 -07001294 i = i + 1
Howard Persh07d99e62012-04-09 15:26:57 -07001295 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001296
Howard Persh8d21c1f2012-04-20 15:57:29 -07001297 def queue_stats_get(self):
1298 # Get queue stats
1299 request = message.queue_stats_request()
1300 request.port_no = ofp.OFPP_ALL
1301 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001302 (self.queue_stats, pkt) = self.controller.transact(request)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001303 if self.queue_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001304 logging.error("Get queue stats failed")
Howard Persh8d21c1f2012-04-20 15:57:29 -07001305 return False
1306 self.valid_queues = map(lambda x: (x.port_no, x.queue_id), \
1307 self.queue_stats.stats \
1308 )
Rich Lane9a003812012-10-04 17:17:59 -07001309 logging.info("(Port, queue) pairs reported by switch:")
1310 logging.info(self.valid_queues)
Rich Lane2014f9b2012-10-05 15:29:40 -07001311 queues_override = test_param_get("queues", [])
Howard Persh8d21c1f2012-04-20 15:57:29 -07001312 if queues_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001313 logging.info("Overriding (port, queue) pairs to:")
1314 logging.info(queues_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001315 self.valid_queues = queues_override
1316 return True
1317
1318 def connect(self, controller):
1319 # Connect to controller, and get all switch capabilities
1320 self.controller_set(controller)
1321 return (self.features_get() \
1322 and self.tbl_stats_get() \
1323 and self.queue_stats_get() \
1324 )
1325
Howard Pershc1199d52012-04-11 14:21:32 -07001326 def flow_stats_get(self, limit = 10000):
rootf6af1672012-04-06 09:46:29 -07001327 request = message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -07001328 query_match = ofp.ofp_match()
1329 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001330 request.match = query_match
1331 request.table_id = 0xff
1332 request.out_port = ofp.OFPP_NONE;
Rich Lane5c3151c2013-01-03 17:15:41 -08001333 self.controller.message_send(request)
Howard Persh3340d452012-04-06 16:45:21 -07001334 # <TBD>
1335 # Glue together successive reponse messages for stats reply.
1336 # Looking at the "more" flag and performing re-assembly
1337 # should be a part of the infrastructure.
1338 # </TBD>
1339 n = 0
1340 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -07001341 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY)
Howard Persh3340d452012-04-06 16:45:21 -07001342 if resp is None:
Howard Pershc1199d52012-04-11 14:21:32 -07001343 return False # Did not get expected response
Howard Persh3340d452012-04-06 16:45:21 -07001344 if n == 0:
1345 self.flow_stats = resp
1346 else:
1347 self.flow_stats.stats.extend(resp.stats)
1348 n = n + 1
Howard Pershc1199d52012-04-11 14:21:32 -07001349 if len(self.flow_stats.stats) > limit:
Rich Lane9a003812012-10-04 17:17:59 -07001350 logging.error("Too many flows returned")
Howard Pershc1199d52012-04-11 14:21:32 -07001351 return False
1352 if (resp.flags & 1) == 0:
1353 break # No more responses expected
Howard Persh3340d452012-04-06 16:45:21 -07001354 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001355
rootf6af1672012-04-06 09:46:29 -07001356 def flow_add(self, flow_cfg, overlapf = False):
Howard Persh680b92a2012-03-31 13:34:35 -07001357 flow_mod_msg = message.flow_mod()
1358 flow_mod_msg.command = ofp.OFPFC_ADD
1359 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001360 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001361 if overlapf:
1362 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001363 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001364 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Howard Persh07d99e62012-04-09 15:26:57 -07001365 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001366 logging.info("Sending flow_mod(add), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001367 % (flow_mod_msg.header.xid)
1368 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001369 self.controller.message_send(flow_mod_msg)
1370 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001371
rootf6af1672012-04-06 09:46:29 -07001372 def flow_mod(self, flow_cfg, strictf):
Howard Persh680b92a2012-03-31 13:34:35 -07001373 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001374 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf \
1375 else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -07001376 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001377 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001378 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001379 logging.info("Sending flow_mod(mod), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001380 % (flow_mod_msg.header.xid)
1381 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001382 self.controller.message_send(flow_mod_msg)
1383 return True
rootf6af1672012-04-06 09:46:29 -07001384
1385 def flow_del(self, flow_cfg, strictf):
1386 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001387 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf \
1388 else ofp.OFPFC_DELETE
rootf6af1672012-04-06 09:46:29 -07001389 flow_mod_msg.buffer_id = 0xffffffff
1390 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001391 flow_mod_msg.out_port = ofp.OFPP_NONE
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)
Rich Lane9a003812012-10-04 17:17:59 -07001394 logging.info("Sending flow_mod(del), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001395 % (flow_mod_msg.header.xid)
1396 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001397 self.controller.message_send(flow_mod_msg)
1398 return True
rootf6af1672012-04-06 09:46:29 -07001399
1400 def barrier(self):
1401 barrier = message.barrier_request()
Dan Talaycoc689a792012-09-28 14:22:53 -07001402 (resp, pkt) = self.controller.transact(barrier, 30)
rootf6af1672012-04-06 09:46:29 -07001403 return (resp is not None)
1404
Howard Persh3340d452012-04-06 16:45:21 -07001405 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001406 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001407 logging.info("Expecting %d error messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001408 num_got = len(self.error_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001409 logging.info("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001410 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001411 logging.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001412 result = False
1413 if num_exp == 0:
1414 return result
1415 elif num_exp == 1:
Rich Lane9a003812012-10-04 17:17:59 -07001416 logging.info("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001417 % (type, code) \
1418 )
1419 f = False
Ed Swierk99a74de2012-08-22 06:40:54 -07001420 for e in self.error_msgs:
Howard Persh3340d452012-04-06 16:45:21 -07001421 if e.type == type and e.code == code:
Rich Lane9a003812012-10-04 17:17:59 -07001422 logging.info("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001423 f = True
1424 if not f:
Rich Lane9a003812012-10-04 17:17:59 -07001425 logging.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001426 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001427 else:
Rich Lane9a003812012-10-04 17:17:59 -07001428 logging.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001429 result = False
1430 return result
1431
Howard Persh3340d452012-04-06 16:45:21 -07001432 def removed_verify(self, num_exp):
1433 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001434 logging.info("Expecting %d removed messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001435 num_got = len(self.removed_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001436 logging.info("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001437 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001438 logging.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001439 result = False
1440 if num_exp < 2:
1441 return result
Rich Lane9a003812012-10-04 17:17:59 -07001442 logging.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001443 return False
1444
Howard Persh5f3c83f2012-04-13 09:57:10 -07001445 # modf == True <=> Verify for flow modify, else for add/delete
1446 def flow_tbl_verify(self, modf = False):
rootf6af1672012-04-06 09:46:29 -07001447 result = True
1448
1449 # Verify flow count in switch
Rich Lane9a003812012-10-04 17:17:59 -07001450 logging.info("Reading table stats")
1451 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001452 if not self.tbl_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001453 logging.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001454 return False
1455 n = 0
1456 for ts in self.tbl_stats.stats:
1457 n = n + ts.active_count
Rich Lane9a003812012-10-04 17:17:59 -07001458 logging.info("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001459 % (n) \
1460 )
1461 if n != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001462 logging.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001463 result = False
1464
1465 # Read flows from switch
Rich Lane9a003812012-10-04 17:17:59 -07001466 logging.info("Retrieving flows from switch")
1467 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001468 if not self.flow_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001469 logging.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001470 return False
Rich Lane9a003812012-10-04 17:17:59 -07001471 logging.info("Retrieved %d flows" % (len(self.flow_stats.stats)))
rootf6af1672012-04-06 09:46:29 -07001472
1473 # Verify flows returned by switch
1474
1475 if len(self.flow_stats.stats) != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001476 logging.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001477 result = False
1478
Rich Lane9a003812012-10-04 17:17:59 -07001479 logging.info("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001480 for fc in self.flow_tbl.values():
1481 fc.matched = False
1482 for fs in self.flow_stats.stats:
1483 flow_in = Flow_Cfg()
1484 flow_in.from_flow_stat(fs)
Rich Lane9a003812012-10-04 17:17:59 -07001485 logging.info("Received flow:")
1486 logging.info(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001487 fc = self.flow_tbl.find(flow_in)
1488 if fc is None:
Rich Lane9a003812012-10-04 17:17:59 -07001489 logging.error("Received flow:")
1490 logging.error(str(flow_in))
1491 logging.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001492 result = False
1493 elif fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001494 logging.error("Received flow:")
1495 logging.error(str(flow_in))
1496 logging.error("re-matches defined flow:")
1497 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001498 result = False
1499 else:
Rich Lane9a003812012-10-04 17:17:59 -07001500 logging.info("matched")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001501 if modf:
1502 # Check for modify
1503
1504 if flow_in.cookie != fc.cookie:
Rich Lane9a003812012-10-04 17:17:59 -07001505 logging.warning("Defined flow:")
1506 logging.warning(str(fc))
1507 logging.warning("Received flow:")
1508 logging.warning(str(flow_in))
1509 logging.warning("cookies do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001510 if not flow_in.actions_equal(fc):
Rich Lane9a003812012-10-04 17:17:59 -07001511 logging.error("Defined flow:")
1512 logging.error(str(fc))
1513 logging.error("Received flow:")
1514 logging.error(str(flow_in))
1515 logging.error("actions do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001516 else:
1517 # Check for add/delete
1518
1519 if not flow_in == fc:
Rich Lane9a003812012-10-04 17:17:59 -07001520 logging.error("Defined flow:")
1521 logging.error(str(fc))
1522 logging.error("Received flow:")
1523 logging.error(str(flow_in))
1524 logging.error("non-key portions of flow do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001525 result = False
rootf6af1672012-04-06 09:46:29 -07001526 fc.matched = True
1527 for fc in self.flow_tbl.values():
1528 if not fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001529 logging.error("Defined flow:")
1530 logging.error(str(fc))
1531 logging.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001532 result = False
1533
1534 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001535
Howard Persh9cab4822012-09-11 17:08:40 -07001536 def settle(self):
1537 time.sleep(2)
1538
Howard Persh07d99e62012-04-09 15:26:57 -07001539# FLOW ADD 5
1540#
1541# OVERVIEW
1542# Add flows to switch, read back and verify flow configurations
1543#
1544# PURPOSE
1545# - Test acceptance of flow adds
1546# - Test ability of switch to process additions to flow table in random
1547# priority order
1548# - Test correctness of flow configuration responses
1549#
1550# PARAMETERS
1551#
1552# Name: num_flows
1553# Type: number
1554# Description:
1555# Number of flows to define; 0 => maximum number of flows, as determined
1556# from switch capabilities
1557# Default: 100
1558#
1559# PROCESS
1560# 1. Delete all flows from switch
1561# 2. Generate <num_flows> distinct flow configurations
1562# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1563# 4. Verify that no OFPT_ERROR responses were generated by switch
1564# 5. Retrieve flow stats from switch
1565# 6. Compare flow configurations returned by switch
1566# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1567# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001568
Rich Laneb90a1c42012-10-05 09:16:05 -07001569class Flow_Add_5(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001570 """
1571 Test FLOW_ADD_5 from draft top-half test plan
1572
1573 INPUTS
1574 num_flows - Number of flows to generate
1575 """
Howard Persh680b92a2012-03-31 13:34:35 -07001576
rootf6af1672012-04-06 09:46:29 -07001577 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001578 logging.info("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001579
Rich Lane2014f9b2012-10-05 15:29:40 -07001580 num_flows = test_param_get("num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001581
Howard Pershc7963582012-03-29 10:02:59 -07001582 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001583
Rich Lane9a003812012-10-04 17:17:59 -07001584 logging.info("Deleting all flows from switch")
1585 rc = delete_all_flows(self.controller)
Howard Pershc7963582012-03-29 10:02:59 -07001586 self.assertEqual(rc, 0, "Failed to delete all flows")
1587
rootf6af1672012-04-06 09:46:29 -07001588 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001589
rootf6af1672012-04-06 09:46:29 -07001590 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001591 self.assertTrue(sw.connect(self.controller), \
1592 "Failed to connect to switch" \
1593 )
Howard Pershc7963582012-03-29 10:02:59 -07001594
rootf6af1672012-04-06 09:46:29 -07001595 if num_flows == 0:
1596 # Number of flows requested was 0
1597 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001598
rootf6af1672012-04-06 09:46:29 -07001599 for ts in sw.tbl_stats.stats:
1600 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001601
Rich Lane9a003812012-10-04 17:17:59 -07001602 logging.info("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001603
1604 # Dream up some flow information, i.e. space to chose from for
1605 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001606
rootf6af1672012-04-06 09:46:29 -07001607 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001608 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001609
rootf6af1672012-04-06 09:46:29 -07001610 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001611
rootf6af1672012-04-06 09:46:29 -07001612 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001613 ft.rand(required_wildcards(self), sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001614
rootf6af1672012-04-06 09:46:29 -07001615 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001616
Rich Lane9a003812012-10-04 17:17:59 -07001617 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001618 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001619 logging.info("Adding flow:")
1620 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001621 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001622
rootf6af1672012-04-06 09:46:29 -07001623 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001624
rootf6af1672012-04-06 09:46:29 -07001625 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001626
rootf6af1672012-04-06 09:46:29 -07001627 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001628
Howard Persh9cab4822012-09-11 17:08:40 -07001629 sw.settle() # Allow switch to settle and generate any notifications
1630
rootf6af1672012-04-06 09:46:29 -07001631 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001632
rootf6af1672012-04-06 09:46:29 -07001633 if not sw.errors_verify(0):
1634 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001635
rootf6af1672012-04-06 09:46:29 -07001636 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001637
rootf6af1672012-04-06 09:46:29 -07001638 sw.flow_tbl = ft
1639 if not sw.flow_tbl_verify():
1640 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001641
rootf6af1672012-04-06 09:46:29 -07001642 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001643 logging.info("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001644
Howard Pershc7963582012-03-29 10:02:59 -07001645
Howard Persh07d99e62012-04-09 15:26:57 -07001646# FLOW ADD 5_1
1647#
1648# OVERVIEW
1649# Verify handling of non-canonical flows
1650#
1651# PURPOSE
1652# - Test that switch detects and correctly responds to a non-canonical flow
1653# definition. A canonical flow is one that satisfies all match qualifier
1654# dependencies; a non-canonical flow is one that does not.
1655#
1656# PARAMETERS
1657# - None
1658#
1659# PROCESS
1660# 1. Delete all flows from switch
1661# 2. Generate 1 flow definition, which is different from its canonicalization
1662# 3. Send flow to switch
1663# 4. Retrieve flow from switch
1664# 5. Compare returned flow to canonical form of defined flow
1665# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1666
1667# Disabled.
1668# Should be DUT dependent.
Howard Persh07d99e62012-04-09 15:26:57 -07001669
Rich Laneb90a1c42012-10-05 09:16:05 -07001670class Flow_Add_5_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001671 """
1672 Test FLOW_ADD_5.1 from draft top-half test plan
1673
1674 INPUTS
1675 None
1676 """
Rich Laned1d9c282012-10-04 22:07:10 -07001677
1678 priority = -1
rootf6af1672012-04-06 09:46:29 -07001679
1680 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001681 logging.info("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001682
Rich Lane2014f9b2012-10-05 15:29:40 -07001683 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001684
1685 # Clear all flows from switch
1686
Rich Lane9a003812012-10-04 17:17:59 -07001687 logging.info("Deleting all flows from switch")
1688 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001689 self.assertEqual(rc, 0, "Failed to delete all flows")
1690
1691 # Get switch capabilites
1692
rootf6af1672012-04-06 09:46:29 -07001693 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001694 self.assertTrue(sw.connect(self.controller), \
1695 "Failed to connect to switch" \
1696 )
rootf6af1672012-04-06 09:46:29 -07001697
1698 # Dream up some flow information, i.e. space to chose from for
1699 # random flow parameter generation
1700
1701 fi = Flow_Info()
1702 fi.rand(10)
1703
1704 # Dream up a flow config that will be canonicalized by the switch
1705
1706 while True:
1707 fc = Flow_Cfg()
1708 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001709 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07001710 sw.tbl_stats.stats[0].wildcards, \
1711 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001712 sw.valid_ports, \
1713 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001714 )
1715 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001716 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001717 break
1718
1719 ft = Flow_Tbl()
1720 ft.insert(fcc)
1721
1722 # Send it to the switch
1723
Rich Lane9a003812012-10-04 17:17:59 -07001724 logging.info("Sending flow add to switch:")
1725 logging.info(str(fc))
1726 logging.info("should be canonicalized as:")
1727 logging.info(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001728 fc.send_rem = False
1729 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1730
1731 # Do barrier, to make sure all flows are in
1732
1733 self.assertTrue(sw.barrier(), "Barrier failed")
1734
1735 result = True
1736
Howard Persh9cab4822012-09-11 17:08:40 -07001737 sw.settle() # Allow switch to settle and generate any notifications
1738
rootf6af1672012-04-06 09:46:29 -07001739 # Check for any error messages
1740
1741 if not sw.errors_verify(0):
1742 result = False
1743
1744 # Verify flow table
1745
1746 sw.flow_tbl = ft
1747 if not sw.flow_tbl_verify():
1748 result = False
1749
1750 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001751 logging.info("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001752
1753
Howard Persh07d99e62012-04-09 15:26:57 -07001754# FLOW ADD 6
1755#
1756# OVERVIEW
1757# Test flow table capacity
1758#
1759# PURPOSE
1760# - Test switch can accept as many flow definitions as it claims
1761# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1762# - Test that attempting to create flows beyond capacity does not corrupt
1763# flow table
1764#
1765# PARAMETERS
1766# None
1767#
1768# PROCESS
1769# 1. Delete all flows from switch
1770# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1771# to determine flow table size, N
1772# 3. Generate (N + 1) distinct flow configurations
1773# 4. Send N flow adds to switch, for flows generated in step 3 above
1774# 5. Verify flow table in switch
1775# 6. Send one more flow add to switch
1776# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1777# response was generated by switch, for last flow mod sent
1778# 7. Retrieve flow stats from switch
1779# 8. Verify flow table in switch
1780# 9. Test PASSED iff:
1781# - error message received, for correct flow
1782# - last flow definition sent to switch is not in flow table
1783# else test FAILED
1784
Howard Persh3340d452012-04-06 16:45:21 -07001785# Disabled because of bogus capacity reported by OVS.
1786# Should be DUT dependent.
Howard Persh3340d452012-04-06 16:45:21 -07001787
Rich Laneb90a1c42012-10-05 09:16:05 -07001788class Flow_Add_6(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001789 """
1790 Test FLOW_ADD_6 from draft top-half test plan
1791
1792 INPUTS
1793 num_flows - Number of flows to generate
1794 """
Howard Pershc7963582012-03-29 10:02:59 -07001795
Rich Laned1d9c282012-10-04 22:07:10 -07001796 priority = -1
1797
Howard Pershc7963582012-03-29 10:02:59 -07001798 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001799 logging.info("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001800
rootf6af1672012-04-06 09:46:29 -07001801 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001802
Rich Lane9a003812012-10-04 17:17:59 -07001803 logging.info("Deleting all flows from switch")
1804 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001805 self.assertEqual(rc, 0, "Failed to delete all flows")
1806
1807 # Get switch capabilites
1808
rootf6af1672012-04-06 09:46:29 -07001809 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001810 self.assertTrue(sw.connect(self.controller), \
1811 "Failed to connect to switch" \
1812 )
rootf6af1672012-04-06 09:46:29 -07001813
root2843d2b2012-04-06 10:27:46 -07001814 num_flows = 0
rootf6af1672012-04-06 09:46:29 -07001815 for ts in sw.tbl_stats.stats:
1816 num_flows = num_flows + ts.max_entries
1817
Rich Lane9a003812012-10-04 17:17:59 -07001818 logging.info("Switch capacity is %d flows" % (num_flows))
1819 logging.info("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001820
1821 # Dream up some flow information, i.e. space to chose from for
1822 # random flow parameter generation
1823
1824 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001825 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001826
1827 # Create a flow table, to switch's capacity
1828
1829 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001830 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07001831
1832 # Send flow table to switch
1833
Rich Lane9a003812012-10-04 17:17:59 -07001834 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001835 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001836 logging.info("Adding flow:")
1837 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001838 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1839
1840 # Do barrier, to make sure all flows are in
1841
1842 self.assertTrue(sw.barrier(), "Barrier failed")
1843
1844 result = True
1845
Howard Persh9cab4822012-09-11 17:08:40 -07001846 sw.settle() # Allow switch to settle and generate any notifications
1847
rootf6af1672012-04-06 09:46:29 -07001848 # Check for any error messages
1849
1850 if not sw.errors_verify(0):
1851 result = False
1852
1853 # Dream up one more flow
1854
Rich Lane9a003812012-10-04 17:17:59 -07001855 logging.info("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001856 while True:
1857 fc = Flow_Cfg()
1858 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001859 required_wildcards(self), \
Howard Persh07d99e62012-04-09 15:26:57 -07001860 sw.tbl_stats.stats[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001861 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001862 sw.valid_ports, \
1863 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001864 )
1865 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001866 if not ft.find(fc):
1867 break
rootf6af1672012-04-06 09:46:29 -07001868
1869 # Send one-more flow
1870
1871 fc.send_rem = False
Rich Lane9a003812012-10-04 17:17:59 -07001872 logging.info("Sending flow add switch")
1873 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001874 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1875
1876 # Do barrier, to make sure all flows are in
1877
1878 self.assertTrue(sw.barrier(), "Barrier failed")
1879
Howard Persh9cab4822012-09-11 17:08:40 -07001880 sw.settle() # Allow switch to settle and generate any notifications
1881
rootf6af1672012-04-06 09:46:29 -07001882 # 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")
Rich Lane9a003812012-10-04 17:17:59 -07001897 logging.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
Rich Laneb90a1c42012-10-05 09:16:05 -07001922class Flow_Add_7(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001923 """
1924 Test FLOW_ADD_7 from draft top-half test plan
1925
1926 INPUTS
1927 None
1928 """
1929
1930 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001931 logging.info("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001932
1933 # Clear all flows from switch
1934
Rich Lane9a003812012-10-04 17:17:59 -07001935 logging.info("Deleting all flows from switch")
1936 rc = delete_all_flows(self.controller)
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, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001956 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07001957 sw.tbl_stats.stats[0].wildcards, \
1958 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001959 sw.valid_ports, \
1960 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001961 )
1962 fc = fc.canonical()
1963
1964 # Send it to the switch
1965
Rich Lane9a003812012-10-04 17:17:59 -07001966 logging.info("Sending flow add to switch:")
1967 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001968 ft = Flow_Tbl()
1969 fc.send_rem = False
1970 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1971 ft.insert(fc)
1972
1973 # Dream up some different actions, with the same flow key
1974
1975 fc2 = copy.deepcopy(fc)
1976 while True:
1977 fc2.rand_mod(fi, \
1978 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001979 sw.valid_ports, \
1980 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001981 )
1982 if fc2 != fc:
1983 break
1984
1985 # Send that to the switch
1986
Rich Lane9a003812012-10-04 17:17:59 -07001987 logging.info("Sending flow add to switch:")
1988 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07001989 fc2.send_rem = False
1990 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
1991 ft.insert(fc2)
1992
1993 # Do barrier, to make sure all flows are in
1994
1995 self.assertTrue(sw.barrier(), "Barrier failed")
1996
1997 result = True
1998
Howard Persh9cab4822012-09-11 17:08:40 -07001999 sw.settle() # Allow switch to settle and generate any notifications
2000
rootf6af1672012-04-06 09:46:29 -07002001 # Check for any error messages
2002
2003 if not sw.errors_verify(0):
2004 result = False
2005
2006 # Verify flow table
2007
2008 sw.flow_tbl = ft
2009 if not sw.flow_tbl_verify():
2010 result = False
2011
2012 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002013 logging.info("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002014
2015
Howard Persh07d99e62012-04-09 15:26:57 -07002016# FLOW ADD 8
2017#
2018# OVERVIEW
2019# Add overlapping flows to switch, verify that overlapping flows are rejected
2020#
2021# PURPOSE
2022# - Test detection of overlapping flows by switch
2023# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
2024# - Test rejection of overlapping flows
2025# - Test defining overlapping flows does not corrupt flow table
2026#
2027# PARAMETERS
2028# None
2029#
2030# PROCESS
2031# 1. Delete all flows from switch
2032# 2. Generate flow definition F1
2033# 3. Generate flow definition F2, with key overlapping F1
2034# 4. Send flow add to switch, for F1
2035# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
2036# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
2037# was generated by switch
2038# 7. Verifiy flows configured in swtich
2039# 8. Test PASSED iff:
2040# - error message received, for overlapping flow
2041# - overlapping flow is not in flow table
2042# else test FAILED
2043
Rich Laneb90a1c42012-10-05 09:16:05 -07002044class Flow_Add_8(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002045 """
2046 Test FLOW_ADD_8 from draft top-half test plan
2047
2048 INPUTS
2049 None
2050 """
2051
2052 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002053 logging.info("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002054
2055 # Clear all flows from switch
2056
Rich Lane9a003812012-10-04 17:17:59 -07002057 logging.info("Deleting all flows from switch")
2058 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002059 self.assertEqual(rc, 0, "Failed to delete all flows")
2060
2061 # Get switch capabilites
2062
rootf6af1672012-04-06 09:46:29 -07002063 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002064 self.assertTrue(sw.connect(self.controller), \
2065 "Failed to connect to switch" \
2066 )
rootf6af1672012-04-06 09:46:29 -07002067
2068 # Dream up some flow information, i.e. space to chose from for
2069 # random flow parameter generation
2070
2071 fi = Flow_Info()
2072 fi.rand(10)
2073
2074 # Dream up a flow config, with at least 1 qualifier specified
2075
2076 fc = Flow_Cfg()
2077 while True:
2078 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002079 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002080 sw.tbl_stats.stats[0].wildcards, \
2081 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002082 sw.valid_ports, \
2083 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002084 )
2085 fc = fc.canonical()
2086 if fc.match.wildcards != ofp.OFPFW_ALL:
2087 break
2088
2089 # Send it to the switch
2090
Rich Lane9a003812012-10-04 17:17:59 -07002091 logging.info("Sending flow add to switch:")
2092 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002093 ft = Flow_Tbl()
2094 fc.send_rem = False
2095 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2096 ft.insert(fc)
2097
2098 # Wildcard out one qualifier that was specified, to create an
2099 # overlapping flow
2100
2101 fc2 = copy.deepcopy(fc)
2102 for wi in shuffle(range(len(all_wildcards_list))):
2103 w = all_wildcards_list[wi]
2104 if (fc2.match.wildcards & w) == 0:
2105 break
2106 if w == ofp.OFPFW_NW_SRC_MASK:
2107 w = ofp.OFPFW_NW_SRC_ALL
2108 wn = "OFPFW_NW_SRC"
2109 elif w == ofp.OFPFW_NW_DST_MASK:
2110 w = ofp.OFPFW_NW_DST_ALL
2111 wn = "OFPFW_NW_DST"
2112 else:
2113 wn = all_wildcard_names[w]
Rich Lane9a003812012-10-04 17:17:59 -07002114 logging.info("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07002115 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07002116 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07002117
2118 # Send that to the switch, with overlap checking
2119
Rich Lane9a003812012-10-04 17:17:59 -07002120 logging.info("Sending flow add to switch:")
2121 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002122 fc2.send_rem = False
2123 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
2124
2125 # Do barrier, to make sure all flows are in
2126 self.assertTrue(sw.barrier(), "Barrier failed")
2127
2128 result = True
2129
Howard Persh9cab4822012-09-11 17:08:40 -07002130 sw.settle() # Allow switch to settle and generate any notifications
2131
rootf6af1672012-04-06 09:46:29 -07002132 # Check for expected error message
2133
2134 if not sw.errors_verify(1, \
2135 ofp.OFPET_FLOW_MOD_FAILED, \
2136 ofp.OFPFMFC_OVERLAP \
2137 ):
2138 result = False
2139
2140 # Verify flow table
2141
2142 sw.flow_tbl = ft
2143 if not sw.flow_tbl_verify():
2144 result = False
2145
2146 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002147 logging.info("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002148
2149
Howard Persh07d99e62012-04-09 15:26:57 -07002150# FLOW MODIFY 1
2151#
2152# OVERVIEW
2153# Strict modify of single existing flow
2154#
2155# PURPOSE
2156# - Verify that strict flow modify operates only on specified flow
2157# - Verify that flow is correctly modified
2158#
2159# PARAMETERS
2160# None
2161#
2162# PROCESS
2163# 1. Delete all flows from switch
2164# 2. Generate 1 flow F
2165# 3. Send flow add to switch, for flow F
2166# 4. Generate new action list for flow F, yielding F'
2167# 5. Send strict flow modify to switch, for flow F'
2168# 6. Verify flow table in switch
2169# 7. Test PASSED iff flow returned by switch is F'; else FAILED
2170
Rich Laneb90a1c42012-10-05 09:16:05 -07002171class Flow_Mod_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002172 """
2173 Test FLOW_MOD_1 from draft top-half test plan
2174
2175 INPUTS
2176 None
2177 """
2178
2179 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002180 logging.info("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002181
2182 # Clear all flows from switch
2183
Rich Lane9a003812012-10-04 17:17:59 -07002184 logging.info("Deleting all flows from switch")
2185 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002186 self.assertEqual(rc, 0, "Failed to delete all flows")
2187
2188 # Get switch capabilites
2189
rootf6af1672012-04-06 09:46:29 -07002190 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002191 self.assertTrue(sw.connect(self.controller), \
2192 "Failed to connect to switch" \
2193 )
rootf6af1672012-04-06 09:46:29 -07002194
2195 # Dream up some flow information, i.e. space to chose from for
2196 # random flow parameter generation
2197
2198 fi = Flow_Info()
2199 fi.rand(10)
2200
2201 # Dream up a flow config
2202
2203 fc = Flow_Cfg()
2204 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002205 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002206 sw.tbl_stats.stats[0].wildcards, \
2207 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002208 sw.valid_ports, \
2209 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002210 )
2211 fc = fc.canonical()
2212
2213 # Send it to the switch
2214
Rich Lane9a003812012-10-04 17:17:59 -07002215 logging.info("Sending flow add to switch:")
2216 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002217 ft = Flow_Tbl()
2218 fc.send_rem = False
2219 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2220 ft.insert(fc)
2221
2222 # Dream up some different actions, with the same flow key
2223
2224 fc2 = copy.deepcopy(fc)
2225 while True:
2226 fc2.rand_mod(fi, \
2227 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002228 sw.valid_ports, \
2229 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002230 )
2231 if fc2 != fc:
2232 break
2233
2234 # Send that to the switch
2235
Rich Lane9a003812012-10-04 17:17:59 -07002236 logging.info("Sending strict flow mod to switch:")
2237 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002238 fc2.send_rem = False
2239 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2240 ft.insert(fc2)
2241
2242 # Do barrier, to make sure all flows are in
2243
2244 self.assertTrue(sw.barrier(), "Barrier failed")
2245
2246 result = True
2247
Howard Persh9cab4822012-09-11 17:08:40 -07002248 sw.settle() # Allow switch to settle and generate any notifications
2249
rootf6af1672012-04-06 09:46:29 -07002250 # Check for any error messages
2251
2252 if not sw.errors_verify(0):
2253 result = False
2254
2255 # Verify flow table
2256
2257 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002258 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002259 result = False
2260
2261 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002262 logging.info("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002263
Howard Persh07d99e62012-04-09 15:26:57 -07002264
2265# FLOW MODIFY 2
2266#
2267# OVERVIEW
2268# Loose modify of mutiple flows
2269#
2270# PURPOSE
2271# - Verify that loose flow modify operates only on matching flows
2272# - Verify that matching flows are correctly modified
2273#
2274# PARAMETERS
2275# Name: num_flows
2276# Type: number
2277# Description:
2278# Number of flows to define
2279# Default: 100
2280#
2281# PROCESS
2282# 1. Delete all flows from switch
2283# 2. Generate <num_flows> distinct flow configurations
2284# 3. Send <num_flows> flow adds to switch
2285# 4. Pick 1 defined flow F at random
2286# 5. Create overlapping loose flow mod match criteria by repeatedly
2287# wildcarding out qualifiers in match of F => F',
2288# and create new actions list A' for F'
2289# 6. Send loose flow modify for F' to switch
2290# 7. Verify flow table in swtich
2291# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2292# are returned in step 7 above, each with correct (original or modified)
2293# action list;
2294# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002295
Rich Laneb90a1c42012-10-05 09:16:05 -07002296class Flow_Mod_2(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002297 """
2298 Test FLOW_MOD_2 from draft top-half test plan
2299
2300 INPUTS
2301 None
2302 """
2303
2304 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002305 logging.info("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002306
Rich Lane2014f9b2012-10-05 15:29:40 -07002307 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002308
2309 # Clear all flows from switch
2310
Rich Lane9a003812012-10-04 17:17:59 -07002311 logging.info("Deleting all flows from switch")
2312 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002313 self.assertEqual(rc, 0, "Failed to delete all flows")
2314
2315 # Get switch capabilites
2316
rootf6af1672012-04-06 09:46:29 -07002317 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002318 self.assertTrue(sw.connect(self.controller), \
2319 "Failed to connect to switch" \
2320 )
rootf6af1672012-04-06 09:46:29 -07002321
2322 # Dream up some flow information, i.e. space to chose from for
2323 # random flow parameter generation
2324
2325 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002326 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002327 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002328
2329 # Dream up some flows
2330
2331 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002332 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002333
2334 # Send flow table to switch
2335
Rich Lane9a003812012-10-04 17:17:59 -07002336 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002337 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002338 logging.info("Adding flow:")
2339 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002340 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2341
2342 # Do barrier, to make sure all flows are in
2343
2344 self.assertTrue(sw.barrier(), "Barrier failed")
2345
2346 result = True
2347
Howard Persh9cab4822012-09-11 17:08:40 -07002348 sw.settle() # Allow switch to settle and generate any notifications
2349
rootf6af1672012-04-06 09:46:29 -07002350 # Check for any error messages
2351
2352 if not sw.errors_verify(0):
2353 result = False
2354
2355 # Verify flow table
2356
2357 sw.flow_tbl = ft
2358 if not sw.flow_tbl_verify():
2359 result = False
2360
2361 # Pick a random flow as a basis
Howard Persh5f3c83f2012-04-13 09:57:10 -07002362
2363 mfc = copy.deepcopy((ft.values())[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002364 mfc.rand_mod(fi, \
2365 sw.sw_features.actions, \
2366 sw.valid_ports, \
2367 sw.valid_queues \
2368 )
rootf6af1672012-04-06 09:46:29 -07002369
2370 # Repeatedly wildcard qualifiers
2371
2372 for wi in shuffle(range(len(all_wildcards_list))):
2373 w = all_wildcards_list[wi]
2374 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2375 n = wildcard_get(mfc.match.wildcards, w)
2376 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002377 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2378 w, \
2379 random.randint(n + 1, 32) \
2380 )
rootf6af1672012-04-06 09:46:29 -07002381 else:
2382 continue
2383 else:
2384 if wildcard_get(mfc.match.wildcards, w) == 0:
2385 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2386 else:
2387 continue
2388 mfc = mfc.canonical()
2389
2390 # Count the number of flows that would be modified
2391
2392 n = 0
2393 for fc in ft.values():
2394 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2395 n = n + 1
2396
2397 # If more than 1, we found our loose delete flow spec
2398 if n > 1:
2399 break
2400
Rich Lane9a003812012-10-04 17:17:59 -07002401 logging.info("Modifying %d flows" % (n))
2402 logging.info("Sending flow mod to switch:")
2403 logging.info(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002404 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2405
2406 # Do barrier, to make sure all flows are in
2407 self.assertTrue(sw.barrier(), "Barrier failed")
2408
Howard Persh9cab4822012-09-11 17:08:40 -07002409 sw.settle() # Allow switch to settle and generate any notifications
2410
rootf6af1672012-04-06 09:46:29 -07002411 # Check for error message
2412
2413 if not sw.errors_verify(0):
2414 result = False
2415
2416 # Apply flow mod to local flow table
2417
2418 for fc in ft.values():
2419 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002420 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002421
2422 # Verify flow table
2423
2424 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002425 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002426 result = False
2427
2428 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002429 logging.info("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002430
2431
Howard Persh07d99e62012-04-09 15:26:57 -07002432# FLOW MODIFY 3
2433
2434# OVERVIEW
2435# Strict modify of non-existent flow
2436#
2437# PURPOSE
2438# Verify that strict modify of a non-existent flow is equivalent to a flow add
2439#
2440# PARAMETERS
2441# None
2442#
2443# PROCESS
2444# 1. Delete all flows from switch
2445# 2. Send single flow mod, as strict modify, to switch
2446# 3. Verify flow table in switch
2447# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2448
Rich Laneb90a1c42012-10-05 09:16:05 -07002449class Flow_Mod_3(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002450 """
2451 Test FLOW_MOD_3 from draft top-half test plan
2452
2453 INPUTS
2454 None
2455 """
2456
2457 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002458 logging.info("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002459
2460 # Clear all flows from switch
2461
Rich Lane9a003812012-10-04 17:17:59 -07002462 logging.info("Deleting all flows from switch")
2463 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002464 self.assertEqual(rc, 0, "Failed to delete all flows")
2465
2466 # Get switch capabilites
2467
rootf6af1672012-04-06 09:46:29 -07002468 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002469 self.assertTrue(sw.connect(self.controller), \
2470 "Failed to connect to switch" \
2471 )
rootf6af1672012-04-06 09:46:29 -07002472
2473 # Dream up some flow information, i.e. space to chose from for
2474 # random flow parameter generation
2475
2476 fi = Flow_Info()
2477 fi.rand(10)
2478
2479 # Dream up a flow config
2480
2481 fc = Flow_Cfg()
2482 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002483 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002484 sw.tbl_stats.stats[0].wildcards, \
2485 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002486 sw.valid_ports, \
2487 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002488 )
2489 fc = fc.canonical()
2490
2491 # Send it to the switch
2492
Rich Lane9a003812012-10-04 17:17:59 -07002493 logging.info("Sending flow mod to switch:")
2494 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002495 ft = Flow_Tbl()
2496 fc.send_rem = False
2497 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2498 ft.insert(fc)
2499
2500 # Do barrier, to make sure all flows are in
2501
2502 self.assertTrue(sw.barrier(), "Barrier failed")
2503
2504 result = True
2505
Howard Persh9cab4822012-09-11 17:08:40 -07002506 sw.settle() # Allow switch to settle and generate any notifications
2507
rootf6af1672012-04-06 09:46:29 -07002508 # Check for any error messages
2509
2510 if not sw.errors_verify(0):
2511 result = False
2512
2513 # Verify flow table
2514
2515 sw.flow_tbl = ft
2516 if not sw.flow_tbl_verify():
2517 result = False
2518
2519 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002520 logging.info("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002521
2522
Howard Persh8d21c1f2012-04-20 15:57:29 -07002523# FLOW MODIFY 3_1
2524
2525# OVERVIEW
2526# No-op modify
2527#
2528# PURPOSE
2529# Verify that modify of a flow with new actions same as old ones operates correctly
2530#
2531# PARAMETERS
2532# None
2533#
2534# PROCESS
2535# 1. Delete all flows from switch
2536# 2. Send single flow mod, as strict modify, to switch
2537# 3. Verify flow table in switch
2538# 4. Send same flow mod, as strict modify, to switch
2539# 5. Verify flow table in switch
2540# 6. Test PASSED iff flow defined in step 2 and 4 above verified; else FAILED
2541
Rich Laneb90a1c42012-10-05 09:16:05 -07002542class Flow_Mod_3_1(base_tests.SimpleProtocol):
Howard Persh8d21c1f2012-04-20 15:57:29 -07002543 """
2544 Test FLOW_MOD_3_1 from draft top-half test plan
2545
2546 INPUTS
2547 None
2548 """
2549
2550 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002551 logging.info("Flow_Mod_3_1 TEST BEGIN")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002552
2553 # Clear all flows from switch
2554
Rich Lane9a003812012-10-04 17:17:59 -07002555 logging.info("Deleting all flows from switch")
2556 rc = delete_all_flows(self.controller)
Howard Persh8d21c1f2012-04-20 15:57:29 -07002557 self.assertEqual(rc, 0, "Failed to delete all flows")
2558
2559 # Get switch capabilites
2560
2561 sw = Switch()
2562 self.assertTrue(sw.connect(self.controller), \
2563 "Failed to connect to switch" \
2564 )
2565
2566 # Dream up some flow information, i.e. space to chose from for
2567 # random flow parameter generation
2568
2569 fi = Flow_Info()
2570 fi.rand(10)
2571
2572 # Dream up a flow config
2573
2574 fc = Flow_Cfg()
2575 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002576 required_wildcards(self), \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002577 sw.tbl_stats.stats[0].wildcards, \
2578 sw.sw_features.actions, \
2579 sw.valid_ports, \
2580 sw.valid_queues \
2581 )
2582 fc = fc.canonical()
2583
2584 # Send it to the switch
2585
Rich Lane9a003812012-10-04 17:17:59 -07002586 logging.info("Sending flow mod to switch:")
2587 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002588 ft = Flow_Tbl()
2589 fc.send_rem = False
2590 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2591 ft.insert(fc)
2592
2593 # Do barrier, to make sure all flows are in
2594
2595 self.assertTrue(sw.barrier(), "Barrier failed")
2596
2597 result = True
2598
Howard Persh9cab4822012-09-11 17:08:40 -07002599 sw.settle() # Allow switch to settle and generate any notifications
2600
Howard Persh8d21c1f2012-04-20 15:57:29 -07002601 # Check for any error messages
2602
2603 if not sw.errors_verify(0):
2604 result = False
2605
2606 # Verify flow table
2607
2608 sw.flow_tbl = ft
2609 if not sw.flow_tbl_verify():
2610 result = False
2611
2612 # Send same flow to the switch again
2613
Rich Lane9a003812012-10-04 17:17:59 -07002614 logging.info("Sending flow mod to switch:")
2615 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002616 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2617
2618 # Do barrier, to make sure all flows are in
2619
2620 self.assertTrue(sw.barrier(), "Barrier failed")
2621
Howard Persh9cab4822012-09-11 17:08:40 -07002622 sw.settle() # Allow switch to settle and generate any notifications
2623
Howard Persh8d21c1f2012-04-20 15:57:29 -07002624 # Check for any error messages
2625
2626 if not sw.errors_verify(0):
2627 result = False
2628
2629 # Verify flow table
2630
2631 if not sw.flow_tbl_verify():
2632 result = False
2633
2634 self.assertTrue(result, "Flow_Mod_3_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002635 logging.info("Flow_Mod_3_1 TEST PASSED")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002636
2637
Howard Persh07d99e62012-04-09 15:26:57 -07002638# FLOW DELETE 1
2639#
2640# OVERVIEW
2641# Strict delete of single flow
2642#
2643# PURPOSE
2644# Verify correct operation of strict delete of single defined flow
2645#
2646# PARAMETERS
2647# None
2648#
2649# PROCESS
2650# 1. Delete all flows from switch
2651# 2. Send flow F to switch
2652# 3. Send strict flow delete for F to switch
2653# 4. Verify flow table in swtich
2654# 6. Test PASSED iff all flows sent to switch in step 2 above,
2655# less flow removed in step 3 above, are returned in step 4 above;
2656# else test FAILED
2657
Rich Laneb90a1c42012-10-05 09:16:05 -07002658class Flow_Del_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002659 """
2660 Test FLOW_DEL_1 from draft top-half test plan
2661
2662 INPUTS
2663 None
2664 """
2665
2666 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002667 logging.info("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002668
2669 # Clear all flows from switch
2670
Rich Lane9a003812012-10-04 17:17:59 -07002671 logging.info("Deleting all flows from switch")
2672 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002673 self.assertEqual(rc, 0, "Failed to delete all flows")
2674
2675 # Get switch capabilites
2676
rootf6af1672012-04-06 09:46:29 -07002677 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002678 self.assertTrue(sw.connect(self.controller), \
2679 "Failed to connect to switch" \
2680 )
rootf6af1672012-04-06 09:46:29 -07002681
2682 # Dream up some flow information, i.e. space to chose from for
2683 # random flow parameter generation
2684
2685 fi = Flow_Info()
2686 fi.rand(10)
2687
2688 # Dream up a flow config
2689
2690 fc = Flow_Cfg()
2691 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002692 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002693 sw.tbl_stats.stats[0].wildcards, \
2694 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002695 sw.valid_ports, \
2696 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002697 )
2698 fc = fc.canonical()
2699
2700 # Send it to the switch
2701
Rich Lane9a003812012-10-04 17:17:59 -07002702 logging.info("Sending flow add to switch:")
2703 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002704 ft = Flow_Tbl()
2705 fc.send_rem = False
2706 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2707 ft.insert(fc)
2708
2709 # Dream up some different actions, with the same flow key
2710
2711 fc2 = copy.deepcopy(fc)
2712 while True:
2713 fc2.rand_mod(fi, \
2714 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002715 sw.valid_ports, \
2716 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002717 )
2718 if fc2 != fc:
2719 break
2720
2721 # Delete strictly
2722
Rich Lane9a003812012-10-04 17:17:59 -07002723 logging.info("Sending strict flow del to switch:")
2724 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002725 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2726 ft.delete(fc)
2727
2728 # Do barrier, to make sure all flows are in
2729
2730 self.assertTrue(sw.barrier(), "Barrier failed")
2731
2732 result = True
2733
Howard Persh9cab4822012-09-11 17:08:40 -07002734 sw.settle() # Allow switch to settle and generate any notifications
2735
rootf6af1672012-04-06 09:46:29 -07002736 # Check for any error messages
2737
2738 if not sw.errors_verify(0):
2739 result = False
2740
2741 # Verify flow table
2742
2743 sw.flow_tbl = ft
2744 if not sw.flow_tbl_verify():
2745 result = False
2746
2747 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002748 logging.info("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002749
2750
Howard Persh07d99e62012-04-09 15:26:57 -07002751# FLOW DELETE 2
2752#
2753# OVERVIEW
2754# Loose delete of multiple flows
2755#
2756# PURPOSE
2757# - Verify correct operation of loose delete of multiple flows
2758#
2759# PARAMETERS
2760# Name: num_flows
2761# Type: number
2762# Description:
2763# Number of flows to define
2764# Default: 100
2765#
2766# PROCESS
2767# 1. Delete all flows from switch
2768# 2. Generate <num_flows> distinct flow configurations
2769# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2770# 4. Pick 1 defined flow F at random
2771# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2772# F' will match more than 1 existing flow key
2773# 6. Send loose flow delete for F' to switch
2774# 7. Verify flow table in switch
2775# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2776# removed in step 6 above (i.e. those that match F'), are returned
2777# in step 7 above;
2778# else test FAILED
2779
Rich Laneb90a1c42012-10-05 09:16:05 -07002780class Flow_Del_2(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002781 """
2782 Test FLOW_DEL_2 from draft top-half test plan
2783
2784 INPUTS
2785 None
2786 """
2787
2788 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002789 logging.info("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002790
Rich Lane2014f9b2012-10-05 15:29:40 -07002791 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002792
2793 # Clear all flows from switch
2794
Rich Lane9a003812012-10-04 17:17:59 -07002795 logging.info("Deleting all flows from switch")
2796 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002797 self.assertEqual(rc, 0, "Failed to delete all flows")
2798
2799 # Get switch capabilites
2800
rootf6af1672012-04-06 09:46:29 -07002801 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002802 self.assertTrue(sw.connect(self.controller), \
2803 "Failed to connect to switch" \
2804 )
rootf6af1672012-04-06 09:46:29 -07002805
2806 # Dream up some flow information, i.e. space to chose from for
2807 # random flow parameter generation
2808
2809 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002810 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002811 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002812
2813 # Dream up some flows
2814
2815 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002816 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002817
2818 # Send flow table to switch
2819
Rich Lane9a003812012-10-04 17:17:59 -07002820 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002821 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002822 logging.info("Adding flow:")
2823 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002824 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2825
2826 # Do barrier, to make sure all flows are in
2827
2828 self.assertTrue(sw.barrier(), "Barrier failed")
2829
2830 result = True
2831
Howard Persh9cab4822012-09-11 17:08:40 -07002832 sw.settle() # Allow switch to settle and generate any notifications
2833
rootf6af1672012-04-06 09:46:29 -07002834 # Check for any error messages
2835
2836 if not sw.errors_verify(0):
2837 result = False
2838
2839 # Verify flow table
2840
2841 sw.flow_tbl = ft
2842 if not sw.flow_tbl_verify():
2843 result = False
2844
2845 # Pick a random flow as a basis
2846
2847 dfc = copy.deepcopy(ft.values()[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002848 dfc.rand_mod(fi, \
2849 sw.sw_features.actions, \
2850 sw.valid_ports, \
2851 sw.valid_queues \
2852 )
rootf6af1672012-04-06 09:46:29 -07002853
2854 # Repeatedly wildcard qualifiers
2855
2856 for wi in shuffle(range(len(all_wildcards_list))):
2857 w = all_wildcards_list[wi]
2858 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2859 n = wildcard_get(dfc.match.wildcards, w)
2860 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002861 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2862 w, \
2863 random.randint(n + 1, 32) \
2864 )
rootf6af1672012-04-06 09:46:29 -07002865 else:
2866 continue
2867 else:
2868 if wildcard_get(dfc.match.wildcards, w) == 0:
2869 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2870 else:
2871 continue
2872 dfc = dfc.canonical()
2873
2874 # Count the number of flows that would be deleted
2875
2876 n = 0
2877 for fc in ft.values():
2878 if dfc.overlaps(fc, True):
2879 n = n + 1
2880
2881 # If more than 1, we found our loose delete flow spec
2882 if n > 1:
2883 break
2884
Rich Lane9a003812012-10-04 17:17:59 -07002885 logging.info("Deleting %d flows" % (n))
2886 logging.info("Sending flow del to switch:")
2887 logging.info(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002888 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2889
2890 # Do barrier, to make sure all flows are in
2891 self.assertTrue(sw.barrier(), "Barrier failed")
2892
Howard Persh9cab4822012-09-11 17:08:40 -07002893 sw.settle() # Allow switch to settle and generate any notifications
2894
rootf6af1672012-04-06 09:46:29 -07002895 # Check for error message
2896
2897 if not sw.errors_verify(0):
2898 result = False
2899
2900 # Apply flow mod to local flow table
2901
2902 for fc in ft.values():
2903 if dfc.overlaps(fc, True):
2904 ft.delete(fc)
2905
2906 # Verify flow table
2907
2908 sw.flow_tbl = ft
2909 if not sw.flow_tbl_verify():
2910 result = False
2911
2912 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002913 logging.info("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002914
2915
Howard Persh07d99e62012-04-09 15:26:57 -07002916# FLOW DELETE 4
2917#
2918# OVERVIEW
2919# Flow removed messages
2920#
2921# PURPOSE
2922# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2923# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2924#
2925# PARAMETERS
2926# None
2927#
2928# PROCESS
2929# 1. Delete all flows from switch
2930# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2931# 3. Send strict flow delete of flow to switch
2932# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2933# 5. Verify flow table in switch
2934# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2935# removed in step 3 above, are returned in step 5 above, and that
2936# asynch message was received; else test FAILED
2937
2938
Rich Laneb90a1c42012-10-05 09:16:05 -07002939class Flow_Del_4(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002940 """
2941 Test FLOW_DEL_4 from draft top-half test plan
2942
2943 INPUTS
2944 None
2945 """
2946
2947 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002948 logging.info("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002949
2950 # Clear all flows from switch
2951
Rich Lane9a003812012-10-04 17:17:59 -07002952 logging.info("Deleting all flows from switch")
2953 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002954 self.assertEqual(rc, 0, "Failed to delete all flows")
2955
2956 # Get switch capabilites
2957
rootf6af1672012-04-06 09:46:29 -07002958 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002959 self.assertTrue(sw.connect(self.controller), \
2960 "Failed to connect to switch" \
2961 )
rootf6af1672012-04-06 09:46:29 -07002962
2963 # Dream up some flow information, i.e. space to chose from for
2964 # random flow parameter generation
2965
2966 fi = Flow_Info()
2967 fi.rand(10)
2968
2969 # Dream up a flow config
2970
2971 fc = Flow_Cfg()
2972 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002973 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002974 sw.tbl_stats.stats[0].wildcards, \
2975 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002976 sw.valid_ports, \
2977 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002978 )
2979 fc = fc.canonical()
2980
2981 # Send it to the switch. with "notify on removed"
2982
Rich Lane9a003812012-10-04 17:17:59 -07002983 logging.info("Sending flow add to switch:")
2984 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002985 ft = Flow_Tbl()
2986 fc.send_rem = True
2987 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2988 ft.insert(fc)
2989
2990 # Dream up some different actions, with the same flow key
2991
2992 fc2 = copy.deepcopy(fc)
2993 while True:
2994 fc2.rand_mod(fi, \
2995 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002996 sw.valid_ports, \
2997 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002998 )
2999 if fc2 != fc:
3000 break
3001
3002 # Delete strictly
3003
Rich Lane9a003812012-10-04 17:17:59 -07003004 logging.info("Sending strict flow del to switch:")
3005 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07003006 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
3007 ft.delete(fc)
3008
3009 # Do barrier, to make sure all flows are in
3010
3011 self.assertTrue(sw.barrier(), "Barrier failed")
3012
3013 result = True
3014
Howard Persh9cab4822012-09-11 17:08:40 -07003015 sw.settle() # Allow switch to settle and generate any notifications
3016
rootf6af1672012-04-06 09:46:29 -07003017 # Check for expected "removed" message
3018
Howard Persh3340d452012-04-06 16:45:21 -07003019 if not sw.errors_verify(0):
3020 result = False
3021
3022 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07003023 result = False
3024
3025 # Verify flow table
3026
3027 sw.flow_tbl = ft
3028 if not sw.flow_tbl_verify():
3029 result = False
3030
3031 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07003032 logging.info("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07003033