blob: b6a00006433370a2ab3f0d2bc5837bc18079f3ac [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
76import basic
77
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 Lane477f4812012-10-04 22:49:00 -0700150 if test_param_get(config, "vlans", []) != []:
151 self.vlans = test_param_get(config, "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 Lane477f4812012-10-04 22:49:00 -0700397 if test_param_get(config, "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 Lane477f4812012-10-04 22:49:00 -0700501 actions_force = test_param_get(config, "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:
566 act.max_len = ACTION_MAX_LEN
567 self.actions.add(act)
568
Howard Persh3340d452012-04-06 16:45:21 -0700569 p = random.randint(1, 100)
Howard Pershc1199d52012-04-11 14:21:32 -0700570 if (((1 << ofp.OFPAT_ENQUEUE) & actions_force) != 0 or p <= 33) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700571 and len(valid_queues) > 0 \
572 and ofp.OFPAT_ENQUEUE in actions:
Howard Pershc1199d52012-04-11 14:21:32 -0700573 # In not forecd, one third of the time, include ENQUEUE actions
574 # at end of list
Howard Persh3340d452012-04-06 16:45:21 -0700575 # At most 1 ENQUEUE action
576 act = action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700577 (act.port, act.queue_id) = rand_pick(valid_queues)
Dan Talayco910a8282012-04-07 00:05:20 -0700578 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700579 self.actions.add(act)
Howard Pershc1199d52012-04-11 14:21:32 -0700580 if (((1 << ofp.OFPAT_OUTPUT) & actions_force) != 0 \
581 or (p > 33 and p <= 66) \
582 ) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700583 and len(valid_ports) > 0 \
Howard Pershc1199d52012-04-11 14:21:32 -0700584 and ofp.OFPAT_OUTPUT in actions:
Howard Persh3340d452012-04-06 16:45:21 -0700585 # One third of the time, include OUTPUT actions at end of list
586 port_idxs = shuffle(range(len(valid_ports)))
587 # Only 1 output action allowed if IN_PORT wildcarded
588 n = 1 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) != 0 \
589 else random.randint(1, len(valid_ports))
590 port_idxs = port_idxs[0 : n]
591 for pi in port_idxs:
592 act = action.action_output()
593 act.port = valid_ports[pi]
Dan Talayco910a8282012-04-07 00:05:20 -0700594 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700595 if act.port != ofp.OFPP_IN_PORT \
596 or wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
597 # OUTPUT(IN_PORT) only valid if OFPFW_IN_PORT not wildcarded
598 self.actions.add(act)
599 else:
600 # One third of the time, include neither
601 pass
602
603
604 # Randomize flow data for flow modifies (i.e. cookie and actions)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700605 def rand_mod(self, fi, valid_actions, valid_ports, valid_queues):
rootf6af1672012-04-06 09:46:29 -0700606 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700607
Dan Talayco910a8282012-04-07 00:05:20 -0700608 # By default, test with conservative ordering conventions
609 # This should probably be indicated in a profile
Rich Lane477f4812012-10-04 22:49:00 -0700610 if test_param_get(config, "conservative_ordered_actions", True):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700611 self.rand_actions_ordered(fi, valid_actions, valid_ports, valid_queues)
Howard Persh3340d452012-04-06 16:45:21 -0700612 return self
613
Rich Lane477f4812012-10-04 22:49:00 -0700614 actions_force = test_param_get(config, "actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700615 if actions_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700616 logging.info("Forced actions:")
617 logging.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700618
619 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh680b92a2012-03-31 13:34:35 -0700620 supported_actions = []
621 for a in all_actions_list:
622 if ((1 << a) & valid_actions) != 0:
623 supported_actions.append(a)
624
Howard Pershc1199d52012-04-11 14:21:32 -0700625 actions \
626 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
627
628 for a in all_actions_list:
629 if ((1 << a) & actions_force) != 0:
630 actions.append(a)
631
632 actions = shuffle(actions)
Howard Pershc7963582012-03-29 10:02:59 -0700633
634 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700635 for a in actions:
Howard Pershc7963582012-03-29 10:02:59 -0700636 if a == ofp.OFPAT_OUTPUT:
637 # TBD - Output actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700638 if len(valid_ports) == 0:
639 continue
Howard Pershc7963582012-03-29 10:02:59 -0700640 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700641 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700642 for pi in port_idxs:
643 act = action.action_output()
Howard Persh680b92a2012-03-31 13:34:35 -0700644 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700645 self.actions.add(act)
646 elif a == ofp.OFPAT_SET_VLAN_VID:
647 act = action.action_set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700648 act.vlan_vid = fi.rand_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700649 self.actions.add(act)
650 elif a == ofp.OFPAT_SET_VLAN_PCP:
Dan Talayco910a8282012-04-07 00:05:20 -0700651 act = action.action_set_vlan_pcp()
652 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700653 elif a == ofp.OFPAT_STRIP_VLAN:
654 act = action.action_strip_vlan()
655 self.actions.add(act)
656 elif a == ofp.OFPAT_SET_DL_SRC:
657 act = action.action_set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700658 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700659 self.actions.add(act)
660 elif a == ofp.OFPAT_SET_DL_DST:
661 act = action.action_set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700662 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700663 self.actions.add(act)
664 elif a == ofp.OFPAT_SET_NW_SRC:
665 act = action.action_set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700666 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700667 self.actions.add(act)
668 elif a == ofp.OFPAT_SET_NW_DST:
669 act = action.action_set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700670 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700671 self.actions.add(act)
672 elif a == ofp.OFPAT_SET_NW_TOS:
673 act = action.action_set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700674 act.nw_tos = fi.rand_ip_tos()
Howard Pershc7963582012-03-29 10:02:59 -0700675 self.actions.add(act)
676 elif a == ofp.OFPAT_SET_TP_SRC:
677 act = action.action_set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700678 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700679 self.actions.add(act)
680 elif a == ofp.OFPAT_SET_TP_DST:
681 act = action.action_set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700682 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700683 self.actions.add(act)
684 elif a == ofp.OFPAT_ENQUEUE:
685 # TBD - Enqueue actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700686 if len(valid_queues) == 0:
687 continue
688 qidxs = shuffle(range(len(valid_queues)))
689 qidxs = qidxs[0 : random.randint(1, len(valid_queues))]
690 for qi in qidxs:
Howard Pershc7963582012-03-29 10:02:59 -0700691 act = action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700692 (act.port, act.queue_id) = valid_queues[qi]
Howard Pershc7963582012-03-29 10:02:59 -0700693 self.actions.add(act)
694
695 return self
696
rootf6af1672012-04-06 09:46:29 -0700697 # Randomize flow cfg
Ed Swierk99a74de2012-08-22 06:40:54 -0700698 def rand(self, fi, wildcards_force, valid_wildcards, valid_actions, valid_ports,
699 valid_queues):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700700 if wildcards_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700701 logging.info("Wildcards forced:")
702 logging.info(wildcards_to_str(wildcards_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700703
rootf6af1672012-04-06 09:46:29 -0700704 # Start with no wildcards, i.e. everything specified
705 self.match.wildcards = 0
Howard Pershc1199d52012-04-11 14:21:32 -0700706
707 if wildcards_force != 0:
708 exact = False
709 else:
710 # Make approx. 5% of flows exact
711 exact = (random.randint(1, 100) <= 5)
rootf6af1672012-04-06 09:46:29 -0700712
713 # For each qualifier Q,
714 # if (wildcarding is not supported for Q,
715 # or an exact flow is specified
716 # or a coin toss comes up heads),
717 # specify Q
718 # else
719 # wildcard Q
720
Howard Pershc1199d52012-04-11 14:21:32 -0700721 if wildcard_get(wildcards_force, ofp.OFPFW_IN_PORT) == 0 \
722 and (wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
723 or exact \
724 or flip_coin() \
725 ):
rootf6af1672012-04-06 09:46:29 -0700726 self.match.in_port = rand_pick(valid_ports)
727 else:
Howard Persh3340d452012-04-06 16:45:21 -0700728 self.match.wildcards = wildcard_set(self.match.wildcards, \
729 ofp.OFPFW_IN_PORT, \
730 1 \
731 )
rootf6af1672012-04-06 09:46:29 -0700732
Howard Pershc1199d52012-04-11 14:21:32 -0700733 if wildcard_get(wildcards_force, ofp.OFPFW_DL_DST) == 0 \
734 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
735 or exact \
736 or flip_coin() \
737 ):
rootf6af1672012-04-06 09:46:29 -0700738 self.match.dl_dst = fi.rand_dl_addr()
739 else:
Howard Persh3340d452012-04-06 16:45:21 -0700740 self.match.wildcards = wildcard_set(self.match.wildcards, \
741 ofp.OFPFW_DL_DST, \
742 1 \
743 )
rootf6af1672012-04-06 09:46:29 -0700744
Howard Pershc1199d52012-04-11 14:21:32 -0700745 if wildcard_get(wildcards_force, ofp.OFPFW_DL_SRC) == 0 \
746 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
747 or exact \
748 or flip_coin() \
749 ):
rootf6af1672012-04-06 09:46:29 -0700750 self.match.dl_src = fi.rand_dl_addr()
751 else:
Howard Persh3340d452012-04-06 16:45:21 -0700752 self.match.wildcards = wildcard_set(self.match.wildcards, \
753 ofp.OFPFW_DL_SRC, \
754 1 \
755 )
rootf6af1672012-04-06 09:46:29 -0700756
Howard Pershc1199d52012-04-11 14:21:32 -0700757 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN) == 0 \
758 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
759 or exact \
760 or flip_coin() \
761 ):
rootf6af1672012-04-06 09:46:29 -0700762 self.match.dl_vlan = fi.rand_vlan()
763 else:
Howard Persh3340d452012-04-06 16:45:21 -0700764 self.match.wildcards = wildcard_set(self.match.wildcards, \
765 ofp.OFPFW_DL_VLAN, \
766 1 \
767 )
rootf6af1672012-04-06 09:46:29 -0700768
Howard Pershc1199d52012-04-11 14:21:32 -0700769 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN_PCP) == 0 \
770 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
771 or exact \
772 or flip_coin() \
773 ):
774 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
775 else:
776 self.match.wildcards = wildcard_set(self.match.wildcards, \
777 ofp.OFPFW_DL_VLAN_PCP, \
778 1 \
779 )
780
781 if wildcard_get(wildcards_force, ofp.OFPFW_DL_TYPE) == 0 \
782 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
783 or exact \
784 or flip_coin() \
785 ):
rootf6af1672012-04-06 09:46:29 -0700786 self.match.dl_type = fi.rand_ethertype()
787 else:
Howard Persh3340d452012-04-06 16:45:21 -0700788 self.match.wildcards = wildcard_set(self.match.wildcards, \
789 ofp.OFPFW_DL_TYPE, \
790 1 \
791 )
rootf6af1672012-04-06 09:46:29 -0700792
Howard Pershc1199d52012-04-11 14:21:32 -0700793 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_SRC_MASK)
794 if n == 0:
795 if exact or flip_coin():
796 n = 0
797 else:
798 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
799 if n > 32:
800 n = 32
801 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700802 self.match.wildcards = wildcard_set(self.match.wildcards, \
803 ofp.OFPFW_NW_SRC_MASK, \
804 n \
805 )
rootf6af1672012-04-06 09:46:29 -0700806 if n < 32:
807 self.match.nw_src = fi.rand_ip_addr() & ~((1 << n) - 1)
808 # Specifying any IP address match other than all bits
809 # don't care requires that Ethertype is one of {IP, ARP}
810 if flip_coin():
811 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700812 self.match.wildcards = wildcard_set(self.match.wildcards, \
813 ofp.OFPFW_DL_TYPE, \
814 0 \
815 )
rootf6af1672012-04-06 09:46:29 -0700816
Howard Pershc1199d52012-04-11 14:21:32 -0700817 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_DST_MASK)
818 if n == 0:
819 if exact or flip_coin():
820 n = 0
821 else:
822 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
823 if n > 32:
824 n = 32
825 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700826 self.match.wildcards = wildcard_set(self.match.wildcards, \
827 ofp.OFPFW_NW_DST_MASK, \
828 n \
829 )
rootf6af1672012-04-06 09:46:29 -0700830 if n < 32:
831 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
832 # Specifying any IP address match other than all bits
833 # don't care requires that Ethertype is one of {IP, ARP}
834 if flip_coin():
835 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700836 self.match.wildcards = wildcard_set(self.match.wildcards, \
837 ofp.OFPFW_DL_TYPE, \
838 0 \
839 )
rootf6af1672012-04-06 09:46:29 -0700840
Howard Pershc1199d52012-04-11 14:21:32 -0700841 if wildcard_get(wildcards_force, ofp.OFPFW_NW_TOS) == 0 \
842 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
843 or exact \
844 or flip_coin() \
845 ):
rootf6af1672012-04-06 09:46:29 -0700846 self.match.nw_tos = fi.rand_ip_tos()
847 # Specifying a TOS value requires that Ethertype is IP
848 if flip_coin():
849 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700850 self.match.wildcards = wildcard_set(self.match.wildcards, \
851 ofp.OFPFW_DL_TYPE, \
852 0 \
853 )
rootf6af1672012-04-06 09:46:29 -0700854 else:
Howard Persh3340d452012-04-06 16:45:21 -0700855 self.match.wildcards = wildcard_set(self.match.wildcards, \
856 ofp.OFPFW_NW_TOS, \
857 1 \
858 )
rootf6af1672012-04-06 09:46:29 -0700859
Dan Talayco910a8282012-04-07 00:05:20 -0700860 # Known issue on OVS with specifying nw_proto w/o dl_type as IP
Howard Pershc1199d52012-04-11 14:21:32 -0700861 if wildcard_get(wildcards_force, ofp.OFPFW_NW_PROTO) == 0 \
862 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
863 or exact \
864 or flip_coin() \
865 ):
Dan Talayco910a8282012-04-07 00:05:20 -0700866 self.match.nw_proto = fi.rand_ip_proto()
867 # Specifying an IP protocol requires that Ethertype is IP
868 if flip_coin():
869 self.match.dl_type = 0x0800
870 self.match.wildcards = wildcard_set(self.match.wildcards, \
871 ofp.OFPFW_DL_TYPE, \
872 0 \
873 )
874 else:
Howard Persh3340d452012-04-06 16:45:21 -0700875 self.match.wildcards = wildcard_set(self.match.wildcards, \
876 ofp.OFPFW_NW_PROTO, \
877 1 \
878 )
Dan Talayco910a8282012-04-07 00:05:20 -0700879
Howard Pershc1199d52012-04-11 14:21:32 -0700880 if wildcard_get(wildcards_force, ofp.OFPFW_TP_SRC) == 0 \
881 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
882 or exact\
883 or flip_coin() \
884 ):
rootf6af1672012-04-06 09:46:29 -0700885 self.match.tp_src = fi.rand_l4_port()
886 # Specifying a L4 port requires that IP protcol is
887 # one of {ICMP, TCP, UDP}
888 if flip_coin():
889 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700890 self.match.wildcards = wildcard_set(self.match.wildcards, \
891 ofp.OFPFW_NW_PROTO, \
892 0 \
893 )
rootf6af1672012-04-06 09:46:29 -0700894 # Specifying a L4 port requirues that Ethertype is IP
895 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700896 self.match.wildcards = wildcard_set(self.match.wildcards, \
897 ofp.OFPFW_DL_TYPE, \
898 0 \
899 )
rootf6af1672012-04-06 09:46:29 -0700900 if self.match.nw_proto == 1:
901 self.match.tp_src = self.match.tp_src & 0xff
902 else:
Howard Persh3340d452012-04-06 16:45:21 -0700903 self.match.wildcards = wildcard_set(self.match.wildcards, \
904 ofp.OFPFW_TP_SRC, \
905 1 \
906 )
rootf6af1672012-04-06 09:46:29 -0700907
Howard Pershc1199d52012-04-11 14:21:32 -0700908 if wildcard_get(wildcards_force, ofp.OFPFW_TP_DST) == 0 \
909 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
910 or exact \
911 or flip_coin() \
912 ):
rootf6af1672012-04-06 09:46:29 -0700913 self.match.tp_dst = fi.rand_l4_port()
914 # Specifying a L4 port requires that IP protcol is
915 # one of {ICMP, TCP, UDP}
916 if flip_coin():
917 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700918 self.match.wildcards = wildcard_set(self.match.wildcards, \
919 ofp.OFPFW_NW_PROTO, \
920 0 \
921 )
rootf6af1672012-04-06 09:46:29 -0700922 # Specifying a L4 port requirues that Ethertype is IP
923 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700924 self.match.wildcards = wildcard_set(self.match.wildcards, \
925 ofp.OFPFW_DL_TYPE, \
926 0 \
927 )
rootf6af1672012-04-06 09:46:29 -0700928 if self.match.nw_proto == 1:
929 self.match.tp_dst = self.match.tp_dst & 0xff
930 else:
Howard Persh3340d452012-04-06 16:45:21 -0700931 self.match.wildcards = wildcard_set(self.match.wildcards, \
932 ofp.OFPFW_TP_DST, \
933 1 \
934 )
rootf6af1672012-04-06 09:46:29 -0700935
936 # If nothing is wildcarded, it is an exact flow spec -- some switches
Howard Persh3340d452012-04-06 16:45:21 -0700937 # (Open vSwitch, for one) *require* that exact flow specs
938 # have priority 65535.
939 self.priority = 65535 if self.match.wildcards == 0 \
940 else fi.rand_priority()
rootf6af1672012-04-06 09:46:29 -0700941
942 # N.B. Don't make the timeout too short, else the flow might
943 # disappear before we get a chance to check for it.
944 t = random.randint(0, 65535)
945 self.idle_timeout = 0 if t < 60 else t
946 t = random.randint(0, 65535)
947 self.hard_timeout = 0 if t < 60 else t
948
Howard Persh8d21c1f2012-04-20 15:57:29 -0700949 self.rand_mod(fi, valid_actions, valid_ports, valid_queues)
rootf6af1672012-04-06 09:46:29 -0700950
951 return self
952
953 # Return flow cfg in canonical form
Howard Persh3340d452012-04-06 16:45:21 -0700954 # - There are dependencies between flow qualifiers, e.g. it only makes
955 # sense to qualify nw_proto if dl_type is qualified to be 0x0800 (IP).
956 # The canonical form of flow match criteria will "wildcard out"
957 # all such cases.
rootf6af1672012-04-06 09:46:29 -0700958 def canonical(self):
959 result = copy.deepcopy(self)
Howard Persh07d99e62012-04-09 15:26:57 -0700960
961 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_VLAN) != 0:
962 result.match.wildcards = wildcard_set(result.match.wildcards, \
963 ofp.OFPFW_DL_VLAN_PCP, \
964 1 \
965 )
966
rootf6af1672012-04-06 09:46:29 -0700967 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
968 or result.match.dl_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700969 # dl_tyoe is wildcarded, or specified as something other
970 # than IP or ARP
Howard Persh07d99e62012-04-09 15:26:57 -0700971 # => nw_src, nw_dst, nw_proto cannot be specified,
972 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700973 result.match.wildcards = wildcard_set(result.match.wildcards, \
974 ofp.OFPFW_NW_SRC_MASK, \
975 32 \
976 )
977 result.match.wildcards = wildcard_set(result.match.wildcards, \
978 ofp.OFPFW_NW_DST_MASK, \
979 32 \
980 )
Howard Persh3340d452012-04-06 16:45:21 -0700981 result.match.wildcards = wildcard_set(result.match.wildcards, \
982 ofp.OFPFW_NW_PROTO, \
983 1 \
984 )
Howard Persh07d99e62012-04-09 15:26:57 -0700985
986 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
987 or result.match.dl_type != 0x0800:
988 # dl_type is wildcarded, or specified as something other than IP
989 # => nw_tos, tp_src and tp_dst cannot be specified,
990 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700991 result.match.wildcards = wildcard_set(result.match.wildcards, \
992 ofp.OFPFW_NW_TOS, \
993 1 \
994 )
995 result.match.wildcards = wildcard_set(result.match.wildcards, \
996 ofp.OFPFW_TP_SRC, \
997 1 \
998 )
999 result.match.wildcards = wildcard_set(result.match.wildcards, \
1000 ofp.OFPFW_TP_DST, \
1001 1 \
1002 )
Howard Persh07d99e62012-04-09 15:26:57 -07001003 result.match.wildcards = wildcard_set(result.match.wildcards, \
1004 ofp.OFPFW_NW_SRC_MASK, \
1005 32 \
1006 )
1007 result.match.wildcards = wildcard_set(result.match.wildcards, \
1008 ofp.OFPFW_NW_DST_MASK, \
1009 32 \
1010 )
1011 result.match.wildcards = wildcard_set(result.match.wildcards, \
1012 ofp.OFPFW_NW_PROTO, \
1013 1 \
1014 )
1015
rootf6af1672012-04-06 09:46:29 -07001016 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
1017 or result.match.nw_proto not in [1, 6, 17]:
Howard Persh3340d452012-04-06 16:45:21 -07001018 # nw_proto is wildcarded, or specified as something other than ICMP,
1019 # TCP or UDP
rootf6af1672012-04-06 09:46:29 -07001020 # => tp_src and tp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001021 result.match.wildcards = wildcard_set(result.match.wildcards, \
1022 ofp.OFPFW_TP_SRC, \
1023 1 \
1024 )
1025 result.match.wildcards = wildcard_set(result.match.wildcards, \
1026 ofp.OFPFW_TP_DST, \
1027 1 \
1028 )
rootf6af1672012-04-06 09:46:29 -07001029 return result
1030
Howard Persh680b92a2012-03-31 13:34:35 -07001031 # Overlap check
1032 # delf == True <=> Check for delete overlap, else add overlap
1033 # "Add overlap" is defined as there exists a packet that could match both the
1034 # receiver and argument flowspecs
1035 # "Delete overlap" is defined as the specificity of the argument flowspec
1036 # is greater than or equal to the specificity of the receiver flowspec
1037 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -07001038 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
1039 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001040 if self.match.in_port != x.match.in_port:
1041 return False # Both specified, and not equal
1042 elif delf:
1043 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001044 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
1045 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001046 if self.match.dl_vlan != x.match.dl_vlan:
1047 return False # Both specified, and not equal
1048 elif delf:
1049 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001050 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
1051 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001052 if self.match.dl_src != x.match.dl_src:
1053 return False # Both specified, and not equal
1054 elif delf:
1055 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001056 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
1057 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001058 if self.match.dl_dst != x.match.dl_dst:
1059 return False # Both specified, and not equal
1060 elif delf:
1061 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001062 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
1063 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001064 if self.match.dl_type != x.match.dl_type:
1065 return False # Both specified, and not equal
1066 elif delf:
1067 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -07001068 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
1069 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001070 if self.match.nw_proto != x.match.nw_proto:
1071 return False # Both specified, and not equal
1072 elif delf:
1073 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001074 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
1075 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001076 if self.match.tp_src != x.match.tp_src:
1077 return False # Both specified, and not equal
1078 elif delf:
1079 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001080 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
1081 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001082 if self.match.tp_dst != x.match.tp_dst:
1083 return False # Both specified, and not equal
1084 elif delf:
1085 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001086 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
1087 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001088 if delf and na < nb:
1089 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001090 if (na < 32 and nb < 32):
1091 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1092 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -07001093 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -07001094 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
1095 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001096 if delf and na < nb:
1097 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001098 if (na < 32 and nb < 32):
1099 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1100 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
rootf6af1672012-04-06 09:46:29 -07001101 return False # Overlapping bits not equal
1102 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
1103 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001104 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
1105 return False # Both specified, and not equal
1106 elif delf:
1107 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001108 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
1109 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001110 if self.match.nw_tos != x.match.nw_tos:
1111 return False # Both specified, and not equal
1112 elif delf:
1113 return False # Receiver more specific
1114 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -07001115
1116 def to_flow_mod_msg(self, msg):
1117 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -07001118 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001119 msg.idle_timeout = self.idle_timeout
1120 msg.hard_timeout = self.hard_timeout
1121 msg.priority = self.priority
1122 msg.actions = self.actions
1123 return msg
1124
1125 def from_flow_stat(self, msg):
1126 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -07001127 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001128 self.idle_timeout = msg.idle_timeout
1129 self.hard_timeout = msg.hard_timeout
1130 self.priority = msg.priority
1131 self.actions = msg.actions
1132
rootf6af1672012-04-06 09:46:29 -07001133 def from_flow_rem(self, msg):
1134 self.match = msg.match
1135 self.idle_timeout = msg.idle_timeout
1136 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -07001137
Howard Pershc7963582012-03-29 10:02:59 -07001138
rootf6af1672012-04-06 09:46:29 -07001139class Flow_Tbl:
1140 def clear(self):
1141 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001142
rootf6af1672012-04-06 09:46:29 -07001143 def __init__(self):
1144 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001145
rootf6af1672012-04-06 09:46:29 -07001146 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001147 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001148
1149 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001150 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001151
1152 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001153 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001154
1155 def values(self):
1156 return self.dict.values()
1157
1158 def count(self):
1159 return len(self.dict)
1160
Ed Swierk99a74de2012-08-22 06:40:54 -07001161 def rand(self, wildcards_force, sw, fi, num_flows):
rootf6af1672012-04-06 09:46:29 -07001162 self.clear()
1163 i = 0
1164 tbl = 0
1165 j = 0
1166 while i < num_flows:
1167 fc = Flow_Cfg()
1168 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001169 wildcards_force, \
rootf6af1672012-04-06 09:46:29 -07001170 sw.tbl_stats.stats[tbl].wildcards, \
1171 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001172 sw.valid_ports, \
1173 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001174 )
1175 fc = fc.canonical()
1176 if self.find(fc):
1177 continue
1178 fc.send_rem = False
1179 self.insert(fc)
1180 i = i + 1
1181 j = j + 1
1182 if j >= sw.tbl_stats.stats[tbl].max_entries:
1183 tbl = tbl + 1
1184 j = 0
1185
1186
1187class Switch:
1188 # Members:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001189 # controller - switch's test controller
1190 # sw_features - switch's OFPT_FEATURES_REPLY message
1191 # valid_ports - list of valid port numbers
1192 # valid_queues - list of valid [port, queue] pairs
1193 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1194 # queue_stats - switch's OFPT_STATS_REPLY message, for queue stats request
1195 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1196 # flow_tbl - (test's idea of) switch's flow table
rootf6af1672012-04-06 09:46:29 -07001197
1198 def __init__(self):
Howard Persh8d21c1f2012-04-20 15:57:29 -07001199 self.controller = None
1200 self.sw_features = None
1201 self.valid_ports = []
1202 self.valid_queues = []
1203 self.tbl_stats = None
1204 self.flow_stats = None
1205 self.flow_tbl = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001206 self.error_msgs = []
1207 self.removed_msgs = []
1208
1209 def error_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001210 logging.info("Got an ERROR message, type=%d, code=%d" \
Ed Swierk99a74de2012-08-22 06:40:54 -07001211 % (msg.type, msg.code) \
1212 )
Rich Lane9a003812012-10-04 17:17:59 -07001213 logging.info("Message header:")
1214 logging.info(msg.header.show())
Ed Swierk99a74de2012-08-22 06:40:54 -07001215 self.error_msgs.append(msg)
1216
1217 def removed_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001218 logging.info("Got a REMOVED message")
1219 logging.info("Message header:")
1220 logging.info(msg.header.show())
Ed Swierk99a74de2012-08-22 06:40:54 -07001221 self.removed_msgs.append(msg)
rootf6af1672012-04-06 09:46:29 -07001222
Howard Persh3340d452012-04-06 16:45:21 -07001223 def controller_set(self, controller):
1224 self.controller = controller
1225 # Register error message handler
Ed Swierk99a74de2012-08-22 06:40:54 -07001226 self.error_msgs = []
1227 self.removed_msgs = []
1228 controller.register(ofp.OFPT_ERROR, self.error_handler)
1229 controller.register(ofp.OFPT_FLOW_REMOVED, self.removed_handler)
Howard Persh3340d452012-04-06 16:45:21 -07001230
rootf6af1672012-04-06 09:46:29 -07001231 def features_get(self):
1232 # Get switch features
1233 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001234 (self.sw_features, pkt) = self.controller.transact(request)
rootf6af1672012-04-06 09:46:29 -07001235 if self.sw_features is None:
Rich Lane9a003812012-10-04 17:17:59 -07001236 logging.error("Get switch features failed")
rootf6af1672012-04-06 09:46:29 -07001237 return False
1238 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Rich Lane9a003812012-10-04 17:17:59 -07001239 logging.info("Ports reported by switch:")
1240 logging.info(self.valid_ports)
Rich Lane477f4812012-10-04 22:49:00 -07001241 ports_override = test_param_get(config, "ports", [])
Howard Persh8d21c1f2012-04-20 15:57:29 -07001242 if ports_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001243 logging.info("Overriding ports to:")
1244 logging.info(ports_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001245 self.valid_ports = ports_override
1246
Howard Persh3340d452012-04-06 16:45:21 -07001247 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1248 # is that universal?
1249
1250 # TBD - There seems to be variability in which switches support which
1251 # ports; need to sort that out
1252 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1253# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1254# ofp.OFPP_NORMAL, \
1255# ofp.OFPP_FLOOD, \
1256# ofp.OFPP_ALL, \
1257# ofp.OFPP_CONTROLLER \
1258# ] \
1259# )
Rich Lane9a003812012-10-04 17:17:59 -07001260 logging.info("Supported actions reported by switch:")
1261 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001262 % (self.sw_features.actions, \
1263 actions_bmap_to_str(self.sw_features.actions) \
1264 ) \
1265 )
Rich Lane477f4812012-10-04 22:49:00 -07001266 actions_override = test_param_get(config, "actions", -1)
Howard Persh07d99e62012-04-09 15:26:57 -07001267 if actions_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001268 logging.info("Overriding supported actions to:")
1269 logging.info(actions_bmap_to_str(actions_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001270 self.sw_features.actions = actions_override
rootf6af1672012-04-06 09:46:29 -07001271 return True
1272
1273 def tbl_stats_get(self):
1274 # Get table stats
Howard Persh680b92a2012-03-31 13:34:35 -07001275 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001276 (self.tbl_stats, pkt) = self.controller.transact(request)
Howard Persh07d99e62012-04-09 15:26:57 -07001277 if self.tbl_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001278 logging.error("Get table stats failed")
Howard Persh07d99e62012-04-09 15:26:57 -07001279 return False
Howard Persh8d21c1f2012-04-20 15:57:29 -07001280 i = 0
Howard Persh07d99e62012-04-09 15:26:57 -07001281 for ts in self.tbl_stats.stats:
Rich Lane9a003812012-10-04 17:17:59 -07001282 logging.info("Supported wildcards for table %d reported by switch:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001283 % (i)
1284 )
Rich Lane9a003812012-10-04 17:17:59 -07001285 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001286 % (ts.wildcards, \
1287 wildcards_to_str(ts.wildcards) \
1288 ) \
1289 )
Rich Lane477f4812012-10-04 22:49:00 -07001290 wildcards_override = test_param_get(config, "wildcards", -1)
Howard Persh07d99e62012-04-09 15:26:57 -07001291 if wildcards_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001292 logging.info("Overriding supported wildcards for table %d to:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001293 % (i)
1294 )
Rich Lane9a003812012-10-04 17:17:59 -07001295 logging.info(wildcards_to_str(wildcards_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001296 ts.wildcards = wildcards_override
Howard Persh8d21c1f2012-04-20 15:57:29 -07001297 i = i + 1
Howard Persh07d99e62012-04-09 15:26:57 -07001298 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001299
Howard Persh8d21c1f2012-04-20 15:57:29 -07001300 def queue_stats_get(self):
1301 # Get queue stats
1302 request = message.queue_stats_request()
1303 request.port_no = ofp.OFPP_ALL
1304 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001305 (self.queue_stats, pkt) = self.controller.transact(request)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001306 if self.queue_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001307 logging.error("Get queue stats failed")
Howard Persh8d21c1f2012-04-20 15:57:29 -07001308 return False
1309 self.valid_queues = map(lambda x: (x.port_no, x.queue_id), \
1310 self.queue_stats.stats \
1311 )
Rich Lane9a003812012-10-04 17:17:59 -07001312 logging.info("(Port, queue) pairs reported by switch:")
1313 logging.info(self.valid_queues)
Rich Lane477f4812012-10-04 22:49:00 -07001314 queues_override = test_param_get(config, "queues", [])
Howard Persh8d21c1f2012-04-20 15:57:29 -07001315 if queues_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001316 logging.info("Overriding (port, queue) pairs to:")
1317 logging.info(queues_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001318 self.valid_queues = queues_override
1319 return True
1320
1321 def connect(self, controller):
1322 # Connect to controller, and get all switch capabilities
1323 self.controller_set(controller)
1324 return (self.features_get() \
1325 and self.tbl_stats_get() \
1326 and self.queue_stats_get() \
1327 )
1328
Howard Pershc1199d52012-04-11 14:21:32 -07001329 def flow_stats_get(self, limit = 10000):
rootf6af1672012-04-06 09:46:29 -07001330 request = message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -07001331 query_match = ofp.ofp_match()
1332 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001333 request.match = query_match
1334 request.table_id = 0xff
1335 request.out_port = ofp.OFPP_NONE;
Howard Persh3340d452012-04-06 16:45:21 -07001336 if self.controller.message_send(request) == -1:
1337 return False
1338 # <TBD>
1339 # Glue together successive reponse messages for stats reply.
1340 # Looking at the "more" flag and performing re-assembly
1341 # should be a part of the infrastructure.
1342 # </TBD>
1343 n = 0
1344 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -07001345 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY)
Howard Persh3340d452012-04-06 16:45:21 -07001346 if resp is None:
Howard Pershc1199d52012-04-11 14:21:32 -07001347 return False # Did not get expected response
Howard Persh3340d452012-04-06 16:45:21 -07001348 if n == 0:
1349 self.flow_stats = resp
1350 else:
1351 self.flow_stats.stats.extend(resp.stats)
1352 n = n + 1
Howard Pershc1199d52012-04-11 14:21:32 -07001353 if len(self.flow_stats.stats) > limit:
Rich Lane9a003812012-10-04 17:17:59 -07001354 logging.error("Too many flows returned")
Howard Pershc1199d52012-04-11 14:21:32 -07001355 return False
1356 if (resp.flags & 1) == 0:
1357 break # No more responses expected
Howard Persh3340d452012-04-06 16:45:21 -07001358 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001359
rootf6af1672012-04-06 09:46:29 -07001360 def flow_add(self, flow_cfg, overlapf = False):
Howard Persh680b92a2012-03-31 13:34:35 -07001361 flow_mod_msg = message.flow_mod()
1362 flow_mod_msg.command = ofp.OFPFC_ADD
1363 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001364 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001365 if overlapf:
1366 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001367 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001368 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Howard Persh07d99e62012-04-09 15:26:57 -07001369 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001370 logging.info("Sending flow_mod(add), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001371 % (flow_mod_msg.header.xid)
1372 )
rootf6af1672012-04-06 09:46:29 -07001373 return (self.controller.message_send(flow_mod_msg) != -1)
Howard Persh680b92a2012-03-31 13:34:35 -07001374
rootf6af1672012-04-06 09:46:29 -07001375 def flow_mod(self, flow_cfg, strictf):
Howard Persh680b92a2012-03-31 13:34:35 -07001376 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001377 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf \
1378 else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -07001379 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001380 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001381 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001382 logging.info("Sending flow_mod(mod), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001383 % (flow_mod_msg.header.xid)
1384 )
rootf6af1672012-04-06 09:46:29 -07001385 return (self.controller.message_send(flow_mod_msg) != -1)
1386
1387 def flow_del(self, flow_cfg, strictf):
1388 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001389 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf \
1390 else ofp.OFPFC_DELETE
rootf6af1672012-04-06 09:46:29 -07001391 flow_mod_msg.buffer_id = 0xffffffff
1392 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001393 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001394 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001395 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001396 logging.info("Sending flow_mod(del), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001397 % (flow_mod_msg.header.xid)
1398 )
rootf6af1672012-04-06 09:46:29 -07001399 return (self.controller.message_send(flow_mod_msg) != -1)
1400
1401 def barrier(self):
1402 barrier = message.barrier_request()
Dan Talaycoc689a792012-09-28 14:22:53 -07001403 (resp, pkt) = self.controller.transact(barrier, 30)
rootf6af1672012-04-06 09:46:29 -07001404 return (resp is not None)
1405
Howard Persh3340d452012-04-06 16:45:21 -07001406 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001407 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001408 logging.info("Expecting %d error messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001409 num_got = len(self.error_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001410 logging.info("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001411 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001412 logging.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001413 result = False
1414 if num_exp == 0:
1415 return result
1416 elif num_exp == 1:
Rich Lane9a003812012-10-04 17:17:59 -07001417 logging.info("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001418 % (type, code) \
1419 )
1420 f = False
Ed Swierk99a74de2012-08-22 06:40:54 -07001421 for e in self.error_msgs:
Howard Persh3340d452012-04-06 16:45:21 -07001422 if e.type == type and e.code == code:
Rich Lane9a003812012-10-04 17:17:59 -07001423 logging.info("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001424 f = True
1425 if not f:
Rich Lane9a003812012-10-04 17:17:59 -07001426 logging.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001427 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001428 else:
Rich Lane9a003812012-10-04 17:17:59 -07001429 logging.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001430 result = False
1431 return result
1432
Howard Persh3340d452012-04-06 16:45:21 -07001433 def removed_verify(self, num_exp):
1434 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001435 logging.info("Expecting %d removed messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001436 num_got = len(self.removed_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001437 logging.info("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001438 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001439 logging.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001440 result = False
1441 if num_exp < 2:
1442 return result
Rich Lane9a003812012-10-04 17:17:59 -07001443 logging.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001444 return False
1445
Howard Persh5f3c83f2012-04-13 09:57:10 -07001446 # modf == True <=> Verify for flow modify, else for add/delete
1447 def flow_tbl_verify(self, modf = False):
rootf6af1672012-04-06 09:46:29 -07001448 result = True
1449
1450 # Verify flow count in switch
Rich Lane9a003812012-10-04 17:17:59 -07001451 logging.info("Reading table stats")
1452 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001453 if not self.tbl_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001454 logging.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001455 return False
1456 n = 0
1457 for ts in self.tbl_stats.stats:
1458 n = n + ts.active_count
Rich Lane9a003812012-10-04 17:17:59 -07001459 logging.info("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001460 % (n) \
1461 )
1462 if n != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001463 logging.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001464 result = False
1465
1466 # Read flows from switch
Rich Lane9a003812012-10-04 17:17:59 -07001467 logging.info("Retrieving flows from switch")
1468 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001469 if not self.flow_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001470 logging.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001471 return False
Rich Lane9a003812012-10-04 17:17:59 -07001472 logging.info("Retrieved %d flows" % (len(self.flow_stats.stats)))
rootf6af1672012-04-06 09:46:29 -07001473
1474 # Verify flows returned by switch
1475
1476 if len(self.flow_stats.stats) != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001477 logging.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001478 result = False
1479
Rich Lane9a003812012-10-04 17:17:59 -07001480 logging.info("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001481 for fc in self.flow_tbl.values():
1482 fc.matched = False
1483 for fs in self.flow_stats.stats:
1484 flow_in = Flow_Cfg()
1485 flow_in.from_flow_stat(fs)
Rich Lane9a003812012-10-04 17:17:59 -07001486 logging.info("Received flow:")
1487 logging.info(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001488 fc = self.flow_tbl.find(flow_in)
1489 if fc is None:
Rich Lane9a003812012-10-04 17:17:59 -07001490 logging.error("Received flow:")
1491 logging.error(str(flow_in))
1492 logging.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001493 result = False
1494 elif fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001495 logging.error("Received flow:")
1496 logging.error(str(flow_in))
1497 logging.error("re-matches defined flow:")
1498 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001499 result = False
1500 else:
Rich Lane9a003812012-10-04 17:17:59 -07001501 logging.info("matched")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001502 if modf:
1503 # Check for modify
1504
1505 if flow_in.cookie != fc.cookie:
Rich Lane9a003812012-10-04 17:17:59 -07001506 logging.warning("Defined flow:")
1507 logging.warning(str(fc))
1508 logging.warning("Received flow:")
1509 logging.warning(str(flow_in))
1510 logging.warning("cookies do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001511 if not flow_in.actions_equal(fc):
Rich Lane9a003812012-10-04 17:17:59 -07001512 logging.error("Defined flow:")
1513 logging.error(str(fc))
1514 logging.error("Received flow:")
1515 logging.error(str(flow_in))
1516 logging.error("actions do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001517 else:
1518 # Check for add/delete
1519
1520 if not flow_in == fc:
Rich Lane9a003812012-10-04 17:17:59 -07001521 logging.error("Defined flow:")
1522 logging.error(str(fc))
1523 logging.error("Received flow:")
1524 logging.error(str(flow_in))
1525 logging.error("non-key portions of flow do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001526 result = False
rootf6af1672012-04-06 09:46:29 -07001527 fc.matched = True
1528 for fc in self.flow_tbl.values():
1529 if not fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001530 logging.error("Defined flow:")
1531 logging.error(str(fc))
1532 logging.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001533 result = False
1534
1535 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001536
Howard Persh9cab4822012-09-11 17:08:40 -07001537 def settle(self):
1538 time.sleep(2)
1539
Howard Persh07d99e62012-04-09 15:26:57 -07001540# FLOW ADD 5
1541#
1542# OVERVIEW
1543# Add flows to switch, read back and verify flow configurations
1544#
1545# PURPOSE
1546# - Test acceptance of flow adds
1547# - Test ability of switch to process additions to flow table in random
1548# priority order
1549# - Test correctness of flow configuration responses
1550#
1551# PARAMETERS
1552#
1553# Name: num_flows
1554# Type: number
1555# Description:
1556# Number of flows to define; 0 => maximum number of flows, as determined
1557# from switch capabilities
1558# Default: 100
1559#
1560# PROCESS
1561# 1. Delete all flows from switch
1562# 2. Generate <num_flows> distinct flow configurations
1563# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1564# 4. Verify that no OFPT_ERROR responses were generated by switch
1565# 5. Retrieve flow stats from switch
1566# 6. Compare flow configurations returned by switch
1567# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1568# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001569
rootf6af1672012-04-06 09:46:29 -07001570class Flow_Add_5(basic.SimpleProtocol):
1571 """
1572 Test FLOW_ADD_5 from draft top-half test plan
1573
1574 INPUTS
1575 num_flows - Number of flows to generate
1576 """
Howard Persh680b92a2012-03-31 13:34:35 -07001577
rootf6af1672012-04-06 09:46:29 -07001578 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001579 logging.info("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001580
Rich Lane477f4812012-10-04 22:49:00 -07001581 num_flows = test_param_get(config, "num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001582
Howard Pershc7963582012-03-29 10:02:59 -07001583 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001584
Rich Lane9a003812012-10-04 17:17:59 -07001585 logging.info("Deleting all flows from switch")
1586 rc = delete_all_flows(self.controller)
Howard Pershc7963582012-03-29 10:02:59 -07001587 self.assertEqual(rc, 0, "Failed to delete all flows")
1588
rootf6af1672012-04-06 09:46:29 -07001589 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001590
rootf6af1672012-04-06 09:46:29 -07001591 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001592 self.assertTrue(sw.connect(self.controller), \
1593 "Failed to connect to switch" \
1594 )
Howard Pershc7963582012-03-29 10:02:59 -07001595
rootf6af1672012-04-06 09:46:29 -07001596 if num_flows == 0:
1597 # Number of flows requested was 0
1598 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001599
rootf6af1672012-04-06 09:46:29 -07001600 for ts in sw.tbl_stats.stats:
1601 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001602
Rich Lane9a003812012-10-04 17:17:59 -07001603 logging.info("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001604
1605 # Dream up some flow information, i.e. space to chose from for
1606 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001607
rootf6af1672012-04-06 09:46:29 -07001608 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001609 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001610
rootf6af1672012-04-06 09:46:29 -07001611 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001612
rootf6af1672012-04-06 09:46:29 -07001613 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001614 ft.rand(required_wildcards(self), sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001615
rootf6af1672012-04-06 09:46:29 -07001616 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001617
Rich Lane9a003812012-10-04 17:17:59 -07001618 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001619 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001620 logging.info("Adding flow:")
1621 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001622 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001623
rootf6af1672012-04-06 09:46:29 -07001624 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001625
rootf6af1672012-04-06 09:46:29 -07001626 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001627
rootf6af1672012-04-06 09:46:29 -07001628 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001629
Howard Persh9cab4822012-09-11 17:08:40 -07001630 sw.settle() # Allow switch to settle and generate any notifications
1631
rootf6af1672012-04-06 09:46:29 -07001632 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001633
rootf6af1672012-04-06 09:46:29 -07001634 if not sw.errors_verify(0):
1635 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001636
rootf6af1672012-04-06 09:46:29 -07001637 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001638
rootf6af1672012-04-06 09:46:29 -07001639 sw.flow_tbl = ft
1640 if not sw.flow_tbl_verify():
1641 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001642
rootf6af1672012-04-06 09:46:29 -07001643 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001644 logging.info("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001645
Howard Pershc7963582012-03-29 10:02:59 -07001646
Howard Persh07d99e62012-04-09 15:26:57 -07001647# FLOW ADD 5_1
1648#
1649# OVERVIEW
1650# Verify handling of non-canonical flows
1651#
1652# PURPOSE
1653# - Test that switch detects and correctly responds to a non-canonical flow
1654# definition. A canonical flow is one that satisfies all match qualifier
1655# dependencies; a non-canonical flow is one that does not.
1656#
1657# PARAMETERS
1658# - None
1659#
1660# PROCESS
1661# 1. Delete all flows from switch
1662# 2. Generate 1 flow definition, which is different from its canonicalization
1663# 3. Send flow to switch
1664# 4. Retrieve flow from switch
1665# 5. Compare returned flow to canonical form of defined flow
1666# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1667
1668# Disabled.
1669# Should be DUT dependent.
Howard Persh07d99e62012-04-09 15:26:57 -07001670
rootf6af1672012-04-06 09:46:29 -07001671class Flow_Add_5_1(basic.SimpleProtocol):
1672 """
1673 Test FLOW_ADD_5.1 from draft top-half test plan
1674
1675 INPUTS
1676 None
1677 """
Rich Laned1d9c282012-10-04 22:07:10 -07001678
1679 priority = -1
rootf6af1672012-04-06 09:46:29 -07001680
1681 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001682 logging.info("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001683
Rich Lane477f4812012-10-04 22:49:00 -07001684 num_flows = test_param_get(config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001685
1686 # Clear all flows from switch
1687
Rich Lane9a003812012-10-04 17:17:59 -07001688 logging.info("Deleting all flows from switch")
1689 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001690 self.assertEqual(rc, 0, "Failed to delete all flows")
1691
1692 # Get switch capabilites
1693
rootf6af1672012-04-06 09:46:29 -07001694 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001695 self.assertTrue(sw.connect(self.controller), \
1696 "Failed to connect to switch" \
1697 )
rootf6af1672012-04-06 09:46:29 -07001698
1699 # Dream up some flow information, i.e. space to chose from for
1700 # random flow parameter generation
1701
1702 fi = Flow_Info()
1703 fi.rand(10)
1704
1705 # Dream up a flow config that will be canonicalized by the switch
1706
1707 while True:
1708 fc = Flow_Cfg()
1709 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001710 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07001711 sw.tbl_stats.stats[0].wildcards, \
1712 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001713 sw.valid_ports, \
1714 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001715 )
1716 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001717 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001718 break
1719
1720 ft = Flow_Tbl()
1721 ft.insert(fcc)
1722
1723 # Send it to the switch
1724
Rich Lane9a003812012-10-04 17:17:59 -07001725 logging.info("Sending flow add to switch:")
1726 logging.info(str(fc))
1727 logging.info("should be canonicalized as:")
1728 logging.info(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001729 fc.send_rem = False
1730 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1731
1732 # Do barrier, to make sure all flows are in
1733
1734 self.assertTrue(sw.barrier(), "Barrier failed")
1735
1736 result = True
1737
Howard Persh9cab4822012-09-11 17:08:40 -07001738 sw.settle() # Allow switch to settle and generate any notifications
1739
rootf6af1672012-04-06 09:46:29 -07001740 # Check for any error messages
1741
1742 if not sw.errors_verify(0):
1743 result = False
1744
1745 # Verify flow table
1746
1747 sw.flow_tbl = ft
1748 if not sw.flow_tbl_verify():
1749 result = False
1750
1751 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001752 logging.info("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001753
1754
Howard Persh07d99e62012-04-09 15:26:57 -07001755# FLOW ADD 6
1756#
1757# OVERVIEW
1758# Test flow table capacity
1759#
1760# PURPOSE
1761# - Test switch can accept as many flow definitions as it claims
1762# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1763# - Test that attempting to create flows beyond capacity does not corrupt
1764# flow table
1765#
1766# PARAMETERS
1767# None
1768#
1769# PROCESS
1770# 1. Delete all flows from switch
1771# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1772# to determine flow table size, N
1773# 3. Generate (N + 1) distinct flow configurations
1774# 4. Send N flow adds to switch, for flows generated in step 3 above
1775# 5. Verify flow table in switch
1776# 6. Send one more flow add to switch
1777# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1778# response was generated by switch, for last flow mod sent
1779# 7. Retrieve flow stats from switch
1780# 8. Verify flow table in switch
1781# 9. Test PASSED iff:
1782# - error message received, for correct flow
1783# - last flow definition sent to switch is not in flow table
1784# else test FAILED
1785
Howard Persh3340d452012-04-06 16:45:21 -07001786# Disabled because of bogus capacity reported by OVS.
1787# Should be DUT dependent.
Howard Persh3340d452012-04-06 16:45:21 -07001788
rootf6af1672012-04-06 09:46:29 -07001789class Flow_Add_6(basic.SimpleProtocol):
1790 """
1791 Test FLOW_ADD_6 from draft top-half test plan
1792
1793 INPUTS
1794 num_flows - Number of flows to generate
1795 """
Howard Pershc7963582012-03-29 10:02:59 -07001796
Rich Laned1d9c282012-10-04 22:07:10 -07001797 priority = -1
1798
Howard Pershc7963582012-03-29 10:02:59 -07001799 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001800 logging.info("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001801
rootf6af1672012-04-06 09:46:29 -07001802 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001803
Rich Lane9a003812012-10-04 17:17:59 -07001804 logging.info("Deleting all flows from switch")
1805 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001806 self.assertEqual(rc, 0, "Failed to delete all flows")
1807
1808 # Get switch capabilites
1809
rootf6af1672012-04-06 09:46:29 -07001810 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001811 self.assertTrue(sw.connect(self.controller), \
1812 "Failed to connect to switch" \
1813 )
rootf6af1672012-04-06 09:46:29 -07001814
root2843d2b2012-04-06 10:27:46 -07001815 num_flows = 0
rootf6af1672012-04-06 09:46:29 -07001816 for ts in sw.tbl_stats.stats:
1817 num_flows = num_flows + ts.max_entries
1818
Rich Lane9a003812012-10-04 17:17:59 -07001819 logging.info("Switch capacity is %d flows" % (num_flows))
1820 logging.info("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001821
1822 # Dream up some flow information, i.e. space to chose from for
1823 # random flow parameter generation
1824
1825 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001826 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001827
1828 # Create a flow table, to switch's capacity
1829
1830 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001831 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07001832
1833 # Send flow table to switch
1834
Rich Lane9a003812012-10-04 17:17:59 -07001835 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001836 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001837 logging.info("Adding flow:")
1838 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001839 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1840
1841 # Do barrier, to make sure all flows are in
1842
1843 self.assertTrue(sw.barrier(), "Barrier failed")
1844
1845 result = True
1846
Howard Persh9cab4822012-09-11 17:08:40 -07001847 sw.settle() # Allow switch to settle and generate any notifications
1848
rootf6af1672012-04-06 09:46:29 -07001849 # Check for any error messages
1850
1851 if not sw.errors_verify(0):
1852 result = False
1853
1854 # Dream up one more flow
1855
Rich Lane9a003812012-10-04 17:17:59 -07001856 logging.info("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001857 while True:
1858 fc = Flow_Cfg()
1859 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001860 required_wildcards(self), \
Howard Persh07d99e62012-04-09 15:26:57 -07001861 sw.tbl_stats.stats[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001862 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001863 sw.valid_ports, \
1864 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001865 )
1866 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001867 if not ft.find(fc):
1868 break
rootf6af1672012-04-06 09:46:29 -07001869
1870 # Send one-more flow
1871
1872 fc.send_rem = False
Rich Lane9a003812012-10-04 17:17:59 -07001873 logging.info("Sending flow add switch")
1874 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001875 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1876
1877 # Do barrier, to make sure all flows are in
1878
1879 self.assertTrue(sw.barrier(), "Barrier failed")
1880
Howard Persh9cab4822012-09-11 17:08:40 -07001881 sw.settle() # Allow switch to settle and generate any notifications
1882
rootf6af1672012-04-06 09:46:29 -07001883 # Check for expected error message
1884
1885 if not sw.errors_verify(1, \
1886 ofp.OFPET_FLOW_MOD_FAILED, \
1887 ofp.OFPFMFC_ALL_TABLES_FULL \
1888 ):
1889 result = False
1890
1891 # Verify flow table
1892
1893 sw.flow_tbl = ft
1894 if not sw.flow_tbl_verify():
1895 result = False
1896
1897 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001898 logging.info("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001899
1900
Howard Persh07d99e62012-04-09 15:26:57 -07001901# FLOW ADD 7
1902#
1903# OVERVIEW
1904# Test flow redefinition
1905#
1906# PURPOSE
1907# Verify that successive flow adds with same priority and match criteria
1908# overwrite in flow table
1909#
1910# PARAMETERS
1911# None
1912#
1913# PROCESS
1914# 1. Delete all flows from switch
1915# 2. Generate flow definition F1
1916# 3. Generate flow definition F2, with same key (priority and match) as F1,
1917# but with different actions
1918# 4. Send flow adds for F1 and F2 to switch
1919# 5. Verify flow definitions in switch
1920# 6. Test PASSED iff 1 flow returned by switch, matching configuration of F2;
1921# else test FAILED
1922
rootf6af1672012-04-06 09:46:29 -07001923class Flow_Add_7(basic.SimpleProtocol):
1924 """
1925 Test FLOW_ADD_7 from draft top-half test plan
1926
1927 INPUTS
1928 None
1929 """
1930
1931 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001932 logging.info("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001933
1934 # Clear all flows from switch
1935
Rich Lane9a003812012-10-04 17:17:59 -07001936 logging.info("Deleting all flows from switch")
1937 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001938 self.assertEqual(rc, 0, "Failed to delete all flows")
1939
1940 # Get switch capabilites
1941
rootf6af1672012-04-06 09:46:29 -07001942 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001943 self.assertTrue(sw.connect(self.controller), \
1944 "Failed to connect to switch" \
1945 )
rootf6af1672012-04-06 09:46:29 -07001946
1947 # Dream up some flow information, i.e. space to chose from for
1948 # random flow parameter generation
1949
1950 fi = Flow_Info()
1951 fi.rand(10)
1952
1953 # Dream up a flow config
1954
1955 fc = Flow_Cfg()
1956 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001957 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07001958 sw.tbl_stats.stats[0].wildcards, \
1959 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001960 sw.valid_ports, \
1961 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001962 )
1963 fc = fc.canonical()
1964
1965 # Send it to the switch
1966
Rich Lane9a003812012-10-04 17:17:59 -07001967 logging.info("Sending flow add to switch:")
1968 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001969 ft = Flow_Tbl()
1970 fc.send_rem = False
1971 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1972 ft.insert(fc)
1973
1974 # Dream up some different actions, with the same flow key
1975
1976 fc2 = copy.deepcopy(fc)
1977 while True:
1978 fc2.rand_mod(fi, \
1979 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001980 sw.valid_ports, \
1981 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001982 )
1983 if fc2 != fc:
1984 break
1985
1986 # Send that to the switch
1987
Rich Lane9a003812012-10-04 17:17:59 -07001988 logging.info("Sending flow add to switch:")
1989 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07001990 fc2.send_rem = False
1991 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
1992 ft.insert(fc2)
1993
1994 # Do barrier, to make sure all flows are in
1995
1996 self.assertTrue(sw.barrier(), "Barrier failed")
1997
1998 result = True
1999
Howard Persh9cab4822012-09-11 17:08:40 -07002000 sw.settle() # Allow switch to settle and generate any notifications
2001
rootf6af1672012-04-06 09:46:29 -07002002 # Check for any error messages
2003
2004 if not sw.errors_verify(0):
2005 result = False
2006
2007 # Verify flow table
2008
2009 sw.flow_tbl = ft
2010 if not sw.flow_tbl_verify():
2011 result = False
2012
2013 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002014 logging.info("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002015
2016
Howard Persh07d99e62012-04-09 15:26:57 -07002017# FLOW ADD 8
2018#
2019# OVERVIEW
2020# Add overlapping flows to switch, verify that overlapping flows are rejected
2021#
2022# PURPOSE
2023# - Test detection of overlapping flows by switch
2024# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
2025# - Test rejection of overlapping flows
2026# - Test defining overlapping flows does not corrupt flow table
2027#
2028# PARAMETERS
2029# None
2030#
2031# PROCESS
2032# 1. Delete all flows from switch
2033# 2. Generate flow definition F1
2034# 3. Generate flow definition F2, with key overlapping F1
2035# 4. Send flow add to switch, for F1
2036# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
2037# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
2038# was generated by switch
2039# 7. Verifiy flows configured in swtich
2040# 8. Test PASSED iff:
2041# - error message received, for overlapping flow
2042# - overlapping flow is not in flow table
2043# else test FAILED
2044
rootf6af1672012-04-06 09:46:29 -07002045class Flow_Add_8(basic.SimpleProtocol):
2046 """
2047 Test FLOW_ADD_8 from draft top-half test plan
2048
2049 INPUTS
2050 None
2051 """
2052
2053 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002054 logging.info("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002055
2056 # Clear all flows from switch
2057
Rich Lane9a003812012-10-04 17:17:59 -07002058 logging.info("Deleting all flows from switch")
2059 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002060 self.assertEqual(rc, 0, "Failed to delete all flows")
2061
2062 # Get switch capabilites
2063
rootf6af1672012-04-06 09:46:29 -07002064 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002065 self.assertTrue(sw.connect(self.controller), \
2066 "Failed to connect to switch" \
2067 )
rootf6af1672012-04-06 09:46:29 -07002068
2069 # Dream up some flow information, i.e. space to chose from for
2070 # random flow parameter generation
2071
2072 fi = Flow_Info()
2073 fi.rand(10)
2074
2075 # Dream up a flow config, with at least 1 qualifier specified
2076
2077 fc = Flow_Cfg()
2078 while True:
2079 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002080 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002081 sw.tbl_stats.stats[0].wildcards, \
2082 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002083 sw.valid_ports, \
2084 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002085 )
2086 fc = fc.canonical()
2087 if fc.match.wildcards != ofp.OFPFW_ALL:
2088 break
2089
2090 # Send it to the switch
2091
Rich Lane9a003812012-10-04 17:17:59 -07002092 logging.info("Sending flow add to switch:")
2093 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002094 ft = Flow_Tbl()
2095 fc.send_rem = False
2096 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2097 ft.insert(fc)
2098
2099 # Wildcard out one qualifier that was specified, to create an
2100 # overlapping flow
2101
2102 fc2 = copy.deepcopy(fc)
2103 for wi in shuffle(range(len(all_wildcards_list))):
2104 w = all_wildcards_list[wi]
2105 if (fc2.match.wildcards & w) == 0:
2106 break
2107 if w == ofp.OFPFW_NW_SRC_MASK:
2108 w = ofp.OFPFW_NW_SRC_ALL
2109 wn = "OFPFW_NW_SRC"
2110 elif w == ofp.OFPFW_NW_DST_MASK:
2111 w = ofp.OFPFW_NW_DST_ALL
2112 wn = "OFPFW_NW_DST"
2113 else:
2114 wn = all_wildcard_names[w]
Rich Lane9a003812012-10-04 17:17:59 -07002115 logging.info("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07002116 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07002117 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07002118
2119 # Send that to the switch, with overlap checking
2120
Rich Lane9a003812012-10-04 17:17:59 -07002121 logging.info("Sending flow add to switch:")
2122 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002123 fc2.send_rem = False
2124 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
2125
2126 # Do barrier, to make sure all flows are in
2127 self.assertTrue(sw.barrier(), "Barrier failed")
2128
2129 result = True
2130
Howard Persh9cab4822012-09-11 17:08:40 -07002131 sw.settle() # Allow switch to settle and generate any notifications
2132
rootf6af1672012-04-06 09:46:29 -07002133 # Check for expected error message
2134
2135 if not sw.errors_verify(1, \
2136 ofp.OFPET_FLOW_MOD_FAILED, \
2137 ofp.OFPFMFC_OVERLAP \
2138 ):
2139 result = False
2140
2141 # Verify flow table
2142
2143 sw.flow_tbl = ft
2144 if not sw.flow_tbl_verify():
2145 result = False
2146
2147 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002148 logging.info("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002149
2150
Howard Persh07d99e62012-04-09 15:26:57 -07002151# FLOW MODIFY 1
2152#
2153# OVERVIEW
2154# Strict modify of single existing flow
2155#
2156# PURPOSE
2157# - Verify that strict flow modify operates only on specified flow
2158# - Verify that flow is correctly modified
2159#
2160# PARAMETERS
2161# None
2162#
2163# PROCESS
2164# 1. Delete all flows from switch
2165# 2. Generate 1 flow F
2166# 3. Send flow add to switch, for flow F
2167# 4. Generate new action list for flow F, yielding F'
2168# 5. Send strict flow modify to switch, for flow F'
2169# 6. Verify flow table in switch
2170# 7. Test PASSED iff flow returned by switch is F'; else FAILED
2171
rootf6af1672012-04-06 09:46:29 -07002172class Flow_Mod_1(basic.SimpleProtocol):
2173 """
2174 Test FLOW_MOD_1 from draft top-half test plan
2175
2176 INPUTS
2177 None
2178 """
2179
2180 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002181 logging.info("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002182
2183 # Clear all flows from switch
2184
Rich Lane9a003812012-10-04 17:17:59 -07002185 logging.info("Deleting all flows from switch")
2186 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002187 self.assertEqual(rc, 0, "Failed to delete all flows")
2188
2189 # Get switch capabilites
2190
rootf6af1672012-04-06 09:46:29 -07002191 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002192 self.assertTrue(sw.connect(self.controller), \
2193 "Failed to connect to switch" \
2194 )
rootf6af1672012-04-06 09:46:29 -07002195
2196 # Dream up some flow information, i.e. space to chose from for
2197 # random flow parameter generation
2198
2199 fi = Flow_Info()
2200 fi.rand(10)
2201
2202 # Dream up a flow config
2203
2204 fc = Flow_Cfg()
2205 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002206 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002207 sw.tbl_stats.stats[0].wildcards, \
2208 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002209 sw.valid_ports, \
2210 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002211 )
2212 fc = fc.canonical()
2213
2214 # Send it to the switch
2215
Rich Lane9a003812012-10-04 17:17:59 -07002216 logging.info("Sending flow add to switch:")
2217 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002218 ft = Flow_Tbl()
2219 fc.send_rem = False
2220 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2221 ft.insert(fc)
2222
2223 # Dream up some different actions, with the same flow key
2224
2225 fc2 = copy.deepcopy(fc)
2226 while True:
2227 fc2.rand_mod(fi, \
2228 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002229 sw.valid_ports, \
2230 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002231 )
2232 if fc2 != fc:
2233 break
2234
2235 # Send that to the switch
2236
Rich Lane9a003812012-10-04 17:17:59 -07002237 logging.info("Sending strict flow mod to switch:")
2238 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002239 fc2.send_rem = False
2240 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2241 ft.insert(fc2)
2242
2243 # Do barrier, to make sure all flows are in
2244
2245 self.assertTrue(sw.barrier(), "Barrier failed")
2246
2247 result = True
2248
Howard Persh9cab4822012-09-11 17:08:40 -07002249 sw.settle() # Allow switch to settle and generate any notifications
2250
rootf6af1672012-04-06 09:46:29 -07002251 # Check for any error messages
2252
2253 if not sw.errors_verify(0):
2254 result = False
2255
2256 # Verify flow table
2257
2258 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002259 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002260 result = False
2261
2262 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002263 logging.info("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002264
Howard Persh07d99e62012-04-09 15:26:57 -07002265
2266# FLOW MODIFY 2
2267#
2268# OVERVIEW
2269# Loose modify of mutiple flows
2270#
2271# PURPOSE
2272# - Verify that loose flow modify operates only on matching flows
2273# - Verify that matching flows are correctly modified
2274#
2275# PARAMETERS
2276# Name: num_flows
2277# Type: number
2278# Description:
2279# Number of flows to define
2280# Default: 100
2281#
2282# PROCESS
2283# 1. Delete all flows from switch
2284# 2. Generate <num_flows> distinct flow configurations
2285# 3. Send <num_flows> flow adds to switch
2286# 4. Pick 1 defined flow F at random
2287# 5. Create overlapping loose flow mod match criteria by repeatedly
2288# wildcarding out qualifiers in match of F => F',
2289# and create new actions list A' for F'
2290# 6. Send loose flow modify for F' to switch
2291# 7. Verify flow table in swtich
2292# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2293# are returned in step 7 above, each with correct (original or modified)
2294# action list;
2295# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002296
2297class Flow_Mod_2(basic.SimpleProtocol):
2298 """
2299 Test FLOW_MOD_2 from draft top-half test plan
2300
2301 INPUTS
2302 None
2303 """
2304
2305 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002306 logging.info("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002307
Rich Lane477f4812012-10-04 22:49:00 -07002308 num_flows = test_param_get(config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002309
2310 # Clear all flows from switch
2311
Rich Lane9a003812012-10-04 17:17:59 -07002312 logging.info("Deleting all flows from switch")
2313 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002314 self.assertEqual(rc, 0, "Failed to delete all flows")
2315
2316 # Get switch capabilites
2317
rootf6af1672012-04-06 09:46:29 -07002318 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002319 self.assertTrue(sw.connect(self.controller), \
2320 "Failed to connect to switch" \
2321 )
rootf6af1672012-04-06 09:46:29 -07002322
2323 # Dream up some flow information, i.e. space to chose from for
2324 # random flow parameter generation
2325
2326 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002327 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002328 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002329
2330 # Dream up some flows
2331
2332 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002333 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002334
2335 # Send flow table to switch
2336
Rich Lane9a003812012-10-04 17:17:59 -07002337 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002338 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002339 logging.info("Adding flow:")
2340 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002341 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2342
2343 # Do barrier, to make sure all flows are in
2344
2345 self.assertTrue(sw.barrier(), "Barrier failed")
2346
2347 result = True
2348
Howard Persh9cab4822012-09-11 17:08:40 -07002349 sw.settle() # Allow switch to settle and generate any notifications
2350
rootf6af1672012-04-06 09:46:29 -07002351 # Check for any error messages
2352
2353 if not sw.errors_verify(0):
2354 result = False
2355
2356 # Verify flow table
2357
2358 sw.flow_tbl = ft
2359 if not sw.flow_tbl_verify():
2360 result = False
2361
2362 # Pick a random flow as a basis
Howard Persh5f3c83f2012-04-13 09:57:10 -07002363
2364 mfc = copy.deepcopy((ft.values())[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002365 mfc.rand_mod(fi, \
2366 sw.sw_features.actions, \
2367 sw.valid_ports, \
2368 sw.valid_queues \
2369 )
rootf6af1672012-04-06 09:46:29 -07002370
2371 # Repeatedly wildcard qualifiers
2372
2373 for wi in shuffle(range(len(all_wildcards_list))):
2374 w = all_wildcards_list[wi]
2375 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2376 n = wildcard_get(mfc.match.wildcards, w)
2377 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002378 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2379 w, \
2380 random.randint(n + 1, 32) \
2381 )
rootf6af1672012-04-06 09:46:29 -07002382 else:
2383 continue
2384 else:
2385 if wildcard_get(mfc.match.wildcards, w) == 0:
2386 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2387 else:
2388 continue
2389 mfc = mfc.canonical()
2390
2391 # Count the number of flows that would be modified
2392
2393 n = 0
2394 for fc in ft.values():
2395 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2396 n = n + 1
2397
2398 # If more than 1, we found our loose delete flow spec
2399 if n > 1:
2400 break
2401
Rich Lane9a003812012-10-04 17:17:59 -07002402 logging.info("Modifying %d flows" % (n))
2403 logging.info("Sending flow mod to switch:")
2404 logging.info(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002405 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2406
2407 # Do barrier, to make sure all flows are in
2408 self.assertTrue(sw.barrier(), "Barrier failed")
2409
Howard Persh9cab4822012-09-11 17:08:40 -07002410 sw.settle() # Allow switch to settle and generate any notifications
2411
rootf6af1672012-04-06 09:46:29 -07002412 # Check for error message
2413
2414 if not sw.errors_verify(0):
2415 result = False
2416
2417 # Apply flow mod to local flow table
2418
2419 for fc in ft.values():
2420 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002421 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002422
2423 # Verify flow table
2424
2425 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002426 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002427 result = False
2428
2429 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002430 logging.info("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002431
2432
Howard Persh07d99e62012-04-09 15:26:57 -07002433# FLOW MODIFY 3
2434
2435# OVERVIEW
2436# Strict modify of non-existent flow
2437#
2438# PURPOSE
2439# Verify that strict modify of a non-existent flow is equivalent to a flow add
2440#
2441# PARAMETERS
2442# None
2443#
2444# PROCESS
2445# 1. Delete all flows from switch
2446# 2. Send single flow mod, as strict modify, to switch
2447# 3. Verify flow table in switch
2448# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2449
rootf6af1672012-04-06 09:46:29 -07002450class Flow_Mod_3(basic.SimpleProtocol):
2451 """
2452 Test FLOW_MOD_3 from draft top-half test plan
2453
2454 INPUTS
2455 None
2456 """
2457
2458 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002459 logging.info("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002460
2461 # Clear all flows from switch
2462
Rich Lane9a003812012-10-04 17:17:59 -07002463 logging.info("Deleting all flows from switch")
2464 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002465 self.assertEqual(rc, 0, "Failed to delete all flows")
2466
2467 # Get switch capabilites
2468
rootf6af1672012-04-06 09:46:29 -07002469 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002470 self.assertTrue(sw.connect(self.controller), \
2471 "Failed to connect to switch" \
2472 )
rootf6af1672012-04-06 09:46:29 -07002473
2474 # Dream up some flow information, i.e. space to chose from for
2475 # random flow parameter generation
2476
2477 fi = Flow_Info()
2478 fi.rand(10)
2479
2480 # Dream up a flow config
2481
2482 fc = Flow_Cfg()
2483 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002484 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002485 sw.tbl_stats.stats[0].wildcards, \
2486 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002487 sw.valid_ports, \
2488 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002489 )
2490 fc = fc.canonical()
2491
2492 # Send it to the switch
2493
Rich Lane9a003812012-10-04 17:17:59 -07002494 logging.info("Sending flow mod to switch:")
2495 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002496 ft = Flow_Tbl()
2497 fc.send_rem = False
2498 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2499 ft.insert(fc)
2500
2501 # Do barrier, to make sure all flows are in
2502
2503 self.assertTrue(sw.barrier(), "Barrier failed")
2504
2505 result = True
2506
Howard Persh9cab4822012-09-11 17:08:40 -07002507 sw.settle() # Allow switch to settle and generate any notifications
2508
rootf6af1672012-04-06 09:46:29 -07002509 # Check for any error messages
2510
2511 if not sw.errors_verify(0):
2512 result = False
2513
2514 # Verify flow table
2515
2516 sw.flow_tbl = ft
2517 if not sw.flow_tbl_verify():
2518 result = False
2519
2520 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002521 logging.info("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002522
2523
Howard Persh8d21c1f2012-04-20 15:57:29 -07002524# FLOW MODIFY 3_1
2525
2526# OVERVIEW
2527# No-op modify
2528#
2529# PURPOSE
2530# Verify that modify of a flow with new actions same as old ones operates correctly
2531#
2532# PARAMETERS
2533# None
2534#
2535# PROCESS
2536# 1. Delete all flows from switch
2537# 2. Send single flow mod, as strict modify, to switch
2538# 3. Verify flow table in switch
2539# 4. Send same flow mod, as strict modify, to switch
2540# 5. Verify flow table in switch
2541# 6. Test PASSED iff flow defined in step 2 and 4 above verified; else FAILED
2542
2543class Flow_Mod_3_1(basic.SimpleProtocol):
2544 """
2545 Test FLOW_MOD_3_1 from draft top-half test plan
2546
2547 INPUTS
2548 None
2549 """
2550
2551 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002552 logging.info("Flow_Mod_3_1 TEST BEGIN")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002553
2554 # Clear all flows from switch
2555
Rich Lane9a003812012-10-04 17:17:59 -07002556 logging.info("Deleting all flows from switch")
2557 rc = delete_all_flows(self.controller)
Howard Persh8d21c1f2012-04-20 15:57:29 -07002558 self.assertEqual(rc, 0, "Failed to delete all flows")
2559
2560 # Get switch capabilites
2561
2562 sw = Switch()
2563 self.assertTrue(sw.connect(self.controller), \
2564 "Failed to connect to switch" \
2565 )
2566
2567 # Dream up some flow information, i.e. space to chose from for
2568 # random flow parameter generation
2569
2570 fi = Flow_Info()
2571 fi.rand(10)
2572
2573 # Dream up a flow config
2574
2575 fc = Flow_Cfg()
2576 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002577 required_wildcards(self), \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002578 sw.tbl_stats.stats[0].wildcards, \
2579 sw.sw_features.actions, \
2580 sw.valid_ports, \
2581 sw.valid_queues \
2582 )
2583 fc = fc.canonical()
2584
2585 # Send it to the switch
2586
Rich Lane9a003812012-10-04 17:17:59 -07002587 logging.info("Sending flow mod to switch:")
2588 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002589 ft = Flow_Tbl()
2590 fc.send_rem = False
2591 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2592 ft.insert(fc)
2593
2594 # Do barrier, to make sure all flows are in
2595
2596 self.assertTrue(sw.barrier(), "Barrier failed")
2597
2598 result = True
2599
Howard Persh9cab4822012-09-11 17:08:40 -07002600 sw.settle() # Allow switch to settle and generate any notifications
2601
Howard Persh8d21c1f2012-04-20 15:57:29 -07002602 # Check for any error messages
2603
2604 if not sw.errors_verify(0):
2605 result = False
2606
2607 # Verify flow table
2608
2609 sw.flow_tbl = ft
2610 if not sw.flow_tbl_verify():
2611 result = False
2612
2613 # Send same flow to the switch again
2614
Rich Lane9a003812012-10-04 17:17:59 -07002615 logging.info("Sending flow mod to switch:")
2616 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002617 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2618
2619 # Do barrier, to make sure all flows are in
2620
2621 self.assertTrue(sw.barrier(), "Barrier failed")
2622
Howard Persh9cab4822012-09-11 17:08:40 -07002623 sw.settle() # Allow switch to settle and generate any notifications
2624
Howard Persh8d21c1f2012-04-20 15:57:29 -07002625 # Check for any error messages
2626
2627 if not sw.errors_verify(0):
2628 result = False
2629
2630 # Verify flow table
2631
2632 if not sw.flow_tbl_verify():
2633 result = False
2634
2635 self.assertTrue(result, "Flow_Mod_3_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002636 logging.info("Flow_Mod_3_1 TEST PASSED")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002637
2638
Howard Persh07d99e62012-04-09 15:26:57 -07002639# FLOW DELETE 1
2640#
2641# OVERVIEW
2642# Strict delete of single flow
2643#
2644# PURPOSE
2645# Verify correct operation of strict delete of single defined flow
2646#
2647# PARAMETERS
2648# None
2649#
2650# PROCESS
2651# 1. Delete all flows from switch
2652# 2. Send flow F to switch
2653# 3. Send strict flow delete for F to switch
2654# 4. Verify flow table in swtich
2655# 6. Test PASSED iff all flows sent to switch in step 2 above,
2656# less flow removed in step 3 above, are returned in step 4 above;
2657# else test FAILED
2658
rootf6af1672012-04-06 09:46:29 -07002659class Flow_Del_1(basic.SimpleProtocol):
2660 """
2661 Test FLOW_DEL_1 from draft top-half test plan
2662
2663 INPUTS
2664 None
2665 """
2666
2667 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002668 logging.info("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002669
2670 # Clear all flows from switch
2671
Rich Lane9a003812012-10-04 17:17:59 -07002672 logging.info("Deleting all flows from switch")
2673 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002674 self.assertEqual(rc, 0, "Failed to delete all flows")
2675
2676 # Get switch capabilites
2677
rootf6af1672012-04-06 09:46:29 -07002678 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002679 self.assertTrue(sw.connect(self.controller), \
2680 "Failed to connect to switch" \
2681 )
rootf6af1672012-04-06 09:46:29 -07002682
2683 # Dream up some flow information, i.e. space to chose from for
2684 # random flow parameter generation
2685
2686 fi = Flow_Info()
2687 fi.rand(10)
2688
2689 # Dream up a flow config
2690
2691 fc = Flow_Cfg()
2692 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002693 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002694 sw.tbl_stats.stats[0].wildcards, \
2695 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002696 sw.valid_ports, \
2697 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002698 )
2699 fc = fc.canonical()
2700
2701 # Send it to the switch
2702
Rich Lane9a003812012-10-04 17:17:59 -07002703 logging.info("Sending flow add to switch:")
2704 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002705 ft = Flow_Tbl()
2706 fc.send_rem = False
2707 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2708 ft.insert(fc)
2709
2710 # Dream up some different actions, with the same flow key
2711
2712 fc2 = copy.deepcopy(fc)
2713 while True:
2714 fc2.rand_mod(fi, \
2715 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002716 sw.valid_ports, \
2717 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002718 )
2719 if fc2 != fc:
2720 break
2721
2722 # Delete strictly
2723
Rich Lane9a003812012-10-04 17:17:59 -07002724 logging.info("Sending strict flow del to switch:")
2725 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002726 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2727 ft.delete(fc)
2728
2729 # Do barrier, to make sure all flows are in
2730
2731 self.assertTrue(sw.barrier(), "Barrier failed")
2732
2733 result = True
2734
Howard Persh9cab4822012-09-11 17:08:40 -07002735 sw.settle() # Allow switch to settle and generate any notifications
2736
rootf6af1672012-04-06 09:46:29 -07002737 # Check for any error messages
2738
2739 if not sw.errors_verify(0):
2740 result = False
2741
2742 # Verify flow table
2743
2744 sw.flow_tbl = ft
2745 if not sw.flow_tbl_verify():
2746 result = False
2747
2748 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002749 logging.info("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002750
2751
Howard Persh07d99e62012-04-09 15:26:57 -07002752# FLOW DELETE 2
2753#
2754# OVERVIEW
2755# Loose delete of multiple flows
2756#
2757# PURPOSE
2758# - Verify correct operation of loose delete of multiple flows
2759#
2760# PARAMETERS
2761# Name: num_flows
2762# Type: number
2763# Description:
2764# Number of flows to define
2765# Default: 100
2766#
2767# PROCESS
2768# 1. Delete all flows from switch
2769# 2. Generate <num_flows> distinct flow configurations
2770# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2771# 4. Pick 1 defined flow F at random
2772# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2773# F' will match more than 1 existing flow key
2774# 6. Send loose flow delete for F' to switch
2775# 7. Verify flow table in switch
2776# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2777# removed in step 6 above (i.e. those that match F'), are returned
2778# in step 7 above;
2779# else test FAILED
2780
rootf6af1672012-04-06 09:46:29 -07002781class Flow_Del_2(basic.SimpleProtocol):
2782 """
2783 Test FLOW_DEL_2 from draft top-half test plan
2784
2785 INPUTS
2786 None
2787 """
2788
2789 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002790 logging.info("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002791
Rich Lane477f4812012-10-04 22:49:00 -07002792 num_flows = test_param_get(config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002793
2794 # Clear all flows from switch
2795
Rich Lane9a003812012-10-04 17:17:59 -07002796 logging.info("Deleting all flows from switch")
2797 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002798 self.assertEqual(rc, 0, "Failed to delete all flows")
2799
2800 # Get switch capabilites
2801
rootf6af1672012-04-06 09:46:29 -07002802 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002803 self.assertTrue(sw.connect(self.controller), \
2804 "Failed to connect to switch" \
2805 )
rootf6af1672012-04-06 09:46:29 -07002806
2807 # Dream up some flow information, i.e. space to chose from for
2808 # random flow parameter generation
2809
2810 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002811 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002812 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002813
2814 # Dream up some flows
2815
2816 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002817 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002818
2819 # Send flow table to switch
2820
Rich Lane9a003812012-10-04 17:17:59 -07002821 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002822 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002823 logging.info("Adding flow:")
2824 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002825 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2826
2827 # Do barrier, to make sure all flows are in
2828
2829 self.assertTrue(sw.barrier(), "Barrier failed")
2830
2831 result = True
2832
Howard Persh9cab4822012-09-11 17:08:40 -07002833 sw.settle() # Allow switch to settle and generate any notifications
2834
rootf6af1672012-04-06 09:46:29 -07002835 # Check for any error messages
2836
2837 if not sw.errors_verify(0):
2838 result = False
2839
2840 # Verify flow table
2841
2842 sw.flow_tbl = ft
2843 if not sw.flow_tbl_verify():
2844 result = False
2845
2846 # Pick a random flow as a basis
2847
2848 dfc = copy.deepcopy(ft.values()[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002849 dfc.rand_mod(fi, \
2850 sw.sw_features.actions, \
2851 sw.valid_ports, \
2852 sw.valid_queues \
2853 )
rootf6af1672012-04-06 09:46:29 -07002854
2855 # Repeatedly wildcard qualifiers
2856
2857 for wi in shuffle(range(len(all_wildcards_list))):
2858 w = all_wildcards_list[wi]
2859 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2860 n = wildcard_get(dfc.match.wildcards, w)
2861 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002862 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2863 w, \
2864 random.randint(n + 1, 32) \
2865 )
rootf6af1672012-04-06 09:46:29 -07002866 else:
2867 continue
2868 else:
2869 if wildcard_get(dfc.match.wildcards, w) == 0:
2870 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2871 else:
2872 continue
2873 dfc = dfc.canonical()
2874
2875 # Count the number of flows that would be deleted
2876
2877 n = 0
2878 for fc in ft.values():
2879 if dfc.overlaps(fc, True):
2880 n = n + 1
2881
2882 # If more than 1, we found our loose delete flow spec
2883 if n > 1:
2884 break
2885
Rich Lane9a003812012-10-04 17:17:59 -07002886 logging.info("Deleting %d flows" % (n))
2887 logging.info("Sending flow del to switch:")
2888 logging.info(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002889 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2890
2891 # Do barrier, to make sure all flows are in
2892 self.assertTrue(sw.barrier(), "Barrier failed")
2893
Howard Persh9cab4822012-09-11 17:08:40 -07002894 sw.settle() # Allow switch to settle and generate any notifications
2895
rootf6af1672012-04-06 09:46:29 -07002896 # Check for error message
2897
2898 if not sw.errors_verify(0):
2899 result = False
2900
2901 # Apply flow mod to local flow table
2902
2903 for fc in ft.values():
2904 if dfc.overlaps(fc, True):
2905 ft.delete(fc)
2906
2907 # Verify flow table
2908
2909 sw.flow_tbl = ft
2910 if not sw.flow_tbl_verify():
2911 result = False
2912
2913 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002914 logging.info("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002915
2916
Howard Persh07d99e62012-04-09 15:26:57 -07002917# FLOW DELETE 4
2918#
2919# OVERVIEW
2920# Flow removed messages
2921#
2922# PURPOSE
2923# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2924# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2925#
2926# PARAMETERS
2927# None
2928#
2929# PROCESS
2930# 1. Delete all flows from switch
2931# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2932# 3. Send strict flow delete of flow to switch
2933# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2934# 5. Verify flow table in switch
2935# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2936# removed in step 3 above, are returned in step 5 above, and that
2937# asynch message was received; else test FAILED
2938
2939
rootf6af1672012-04-06 09:46:29 -07002940class Flow_Del_4(basic.SimpleProtocol):
2941 """
2942 Test FLOW_DEL_4 from draft top-half test plan
2943
2944 INPUTS
2945 None
2946 """
2947
2948 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002949 logging.info("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002950
2951 # Clear all flows from switch
2952
Rich Lane9a003812012-10-04 17:17:59 -07002953 logging.info("Deleting all flows from switch")
2954 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002955 self.assertEqual(rc, 0, "Failed to delete all flows")
2956
2957 # Get switch capabilites
2958
rootf6af1672012-04-06 09:46:29 -07002959 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002960 self.assertTrue(sw.connect(self.controller), \
2961 "Failed to connect to switch" \
2962 )
rootf6af1672012-04-06 09:46:29 -07002963
2964 # Dream up some flow information, i.e. space to chose from for
2965 # random flow parameter generation
2966
2967 fi = Flow_Info()
2968 fi.rand(10)
2969
2970 # Dream up a flow config
2971
2972 fc = Flow_Cfg()
2973 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002974 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002975 sw.tbl_stats.stats[0].wildcards, \
2976 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002977 sw.valid_ports, \
2978 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002979 )
2980 fc = fc.canonical()
2981
2982 # Send it to the switch. with "notify on removed"
2983
Rich Lane9a003812012-10-04 17:17:59 -07002984 logging.info("Sending flow add to switch:")
2985 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002986 ft = Flow_Tbl()
2987 fc.send_rem = True
2988 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2989 ft.insert(fc)
2990
2991 # Dream up some different actions, with the same flow key
2992
2993 fc2 = copy.deepcopy(fc)
2994 while True:
2995 fc2.rand_mod(fi, \
2996 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002997 sw.valid_ports, \
2998 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002999 )
3000 if fc2 != fc:
3001 break
3002
3003 # Delete strictly
3004
Rich Lane9a003812012-10-04 17:17:59 -07003005 logging.info("Sending strict flow del to switch:")
3006 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07003007 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
3008 ft.delete(fc)
3009
3010 # Do barrier, to make sure all flows are in
3011
3012 self.assertTrue(sw.barrier(), "Barrier failed")
3013
3014 result = True
3015
Howard Persh9cab4822012-09-11 17:08:40 -07003016 sw.settle() # Allow switch to settle and generate any notifications
3017
rootf6af1672012-04-06 09:46:29 -07003018 # Check for expected "removed" message
3019
Howard Persh3340d452012-04-06 16:45:21 -07003020 if not sw.errors_verify(0):
3021 result = False
3022
3023 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07003024 result = False
3025
3026 # Verify flow table
3027
3028 sw.flow_tbl = ft
3029 if not sw.flow_tbl_verify():
3030 result = False
3031
3032 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07003033 logging.info("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07003034