blob: cd607ddd8a17e92b7fae77ff7075732b8df07d35 [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
Howard Pershc7963582012-03-29 10:02:59 -070087def test_set_init(config):
88 """
89 Set up function for packet action test classes
90
91 @param config The configuration dictionary; see oft
92 """
93
94 basic.test_set_init(config)
95
Dan Talayco910a8282012-04-07 00:05:20 -070096 global fq_port_map
Dan Talayco910a8282012-04-07 00:05:20 -070097 global fq_config
Howard Pershc7963582012-03-29 10:02:59 -070098
Dan Talayco910a8282012-04-07 00:05:20 -070099 fq_port_map = config["port_map"]
100 fq_config = config
root2843d2b2012-04-06 10:27:46 -0700101
Howard Pershc7963582012-03-29 10:02:59 -0700102
rootf6af1672012-04-06 09:46:29 -0700103def flip_coin():
104 return random.randint(1, 100) <= 50
105
106
Howard Pershc7963582012-03-29 10:02:59 -0700107def shuffle(list):
108 n = len(list)
109 lim = n * n
110 i = 0
111 while i < lim:
112 a = random.randint(0, n - 1)
113 b = random.randint(0, n - 1)
114 temp = list[a]
115 list[a] = list[b]
116 list[b] = temp
117 i = i + 1
118 return list
119
120
Howard Persh680b92a2012-03-31 13:34:35 -0700121def rand_pick(list):
122 return list[random.randint(0, len(list) - 1)]
Howard Pershc7963582012-03-29 10:02:59 -0700123
Howard Persh680b92a2012-03-31 13:34:35 -0700124def rand_dl_addr():
125 return [random.randint(0, 255) & ~1,
126 random.randint(0, 255),
127 random.randint(0, 255),
128 random.randint(0, 255),
129 random.randint(0, 255),
130 random.randint(0, 255)
131 ]
Howard Pershc7963582012-03-29 10:02:59 -0700132
133def rand_nw_addr():
134 return random.randint(0, (1 << 32) - 1)
135
136
rootf6af1672012-04-06 09:46:29 -0700137class Flow_Info:
Howard Persh680b92a2012-03-31 13:34:35 -0700138 # Members:
139 # priorities - list of flow priorities
140 # dl_addrs - list of MAC addresses
141 # vlans - list of VLAN ids
142 # ethertypes - list of Ethertypes
143 # ip_addrs - list of IP addresses
144 # ip_tos - list of IP TOS values
145 # ip_protos - list of IP protocols
146 # l4_ports - list of L4 ports
147
148 def __init__(self):
149 priorities = []
150 dl_addrs = []
151 vlans = []
152 ethertypes = []
153 ip_addrs = []
154 ip_tos = []
155 ip_protos = []
156 l4_ports = []
157
158 def rand(self, n):
159 self.priorities = []
160 i = 0
161 while i < n:
162 self.priorities.append(random.randint(1, 65534))
163 i = i + 1
164
165 self.dl_addrs = []
166 i = 0
167 while i < n:
168 self.dl_addrs.append(rand_dl_addr())
169 i = i + 1
170
Howard Pershb10a47a2012-08-21 13:54:47 -0700171 if test_param_get(fq_config, "vlans", []) != []:
172 self.vlans = test_param_get(fq_config, "vlans", [])
173
Rich Lane9a003812012-10-04 17:17:59 -0700174 logging.info("Overriding VLAN ids to:")
175 logging.info(self.vlans)
Howard Pershb10a47a2012-08-21 13:54:47 -0700176 else:
177 self.vlans = []
178 i = 0
179 while i < n:
180 self.vlans.append(random.randint(1, 4094))
181 i = i + 1
Howard Persh680b92a2012-03-31 13:34:35 -0700182
rootf6af1672012-04-06 09:46:29 -0700183 self.ethertypes = [0x0800, 0x0806]
Howard Persh680b92a2012-03-31 13:34:35 -0700184 i = 0
185 while i < n:
186 self.ethertypes.append(random.randint(0, (1 << 16) - 1))
187 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700188 self.ethertypes = shuffle(self.ethertypes)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700189
190 self.ip_addrs = []
191 i = 0
192 while i < n:
193 self.ip_addrs.append(rand_nw_addr())
194 i = i + 1
195
196 self.ip_tos = []
197 i = 0
198 while i < n:
199 self.ip_tos.append(random.randint(0, (1 << 8) - 1) & ~3)
200 i = i + 1
201
rootf6af1672012-04-06 09:46:29 -0700202 self.ip_protos = [1, 6, 17]
Howard Persh680b92a2012-03-31 13:34:35 -0700203 i = 0
204 while i < n:
205 self.ip_protos.append(random.randint(0, (1 << 8) - 1))
206 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700207 self.ip_protos = shuffle(self.ip_protos)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700208
209 self.l4_ports = []
210 i = 0
211 while i < n:
212 self.l4_ports.append(random.randint(0, (1 << 16) - 1))
213 i = i + 1
214
215 def rand_priority(self):
216 return rand_pick(self.priorities)
217
218 def rand_dl_addr(self):
219 return rand_pick(self.dl_addrs)
220
221 def rand_vlan(self):
222 return rand_pick(self.vlans)
223
224 def rand_ethertype(self):
225 return rand_pick(self.ethertypes)
226
227 def rand_ip_addr(self):
228 return rand_pick(self.ip_addrs)
229
230 def rand_ip_tos(self):
231 return rand_pick(self.ip_tos)
232
233 def rand_ip_proto(self):
234 return rand_pick(self.ip_protos)
235
236 def rand_l4_port(self):
237 return rand_pick(self.l4_ports)
238
239
Howard Pershc7963582012-03-29 10:02:59 -0700240# TBD - These don't belong here
241
Howard Persh680b92a2012-03-31 13:34:35 -0700242all_wildcards_list = [ofp.OFPFW_IN_PORT,
Howard Persh680b92a2012-03-31 13:34:35 -0700243 ofp.OFPFW_DL_DST,
rootf6af1672012-04-06 09:46:29 -0700244 ofp.OFPFW_DL_SRC,
245 ofp.OFPFW_DL_VLAN,
246 ofp.OFPFW_DL_VLAN_PCP,
Howard Persh680b92a2012-03-31 13:34:35 -0700247 ofp.OFPFW_DL_TYPE,
rootf6af1672012-04-06 09:46:29 -0700248 ofp.OFPFW_NW_TOS,
Howard Persh680b92a2012-03-31 13:34:35 -0700249 ofp.OFPFW_NW_PROTO,
Howard Persh680b92a2012-03-31 13:34:35 -0700250 ofp.OFPFW_NW_SRC_MASK,
251 ofp.OFPFW_NW_DST_MASK,
rootf6af1672012-04-06 09:46:29 -0700252 ofp.OFPFW_TP_SRC,
253 ofp.OFPFW_TP_DST
Howard Persh680b92a2012-03-31 13:34:35 -0700254 ]
Howard Pershc7963582012-03-29 10:02:59 -0700255
Howard Persh3340d452012-04-06 16:45:21 -0700256# TBD - Need this because there are duplicates in ofp.ofp_flow_wildcards_map
257# -- FIX
rootf6af1672012-04-06 09:46:29 -0700258all_wildcard_names = {
259 1 : 'OFPFW_IN_PORT',
260 2 : 'OFPFW_DL_VLAN',
261 4 : 'OFPFW_DL_SRC',
262 8 : 'OFPFW_DL_DST',
263 16 : 'OFPFW_DL_TYPE',
264 32 : 'OFPFW_NW_PROTO',
265 64 : 'OFPFW_TP_SRC',
266 128 : 'OFPFW_TP_DST',
267 1048576 : 'OFPFW_DL_VLAN_PCP',
268 2097152 : 'OFPFW_NW_TOS'
269}
270
rootf6af1672012-04-06 09:46:29 -0700271def wildcard_set(x, w, val):
272 result = x
273 if w == ofp.OFPFW_NW_SRC_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700274 result = (result & ~ofp.OFPFW_NW_SRC_MASK) \
275 | (val << ofp.OFPFW_NW_SRC_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700276 elif w == ofp.OFPFW_NW_DST_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700277 result = (result & ~ofp.OFPFW_NW_DST_MASK) \
278 | (val << ofp.OFPFW_NW_DST_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700279 elif val == 0:
280 result = result & ~w
281 else:
282 result = result | w
283 return result
284
285def wildcard_get(x, w):
286 if w == ofp.OFPFW_NW_SRC_MASK:
287 return (x & ofp.OFPFW_NW_SRC_MASK) >> ofp.OFPFW_NW_SRC_SHIFT
288 if w == ofp.OFPFW_NW_DST_MASK:
289 return (x & ofp.OFPFW_NW_DST_MASK) >> ofp.OFPFW_NW_DST_SHIFT
290 return 1 if (x & w) != 0 else 0
291
Howard Persh8d21c1f2012-04-20 15:57:29 -0700292def wildcards_to_str(wildcards):
293 result = "{"
294 sep = ""
295 for w in all_wildcards_list:
296 if (wildcards & w) == 0:
297 continue
298 if w == ofp.OFPFW_NW_SRC_MASK:
299 n = wildcard_get(wildcards, w)
300 if n > 0:
301 result = result + sep + ("OFPFW_NW_SRC(%d)" % (n))
302 elif w == ofp.OFPFW_NW_DST_MASK:
303 n = wildcard_get(wildcards, w)
304 if n > 0:
305 result = result + sep + ("OFPFW_NW_DST(%d)" % (n))
306 else:
307 result = result + sep + all_wildcard_names[w]
308 sep = ", "
309 result = result +"}"
310 return result
Howard Pershc7963582012-03-29 10:02:59 -0700311
Howard Persh680b92a2012-03-31 13:34:35 -0700312all_actions_list = [ofp.OFPAT_OUTPUT,
313 ofp.OFPAT_SET_VLAN_VID,
314 ofp.OFPAT_SET_VLAN_PCP,
315 ofp.OFPAT_STRIP_VLAN,
316 ofp.OFPAT_SET_DL_SRC,
317 ofp.OFPAT_SET_DL_DST,
318 ofp.OFPAT_SET_NW_SRC,
319 ofp.OFPAT_SET_NW_DST,
320 ofp.OFPAT_SET_NW_TOS,
321 ofp.OFPAT_SET_TP_SRC,
322 ofp.OFPAT_SET_TP_DST,
323 ofp.OFPAT_ENQUEUE
324 ]
325
Howard Persh8d21c1f2012-04-20 15:57:29 -0700326def actions_bmap_to_str(bm):
327 result = "{"
328 sep = ""
329 for a in all_actions_list:
330 if ((1 << a) & bm) != 0:
331 result = result + sep + ofp.ofp_action_type_map[a]
332 sep = ", "
333 result = result + "}"
334 return result
335
Howard Persh680b92a2012-03-31 13:34:35 -0700336def dl_addr_to_str(a):
337 return "%x:%x:%x:%x:%x:%x" % tuple(a)
338
339def ip_addr_to_str(a, n):
rootf6af1672012-04-06 09:46:29 -0700340 if n is not None:
341 a = a & ~((1 << (32 - n)) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700342 result = "%d.%d.%d.%d" % (a >> 24, \
343 (a >> 16) & 0xff, \
344 (a >> 8) & 0xff, \
345 a & 0xff \
346 )
347 if n is not None:
348 result = result + ("/%d" % (n))
349 return result
350
Howard Pershc7963582012-03-29 10:02:59 -0700351
rootf6af1672012-04-06 09:46:29 -0700352class Flow_Cfg:
Howard Pershc7963582012-03-29 10:02:59 -0700353 # Members:
354 # - match
355 # - idle_timeout
356 # - hard_timeout
357 # - priority
358 # - action_list
359
360 def __init__(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700361 self.priority = 0
Howard Pershc7963582012-03-29 10:02:59 -0700362 self.match = parse.ofp_match()
363 self.match.wildcards = ofp.OFPFW_ALL
364 self.idle_timeout = 0
365 self.hard_timeout = 0
Howard Pershc7963582012-03-29 10:02:59 -0700366 self.actions = action_list.action_list()
367
rootf6af1672012-04-06 09:46:29 -0700368 # {pri, match} is considered a flow key
369 def key_equal(self, x):
Howard Persh680b92a2012-03-31 13:34:35 -0700370 if self.priority != x.priority:
371 return False
372 # TBD - Should this logic be moved to ofp_match.__eq__()?
373 if self.match.wildcards != x.match.wildcards:
374 return False
rootf6af1672012-04-06 09:46:29 -0700375 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700376 and self.match.in_port != x.match.in_port:
377 return False
rootf6af1672012-04-06 09:46:29 -0700378 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700379 and self.match.dl_dst != x.match.dl_dst:
380 return False
rootf6af1672012-04-06 09:46:29 -0700381 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0 \
382 and self.match.dl_src != x.match.dl_src:
383 return False
384 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700385 and self.match.dl_vlan != x.match.dl_vlan:
386 return False
rootf6af1672012-04-06 09:46:29 -0700387 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700388 and self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
389 return False
rootf6af1672012-04-06 09:46:29 -0700390 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700391 and self.match.dl_type != x.match.dl_type:
392 return False
rootf6af1672012-04-06 09:46:29 -0700393 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700394 and self.match.nw_tos != x.match.nw_tos:
395 return False
rootf6af1672012-04-06 09:46:29 -0700396 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700397 and self.match.nw_proto != x.match.nw_proto:
398 return False
rootf6af1672012-04-06 09:46:29 -0700399 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
400 if n < 32:
401 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700402 if (self.match.nw_src & m) != (x.match.nw_src & m):
403 return False
rootf6af1672012-04-06 09:46:29 -0700404 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
405 if n < 32:
406 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700407 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
408 return False
rootf6af1672012-04-06 09:46:29 -0700409 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0 \
410 and self.match.tp_src != x.match.tp_src:
Howard Persh680b92a2012-03-31 13:34:35 -0700411 return False
rootf6af1672012-04-06 09:46:29 -0700412 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0 \
413 and self.match.tp_dst != x.match.tp_dst:
414 return False
415 return True
416
Howard Persh5f3c83f2012-04-13 09:57:10 -0700417 def actions_equal(self, x):
418 if test_param_get(fq_config, "conservative_ordered_actions", True):
419 # Compare actions lists as unordered
420
root2843d2b2012-04-06 10:27:46 -0700421 aa = copy.deepcopy(x.actions.actions)
422 for a in self.actions.actions:
423 i = 0
424 while i < len(aa):
425 if a == aa[i]:
426 break
427 i = i + 1
428 if i < len(aa):
429 aa.pop(i)
430 else:
431 return False
432 return aa == []
433 else:
434 return self.actions == x.actions
Howard Persh5f3c83f2012-04-13 09:57:10 -0700435
436 def non_key_equal(self, x):
437 if self.cookie != x.cookie:
438 return False
439 if self.idle_timeout != x.idle_timeout:
440 return False
441 if self.hard_timeout != x.hard_timeout:
442 return False
443 return self.actions_equal(x)
rootf6af1672012-04-06 09:46:29 -0700444
root2843d2b2012-04-06 10:27:46 -0700445 def key_str(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700446 result = "priority=%d" % self.priority
447 # TBD - Would be nice if ofp_match.show() was better behaved
448 # (no newlines), and more intuitive (things in hex where approprate), etc.
Howard Persh8d21c1f2012-04-20 15:57:29 -0700449 result = result + (", wildcards=0x%x=%s" \
450 % (self.match.wildcards, \
451 wildcards_to_str(self.match.wildcards) \
452 )
453 )
rootf6af1672012-04-06 09:46:29 -0700454 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700455 result = result + (", in_port=%d" % (self.match.in_port))
rootf6af1672012-04-06 09:46:29 -0700456 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700457 result = result + (", dl_dst=%s" \
458 % (dl_addr_to_str(self.match.dl_dst)) \
459 )
rootf6af1672012-04-06 09:46:29 -0700460 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700461 result = result + (", dl_src=%s" \
462 % (dl_addr_to_str(self.match.dl_src)) \
463 )
rootf6af1672012-04-06 09:46:29 -0700464 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700465 result = result + (", dl_vlan=%d" % (self.match.dl_vlan))
rootf6af1672012-04-06 09:46:29 -0700466 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700467 result = result + (", dl_vlan_pcp=%d" % (self.match.dl_vlan_pcp))
rootf6af1672012-04-06 09:46:29 -0700468 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700469 result = result + (", dl_type=0x%x" % (self.match.dl_type))
rootf6af1672012-04-06 09:46:29 -0700470 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700471 result = result + (", nw_tos=0x%x" % (self.match.nw_tos))
rootf6af1672012-04-06 09:46:29 -0700472 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700473 result = result + (", nw_proto=%d" % (self.match.nw_proto))
rootf6af1672012-04-06 09:46:29 -0700474 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700475 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700476 result = result + (", nw_src=%s" % \
477 (ip_addr_to_str(self.match.nw_src, 32 - n)) \
478 )
rootf6af1672012-04-06 09:46:29 -0700479 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700480 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700481 result = result + (", nw_dst=%s" % \
482 (ip_addr_to_str(self.match.nw_dst, 32 - n)) \
483 )
rootf6af1672012-04-06 09:46:29 -0700484 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700485 result = result + (", tp_src=%d" % self.match.tp_src)
rootf6af1672012-04-06 09:46:29 -0700486 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700487 result = result + (", tp_dst=%d" % self.match.tp_dst)
rootf6af1672012-04-06 09:46:29 -0700488 return result
489
490 def __eq__(self, x):
491 return (self.key_equal(x) and self.non_key_equal(x))
492
493 def __str__(self):
root2843d2b2012-04-06 10:27:46 -0700494 result = self.key_str()
495 result = result + (", cookie=%d" % self.cookie)
Howard Persh680b92a2012-03-31 13:34:35 -0700496 result = result + (", idle_timeout=%d" % self.idle_timeout)
497 result = result + (", hard_timeout=%d" % self.hard_timeout)
Howard Persh680b92a2012-03-31 13:34:35 -0700498 for a in self.actions.actions:
499 result = result + (", action=%s" % ofp.ofp_action_type_map[a.type])
500 if a.type == ofp.OFPAT_OUTPUT:
501 result = result + ("(%d)" % (a.port))
502 elif a.type == ofp.OFPAT_SET_VLAN_VID:
503 result = result + ("(%d)" % (a.vlan_vid))
504 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
505 result = result + ("(%d)" % (a.vlan_pcp))
506 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
507 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
508 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
509 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
510 elif a.type == ofp.OFPAT_SET_NW_TOS:
511 result = result + ("(0x%x)" % (a.nw_tos))
512 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
513 result = result + ("(%d)" % (a.tp_port))
514 elif a.type == ofp.OFPAT_ENQUEUE:
515 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
516 return result
Howard Pershc7963582012-03-29 10:02:59 -0700517
Howard Persh8d21c1f2012-04-20 15:57:29 -0700518 def rand_actions_ordered(self, fi, valid_actions, valid_ports, valid_queues):
Howard Persh3340d452012-04-06 16:45:21 -0700519 # Action lists are ordered, so pick an ordered random subset of
520 # supported actions
Howard Pershc1199d52012-04-11 14:21:32 -0700521
522 actions_force = test_param_get(fq_config, "actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700523 if actions_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700524 logging.info("Forced actions:")
525 logging.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700526
Dan Talayco910a8282012-04-07 00:05:20 -0700527 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh3340d452012-04-06 16:45:21 -0700528 supported_actions = []
529 for a in all_actions_list:
530 if ((1 << a) & valid_actions) != 0:
531 supported_actions.append(a)
532
Howard Pershc1199d52012-04-11 14:21:32 -0700533 actions \
534 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
535
536 for a in all_actions_list:
537 if ((1 << a) & actions_force) != 0:
538 actions.append(a)
539
540 actions = shuffle(actions)
Howard Persh3340d452012-04-06 16:45:21 -0700541
Howard Persh6a3698d2012-08-21 14:26:39 -0700542 set_vlanf = False
543 strip_vlanf = False
Howard Persh3340d452012-04-06 16:45:21 -0700544 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700545 for a in actions:
Dan Talayco910a8282012-04-07 00:05:20 -0700546 act = None
Howard Persh3340d452012-04-06 16:45:21 -0700547 if a == ofp.OFPAT_OUTPUT:
548 pass # OUTPUT actions must come last
549 elif a == ofp.OFPAT_SET_VLAN_VID:
Howard Persh6a3698d2012-08-21 14:26:39 -0700550 if not strip_vlanf:
551 act = action.action_set_vlan_vid()
552 act.vlan_vid = fi.rand_vlan()
553 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700554 elif a == ofp.OFPAT_SET_VLAN_PCP:
Howard Persh6a3698d2012-08-21 14:26:39 -0700555 if not strip_vlanf:
556 act = action.action_set_vlan_pcp()
557 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
558 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700559 elif a == ofp.OFPAT_STRIP_VLAN:
Howard Persh6a3698d2012-08-21 14:26:39 -0700560 if not set_vlanf:
561 act = action.action_strip_vlan()
562 strip_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700563 elif a == ofp.OFPAT_SET_DL_SRC:
564 act = action.action_set_dl_src()
565 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700566 elif a == ofp.OFPAT_SET_DL_DST:
567 act = action.action_set_dl_dst()
568 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700569 elif a == ofp.OFPAT_SET_NW_SRC:
570 act = action.action_set_nw_src()
571 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700572 elif a == ofp.OFPAT_SET_NW_DST:
573 act = action.action_set_nw_dst()
574 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700575 elif a == ofp.OFPAT_SET_NW_TOS:
576 act = action.action_set_nw_tos()
577 act.nw_tos = fi.rand_ip_tos()
Howard Persh3340d452012-04-06 16:45:21 -0700578 elif a == ofp.OFPAT_SET_TP_SRC:
579 act = action.action_set_tp_src()
580 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700581 elif a == ofp.OFPAT_SET_TP_DST:
582 act = action.action_set_tp_dst()
583 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700584 elif a == ofp.OFPAT_ENQUEUE:
585 pass # Enqueue actions must come last
Dan Talayco910a8282012-04-07 00:05:20 -0700586 if act:
587 act.max_len = ACTION_MAX_LEN
588 self.actions.add(act)
589
Howard Persh3340d452012-04-06 16:45:21 -0700590 p = random.randint(1, 100)
Howard Pershc1199d52012-04-11 14:21:32 -0700591 if (((1 << ofp.OFPAT_ENQUEUE) & actions_force) != 0 or p <= 33) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700592 and len(valid_queues) > 0 \
593 and ofp.OFPAT_ENQUEUE in actions:
Howard Pershc1199d52012-04-11 14:21:32 -0700594 # In not forecd, one third of the time, include ENQUEUE actions
595 # at end of list
Howard Persh3340d452012-04-06 16:45:21 -0700596 # At most 1 ENQUEUE action
597 act = action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700598 (act.port, act.queue_id) = rand_pick(valid_queues)
Dan Talayco910a8282012-04-07 00:05:20 -0700599 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700600 self.actions.add(act)
Howard Pershc1199d52012-04-11 14:21:32 -0700601 if (((1 << ofp.OFPAT_OUTPUT) & actions_force) != 0 \
602 or (p > 33 and p <= 66) \
603 ) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700604 and len(valid_ports) > 0 \
Howard Pershc1199d52012-04-11 14:21:32 -0700605 and ofp.OFPAT_OUTPUT in actions:
Howard Persh3340d452012-04-06 16:45:21 -0700606 # One third of the time, include OUTPUT actions at end of list
607 port_idxs = shuffle(range(len(valid_ports)))
608 # Only 1 output action allowed if IN_PORT wildcarded
609 n = 1 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) != 0 \
610 else random.randint(1, len(valid_ports))
611 port_idxs = port_idxs[0 : n]
612 for pi in port_idxs:
613 act = action.action_output()
614 act.port = valid_ports[pi]
Dan Talayco910a8282012-04-07 00:05:20 -0700615 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700616 if act.port != ofp.OFPP_IN_PORT \
617 or wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
618 # OUTPUT(IN_PORT) only valid if OFPFW_IN_PORT not wildcarded
619 self.actions.add(act)
620 else:
621 # One third of the time, include neither
622 pass
623
624
625 # Randomize flow data for flow modifies (i.e. cookie and actions)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700626 def rand_mod(self, fi, valid_actions, valid_ports, valid_queues):
rootf6af1672012-04-06 09:46:29 -0700627 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700628
Dan Talayco910a8282012-04-07 00:05:20 -0700629 # By default, test with conservative ordering conventions
630 # This should probably be indicated in a profile
631 if test_param_get(fq_config, "conservative_ordered_actions", True):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700632 self.rand_actions_ordered(fi, valid_actions, valid_ports, valid_queues)
Howard Persh3340d452012-04-06 16:45:21 -0700633 return self
634
Howard Pershc1199d52012-04-11 14:21:32 -0700635 actions_force = test_param_get(fq_config, "actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700636 if actions_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700637 logging.info("Forced actions:")
638 logging.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700639
640 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh680b92a2012-03-31 13:34:35 -0700641 supported_actions = []
642 for a in all_actions_list:
643 if ((1 << a) & valid_actions) != 0:
644 supported_actions.append(a)
645
Howard Pershc1199d52012-04-11 14:21:32 -0700646 actions \
647 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
648
649 for a in all_actions_list:
650 if ((1 << a) & actions_force) != 0:
651 actions.append(a)
652
653 actions = shuffle(actions)
Howard Pershc7963582012-03-29 10:02:59 -0700654
655 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700656 for a in actions:
Howard Pershc7963582012-03-29 10:02:59 -0700657 if a == ofp.OFPAT_OUTPUT:
658 # TBD - Output actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700659 if len(valid_ports) == 0:
660 continue
Howard Pershc7963582012-03-29 10:02:59 -0700661 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700662 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700663 for pi in port_idxs:
664 act = action.action_output()
Howard Persh680b92a2012-03-31 13:34:35 -0700665 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700666 self.actions.add(act)
667 elif a == ofp.OFPAT_SET_VLAN_VID:
668 act = action.action_set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700669 act.vlan_vid = fi.rand_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700670 self.actions.add(act)
671 elif a == ofp.OFPAT_SET_VLAN_PCP:
Dan Talayco910a8282012-04-07 00:05:20 -0700672 act = action.action_set_vlan_pcp()
673 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700674 elif a == ofp.OFPAT_STRIP_VLAN:
675 act = action.action_strip_vlan()
676 self.actions.add(act)
677 elif a == ofp.OFPAT_SET_DL_SRC:
678 act = action.action_set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700679 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700680 self.actions.add(act)
681 elif a == ofp.OFPAT_SET_DL_DST:
682 act = action.action_set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700683 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700684 self.actions.add(act)
685 elif a == ofp.OFPAT_SET_NW_SRC:
686 act = action.action_set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700687 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700688 self.actions.add(act)
689 elif a == ofp.OFPAT_SET_NW_DST:
690 act = action.action_set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700691 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700692 self.actions.add(act)
693 elif a == ofp.OFPAT_SET_NW_TOS:
694 act = action.action_set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700695 act.nw_tos = fi.rand_ip_tos()
Howard Pershc7963582012-03-29 10:02:59 -0700696 self.actions.add(act)
697 elif a == ofp.OFPAT_SET_TP_SRC:
698 act = action.action_set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700699 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700700 self.actions.add(act)
701 elif a == ofp.OFPAT_SET_TP_DST:
702 act = action.action_set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700703 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700704 self.actions.add(act)
705 elif a == ofp.OFPAT_ENQUEUE:
706 # TBD - Enqueue actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700707 if len(valid_queues) == 0:
708 continue
709 qidxs = shuffle(range(len(valid_queues)))
710 qidxs = qidxs[0 : random.randint(1, len(valid_queues))]
711 for qi in qidxs:
Howard Pershc7963582012-03-29 10:02:59 -0700712 act = action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700713 (act.port, act.queue_id) = valid_queues[qi]
Howard Pershc7963582012-03-29 10:02:59 -0700714 self.actions.add(act)
715
716 return self
717
rootf6af1672012-04-06 09:46:29 -0700718 # Randomize flow cfg
Ed Swierk99a74de2012-08-22 06:40:54 -0700719 def rand(self, fi, wildcards_force, valid_wildcards, valid_actions, valid_ports,
720 valid_queues):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700721 if wildcards_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700722 logging.info("Wildcards forced:")
723 logging.info(wildcards_to_str(wildcards_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700724
rootf6af1672012-04-06 09:46:29 -0700725 # Start with no wildcards, i.e. everything specified
726 self.match.wildcards = 0
Howard Pershc1199d52012-04-11 14:21:32 -0700727
728 if wildcards_force != 0:
729 exact = False
730 else:
731 # Make approx. 5% of flows exact
732 exact = (random.randint(1, 100) <= 5)
rootf6af1672012-04-06 09:46:29 -0700733
734 # For each qualifier Q,
735 # if (wildcarding is not supported for Q,
736 # or an exact flow is specified
737 # or a coin toss comes up heads),
738 # specify Q
739 # else
740 # wildcard Q
741
Howard Pershc1199d52012-04-11 14:21:32 -0700742 if wildcard_get(wildcards_force, ofp.OFPFW_IN_PORT) == 0 \
743 and (wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
744 or exact \
745 or flip_coin() \
746 ):
rootf6af1672012-04-06 09:46:29 -0700747 self.match.in_port = rand_pick(valid_ports)
748 else:
Howard Persh3340d452012-04-06 16:45:21 -0700749 self.match.wildcards = wildcard_set(self.match.wildcards, \
750 ofp.OFPFW_IN_PORT, \
751 1 \
752 )
rootf6af1672012-04-06 09:46:29 -0700753
Howard Pershc1199d52012-04-11 14:21:32 -0700754 if wildcard_get(wildcards_force, ofp.OFPFW_DL_DST) == 0 \
755 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
756 or exact \
757 or flip_coin() \
758 ):
rootf6af1672012-04-06 09:46:29 -0700759 self.match.dl_dst = fi.rand_dl_addr()
760 else:
Howard Persh3340d452012-04-06 16:45:21 -0700761 self.match.wildcards = wildcard_set(self.match.wildcards, \
762 ofp.OFPFW_DL_DST, \
763 1 \
764 )
rootf6af1672012-04-06 09:46:29 -0700765
Howard Pershc1199d52012-04-11 14:21:32 -0700766 if wildcard_get(wildcards_force, ofp.OFPFW_DL_SRC) == 0 \
767 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
768 or exact \
769 or flip_coin() \
770 ):
rootf6af1672012-04-06 09:46:29 -0700771 self.match.dl_src = fi.rand_dl_addr()
772 else:
Howard Persh3340d452012-04-06 16:45:21 -0700773 self.match.wildcards = wildcard_set(self.match.wildcards, \
774 ofp.OFPFW_DL_SRC, \
775 1 \
776 )
rootf6af1672012-04-06 09:46:29 -0700777
Howard Pershc1199d52012-04-11 14:21:32 -0700778 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN) == 0 \
779 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
780 or exact \
781 or flip_coin() \
782 ):
rootf6af1672012-04-06 09:46:29 -0700783 self.match.dl_vlan = fi.rand_vlan()
784 else:
Howard Persh3340d452012-04-06 16:45:21 -0700785 self.match.wildcards = wildcard_set(self.match.wildcards, \
786 ofp.OFPFW_DL_VLAN, \
787 1 \
788 )
rootf6af1672012-04-06 09:46:29 -0700789
Howard Pershc1199d52012-04-11 14:21:32 -0700790 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN_PCP) == 0 \
791 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
792 or exact \
793 or flip_coin() \
794 ):
795 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
796 else:
797 self.match.wildcards = wildcard_set(self.match.wildcards, \
798 ofp.OFPFW_DL_VLAN_PCP, \
799 1 \
800 )
801
802 if wildcard_get(wildcards_force, ofp.OFPFW_DL_TYPE) == 0 \
803 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
804 or exact \
805 or flip_coin() \
806 ):
rootf6af1672012-04-06 09:46:29 -0700807 self.match.dl_type = fi.rand_ethertype()
808 else:
Howard Persh3340d452012-04-06 16:45:21 -0700809 self.match.wildcards = wildcard_set(self.match.wildcards, \
810 ofp.OFPFW_DL_TYPE, \
811 1 \
812 )
rootf6af1672012-04-06 09:46:29 -0700813
Howard Pershc1199d52012-04-11 14:21:32 -0700814 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_SRC_MASK)
815 if n == 0:
816 if exact or flip_coin():
817 n = 0
818 else:
819 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
820 if n > 32:
821 n = 32
822 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700823 self.match.wildcards = wildcard_set(self.match.wildcards, \
824 ofp.OFPFW_NW_SRC_MASK, \
825 n \
826 )
rootf6af1672012-04-06 09:46:29 -0700827 if n < 32:
828 self.match.nw_src = fi.rand_ip_addr() & ~((1 << n) - 1)
829 # Specifying any IP address match other than all bits
830 # don't care requires that Ethertype is one of {IP, ARP}
831 if flip_coin():
832 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700833 self.match.wildcards = wildcard_set(self.match.wildcards, \
834 ofp.OFPFW_DL_TYPE, \
835 0 \
836 )
rootf6af1672012-04-06 09:46:29 -0700837
Howard Pershc1199d52012-04-11 14:21:32 -0700838 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_DST_MASK)
839 if n == 0:
840 if exact or flip_coin():
841 n = 0
842 else:
843 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
844 if n > 32:
845 n = 32
846 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700847 self.match.wildcards = wildcard_set(self.match.wildcards, \
848 ofp.OFPFW_NW_DST_MASK, \
849 n \
850 )
rootf6af1672012-04-06 09:46:29 -0700851 if n < 32:
852 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
853 # Specifying any IP address match other than all bits
854 # don't care requires that Ethertype is one of {IP, ARP}
855 if flip_coin():
856 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700857 self.match.wildcards = wildcard_set(self.match.wildcards, \
858 ofp.OFPFW_DL_TYPE, \
859 0 \
860 )
rootf6af1672012-04-06 09:46:29 -0700861
Howard Pershc1199d52012-04-11 14:21:32 -0700862 if wildcard_get(wildcards_force, ofp.OFPFW_NW_TOS) == 0 \
863 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
864 or exact \
865 or flip_coin() \
866 ):
rootf6af1672012-04-06 09:46:29 -0700867 self.match.nw_tos = fi.rand_ip_tos()
868 # Specifying a TOS value requires that Ethertype is IP
869 if flip_coin():
870 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700871 self.match.wildcards = wildcard_set(self.match.wildcards, \
872 ofp.OFPFW_DL_TYPE, \
873 0 \
874 )
rootf6af1672012-04-06 09:46:29 -0700875 else:
Howard Persh3340d452012-04-06 16:45:21 -0700876 self.match.wildcards = wildcard_set(self.match.wildcards, \
877 ofp.OFPFW_NW_TOS, \
878 1 \
879 )
rootf6af1672012-04-06 09:46:29 -0700880
Dan Talayco910a8282012-04-07 00:05:20 -0700881 # Known issue on OVS with specifying nw_proto w/o dl_type as IP
Howard Pershc1199d52012-04-11 14:21:32 -0700882 if wildcard_get(wildcards_force, ofp.OFPFW_NW_PROTO) == 0 \
883 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
884 or exact \
885 or flip_coin() \
886 ):
Dan Talayco910a8282012-04-07 00:05:20 -0700887 self.match.nw_proto = fi.rand_ip_proto()
888 # Specifying an IP protocol requires that Ethertype is IP
889 if flip_coin():
890 self.match.dl_type = 0x0800
891 self.match.wildcards = wildcard_set(self.match.wildcards, \
892 ofp.OFPFW_DL_TYPE, \
893 0 \
894 )
895 else:
Howard Persh3340d452012-04-06 16:45:21 -0700896 self.match.wildcards = wildcard_set(self.match.wildcards, \
897 ofp.OFPFW_NW_PROTO, \
898 1 \
899 )
Dan Talayco910a8282012-04-07 00:05:20 -0700900
Howard Pershc1199d52012-04-11 14:21:32 -0700901 if wildcard_get(wildcards_force, ofp.OFPFW_TP_SRC) == 0 \
902 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
903 or exact\
904 or flip_coin() \
905 ):
rootf6af1672012-04-06 09:46:29 -0700906 self.match.tp_src = fi.rand_l4_port()
907 # Specifying a L4 port requires that IP protcol is
908 # one of {ICMP, TCP, UDP}
909 if flip_coin():
910 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700911 self.match.wildcards = wildcard_set(self.match.wildcards, \
912 ofp.OFPFW_NW_PROTO, \
913 0 \
914 )
rootf6af1672012-04-06 09:46:29 -0700915 # Specifying a L4 port requirues that Ethertype is IP
916 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700917 self.match.wildcards = wildcard_set(self.match.wildcards, \
918 ofp.OFPFW_DL_TYPE, \
919 0 \
920 )
rootf6af1672012-04-06 09:46:29 -0700921 if self.match.nw_proto == 1:
922 self.match.tp_src = self.match.tp_src & 0xff
923 else:
Howard Persh3340d452012-04-06 16:45:21 -0700924 self.match.wildcards = wildcard_set(self.match.wildcards, \
925 ofp.OFPFW_TP_SRC, \
926 1 \
927 )
rootf6af1672012-04-06 09:46:29 -0700928
Howard Pershc1199d52012-04-11 14:21:32 -0700929 if wildcard_get(wildcards_force, ofp.OFPFW_TP_DST) == 0 \
930 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
931 or exact \
932 or flip_coin() \
933 ):
rootf6af1672012-04-06 09:46:29 -0700934 self.match.tp_dst = fi.rand_l4_port()
935 # Specifying a L4 port requires that IP protcol is
936 # one of {ICMP, TCP, UDP}
937 if flip_coin():
938 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700939 self.match.wildcards = wildcard_set(self.match.wildcards, \
940 ofp.OFPFW_NW_PROTO, \
941 0 \
942 )
rootf6af1672012-04-06 09:46:29 -0700943 # Specifying a L4 port requirues that Ethertype is IP
944 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700945 self.match.wildcards = wildcard_set(self.match.wildcards, \
946 ofp.OFPFW_DL_TYPE, \
947 0 \
948 )
rootf6af1672012-04-06 09:46:29 -0700949 if self.match.nw_proto == 1:
950 self.match.tp_dst = self.match.tp_dst & 0xff
951 else:
Howard Persh3340d452012-04-06 16:45:21 -0700952 self.match.wildcards = wildcard_set(self.match.wildcards, \
953 ofp.OFPFW_TP_DST, \
954 1 \
955 )
rootf6af1672012-04-06 09:46:29 -0700956
957 # If nothing is wildcarded, it is an exact flow spec -- some switches
Howard Persh3340d452012-04-06 16:45:21 -0700958 # (Open vSwitch, for one) *require* that exact flow specs
959 # have priority 65535.
960 self.priority = 65535 if self.match.wildcards == 0 \
961 else fi.rand_priority()
rootf6af1672012-04-06 09:46:29 -0700962
963 # N.B. Don't make the timeout too short, else the flow might
964 # disappear before we get a chance to check for it.
965 t = random.randint(0, 65535)
966 self.idle_timeout = 0 if t < 60 else t
967 t = random.randint(0, 65535)
968 self.hard_timeout = 0 if t < 60 else t
969
Howard Persh8d21c1f2012-04-20 15:57:29 -0700970 self.rand_mod(fi, valid_actions, valid_ports, valid_queues)
rootf6af1672012-04-06 09:46:29 -0700971
972 return self
973
974 # Return flow cfg in canonical form
Howard Persh3340d452012-04-06 16:45:21 -0700975 # - There are dependencies between flow qualifiers, e.g. it only makes
976 # sense to qualify nw_proto if dl_type is qualified to be 0x0800 (IP).
977 # The canonical form of flow match criteria will "wildcard out"
978 # all such cases.
rootf6af1672012-04-06 09:46:29 -0700979 def canonical(self):
980 result = copy.deepcopy(self)
Howard Persh07d99e62012-04-09 15:26:57 -0700981
982 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_VLAN) != 0:
983 result.match.wildcards = wildcard_set(result.match.wildcards, \
984 ofp.OFPFW_DL_VLAN_PCP, \
985 1 \
986 )
987
rootf6af1672012-04-06 09:46:29 -0700988 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
989 or result.match.dl_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700990 # dl_tyoe is wildcarded, or specified as something other
991 # than IP or ARP
Howard Persh07d99e62012-04-09 15:26:57 -0700992 # => nw_src, nw_dst, nw_proto cannot be specified,
993 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700994 result.match.wildcards = wildcard_set(result.match.wildcards, \
995 ofp.OFPFW_NW_SRC_MASK, \
996 32 \
997 )
998 result.match.wildcards = wildcard_set(result.match.wildcards, \
999 ofp.OFPFW_NW_DST_MASK, \
1000 32 \
1001 )
Howard Persh3340d452012-04-06 16:45:21 -07001002 result.match.wildcards = wildcard_set(result.match.wildcards, \
1003 ofp.OFPFW_NW_PROTO, \
1004 1 \
1005 )
Howard Persh07d99e62012-04-09 15:26:57 -07001006
1007 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
1008 or result.match.dl_type != 0x0800:
1009 # dl_type is wildcarded, or specified as something other than IP
1010 # => nw_tos, tp_src and tp_dst cannot be specified,
1011 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001012 result.match.wildcards = wildcard_set(result.match.wildcards, \
1013 ofp.OFPFW_NW_TOS, \
1014 1 \
1015 )
1016 result.match.wildcards = wildcard_set(result.match.wildcards, \
1017 ofp.OFPFW_TP_SRC, \
1018 1 \
1019 )
1020 result.match.wildcards = wildcard_set(result.match.wildcards, \
1021 ofp.OFPFW_TP_DST, \
1022 1 \
1023 )
Howard Persh07d99e62012-04-09 15:26:57 -07001024 result.match.wildcards = wildcard_set(result.match.wildcards, \
1025 ofp.OFPFW_NW_SRC_MASK, \
1026 32 \
1027 )
1028 result.match.wildcards = wildcard_set(result.match.wildcards, \
1029 ofp.OFPFW_NW_DST_MASK, \
1030 32 \
1031 )
1032 result.match.wildcards = wildcard_set(result.match.wildcards, \
1033 ofp.OFPFW_NW_PROTO, \
1034 1 \
1035 )
1036
rootf6af1672012-04-06 09:46:29 -07001037 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
1038 or result.match.nw_proto not in [1, 6, 17]:
Howard Persh3340d452012-04-06 16:45:21 -07001039 # nw_proto is wildcarded, or specified as something other than ICMP,
1040 # TCP or UDP
rootf6af1672012-04-06 09:46:29 -07001041 # => tp_src and tp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001042 result.match.wildcards = wildcard_set(result.match.wildcards, \
1043 ofp.OFPFW_TP_SRC, \
1044 1 \
1045 )
1046 result.match.wildcards = wildcard_set(result.match.wildcards, \
1047 ofp.OFPFW_TP_DST, \
1048 1 \
1049 )
rootf6af1672012-04-06 09:46:29 -07001050 return result
1051
Howard Persh680b92a2012-03-31 13:34:35 -07001052 # Overlap check
1053 # delf == True <=> Check for delete overlap, else add overlap
1054 # "Add overlap" is defined as there exists a packet that could match both the
1055 # receiver and argument flowspecs
1056 # "Delete overlap" is defined as the specificity of the argument flowspec
1057 # is greater than or equal to the specificity of the receiver flowspec
1058 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -07001059 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
1060 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001061 if self.match.in_port != x.match.in_port:
1062 return False # Both specified, and not equal
1063 elif delf:
1064 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001065 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
1066 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001067 if self.match.dl_vlan != x.match.dl_vlan:
1068 return False # Both specified, and not equal
1069 elif delf:
1070 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001071 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
1072 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001073 if self.match.dl_src != x.match.dl_src:
1074 return False # Both specified, and not equal
1075 elif delf:
1076 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001077 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
1078 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001079 if self.match.dl_dst != x.match.dl_dst:
1080 return False # Both specified, and not equal
1081 elif delf:
1082 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001083 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
1084 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001085 if self.match.dl_type != x.match.dl_type:
1086 return False # Both specified, and not equal
1087 elif delf:
1088 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -07001089 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
1090 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001091 if self.match.nw_proto != x.match.nw_proto:
1092 return False # Both specified, and not equal
1093 elif delf:
1094 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001095 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
1096 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001097 if self.match.tp_src != x.match.tp_src:
1098 return False # Both specified, and not equal
1099 elif delf:
1100 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001101 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
1102 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001103 if self.match.tp_dst != x.match.tp_dst:
1104 return False # Both specified, and not equal
1105 elif delf:
1106 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001107 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
1108 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001109 if delf and na < nb:
1110 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001111 if (na < 32 and nb < 32):
1112 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1113 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -07001114 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -07001115 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
1116 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001117 if delf and na < nb:
1118 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001119 if (na < 32 and nb < 32):
1120 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1121 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
rootf6af1672012-04-06 09:46:29 -07001122 return False # Overlapping bits not equal
1123 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
1124 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001125 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
1126 return False # Both specified, and not equal
1127 elif delf:
1128 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001129 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
1130 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001131 if self.match.nw_tos != x.match.nw_tos:
1132 return False # Both specified, and not equal
1133 elif delf:
1134 return False # Receiver more specific
1135 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -07001136
1137 def to_flow_mod_msg(self, msg):
1138 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -07001139 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001140 msg.idle_timeout = self.idle_timeout
1141 msg.hard_timeout = self.hard_timeout
1142 msg.priority = self.priority
1143 msg.actions = self.actions
1144 return msg
1145
1146 def from_flow_stat(self, msg):
1147 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -07001148 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001149 self.idle_timeout = msg.idle_timeout
1150 self.hard_timeout = msg.hard_timeout
1151 self.priority = msg.priority
1152 self.actions = msg.actions
1153
rootf6af1672012-04-06 09:46:29 -07001154 def from_flow_rem(self, msg):
1155 self.match = msg.match
1156 self.idle_timeout = msg.idle_timeout
1157 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -07001158
Howard Pershc7963582012-03-29 10:02:59 -07001159
rootf6af1672012-04-06 09:46:29 -07001160class Flow_Tbl:
1161 def clear(self):
1162 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001163
rootf6af1672012-04-06 09:46:29 -07001164 def __init__(self):
1165 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001166
rootf6af1672012-04-06 09:46:29 -07001167 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001168 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001169
1170 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001171 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001172
1173 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001174 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001175
1176 def values(self):
1177 return self.dict.values()
1178
1179 def count(self):
1180 return len(self.dict)
1181
Ed Swierk99a74de2012-08-22 06:40:54 -07001182 def rand(self, wildcards_force, sw, fi, num_flows):
rootf6af1672012-04-06 09:46:29 -07001183 self.clear()
1184 i = 0
1185 tbl = 0
1186 j = 0
1187 while i < num_flows:
1188 fc = Flow_Cfg()
1189 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001190 wildcards_force, \
rootf6af1672012-04-06 09:46:29 -07001191 sw.tbl_stats.stats[tbl].wildcards, \
1192 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001193 sw.valid_ports, \
1194 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001195 )
1196 fc = fc.canonical()
1197 if self.find(fc):
1198 continue
1199 fc.send_rem = False
1200 self.insert(fc)
1201 i = i + 1
1202 j = j + 1
1203 if j >= sw.tbl_stats.stats[tbl].max_entries:
1204 tbl = tbl + 1
1205 j = 0
1206
1207
1208class Switch:
1209 # Members:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001210 # controller - switch's test controller
1211 # sw_features - switch's OFPT_FEATURES_REPLY message
1212 # valid_ports - list of valid port numbers
1213 # valid_queues - list of valid [port, queue] pairs
1214 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1215 # queue_stats - switch's OFPT_STATS_REPLY message, for queue stats request
1216 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1217 # flow_tbl - (test's idea of) switch's flow table
rootf6af1672012-04-06 09:46:29 -07001218
1219 def __init__(self):
Howard Persh8d21c1f2012-04-20 15:57:29 -07001220 self.controller = None
1221 self.sw_features = None
1222 self.valid_ports = []
1223 self.valid_queues = []
1224 self.tbl_stats = None
1225 self.flow_stats = None
1226 self.flow_tbl = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001227 self.error_msgs = []
1228 self.removed_msgs = []
1229
1230 def error_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001231 logging.info("Got an ERROR message, type=%d, code=%d" \
Ed Swierk99a74de2012-08-22 06:40:54 -07001232 % (msg.type, msg.code) \
1233 )
Rich Lane9a003812012-10-04 17:17:59 -07001234 logging.info("Message header:")
1235 logging.info(msg.header.show())
Ed Swierk99a74de2012-08-22 06:40:54 -07001236 self.error_msgs.append(msg)
1237
1238 def removed_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001239 logging.info("Got a REMOVED message")
1240 logging.info("Message header:")
1241 logging.info(msg.header.show())
Ed Swierk99a74de2012-08-22 06:40:54 -07001242 self.removed_msgs.append(msg)
rootf6af1672012-04-06 09:46:29 -07001243
Howard Persh3340d452012-04-06 16:45:21 -07001244 def controller_set(self, controller):
1245 self.controller = controller
1246 # Register error message handler
Ed Swierk99a74de2012-08-22 06:40:54 -07001247 self.error_msgs = []
1248 self.removed_msgs = []
1249 controller.register(ofp.OFPT_ERROR, self.error_handler)
1250 controller.register(ofp.OFPT_FLOW_REMOVED, self.removed_handler)
Howard Persh3340d452012-04-06 16:45:21 -07001251
rootf6af1672012-04-06 09:46:29 -07001252 def features_get(self):
1253 # Get switch features
1254 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001255 (self.sw_features, pkt) = self.controller.transact(request)
rootf6af1672012-04-06 09:46:29 -07001256 if self.sw_features is None:
Rich Lane9a003812012-10-04 17:17:59 -07001257 logging.error("Get switch features failed")
rootf6af1672012-04-06 09:46:29 -07001258 return False
1259 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Rich Lane9a003812012-10-04 17:17:59 -07001260 logging.info("Ports reported by switch:")
1261 logging.info(self.valid_ports)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001262 ports_override = test_param_get(fq_config, "ports", [])
1263 if ports_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001264 logging.info("Overriding ports to:")
1265 logging.info(ports_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001266 self.valid_ports = ports_override
1267
Howard Persh3340d452012-04-06 16:45:21 -07001268 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1269 # is that universal?
1270
1271 # TBD - There seems to be variability in which switches support which
1272 # ports; need to sort that out
1273 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1274# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1275# ofp.OFPP_NORMAL, \
1276# ofp.OFPP_FLOOD, \
1277# ofp.OFPP_ALL, \
1278# ofp.OFPP_CONTROLLER \
1279# ] \
1280# )
Rich Lane9a003812012-10-04 17:17:59 -07001281 logging.info("Supported actions reported by switch:")
1282 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001283 % (self.sw_features.actions, \
1284 actions_bmap_to_str(self.sw_features.actions) \
1285 ) \
1286 )
Howard Persh07d99e62012-04-09 15:26:57 -07001287 actions_override = test_param_get(fq_config, "actions", -1)
1288 if actions_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001289 logging.info("Overriding supported actions to:")
1290 logging.info(actions_bmap_to_str(actions_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001291 self.sw_features.actions = actions_override
rootf6af1672012-04-06 09:46:29 -07001292 return True
1293
1294 def tbl_stats_get(self):
1295 # Get table stats
Howard Persh680b92a2012-03-31 13:34:35 -07001296 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001297 (self.tbl_stats, pkt) = self.controller.transact(request)
Howard Persh07d99e62012-04-09 15:26:57 -07001298 if self.tbl_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001299 logging.error("Get table stats failed")
Howard Persh07d99e62012-04-09 15:26:57 -07001300 return False
Howard Persh8d21c1f2012-04-20 15:57:29 -07001301 i = 0
Howard Persh07d99e62012-04-09 15:26:57 -07001302 for ts in self.tbl_stats.stats:
Rich Lane9a003812012-10-04 17:17:59 -07001303 logging.info("Supported wildcards for table %d reported by switch:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001304 % (i)
1305 )
Rich Lane9a003812012-10-04 17:17:59 -07001306 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001307 % (ts.wildcards, \
1308 wildcards_to_str(ts.wildcards) \
1309 ) \
1310 )
Howard Persh07d99e62012-04-09 15:26:57 -07001311 wildcards_override = test_param_get(fq_config, "wildcards", -1)
1312 if wildcards_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001313 logging.info("Overriding supported wildcards for table %d to:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001314 % (i)
1315 )
Rich Lane9a003812012-10-04 17:17:59 -07001316 logging.info(wildcards_to_str(wildcards_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001317 ts.wildcards = wildcards_override
Howard Persh8d21c1f2012-04-20 15:57:29 -07001318 i = i + 1
Howard Persh07d99e62012-04-09 15:26:57 -07001319 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001320
Howard Persh8d21c1f2012-04-20 15:57:29 -07001321 def queue_stats_get(self):
1322 # Get queue stats
1323 request = message.queue_stats_request()
1324 request.port_no = ofp.OFPP_ALL
1325 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001326 (self.queue_stats, pkt) = self.controller.transact(request)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001327 if self.queue_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001328 logging.error("Get queue stats failed")
Howard Persh8d21c1f2012-04-20 15:57:29 -07001329 return False
1330 self.valid_queues = map(lambda x: (x.port_no, x.queue_id), \
1331 self.queue_stats.stats \
1332 )
Rich Lane9a003812012-10-04 17:17:59 -07001333 logging.info("(Port, queue) pairs reported by switch:")
1334 logging.info(self.valid_queues)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001335 queues_override = test_param_get(fq_config, "queues", [])
1336 if queues_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001337 logging.info("Overriding (port, queue) pairs to:")
1338 logging.info(queues_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001339 self.valid_queues = queues_override
1340 return True
1341
1342 def connect(self, controller):
1343 # Connect to controller, and get all switch capabilities
1344 self.controller_set(controller)
1345 return (self.features_get() \
1346 and self.tbl_stats_get() \
1347 and self.queue_stats_get() \
1348 )
1349
Howard Pershc1199d52012-04-11 14:21:32 -07001350 def flow_stats_get(self, limit = 10000):
rootf6af1672012-04-06 09:46:29 -07001351 request = message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -07001352 query_match = ofp.ofp_match()
1353 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001354 request.match = query_match
1355 request.table_id = 0xff
1356 request.out_port = ofp.OFPP_NONE;
Howard Persh3340d452012-04-06 16:45:21 -07001357 if self.controller.message_send(request) == -1:
1358 return False
1359 # <TBD>
1360 # Glue together successive reponse messages for stats reply.
1361 # Looking at the "more" flag and performing re-assembly
1362 # should be a part of the infrastructure.
1363 # </TBD>
1364 n = 0
1365 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -07001366 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY)
Howard Persh3340d452012-04-06 16:45:21 -07001367 if resp is None:
Howard Pershc1199d52012-04-11 14:21:32 -07001368 return False # Did not get expected response
Howard Persh3340d452012-04-06 16:45:21 -07001369 if n == 0:
1370 self.flow_stats = resp
1371 else:
1372 self.flow_stats.stats.extend(resp.stats)
1373 n = n + 1
Howard Pershc1199d52012-04-11 14:21:32 -07001374 if len(self.flow_stats.stats) > limit:
Rich Lane9a003812012-10-04 17:17:59 -07001375 logging.error("Too many flows returned")
Howard Pershc1199d52012-04-11 14:21:32 -07001376 return False
1377 if (resp.flags & 1) == 0:
1378 break # No more responses expected
Howard Persh3340d452012-04-06 16:45:21 -07001379 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001380
rootf6af1672012-04-06 09:46:29 -07001381 def flow_add(self, flow_cfg, overlapf = False):
Howard Persh680b92a2012-03-31 13:34:35 -07001382 flow_mod_msg = message.flow_mod()
1383 flow_mod_msg.command = ofp.OFPFC_ADD
1384 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001385 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001386 if overlapf:
1387 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001388 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001389 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Howard Persh07d99e62012-04-09 15:26:57 -07001390 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001391 logging.info("Sending flow_mod(add), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001392 % (flow_mod_msg.header.xid)
1393 )
rootf6af1672012-04-06 09:46:29 -07001394 return (self.controller.message_send(flow_mod_msg) != -1)
Howard Persh680b92a2012-03-31 13:34:35 -07001395
rootf6af1672012-04-06 09:46:29 -07001396 def flow_mod(self, flow_cfg, strictf):
Howard Persh680b92a2012-03-31 13:34:35 -07001397 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001398 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf \
1399 else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -07001400 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001401 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001402 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001403 logging.info("Sending flow_mod(mod), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001404 % (flow_mod_msg.header.xid)
1405 )
rootf6af1672012-04-06 09:46:29 -07001406 return (self.controller.message_send(flow_mod_msg) != -1)
1407
1408 def flow_del(self, flow_cfg, strictf):
1409 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001410 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf \
1411 else ofp.OFPFC_DELETE
rootf6af1672012-04-06 09:46:29 -07001412 flow_mod_msg.buffer_id = 0xffffffff
1413 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001414 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001415 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001416 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001417 logging.info("Sending flow_mod(del), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001418 % (flow_mod_msg.header.xid)
1419 )
rootf6af1672012-04-06 09:46:29 -07001420 return (self.controller.message_send(flow_mod_msg) != -1)
1421
1422 def barrier(self):
1423 barrier = message.barrier_request()
Dan Talaycoc689a792012-09-28 14:22:53 -07001424 (resp, pkt) = self.controller.transact(barrier, 30)
rootf6af1672012-04-06 09:46:29 -07001425 return (resp is not None)
1426
Howard Persh3340d452012-04-06 16:45:21 -07001427 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001428 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001429 logging.info("Expecting %d error messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001430 num_got = len(self.error_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001431 logging.info("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001432 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001433 logging.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001434 result = False
1435 if num_exp == 0:
1436 return result
1437 elif num_exp == 1:
Rich Lane9a003812012-10-04 17:17:59 -07001438 logging.info("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001439 % (type, code) \
1440 )
1441 f = False
Ed Swierk99a74de2012-08-22 06:40:54 -07001442 for e in self.error_msgs:
Howard Persh3340d452012-04-06 16:45:21 -07001443 if e.type == type and e.code == code:
Rich Lane9a003812012-10-04 17:17:59 -07001444 logging.info("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001445 f = True
1446 if not f:
Rich Lane9a003812012-10-04 17:17:59 -07001447 logging.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001448 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001449 else:
Rich Lane9a003812012-10-04 17:17:59 -07001450 logging.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001451 result = False
1452 return result
1453
Howard Persh3340d452012-04-06 16:45:21 -07001454 def removed_verify(self, num_exp):
1455 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001456 logging.info("Expecting %d removed messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001457 num_got = len(self.removed_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001458 logging.info("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001459 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001460 logging.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001461 result = False
1462 if num_exp < 2:
1463 return result
Rich Lane9a003812012-10-04 17:17:59 -07001464 logging.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001465 return False
1466
Howard Persh5f3c83f2012-04-13 09:57:10 -07001467 # modf == True <=> Verify for flow modify, else for add/delete
1468 def flow_tbl_verify(self, modf = False):
rootf6af1672012-04-06 09:46:29 -07001469 result = True
1470
1471 # Verify flow count in switch
Rich Lane9a003812012-10-04 17:17:59 -07001472 logging.info("Reading table stats")
1473 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001474 if not self.tbl_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001475 logging.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001476 return False
1477 n = 0
1478 for ts in self.tbl_stats.stats:
1479 n = n + ts.active_count
Rich Lane9a003812012-10-04 17:17:59 -07001480 logging.info("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001481 % (n) \
1482 )
1483 if n != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001484 logging.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001485 result = False
1486
1487 # Read flows from switch
Rich Lane9a003812012-10-04 17:17:59 -07001488 logging.info("Retrieving flows from switch")
1489 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001490 if not self.flow_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001491 logging.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001492 return False
Rich Lane9a003812012-10-04 17:17:59 -07001493 logging.info("Retrieved %d flows" % (len(self.flow_stats.stats)))
rootf6af1672012-04-06 09:46:29 -07001494
1495 # Verify flows returned by switch
1496
1497 if len(self.flow_stats.stats) != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001498 logging.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001499 result = False
1500
Rich Lane9a003812012-10-04 17:17:59 -07001501 logging.info("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001502 for fc in self.flow_tbl.values():
1503 fc.matched = False
1504 for fs in self.flow_stats.stats:
1505 flow_in = Flow_Cfg()
1506 flow_in.from_flow_stat(fs)
Rich Lane9a003812012-10-04 17:17:59 -07001507 logging.info("Received flow:")
1508 logging.info(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001509 fc = self.flow_tbl.find(flow_in)
1510 if fc is None:
Rich Lane9a003812012-10-04 17:17:59 -07001511 logging.error("Received flow:")
1512 logging.error(str(flow_in))
1513 logging.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001514 result = False
1515 elif fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001516 logging.error("Received flow:")
1517 logging.error(str(flow_in))
1518 logging.error("re-matches defined flow:")
1519 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001520 result = False
1521 else:
Rich Lane9a003812012-10-04 17:17:59 -07001522 logging.info("matched")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001523 if modf:
1524 # Check for modify
1525
1526 if flow_in.cookie != fc.cookie:
Rich Lane9a003812012-10-04 17:17:59 -07001527 logging.warning("Defined flow:")
1528 logging.warning(str(fc))
1529 logging.warning("Received flow:")
1530 logging.warning(str(flow_in))
1531 logging.warning("cookies do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001532 if not flow_in.actions_equal(fc):
Rich Lane9a003812012-10-04 17:17:59 -07001533 logging.error("Defined flow:")
1534 logging.error(str(fc))
1535 logging.error("Received flow:")
1536 logging.error(str(flow_in))
1537 logging.error("actions do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001538 else:
1539 # Check for add/delete
1540
1541 if not flow_in == fc:
Rich Lane9a003812012-10-04 17:17:59 -07001542 logging.error("Defined flow:")
1543 logging.error(str(fc))
1544 logging.error("Received flow:")
1545 logging.error(str(flow_in))
1546 logging.error("non-key portions of flow do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001547 result = False
rootf6af1672012-04-06 09:46:29 -07001548 fc.matched = True
1549 for fc in self.flow_tbl.values():
1550 if not fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001551 logging.error("Defined flow:")
1552 logging.error(str(fc))
1553 logging.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001554 result = False
1555
1556 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001557
Howard Persh9cab4822012-09-11 17:08:40 -07001558 def settle(self):
1559 time.sleep(2)
1560
Howard Persh07d99e62012-04-09 15:26:57 -07001561# FLOW ADD 5
1562#
1563# OVERVIEW
1564# Add flows to switch, read back and verify flow configurations
1565#
1566# PURPOSE
1567# - Test acceptance of flow adds
1568# - Test ability of switch to process additions to flow table in random
1569# priority order
1570# - Test correctness of flow configuration responses
1571#
1572# PARAMETERS
1573#
1574# Name: num_flows
1575# Type: number
1576# Description:
1577# Number of flows to define; 0 => maximum number of flows, as determined
1578# from switch capabilities
1579# Default: 100
1580#
1581# PROCESS
1582# 1. Delete all flows from switch
1583# 2. Generate <num_flows> distinct flow configurations
1584# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1585# 4. Verify that no OFPT_ERROR responses were generated by switch
1586# 5. Retrieve flow stats from switch
1587# 6. Compare flow configurations returned by switch
1588# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1589# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001590
rootf6af1672012-04-06 09:46:29 -07001591class Flow_Add_5(basic.SimpleProtocol):
1592 """
1593 Test FLOW_ADD_5 from draft top-half test plan
1594
1595 INPUTS
1596 num_flows - Number of flows to generate
1597 """
Howard Persh680b92a2012-03-31 13:34:35 -07001598
rootf6af1672012-04-06 09:46:29 -07001599 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001600 logging.info("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001601
Dan Talayco910a8282012-04-07 00:05:20 -07001602 num_flows = test_param_get(fq_config, "num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001603
Howard Pershc7963582012-03-29 10:02:59 -07001604 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001605
Rich Lane9a003812012-10-04 17:17:59 -07001606 logging.info("Deleting all flows from switch")
1607 rc = delete_all_flows(self.controller)
Howard Pershc7963582012-03-29 10:02:59 -07001608 self.assertEqual(rc, 0, "Failed to delete all flows")
1609
rootf6af1672012-04-06 09:46:29 -07001610 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001611
rootf6af1672012-04-06 09:46:29 -07001612 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001613 self.assertTrue(sw.connect(self.controller), \
1614 "Failed to connect to switch" \
1615 )
Howard Pershc7963582012-03-29 10:02:59 -07001616
rootf6af1672012-04-06 09:46:29 -07001617 if num_flows == 0:
1618 # Number of flows requested was 0
1619 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001620
rootf6af1672012-04-06 09:46:29 -07001621 for ts in sw.tbl_stats.stats:
1622 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001623
Rich Lane9a003812012-10-04 17:17:59 -07001624 logging.info("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001625
1626 # Dream up some flow information, i.e. space to chose from for
1627 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001628
rootf6af1672012-04-06 09:46:29 -07001629 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001630 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001631
rootf6af1672012-04-06 09:46:29 -07001632 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001633
rootf6af1672012-04-06 09:46:29 -07001634 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001635 ft.rand(required_wildcards(self), sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001636
rootf6af1672012-04-06 09:46:29 -07001637 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001638
Rich Lane9a003812012-10-04 17:17:59 -07001639 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001640 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001641 logging.info("Adding flow:")
1642 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001643 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001644
rootf6af1672012-04-06 09:46:29 -07001645 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001646
rootf6af1672012-04-06 09:46:29 -07001647 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001648
rootf6af1672012-04-06 09:46:29 -07001649 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001650
Howard Persh9cab4822012-09-11 17:08:40 -07001651 sw.settle() # Allow switch to settle and generate any notifications
1652
rootf6af1672012-04-06 09:46:29 -07001653 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001654
rootf6af1672012-04-06 09:46:29 -07001655 if not sw.errors_verify(0):
1656 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001657
rootf6af1672012-04-06 09:46:29 -07001658 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001659
rootf6af1672012-04-06 09:46:29 -07001660 sw.flow_tbl = ft
1661 if not sw.flow_tbl_verify():
1662 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001663
rootf6af1672012-04-06 09:46:29 -07001664 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001665 logging.info("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001666
Howard Pershc7963582012-03-29 10:02:59 -07001667
Howard Persh07d99e62012-04-09 15:26:57 -07001668# FLOW ADD 5_1
1669#
1670# OVERVIEW
1671# Verify handling of non-canonical flows
1672#
1673# PURPOSE
1674# - Test that switch detects and correctly responds to a non-canonical flow
1675# definition. A canonical flow is one that satisfies all match qualifier
1676# dependencies; a non-canonical flow is one that does not.
1677#
1678# PARAMETERS
1679# - None
1680#
1681# PROCESS
1682# 1. Delete all flows from switch
1683# 2. Generate 1 flow definition, which is different from its canonicalization
1684# 3. Send flow to switch
1685# 4. Retrieve flow from switch
1686# 5. Compare returned flow to canonical form of defined flow
1687# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1688
1689# Disabled.
1690# Should be DUT dependent.
Howard Persh07d99e62012-04-09 15:26:57 -07001691
rootf6af1672012-04-06 09:46:29 -07001692class Flow_Add_5_1(basic.SimpleProtocol):
1693 """
1694 Test FLOW_ADD_5.1 from draft top-half test plan
1695
1696 INPUTS
1697 None
1698 """
Rich Laned1d9c282012-10-04 22:07:10 -07001699
1700 priority = -1
rootf6af1672012-04-06 09:46:29 -07001701
1702 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001703 logging.info("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001704
Dan Talayco910a8282012-04-07 00:05:20 -07001705 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001706
1707 # Clear all flows from switch
1708
Rich Lane9a003812012-10-04 17:17:59 -07001709 logging.info("Deleting all flows from switch")
1710 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001711 self.assertEqual(rc, 0, "Failed to delete all flows")
1712
1713 # Get switch capabilites
1714
rootf6af1672012-04-06 09:46:29 -07001715 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001716 self.assertTrue(sw.connect(self.controller), \
1717 "Failed to connect to switch" \
1718 )
rootf6af1672012-04-06 09:46:29 -07001719
1720 # Dream up some flow information, i.e. space to chose from for
1721 # random flow parameter generation
1722
1723 fi = Flow_Info()
1724 fi.rand(10)
1725
1726 # Dream up a flow config that will be canonicalized by the switch
1727
1728 while True:
1729 fc = Flow_Cfg()
1730 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001731 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07001732 sw.tbl_stats.stats[0].wildcards, \
1733 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001734 sw.valid_ports, \
1735 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001736 )
1737 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001738 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001739 break
1740
1741 ft = Flow_Tbl()
1742 ft.insert(fcc)
1743
1744 # Send it to the switch
1745
Rich Lane9a003812012-10-04 17:17:59 -07001746 logging.info("Sending flow add to switch:")
1747 logging.info(str(fc))
1748 logging.info("should be canonicalized as:")
1749 logging.info(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001750 fc.send_rem = False
1751 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1752
1753 # Do barrier, to make sure all flows are in
1754
1755 self.assertTrue(sw.barrier(), "Barrier failed")
1756
1757 result = True
1758
Howard Persh9cab4822012-09-11 17:08:40 -07001759 sw.settle() # Allow switch to settle and generate any notifications
1760
rootf6af1672012-04-06 09:46:29 -07001761 # Check for any error messages
1762
1763 if not sw.errors_verify(0):
1764 result = False
1765
1766 # Verify flow table
1767
1768 sw.flow_tbl = ft
1769 if not sw.flow_tbl_verify():
1770 result = False
1771
1772 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001773 logging.info("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001774
1775
Howard Persh07d99e62012-04-09 15:26:57 -07001776# FLOW ADD 6
1777#
1778# OVERVIEW
1779# Test flow table capacity
1780#
1781# PURPOSE
1782# - Test switch can accept as many flow definitions as it claims
1783# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1784# - Test that attempting to create flows beyond capacity does not corrupt
1785# flow table
1786#
1787# PARAMETERS
1788# None
1789#
1790# PROCESS
1791# 1. Delete all flows from switch
1792# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1793# to determine flow table size, N
1794# 3. Generate (N + 1) distinct flow configurations
1795# 4. Send N flow adds to switch, for flows generated in step 3 above
1796# 5. Verify flow table in switch
1797# 6. Send one more flow add to switch
1798# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1799# response was generated by switch, for last flow mod sent
1800# 7. Retrieve flow stats from switch
1801# 8. Verify flow table in switch
1802# 9. Test PASSED iff:
1803# - error message received, for correct flow
1804# - last flow definition sent to switch is not in flow table
1805# else test FAILED
1806
Howard Persh3340d452012-04-06 16:45:21 -07001807# Disabled because of bogus capacity reported by OVS.
1808# Should be DUT dependent.
Howard Persh3340d452012-04-06 16:45:21 -07001809
rootf6af1672012-04-06 09:46:29 -07001810class Flow_Add_6(basic.SimpleProtocol):
1811 """
1812 Test FLOW_ADD_6 from draft top-half test plan
1813
1814 INPUTS
1815 num_flows - Number of flows to generate
1816 """
Howard Pershc7963582012-03-29 10:02:59 -07001817
Rich Laned1d9c282012-10-04 22:07:10 -07001818 priority = -1
1819
Howard Pershc7963582012-03-29 10:02:59 -07001820 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001821 logging.info("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001822
rootf6af1672012-04-06 09:46:29 -07001823 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001824
Rich Lane9a003812012-10-04 17:17:59 -07001825 logging.info("Deleting all flows from switch")
1826 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001827 self.assertEqual(rc, 0, "Failed to delete all flows")
1828
1829 # Get switch capabilites
1830
rootf6af1672012-04-06 09:46:29 -07001831 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001832 self.assertTrue(sw.connect(self.controller), \
1833 "Failed to connect to switch" \
1834 )
rootf6af1672012-04-06 09:46:29 -07001835
root2843d2b2012-04-06 10:27:46 -07001836 num_flows = 0
rootf6af1672012-04-06 09:46:29 -07001837 for ts in sw.tbl_stats.stats:
1838 num_flows = num_flows + ts.max_entries
1839
Rich Lane9a003812012-10-04 17:17:59 -07001840 logging.info("Switch capacity is %d flows" % (num_flows))
1841 logging.info("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001842
1843 # Dream up some flow information, i.e. space to chose from for
1844 # random flow parameter generation
1845
1846 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001847 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001848
1849 # Create a flow table, to switch's capacity
1850
1851 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001852 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07001853
1854 # Send flow table to switch
1855
Rich Lane9a003812012-10-04 17:17:59 -07001856 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001857 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001858 logging.info("Adding flow:")
1859 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001860 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1861
1862 # Do barrier, to make sure all flows are in
1863
1864 self.assertTrue(sw.barrier(), "Barrier failed")
1865
1866 result = True
1867
Howard Persh9cab4822012-09-11 17:08:40 -07001868 sw.settle() # Allow switch to settle and generate any notifications
1869
rootf6af1672012-04-06 09:46:29 -07001870 # Check for any error messages
1871
1872 if not sw.errors_verify(0):
1873 result = False
1874
1875 # Dream up one more flow
1876
Rich Lane9a003812012-10-04 17:17:59 -07001877 logging.info("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001878 while True:
1879 fc = Flow_Cfg()
1880 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001881 required_wildcards(self), \
Howard Persh07d99e62012-04-09 15:26:57 -07001882 sw.tbl_stats.stats[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001883 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001884 sw.valid_ports, \
1885 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001886 )
1887 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001888 if not ft.find(fc):
1889 break
rootf6af1672012-04-06 09:46:29 -07001890
1891 # Send one-more flow
1892
1893 fc.send_rem = False
Rich Lane9a003812012-10-04 17:17:59 -07001894 logging.info("Sending flow add switch")
1895 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001896 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1897
1898 # Do barrier, to make sure all flows are in
1899
1900 self.assertTrue(sw.barrier(), "Barrier failed")
1901
Howard Persh9cab4822012-09-11 17:08:40 -07001902 sw.settle() # Allow switch to settle and generate any notifications
1903
rootf6af1672012-04-06 09:46:29 -07001904 # Check for expected error message
1905
1906 if not sw.errors_verify(1, \
1907 ofp.OFPET_FLOW_MOD_FAILED, \
1908 ofp.OFPFMFC_ALL_TABLES_FULL \
1909 ):
1910 result = False
1911
1912 # Verify flow table
1913
1914 sw.flow_tbl = ft
1915 if not sw.flow_tbl_verify():
1916 result = False
1917
1918 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001919 logging.info("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001920
1921
Howard Persh07d99e62012-04-09 15:26:57 -07001922# FLOW ADD 7
1923#
1924# OVERVIEW
1925# Test flow redefinition
1926#
1927# PURPOSE
1928# Verify that successive flow adds with same priority and match criteria
1929# overwrite in flow table
1930#
1931# PARAMETERS
1932# None
1933#
1934# PROCESS
1935# 1. Delete all flows from switch
1936# 2. Generate flow definition F1
1937# 3. Generate flow definition F2, with same key (priority and match) as F1,
1938# but with different actions
1939# 4. Send flow adds for F1 and F2 to switch
1940# 5. Verify flow definitions in switch
1941# 6. Test PASSED iff 1 flow returned by switch, matching configuration of F2;
1942# else test FAILED
1943
rootf6af1672012-04-06 09:46:29 -07001944class Flow_Add_7(basic.SimpleProtocol):
1945 """
1946 Test FLOW_ADD_7 from draft top-half test plan
1947
1948 INPUTS
1949 None
1950 """
1951
1952 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001953 logging.info("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001954
1955 # Clear all flows from switch
1956
Rich Lane9a003812012-10-04 17:17:59 -07001957 logging.info("Deleting all flows from switch")
1958 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001959 self.assertEqual(rc, 0, "Failed to delete all flows")
1960
1961 # Get switch capabilites
1962
rootf6af1672012-04-06 09:46:29 -07001963 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001964 self.assertTrue(sw.connect(self.controller), \
1965 "Failed to connect to switch" \
1966 )
rootf6af1672012-04-06 09:46:29 -07001967
1968 # Dream up some flow information, i.e. space to chose from for
1969 # random flow parameter generation
1970
1971 fi = Flow_Info()
1972 fi.rand(10)
1973
1974 # Dream up a flow config
1975
1976 fc = Flow_Cfg()
1977 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001978 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07001979 sw.tbl_stats.stats[0].wildcards, \
1980 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001981 sw.valid_ports, \
1982 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001983 )
1984 fc = fc.canonical()
1985
1986 # Send it to the switch
1987
Rich Lane9a003812012-10-04 17:17:59 -07001988 logging.info("Sending flow add to switch:")
1989 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001990 ft = Flow_Tbl()
1991 fc.send_rem = False
1992 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1993 ft.insert(fc)
1994
1995 # Dream up some different actions, with the same flow key
1996
1997 fc2 = copy.deepcopy(fc)
1998 while True:
1999 fc2.rand_mod(fi, \
2000 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002001 sw.valid_ports, \
2002 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002003 )
2004 if fc2 != fc:
2005 break
2006
2007 # Send that to the switch
2008
Rich Lane9a003812012-10-04 17:17:59 -07002009 logging.info("Sending flow add to switch:")
2010 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002011 fc2.send_rem = False
2012 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
2013 ft.insert(fc2)
2014
2015 # Do barrier, to make sure all flows are in
2016
2017 self.assertTrue(sw.barrier(), "Barrier failed")
2018
2019 result = True
2020
Howard Persh9cab4822012-09-11 17:08:40 -07002021 sw.settle() # Allow switch to settle and generate any notifications
2022
rootf6af1672012-04-06 09:46:29 -07002023 # Check for any error messages
2024
2025 if not sw.errors_verify(0):
2026 result = False
2027
2028 # Verify flow table
2029
2030 sw.flow_tbl = ft
2031 if not sw.flow_tbl_verify():
2032 result = False
2033
2034 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002035 logging.info("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002036
2037
Howard Persh07d99e62012-04-09 15:26:57 -07002038# FLOW ADD 8
2039#
2040# OVERVIEW
2041# Add overlapping flows to switch, verify that overlapping flows are rejected
2042#
2043# PURPOSE
2044# - Test detection of overlapping flows by switch
2045# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
2046# - Test rejection of overlapping flows
2047# - Test defining overlapping flows does not corrupt flow table
2048#
2049# PARAMETERS
2050# None
2051#
2052# PROCESS
2053# 1. Delete all flows from switch
2054# 2. Generate flow definition F1
2055# 3. Generate flow definition F2, with key overlapping F1
2056# 4. Send flow add to switch, for F1
2057# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
2058# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
2059# was generated by switch
2060# 7. Verifiy flows configured in swtich
2061# 8. Test PASSED iff:
2062# - error message received, for overlapping flow
2063# - overlapping flow is not in flow table
2064# else test FAILED
2065
rootf6af1672012-04-06 09:46:29 -07002066class Flow_Add_8(basic.SimpleProtocol):
2067 """
2068 Test FLOW_ADD_8 from draft top-half test plan
2069
2070 INPUTS
2071 None
2072 """
2073
2074 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002075 logging.info("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002076
2077 # Clear all flows from switch
2078
Rich Lane9a003812012-10-04 17:17:59 -07002079 logging.info("Deleting all flows from switch")
2080 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002081 self.assertEqual(rc, 0, "Failed to delete all flows")
2082
2083 # Get switch capabilites
2084
rootf6af1672012-04-06 09:46:29 -07002085 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002086 self.assertTrue(sw.connect(self.controller), \
2087 "Failed to connect to switch" \
2088 )
rootf6af1672012-04-06 09:46:29 -07002089
2090 # Dream up some flow information, i.e. space to chose from for
2091 # random flow parameter generation
2092
2093 fi = Flow_Info()
2094 fi.rand(10)
2095
2096 # Dream up a flow config, with at least 1 qualifier specified
2097
2098 fc = Flow_Cfg()
2099 while True:
2100 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002101 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002102 sw.tbl_stats.stats[0].wildcards, \
2103 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002104 sw.valid_ports, \
2105 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002106 )
2107 fc = fc.canonical()
2108 if fc.match.wildcards != ofp.OFPFW_ALL:
2109 break
2110
2111 # Send it to the switch
2112
Rich Lane9a003812012-10-04 17:17:59 -07002113 logging.info("Sending flow add to switch:")
2114 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002115 ft = Flow_Tbl()
2116 fc.send_rem = False
2117 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2118 ft.insert(fc)
2119
2120 # Wildcard out one qualifier that was specified, to create an
2121 # overlapping flow
2122
2123 fc2 = copy.deepcopy(fc)
2124 for wi in shuffle(range(len(all_wildcards_list))):
2125 w = all_wildcards_list[wi]
2126 if (fc2.match.wildcards & w) == 0:
2127 break
2128 if w == ofp.OFPFW_NW_SRC_MASK:
2129 w = ofp.OFPFW_NW_SRC_ALL
2130 wn = "OFPFW_NW_SRC"
2131 elif w == ofp.OFPFW_NW_DST_MASK:
2132 w = ofp.OFPFW_NW_DST_ALL
2133 wn = "OFPFW_NW_DST"
2134 else:
2135 wn = all_wildcard_names[w]
Rich Lane9a003812012-10-04 17:17:59 -07002136 logging.info("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07002137 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07002138 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07002139
2140 # Send that to the switch, with overlap checking
2141
Rich Lane9a003812012-10-04 17:17:59 -07002142 logging.info("Sending flow add to switch:")
2143 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002144 fc2.send_rem = False
2145 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
2146
2147 # Do barrier, to make sure all flows are in
2148 self.assertTrue(sw.barrier(), "Barrier failed")
2149
2150 result = True
2151
Howard Persh9cab4822012-09-11 17:08:40 -07002152 sw.settle() # Allow switch to settle and generate any notifications
2153
rootf6af1672012-04-06 09:46:29 -07002154 # Check for expected error message
2155
2156 if not sw.errors_verify(1, \
2157 ofp.OFPET_FLOW_MOD_FAILED, \
2158 ofp.OFPFMFC_OVERLAP \
2159 ):
2160 result = False
2161
2162 # Verify flow table
2163
2164 sw.flow_tbl = ft
2165 if not sw.flow_tbl_verify():
2166 result = False
2167
2168 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002169 logging.info("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002170
2171
Howard Persh07d99e62012-04-09 15:26:57 -07002172# FLOW MODIFY 1
2173#
2174# OVERVIEW
2175# Strict modify of single existing flow
2176#
2177# PURPOSE
2178# - Verify that strict flow modify operates only on specified flow
2179# - Verify that flow is correctly modified
2180#
2181# PARAMETERS
2182# None
2183#
2184# PROCESS
2185# 1. Delete all flows from switch
2186# 2. Generate 1 flow F
2187# 3. Send flow add to switch, for flow F
2188# 4. Generate new action list for flow F, yielding F'
2189# 5. Send strict flow modify to switch, for flow F'
2190# 6. Verify flow table in switch
2191# 7. Test PASSED iff flow returned by switch is F'; else FAILED
2192
rootf6af1672012-04-06 09:46:29 -07002193class Flow_Mod_1(basic.SimpleProtocol):
2194 """
2195 Test FLOW_MOD_1 from draft top-half test plan
2196
2197 INPUTS
2198 None
2199 """
2200
2201 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002202 logging.info("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002203
2204 # Clear all flows from switch
2205
Rich Lane9a003812012-10-04 17:17:59 -07002206 logging.info("Deleting all flows from switch")
2207 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002208 self.assertEqual(rc, 0, "Failed to delete all flows")
2209
2210 # Get switch capabilites
2211
rootf6af1672012-04-06 09:46:29 -07002212 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002213 self.assertTrue(sw.connect(self.controller), \
2214 "Failed to connect to switch" \
2215 )
rootf6af1672012-04-06 09:46:29 -07002216
2217 # Dream up some flow information, i.e. space to chose from for
2218 # random flow parameter generation
2219
2220 fi = Flow_Info()
2221 fi.rand(10)
2222
2223 # Dream up a flow config
2224
2225 fc = Flow_Cfg()
2226 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002227 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002228 sw.tbl_stats.stats[0].wildcards, \
2229 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002230 sw.valid_ports, \
2231 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002232 )
2233 fc = fc.canonical()
2234
2235 # Send it to the switch
2236
Rich Lane9a003812012-10-04 17:17:59 -07002237 logging.info("Sending flow add to switch:")
2238 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002239 ft = Flow_Tbl()
2240 fc.send_rem = False
2241 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2242 ft.insert(fc)
2243
2244 # Dream up some different actions, with the same flow key
2245
2246 fc2 = copy.deepcopy(fc)
2247 while True:
2248 fc2.rand_mod(fi, \
2249 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002250 sw.valid_ports, \
2251 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002252 )
2253 if fc2 != fc:
2254 break
2255
2256 # Send that to the switch
2257
Rich Lane9a003812012-10-04 17:17:59 -07002258 logging.info("Sending strict flow mod to switch:")
2259 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002260 fc2.send_rem = False
2261 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2262 ft.insert(fc2)
2263
2264 # Do barrier, to make sure all flows are in
2265
2266 self.assertTrue(sw.barrier(), "Barrier failed")
2267
2268 result = True
2269
Howard Persh9cab4822012-09-11 17:08:40 -07002270 sw.settle() # Allow switch to settle and generate any notifications
2271
rootf6af1672012-04-06 09:46:29 -07002272 # Check for any error messages
2273
2274 if not sw.errors_verify(0):
2275 result = False
2276
2277 # Verify flow table
2278
2279 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002280 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002281 result = False
2282
2283 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002284 logging.info("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002285
Howard Persh07d99e62012-04-09 15:26:57 -07002286
2287# FLOW MODIFY 2
2288#
2289# OVERVIEW
2290# Loose modify of mutiple flows
2291#
2292# PURPOSE
2293# - Verify that loose flow modify operates only on matching flows
2294# - Verify that matching flows are correctly modified
2295#
2296# PARAMETERS
2297# Name: num_flows
2298# Type: number
2299# Description:
2300# Number of flows to define
2301# Default: 100
2302#
2303# PROCESS
2304# 1. Delete all flows from switch
2305# 2. Generate <num_flows> distinct flow configurations
2306# 3. Send <num_flows> flow adds to switch
2307# 4. Pick 1 defined flow F at random
2308# 5. Create overlapping loose flow mod match criteria by repeatedly
2309# wildcarding out qualifiers in match of F => F',
2310# and create new actions list A' for F'
2311# 6. Send loose flow modify for F' to switch
2312# 7. Verify flow table in swtich
2313# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2314# are returned in step 7 above, each with correct (original or modified)
2315# action list;
2316# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002317
2318class Flow_Mod_2(basic.SimpleProtocol):
2319 """
2320 Test FLOW_MOD_2 from draft top-half test plan
2321
2322 INPUTS
2323 None
2324 """
2325
2326 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002327 logging.info("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002328
Dan Talayco910a8282012-04-07 00:05:20 -07002329 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002330
2331 # Clear all flows from switch
2332
Rich Lane9a003812012-10-04 17:17:59 -07002333 logging.info("Deleting all flows from switch")
2334 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002335 self.assertEqual(rc, 0, "Failed to delete all flows")
2336
2337 # Get switch capabilites
2338
rootf6af1672012-04-06 09:46:29 -07002339 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002340 self.assertTrue(sw.connect(self.controller), \
2341 "Failed to connect to switch" \
2342 )
rootf6af1672012-04-06 09:46:29 -07002343
2344 # Dream up some flow information, i.e. space to chose from for
2345 # random flow parameter generation
2346
2347 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002348 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002349 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002350
2351 # Dream up some flows
2352
2353 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002354 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002355
2356 # Send flow table to switch
2357
Rich Lane9a003812012-10-04 17:17:59 -07002358 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002359 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002360 logging.info("Adding flow:")
2361 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002362 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2363
2364 # Do barrier, to make sure all flows are in
2365
2366 self.assertTrue(sw.barrier(), "Barrier failed")
2367
2368 result = True
2369
Howard Persh9cab4822012-09-11 17:08:40 -07002370 sw.settle() # Allow switch to settle and generate any notifications
2371
rootf6af1672012-04-06 09:46:29 -07002372 # Check for any error messages
2373
2374 if not sw.errors_verify(0):
2375 result = False
2376
2377 # Verify flow table
2378
2379 sw.flow_tbl = ft
2380 if not sw.flow_tbl_verify():
2381 result = False
2382
2383 # Pick a random flow as a basis
Howard Persh5f3c83f2012-04-13 09:57:10 -07002384
2385 mfc = copy.deepcopy((ft.values())[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002386 mfc.rand_mod(fi, \
2387 sw.sw_features.actions, \
2388 sw.valid_ports, \
2389 sw.valid_queues \
2390 )
rootf6af1672012-04-06 09:46:29 -07002391
2392 # Repeatedly wildcard qualifiers
2393
2394 for wi in shuffle(range(len(all_wildcards_list))):
2395 w = all_wildcards_list[wi]
2396 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2397 n = wildcard_get(mfc.match.wildcards, w)
2398 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002399 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2400 w, \
2401 random.randint(n + 1, 32) \
2402 )
rootf6af1672012-04-06 09:46:29 -07002403 else:
2404 continue
2405 else:
2406 if wildcard_get(mfc.match.wildcards, w) == 0:
2407 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2408 else:
2409 continue
2410 mfc = mfc.canonical()
2411
2412 # Count the number of flows that would be modified
2413
2414 n = 0
2415 for fc in ft.values():
2416 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2417 n = n + 1
2418
2419 # If more than 1, we found our loose delete flow spec
2420 if n > 1:
2421 break
2422
Rich Lane9a003812012-10-04 17:17:59 -07002423 logging.info("Modifying %d flows" % (n))
2424 logging.info("Sending flow mod to switch:")
2425 logging.info(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002426 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2427
2428 # Do barrier, to make sure all flows are in
2429 self.assertTrue(sw.barrier(), "Barrier failed")
2430
Howard Persh9cab4822012-09-11 17:08:40 -07002431 sw.settle() # Allow switch to settle and generate any notifications
2432
rootf6af1672012-04-06 09:46:29 -07002433 # Check for error message
2434
2435 if not sw.errors_verify(0):
2436 result = False
2437
2438 # Apply flow mod to local flow table
2439
2440 for fc in ft.values():
2441 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002442 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002443
2444 # Verify flow table
2445
2446 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002447 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002448 result = False
2449
2450 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002451 logging.info("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002452
2453
Howard Persh07d99e62012-04-09 15:26:57 -07002454# FLOW MODIFY 3
2455
2456# OVERVIEW
2457# Strict modify of non-existent flow
2458#
2459# PURPOSE
2460# Verify that strict modify of a non-existent flow is equivalent to a flow add
2461#
2462# PARAMETERS
2463# None
2464#
2465# PROCESS
2466# 1. Delete all flows from switch
2467# 2. Send single flow mod, as strict modify, to switch
2468# 3. Verify flow table in switch
2469# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2470
rootf6af1672012-04-06 09:46:29 -07002471class Flow_Mod_3(basic.SimpleProtocol):
2472 """
2473 Test FLOW_MOD_3 from draft top-half test plan
2474
2475 INPUTS
2476 None
2477 """
2478
2479 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002480 logging.info("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002481
2482 # Clear all flows from switch
2483
Rich Lane9a003812012-10-04 17:17:59 -07002484 logging.info("Deleting all flows from switch")
2485 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002486 self.assertEqual(rc, 0, "Failed to delete all flows")
2487
2488 # Get switch capabilites
2489
rootf6af1672012-04-06 09:46:29 -07002490 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002491 self.assertTrue(sw.connect(self.controller), \
2492 "Failed to connect to switch" \
2493 )
rootf6af1672012-04-06 09:46:29 -07002494
2495 # Dream up some flow information, i.e. space to chose from for
2496 # random flow parameter generation
2497
2498 fi = Flow_Info()
2499 fi.rand(10)
2500
2501 # Dream up a flow config
2502
2503 fc = Flow_Cfg()
2504 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002505 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002506 sw.tbl_stats.stats[0].wildcards, \
2507 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002508 sw.valid_ports, \
2509 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002510 )
2511 fc = fc.canonical()
2512
2513 # Send it to the switch
2514
Rich Lane9a003812012-10-04 17:17:59 -07002515 logging.info("Sending flow mod to switch:")
2516 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002517 ft = Flow_Tbl()
2518 fc.send_rem = False
2519 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2520 ft.insert(fc)
2521
2522 # Do barrier, to make sure all flows are in
2523
2524 self.assertTrue(sw.barrier(), "Barrier failed")
2525
2526 result = True
2527
Howard Persh9cab4822012-09-11 17:08:40 -07002528 sw.settle() # Allow switch to settle and generate any notifications
2529
rootf6af1672012-04-06 09:46:29 -07002530 # Check for any error messages
2531
2532 if not sw.errors_verify(0):
2533 result = False
2534
2535 # Verify flow table
2536
2537 sw.flow_tbl = ft
2538 if not sw.flow_tbl_verify():
2539 result = False
2540
2541 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002542 logging.info("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002543
2544
Howard Persh8d21c1f2012-04-20 15:57:29 -07002545# FLOW MODIFY 3_1
2546
2547# OVERVIEW
2548# No-op modify
2549#
2550# PURPOSE
2551# Verify that modify of a flow with new actions same as old ones operates correctly
2552#
2553# PARAMETERS
2554# None
2555#
2556# PROCESS
2557# 1. Delete all flows from switch
2558# 2. Send single flow mod, as strict modify, to switch
2559# 3. Verify flow table in switch
2560# 4. Send same flow mod, as strict modify, to switch
2561# 5. Verify flow table in switch
2562# 6. Test PASSED iff flow defined in step 2 and 4 above verified; else FAILED
2563
2564class Flow_Mod_3_1(basic.SimpleProtocol):
2565 """
2566 Test FLOW_MOD_3_1 from draft top-half test plan
2567
2568 INPUTS
2569 None
2570 """
2571
2572 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002573 logging.info("Flow_Mod_3_1 TEST BEGIN")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002574
2575 # Clear all flows from switch
2576
Rich Lane9a003812012-10-04 17:17:59 -07002577 logging.info("Deleting all flows from switch")
2578 rc = delete_all_flows(self.controller)
Howard Persh8d21c1f2012-04-20 15:57:29 -07002579 self.assertEqual(rc, 0, "Failed to delete all flows")
2580
2581 # Get switch capabilites
2582
2583 sw = Switch()
2584 self.assertTrue(sw.connect(self.controller), \
2585 "Failed to connect to switch" \
2586 )
2587
2588 # Dream up some flow information, i.e. space to chose from for
2589 # random flow parameter generation
2590
2591 fi = Flow_Info()
2592 fi.rand(10)
2593
2594 # Dream up a flow config
2595
2596 fc = Flow_Cfg()
2597 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002598 required_wildcards(self), \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002599 sw.tbl_stats.stats[0].wildcards, \
2600 sw.sw_features.actions, \
2601 sw.valid_ports, \
2602 sw.valid_queues \
2603 )
2604 fc = fc.canonical()
2605
2606 # Send it to the switch
2607
Rich Lane9a003812012-10-04 17:17:59 -07002608 logging.info("Sending flow mod to switch:")
2609 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002610 ft = Flow_Tbl()
2611 fc.send_rem = False
2612 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2613 ft.insert(fc)
2614
2615 # Do barrier, to make sure all flows are in
2616
2617 self.assertTrue(sw.barrier(), "Barrier failed")
2618
2619 result = True
2620
Howard Persh9cab4822012-09-11 17:08:40 -07002621 sw.settle() # Allow switch to settle and generate any notifications
2622
Howard Persh8d21c1f2012-04-20 15:57:29 -07002623 # Check for any error messages
2624
2625 if not sw.errors_verify(0):
2626 result = False
2627
2628 # Verify flow table
2629
2630 sw.flow_tbl = ft
2631 if not sw.flow_tbl_verify():
2632 result = False
2633
2634 # Send same flow to the switch again
2635
Rich Lane9a003812012-10-04 17:17:59 -07002636 logging.info("Sending flow mod to switch:")
2637 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002638 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2639
2640 # Do barrier, to make sure all flows are in
2641
2642 self.assertTrue(sw.barrier(), "Barrier failed")
2643
Howard Persh9cab4822012-09-11 17:08:40 -07002644 sw.settle() # Allow switch to settle and generate any notifications
2645
Howard Persh8d21c1f2012-04-20 15:57:29 -07002646 # Check for any error messages
2647
2648 if not sw.errors_verify(0):
2649 result = False
2650
2651 # Verify flow table
2652
2653 if not sw.flow_tbl_verify():
2654 result = False
2655
2656 self.assertTrue(result, "Flow_Mod_3_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002657 logging.info("Flow_Mod_3_1 TEST PASSED")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002658
2659
Howard Persh07d99e62012-04-09 15:26:57 -07002660# FLOW DELETE 1
2661#
2662# OVERVIEW
2663# Strict delete of single flow
2664#
2665# PURPOSE
2666# Verify correct operation of strict delete of single defined flow
2667#
2668# PARAMETERS
2669# None
2670#
2671# PROCESS
2672# 1. Delete all flows from switch
2673# 2. Send flow F to switch
2674# 3. Send strict flow delete for F to switch
2675# 4. Verify flow table in swtich
2676# 6. Test PASSED iff all flows sent to switch in step 2 above,
2677# less flow removed in step 3 above, are returned in step 4 above;
2678# else test FAILED
2679
rootf6af1672012-04-06 09:46:29 -07002680class Flow_Del_1(basic.SimpleProtocol):
2681 """
2682 Test FLOW_DEL_1 from draft top-half test plan
2683
2684 INPUTS
2685 None
2686 """
2687
2688 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002689 logging.info("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002690
2691 # Clear all flows from switch
2692
Rich Lane9a003812012-10-04 17:17:59 -07002693 logging.info("Deleting all flows from switch")
2694 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002695 self.assertEqual(rc, 0, "Failed to delete all flows")
2696
2697 # Get switch capabilites
2698
rootf6af1672012-04-06 09:46:29 -07002699 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002700 self.assertTrue(sw.connect(self.controller), \
2701 "Failed to connect to switch" \
2702 )
rootf6af1672012-04-06 09:46:29 -07002703
2704 # Dream up some flow information, i.e. space to chose from for
2705 # random flow parameter generation
2706
2707 fi = Flow_Info()
2708 fi.rand(10)
2709
2710 # Dream up a flow config
2711
2712 fc = Flow_Cfg()
2713 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002714 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002715 sw.tbl_stats.stats[0].wildcards, \
2716 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002717 sw.valid_ports, \
2718 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002719 )
2720 fc = fc.canonical()
2721
2722 # Send it to the switch
2723
Rich Lane9a003812012-10-04 17:17:59 -07002724 logging.info("Sending flow add to switch:")
2725 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002726 ft = Flow_Tbl()
2727 fc.send_rem = False
2728 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2729 ft.insert(fc)
2730
2731 # Dream up some different actions, with the same flow key
2732
2733 fc2 = copy.deepcopy(fc)
2734 while True:
2735 fc2.rand_mod(fi, \
2736 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002737 sw.valid_ports, \
2738 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002739 )
2740 if fc2 != fc:
2741 break
2742
2743 # Delete strictly
2744
Rich Lane9a003812012-10-04 17:17:59 -07002745 logging.info("Sending strict flow del to switch:")
2746 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002747 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2748 ft.delete(fc)
2749
2750 # Do barrier, to make sure all flows are in
2751
2752 self.assertTrue(sw.barrier(), "Barrier failed")
2753
2754 result = True
2755
Howard Persh9cab4822012-09-11 17:08:40 -07002756 sw.settle() # Allow switch to settle and generate any notifications
2757
rootf6af1672012-04-06 09:46:29 -07002758 # Check for any error messages
2759
2760 if not sw.errors_verify(0):
2761 result = False
2762
2763 # Verify flow table
2764
2765 sw.flow_tbl = ft
2766 if not sw.flow_tbl_verify():
2767 result = False
2768
2769 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002770 logging.info("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002771
2772
Howard Persh07d99e62012-04-09 15:26:57 -07002773# FLOW DELETE 2
2774#
2775# OVERVIEW
2776# Loose delete of multiple flows
2777#
2778# PURPOSE
2779# - Verify correct operation of loose delete of multiple flows
2780#
2781# PARAMETERS
2782# Name: num_flows
2783# Type: number
2784# Description:
2785# Number of flows to define
2786# Default: 100
2787#
2788# PROCESS
2789# 1. Delete all flows from switch
2790# 2. Generate <num_flows> distinct flow configurations
2791# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2792# 4. Pick 1 defined flow F at random
2793# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2794# F' will match more than 1 existing flow key
2795# 6. Send loose flow delete for F' to switch
2796# 7. Verify flow table in switch
2797# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2798# removed in step 6 above (i.e. those that match F'), are returned
2799# in step 7 above;
2800# else test FAILED
2801
rootf6af1672012-04-06 09:46:29 -07002802class Flow_Del_2(basic.SimpleProtocol):
2803 """
2804 Test FLOW_DEL_2 from draft top-half test plan
2805
2806 INPUTS
2807 None
2808 """
2809
2810 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002811 logging.info("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002812
Dan Talayco910a8282012-04-07 00:05:20 -07002813 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002814
2815 # Clear all flows from switch
2816
Rich Lane9a003812012-10-04 17:17:59 -07002817 logging.info("Deleting all flows from switch")
2818 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002819 self.assertEqual(rc, 0, "Failed to delete all flows")
2820
2821 # Get switch capabilites
2822
rootf6af1672012-04-06 09:46:29 -07002823 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002824 self.assertTrue(sw.connect(self.controller), \
2825 "Failed to connect to switch" \
2826 )
rootf6af1672012-04-06 09:46:29 -07002827
2828 # Dream up some flow information, i.e. space to chose from for
2829 # random flow parameter generation
2830
2831 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002832 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002833 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002834
2835 # Dream up some flows
2836
2837 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002838 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002839
2840 # Send flow table to switch
2841
Rich Lane9a003812012-10-04 17:17:59 -07002842 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002843 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002844 logging.info("Adding flow:")
2845 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002846 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2847
2848 # Do barrier, to make sure all flows are in
2849
2850 self.assertTrue(sw.barrier(), "Barrier failed")
2851
2852 result = True
2853
Howard Persh9cab4822012-09-11 17:08:40 -07002854 sw.settle() # Allow switch to settle and generate any notifications
2855
rootf6af1672012-04-06 09:46:29 -07002856 # Check for any error messages
2857
2858 if not sw.errors_verify(0):
2859 result = False
2860
2861 # Verify flow table
2862
2863 sw.flow_tbl = ft
2864 if not sw.flow_tbl_verify():
2865 result = False
2866
2867 # Pick a random flow as a basis
2868
2869 dfc = copy.deepcopy(ft.values()[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002870 dfc.rand_mod(fi, \
2871 sw.sw_features.actions, \
2872 sw.valid_ports, \
2873 sw.valid_queues \
2874 )
rootf6af1672012-04-06 09:46:29 -07002875
2876 # Repeatedly wildcard qualifiers
2877
2878 for wi in shuffle(range(len(all_wildcards_list))):
2879 w = all_wildcards_list[wi]
2880 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2881 n = wildcard_get(dfc.match.wildcards, w)
2882 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002883 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2884 w, \
2885 random.randint(n + 1, 32) \
2886 )
rootf6af1672012-04-06 09:46:29 -07002887 else:
2888 continue
2889 else:
2890 if wildcard_get(dfc.match.wildcards, w) == 0:
2891 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2892 else:
2893 continue
2894 dfc = dfc.canonical()
2895
2896 # Count the number of flows that would be deleted
2897
2898 n = 0
2899 for fc in ft.values():
2900 if dfc.overlaps(fc, True):
2901 n = n + 1
2902
2903 # If more than 1, we found our loose delete flow spec
2904 if n > 1:
2905 break
2906
Rich Lane9a003812012-10-04 17:17:59 -07002907 logging.info("Deleting %d flows" % (n))
2908 logging.info("Sending flow del to switch:")
2909 logging.info(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002910 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2911
2912 # Do barrier, to make sure all flows are in
2913 self.assertTrue(sw.barrier(), "Barrier failed")
2914
Howard Persh9cab4822012-09-11 17:08:40 -07002915 sw.settle() # Allow switch to settle and generate any notifications
2916
rootf6af1672012-04-06 09:46:29 -07002917 # Check for error message
2918
2919 if not sw.errors_verify(0):
2920 result = False
2921
2922 # Apply flow mod to local flow table
2923
2924 for fc in ft.values():
2925 if dfc.overlaps(fc, True):
2926 ft.delete(fc)
2927
2928 # Verify flow table
2929
2930 sw.flow_tbl = ft
2931 if not sw.flow_tbl_verify():
2932 result = False
2933
2934 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002935 logging.info("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002936
2937
Howard Persh07d99e62012-04-09 15:26:57 -07002938# FLOW DELETE 4
2939#
2940# OVERVIEW
2941# Flow removed messages
2942#
2943# PURPOSE
2944# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2945# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2946#
2947# PARAMETERS
2948# None
2949#
2950# PROCESS
2951# 1. Delete all flows from switch
2952# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2953# 3. Send strict flow delete of flow to switch
2954# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2955# 5. Verify flow table in switch
2956# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2957# removed in step 3 above, are returned in step 5 above, and that
2958# asynch message was received; else test FAILED
2959
2960
rootf6af1672012-04-06 09:46:29 -07002961class Flow_Del_4(basic.SimpleProtocol):
2962 """
2963 Test FLOW_DEL_4 from draft top-half test plan
2964
2965 INPUTS
2966 None
2967 """
2968
2969 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002970 logging.info("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002971
2972 # Clear all flows from switch
2973
Rich Lane9a003812012-10-04 17:17:59 -07002974 logging.info("Deleting all flows from switch")
2975 rc = delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002976 self.assertEqual(rc, 0, "Failed to delete all flows")
2977
2978 # Get switch capabilites
2979
rootf6af1672012-04-06 09:46:29 -07002980 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002981 self.assertTrue(sw.connect(self.controller), \
2982 "Failed to connect to switch" \
2983 )
rootf6af1672012-04-06 09:46:29 -07002984
2985 # Dream up some flow information, i.e. space to chose from for
2986 # random flow parameter generation
2987
2988 fi = Flow_Info()
2989 fi.rand(10)
2990
2991 # Dream up a flow config
2992
2993 fc = Flow_Cfg()
2994 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002995 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002996 sw.tbl_stats.stats[0].wildcards, \
2997 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002998 sw.valid_ports, \
2999 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07003000 )
3001 fc = fc.canonical()
3002
3003 # Send it to the switch. with "notify on removed"
3004
Rich Lane9a003812012-10-04 17:17:59 -07003005 logging.info("Sending flow add to switch:")
3006 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07003007 ft = Flow_Tbl()
3008 fc.send_rem = True
3009 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
3010 ft.insert(fc)
3011
3012 # Dream up some different actions, with the same flow key
3013
3014 fc2 = copy.deepcopy(fc)
3015 while True:
3016 fc2.rand_mod(fi, \
3017 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07003018 sw.valid_ports, \
3019 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07003020 )
3021 if fc2 != fc:
3022 break
3023
3024 # Delete strictly
3025
Rich Lane9a003812012-10-04 17:17:59 -07003026 logging.info("Sending strict flow del to switch:")
3027 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07003028 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
3029 ft.delete(fc)
3030
3031 # Do barrier, to make sure all flows are in
3032
3033 self.assertTrue(sw.barrier(), "Barrier failed")
3034
3035 result = True
3036
Howard Persh9cab4822012-09-11 17:08:40 -07003037 sw.settle() # Allow switch to settle and generate any notifications
3038
rootf6af1672012-04-06 09:46:29 -07003039 # Check for expected "removed" message
3040
Howard Persh3340d452012-04-06 16:45:21 -07003041 if not sw.errors_verify(0):
3042 result = False
3043
3044 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07003045 result = False
3046
3047 # Verify flow table
3048
3049 sw.flow_tbl = ft
3050 if not sw.flow_tbl_verify():
3051 result = False
3052
3053 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07003054 logging.info("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07003055