blob: 9931c896a0f6da2e391dadf949d252e1136d8e5f [file] [log] [blame]
Howard Pershc7963582012-03-29 10:02:59 -07001"""
2Flow query test case.
3
Howard Persh3340d452012-04-06 16:45:21 -07004Attempts to fill switch to capacity with randomized flows, and ensure that
5they all are read back correctly.
Howard Pershc7963582012-03-29 10:02:59 -07006"""
Howard Persh07d99e62012-04-09 15:26:57 -07007
8# COMMON TEST PARAMETERS
9#
10# Name: wildcards
11# Type: number
12# Description:
13# Overrides bitmap of supported wildcards reported by switch
14# Default: none
15#
Howard Pershc1199d52012-04-11 14:21:32 -070016# Name: wildcards_force
17# Type: number
18# Description:
19# Bitmap of wildcards to always be set
20# Default: none
21#
Howard Persh07d99e62012-04-09 15:26:57 -070022# Name: actions
23# Type: number
24# Description:
25# Overrides bitmap of supported actions reported by switch
26# Default: none
27#
Howard Pershc1199d52012-04-11 14:21:32 -070028# Name: actions_force
29# Type: number
30# Description:
31# Bitmap of actions to always be used
32# Default: none
33#
34# Name: ports
35# Type: list of OF port numbers
36# Description:
37# Override list of OF port numbers reported by switch
38# Default: none
39#
Howard Persh8d21c1f2012-04-20 15:57:29 -070040# Name: queues
41# Type: list of OF (port-number, queue-id) pairs
42# Description:
43# Override list of OF (port-number, queue-id) pairs returned by switch
44# Default: none
45#
Howard Pershb10a47a2012-08-21 13:54:47 -070046# Name: vlans
47# Type: list of VLAN ids
48# Description:
49# Override VLAN ids used in tests to given list
50# Default: []
51#
Howard Persh07d99e62012-04-09 15:26:57 -070052# Name: conservative_ordered_actions
53# Type: boolean (True or False)
54# Description:
55# Compare flow actions lists as unordered
56# Default: True
57
58
Howard Persh680b92a2012-03-31 13:34:35 -070059import math
Howard Pershc7963582012-03-29 10:02:59 -070060
61import logging
62
63import unittest
64import random
Howard Persh9cab4822012-09-11 17:08:40 -070065import time
Howard Pershc7963582012-03-29 10:02:59 -070066
67import oftest.controller as controller
68import oftest.cstruct as ofp
69import oftest.message as message
70import oftest.dataplane as dataplane
71import oftest.action as action
72import oftest.action_list as action_list
73import oftest.parse as parse
74import pktact
75import basic
76
Rich Laneda3b5ad2012-10-03 09:05:32 -070077from oftest.testutils import *
Howard Pershc7963582012-03-29 10:02:59 -070078from time import sleep
79
80#@var port_map Local copy of the configuration map from OF port
81# numbers to OS interfaces
Dan Talayco910a8282012-04-07 00:05:20 -070082fq_port_map = None
Dan Talayco910a8282012-04-07 00:05:20 -070083#@var fq_config Local copy of global configuration data
84fq_config = None
Howard Pershc7963582012-03-29 10:02:59 -070085
rootf6af1672012-04-06 09:46:29 -070086# For test priority
87test_prio = {}
88
89
Howard Pershc7963582012-03-29 10:02:59 -070090def test_set_init(config):
91 """
92 Set up function for packet action test classes
93
94 @param config The configuration dictionary; see oft
95 """
96
97 basic.test_set_init(config)
98
Dan Talayco910a8282012-04-07 00:05:20 -070099 global fq_port_map
Dan Talayco910a8282012-04-07 00:05:20 -0700100 global fq_config
Howard Pershc7963582012-03-29 10:02:59 -0700101
Dan Talayco910a8282012-04-07 00:05:20 -0700102 fq_port_map = config["port_map"]
103 fq_config = config
root2843d2b2012-04-06 10:27:46 -0700104
Howard Pershc7963582012-03-29 10:02:59 -0700105
rootf6af1672012-04-06 09:46:29 -0700106def flip_coin():
107 return random.randint(1, 100) <= 50
108
109
Howard Pershc7963582012-03-29 10:02:59 -0700110def shuffle(list):
111 n = len(list)
112 lim = n * n
113 i = 0
114 while i < lim:
115 a = random.randint(0, n - 1)
116 b = random.randint(0, n - 1)
117 temp = list[a]
118 list[a] = list[b]
119 list[b] = temp
120 i = i + 1
121 return list
122
123
Howard Persh680b92a2012-03-31 13:34:35 -0700124def rand_pick(list):
125 return list[random.randint(0, len(list) - 1)]
Howard Pershc7963582012-03-29 10:02:59 -0700126
Howard Persh680b92a2012-03-31 13:34:35 -0700127def rand_dl_addr():
128 return [random.randint(0, 255) & ~1,
129 random.randint(0, 255),
130 random.randint(0, 255),
131 random.randint(0, 255),
132 random.randint(0, 255),
133 random.randint(0, 255)
134 ]
Howard Pershc7963582012-03-29 10:02:59 -0700135
136def rand_nw_addr():
137 return random.randint(0, (1 << 32) - 1)
138
139
rootf6af1672012-04-06 09:46:29 -0700140class Flow_Info:
Howard Persh680b92a2012-03-31 13:34:35 -0700141 # Members:
142 # priorities - list of flow priorities
143 # dl_addrs - list of MAC addresses
144 # vlans - list of VLAN ids
145 # ethertypes - list of Ethertypes
146 # ip_addrs - list of IP addresses
147 # ip_tos - list of IP TOS values
148 # ip_protos - list of IP protocols
149 # l4_ports - list of L4 ports
150
151 def __init__(self):
152 priorities = []
153 dl_addrs = []
154 vlans = []
155 ethertypes = []
156 ip_addrs = []
157 ip_tos = []
158 ip_protos = []
159 l4_ports = []
160
161 def rand(self, n):
162 self.priorities = []
163 i = 0
164 while i < n:
165 self.priorities.append(random.randint(1, 65534))
166 i = i + 1
167
168 self.dl_addrs = []
169 i = 0
170 while i < n:
171 self.dl_addrs.append(rand_dl_addr())
172 i = i + 1
173
Howard Pershb10a47a2012-08-21 13:54:47 -0700174 if test_param_get(fq_config, "vlans", []) != []:
175 self.vlans = test_param_get(fq_config, "vlans", [])
176
Rich Lane9a003812012-10-04 17:17:59 -0700177 logging.info("Overriding VLAN ids to:")
178 logging.info(self.vlans)
Howard Pershb10a47a2012-08-21 13:54:47 -0700179 else:
180 self.vlans = []
181 i = 0
182 while i < n:
183 self.vlans.append(random.randint(1, 4094))
184 i = i + 1
Howard Persh680b92a2012-03-31 13:34:35 -0700185
rootf6af1672012-04-06 09:46:29 -0700186 self.ethertypes = [0x0800, 0x0806]
Howard Persh680b92a2012-03-31 13:34:35 -0700187 i = 0
188 while i < n:
189 self.ethertypes.append(random.randint(0, (1 << 16) - 1))
190 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700191 self.ethertypes = shuffle(self.ethertypes)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700192
193 self.ip_addrs = []
194 i = 0
195 while i < n:
196 self.ip_addrs.append(rand_nw_addr())
197 i = i + 1
198
199 self.ip_tos = []
200 i = 0
201 while i < n:
202 self.ip_tos.append(random.randint(0, (1 << 8) - 1) & ~3)
203 i = i + 1
204
rootf6af1672012-04-06 09:46:29 -0700205 self.ip_protos = [1, 6, 17]
Howard Persh680b92a2012-03-31 13:34:35 -0700206 i = 0
207 while i < n:
208 self.ip_protos.append(random.randint(0, (1 << 8) - 1))
209 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700210 self.ip_protos = shuffle(self.ip_protos)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700211
212 self.l4_ports = []
213 i = 0
214 while i < n:
215 self.l4_ports.append(random.randint(0, (1 << 16) - 1))
216 i = i + 1
217
218 def rand_priority(self):
219 return rand_pick(self.priorities)
220
221 def rand_dl_addr(self):
222 return rand_pick(self.dl_addrs)
223
224 def rand_vlan(self):
225 return rand_pick(self.vlans)
226
227 def rand_ethertype(self):
228 return rand_pick(self.ethertypes)
229
230 def rand_ip_addr(self):
231 return rand_pick(self.ip_addrs)
232
233 def rand_ip_tos(self):
234 return rand_pick(self.ip_tos)
235
236 def rand_ip_proto(self):
237 return rand_pick(self.ip_protos)
238
239 def rand_l4_port(self):
240 return rand_pick(self.l4_ports)
241
242
Howard Pershc7963582012-03-29 10:02:59 -0700243# TBD - These don't belong here
244
Howard Persh680b92a2012-03-31 13:34:35 -0700245all_wildcards_list = [ofp.OFPFW_IN_PORT,
Howard Persh680b92a2012-03-31 13:34:35 -0700246 ofp.OFPFW_DL_DST,
rootf6af1672012-04-06 09:46:29 -0700247 ofp.OFPFW_DL_SRC,
248 ofp.OFPFW_DL_VLAN,
249 ofp.OFPFW_DL_VLAN_PCP,
Howard Persh680b92a2012-03-31 13:34:35 -0700250 ofp.OFPFW_DL_TYPE,
rootf6af1672012-04-06 09:46:29 -0700251 ofp.OFPFW_NW_TOS,
Howard Persh680b92a2012-03-31 13:34:35 -0700252 ofp.OFPFW_NW_PROTO,
Howard Persh680b92a2012-03-31 13:34:35 -0700253 ofp.OFPFW_NW_SRC_MASK,
254 ofp.OFPFW_NW_DST_MASK,
rootf6af1672012-04-06 09:46:29 -0700255 ofp.OFPFW_TP_SRC,
256 ofp.OFPFW_TP_DST
Howard Persh680b92a2012-03-31 13:34:35 -0700257 ]
Howard Pershc7963582012-03-29 10:02:59 -0700258
Howard Persh3340d452012-04-06 16:45:21 -0700259# TBD - Need this because there are duplicates in ofp.ofp_flow_wildcards_map
260# -- FIX
rootf6af1672012-04-06 09:46:29 -0700261all_wildcard_names = {
262 1 : 'OFPFW_IN_PORT',
263 2 : 'OFPFW_DL_VLAN',
264 4 : 'OFPFW_DL_SRC',
265 8 : 'OFPFW_DL_DST',
266 16 : 'OFPFW_DL_TYPE',
267 32 : 'OFPFW_NW_PROTO',
268 64 : 'OFPFW_TP_SRC',
269 128 : 'OFPFW_TP_DST',
270 1048576 : 'OFPFW_DL_VLAN_PCP',
271 2097152 : 'OFPFW_NW_TOS'
272}
273
rootf6af1672012-04-06 09:46:29 -0700274def wildcard_set(x, w, val):
275 result = x
276 if w == ofp.OFPFW_NW_SRC_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700277 result = (result & ~ofp.OFPFW_NW_SRC_MASK) \
278 | (val << ofp.OFPFW_NW_SRC_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700279 elif w == ofp.OFPFW_NW_DST_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700280 result = (result & ~ofp.OFPFW_NW_DST_MASK) \
281 | (val << ofp.OFPFW_NW_DST_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700282 elif val == 0:
283 result = result & ~w
284 else:
285 result = result | w
286 return result
287
288def wildcard_get(x, w):
289 if w == ofp.OFPFW_NW_SRC_MASK:
290 return (x & ofp.OFPFW_NW_SRC_MASK) >> ofp.OFPFW_NW_SRC_SHIFT
291 if w == ofp.OFPFW_NW_DST_MASK:
292 return (x & ofp.OFPFW_NW_DST_MASK) >> ofp.OFPFW_NW_DST_SHIFT
293 return 1 if (x & w) != 0 else 0
294
Howard Persh8d21c1f2012-04-20 15:57:29 -0700295def wildcards_to_str(wildcards):
296 result = "{"
297 sep = ""
298 for w in all_wildcards_list:
299 if (wildcards & w) == 0:
300 continue
301 if w == ofp.OFPFW_NW_SRC_MASK:
302 n = wildcard_get(wildcards, w)
303 if n > 0:
304 result = result + sep + ("OFPFW_NW_SRC(%d)" % (n))
305 elif w == ofp.OFPFW_NW_DST_MASK:
306 n = wildcard_get(wildcards, w)
307 if n > 0:
308 result = result + sep + ("OFPFW_NW_DST(%d)" % (n))
309 else:
310 result = result + sep + all_wildcard_names[w]
311 sep = ", "
312 result = result +"}"
313 return result
Howard Pershc7963582012-03-29 10:02:59 -0700314
Howard Persh680b92a2012-03-31 13:34:35 -0700315all_actions_list = [ofp.OFPAT_OUTPUT,
316 ofp.OFPAT_SET_VLAN_VID,
317 ofp.OFPAT_SET_VLAN_PCP,
318 ofp.OFPAT_STRIP_VLAN,
319 ofp.OFPAT_SET_DL_SRC,
320 ofp.OFPAT_SET_DL_DST,
321 ofp.OFPAT_SET_NW_SRC,
322 ofp.OFPAT_SET_NW_DST,
323 ofp.OFPAT_SET_NW_TOS,
324 ofp.OFPAT_SET_TP_SRC,
325 ofp.OFPAT_SET_TP_DST,
326 ofp.OFPAT_ENQUEUE
327 ]
328
Howard Persh8d21c1f2012-04-20 15:57:29 -0700329def actions_bmap_to_str(bm):
330 result = "{"
331 sep = ""
332 for a in all_actions_list:
333 if ((1 << a) & bm) != 0:
334 result = result + sep + ofp.ofp_action_type_map[a]
335 sep = ", "
336 result = result + "}"
337 return result
338
Howard Persh680b92a2012-03-31 13:34:35 -0700339def dl_addr_to_str(a):
340 return "%x:%x:%x:%x:%x:%x" % tuple(a)
341
342def ip_addr_to_str(a, n):
rootf6af1672012-04-06 09:46:29 -0700343 if n is not None:
344 a = a & ~((1 << (32 - n)) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700345 result = "%d.%d.%d.%d" % (a >> 24, \
346 (a >> 16) & 0xff, \
347 (a >> 8) & 0xff, \
348 a & 0xff \
349 )
350 if n is not None:
351 result = result + ("/%d" % (n))
352 return result
353
Howard Pershc7963582012-03-29 10:02:59 -0700354
rootf6af1672012-04-06 09:46:29 -0700355class Flow_Cfg:
Howard Pershc7963582012-03-29 10:02:59 -0700356 # Members:
357 # - match
358 # - idle_timeout
359 # - hard_timeout
360 # - priority
361 # - action_list
362
363 def __init__(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700364 self.priority = 0
Howard Pershc7963582012-03-29 10:02:59 -0700365 self.match = parse.ofp_match()
366 self.match.wildcards = ofp.OFPFW_ALL
367 self.idle_timeout = 0
368 self.hard_timeout = 0
Howard Pershc7963582012-03-29 10:02:59 -0700369 self.actions = action_list.action_list()
370
rootf6af1672012-04-06 09:46:29 -0700371 # {pri, match} is considered a flow key
372 def key_equal(self, x):
Howard Persh680b92a2012-03-31 13:34:35 -0700373 if self.priority != x.priority:
374 return False
375 # TBD - Should this logic be moved to ofp_match.__eq__()?
376 if self.match.wildcards != x.match.wildcards:
377 return False
rootf6af1672012-04-06 09:46:29 -0700378 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700379 and self.match.in_port != x.match.in_port:
380 return False
rootf6af1672012-04-06 09:46:29 -0700381 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700382 and self.match.dl_dst != x.match.dl_dst:
383 return False
rootf6af1672012-04-06 09:46:29 -0700384 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0 \
385 and self.match.dl_src != x.match.dl_src:
386 return False
387 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700388 and self.match.dl_vlan != x.match.dl_vlan:
389 return False
rootf6af1672012-04-06 09:46:29 -0700390 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700391 and self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
392 return False
rootf6af1672012-04-06 09:46:29 -0700393 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700394 and self.match.dl_type != x.match.dl_type:
395 return False
rootf6af1672012-04-06 09:46:29 -0700396 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700397 and self.match.nw_tos != x.match.nw_tos:
398 return False
rootf6af1672012-04-06 09:46:29 -0700399 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700400 and self.match.nw_proto != x.match.nw_proto:
401 return False
rootf6af1672012-04-06 09:46:29 -0700402 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
403 if n < 32:
404 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700405 if (self.match.nw_src & m) != (x.match.nw_src & m):
406 return False
rootf6af1672012-04-06 09:46:29 -0700407 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
408 if n < 32:
409 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700410 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
411 return False
rootf6af1672012-04-06 09:46:29 -0700412 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0 \
413 and self.match.tp_src != x.match.tp_src:
Howard Persh680b92a2012-03-31 13:34:35 -0700414 return False
rootf6af1672012-04-06 09:46:29 -0700415 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0 \
416 and self.match.tp_dst != x.match.tp_dst:
417 return False
418 return True
419
Howard Persh5f3c83f2012-04-13 09:57:10 -0700420 def actions_equal(self, x):
421 if test_param_get(fq_config, "conservative_ordered_actions", True):
422 # Compare actions lists as unordered
423
root2843d2b2012-04-06 10:27:46 -0700424 aa = copy.deepcopy(x.actions.actions)
425 for a in self.actions.actions:
426 i = 0
427 while i < len(aa):
428 if a == aa[i]:
429 break
430 i = i + 1
431 if i < len(aa):
432 aa.pop(i)
433 else:
434 return False
435 return aa == []
436 else:
437 return self.actions == x.actions
Howard Persh5f3c83f2012-04-13 09:57:10 -0700438
439 def non_key_equal(self, x):
440 if self.cookie != x.cookie:
441 return False
442 if self.idle_timeout != x.idle_timeout:
443 return False
444 if self.hard_timeout != x.hard_timeout:
445 return False
446 return self.actions_equal(x)
rootf6af1672012-04-06 09:46:29 -0700447
root2843d2b2012-04-06 10:27:46 -0700448 def key_str(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700449 result = "priority=%d" % self.priority
450 # TBD - Would be nice if ofp_match.show() was better behaved
451 # (no newlines), and more intuitive (things in hex where approprate), etc.
Howard Persh8d21c1f2012-04-20 15:57:29 -0700452 result = result + (", wildcards=0x%x=%s" \
453 % (self.match.wildcards, \
454 wildcards_to_str(self.match.wildcards) \
455 )
456 )
rootf6af1672012-04-06 09:46:29 -0700457 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700458 result = result + (", in_port=%d" % (self.match.in_port))
rootf6af1672012-04-06 09:46:29 -0700459 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700460 result = result + (", dl_dst=%s" \
461 % (dl_addr_to_str(self.match.dl_dst)) \
462 )
rootf6af1672012-04-06 09:46:29 -0700463 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700464 result = result + (", dl_src=%s" \
465 % (dl_addr_to_str(self.match.dl_src)) \
466 )
rootf6af1672012-04-06 09:46:29 -0700467 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700468 result = result + (", dl_vlan=%d" % (self.match.dl_vlan))
rootf6af1672012-04-06 09:46:29 -0700469 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700470 result = result + (", dl_vlan_pcp=%d" % (self.match.dl_vlan_pcp))
rootf6af1672012-04-06 09:46:29 -0700471 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700472 result = result + (", dl_type=0x%x" % (self.match.dl_type))
rootf6af1672012-04-06 09:46:29 -0700473 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700474 result = result + (", nw_tos=0x%x" % (self.match.nw_tos))
rootf6af1672012-04-06 09:46:29 -0700475 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700476 result = result + (", nw_proto=%d" % (self.match.nw_proto))
rootf6af1672012-04-06 09:46:29 -0700477 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700478 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700479 result = result + (", nw_src=%s" % \
480 (ip_addr_to_str(self.match.nw_src, 32 - n)) \
481 )
rootf6af1672012-04-06 09:46:29 -0700482 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700483 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700484 result = result + (", nw_dst=%s" % \
485 (ip_addr_to_str(self.match.nw_dst, 32 - n)) \
486 )
rootf6af1672012-04-06 09:46:29 -0700487 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700488 result = result + (", tp_src=%d" % self.match.tp_src)
rootf6af1672012-04-06 09:46:29 -0700489 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700490 result = result + (", tp_dst=%d" % self.match.tp_dst)
rootf6af1672012-04-06 09:46:29 -0700491 return result
492
493 def __eq__(self, x):
494 return (self.key_equal(x) and self.non_key_equal(x))
495
496 def __str__(self):
root2843d2b2012-04-06 10:27:46 -0700497 result = self.key_str()
498 result = result + (", cookie=%d" % self.cookie)
Howard Persh680b92a2012-03-31 13:34:35 -0700499 result = result + (", idle_timeout=%d" % self.idle_timeout)
500 result = result + (", hard_timeout=%d" % self.hard_timeout)
Howard Persh680b92a2012-03-31 13:34:35 -0700501 for a in self.actions.actions:
502 result = result + (", action=%s" % ofp.ofp_action_type_map[a.type])
503 if a.type == ofp.OFPAT_OUTPUT:
504 result = result + ("(%d)" % (a.port))
505 elif a.type == ofp.OFPAT_SET_VLAN_VID:
506 result = result + ("(%d)" % (a.vlan_vid))
507 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
508 result = result + ("(%d)" % (a.vlan_pcp))
509 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
510 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
511 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
512 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
513 elif a.type == ofp.OFPAT_SET_NW_TOS:
514 result = result + ("(0x%x)" % (a.nw_tos))
515 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
516 result = result + ("(%d)" % (a.tp_port))
517 elif a.type == ofp.OFPAT_ENQUEUE:
518 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
519 return result
Howard Pershc7963582012-03-29 10:02:59 -0700520
Howard Persh8d21c1f2012-04-20 15:57:29 -0700521 def rand_actions_ordered(self, fi, valid_actions, valid_ports, valid_queues):
Howard Persh3340d452012-04-06 16:45:21 -0700522 # Action lists are ordered, so pick an ordered random subset of
523 # supported actions
Howard Pershc1199d52012-04-11 14:21:32 -0700524
525 actions_force = test_param_get(fq_config, "actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700526 if actions_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700527 logging.info("Forced actions:")
528 logging.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700529
Dan Talayco910a8282012-04-07 00:05:20 -0700530 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh3340d452012-04-06 16:45:21 -0700531 supported_actions = []
532 for a in all_actions_list:
533 if ((1 << a) & valid_actions) != 0:
534 supported_actions.append(a)
535
Howard Pershc1199d52012-04-11 14:21:32 -0700536 actions \
537 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
538
539 for a in all_actions_list:
540 if ((1 << a) & actions_force) != 0:
541 actions.append(a)
542
543 actions = shuffle(actions)
Howard Persh3340d452012-04-06 16:45:21 -0700544
Howard Persh6a3698d2012-08-21 14:26:39 -0700545 set_vlanf = False
546 strip_vlanf = False
Howard Persh3340d452012-04-06 16:45:21 -0700547 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700548 for a in actions:
Dan Talayco910a8282012-04-07 00:05:20 -0700549 act = None
Howard Persh3340d452012-04-06 16:45:21 -0700550 if a == ofp.OFPAT_OUTPUT:
551 pass # OUTPUT actions must come last
552 elif a == ofp.OFPAT_SET_VLAN_VID:
Howard Persh6a3698d2012-08-21 14:26:39 -0700553 if not strip_vlanf:
554 act = action.action_set_vlan_vid()
555 act.vlan_vid = fi.rand_vlan()
556 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700557 elif a == ofp.OFPAT_SET_VLAN_PCP:
Howard Persh6a3698d2012-08-21 14:26:39 -0700558 if not strip_vlanf:
559 act = action.action_set_vlan_pcp()
560 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
561 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700562 elif a == ofp.OFPAT_STRIP_VLAN:
Howard Persh6a3698d2012-08-21 14:26:39 -0700563 if not set_vlanf:
564 act = action.action_strip_vlan()
565 strip_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700566 elif a == ofp.OFPAT_SET_DL_SRC:
567 act = action.action_set_dl_src()
568 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700569 elif a == ofp.OFPAT_SET_DL_DST:
570 act = action.action_set_dl_dst()
571 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700572 elif a == ofp.OFPAT_SET_NW_SRC:
573 act = action.action_set_nw_src()
574 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700575 elif a == ofp.OFPAT_SET_NW_DST:
576 act = action.action_set_nw_dst()
577 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700578 elif a == ofp.OFPAT_SET_NW_TOS:
579 act = action.action_set_nw_tos()
580 act.nw_tos = fi.rand_ip_tos()
Howard Persh3340d452012-04-06 16:45:21 -0700581 elif a == ofp.OFPAT_SET_TP_SRC:
582 act = action.action_set_tp_src()
583 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700584 elif a == ofp.OFPAT_SET_TP_DST:
585 act = action.action_set_tp_dst()
586 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700587 elif a == ofp.OFPAT_ENQUEUE:
588 pass # Enqueue actions must come last
Dan Talayco910a8282012-04-07 00:05:20 -0700589 if act:
590 act.max_len = ACTION_MAX_LEN
591 self.actions.add(act)
592
Howard Persh3340d452012-04-06 16:45:21 -0700593 p = random.randint(1, 100)
Howard Pershc1199d52012-04-11 14:21:32 -0700594 if (((1 << ofp.OFPAT_ENQUEUE) & actions_force) != 0 or p <= 33) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700595 and len(valid_queues) > 0 \
596 and ofp.OFPAT_ENQUEUE in actions:
Howard Pershc1199d52012-04-11 14:21:32 -0700597 # In not forecd, one third of the time, include ENQUEUE actions
598 # at end of list
Howard Persh3340d452012-04-06 16:45:21 -0700599 # At most 1 ENQUEUE action
600 act = action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700601 (act.port, act.queue_id) = rand_pick(valid_queues)
Dan Talayco910a8282012-04-07 00:05:20 -0700602 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700603 self.actions.add(act)
Howard Pershc1199d52012-04-11 14:21:32 -0700604 if (((1 << ofp.OFPAT_OUTPUT) & actions_force) != 0 \
605 or (p > 33 and p <= 66) \
606 ) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700607 and len(valid_ports) > 0 \
Howard Pershc1199d52012-04-11 14:21:32 -0700608 and ofp.OFPAT_OUTPUT in actions:
Howard Persh3340d452012-04-06 16:45:21 -0700609 # One third of the time, include OUTPUT actions at end of list
610 port_idxs = shuffle(range(len(valid_ports)))
611 # Only 1 output action allowed if IN_PORT wildcarded
612 n = 1 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) != 0 \
613 else random.randint(1, len(valid_ports))
614 port_idxs = port_idxs[0 : n]
615 for pi in port_idxs:
616 act = action.action_output()
617 act.port = valid_ports[pi]
Dan Talayco910a8282012-04-07 00:05:20 -0700618 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700619 if act.port != ofp.OFPP_IN_PORT \
620 or wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
621 # OUTPUT(IN_PORT) only valid if OFPFW_IN_PORT not wildcarded
622 self.actions.add(act)
623 else:
624 # One third of the time, include neither
625 pass
626
627
628 # Randomize flow data for flow modifies (i.e. cookie and actions)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700629 def rand_mod(self, fi, valid_actions, valid_ports, valid_queues):
rootf6af1672012-04-06 09:46:29 -0700630 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700631
Dan Talayco910a8282012-04-07 00:05:20 -0700632 # By default, test with conservative ordering conventions
633 # This should probably be indicated in a profile
634 if test_param_get(fq_config, "conservative_ordered_actions", True):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700635 self.rand_actions_ordered(fi, valid_actions, valid_ports, valid_queues)
Howard Persh3340d452012-04-06 16:45:21 -0700636 return self
637
Howard Pershc1199d52012-04-11 14:21:32 -0700638 actions_force = test_param_get(fq_config, "actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700639 if actions_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700640 logging.info("Forced actions:")
641 logging.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700642
643 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh680b92a2012-03-31 13:34:35 -0700644 supported_actions = []
645 for a in all_actions_list:
646 if ((1 << a) & valid_actions) != 0:
647 supported_actions.append(a)
648
Howard Pershc1199d52012-04-11 14:21:32 -0700649 actions \
650 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
651
652 for a in all_actions_list:
653 if ((1 << a) & actions_force) != 0:
654 actions.append(a)
655
656 actions = shuffle(actions)
Howard Pershc7963582012-03-29 10:02:59 -0700657
658 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700659 for a in actions:
Howard Pershc7963582012-03-29 10:02:59 -0700660 if a == ofp.OFPAT_OUTPUT:
661 # TBD - Output actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700662 if len(valid_ports) == 0:
663 continue
Howard Pershc7963582012-03-29 10:02:59 -0700664 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700665 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700666 for pi in port_idxs:
667 act = action.action_output()
Howard Persh680b92a2012-03-31 13:34:35 -0700668 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700669 self.actions.add(act)
670 elif a == ofp.OFPAT_SET_VLAN_VID:
671 act = action.action_set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700672 act.vlan_vid = fi.rand_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700673 self.actions.add(act)
674 elif a == ofp.OFPAT_SET_VLAN_PCP:
Dan Talayco910a8282012-04-07 00:05:20 -0700675 act = action.action_set_vlan_pcp()
676 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700677 elif a == ofp.OFPAT_STRIP_VLAN:
678 act = action.action_strip_vlan()
679 self.actions.add(act)
680 elif a == ofp.OFPAT_SET_DL_SRC:
681 act = action.action_set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700682 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700683 self.actions.add(act)
684 elif a == ofp.OFPAT_SET_DL_DST:
685 act = action.action_set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700686 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700687 self.actions.add(act)
688 elif a == ofp.OFPAT_SET_NW_SRC:
689 act = action.action_set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700690 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700691 self.actions.add(act)
692 elif a == ofp.OFPAT_SET_NW_DST:
693 act = action.action_set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700694 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700695 self.actions.add(act)
696 elif a == ofp.OFPAT_SET_NW_TOS:
697 act = action.action_set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700698 act.nw_tos = fi.rand_ip_tos()
Howard Pershc7963582012-03-29 10:02:59 -0700699 self.actions.add(act)
700 elif a == ofp.OFPAT_SET_TP_SRC:
701 act = action.action_set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700702 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700703 self.actions.add(act)
704 elif a == ofp.OFPAT_SET_TP_DST:
705 act = action.action_set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700706 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700707 self.actions.add(act)
708 elif a == ofp.OFPAT_ENQUEUE:
709 # TBD - Enqueue actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700710 if len(valid_queues) == 0:
711 continue
712 qidxs = shuffle(range(len(valid_queues)))
713 qidxs = qidxs[0 : random.randint(1, len(valid_queues))]
714 for qi in qidxs:
Howard Pershc7963582012-03-29 10:02:59 -0700715 act = action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700716 (act.port, act.queue_id) = valid_queues[qi]
Howard Pershc7963582012-03-29 10:02:59 -0700717 self.actions.add(act)
718
719 return self
720
rootf6af1672012-04-06 09:46:29 -0700721 # Randomize flow cfg
Ed Swierk99a74de2012-08-22 06:40:54 -0700722 def rand(self, fi, wildcards_force, valid_wildcards, valid_actions, valid_ports,
723 valid_queues):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700724 if wildcards_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700725 logging.info("Wildcards forced:")
726 logging.info(wildcards_to_str(wildcards_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700727
rootf6af1672012-04-06 09:46:29 -0700728 # Start with no wildcards, i.e. everything specified
729 self.match.wildcards = 0
Howard Pershc1199d52012-04-11 14:21:32 -0700730
731 if wildcards_force != 0:
732 exact = False
733 else:
734 # Make approx. 5% of flows exact
735 exact = (random.randint(1, 100) <= 5)
rootf6af1672012-04-06 09:46:29 -0700736
737 # For each qualifier Q,
738 # if (wildcarding is not supported for Q,
739 # or an exact flow is specified
740 # or a coin toss comes up heads),
741 # specify Q
742 # else
743 # wildcard Q
744
Howard Pershc1199d52012-04-11 14:21:32 -0700745 if wildcard_get(wildcards_force, ofp.OFPFW_IN_PORT) == 0 \
746 and (wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
747 or exact \
748 or flip_coin() \
749 ):
rootf6af1672012-04-06 09:46:29 -0700750 self.match.in_port = rand_pick(valid_ports)
751 else:
Howard Persh3340d452012-04-06 16:45:21 -0700752 self.match.wildcards = wildcard_set(self.match.wildcards, \
753 ofp.OFPFW_IN_PORT, \
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_DST) == 0 \
758 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
759 or exact \
760 or flip_coin() \
761 ):
rootf6af1672012-04-06 09:46:29 -0700762 self.match.dl_dst = fi.rand_dl_addr()
763 else:
Howard Persh3340d452012-04-06 16:45:21 -0700764 self.match.wildcards = wildcard_set(self.match.wildcards, \
765 ofp.OFPFW_DL_DST, \
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_SRC) == 0 \
770 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
771 or exact \
772 or flip_coin() \
773 ):
rootf6af1672012-04-06 09:46:29 -0700774 self.match.dl_src = fi.rand_dl_addr()
775 else:
Howard Persh3340d452012-04-06 16:45:21 -0700776 self.match.wildcards = wildcard_set(self.match.wildcards, \
777 ofp.OFPFW_DL_SRC, \
778 1 \
779 )
rootf6af1672012-04-06 09:46:29 -0700780
Howard Pershc1199d52012-04-11 14:21:32 -0700781 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN) == 0 \
782 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
783 or exact \
784 or flip_coin() \
785 ):
rootf6af1672012-04-06 09:46:29 -0700786 self.match.dl_vlan = fi.rand_vlan()
787 else:
Howard Persh3340d452012-04-06 16:45:21 -0700788 self.match.wildcards = wildcard_set(self.match.wildcards, \
789 ofp.OFPFW_DL_VLAN, \
790 1 \
791 )
rootf6af1672012-04-06 09:46:29 -0700792
Howard Pershc1199d52012-04-11 14:21:32 -0700793 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN_PCP) == 0 \
794 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
795 or exact \
796 or flip_coin() \
797 ):
798 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
799 else:
800 self.match.wildcards = wildcard_set(self.match.wildcards, \
801 ofp.OFPFW_DL_VLAN_PCP, \
802 1 \
803 )
804
805 if wildcard_get(wildcards_force, ofp.OFPFW_DL_TYPE) == 0 \
806 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
807 or exact \
808 or flip_coin() \
809 ):
rootf6af1672012-04-06 09:46:29 -0700810 self.match.dl_type = fi.rand_ethertype()
811 else:
Howard Persh3340d452012-04-06 16:45:21 -0700812 self.match.wildcards = wildcard_set(self.match.wildcards, \
813 ofp.OFPFW_DL_TYPE, \
814 1 \
815 )
rootf6af1672012-04-06 09:46:29 -0700816
Howard Pershc1199d52012-04-11 14:21:32 -0700817 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_SRC_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_SRC_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_SRC_MASK, \
828 n \
829 )
rootf6af1672012-04-06 09:46:29 -0700830 if n < 32:
831 self.match.nw_src = 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 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_DST_MASK)
842 if n == 0:
843 if exact or flip_coin():
844 n = 0
845 else:
846 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
847 if n > 32:
848 n = 32
849 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700850 self.match.wildcards = wildcard_set(self.match.wildcards, \
851 ofp.OFPFW_NW_DST_MASK, \
852 n \
853 )
rootf6af1672012-04-06 09:46:29 -0700854 if n < 32:
855 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
856 # Specifying any IP address match other than all bits
857 # don't care requires that Ethertype is one of {IP, ARP}
858 if flip_coin():
859 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700860 self.match.wildcards = wildcard_set(self.match.wildcards, \
861 ofp.OFPFW_DL_TYPE, \
862 0 \
863 )
rootf6af1672012-04-06 09:46:29 -0700864
Howard Pershc1199d52012-04-11 14:21:32 -0700865 if wildcard_get(wildcards_force, ofp.OFPFW_NW_TOS) == 0 \
866 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
867 or exact \
868 or flip_coin() \
869 ):
rootf6af1672012-04-06 09:46:29 -0700870 self.match.nw_tos = fi.rand_ip_tos()
871 # Specifying a TOS value requires that Ethertype is IP
872 if flip_coin():
873 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700874 self.match.wildcards = wildcard_set(self.match.wildcards, \
875 ofp.OFPFW_DL_TYPE, \
876 0 \
877 )
rootf6af1672012-04-06 09:46:29 -0700878 else:
Howard Persh3340d452012-04-06 16:45:21 -0700879 self.match.wildcards = wildcard_set(self.match.wildcards, \
880 ofp.OFPFW_NW_TOS, \
881 1 \
882 )
rootf6af1672012-04-06 09:46:29 -0700883
Dan Talayco910a8282012-04-07 00:05:20 -0700884 # Known issue on OVS with specifying nw_proto w/o dl_type as IP
Howard Pershc1199d52012-04-11 14:21:32 -0700885 if wildcard_get(wildcards_force, ofp.OFPFW_NW_PROTO) == 0 \
886 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
887 or exact \
888 or flip_coin() \
889 ):
Dan Talayco910a8282012-04-07 00:05:20 -0700890 self.match.nw_proto = fi.rand_ip_proto()
891 # Specifying an IP protocol requires that Ethertype is IP
892 if flip_coin():
893 self.match.dl_type = 0x0800
894 self.match.wildcards = wildcard_set(self.match.wildcards, \
895 ofp.OFPFW_DL_TYPE, \
896 0 \
897 )
898 else:
Howard Persh3340d452012-04-06 16:45:21 -0700899 self.match.wildcards = wildcard_set(self.match.wildcards, \
900 ofp.OFPFW_NW_PROTO, \
901 1 \
902 )
Dan Talayco910a8282012-04-07 00:05:20 -0700903
Howard Pershc1199d52012-04-11 14:21:32 -0700904 if wildcard_get(wildcards_force, ofp.OFPFW_TP_SRC) == 0 \
905 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
906 or exact\
907 or flip_coin() \
908 ):
rootf6af1672012-04-06 09:46:29 -0700909 self.match.tp_src = fi.rand_l4_port()
910 # Specifying a L4 port requires that IP protcol is
911 # one of {ICMP, TCP, UDP}
912 if flip_coin():
913 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700914 self.match.wildcards = wildcard_set(self.match.wildcards, \
915 ofp.OFPFW_NW_PROTO, \
916 0 \
917 )
rootf6af1672012-04-06 09:46:29 -0700918 # Specifying a L4 port requirues that Ethertype is IP
919 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700920 self.match.wildcards = wildcard_set(self.match.wildcards, \
921 ofp.OFPFW_DL_TYPE, \
922 0 \
923 )
rootf6af1672012-04-06 09:46:29 -0700924 if self.match.nw_proto == 1:
925 self.match.tp_src = self.match.tp_src & 0xff
926 else:
Howard Persh3340d452012-04-06 16:45:21 -0700927 self.match.wildcards = wildcard_set(self.match.wildcards, \
928 ofp.OFPFW_TP_SRC, \
929 1 \
930 )
rootf6af1672012-04-06 09:46:29 -0700931
Howard Pershc1199d52012-04-11 14:21:32 -0700932 if wildcard_get(wildcards_force, ofp.OFPFW_TP_DST) == 0 \
933 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
934 or exact \
935 or flip_coin() \
936 ):
rootf6af1672012-04-06 09:46:29 -0700937 self.match.tp_dst = fi.rand_l4_port()
938 # Specifying a L4 port requires that IP protcol is
939 # one of {ICMP, TCP, UDP}
940 if flip_coin():
941 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700942 self.match.wildcards = wildcard_set(self.match.wildcards, \
943 ofp.OFPFW_NW_PROTO, \
944 0 \
945 )
rootf6af1672012-04-06 09:46:29 -0700946 # Specifying a L4 port requirues that Ethertype is IP
947 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700948 self.match.wildcards = wildcard_set(self.match.wildcards, \
949 ofp.OFPFW_DL_TYPE, \
950 0 \
951 )
rootf6af1672012-04-06 09:46:29 -0700952 if self.match.nw_proto == 1:
953 self.match.tp_dst = self.match.tp_dst & 0xff
954 else:
Howard Persh3340d452012-04-06 16:45:21 -0700955 self.match.wildcards = wildcard_set(self.match.wildcards, \
956 ofp.OFPFW_TP_DST, \
957 1 \
958 )
rootf6af1672012-04-06 09:46:29 -0700959
960 # If nothing is wildcarded, it is an exact flow spec -- some switches
Howard Persh3340d452012-04-06 16:45:21 -0700961 # (Open vSwitch, for one) *require* that exact flow specs
962 # have priority 65535.
963 self.priority = 65535 if self.match.wildcards == 0 \
964 else fi.rand_priority()
rootf6af1672012-04-06 09:46:29 -0700965
966 # N.B. Don't make the timeout too short, else the flow might
967 # disappear before we get a chance to check for it.
968 t = random.randint(0, 65535)
969 self.idle_timeout = 0 if t < 60 else t
970 t = random.randint(0, 65535)
971 self.hard_timeout = 0 if t < 60 else t
972
Howard Persh8d21c1f2012-04-20 15:57:29 -0700973 self.rand_mod(fi, valid_actions, valid_ports, valid_queues)
rootf6af1672012-04-06 09:46:29 -0700974
975 return self
976
977 # Return flow cfg in canonical form
Howard Persh3340d452012-04-06 16:45:21 -0700978 # - There are dependencies between flow qualifiers, e.g. it only makes
979 # sense to qualify nw_proto if dl_type is qualified to be 0x0800 (IP).
980 # The canonical form of flow match criteria will "wildcard out"
981 # all such cases.
rootf6af1672012-04-06 09:46:29 -0700982 def canonical(self):
983 result = copy.deepcopy(self)
Howard Persh07d99e62012-04-09 15:26:57 -0700984
985 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_VLAN) != 0:
986 result.match.wildcards = wildcard_set(result.match.wildcards, \
987 ofp.OFPFW_DL_VLAN_PCP, \
988 1 \
989 )
990
rootf6af1672012-04-06 09:46:29 -0700991 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
992 or result.match.dl_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700993 # dl_tyoe is wildcarded, or specified as something other
994 # than IP or ARP
Howard Persh07d99e62012-04-09 15:26:57 -0700995 # => nw_src, nw_dst, nw_proto cannot be specified,
996 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700997 result.match.wildcards = wildcard_set(result.match.wildcards, \
998 ofp.OFPFW_NW_SRC_MASK, \
999 32 \
1000 )
1001 result.match.wildcards = wildcard_set(result.match.wildcards, \
1002 ofp.OFPFW_NW_DST_MASK, \
1003 32 \
1004 )
Howard Persh3340d452012-04-06 16:45:21 -07001005 result.match.wildcards = wildcard_set(result.match.wildcards, \
1006 ofp.OFPFW_NW_PROTO, \
1007 1 \
1008 )
Howard Persh07d99e62012-04-09 15:26:57 -07001009
1010 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
1011 or result.match.dl_type != 0x0800:
1012 # dl_type is wildcarded, or specified as something other than IP
1013 # => nw_tos, tp_src and tp_dst cannot be specified,
1014 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001015 result.match.wildcards = wildcard_set(result.match.wildcards, \
1016 ofp.OFPFW_NW_TOS, \
1017 1 \
1018 )
1019 result.match.wildcards = wildcard_set(result.match.wildcards, \
1020 ofp.OFPFW_TP_SRC, \
1021 1 \
1022 )
1023 result.match.wildcards = wildcard_set(result.match.wildcards, \
1024 ofp.OFPFW_TP_DST, \
1025 1 \
1026 )
Howard Persh07d99e62012-04-09 15:26:57 -07001027 result.match.wildcards = wildcard_set(result.match.wildcards, \
1028 ofp.OFPFW_NW_SRC_MASK, \
1029 32 \
1030 )
1031 result.match.wildcards = wildcard_set(result.match.wildcards, \
1032 ofp.OFPFW_NW_DST_MASK, \
1033 32 \
1034 )
1035 result.match.wildcards = wildcard_set(result.match.wildcards, \
1036 ofp.OFPFW_NW_PROTO, \
1037 1 \
1038 )
1039
rootf6af1672012-04-06 09:46:29 -07001040 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
1041 or result.match.nw_proto not in [1, 6, 17]:
Howard Persh3340d452012-04-06 16:45:21 -07001042 # nw_proto is wildcarded, or specified as something other than ICMP,
1043 # TCP or UDP
rootf6af1672012-04-06 09:46:29 -07001044 # => tp_src and tp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001045 result.match.wildcards = wildcard_set(result.match.wildcards, \
1046 ofp.OFPFW_TP_SRC, \
1047 1 \
1048 )
1049 result.match.wildcards = wildcard_set(result.match.wildcards, \
1050 ofp.OFPFW_TP_DST, \
1051 1 \
1052 )
rootf6af1672012-04-06 09:46:29 -07001053 return result
1054
Howard Persh680b92a2012-03-31 13:34:35 -07001055 # Overlap check
1056 # delf == True <=> Check for delete overlap, else add overlap
1057 # "Add overlap" is defined as there exists a packet that could match both the
1058 # receiver and argument flowspecs
1059 # "Delete overlap" is defined as the specificity of the argument flowspec
1060 # is greater than or equal to the specificity of the receiver flowspec
1061 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -07001062 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
1063 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001064 if self.match.in_port != x.match.in_port:
1065 return False # Both specified, and not equal
1066 elif delf:
1067 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001068 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
1069 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001070 if self.match.dl_vlan != x.match.dl_vlan:
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_DL_SRC) == 0:
1075 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001076 if self.match.dl_src != x.match.dl_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_DL_DST) == 0:
1081 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001082 if self.match.dl_dst != x.match.dl_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 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
1087 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001088 if self.match.dl_type != x.match.dl_type:
1089 return False # Both specified, and not equal
1090 elif delf:
1091 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -07001092 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
1093 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001094 if self.match.nw_proto != x.match.nw_proto:
1095 return False # Both specified, and not equal
1096 elif delf:
1097 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001098 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
1099 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001100 if self.match.tp_src != x.match.tp_src:
1101 return False # Both specified, and not equal
1102 elif delf:
1103 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001104 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
1105 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001106 if self.match.tp_dst != x.match.tp_dst:
1107 return False # Both specified, and not equal
1108 elif delf:
1109 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001110 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
1111 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001112 if delf and na < nb:
1113 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001114 if (na < 32 and nb < 32):
1115 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1116 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -07001117 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -07001118 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
1119 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001120 if delf and na < nb:
1121 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001122 if (na < 32 and nb < 32):
1123 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1124 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
rootf6af1672012-04-06 09:46:29 -07001125 return False # Overlapping bits not equal
1126 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
1127 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001128 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
1129 return False # Both specified, and not equal
1130 elif delf:
1131 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001132 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
1133 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001134 if self.match.nw_tos != x.match.nw_tos:
1135 return False # Both specified, and not equal
1136 elif delf:
1137 return False # Receiver more specific
1138 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -07001139
1140 def to_flow_mod_msg(self, msg):
1141 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -07001142 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001143 msg.idle_timeout = self.idle_timeout
1144 msg.hard_timeout = self.hard_timeout
1145 msg.priority = self.priority
1146 msg.actions = self.actions
1147 return msg
1148
1149 def from_flow_stat(self, msg):
1150 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -07001151 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001152 self.idle_timeout = msg.idle_timeout
1153 self.hard_timeout = msg.hard_timeout
1154 self.priority = msg.priority
1155 self.actions = msg.actions
1156
rootf6af1672012-04-06 09:46:29 -07001157 def from_flow_rem(self, msg):
1158 self.match = msg.match
1159 self.idle_timeout = msg.idle_timeout
1160 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -07001161
Howard Pershc7963582012-03-29 10:02:59 -07001162
rootf6af1672012-04-06 09:46:29 -07001163class Flow_Tbl:
1164 def clear(self):
1165 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001166
rootf6af1672012-04-06 09:46:29 -07001167 def __init__(self):
1168 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001169
rootf6af1672012-04-06 09:46:29 -07001170 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001171 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001172
1173 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001174 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001175
1176 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001177 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001178
1179 def values(self):
1180 return self.dict.values()
1181
1182 def count(self):
1183 return len(self.dict)
1184
Ed Swierk99a74de2012-08-22 06:40:54 -07001185 def rand(self, wildcards_force, sw, fi, num_flows):
rootf6af1672012-04-06 09:46:29 -07001186 self.clear()
1187 i = 0
1188 tbl = 0
1189 j = 0
1190 while i < num_flows:
1191 fc = Flow_Cfg()
1192 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001193 wildcards_force, \
rootf6af1672012-04-06 09:46:29 -07001194 sw.tbl_stats.stats[tbl].wildcards, \
1195 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001196 sw.valid_ports, \
1197 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001198 )
1199 fc = fc.canonical()
1200 if self.find(fc):
1201 continue
1202 fc.send_rem = False
1203 self.insert(fc)
1204 i = i + 1
1205 j = j + 1
1206 if j >= sw.tbl_stats.stats[tbl].max_entries:
1207 tbl = tbl + 1
1208 j = 0
1209
1210
1211class Switch:
1212 # Members:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001213 # controller - switch's test controller
1214 # sw_features - switch's OFPT_FEATURES_REPLY message
1215 # valid_ports - list of valid port numbers
1216 # valid_queues - list of valid [port, queue] pairs
1217 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1218 # queue_stats - switch's OFPT_STATS_REPLY message, for queue stats request
1219 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1220 # flow_tbl - (test's idea of) switch's flow table
rootf6af1672012-04-06 09:46:29 -07001221
1222 def __init__(self):
Howard Persh8d21c1f2012-04-20 15:57:29 -07001223 self.controller = None
1224 self.sw_features = None
1225 self.valid_ports = []
1226 self.valid_queues = []
1227 self.tbl_stats = None
1228 self.flow_stats = None
1229 self.flow_tbl = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001230 self.error_msgs = []
1231 self.removed_msgs = []
1232
1233 def error_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001234 logging.info("Got an ERROR message, type=%d, code=%d" \
Ed Swierk99a74de2012-08-22 06:40:54 -07001235 % (msg.type, msg.code) \
1236 )
Rich Lane9a003812012-10-04 17:17:59 -07001237 logging.info("Message header:")
1238 logging.info(msg.header.show())
Ed Swierk99a74de2012-08-22 06:40:54 -07001239 self.error_msgs.append(msg)
1240
1241 def removed_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001242 logging.info("Got a REMOVED message")
1243 logging.info("Message header:")
1244 logging.info(msg.header.show())
Ed Swierk99a74de2012-08-22 06:40:54 -07001245 self.removed_msgs.append(msg)
rootf6af1672012-04-06 09:46:29 -07001246
Howard Persh3340d452012-04-06 16:45:21 -07001247 def controller_set(self, controller):
1248 self.controller = controller
1249 # Register error message handler
Ed Swierk99a74de2012-08-22 06:40:54 -07001250 self.error_msgs = []
1251 self.removed_msgs = []
1252 controller.register(ofp.OFPT_ERROR, self.error_handler)
1253 controller.register(ofp.OFPT_FLOW_REMOVED, self.removed_handler)
Howard Persh3340d452012-04-06 16:45:21 -07001254
rootf6af1672012-04-06 09:46:29 -07001255 def features_get(self):
1256 # Get switch features
1257 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001258 (self.sw_features, pkt) = self.controller.transact(request)
rootf6af1672012-04-06 09:46:29 -07001259 if self.sw_features is None:
Rich Lane9a003812012-10-04 17:17:59 -07001260 logging.error("Get switch features failed")
rootf6af1672012-04-06 09:46:29 -07001261 return False
1262 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Rich Lane9a003812012-10-04 17:17:59 -07001263 logging.info("Ports reported by switch:")
1264 logging.info(self.valid_ports)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001265 ports_override = test_param_get(fq_config, "ports", [])
1266 if ports_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001267 logging.info("Overriding ports to:")
1268 logging.info(ports_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001269 self.valid_ports = ports_override
1270
Howard Persh3340d452012-04-06 16:45:21 -07001271 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1272 # is that universal?
1273
1274 # TBD - There seems to be variability in which switches support which
1275 # ports; need to sort that out
1276 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1277# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1278# ofp.OFPP_NORMAL, \
1279# ofp.OFPP_FLOOD, \
1280# ofp.OFPP_ALL, \
1281# ofp.OFPP_CONTROLLER \
1282# ] \
1283# )
Rich Lane9a003812012-10-04 17:17:59 -07001284 logging.info("Supported actions reported by switch:")
1285 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001286 % (self.sw_features.actions, \
1287 actions_bmap_to_str(self.sw_features.actions) \
1288 ) \
1289 )
Howard Persh07d99e62012-04-09 15:26:57 -07001290 actions_override = test_param_get(fq_config, "actions", -1)
1291 if actions_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001292 logging.info("Overriding supported actions to:")
1293 logging.info(actions_bmap_to_str(actions_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001294 self.sw_features.actions = actions_override
rootf6af1672012-04-06 09:46:29 -07001295 return True
1296
1297 def tbl_stats_get(self):
1298 # Get table stats
Howard Persh680b92a2012-03-31 13:34:35 -07001299 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001300 (self.tbl_stats, pkt) = self.controller.transact(request)
Howard Persh07d99e62012-04-09 15:26:57 -07001301 if self.tbl_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001302 logging.error("Get table stats failed")
Howard Persh07d99e62012-04-09 15:26:57 -07001303 return False
Howard Persh8d21c1f2012-04-20 15:57:29 -07001304 i = 0
Howard Persh07d99e62012-04-09 15:26:57 -07001305 for ts in self.tbl_stats.stats:
Rich Lane9a003812012-10-04 17:17:59 -07001306 logging.info("Supported wildcards for table %d reported by switch:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001307 % (i)
1308 )
Rich Lane9a003812012-10-04 17:17:59 -07001309 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001310 % (ts.wildcards, \
1311 wildcards_to_str(ts.wildcards) \
1312 ) \
1313 )
Howard Persh07d99e62012-04-09 15:26:57 -07001314 wildcards_override = test_param_get(fq_config, "wildcards", -1)
1315 if wildcards_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001316 logging.info("Overriding supported wildcards for table %d to:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001317 % (i)
1318 )
Rich Lane9a003812012-10-04 17:17:59 -07001319 logging.info(wildcards_to_str(wildcards_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001320 ts.wildcards = wildcards_override
Howard Persh8d21c1f2012-04-20 15:57:29 -07001321 i = i + 1
Howard Persh07d99e62012-04-09 15:26:57 -07001322 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001323
Howard Persh8d21c1f2012-04-20 15:57:29 -07001324 def queue_stats_get(self):
1325 # Get queue stats
1326 request = message.queue_stats_request()
1327 request.port_no = ofp.OFPP_ALL
1328 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001329 (self.queue_stats, pkt) = self.controller.transact(request)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001330 if self.queue_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001331 logging.error("Get queue stats failed")
Howard Persh8d21c1f2012-04-20 15:57:29 -07001332 return False
1333 self.valid_queues = map(lambda x: (x.port_no, x.queue_id), \
1334 self.queue_stats.stats \
1335 )
Rich Lane9a003812012-10-04 17:17:59 -07001336 logging.info("(Port, queue) pairs reported by switch:")
1337 logging.info(self.valid_queues)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001338 queues_override = test_param_get(fq_config, "queues", [])
1339 if queues_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001340 logging.info("Overriding (port, queue) pairs to:")
1341 logging.info(queues_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001342 self.valid_queues = queues_override
1343 return True
1344
1345 def connect(self, controller):
1346 # Connect to controller, and get all switch capabilities
1347 self.controller_set(controller)
1348 return (self.features_get() \
1349 and self.tbl_stats_get() \
1350 and self.queue_stats_get() \
1351 )
1352
Howard Pershc1199d52012-04-11 14:21:32 -07001353 def flow_stats_get(self, limit = 10000):
rootf6af1672012-04-06 09:46:29 -07001354 request = message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -07001355 query_match = ofp.ofp_match()
1356 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001357 request.match = query_match
1358 request.table_id = 0xff
1359 request.out_port = ofp.OFPP_NONE;
Howard Persh3340d452012-04-06 16:45:21 -07001360 if self.controller.message_send(request) == -1:
1361 return False
1362 # <TBD>
1363 # Glue together successive reponse messages for stats reply.
1364 # Looking at the "more" flag and performing re-assembly
1365 # should be a part of the infrastructure.
1366 # </TBD>
1367 n = 0
1368 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -07001369 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY)
Howard Persh3340d452012-04-06 16:45:21 -07001370 if resp is None:
Howard Pershc1199d52012-04-11 14:21:32 -07001371 return False # Did not get expected response
Howard Persh3340d452012-04-06 16:45:21 -07001372 if n == 0:
1373 self.flow_stats = resp
1374 else:
1375 self.flow_stats.stats.extend(resp.stats)
1376 n = n + 1
Howard Pershc1199d52012-04-11 14:21:32 -07001377 if len(self.flow_stats.stats) > limit:
Rich Lane9a003812012-10-04 17:17:59 -07001378 logging.error("Too many flows returned")
Howard Pershc1199d52012-04-11 14:21:32 -07001379 return False
1380 if (resp.flags & 1) == 0:
1381 break # No more responses expected
Howard Persh3340d452012-04-06 16:45:21 -07001382 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001383
rootf6af1672012-04-06 09:46:29 -07001384 def flow_add(self, flow_cfg, overlapf = False):
Howard Persh680b92a2012-03-31 13:34:35 -07001385 flow_mod_msg = message.flow_mod()
1386 flow_mod_msg.command = ofp.OFPFC_ADD
1387 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001388 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001389 if overlapf:
1390 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001391 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001392 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Howard Persh07d99e62012-04-09 15:26:57 -07001393 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001394 logging.info("Sending flow_mod(add), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001395 % (flow_mod_msg.header.xid)
1396 )
rootf6af1672012-04-06 09:46:29 -07001397 return (self.controller.message_send(flow_mod_msg) != -1)
Howard Persh680b92a2012-03-31 13:34:35 -07001398
rootf6af1672012-04-06 09:46:29 -07001399 def flow_mod(self, flow_cfg, strictf):
Howard Persh680b92a2012-03-31 13:34:35 -07001400 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001401 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf \
1402 else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -07001403 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001404 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001405 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001406 logging.info("Sending flow_mod(mod), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001407 % (flow_mod_msg.header.xid)
1408 )
rootf6af1672012-04-06 09:46:29 -07001409 return (self.controller.message_send(flow_mod_msg) != -1)
1410
1411 def flow_del(self, flow_cfg, strictf):
1412 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001413 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf \
1414 else ofp.OFPFC_DELETE
rootf6af1672012-04-06 09:46:29 -07001415 flow_mod_msg.buffer_id = 0xffffffff
1416 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001417 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001418 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001419 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001420 logging.info("Sending flow_mod(del), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001421 % (flow_mod_msg.header.xid)
1422 )
rootf6af1672012-04-06 09:46:29 -07001423 return (self.controller.message_send(flow_mod_msg) != -1)
1424
1425 def barrier(self):
1426 barrier = message.barrier_request()
Dan Talaycoc689a792012-09-28 14:22:53 -07001427 (resp, pkt) = self.controller.transact(barrier, 30)
rootf6af1672012-04-06 09:46:29 -07001428 return (resp is not None)
1429
Howard Persh3340d452012-04-06 16:45:21 -07001430 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001431 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001432 logging.info("Expecting %d error messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001433 num_got = len(self.error_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001434 logging.info("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001435 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001436 logging.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001437 result = False
1438 if num_exp == 0:
1439 return result
1440 elif num_exp == 1:
Rich Lane9a003812012-10-04 17:17:59 -07001441 logging.info("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001442 % (type, code) \
1443 )
1444 f = False
Ed Swierk99a74de2012-08-22 06:40:54 -07001445 for e in self.error_msgs:
Howard Persh3340d452012-04-06 16:45:21 -07001446 if e.type == type and e.code == code:
Rich Lane9a003812012-10-04 17:17:59 -07001447 logging.info("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001448 f = True
1449 if not f:
Rich Lane9a003812012-10-04 17:17:59 -07001450 logging.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001451 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001452 else:
Rich Lane9a003812012-10-04 17:17:59 -07001453 logging.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001454 result = False
1455 return result
1456
Howard Persh3340d452012-04-06 16:45:21 -07001457 def removed_verify(self, num_exp):
1458 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001459 logging.info("Expecting %d removed messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001460 num_got = len(self.removed_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001461 logging.info("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001462 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001463 logging.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001464 result = False
1465 if num_exp < 2:
1466 return result
Rich Lane9a003812012-10-04 17:17:59 -07001467 logging.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001468 return False
1469
Howard Persh5f3c83f2012-04-13 09:57:10 -07001470 # modf == True <=> Verify for flow modify, else for add/delete
1471 def flow_tbl_verify(self, modf = False):
rootf6af1672012-04-06 09:46:29 -07001472 result = True
1473
1474 # Verify flow count in switch
Rich Lane9a003812012-10-04 17:17:59 -07001475 logging.info("Reading table stats")
1476 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001477 if not self.tbl_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001478 logging.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001479 return False
1480 n = 0
1481 for ts in self.tbl_stats.stats:
1482 n = n + ts.active_count
Rich Lane9a003812012-10-04 17:17:59 -07001483 logging.info("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001484 % (n) \
1485 )
1486 if n != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001487 logging.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001488 result = False
1489
1490 # Read flows from switch
Rich Lane9a003812012-10-04 17:17:59 -07001491 logging.info("Retrieving flows from switch")
1492 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001493 if not self.flow_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001494 logging.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001495 return False
Rich Lane9a003812012-10-04 17:17:59 -07001496 logging.info("Retrieved %d flows" % (len(self.flow_stats.stats)))
rootf6af1672012-04-06 09:46:29 -07001497
1498 # Verify flows returned by switch
1499
1500 if len(self.flow_stats.stats) != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001501 logging.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001502 result = False
1503
Rich Lane9a003812012-10-04 17:17:59 -07001504 logging.info("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001505 for fc in self.flow_tbl.values():
1506 fc.matched = False
1507 for fs in self.flow_stats.stats:
1508 flow_in = Flow_Cfg()
1509 flow_in.from_flow_stat(fs)
Rich Lane9a003812012-10-04 17:17:59 -07001510 logging.info("Received flow:")
1511 logging.info(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001512 fc = self.flow_tbl.find(flow_in)
1513 if fc is None:
Rich Lane9a003812012-10-04 17:17:59 -07001514 logging.error("Received flow:")
1515 logging.error(str(flow_in))
1516 logging.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001517 result = False
1518 elif fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001519 logging.error("Received flow:")
1520 logging.error(str(flow_in))
1521 logging.error("re-matches defined flow:")
1522 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001523 result = False
1524 else:
Rich Lane9a003812012-10-04 17:17:59 -07001525 logging.info("matched")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001526 if modf:
1527 # Check for modify
1528
1529 if flow_in.cookie != fc.cookie:
Rich Lane9a003812012-10-04 17:17:59 -07001530 logging.warning("Defined flow:")
1531 logging.warning(str(fc))
1532 logging.warning("Received flow:")
1533 logging.warning(str(flow_in))
1534 logging.warning("cookies do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001535 if not flow_in.actions_equal(fc):
Rich Lane9a003812012-10-04 17:17:59 -07001536 logging.error("Defined flow:")
1537 logging.error(str(fc))
1538 logging.error("Received flow:")
1539 logging.error(str(flow_in))
1540 logging.error("actions do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001541 else:
1542 # Check for add/delete
1543
1544 if not flow_in == fc:
Rich Lane9a003812012-10-04 17:17:59 -07001545 logging.error("Defined flow:")
1546 logging.error(str(fc))
1547 logging.error("Received flow:")
1548 logging.error(str(flow_in))
1549 logging.error("non-key portions of flow do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001550 result = False
rootf6af1672012-04-06 09:46:29 -07001551 fc.matched = True
1552 for fc in self.flow_tbl.values():
1553 if not fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001554 logging.error("Defined flow:")
1555 logging.error(str(fc))
1556 logging.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001557 result = False
1558
1559 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001560
Howard Persh9cab4822012-09-11 17:08:40 -07001561 def settle(self):
1562 time.sleep(2)
1563
Howard Persh07d99e62012-04-09 15:26:57 -07001564# FLOW ADD 5
1565#
1566# OVERVIEW
1567# Add flows to switch, read back and verify flow configurations
1568#
1569# PURPOSE
1570# - Test acceptance of flow adds
1571# - Test ability of switch to process additions to flow table in random
1572# priority order
1573# - Test correctness of flow configuration responses
1574#
1575# PARAMETERS
1576#
1577# Name: num_flows
1578# Type: number
1579# Description:
1580# Number of flows to define; 0 => maximum number of flows, as determined
1581# from switch capabilities
1582# Default: 100
1583#
1584# PROCESS
1585# 1. Delete all flows from switch
1586# 2. Generate <num_flows> distinct flow configurations
1587# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1588# 4. Verify that no OFPT_ERROR responses were generated by switch
1589# 5. Retrieve flow stats from switch
1590# 6. Compare flow configurations returned by switch
1591# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1592# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001593
rootf6af1672012-04-06 09:46:29 -07001594class Flow_Add_5(basic.SimpleProtocol):
1595 """
1596 Test FLOW_ADD_5 from draft top-half test plan
1597
1598 INPUTS
1599 num_flows - Number of flows to generate
1600 """
Howard Persh680b92a2012-03-31 13:34:35 -07001601
rootf6af1672012-04-06 09:46:29 -07001602 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001603 logging.info("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001604
Dan Talayco910a8282012-04-07 00:05:20 -07001605 num_flows = test_param_get(fq_config, "num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001606
Howard Pershc7963582012-03-29 10:02:59 -07001607 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001608
Rich Lane9a003812012-10-04 17:17:59 -07001609 logging.info("Deleting all flows from switch")
1610 rc = delete_all_flows(self.controller)
Howard Pershc7963582012-03-29 10:02:59 -07001611 self.assertEqual(rc, 0, "Failed to delete all flows")
1612
rootf6af1672012-04-06 09:46:29 -07001613 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001614
rootf6af1672012-04-06 09:46:29 -07001615 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001616 self.assertTrue(sw.connect(self.controller), \
1617 "Failed to connect to switch" \
1618 )
Howard Pershc7963582012-03-29 10:02:59 -07001619
rootf6af1672012-04-06 09:46:29 -07001620 if num_flows == 0:
1621 # Number of flows requested was 0
1622 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001623
rootf6af1672012-04-06 09:46:29 -07001624 for ts in sw.tbl_stats.stats:
1625 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001626
Rich Lane9a003812012-10-04 17:17:59 -07001627 logging.info("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001628
1629 # Dream up some flow information, i.e. space to chose from for
1630 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001631
rootf6af1672012-04-06 09:46:29 -07001632 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001633 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001634
rootf6af1672012-04-06 09:46:29 -07001635 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001636
rootf6af1672012-04-06 09:46:29 -07001637 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001638 ft.rand(required_wildcards(self), sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001639
rootf6af1672012-04-06 09:46:29 -07001640 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001641
Rich Lane9a003812012-10-04 17:17:59 -07001642 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001643 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001644 logging.info("Adding flow:")
1645 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001646 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001647
rootf6af1672012-04-06 09:46:29 -07001648 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001649
rootf6af1672012-04-06 09:46:29 -07001650 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001651
rootf6af1672012-04-06 09:46:29 -07001652 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001653
Howard Persh9cab4822012-09-11 17:08:40 -07001654 sw.settle() # Allow switch to settle and generate any notifications
1655
rootf6af1672012-04-06 09:46:29 -07001656 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001657
rootf6af1672012-04-06 09:46:29 -07001658 if not sw.errors_verify(0):
1659 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001660
rootf6af1672012-04-06 09:46:29 -07001661 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001662
rootf6af1672012-04-06 09:46:29 -07001663 sw.flow_tbl = ft
1664 if not sw.flow_tbl_verify():
1665 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001666
rootf6af1672012-04-06 09:46:29 -07001667 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001668 logging.info("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001669
Howard Pershc7963582012-03-29 10:02:59 -07001670
Howard Persh07d99e62012-04-09 15:26:57 -07001671# FLOW ADD 5_1
1672#
1673# OVERVIEW
1674# Verify handling of non-canonical flows
1675#
1676# PURPOSE
1677# - Test that switch detects and correctly responds to a non-canonical flow
1678# definition. A canonical flow is one that satisfies all match qualifier
1679# dependencies; a non-canonical flow is one that does not.
1680#
1681# PARAMETERS
1682# - None
1683#
1684# PROCESS
1685# 1. Delete all flows from switch
1686# 2. Generate 1 flow definition, which is different from its canonicalization
1687# 3. Send flow to switch
1688# 4. Retrieve flow from switch
1689# 5. Compare returned flow to canonical form of defined flow
1690# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1691
1692# Disabled.
1693# Should be DUT dependent.
1694test_prio["Flow_Add_5_1"] = -1
1695
rootf6af1672012-04-06 09:46:29 -07001696class Flow_Add_5_1(basic.SimpleProtocol):
1697 """
1698 Test FLOW_ADD_5.1 from draft top-half test plan
1699
1700 INPUTS
1701 None
1702 """
1703
1704 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001705 logging.info("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001706
Dan Talayco910a8282012-04-07 00:05:20 -07001707 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001708
1709 # Clear all flows from switch
1710
Rich Lane9a003812012-10-04 17:17:59 -07001711 logging.info("Deleting all flows from switch")
1712 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001713 self.assertEqual(rc, 0, "Failed to delete all flows")
1714
1715 # Get switch capabilites
1716
rootf6af1672012-04-06 09:46:29 -07001717 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001718 self.assertTrue(sw.connect(self.controller), \
1719 "Failed to connect to switch" \
1720 )
rootf6af1672012-04-06 09:46:29 -07001721
1722 # Dream up some flow information, i.e. space to chose from for
1723 # random flow parameter generation
1724
1725 fi = Flow_Info()
1726 fi.rand(10)
1727
1728 # Dream up a flow config that will be canonicalized by the switch
1729
1730 while True:
1731 fc = Flow_Cfg()
1732 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001733 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07001734 sw.tbl_stats.stats[0].wildcards, \
1735 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001736 sw.valid_ports, \
1737 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001738 )
1739 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001740 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001741 break
1742
1743 ft = Flow_Tbl()
1744 ft.insert(fcc)
1745
1746 # Send it to the switch
1747
Rich Lane9a003812012-10-04 17:17:59 -07001748 logging.info("Sending flow add to switch:")
1749 logging.info(str(fc))
1750 logging.info("should be canonicalized as:")
1751 logging.info(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001752 fc.send_rem = False
1753 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1754
1755 # Do barrier, to make sure all flows are in
1756
1757 self.assertTrue(sw.barrier(), "Barrier failed")
1758
1759 result = True
1760
Howard Persh9cab4822012-09-11 17:08:40 -07001761 sw.settle() # Allow switch to settle and generate any notifications
1762
rootf6af1672012-04-06 09:46:29 -07001763 # Check for any error messages
1764
1765 if not sw.errors_verify(0):
1766 result = False
1767
1768 # Verify flow table
1769
1770 sw.flow_tbl = ft
1771 if not sw.flow_tbl_verify():
1772 result = False
1773
1774 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001775 logging.info("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001776
1777
Howard Persh07d99e62012-04-09 15:26:57 -07001778# FLOW ADD 6
1779#
1780# OVERVIEW
1781# Test flow table capacity
1782#
1783# PURPOSE
1784# - Test switch can accept as many flow definitions as it claims
1785# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1786# - Test that attempting to create flows beyond capacity does not corrupt
1787# flow table
1788#
1789# PARAMETERS
1790# None
1791#
1792# PROCESS
1793# 1. Delete all flows from switch
1794# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1795# to determine flow table size, N
1796# 3. Generate (N + 1) distinct flow configurations
1797# 4. Send N flow adds to switch, for flows generated in step 3 above
1798# 5. Verify flow table in switch
1799# 6. Send one more flow add to switch
1800# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1801# response was generated by switch, for last flow mod sent
1802# 7. Retrieve flow stats from switch
1803# 8. Verify flow table in switch
1804# 9. Test PASSED iff:
1805# - error message received, for correct flow
1806# - last flow definition sent to switch is not in flow table
1807# else test FAILED
1808
Howard Persh3340d452012-04-06 16:45:21 -07001809# Disabled because of bogus capacity reported by OVS.
1810# Should be DUT dependent.
1811test_prio["Flow_Add_6"] = -1
1812
rootf6af1672012-04-06 09:46:29 -07001813class Flow_Add_6(basic.SimpleProtocol):
1814 """
1815 Test FLOW_ADD_6 from draft top-half test plan
1816
1817 INPUTS
1818 num_flows - Number of flows to generate
1819 """
Howard Pershc7963582012-03-29 10:02:59 -07001820
1821 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001822 logging.info("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001823
rootf6af1672012-04-06 09:46:29 -07001824 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001825
Rich Lane9a003812012-10-04 17:17:59 -07001826 logging.info("Deleting all flows from switch")
1827 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001828 self.assertEqual(rc, 0, "Failed to delete all flows")
1829
1830 # Get switch capabilites
1831
rootf6af1672012-04-06 09:46:29 -07001832 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001833 self.assertTrue(sw.connect(self.controller), \
1834 "Failed to connect to switch" \
1835 )
rootf6af1672012-04-06 09:46:29 -07001836
root2843d2b2012-04-06 10:27:46 -07001837 num_flows = 0
rootf6af1672012-04-06 09:46:29 -07001838 for ts in sw.tbl_stats.stats:
1839 num_flows = num_flows + ts.max_entries
1840
Rich Lane9a003812012-10-04 17:17:59 -07001841 logging.info("Switch capacity is %d flows" % (num_flows))
1842 logging.info("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001843
1844 # Dream up some flow information, i.e. space to chose from for
1845 # random flow parameter generation
1846
1847 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001848 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001849
1850 # Create a flow table, to switch's capacity
1851
1852 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001853 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07001854
1855 # Send flow table to switch
1856
Rich Lane9a003812012-10-04 17:17:59 -07001857 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001858 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001859 logging.info("Adding flow:")
1860 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001861 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1862
1863 # Do barrier, to make sure all flows are in
1864
1865 self.assertTrue(sw.barrier(), "Barrier failed")
1866
1867 result = True
1868
Howard Persh9cab4822012-09-11 17:08:40 -07001869 sw.settle() # Allow switch to settle and generate any notifications
1870
rootf6af1672012-04-06 09:46:29 -07001871 # Check for any error messages
1872
1873 if not sw.errors_verify(0):
1874 result = False
1875
1876 # Dream up one more flow
1877
Rich Lane9a003812012-10-04 17:17:59 -07001878 logging.info("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001879 while True:
1880 fc = Flow_Cfg()
1881 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001882 required_wildcards(self), \
Howard Persh07d99e62012-04-09 15:26:57 -07001883 sw.tbl_stats.stats[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001884 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001885 sw.valid_ports, \
1886 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001887 )
1888 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001889 if not ft.find(fc):
1890 break
rootf6af1672012-04-06 09:46:29 -07001891
1892 # Send one-more flow
1893
1894 fc.send_rem = False
Rich Lane9a003812012-10-04 17:17:59 -07001895 logging.info("Sending flow add switch")
1896 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001897 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1898
1899 # Do barrier, to make sure all flows are in
1900
1901 self.assertTrue(sw.barrier(), "Barrier failed")
1902
Howard Persh9cab4822012-09-11 17:08:40 -07001903 sw.settle() # Allow switch to settle and generate any notifications
1904
rootf6af1672012-04-06 09:46:29 -07001905 # Check for expected error message
1906
1907 if not sw.errors_verify(1, \
1908 ofp.OFPET_FLOW_MOD_FAILED, \
1909 ofp.OFPFMFC_ALL_TABLES_FULL \
1910 ):
1911 result = False
1912
1913 # Verify flow table
1914
1915 sw.flow_tbl = ft
1916 if not sw.flow_tbl_verify():
1917 result = False
1918
1919 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001920 logging.info("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001921
1922
Howard Persh07d99e62012-04-09 15:26:57 -07001923# FLOW ADD 7
1924#
1925# OVERVIEW
1926# Test flow redefinition
1927#
1928# PURPOSE
1929# Verify that successive flow adds with same priority and match criteria
1930# overwrite in flow table
1931#
1932# PARAMETERS
1933# None
1934#
1935# PROCESS
1936# 1. Delete all flows from switch
1937# 2. Generate flow definition F1
1938# 3. Generate flow definition F2, with same key (priority and match) as F1,
1939# but with different actions
1940# 4. Send flow adds for F1 and F2 to switch
1941# 5. Verify flow definitions in switch
1942# 6. Test PASSED iff 1 flow returned by switch, matching configuration of F2;
1943# else test FAILED
1944
rootf6af1672012-04-06 09:46:29 -07001945class Flow_Add_7(basic.SimpleProtocol):
1946 """
1947 Test FLOW_ADD_7 from draft top-half test plan
1948
1949 INPUTS
1950 None
1951 """
1952
1953 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001954 logging.info("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001955
1956 # Clear all flows from switch
1957
Rich Lane9a003812012-10-04 17:17:59 -07001958 logging.info("Deleting all flows from switch")
1959 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001960 self.assertEqual(rc, 0, "Failed to delete all flows")
1961
1962 # Get switch capabilites
1963
rootf6af1672012-04-06 09:46:29 -07001964 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001965 self.assertTrue(sw.connect(self.controller), \
1966 "Failed to connect to switch" \
1967 )
rootf6af1672012-04-06 09:46:29 -07001968
1969 # Dream up some flow information, i.e. space to chose from for
1970 # random flow parameter generation
1971
1972 fi = Flow_Info()
1973 fi.rand(10)
1974
1975 # Dream up a flow config
1976
1977 fc = Flow_Cfg()
1978 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001979 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07001980 sw.tbl_stats.stats[0].wildcards, \
1981 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001982 sw.valid_ports, \
1983 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001984 )
1985 fc = fc.canonical()
1986
1987 # Send it to the switch
1988
Rich Lane9a003812012-10-04 17:17:59 -07001989 logging.info("Sending flow add to switch:")
1990 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001991 ft = Flow_Tbl()
1992 fc.send_rem = False
1993 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1994 ft.insert(fc)
1995
1996 # Dream up some different actions, with the same flow key
1997
1998 fc2 = copy.deepcopy(fc)
1999 while True:
2000 fc2.rand_mod(fi, \
2001 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002002 sw.valid_ports, \
2003 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002004 )
2005 if fc2 != fc:
2006 break
2007
2008 # Send that to the switch
2009
Rich Lane9a003812012-10-04 17:17:59 -07002010 logging.info("Sending flow add to switch:")
2011 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002012 fc2.send_rem = False
2013 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
2014 ft.insert(fc2)
2015
2016 # Do barrier, to make sure all flows are in
2017
2018 self.assertTrue(sw.barrier(), "Barrier failed")
2019
2020 result = True
2021
Howard Persh9cab4822012-09-11 17:08:40 -07002022 sw.settle() # Allow switch to settle and generate any notifications
2023
rootf6af1672012-04-06 09:46:29 -07002024 # Check for any error messages
2025
2026 if not sw.errors_verify(0):
2027 result = False
2028
2029 # Verify flow table
2030
2031 sw.flow_tbl = ft
2032 if not sw.flow_tbl_verify():
2033 result = False
2034
2035 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002036 logging.info("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002037
2038
Howard Persh07d99e62012-04-09 15:26:57 -07002039# FLOW ADD 8
2040#
2041# OVERVIEW
2042# Add overlapping flows to switch, verify that overlapping flows are rejected
2043#
2044# PURPOSE
2045# - Test detection of overlapping flows by switch
2046# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
2047# - Test rejection of overlapping flows
2048# - Test defining overlapping flows does not corrupt flow table
2049#
2050# PARAMETERS
2051# None
2052#
2053# PROCESS
2054# 1. Delete all flows from switch
2055# 2. Generate flow definition F1
2056# 3. Generate flow definition F2, with key overlapping F1
2057# 4. Send flow add to switch, for F1
2058# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
2059# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
2060# was generated by switch
2061# 7. Verifiy flows configured in swtich
2062# 8. Test PASSED iff:
2063# - error message received, for overlapping flow
2064# - overlapping flow is not in flow table
2065# else test FAILED
2066
rootf6af1672012-04-06 09:46:29 -07002067class Flow_Add_8(basic.SimpleProtocol):
2068 """
2069 Test FLOW_ADD_8 from draft top-half test plan
2070
2071 INPUTS
2072 None
2073 """
2074
2075 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002076 logging.info("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002077
2078 # Clear all flows from switch
2079
Rich Lane9a003812012-10-04 17:17:59 -07002080 logging.info("Deleting all flows from switch")
2081 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002082 self.assertEqual(rc, 0, "Failed to delete all flows")
2083
2084 # Get switch capabilites
2085
rootf6af1672012-04-06 09:46:29 -07002086 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002087 self.assertTrue(sw.connect(self.controller), \
2088 "Failed to connect to switch" \
2089 )
rootf6af1672012-04-06 09:46:29 -07002090
2091 # Dream up some flow information, i.e. space to chose from for
2092 # random flow parameter generation
2093
2094 fi = Flow_Info()
2095 fi.rand(10)
2096
2097 # Dream up a flow config, with at least 1 qualifier specified
2098
2099 fc = Flow_Cfg()
2100 while True:
2101 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002102 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002103 sw.tbl_stats.stats[0].wildcards, \
2104 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002105 sw.valid_ports, \
2106 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002107 )
2108 fc = fc.canonical()
2109 if fc.match.wildcards != ofp.OFPFW_ALL:
2110 break
2111
2112 # Send it to the switch
2113
Rich Lane9a003812012-10-04 17:17:59 -07002114 logging.info("Sending flow add to switch:")
2115 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002116 ft = Flow_Tbl()
2117 fc.send_rem = False
2118 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2119 ft.insert(fc)
2120
2121 # Wildcard out one qualifier that was specified, to create an
2122 # overlapping flow
2123
2124 fc2 = copy.deepcopy(fc)
2125 for wi in shuffle(range(len(all_wildcards_list))):
2126 w = all_wildcards_list[wi]
2127 if (fc2.match.wildcards & w) == 0:
2128 break
2129 if w == ofp.OFPFW_NW_SRC_MASK:
2130 w = ofp.OFPFW_NW_SRC_ALL
2131 wn = "OFPFW_NW_SRC"
2132 elif w == ofp.OFPFW_NW_DST_MASK:
2133 w = ofp.OFPFW_NW_DST_ALL
2134 wn = "OFPFW_NW_DST"
2135 else:
2136 wn = all_wildcard_names[w]
Rich Lane9a003812012-10-04 17:17:59 -07002137 logging.info("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07002138 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07002139 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07002140
2141 # Send that to the switch, with overlap checking
2142
Rich Lane9a003812012-10-04 17:17:59 -07002143 logging.info("Sending flow add to switch:")
2144 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002145 fc2.send_rem = False
2146 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
2147
2148 # Do barrier, to make sure all flows are in
2149 self.assertTrue(sw.barrier(), "Barrier failed")
2150
2151 result = True
2152
Howard Persh9cab4822012-09-11 17:08:40 -07002153 sw.settle() # Allow switch to settle and generate any notifications
2154
rootf6af1672012-04-06 09:46:29 -07002155 # Check for expected error message
2156
2157 if not sw.errors_verify(1, \
2158 ofp.OFPET_FLOW_MOD_FAILED, \
2159 ofp.OFPFMFC_OVERLAP \
2160 ):
2161 result = False
2162
2163 # Verify flow table
2164
2165 sw.flow_tbl = ft
2166 if not sw.flow_tbl_verify():
2167 result = False
2168
2169 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002170 logging.info("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002171
2172
Howard Persh07d99e62012-04-09 15:26:57 -07002173# FLOW MODIFY 1
2174#
2175# OVERVIEW
2176# Strict modify of single existing flow
2177#
2178# PURPOSE
2179# - Verify that strict flow modify operates only on specified flow
2180# - Verify that flow is correctly modified
2181#
2182# PARAMETERS
2183# None
2184#
2185# PROCESS
2186# 1. Delete all flows from switch
2187# 2. Generate 1 flow F
2188# 3. Send flow add to switch, for flow F
2189# 4. Generate new action list for flow F, yielding F'
2190# 5. Send strict flow modify to switch, for flow F'
2191# 6. Verify flow table in switch
2192# 7. Test PASSED iff flow returned by switch is F'; else FAILED
2193
rootf6af1672012-04-06 09:46:29 -07002194class Flow_Mod_1(basic.SimpleProtocol):
2195 """
2196 Test FLOW_MOD_1 from draft top-half test plan
2197
2198 INPUTS
2199 None
2200 """
2201
2202 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002203 logging.info("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002204
2205 # Clear all flows from switch
2206
Rich Lane9a003812012-10-04 17:17:59 -07002207 logging.info("Deleting all flows from switch")
2208 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002209 self.assertEqual(rc, 0, "Failed to delete all flows")
2210
2211 # Get switch capabilites
2212
rootf6af1672012-04-06 09:46:29 -07002213 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002214 self.assertTrue(sw.connect(self.controller), \
2215 "Failed to connect to switch" \
2216 )
rootf6af1672012-04-06 09:46:29 -07002217
2218 # Dream up some flow information, i.e. space to chose from for
2219 # random flow parameter generation
2220
2221 fi = Flow_Info()
2222 fi.rand(10)
2223
2224 # Dream up a flow config
2225
2226 fc = Flow_Cfg()
2227 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002228 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002229 sw.tbl_stats.stats[0].wildcards, \
2230 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002231 sw.valid_ports, \
2232 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002233 )
2234 fc = fc.canonical()
2235
2236 # Send it to the switch
2237
Rich Lane9a003812012-10-04 17:17:59 -07002238 logging.info("Sending flow add to switch:")
2239 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002240 ft = Flow_Tbl()
2241 fc.send_rem = False
2242 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2243 ft.insert(fc)
2244
2245 # Dream up some different actions, with the same flow key
2246
2247 fc2 = copy.deepcopy(fc)
2248 while True:
2249 fc2.rand_mod(fi, \
2250 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002251 sw.valid_ports, \
2252 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002253 )
2254 if fc2 != fc:
2255 break
2256
2257 # Send that to the switch
2258
Rich Lane9a003812012-10-04 17:17:59 -07002259 logging.info("Sending strict flow mod to switch:")
2260 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002261 fc2.send_rem = False
2262 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2263 ft.insert(fc2)
2264
2265 # Do barrier, to make sure all flows are in
2266
2267 self.assertTrue(sw.barrier(), "Barrier failed")
2268
2269 result = True
2270
Howard Persh9cab4822012-09-11 17:08:40 -07002271 sw.settle() # Allow switch to settle and generate any notifications
2272
rootf6af1672012-04-06 09:46:29 -07002273 # Check for any error messages
2274
2275 if not sw.errors_verify(0):
2276 result = False
2277
2278 # Verify flow table
2279
2280 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002281 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002282 result = False
2283
2284 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002285 logging.info("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002286
Howard Persh07d99e62012-04-09 15:26:57 -07002287
2288# FLOW MODIFY 2
2289#
2290# OVERVIEW
2291# Loose modify of mutiple flows
2292#
2293# PURPOSE
2294# - Verify that loose flow modify operates only on matching flows
2295# - Verify that matching flows are correctly modified
2296#
2297# PARAMETERS
2298# Name: num_flows
2299# Type: number
2300# Description:
2301# Number of flows to define
2302# Default: 100
2303#
2304# PROCESS
2305# 1. Delete all flows from switch
2306# 2. Generate <num_flows> distinct flow configurations
2307# 3. Send <num_flows> flow adds to switch
2308# 4. Pick 1 defined flow F at random
2309# 5. Create overlapping loose flow mod match criteria by repeatedly
2310# wildcarding out qualifiers in match of F => F',
2311# and create new actions list A' for F'
2312# 6. Send loose flow modify for F' to switch
2313# 7. Verify flow table in swtich
2314# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2315# are returned in step 7 above, each with correct (original or modified)
2316# action list;
2317# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002318
2319class Flow_Mod_2(basic.SimpleProtocol):
2320 """
2321 Test FLOW_MOD_2 from draft top-half test plan
2322
2323 INPUTS
2324 None
2325 """
2326
2327 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002328 logging.info("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002329
Dan Talayco910a8282012-04-07 00:05:20 -07002330 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002331
2332 # Clear all flows from switch
2333
Rich Lane9a003812012-10-04 17:17:59 -07002334 logging.info("Deleting all flows from switch")
2335 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002336 self.assertEqual(rc, 0, "Failed to delete all flows")
2337
2338 # Get switch capabilites
2339
rootf6af1672012-04-06 09:46:29 -07002340 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002341 self.assertTrue(sw.connect(self.controller), \
2342 "Failed to connect to switch" \
2343 )
rootf6af1672012-04-06 09:46:29 -07002344
2345 # Dream up some flow information, i.e. space to chose from for
2346 # random flow parameter generation
2347
2348 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002349 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002350 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002351
2352 # Dream up some flows
2353
2354 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002355 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002356
2357 # Send flow table to switch
2358
Rich Lane9a003812012-10-04 17:17:59 -07002359 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002360 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002361 logging.info("Adding flow:")
2362 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002363 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2364
2365 # Do barrier, to make sure all flows are in
2366
2367 self.assertTrue(sw.barrier(), "Barrier failed")
2368
2369 result = True
2370
Howard Persh9cab4822012-09-11 17:08:40 -07002371 sw.settle() # Allow switch to settle and generate any notifications
2372
rootf6af1672012-04-06 09:46:29 -07002373 # Check for any error messages
2374
2375 if not sw.errors_verify(0):
2376 result = False
2377
2378 # Verify flow table
2379
2380 sw.flow_tbl = ft
2381 if not sw.flow_tbl_verify():
2382 result = False
2383
2384 # Pick a random flow as a basis
Howard Persh5f3c83f2012-04-13 09:57:10 -07002385
2386 mfc = copy.deepcopy((ft.values())[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002387 mfc.rand_mod(fi, \
2388 sw.sw_features.actions, \
2389 sw.valid_ports, \
2390 sw.valid_queues \
2391 )
rootf6af1672012-04-06 09:46:29 -07002392
2393 # Repeatedly wildcard qualifiers
2394
2395 for wi in shuffle(range(len(all_wildcards_list))):
2396 w = all_wildcards_list[wi]
2397 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2398 n = wildcard_get(mfc.match.wildcards, w)
2399 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002400 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2401 w, \
2402 random.randint(n + 1, 32) \
2403 )
rootf6af1672012-04-06 09:46:29 -07002404 else:
2405 continue
2406 else:
2407 if wildcard_get(mfc.match.wildcards, w) == 0:
2408 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2409 else:
2410 continue
2411 mfc = mfc.canonical()
2412
2413 # Count the number of flows that would be modified
2414
2415 n = 0
2416 for fc in ft.values():
2417 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2418 n = n + 1
2419
2420 # If more than 1, we found our loose delete flow spec
2421 if n > 1:
2422 break
2423
Rich Lane9a003812012-10-04 17:17:59 -07002424 logging.info("Modifying %d flows" % (n))
2425 logging.info("Sending flow mod to switch:")
2426 logging.info(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002427 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2428
2429 # Do barrier, to make sure all flows are in
2430 self.assertTrue(sw.barrier(), "Barrier failed")
2431
Howard Persh9cab4822012-09-11 17:08:40 -07002432 sw.settle() # Allow switch to settle and generate any notifications
2433
rootf6af1672012-04-06 09:46:29 -07002434 # Check for error message
2435
2436 if not sw.errors_verify(0):
2437 result = False
2438
2439 # Apply flow mod to local flow table
2440
2441 for fc in ft.values():
2442 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002443 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002444
2445 # Verify flow table
2446
2447 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002448 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002449 result = False
2450
2451 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002452 logging.info("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002453
2454
Howard Persh07d99e62012-04-09 15:26:57 -07002455# FLOW MODIFY 3
2456
2457# OVERVIEW
2458# Strict modify of non-existent flow
2459#
2460# PURPOSE
2461# Verify that strict modify of a non-existent flow is equivalent to a flow add
2462#
2463# PARAMETERS
2464# None
2465#
2466# PROCESS
2467# 1. Delete all flows from switch
2468# 2. Send single flow mod, as strict modify, to switch
2469# 3. Verify flow table in switch
2470# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2471
rootf6af1672012-04-06 09:46:29 -07002472class Flow_Mod_3(basic.SimpleProtocol):
2473 """
2474 Test FLOW_MOD_3 from draft top-half test plan
2475
2476 INPUTS
2477 None
2478 """
2479
2480 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002481 logging.info("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002482
2483 # Clear all flows from switch
2484
Rich Lane9a003812012-10-04 17:17:59 -07002485 logging.info("Deleting all flows from switch")
2486 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002487 self.assertEqual(rc, 0, "Failed to delete all flows")
2488
2489 # Get switch capabilites
2490
rootf6af1672012-04-06 09:46:29 -07002491 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002492 self.assertTrue(sw.connect(self.controller), \
2493 "Failed to connect to switch" \
2494 )
rootf6af1672012-04-06 09:46:29 -07002495
2496 # Dream up some flow information, i.e. space to chose from for
2497 # random flow parameter generation
2498
2499 fi = Flow_Info()
2500 fi.rand(10)
2501
2502 # Dream up a flow config
2503
2504 fc = Flow_Cfg()
2505 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002506 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002507 sw.tbl_stats.stats[0].wildcards, \
2508 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002509 sw.valid_ports, \
2510 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002511 )
2512 fc = fc.canonical()
2513
2514 # Send it to the switch
2515
Rich Lane9a003812012-10-04 17:17:59 -07002516 logging.info("Sending flow mod to switch:")
2517 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002518 ft = Flow_Tbl()
2519 fc.send_rem = False
2520 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2521 ft.insert(fc)
2522
2523 # Do barrier, to make sure all flows are in
2524
2525 self.assertTrue(sw.barrier(), "Barrier failed")
2526
2527 result = True
2528
Howard Persh9cab4822012-09-11 17:08:40 -07002529 sw.settle() # Allow switch to settle and generate any notifications
2530
rootf6af1672012-04-06 09:46:29 -07002531 # Check for any error messages
2532
2533 if not sw.errors_verify(0):
2534 result = False
2535
2536 # Verify flow table
2537
2538 sw.flow_tbl = ft
2539 if not sw.flow_tbl_verify():
2540 result = False
2541
2542 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002543 logging.info("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002544
2545
Howard Persh8d21c1f2012-04-20 15:57:29 -07002546# FLOW MODIFY 3_1
2547
2548# OVERVIEW
2549# No-op modify
2550#
2551# PURPOSE
2552# Verify that modify of a flow with new actions same as old ones operates correctly
2553#
2554# PARAMETERS
2555# None
2556#
2557# PROCESS
2558# 1. Delete all flows from switch
2559# 2. Send single flow mod, as strict modify, to switch
2560# 3. Verify flow table in switch
2561# 4. Send same flow mod, as strict modify, to switch
2562# 5. Verify flow table in switch
2563# 6. Test PASSED iff flow defined in step 2 and 4 above verified; else FAILED
2564
2565class Flow_Mod_3_1(basic.SimpleProtocol):
2566 """
2567 Test FLOW_MOD_3_1 from draft top-half test plan
2568
2569 INPUTS
2570 None
2571 """
2572
2573 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002574 logging.info("Flow_Mod_3_1 TEST BEGIN")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002575
2576 # Clear all flows from switch
2577
Rich Lane9a003812012-10-04 17:17:59 -07002578 logging.info("Deleting all flows from switch")
2579 rc = delete_all_flows(self.controller)
Howard Persh8d21c1f2012-04-20 15:57:29 -07002580 self.assertEqual(rc, 0, "Failed to delete all flows")
2581
2582 # Get switch capabilites
2583
2584 sw = Switch()
2585 self.assertTrue(sw.connect(self.controller), \
2586 "Failed to connect to switch" \
2587 )
2588
2589 # Dream up some flow information, i.e. space to chose from for
2590 # random flow parameter generation
2591
2592 fi = Flow_Info()
2593 fi.rand(10)
2594
2595 # Dream up a flow config
2596
2597 fc = Flow_Cfg()
2598 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002599 required_wildcards(self), \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002600 sw.tbl_stats.stats[0].wildcards, \
2601 sw.sw_features.actions, \
2602 sw.valid_ports, \
2603 sw.valid_queues \
2604 )
2605 fc = fc.canonical()
2606
2607 # Send it to the switch
2608
Rich Lane9a003812012-10-04 17:17:59 -07002609 logging.info("Sending flow mod to switch:")
2610 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002611 ft = Flow_Tbl()
2612 fc.send_rem = False
2613 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2614 ft.insert(fc)
2615
2616 # Do barrier, to make sure all flows are in
2617
2618 self.assertTrue(sw.barrier(), "Barrier failed")
2619
2620 result = True
2621
Howard Persh9cab4822012-09-11 17:08:40 -07002622 sw.settle() # Allow switch to settle and generate any notifications
2623
Howard Persh8d21c1f2012-04-20 15:57:29 -07002624 # Check for any error messages
2625
2626 if not sw.errors_verify(0):
2627 result = False
2628
2629 # Verify flow table
2630
2631 sw.flow_tbl = ft
2632 if not sw.flow_tbl_verify():
2633 result = False
2634
2635 # Send same flow to the switch again
2636
Rich Lane9a003812012-10-04 17:17:59 -07002637 logging.info("Sending flow mod to switch:")
2638 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002639 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2640
2641 # Do barrier, to make sure all flows are in
2642
2643 self.assertTrue(sw.barrier(), "Barrier failed")
2644
Howard Persh9cab4822012-09-11 17:08:40 -07002645 sw.settle() # Allow switch to settle and generate any notifications
2646
Howard Persh8d21c1f2012-04-20 15:57:29 -07002647 # Check for any error messages
2648
2649 if not sw.errors_verify(0):
2650 result = False
2651
2652 # Verify flow table
2653
2654 if not sw.flow_tbl_verify():
2655 result = False
2656
2657 self.assertTrue(result, "Flow_Mod_3_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002658 logging.info("Flow_Mod_3_1 TEST PASSED")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002659
2660
Howard Persh07d99e62012-04-09 15:26:57 -07002661# FLOW DELETE 1
2662#
2663# OVERVIEW
2664# Strict delete of single flow
2665#
2666# PURPOSE
2667# Verify correct operation of strict delete of single defined flow
2668#
2669# PARAMETERS
2670# None
2671#
2672# PROCESS
2673# 1. Delete all flows from switch
2674# 2. Send flow F to switch
2675# 3. Send strict flow delete for F to switch
2676# 4. Verify flow table in swtich
2677# 6. Test PASSED iff all flows sent to switch in step 2 above,
2678# less flow removed in step 3 above, are returned in step 4 above;
2679# else test FAILED
2680
rootf6af1672012-04-06 09:46:29 -07002681class Flow_Del_1(basic.SimpleProtocol):
2682 """
2683 Test FLOW_DEL_1 from draft top-half test plan
2684
2685 INPUTS
2686 None
2687 """
2688
2689 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002690 logging.info("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002691
2692 # Clear all flows from switch
2693
Rich Lane9a003812012-10-04 17:17:59 -07002694 logging.info("Deleting all flows from switch")
2695 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002696 self.assertEqual(rc, 0, "Failed to delete all flows")
2697
2698 # Get switch capabilites
2699
rootf6af1672012-04-06 09:46:29 -07002700 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002701 self.assertTrue(sw.connect(self.controller), \
2702 "Failed to connect to switch" \
2703 )
rootf6af1672012-04-06 09:46:29 -07002704
2705 # Dream up some flow information, i.e. space to chose from for
2706 # random flow parameter generation
2707
2708 fi = Flow_Info()
2709 fi.rand(10)
2710
2711 # Dream up a flow config
2712
2713 fc = Flow_Cfg()
2714 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002715 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002716 sw.tbl_stats.stats[0].wildcards, \
2717 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002718 sw.valid_ports, \
2719 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002720 )
2721 fc = fc.canonical()
2722
2723 # Send it to the switch
2724
Rich Lane9a003812012-10-04 17:17:59 -07002725 logging.info("Sending flow add to switch:")
2726 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002727 ft = Flow_Tbl()
2728 fc.send_rem = False
2729 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2730 ft.insert(fc)
2731
2732 # Dream up some different actions, with the same flow key
2733
2734 fc2 = copy.deepcopy(fc)
2735 while True:
2736 fc2.rand_mod(fi, \
2737 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002738 sw.valid_ports, \
2739 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002740 )
2741 if fc2 != fc:
2742 break
2743
2744 # Delete strictly
2745
Rich Lane9a003812012-10-04 17:17:59 -07002746 logging.info("Sending strict flow del to switch:")
2747 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002748 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2749 ft.delete(fc)
2750
2751 # Do barrier, to make sure all flows are in
2752
2753 self.assertTrue(sw.barrier(), "Barrier failed")
2754
2755 result = True
2756
Howard Persh9cab4822012-09-11 17:08:40 -07002757 sw.settle() # Allow switch to settle and generate any notifications
2758
rootf6af1672012-04-06 09:46:29 -07002759 # Check for any error messages
2760
2761 if not sw.errors_verify(0):
2762 result = False
2763
2764 # Verify flow table
2765
2766 sw.flow_tbl = ft
2767 if not sw.flow_tbl_verify():
2768 result = False
2769
2770 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002771 logging.info("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002772
2773
Howard Persh07d99e62012-04-09 15:26:57 -07002774# FLOW DELETE 2
2775#
2776# OVERVIEW
2777# Loose delete of multiple flows
2778#
2779# PURPOSE
2780# - Verify correct operation of loose delete of multiple flows
2781#
2782# PARAMETERS
2783# Name: num_flows
2784# Type: number
2785# Description:
2786# Number of flows to define
2787# Default: 100
2788#
2789# PROCESS
2790# 1. Delete all flows from switch
2791# 2. Generate <num_flows> distinct flow configurations
2792# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2793# 4. Pick 1 defined flow F at random
2794# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2795# F' will match more than 1 existing flow key
2796# 6. Send loose flow delete for F' to switch
2797# 7. Verify flow table in switch
2798# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2799# removed in step 6 above (i.e. those that match F'), are returned
2800# in step 7 above;
2801# else test FAILED
2802
rootf6af1672012-04-06 09:46:29 -07002803class Flow_Del_2(basic.SimpleProtocol):
2804 """
2805 Test FLOW_DEL_2 from draft top-half test plan
2806
2807 INPUTS
2808 None
2809 """
2810
2811 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002812 logging.info("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002813
Dan Talayco910a8282012-04-07 00:05:20 -07002814 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002815
2816 # Clear all flows from switch
2817
Rich Lane9a003812012-10-04 17:17:59 -07002818 logging.info("Deleting all flows from switch")
2819 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002820 self.assertEqual(rc, 0, "Failed to delete all flows")
2821
2822 # Get switch capabilites
2823
rootf6af1672012-04-06 09:46:29 -07002824 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002825 self.assertTrue(sw.connect(self.controller), \
2826 "Failed to connect to switch" \
2827 )
rootf6af1672012-04-06 09:46:29 -07002828
2829 # Dream up some flow information, i.e. space to chose from for
2830 # random flow parameter generation
2831
2832 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002833 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002834 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002835
2836 # Dream up some flows
2837
2838 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002839 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002840
2841 # Send flow table to switch
2842
Rich Lane9a003812012-10-04 17:17:59 -07002843 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002844 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002845 logging.info("Adding flow:")
2846 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002847 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2848
2849 # Do barrier, to make sure all flows are in
2850
2851 self.assertTrue(sw.barrier(), "Barrier failed")
2852
2853 result = True
2854
Howard Persh9cab4822012-09-11 17:08:40 -07002855 sw.settle() # Allow switch to settle and generate any notifications
2856
rootf6af1672012-04-06 09:46:29 -07002857 # Check for any error messages
2858
2859 if not sw.errors_verify(0):
2860 result = False
2861
2862 # Verify flow table
2863
2864 sw.flow_tbl = ft
2865 if not sw.flow_tbl_verify():
2866 result = False
2867
2868 # Pick a random flow as a basis
2869
2870 dfc = copy.deepcopy(ft.values()[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002871 dfc.rand_mod(fi, \
2872 sw.sw_features.actions, \
2873 sw.valid_ports, \
2874 sw.valid_queues \
2875 )
rootf6af1672012-04-06 09:46:29 -07002876
2877 # Repeatedly wildcard qualifiers
2878
2879 for wi in shuffle(range(len(all_wildcards_list))):
2880 w = all_wildcards_list[wi]
2881 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2882 n = wildcard_get(dfc.match.wildcards, w)
2883 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002884 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2885 w, \
2886 random.randint(n + 1, 32) \
2887 )
rootf6af1672012-04-06 09:46:29 -07002888 else:
2889 continue
2890 else:
2891 if wildcard_get(dfc.match.wildcards, w) == 0:
2892 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2893 else:
2894 continue
2895 dfc = dfc.canonical()
2896
2897 # Count the number of flows that would be deleted
2898
2899 n = 0
2900 for fc in ft.values():
2901 if dfc.overlaps(fc, True):
2902 n = n + 1
2903
2904 # If more than 1, we found our loose delete flow spec
2905 if n > 1:
2906 break
2907
Rich Lane9a003812012-10-04 17:17:59 -07002908 logging.info("Deleting %d flows" % (n))
2909 logging.info("Sending flow del to switch:")
2910 logging.info(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002911 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2912
2913 # Do barrier, to make sure all flows are in
2914 self.assertTrue(sw.barrier(), "Barrier failed")
2915
Howard Persh9cab4822012-09-11 17:08:40 -07002916 sw.settle() # Allow switch to settle and generate any notifications
2917
rootf6af1672012-04-06 09:46:29 -07002918 # Check for error message
2919
2920 if not sw.errors_verify(0):
2921 result = False
2922
2923 # Apply flow mod to local flow table
2924
2925 for fc in ft.values():
2926 if dfc.overlaps(fc, True):
2927 ft.delete(fc)
2928
2929 # Verify flow table
2930
2931 sw.flow_tbl = ft
2932 if not sw.flow_tbl_verify():
2933 result = False
2934
2935 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002936 logging.info("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002937
2938
Howard Persh07d99e62012-04-09 15:26:57 -07002939# FLOW DELETE 4
2940#
2941# OVERVIEW
2942# Flow removed messages
2943#
2944# PURPOSE
2945# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2946# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2947#
2948# PARAMETERS
2949# None
2950#
2951# PROCESS
2952# 1. Delete all flows from switch
2953# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2954# 3. Send strict flow delete of flow to switch
2955# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2956# 5. Verify flow table in switch
2957# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2958# removed in step 3 above, are returned in step 5 above, and that
2959# asynch message was received; else test FAILED
2960
2961
rootf6af1672012-04-06 09:46:29 -07002962class Flow_Del_4(basic.SimpleProtocol):
2963 """
2964 Test FLOW_DEL_4 from draft top-half test plan
2965
2966 INPUTS
2967 None
2968 """
2969
2970 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002971 logging.info("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002972
2973 # Clear all flows from switch
2974
Rich Lane9a003812012-10-04 17:17:59 -07002975 logging.info("Deleting all flows from switch")
2976 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002977 self.assertEqual(rc, 0, "Failed to delete all flows")
2978
2979 # Get switch capabilites
2980
rootf6af1672012-04-06 09:46:29 -07002981 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002982 self.assertTrue(sw.connect(self.controller), \
2983 "Failed to connect to switch" \
2984 )
rootf6af1672012-04-06 09:46:29 -07002985
2986 # Dream up some flow information, i.e. space to chose from for
2987 # random flow parameter generation
2988
2989 fi = Flow_Info()
2990 fi.rand(10)
2991
2992 # Dream up a flow config
2993
2994 fc = Flow_Cfg()
2995 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002996 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002997 sw.tbl_stats.stats[0].wildcards, \
2998 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002999 sw.valid_ports, \
3000 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07003001 )
3002 fc = fc.canonical()
3003
3004 # Send it to the switch. with "notify on removed"
3005
Rich Lane9a003812012-10-04 17:17:59 -07003006 logging.info("Sending flow add to switch:")
3007 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07003008 ft = Flow_Tbl()
3009 fc.send_rem = True
3010 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
3011 ft.insert(fc)
3012
3013 # Dream up some different actions, with the same flow key
3014
3015 fc2 = copy.deepcopy(fc)
3016 while True:
3017 fc2.rand_mod(fi, \
3018 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07003019 sw.valid_ports, \
3020 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07003021 )
3022 if fc2 != fc:
3023 break
3024
3025 # Delete strictly
3026
Rich Lane9a003812012-10-04 17:17:59 -07003027 logging.info("Sending strict flow del to switch:")
3028 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07003029 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
3030 ft.delete(fc)
3031
3032 # Do barrier, to make sure all flows are in
3033
3034 self.assertTrue(sw.barrier(), "Barrier failed")
3035
3036 result = True
3037
Howard Persh9cab4822012-09-11 17:08:40 -07003038 sw.settle() # Allow switch to settle and generate any notifications
3039
rootf6af1672012-04-06 09:46:29 -07003040 # Check for expected "removed" message
3041
Howard Persh3340d452012-04-06 16:45:21 -07003042 if not sw.errors_verify(0):
3043 result = False
3044
3045 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07003046 result = False
3047
3048 # Verify flow table
3049
3050 sw.flow_tbl = ft
3051 if not sw.flow_tbl_verify():
3052 result = False
3053
3054 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07003055 logging.info("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07003056