blob: 69402f488e69866203630cd97ff7e32dbd8482c7 [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 Persh07d99e62012-04-09 15:26:57 -070040# Name: conservative_ordered_actions
41# Type: boolean (True or False)
42# Description:
43# Compare flow actions lists as unordered
44# Default: True
45
46
Howard Persh680b92a2012-03-31 13:34:35 -070047import math
Howard Pershc7963582012-03-29 10:02:59 -070048
49import logging
50
51import unittest
52import random
53
54import oftest.controller as controller
55import oftest.cstruct as ofp
56import oftest.message as message
57import oftest.dataplane as dataplane
58import oftest.action as action
59import oftest.action_list as action_list
60import oftest.parse as parse
61import pktact
62import basic
63
64from testutils import *
65from time import sleep
66
67#@var port_map Local copy of the configuration map from OF port
68# numbers to OS interfaces
Dan Talayco910a8282012-04-07 00:05:20 -070069fq_port_map = None
70#@var fq_logger Local logger object
71fq_logger = None
72#@var fq_config Local copy of global configuration data
73fq_config = None
Howard Pershc7963582012-03-29 10:02:59 -070074
rootf6af1672012-04-06 09:46:29 -070075# For test priority
76test_prio = {}
77
78
Howard Pershc7963582012-03-29 10:02:59 -070079def test_set_init(config):
80 """
81 Set up function for packet action test classes
82
83 @param config The configuration dictionary; see oft
84 """
85
86 basic.test_set_init(config)
87
Dan Talayco910a8282012-04-07 00:05:20 -070088 global fq_port_map
89 global fq_logger
90 global fq_config
Howard Pershc7963582012-03-29 10:02:59 -070091
Dan Talayco910a8282012-04-07 00:05:20 -070092 fq_logger = logging.getLogger("flowq")
93 fq_logger.info("Initializing test set")
94 fq_port_map = config["port_map"]
95 fq_config = config
root2843d2b2012-04-06 10:27:46 -070096
Howard Pershc7963582012-03-29 10:02:59 -070097
rootf6af1672012-04-06 09:46:29 -070098def flip_coin():
99 return random.randint(1, 100) <= 50
100
101
Howard Pershc7963582012-03-29 10:02:59 -0700102def shuffle(list):
103 n = len(list)
104 lim = n * n
105 i = 0
106 while i < lim:
107 a = random.randint(0, n - 1)
108 b = random.randint(0, n - 1)
109 temp = list[a]
110 list[a] = list[b]
111 list[b] = temp
112 i = i + 1
113 return list
114
115
Howard Persh680b92a2012-03-31 13:34:35 -0700116def rand_pick(list):
117 return list[random.randint(0, len(list) - 1)]
Howard Pershc7963582012-03-29 10:02:59 -0700118
Howard Persh680b92a2012-03-31 13:34:35 -0700119def rand_dl_addr():
120 return [random.randint(0, 255) & ~1,
121 random.randint(0, 255),
122 random.randint(0, 255),
123 random.randint(0, 255),
124 random.randint(0, 255),
125 random.randint(0, 255)
126 ]
Howard Pershc7963582012-03-29 10:02:59 -0700127
128def rand_nw_addr():
129 return random.randint(0, (1 << 32) - 1)
130
131
rootf6af1672012-04-06 09:46:29 -0700132class Flow_Info:
Howard Persh680b92a2012-03-31 13:34:35 -0700133 # Members:
134 # priorities - list of flow priorities
135 # dl_addrs - list of MAC addresses
136 # vlans - list of VLAN ids
137 # ethertypes - list of Ethertypes
138 # ip_addrs - list of IP addresses
139 # ip_tos - list of IP TOS values
140 # ip_protos - list of IP protocols
141 # l4_ports - list of L4 ports
142
143 def __init__(self):
144 priorities = []
145 dl_addrs = []
146 vlans = []
147 ethertypes = []
148 ip_addrs = []
149 ip_tos = []
150 ip_protos = []
151 l4_ports = []
152
153 def rand(self, n):
154 self.priorities = []
155 i = 0
156 while i < n:
157 self.priorities.append(random.randint(1, 65534))
158 i = i + 1
159
160 self.dl_addrs = []
161 i = 0
162 while i < n:
163 self.dl_addrs.append(rand_dl_addr())
164 i = i + 1
165
166 self.vlans = []
167 i = 0
168 while i < n:
169 self.vlans.append(random.randint(1, 4094))
170 i = i + 1
171
rootf6af1672012-04-06 09:46:29 -0700172 self.ethertypes = [0x0800, 0x0806]
Howard Persh680b92a2012-03-31 13:34:35 -0700173 i = 0
174 while i < n:
175 self.ethertypes.append(random.randint(0, (1 << 16) - 1))
176 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700177 self.ethertypes = shuffle(self.ethertypes)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700178
179 self.ip_addrs = []
180 i = 0
181 while i < n:
182 self.ip_addrs.append(rand_nw_addr())
183 i = i + 1
184
185 self.ip_tos = []
186 i = 0
187 while i < n:
188 self.ip_tos.append(random.randint(0, (1 << 8) - 1) & ~3)
189 i = i + 1
190
rootf6af1672012-04-06 09:46:29 -0700191 self.ip_protos = [1, 6, 17]
Howard Persh680b92a2012-03-31 13:34:35 -0700192 i = 0
193 while i < n:
194 self.ip_protos.append(random.randint(0, (1 << 8) - 1))
195 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700196 self.ip_protos = shuffle(self.ip_protos)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700197
198 self.l4_ports = []
199 i = 0
200 while i < n:
201 self.l4_ports.append(random.randint(0, (1 << 16) - 1))
202 i = i + 1
203
204 def rand_priority(self):
205 return rand_pick(self.priorities)
206
207 def rand_dl_addr(self):
208 return rand_pick(self.dl_addrs)
209
210 def rand_vlan(self):
211 return rand_pick(self.vlans)
212
213 def rand_ethertype(self):
214 return rand_pick(self.ethertypes)
215
216 def rand_ip_addr(self):
217 return rand_pick(self.ip_addrs)
218
219 def rand_ip_tos(self):
220 return rand_pick(self.ip_tos)
221
222 def rand_ip_proto(self):
223 return rand_pick(self.ip_protos)
224
225 def rand_l4_port(self):
226 return rand_pick(self.l4_ports)
227
228
Howard Pershc7963582012-03-29 10:02:59 -0700229# TBD - These don't belong here
230
Howard Persh680b92a2012-03-31 13:34:35 -0700231all_wildcards_list = [ofp.OFPFW_IN_PORT,
Howard Persh680b92a2012-03-31 13:34:35 -0700232 ofp.OFPFW_DL_DST,
rootf6af1672012-04-06 09:46:29 -0700233 ofp.OFPFW_DL_SRC,
234 ofp.OFPFW_DL_VLAN,
235 ofp.OFPFW_DL_VLAN_PCP,
Howard Persh680b92a2012-03-31 13:34:35 -0700236 ofp.OFPFW_DL_TYPE,
rootf6af1672012-04-06 09:46:29 -0700237 ofp.OFPFW_NW_TOS,
Howard Persh680b92a2012-03-31 13:34:35 -0700238 ofp.OFPFW_NW_PROTO,
Howard Persh680b92a2012-03-31 13:34:35 -0700239 ofp.OFPFW_NW_SRC_MASK,
240 ofp.OFPFW_NW_DST_MASK,
rootf6af1672012-04-06 09:46:29 -0700241 ofp.OFPFW_TP_SRC,
242 ofp.OFPFW_TP_DST
Howard Persh680b92a2012-03-31 13:34:35 -0700243 ]
Howard Pershc7963582012-03-29 10:02:59 -0700244
Howard Persh3340d452012-04-06 16:45:21 -0700245# TBD - Need this because there are duplicates in ofp.ofp_flow_wildcards_map
246# -- FIX
rootf6af1672012-04-06 09:46:29 -0700247all_wildcard_names = {
248 1 : 'OFPFW_IN_PORT',
249 2 : 'OFPFW_DL_VLAN',
250 4 : 'OFPFW_DL_SRC',
251 8 : 'OFPFW_DL_DST',
252 16 : 'OFPFW_DL_TYPE',
253 32 : 'OFPFW_NW_PROTO',
254 64 : 'OFPFW_TP_SRC',
255 128 : 'OFPFW_TP_DST',
256 1048576 : 'OFPFW_DL_VLAN_PCP',
257 2097152 : 'OFPFW_NW_TOS'
258}
259
260
261def wildcard_set(x, w, val):
262 result = x
263 if w == ofp.OFPFW_NW_SRC_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700264 result = (result & ~ofp.OFPFW_NW_SRC_MASK) \
265 | (val << ofp.OFPFW_NW_SRC_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700266 elif w == ofp.OFPFW_NW_DST_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700267 result = (result & ~ofp.OFPFW_NW_DST_MASK) \
268 | (val << ofp.OFPFW_NW_DST_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700269 elif val == 0:
270 result = result & ~w
271 else:
272 result = result | w
273 return result
274
275def wildcard_get(x, w):
276 if w == ofp.OFPFW_NW_SRC_MASK:
277 return (x & ofp.OFPFW_NW_SRC_MASK) >> ofp.OFPFW_NW_SRC_SHIFT
278 if w == ofp.OFPFW_NW_DST_MASK:
279 return (x & ofp.OFPFW_NW_DST_MASK) >> ofp.OFPFW_NW_DST_SHIFT
280 return 1 if (x & w) != 0 else 0
281
Howard Pershc7963582012-03-29 10:02:59 -0700282
Howard Persh680b92a2012-03-31 13:34:35 -0700283all_actions_list = [ofp.OFPAT_OUTPUT,
284 ofp.OFPAT_SET_VLAN_VID,
285 ofp.OFPAT_SET_VLAN_PCP,
286 ofp.OFPAT_STRIP_VLAN,
287 ofp.OFPAT_SET_DL_SRC,
288 ofp.OFPAT_SET_DL_DST,
289 ofp.OFPAT_SET_NW_SRC,
290 ofp.OFPAT_SET_NW_DST,
291 ofp.OFPAT_SET_NW_TOS,
292 ofp.OFPAT_SET_TP_SRC,
293 ofp.OFPAT_SET_TP_DST,
294 ofp.OFPAT_ENQUEUE
295 ]
296
297def dl_addr_to_str(a):
298 return "%x:%x:%x:%x:%x:%x" % tuple(a)
299
300def ip_addr_to_str(a, n):
rootf6af1672012-04-06 09:46:29 -0700301 if n is not None:
302 a = a & ~((1 << (32 - n)) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700303 result = "%d.%d.%d.%d" % (a >> 24, \
304 (a >> 16) & 0xff, \
305 (a >> 8) & 0xff, \
306 a & 0xff \
307 )
308 if n is not None:
309 result = result + ("/%d" % (n))
310 return result
311
Howard Pershc7963582012-03-29 10:02:59 -0700312
rootf6af1672012-04-06 09:46:29 -0700313class Flow_Cfg:
Howard Pershc7963582012-03-29 10:02:59 -0700314 # Members:
315 # - match
316 # - idle_timeout
317 # - hard_timeout
318 # - priority
319 # - action_list
320
321 def __init__(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700322 self.priority = 0
Howard Pershc7963582012-03-29 10:02:59 -0700323 self.match = parse.ofp_match()
324 self.match.wildcards = ofp.OFPFW_ALL
325 self.idle_timeout = 0
326 self.hard_timeout = 0
Howard Pershc7963582012-03-29 10:02:59 -0700327 self.actions = action_list.action_list()
328
rootf6af1672012-04-06 09:46:29 -0700329 # {pri, match} is considered a flow key
330 def key_equal(self, x):
Howard Persh680b92a2012-03-31 13:34:35 -0700331 if self.priority != x.priority:
332 return False
333 # TBD - Should this logic be moved to ofp_match.__eq__()?
334 if self.match.wildcards != x.match.wildcards:
335 return False
rootf6af1672012-04-06 09:46:29 -0700336 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700337 and self.match.in_port != x.match.in_port:
338 return False
rootf6af1672012-04-06 09:46:29 -0700339 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700340 and self.match.dl_dst != x.match.dl_dst:
341 return False
rootf6af1672012-04-06 09:46:29 -0700342 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0 \
343 and self.match.dl_src != x.match.dl_src:
344 return False
345 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700346 and self.match.dl_vlan != x.match.dl_vlan:
347 return False
rootf6af1672012-04-06 09:46:29 -0700348 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700349 and self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
350 return False
rootf6af1672012-04-06 09:46:29 -0700351 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700352 and self.match.dl_type != x.match.dl_type:
353 return False
rootf6af1672012-04-06 09:46:29 -0700354 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700355 and self.match.nw_tos != x.match.nw_tos:
356 return False
rootf6af1672012-04-06 09:46:29 -0700357 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700358 and self.match.nw_proto != x.match.nw_proto:
359 return False
rootf6af1672012-04-06 09:46:29 -0700360 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
361 if n < 32:
362 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700363 if (self.match.nw_src & m) != (x.match.nw_src & m):
364 return False
rootf6af1672012-04-06 09:46:29 -0700365 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
366 if n < 32:
367 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700368 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
369 return False
rootf6af1672012-04-06 09:46:29 -0700370 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0 \
371 and self.match.tp_src != x.match.tp_src:
Howard Persh680b92a2012-03-31 13:34:35 -0700372 return False
rootf6af1672012-04-06 09:46:29 -0700373 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0 \
374 and self.match.tp_dst != x.match.tp_dst:
375 return False
376 return True
377
Howard Persh5f3c83f2012-04-13 09:57:10 -0700378 def actions_equal(self, x):
379 if test_param_get(fq_config, "conservative_ordered_actions", True):
380 # Compare actions lists as unordered
381
root2843d2b2012-04-06 10:27:46 -0700382 aa = copy.deepcopy(x.actions.actions)
383 for a in self.actions.actions:
384 i = 0
385 while i < len(aa):
386 if a == aa[i]:
387 break
388 i = i + 1
389 if i < len(aa):
390 aa.pop(i)
391 else:
392 return False
393 return aa == []
394 else:
395 return self.actions == x.actions
Howard Persh5f3c83f2012-04-13 09:57:10 -0700396
397 def non_key_equal(self, x):
398 if self.cookie != x.cookie:
399 return False
400 if self.idle_timeout != x.idle_timeout:
401 return False
402 if self.hard_timeout != x.hard_timeout:
403 return False
404 return self.actions_equal(x)
rootf6af1672012-04-06 09:46:29 -0700405
root2843d2b2012-04-06 10:27:46 -0700406 def key_str(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700407 result = "priority=%d" % self.priority
408 # TBD - Would be nice if ofp_match.show() was better behaved
409 # (no newlines), and more intuitive (things in hex where approprate), etc.
rootf6af1672012-04-06 09:46:29 -0700410 result = result + (", wildcards=0x%x={" % (self.match.wildcards))
Howard Persh680b92a2012-03-31 13:34:35 -0700411 sep = ""
rootf6af1672012-04-06 09:46:29 -0700412 for w in all_wildcards_list:
413 if (self.match.wildcards & w) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700414 continue
415 if w == ofp.OFPFW_NW_SRC_MASK:
rootf6af1672012-04-06 09:46:29 -0700416 n = wildcard_get(self.match.wildcards, w)
417 if n > 0:
418 result = result + sep + ("OFPFW_NW_SRC(%d)" % (n))
Howard Persh680b92a2012-03-31 13:34:35 -0700419 elif w == ofp.OFPFW_NW_DST_MASK:
rootf6af1672012-04-06 09:46:29 -0700420 n = wildcard_get(self.match.wildcards, w)
421 if n > 0:
422 result = result + sep + ("OFPFW_NW_DST(%d)" % (n))
Howard Persh680b92a2012-03-31 13:34:35 -0700423 else:
rootf6af1672012-04-06 09:46:29 -0700424 result = result + sep + all_wildcard_names[w]
Howard Persh680b92a2012-03-31 13:34:35 -0700425 sep = ", "
426 result = result +"}"
rootf6af1672012-04-06 09:46:29 -0700427 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700428 result = result + (", in_port=%d" % (self.match.in_port))
rootf6af1672012-04-06 09:46:29 -0700429 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700430 result = result + (", dl_dst=%s" \
431 % (dl_addr_to_str(self.match.dl_dst)) \
432 )
rootf6af1672012-04-06 09:46:29 -0700433 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700434 result = result + (", dl_src=%s" \
435 % (dl_addr_to_str(self.match.dl_src)) \
436 )
rootf6af1672012-04-06 09:46:29 -0700437 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700438 result = result + (", dl_vlan=%d" % (self.match.dl_vlan))
rootf6af1672012-04-06 09:46:29 -0700439 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700440 result = result + (", dl_vlan_pcp=%d" % (self.match.dl_vlan_pcp))
rootf6af1672012-04-06 09:46:29 -0700441 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700442 result = result + (", dl_type=0x%x" % (self.match.dl_type))
rootf6af1672012-04-06 09:46:29 -0700443 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700444 result = result + (", nw_tos=0x%x" % (self.match.nw_tos))
rootf6af1672012-04-06 09:46:29 -0700445 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700446 result = result + (", nw_proto=%d" % (self.match.nw_proto))
rootf6af1672012-04-06 09:46:29 -0700447 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700448 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700449 result = result + (", nw_src=%s" % \
450 (ip_addr_to_str(self.match.nw_src, 32 - n)) \
451 )
rootf6af1672012-04-06 09:46:29 -0700452 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700453 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700454 result = result + (", nw_dst=%s" % \
455 (ip_addr_to_str(self.match.nw_dst, 32 - n)) \
456 )
rootf6af1672012-04-06 09:46:29 -0700457 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700458 result = result + (", tp_src=%d" % self.match.tp_src)
rootf6af1672012-04-06 09:46:29 -0700459 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700460 result = result + (", tp_dst=%d" % self.match.tp_dst)
rootf6af1672012-04-06 09:46:29 -0700461 return result
462
463 def __eq__(self, x):
464 return (self.key_equal(x) and self.non_key_equal(x))
465
466 def __str__(self):
root2843d2b2012-04-06 10:27:46 -0700467 result = self.key_str()
468 result = result + (", cookie=%d" % self.cookie)
Howard Persh680b92a2012-03-31 13:34:35 -0700469 result = result + (", idle_timeout=%d" % self.idle_timeout)
470 result = result + (", hard_timeout=%d" % self.hard_timeout)
Howard Persh680b92a2012-03-31 13:34:35 -0700471 for a in self.actions.actions:
472 result = result + (", action=%s" % ofp.ofp_action_type_map[a.type])
473 if a.type == ofp.OFPAT_OUTPUT:
474 result = result + ("(%d)" % (a.port))
475 elif a.type == ofp.OFPAT_SET_VLAN_VID:
476 result = result + ("(%d)" % (a.vlan_vid))
477 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
478 result = result + ("(%d)" % (a.vlan_pcp))
479 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
480 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
481 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
482 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
483 elif a.type == ofp.OFPAT_SET_NW_TOS:
484 result = result + ("(0x%x)" % (a.nw_tos))
485 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
486 result = result + ("(%d)" % (a.tp_port))
487 elif a.type == ofp.OFPAT_ENQUEUE:
488 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
489 return result
Howard Pershc7963582012-03-29 10:02:59 -0700490
Dan Talayco910a8282012-04-07 00:05:20 -0700491 def rand_actions_ordered(self, fi, valid_actions, valid_ports):
Howard Persh3340d452012-04-06 16:45:21 -0700492 # Action lists are ordered, so pick an ordered random subset of
493 # supported actions
Howard Pershc1199d52012-04-11 14:21:32 -0700494
495 actions_force = test_param_get(fq_config, "actions_force", 0)
496
Dan Talayco910a8282012-04-07 00:05:20 -0700497 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh3340d452012-04-06 16:45:21 -0700498 supported_actions = []
499 for a in all_actions_list:
500 if ((1 << a) & valid_actions) != 0:
501 supported_actions.append(a)
502
Howard Pershc1199d52012-04-11 14:21:32 -0700503 actions \
504 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
505
506 for a in all_actions_list:
507 if ((1 << a) & actions_force) != 0:
508 actions.append(a)
509
510 actions = shuffle(actions)
Howard Persh3340d452012-04-06 16:45:21 -0700511
Howard Persh3340d452012-04-06 16:45:21 -0700512 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700513 for a in actions:
Dan Talayco910a8282012-04-07 00:05:20 -0700514 act = None
Howard Persh3340d452012-04-06 16:45:21 -0700515 if a == ofp.OFPAT_OUTPUT:
516 pass # OUTPUT actions must come last
517 elif a == ofp.OFPAT_SET_VLAN_VID:
518 act = action.action_set_vlan_vid()
519 act.vlan_vid = fi.rand_vlan()
Howard Persh3340d452012-04-06 16:45:21 -0700520 elif a == ofp.OFPAT_SET_VLAN_PCP:
521 act = action.action_set_vlan_pcp()
522 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Persh3340d452012-04-06 16:45:21 -0700523 elif a == ofp.OFPAT_STRIP_VLAN:
524 act = action.action_strip_vlan()
Howard Persh3340d452012-04-06 16:45:21 -0700525 elif a == ofp.OFPAT_SET_DL_SRC:
526 act = action.action_set_dl_src()
527 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700528 elif a == ofp.OFPAT_SET_DL_DST:
529 act = action.action_set_dl_dst()
530 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700531 elif a == ofp.OFPAT_SET_NW_SRC:
532 act = action.action_set_nw_src()
533 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700534 elif a == ofp.OFPAT_SET_NW_DST:
535 act = action.action_set_nw_dst()
536 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700537 elif a == ofp.OFPAT_SET_NW_TOS:
538 act = action.action_set_nw_tos()
539 act.nw_tos = fi.rand_ip_tos()
Howard Persh3340d452012-04-06 16:45:21 -0700540 elif a == ofp.OFPAT_SET_TP_SRC:
541 act = action.action_set_tp_src()
542 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700543 elif a == ofp.OFPAT_SET_TP_DST:
544 act = action.action_set_tp_dst()
545 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700546 elif a == ofp.OFPAT_ENQUEUE:
547 pass # Enqueue actions must come last
Dan Talayco910a8282012-04-07 00:05:20 -0700548 if act:
549 act.max_len = ACTION_MAX_LEN
550 self.actions.add(act)
551
Howard Persh3340d452012-04-06 16:45:21 -0700552 p = random.randint(1, 100)
Howard Pershc1199d52012-04-11 14:21:32 -0700553 if (((1 << ofp.OFPAT_ENQUEUE) & actions_force) != 0 or p <= 33) \
554 and ofp.OFPAT_ENQUEUE in actions:
555 # In not forecd, one third of the time, include ENQUEUE actions
556 # at end of list
Howard Persh3340d452012-04-06 16:45:21 -0700557 # At most 1 ENQUEUE action
558 act = action.action_enqueue()
559 act.port = rand_pick(valid_ports)
560 # TBD - Limits for queue number?
561 act.queue_id = random.randint(0, 7)
Dan Talayco910a8282012-04-07 00:05:20 -0700562 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700563 self.actions.add(act)
Howard Pershc1199d52012-04-11 14:21:32 -0700564 if (((1 << ofp.OFPAT_OUTPUT) & actions_force) != 0 \
565 or (p > 33 and p <= 66) \
566 ) \
567 and ofp.OFPAT_OUTPUT in actions:
Howard Persh3340d452012-04-06 16:45:21 -0700568 # One third of the time, include OUTPUT actions at end of list
569 port_idxs = shuffle(range(len(valid_ports)))
570 # Only 1 output action allowed if IN_PORT wildcarded
571 n = 1 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) != 0 \
572 else random.randint(1, len(valid_ports))
573 port_idxs = port_idxs[0 : n]
574 for pi in port_idxs:
575 act = action.action_output()
576 act.port = valid_ports[pi]
Dan Talayco910a8282012-04-07 00:05:20 -0700577 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700578 if act.port != ofp.OFPP_IN_PORT \
579 or wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
580 # OUTPUT(IN_PORT) only valid if OFPFW_IN_PORT not wildcarded
581 self.actions.add(act)
582 else:
583 # One third of the time, include neither
584 pass
585
586
587 # Randomize flow data for flow modifies (i.e. cookie and actions)
rootf6af1672012-04-06 09:46:29 -0700588 def rand_mod(self, fi, valid_actions, valid_ports):
589 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700590
Dan Talayco910a8282012-04-07 00:05:20 -0700591 # By default, test with conservative ordering conventions
592 # This should probably be indicated in a profile
593 if test_param_get(fq_config, "conservative_ordered_actions", True):
594 self.rand_actions_ordered(fi, valid_actions, valid_ports)
Howard Persh3340d452012-04-06 16:45:21 -0700595 return self
596
Howard Pershc1199d52012-04-11 14:21:32 -0700597 actions_force = test_param_get(fq_config, "actions_force", 0)
598
599 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh680b92a2012-03-31 13:34:35 -0700600 supported_actions = []
601 for a in all_actions_list:
602 if ((1 << a) & valid_actions) != 0:
603 supported_actions.append(a)
604
Howard Pershc1199d52012-04-11 14:21:32 -0700605 actions \
606 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
607
608 for a in all_actions_list:
609 if ((1 << a) & actions_force) != 0:
610 actions.append(a)
611
612 actions = shuffle(actions)
Howard Pershc7963582012-03-29 10:02:59 -0700613
614 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700615 for a in actions:
Howard Pershc7963582012-03-29 10:02:59 -0700616 if a == ofp.OFPAT_OUTPUT:
617 # TBD - Output actions are clustered in list, spread them out?
618 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700619 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700620 for pi in port_idxs:
621 act = action.action_output()
Howard Persh680b92a2012-03-31 13:34:35 -0700622 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700623 self.actions.add(act)
624 elif a == ofp.OFPAT_SET_VLAN_VID:
625 act = action.action_set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700626 act.vlan_vid = fi.rand_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700627 self.actions.add(act)
628 elif a == ofp.OFPAT_SET_VLAN_PCP:
Dan Talayco910a8282012-04-07 00:05:20 -0700629 act = action.action_set_vlan_pcp()
630 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700631 elif a == ofp.OFPAT_STRIP_VLAN:
632 act = action.action_strip_vlan()
633 self.actions.add(act)
634 elif a == ofp.OFPAT_SET_DL_SRC:
635 act = action.action_set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700636 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700637 self.actions.add(act)
638 elif a == ofp.OFPAT_SET_DL_DST:
639 act = action.action_set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700640 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700641 self.actions.add(act)
642 elif a == ofp.OFPAT_SET_NW_SRC:
643 act = action.action_set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700644 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700645 self.actions.add(act)
646 elif a == ofp.OFPAT_SET_NW_DST:
647 act = action.action_set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700648 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700649 self.actions.add(act)
650 elif a == ofp.OFPAT_SET_NW_TOS:
651 act = action.action_set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700652 act.nw_tos = fi.rand_ip_tos()
Howard Pershc7963582012-03-29 10:02:59 -0700653 self.actions.add(act)
654 elif a == ofp.OFPAT_SET_TP_SRC:
655 act = action.action_set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700656 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700657 self.actions.add(act)
658 elif a == ofp.OFPAT_SET_TP_DST:
659 act = action.action_set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700660 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700661 self.actions.add(act)
662 elif a == ofp.OFPAT_ENQUEUE:
663 # TBD - Enqueue actions are clustered in list, spread them out?
664 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700665 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700666 for pi in port_idxs:
667 act = action.action_enqueue()
Howard Persh680b92a2012-03-31 13:34:35 -0700668 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700669 # TBD - Limits for queue number?
670 act.queue_id = random.randint(0, 7)
671 self.actions.add(act)
672
673 return self
674
rootf6af1672012-04-06 09:46:29 -0700675 # Randomize flow cfg
676 def rand(self, fi, valid_wildcards, valid_actions, valid_ports):
Howard Pershc1199d52012-04-11 14:21:32 -0700677 wildcards_force = test_param_get(fq_config, "wildcards_force", 0)
678
rootf6af1672012-04-06 09:46:29 -0700679 # Start with no wildcards, i.e. everything specified
680 self.match.wildcards = 0
Howard Pershc1199d52012-04-11 14:21:32 -0700681
682 if wildcards_force != 0:
683 exact = False
684 else:
685 # Make approx. 5% of flows exact
686 exact = (random.randint(1, 100) <= 5)
rootf6af1672012-04-06 09:46:29 -0700687
688 # For each qualifier Q,
689 # if (wildcarding is not supported for Q,
690 # or an exact flow is specified
691 # or a coin toss comes up heads),
692 # specify Q
693 # else
694 # wildcard Q
695
Howard Pershc1199d52012-04-11 14:21:32 -0700696 if wildcard_get(wildcards_force, ofp.OFPFW_IN_PORT) == 0 \
697 and (wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
698 or exact \
699 or flip_coin() \
700 ):
rootf6af1672012-04-06 09:46:29 -0700701 self.match.in_port = rand_pick(valid_ports)
702 else:
Howard Persh3340d452012-04-06 16:45:21 -0700703 self.match.wildcards = wildcard_set(self.match.wildcards, \
704 ofp.OFPFW_IN_PORT, \
705 1 \
706 )
rootf6af1672012-04-06 09:46:29 -0700707
Howard Pershc1199d52012-04-11 14:21:32 -0700708 if wildcard_get(wildcards_force, ofp.OFPFW_DL_DST) == 0 \
709 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
710 or exact \
711 or flip_coin() \
712 ):
rootf6af1672012-04-06 09:46:29 -0700713 self.match.dl_dst = fi.rand_dl_addr()
714 else:
Howard Persh3340d452012-04-06 16:45:21 -0700715 self.match.wildcards = wildcard_set(self.match.wildcards, \
716 ofp.OFPFW_DL_DST, \
717 1 \
718 )
rootf6af1672012-04-06 09:46:29 -0700719
Howard Pershc1199d52012-04-11 14:21:32 -0700720 if wildcard_get(wildcards_force, ofp.OFPFW_DL_SRC) == 0 \
721 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
722 or exact \
723 or flip_coin() \
724 ):
rootf6af1672012-04-06 09:46:29 -0700725 self.match.dl_src = fi.rand_dl_addr()
726 else:
Howard Persh3340d452012-04-06 16:45:21 -0700727 self.match.wildcards = wildcard_set(self.match.wildcards, \
728 ofp.OFPFW_DL_SRC, \
729 1 \
730 )
rootf6af1672012-04-06 09:46:29 -0700731
Howard Pershc1199d52012-04-11 14:21:32 -0700732 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN) == 0 \
733 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
734 or exact \
735 or flip_coin() \
736 ):
rootf6af1672012-04-06 09:46:29 -0700737 self.match.dl_vlan = fi.rand_vlan()
738 else:
Howard Persh3340d452012-04-06 16:45:21 -0700739 self.match.wildcards = wildcard_set(self.match.wildcards, \
740 ofp.OFPFW_DL_VLAN, \
741 1 \
742 )
rootf6af1672012-04-06 09:46:29 -0700743
Howard Pershc1199d52012-04-11 14:21:32 -0700744 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN_PCP) == 0 \
745 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
746 or exact \
747 or flip_coin() \
748 ):
749 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
750 else:
751 self.match.wildcards = wildcard_set(self.match.wildcards, \
752 ofp.OFPFW_DL_VLAN_PCP, \
753 1 \
754 )
755
756 if wildcard_get(wildcards_force, ofp.OFPFW_DL_TYPE) == 0 \
757 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
758 or exact \
759 or flip_coin() \
760 ):
rootf6af1672012-04-06 09:46:29 -0700761 self.match.dl_type = fi.rand_ethertype()
762 else:
Howard Persh3340d452012-04-06 16:45:21 -0700763 self.match.wildcards = wildcard_set(self.match.wildcards, \
764 ofp.OFPFW_DL_TYPE, \
765 1 \
766 )
rootf6af1672012-04-06 09:46:29 -0700767
Howard Pershc1199d52012-04-11 14:21:32 -0700768 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_SRC_MASK)
769 if n == 0:
770 if exact or flip_coin():
771 n = 0
772 else:
773 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
774 if n > 32:
775 n = 32
776 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700777 self.match.wildcards = wildcard_set(self.match.wildcards, \
778 ofp.OFPFW_NW_SRC_MASK, \
779 n \
780 )
rootf6af1672012-04-06 09:46:29 -0700781 if n < 32:
782 self.match.nw_src = fi.rand_ip_addr() & ~((1 << n) - 1)
783 # Specifying any IP address match other than all bits
784 # don't care requires that Ethertype is one of {IP, ARP}
785 if flip_coin():
786 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700787 self.match.wildcards = wildcard_set(self.match.wildcards, \
788 ofp.OFPFW_DL_TYPE, \
789 0 \
790 )
rootf6af1672012-04-06 09:46:29 -0700791
Howard Pershc1199d52012-04-11 14:21:32 -0700792 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_DST_MASK)
793 if n == 0:
794 if exact or flip_coin():
795 n = 0
796 else:
797 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
798 if n > 32:
799 n = 32
800 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700801 self.match.wildcards = wildcard_set(self.match.wildcards, \
802 ofp.OFPFW_NW_DST_MASK, \
803 n \
804 )
rootf6af1672012-04-06 09:46:29 -0700805 if n < 32:
806 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
807 # Specifying any IP address match other than all bits
808 # don't care requires that Ethertype is one of {IP, ARP}
809 if flip_coin():
810 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700811 self.match.wildcards = wildcard_set(self.match.wildcards, \
812 ofp.OFPFW_DL_TYPE, \
813 0 \
814 )
rootf6af1672012-04-06 09:46:29 -0700815
Howard Pershc1199d52012-04-11 14:21:32 -0700816 if wildcard_get(wildcards_force, ofp.OFPFW_NW_TOS) == 0 \
817 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
818 or exact \
819 or flip_coin() \
820 ):
rootf6af1672012-04-06 09:46:29 -0700821 self.match.nw_tos = fi.rand_ip_tos()
822 # Specifying a TOS value requires that Ethertype is IP
823 if flip_coin():
824 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700825 self.match.wildcards = wildcard_set(self.match.wildcards, \
826 ofp.OFPFW_DL_TYPE, \
827 0 \
828 )
rootf6af1672012-04-06 09:46:29 -0700829 else:
Howard Persh3340d452012-04-06 16:45:21 -0700830 self.match.wildcards = wildcard_set(self.match.wildcards, \
831 ofp.OFPFW_NW_TOS, \
832 1 \
833 )
rootf6af1672012-04-06 09:46:29 -0700834
Dan Talayco910a8282012-04-07 00:05:20 -0700835 # Known issue on OVS with specifying nw_proto w/o dl_type as IP
Howard Pershc1199d52012-04-11 14:21:32 -0700836 if wildcard_get(wildcards_force, ofp.OFPFW_NW_PROTO) == 0 \
837 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
838 or exact \
839 or flip_coin() \
840 ):
Dan Talayco910a8282012-04-07 00:05:20 -0700841 self.match.nw_proto = fi.rand_ip_proto()
842 # Specifying an IP protocol requires that Ethertype is IP
843 if flip_coin():
844 self.match.dl_type = 0x0800
845 self.match.wildcards = wildcard_set(self.match.wildcards, \
846 ofp.OFPFW_DL_TYPE, \
847 0 \
848 )
849 else:
Howard Persh3340d452012-04-06 16:45:21 -0700850 self.match.wildcards = wildcard_set(self.match.wildcards, \
851 ofp.OFPFW_NW_PROTO, \
852 1 \
853 )
Dan Talayco910a8282012-04-07 00:05:20 -0700854
Howard Pershc1199d52012-04-11 14:21:32 -0700855 if wildcard_get(wildcards_force, ofp.OFPFW_TP_SRC) == 0 \
856 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
857 or exact\
858 or flip_coin() \
859 ):
rootf6af1672012-04-06 09:46:29 -0700860 self.match.tp_src = fi.rand_l4_port()
861 # Specifying a L4 port requires that IP protcol is
862 # one of {ICMP, TCP, UDP}
863 if flip_coin():
864 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700865 self.match.wildcards = wildcard_set(self.match.wildcards, \
866 ofp.OFPFW_NW_PROTO, \
867 0 \
868 )
rootf6af1672012-04-06 09:46:29 -0700869 # Specifying a L4 port requirues that Ethertype is IP
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 if self.match.nw_proto == 1:
876 self.match.tp_src = self.match.tp_src & 0xff
877 else:
Howard Persh3340d452012-04-06 16:45:21 -0700878 self.match.wildcards = wildcard_set(self.match.wildcards, \
879 ofp.OFPFW_TP_SRC, \
880 1 \
881 )
rootf6af1672012-04-06 09:46:29 -0700882
Howard Pershc1199d52012-04-11 14:21:32 -0700883 if wildcard_get(wildcards_force, ofp.OFPFW_TP_DST) == 0 \
884 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
885 or exact \
886 or flip_coin() \
887 ):
rootf6af1672012-04-06 09:46:29 -0700888 self.match.tp_dst = fi.rand_l4_port()
889 # Specifying a L4 port requires that IP protcol is
890 # one of {ICMP, TCP, UDP}
891 if flip_coin():
892 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700893 self.match.wildcards = wildcard_set(self.match.wildcards, \
894 ofp.OFPFW_NW_PROTO, \
895 0 \
896 )
rootf6af1672012-04-06 09:46:29 -0700897 # Specifying a L4 port requirues that Ethertype is IP
898 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700899 self.match.wildcards = wildcard_set(self.match.wildcards, \
900 ofp.OFPFW_DL_TYPE, \
901 0 \
902 )
rootf6af1672012-04-06 09:46:29 -0700903 if self.match.nw_proto == 1:
904 self.match.tp_dst = self.match.tp_dst & 0xff
905 else:
Howard Persh3340d452012-04-06 16:45:21 -0700906 self.match.wildcards = wildcard_set(self.match.wildcards, \
907 ofp.OFPFW_TP_DST, \
908 1 \
909 )
rootf6af1672012-04-06 09:46:29 -0700910
911 # If nothing is wildcarded, it is an exact flow spec -- some switches
Howard Persh3340d452012-04-06 16:45:21 -0700912 # (Open vSwitch, for one) *require* that exact flow specs
913 # have priority 65535.
914 self.priority = 65535 if self.match.wildcards == 0 \
915 else fi.rand_priority()
rootf6af1672012-04-06 09:46:29 -0700916
917 # N.B. Don't make the timeout too short, else the flow might
918 # disappear before we get a chance to check for it.
919 t = random.randint(0, 65535)
920 self.idle_timeout = 0 if t < 60 else t
921 t = random.randint(0, 65535)
922 self.hard_timeout = 0 if t < 60 else t
923
924 self.rand_mod(fi, valid_actions, valid_ports)
925
926 return self
927
928 # Return flow cfg in canonical form
Howard Persh3340d452012-04-06 16:45:21 -0700929 # - There are dependencies between flow qualifiers, e.g. it only makes
930 # sense to qualify nw_proto if dl_type is qualified to be 0x0800 (IP).
931 # The canonical form of flow match criteria will "wildcard out"
932 # all such cases.
rootf6af1672012-04-06 09:46:29 -0700933 def canonical(self):
934 result = copy.deepcopy(self)
Howard Persh07d99e62012-04-09 15:26:57 -0700935
936 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_VLAN) != 0:
937 result.match.wildcards = wildcard_set(result.match.wildcards, \
938 ofp.OFPFW_DL_VLAN_PCP, \
939 1 \
940 )
941
rootf6af1672012-04-06 09:46:29 -0700942 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
943 or result.match.dl_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700944 # dl_tyoe is wildcarded, or specified as something other
945 # than IP or ARP
Howard Persh07d99e62012-04-09 15:26:57 -0700946 # => nw_src, nw_dst, nw_proto cannot be specified,
947 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700948 result.match.wildcards = wildcard_set(result.match.wildcards, \
949 ofp.OFPFW_NW_SRC_MASK, \
950 32 \
951 )
952 result.match.wildcards = wildcard_set(result.match.wildcards, \
953 ofp.OFPFW_NW_DST_MASK, \
954 32 \
955 )
Howard Persh3340d452012-04-06 16:45:21 -0700956 result.match.wildcards = wildcard_set(result.match.wildcards, \
957 ofp.OFPFW_NW_PROTO, \
958 1 \
959 )
Howard Persh07d99e62012-04-09 15:26:57 -0700960
961 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
962 or result.match.dl_type != 0x0800:
963 # dl_type is wildcarded, or specified as something other than IP
964 # => nw_tos, tp_src and tp_dst cannot be specified,
965 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700966 result.match.wildcards = wildcard_set(result.match.wildcards, \
967 ofp.OFPFW_NW_TOS, \
968 1 \
969 )
970 result.match.wildcards = wildcard_set(result.match.wildcards, \
971 ofp.OFPFW_TP_SRC, \
972 1 \
973 )
974 result.match.wildcards = wildcard_set(result.match.wildcards, \
975 ofp.OFPFW_TP_DST, \
976 1 \
977 )
Howard Persh07d99e62012-04-09 15:26:57 -0700978 result.match.wildcards = wildcard_set(result.match.wildcards, \
979 ofp.OFPFW_NW_SRC_MASK, \
980 32 \
981 )
982 result.match.wildcards = wildcard_set(result.match.wildcards, \
983 ofp.OFPFW_NW_DST_MASK, \
984 32 \
985 )
986 result.match.wildcards = wildcard_set(result.match.wildcards, \
987 ofp.OFPFW_NW_PROTO, \
988 1 \
989 )
990
rootf6af1672012-04-06 09:46:29 -0700991 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
992 or result.match.nw_proto not in [1, 6, 17]:
Howard Persh3340d452012-04-06 16:45:21 -0700993 # nw_proto is wildcarded, or specified as something other than ICMP,
994 # TCP or UDP
rootf6af1672012-04-06 09:46:29 -0700995 # => tp_src and tp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700996 result.match.wildcards = wildcard_set(result.match.wildcards, \
997 ofp.OFPFW_TP_SRC, \
998 1 \
999 )
1000 result.match.wildcards = wildcard_set(result.match.wildcards, \
1001 ofp.OFPFW_TP_DST, \
1002 1 \
1003 )
rootf6af1672012-04-06 09:46:29 -07001004 return result
1005
Howard Persh680b92a2012-03-31 13:34:35 -07001006 # Overlap check
1007 # delf == True <=> Check for delete overlap, else add overlap
1008 # "Add overlap" is defined as there exists a packet that could match both the
1009 # receiver and argument flowspecs
1010 # "Delete overlap" is defined as the specificity of the argument flowspec
1011 # is greater than or equal to the specificity of the receiver flowspec
1012 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -07001013 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
1014 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001015 if self.match.in_port != x.match.in_port:
1016 return False # Both specified, and not equal
1017 elif delf:
1018 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001019 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
1020 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001021 if self.match.dl_vlan != x.match.dl_vlan:
1022 return False # Both specified, and not equal
1023 elif delf:
1024 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001025 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
1026 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001027 if self.match.dl_src != x.match.dl_src:
1028 return False # Both specified, and not equal
1029 elif delf:
1030 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001031 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
1032 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001033 if self.match.dl_dst != x.match.dl_dst:
1034 return False # Both specified, and not equal
1035 elif delf:
1036 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001037 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
1038 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001039 if self.match.dl_type != x.match.dl_type:
1040 return False # Both specified, and not equal
1041 elif delf:
1042 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -07001043 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
1044 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001045 if self.match.nw_proto != x.match.nw_proto:
1046 return False # Both specified, and not equal
1047 elif delf:
1048 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001049 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
1050 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001051 if self.match.tp_src != x.match.tp_src:
1052 return False # Both specified, and not equal
1053 elif delf:
1054 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001055 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
1056 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001057 if self.match.tp_dst != x.match.tp_dst:
1058 return False # Both specified, and not equal
1059 elif delf:
1060 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001061 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
1062 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001063 if delf and na < nb:
1064 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001065 if (na < 32 and nb < 32):
1066 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1067 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -07001068 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -07001069 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
1070 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001071 if delf and na < nb:
1072 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001073 if (na < 32 and nb < 32):
1074 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1075 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
rootf6af1672012-04-06 09:46:29 -07001076 return False # Overlapping bits not equal
1077 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
1078 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001079 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
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_NW_TOS) == 0:
1084 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001085 if self.match.nw_tos != x.match.nw_tos:
1086 return False # Both specified, and not equal
1087 elif delf:
1088 return False # Receiver more specific
1089 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -07001090
1091 def to_flow_mod_msg(self, msg):
1092 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -07001093 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001094 msg.idle_timeout = self.idle_timeout
1095 msg.hard_timeout = self.hard_timeout
1096 msg.priority = self.priority
1097 msg.actions = self.actions
1098 return msg
1099
1100 def from_flow_stat(self, msg):
1101 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -07001102 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001103 self.idle_timeout = msg.idle_timeout
1104 self.hard_timeout = msg.hard_timeout
1105 self.priority = msg.priority
1106 self.actions = msg.actions
1107
rootf6af1672012-04-06 09:46:29 -07001108 def from_flow_rem(self, msg):
1109 self.match = msg.match
1110 self.idle_timeout = msg.idle_timeout
1111 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -07001112
Howard Pershc7963582012-03-29 10:02:59 -07001113
rootf6af1672012-04-06 09:46:29 -07001114class Flow_Tbl:
1115 def clear(self):
1116 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001117
rootf6af1672012-04-06 09:46:29 -07001118 def __init__(self):
1119 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001120
rootf6af1672012-04-06 09:46:29 -07001121 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001122 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001123
1124 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001125 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001126
1127 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001128 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001129
1130 def values(self):
1131 return self.dict.values()
1132
1133 def count(self):
1134 return len(self.dict)
1135
1136 def rand(self, sw, fi, num_flows):
1137 self.clear()
1138 i = 0
1139 tbl = 0
1140 j = 0
1141 while i < num_flows:
1142 fc = Flow_Cfg()
1143 fc.rand(fi, \
1144 sw.tbl_stats.stats[tbl].wildcards, \
1145 sw.sw_features.actions, \
1146 sw.valid_ports \
1147 )
1148 fc = fc.canonical()
1149 if self.find(fc):
1150 continue
1151 fc.send_rem = False
1152 self.insert(fc)
1153 i = i + 1
1154 j = j + 1
1155 if j >= sw.tbl_stats.stats[tbl].max_entries:
1156 tbl = tbl + 1
1157 j = 0
1158
1159
Howard Persh3340d452012-04-06 16:45:21 -07001160error_msgs = []
1161removed_msgs = []
1162
1163def error_handler(self, msg, rawmsg):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001164 fq_logger.info("Got an ERROR message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001165 % (msg.type, msg.code) \
1166 )
Howard Persh5f3c83f2012-04-13 09:57:10 -07001167 fq_logger.info("Message header:")
1168 fq_logger.info(msg.header.show())
Howard Persh3340d452012-04-06 16:45:21 -07001169 global error_msgs
1170 error_msgs.append(msg)
1171 pass
1172
1173def removed_handler(self, msg, rawmsg):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001174 fq_logger.info("Got a REMOVED message")
1175 fq_logger.info("Message header:")
1176 fq_logger.info(msg.header.show())
Howard Persh3340d452012-04-06 16:45:21 -07001177 global removed_msgs
1178 removed_msgs.append(msg)
1179 pass
1180
rootf6af1672012-04-06 09:46:29 -07001181class Switch:
1182 # Members:
1183 # controller - switch's test controller
1184 # sw_features - switch's OFPT_FEATURES_REPLY message
1185 # valid_ports - list of valid port numbers
1186 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1187 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1188 # flow_tbl - (test's idea of) switch's flow table
1189
1190 def __init__(self):
1191 self.controller = None
1192 self.sw_features = None
1193 self.valid_ports = []
1194 self.tbl_stats = None
1195 self.flow_stats = None
1196 self.flow_tbl = Flow_Tbl()
1197
Howard Persh3340d452012-04-06 16:45:21 -07001198 def controller_set(self, controller):
1199 self.controller = controller
1200 # Register error message handler
1201 global error_msgs
1202 error_msgs = []
1203 controller.register(ofp.OFPT_ERROR, error_handler)
1204 controller.register(ofp.OFPT_FLOW_REMOVED, removed_handler)
1205
rootf6af1672012-04-06 09:46:29 -07001206 def features_get(self):
1207 # Get switch features
1208 request = message.features_request()
1209 (self.sw_features, pkt) = self.controller.transact(request, timeout=2)
1210 if self.sw_features is None:
1211 return False
1212 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Howard Persh3340d452012-04-06 16:45:21 -07001213 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1214 # is that universal?
1215
1216 # TBD - There seems to be variability in which switches support which
1217 # ports; need to sort that out
1218 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1219# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1220# ofp.OFPP_NORMAL, \
1221# ofp.OFPP_FLOOD, \
1222# ofp.OFPP_ALL, \
1223# ofp.OFPP_CONTROLLER \
1224# ] \
1225# )
Howard Persh07d99e62012-04-09 15:26:57 -07001226 actions_override = test_param_get(fq_config, "actions", -1)
1227 if actions_override != -1:
1228 self.sw_features.actions = actions_override
Howard Pershc1199d52012-04-11 14:21:32 -07001229 ports_override = test_param_get(fq_config, "ports", [])
1230 if ports_override != []:
1231 self.valid_ports = ports_override
Howard Persh07d99e62012-04-09 15:26:57 -07001232
rootf6af1672012-04-06 09:46:29 -07001233 return True
1234
1235 def tbl_stats_get(self):
1236 # Get table stats
Howard Persh680b92a2012-03-31 13:34:35 -07001237 request = message.table_stats_request()
rootf6af1672012-04-06 09:46:29 -07001238 (self.tbl_stats, pkt) = self.controller.transact(request, timeout=2)
Howard Persh07d99e62012-04-09 15:26:57 -07001239 if self.tbl_stats is None:
1240 return False
1241 for ts in self.tbl_stats.stats:
1242 wildcards_override = test_param_get(fq_config, "wildcards", -1)
1243 if wildcards_override != -1:
1244 ts.wildcards = wildcards_override
1245 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001246
Howard Pershc1199d52012-04-11 14:21:32 -07001247 def flow_stats_get(self, limit = 10000):
rootf6af1672012-04-06 09:46:29 -07001248 request = message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -07001249 query_match = ofp.ofp_match()
1250 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001251 request.match = query_match
1252 request.table_id = 0xff
1253 request.out_port = ofp.OFPP_NONE;
Howard Persh3340d452012-04-06 16:45:21 -07001254 if self.controller.message_send(request) == -1:
1255 return False
1256 # <TBD>
1257 # Glue together successive reponse messages for stats reply.
1258 # Looking at the "more" flag and performing re-assembly
1259 # should be a part of the infrastructure.
1260 # </TBD>
1261 n = 0
1262 while True:
Howard Persh07d99e62012-04-09 15:26:57 -07001263 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY, 4)
Howard Persh3340d452012-04-06 16:45:21 -07001264 if resp is None:
Howard Pershc1199d52012-04-11 14:21:32 -07001265 return False # Did not get expected response
Howard Persh3340d452012-04-06 16:45:21 -07001266 if n == 0:
1267 self.flow_stats = resp
1268 else:
1269 self.flow_stats.stats.extend(resp.stats)
1270 n = n + 1
Howard Pershc1199d52012-04-11 14:21:32 -07001271 if len(self.flow_stats.stats) > limit:
1272 fq_logger.error("Too many flows returned")
1273 return False
1274 if (resp.flags & 1) == 0:
1275 break # No more responses expected
Howard Persh3340d452012-04-06 16:45:21 -07001276 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001277
rootf6af1672012-04-06 09:46:29 -07001278 def flow_add(self, flow_cfg, overlapf = False):
Howard Persh680b92a2012-03-31 13:34:35 -07001279 flow_mod_msg = message.flow_mod()
1280 flow_mod_msg.command = ofp.OFPFC_ADD
1281 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001282 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001283 if overlapf:
1284 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001285 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001286 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Howard Persh07d99e62012-04-09 15:26:57 -07001287 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001288 fq_logger.info("Sending flow_mod(add), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001289 % (flow_mod_msg.header.xid)
1290 )
rootf6af1672012-04-06 09:46:29 -07001291 return (self.controller.message_send(flow_mod_msg) != -1)
Howard Persh680b92a2012-03-31 13:34:35 -07001292
rootf6af1672012-04-06 09:46:29 -07001293 def flow_mod(self, flow_cfg, strictf):
Howard Persh680b92a2012-03-31 13:34:35 -07001294 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001295 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf \
1296 else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -07001297 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001298 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001299 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001300 fq_logger.info("Sending flow_mod(mod), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001301 % (flow_mod_msg.header.xid)
1302 )
rootf6af1672012-04-06 09:46:29 -07001303 return (self.controller.message_send(flow_mod_msg) != -1)
1304
1305 def flow_del(self, flow_cfg, strictf):
1306 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001307 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf \
1308 else ofp.OFPFC_DELETE
rootf6af1672012-04-06 09:46:29 -07001309 flow_mod_msg.buffer_id = 0xffffffff
1310 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001311 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001312 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001313 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001314 fq_logger.info("Sending flow_mod(del), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001315 % (flow_mod_msg.header.xid)
1316 )
rootf6af1672012-04-06 09:46:29 -07001317 return (self.controller.message_send(flow_mod_msg) != -1)
1318
1319 def barrier(self):
1320 barrier = message.barrier_request()
Howard Persh07d99e62012-04-09 15:26:57 -07001321 (resp, pkt) = self.controller.transact(barrier, 20)
rootf6af1672012-04-06 09:46:29 -07001322 return (resp is not None)
1323
Howard Persh3340d452012-04-06 16:45:21 -07001324 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001325 result = True
Howard Persh3340d452012-04-06 16:45:21 -07001326 global error_msgs
Howard Persh5f3c83f2012-04-13 09:57:10 -07001327 fq_logger.info("Expecting %d error messages" % (num_exp))
Howard Persh3340d452012-04-06 16:45:21 -07001328 num_got = len(error_msgs)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001329 fq_logger.info("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001330 if num_got != num_exp:
Dan Talayco910a8282012-04-07 00:05:20 -07001331 fq_logger.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001332 result = False
1333 if num_exp == 0:
1334 return result
1335 elif num_exp == 1:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001336 fq_logger.info("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001337 % (type, code) \
1338 )
1339 f = False
1340 for e in error_msgs:
1341 if e.type == type and e.code == code:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001342 fq_logger.info("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001343 f = True
1344 if not f:
Dan Talayco910a8282012-04-07 00:05:20 -07001345 fq_logger.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001346 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001347 else:
Dan Talayco910a8282012-04-07 00:05:20 -07001348 fq_logger.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001349 result = False
1350 return result
1351
Howard Persh3340d452012-04-06 16:45:21 -07001352 def removed_verify(self, num_exp):
1353 result = True
1354 global removed_msgs
Howard Persh5f3c83f2012-04-13 09:57:10 -07001355 fq_logger.info("Expecting %d removed messages" % (num_exp))
Howard Persh3340d452012-04-06 16:45:21 -07001356 num_got = len(removed_msgs)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001357 fq_logger.info("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001358 if num_got != num_exp:
Dan Talayco910a8282012-04-07 00:05:20 -07001359 fq_logger.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001360 result = False
1361 if num_exp < 2:
1362 return result
Dan Talayco910a8282012-04-07 00:05:20 -07001363 fq_logger.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001364 return False
1365
Howard Persh5f3c83f2012-04-13 09:57:10 -07001366 # modf == True <=> Verify for flow modify, else for add/delete
1367 def flow_tbl_verify(self, modf = False):
rootf6af1672012-04-06 09:46:29 -07001368 result = True
1369
1370 # Verify flow count in switch
Howard Persh5f3c83f2012-04-13 09:57:10 -07001371 fq_logger.info("Reading table stats")
1372 fq_logger.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001373 if not self.tbl_stats_get():
Dan Talayco910a8282012-04-07 00:05:20 -07001374 fq_logger.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001375 return False
1376 n = 0
1377 for ts in self.tbl_stats.stats:
1378 n = n + ts.active_count
Howard Persh5f3c83f2012-04-13 09:57:10 -07001379 fq_logger.info("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001380 % (n) \
1381 )
1382 if n != self.flow_tbl.count():
Dan Talayco910a8282012-04-07 00:05:20 -07001383 fq_logger.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001384 result = False
1385
1386 # Read flows from switch
Howard Persh5f3c83f2012-04-13 09:57:10 -07001387 fq_logger.info("Retrieving flows from switch")
1388 fq_logger.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001389 if not self.flow_stats_get():
Dan Talayco910a8282012-04-07 00:05:20 -07001390 fq_logger.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001391 return False
Howard Persh5f3c83f2012-04-13 09:57:10 -07001392 fq_logger.info("Retrieved %d flows" % (len(self.flow_stats.stats)))
rootf6af1672012-04-06 09:46:29 -07001393
1394 # Verify flows returned by switch
1395
1396 if len(self.flow_stats.stats) != self.flow_tbl.count():
Dan Talayco910a8282012-04-07 00:05:20 -07001397 fq_logger.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001398 result = False
1399
Howard Persh5f3c83f2012-04-13 09:57:10 -07001400 fq_logger.info("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001401 for fc in self.flow_tbl.values():
1402 fc.matched = False
1403 for fs in self.flow_stats.stats:
1404 flow_in = Flow_Cfg()
1405 flow_in.from_flow_stat(fs)
Howard Persh5f3c83f2012-04-13 09:57:10 -07001406 fq_logger.info("Received flow:")
1407 fq_logger.info(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001408 fc = self.flow_tbl.find(flow_in)
1409 if fc is None:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001410 fq_logger.error("Received flow:")
1411 fq_logger.error(str(flow_in))
Dan Talayco910a8282012-04-07 00:05:20 -07001412 fq_logger.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001413 result = False
1414 elif fc.matched:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001415 fq_logger.error("Received flow:")
1416 fq_logger.error(str(flow_in))
Dan Talayco910a8282012-04-07 00:05:20 -07001417 fq_logger.error("re-matches defined flow:")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001418 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001419 result = False
1420 else:
Howard Persh5f3c83f2012-04-13 09:57:10 -07001421 fq_logger.info("matched")
1422 if modf:
1423 # Check for modify
1424
1425 if flow_in.cookie != fc.cookie:
1426 fq_logger.warning("Defined flow:")
1427 fq_logger.warning(str(fc))
1428 fq_logger.warning("Received flow:")
1429 fq_logger.warning(str(flow_in))
1430 fq_logger.warning("cookies do not match")
1431 if not flow_in.actions_equal(fc):
1432 fq_logger.error("Defined flow:")
1433 fq_logger.error(str(fc))
1434 fq_logger.error("Received flow:")
1435 fq_logger.error(str(flow_in))
1436 fq_logger.error("actions do not match")
1437 else:
1438 # Check for add/delete
1439
1440 if not flow_in == fc:
1441 fq_logger.error("Defined flow:")
1442 fq_logger.error(str(fc))
1443 fq_logger.error("Received flow:")
1444 fq_logger.error(str(flow_in))
1445 fq_logger.error("non-key portions of flow do not match")
1446 result = False
rootf6af1672012-04-06 09:46:29 -07001447 fc.matched = True
1448 for fc in self.flow_tbl.values():
1449 if not fc.matched:
Dan Talayco910a8282012-04-07 00:05:20 -07001450 fq_logger.error("Defined flow:")
1451 fq_logger.error(str(fc))
1452 fq_logger.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001453 result = False
1454
1455 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001456
Howard Persh07d99e62012-04-09 15:26:57 -07001457# FLOW ADD 5
1458#
1459# OVERVIEW
1460# Add flows to switch, read back and verify flow configurations
1461#
1462# PURPOSE
1463# - Test acceptance of flow adds
1464# - Test ability of switch to process additions to flow table in random
1465# priority order
1466# - Test correctness of flow configuration responses
1467#
1468# PARAMETERS
1469#
1470# Name: num_flows
1471# Type: number
1472# Description:
1473# Number of flows to define; 0 => maximum number of flows, as determined
1474# from switch capabilities
1475# Default: 100
1476#
1477# PROCESS
1478# 1. Delete all flows from switch
1479# 2. Generate <num_flows> distinct flow configurations
1480# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1481# 4. Verify that no OFPT_ERROR responses were generated by switch
1482# 5. Retrieve flow stats from switch
1483# 6. Compare flow configurations returned by switch
1484# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1485# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001486
rootf6af1672012-04-06 09:46:29 -07001487class Flow_Add_5(basic.SimpleProtocol):
1488 """
1489 Test FLOW_ADD_5 from draft top-half test plan
1490
1491 INPUTS
1492 num_flows - Number of flows to generate
1493 """
Howard Persh680b92a2012-03-31 13:34:35 -07001494
rootf6af1672012-04-06 09:46:29 -07001495 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001496 fq_logger.info("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001497
Dan Talayco910a8282012-04-07 00:05:20 -07001498 num_flows = test_param_get(fq_config, "num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001499
Howard Pershc7963582012-03-29 10:02:59 -07001500 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001501
Howard Persh5f3c83f2012-04-13 09:57:10 -07001502 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001503 rc = delete_all_flows(self.controller, fq_logger)
Howard Pershc7963582012-03-29 10:02:59 -07001504 self.assertEqual(rc, 0, "Failed to delete all flows")
1505
rootf6af1672012-04-06 09:46:29 -07001506 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001507
Howard Persh5f3c83f2012-04-13 09:57:10 -07001508 fq_logger.info("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001509 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001510 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001511 self.assertTrue(sw.features_get(), "Get switch features failed")
1512 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
Howard Pershc7963582012-03-29 10:02:59 -07001513
rootf6af1672012-04-06 09:46:29 -07001514 if num_flows == 0:
1515 # Number of flows requested was 0
1516 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001517
rootf6af1672012-04-06 09:46:29 -07001518 for ts in sw.tbl_stats.stats:
1519 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001520
Howard Persh5f3c83f2012-04-13 09:57:10 -07001521 fq_logger.info("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001522
1523 # Dream up some flow information, i.e. space to chose from for
1524 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001525
rootf6af1672012-04-06 09:46:29 -07001526 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001527 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001528
rootf6af1672012-04-06 09:46:29 -07001529 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001530
rootf6af1672012-04-06 09:46:29 -07001531 ft = Flow_Tbl()
1532 ft.rand(sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001533
rootf6af1672012-04-06 09:46:29 -07001534 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001535
Howard Persh5f3c83f2012-04-13 09:57:10 -07001536 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001537 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07001538 fq_logger.info("Adding flow:")
1539 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001540 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001541
rootf6af1672012-04-06 09:46:29 -07001542 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001543
rootf6af1672012-04-06 09:46:29 -07001544 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001545
rootf6af1672012-04-06 09:46:29 -07001546 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001547
rootf6af1672012-04-06 09:46:29 -07001548 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001549
rootf6af1672012-04-06 09:46:29 -07001550 if not sw.errors_verify(0):
1551 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001552
rootf6af1672012-04-06 09:46:29 -07001553 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001554
rootf6af1672012-04-06 09:46:29 -07001555 sw.flow_tbl = ft
1556 if not sw.flow_tbl_verify():
1557 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001558
rootf6af1672012-04-06 09:46:29 -07001559 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001560 fq_logger.info("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001561
Howard Pershc7963582012-03-29 10:02:59 -07001562
Howard Persh07d99e62012-04-09 15:26:57 -07001563# FLOW ADD 5_1
1564#
1565# OVERVIEW
1566# Verify handling of non-canonical flows
1567#
1568# PURPOSE
1569# - Test that switch detects and correctly responds to a non-canonical flow
1570# definition. A canonical flow is one that satisfies all match qualifier
1571# dependencies; a non-canonical flow is one that does not.
1572#
1573# PARAMETERS
1574# - None
1575#
1576# PROCESS
1577# 1. Delete all flows from switch
1578# 2. Generate 1 flow definition, which is different from its canonicalization
1579# 3. Send flow to switch
1580# 4. Retrieve flow from switch
1581# 5. Compare returned flow to canonical form of defined flow
1582# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1583
1584# Disabled.
1585# Should be DUT dependent.
1586test_prio["Flow_Add_5_1"] = -1
1587
rootf6af1672012-04-06 09:46:29 -07001588class Flow_Add_5_1(basic.SimpleProtocol):
1589 """
1590 Test FLOW_ADD_5.1 from draft top-half test plan
1591
1592 INPUTS
1593 None
1594 """
1595
1596 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001597 fq_logger.info("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001598
Dan Talayco910a8282012-04-07 00:05:20 -07001599 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001600
1601 # Clear all flows from switch
1602
Howard Persh5f3c83f2012-04-13 09:57:10 -07001603 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001604 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001605 self.assertEqual(rc, 0, "Failed to delete all flows")
1606
1607 # Get switch capabilites
1608
Howard Persh5f3c83f2012-04-13 09:57:10 -07001609 fq_logger.info("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001610 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001611 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001612 self.assertTrue(sw.features_get(), "Get switch features failed")
1613 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1614
1615 # Dream up some flow information, i.e. space to chose from for
1616 # random flow parameter generation
1617
1618 fi = Flow_Info()
1619 fi.rand(10)
1620
1621 # Dream up a flow config that will be canonicalized by the switch
1622
1623 while True:
1624 fc = Flow_Cfg()
1625 fc.rand(fi, \
1626 sw.tbl_stats.stats[0].wildcards, \
1627 sw.sw_features.actions, \
1628 sw.valid_ports \
1629 )
1630 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001631 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001632 break
1633
1634 ft = Flow_Tbl()
1635 ft.insert(fcc)
1636
1637 # Send it to the switch
1638
Howard Persh5f3c83f2012-04-13 09:57:10 -07001639 fq_logger.info("Sending flow add to switch:")
1640 fq_logger.info(str(fc))
1641 fq_logger.info("should be canonicalized as:")
1642 fq_logger.info(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001643 fc.send_rem = False
1644 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1645
1646 # Do barrier, to make sure all flows are in
1647
1648 self.assertTrue(sw.barrier(), "Barrier failed")
1649
1650 result = True
1651
1652 # Check for any error messages
1653
1654 if not sw.errors_verify(0):
1655 result = False
1656
1657 # Verify flow table
1658
1659 sw.flow_tbl = ft
1660 if not sw.flow_tbl_verify():
1661 result = False
1662
1663 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001664 fq_logger.info("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001665
1666
Howard Persh07d99e62012-04-09 15:26:57 -07001667# FLOW ADD 6
1668#
1669# OVERVIEW
1670# Test flow table capacity
1671#
1672# PURPOSE
1673# - Test switch can accept as many flow definitions as it claims
1674# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1675# - Test that attempting to create flows beyond capacity does not corrupt
1676# flow table
1677#
1678# PARAMETERS
1679# None
1680#
1681# PROCESS
1682# 1. Delete all flows from switch
1683# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1684# to determine flow table size, N
1685# 3. Generate (N + 1) distinct flow configurations
1686# 4. Send N flow adds to switch, for flows generated in step 3 above
1687# 5. Verify flow table in switch
1688# 6. Send one more flow add to switch
1689# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1690# response was generated by switch, for last flow mod sent
1691# 7. Retrieve flow stats from switch
1692# 8. Verify flow table in switch
1693# 9. Test PASSED iff:
1694# - error message received, for correct flow
1695# - last flow definition sent to switch is not in flow table
1696# else test FAILED
1697
Howard Persh3340d452012-04-06 16:45:21 -07001698# Disabled because of bogus capacity reported by OVS.
1699# Should be DUT dependent.
1700test_prio["Flow_Add_6"] = -1
1701
rootf6af1672012-04-06 09:46:29 -07001702class Flow_Add_6(basic.SimpleProtocol):
1703 """
1704 Test FLOW_ADD_6 from draft top-half test plan
1705
1706 INPUTS
1707 num_flows - Number of flows to generate
1708 """
Howard Pershc7963582012-03-29 10:02:59 -07001709
1710 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001711 fq_logger.info("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001712
rootf6af1672012-04-06 09:46:29 -07001713 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001714
Howard Persh5f3c83f2012-04-13 09:57:10 -07001715 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001716 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001717 self.assertEqual(rc, 0, "Failed to delete all flows")
1718
1719 # Get switch capabilites
1720
Howard Persh5f3c83f2012-04-13 09:57:10 -07001721 fq_logger.info("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001722 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001723 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001724 self.assertTrue(sw.features_get(), "Get switch features failed")
1725 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1726
root2843d2b2012-04-06 10:27:46 -07001727 num_flows = 0
rootf6af1672012-04-06 09:46:29 -07001728 for ts in sw.tbl_stats.stats:
1729 num_flows = num_flows + ts.max_entries
1730
Howard Persh5f3c83f2012-04-13 09:57:10 -07001731 fq_logger.info("Switch capacity is %d flows" % (num_flows))
1732 fq_logger.info("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001733
1734 # Dream up some flow information, i.e. space to chose from for
1735 # random flow parameter generation
1736
1737 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001738 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001739
1740 # Create a flow table, to switch's capacity
1741
1742 ft = Flow_Tbl()
1743 ft.rand(sw, fi, num_flows)
1744
1745 # Send flow table to switch
1746
Howard Persh5f3c83f2012-04-13 09:57:10 -07001747 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001748 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07001749 fq_logger.info("Adding flow:")
1750 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001751 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
1759 # Check for any error messages
1760
1761 if not sw.errors_verify(0):
1762 result = False
1763
1764 # Dream up one more flow
1765
Howard Persh5f3c83f2012-04-13 09:57:10 -07001766 fq_logger.info("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001767 while True:
1768 fc = Flow_Cfg()
1769 fc.rand(fi, \
Howard Persh07d99e62012-04-09 15:26:57 -07001770 sw.tbl_stats.stats[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001771 sw.sw_features.actions, \
1772 sw.valid_ports \
1773 )
1774 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001775 if not ft.find(fc):
1776 break
rootf6af1672012-04-06 09:46:29 -07001777
1778 # Send one-more flow
1779
1780 fc.send_rem = False
Howard Persh5f3c83f2012-04-13 09:57:10 -07001781 fq_logger.info("Sending flow add switch")
1782 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001783 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1784
1785 # Do barrier, to make sure all flows are in
1786
1787 self.assertTrue(sw.barrier(), "Barrier failed")
1788
1789 # Check for expected error message
1790
1791 if not sw.errors_verify(1, \
1792 ofp.OFPET_FLOW_MOD_FAILED, \
1793 ofp.OFPFMFC_ALL_TABLES_FULL \
1794 ):
1795 result = False
1796
1797 # Verify flow table
1798
1799 sw.flow_tbl = ft
1800 if not sw.flow_tbl_verify():
1801 result = False
1802
1803 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001804 fq_logger.info("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001805
1806
Howard Persh07d99e62012-04-09 15:26:57 -07001807# FLOW ADD 7
1808#
1809# OVERVIEW
1810# Test flow redefinition
1811#
1812# PURPOSE
1813# Verify that successive flow adds with same priority and match criteria
1814# overwrite in flow table
1815#
1816# PARAMETERS
1817# None
1818#
1819# PROCESS
1820# 1. Delete all flows from switch
1821# 2. Generate flow definition F1
1822# 3. Generate flow definition F2, with same key (priority and match) as F1,
1823# but with different actions
1824# 4. Send flow adds for F1 and F2 to switch
1825# 5. Verify flow definitions in switch
1826# 6. Test PASSED iff 1 flow returned by switch, matching configuration of F2;
1827# else test FAILED
1828
rootf6af1672012-04-06 09:46:29 -07001829class Flow_Add_7(basic.SimpleProtocol):
1830 """
1831 Test FLOW_ADD_7 from draft top-half test plan
1832
1833 INPUTS
1834 None
1835 """
1836
1837 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001838 fq_logger.info("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001839
1840 # Clear all flows from switch
1841
Howard Persh5f3c83f2012-04-13 09:57:10 -07001842 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001843 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001844 self.assertEqual(rc, 0, "Failed to delete all flows")
1845
1846 # Get switch capabilites
1847
Howard Persh5f3c83f2012-04-13 09:57:10 -07001848 fq_logger.info("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001849 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001850 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001851 self.assertTrue(sw.features_get(), "Get switch features failed")
1852 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1853
1854 # Dream up some flow information, i.e. space to chose from for
1855 # random flow parameter generation
1856
1857 fi = Flow_Info()
1858 fi.rand(10)
1859
1860 # Dream up a flow config
1861
1862 fc = Flow_Cfg()
1863 fc.rand(fi, \
1864 sw.tbl_stats.stats[0].wildcards, \
1865 sw.sw_features.actions, \
1866 sw.valid_ports \
1867 )
1868 fc = fc.canonical()
1869
1870 # Send it to the switch
1871
Howard Persh5f3c83f2012-04-13 09:57:10 -07001872 fq_logger.info("Sending flow add to switch:")
1873 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001874 ft = Flow_Tbl()
1875 fc.send_rem = False
1876 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1877 ft.insert(fc)
1878
1879 # Dream up some different actions, with the same flow key
1880
1881 fc2 = copy.deepcopy(fc)
1882 while True:
1883 fc2.rand_mod(fi, \
1884 sw.sw_features.actions, \
1885 sw.valid_ports \
1886 )
1887 if fc2 != fc:
1888 break
1889
1890 # Send that to the switch
1891
Howard Persh5f3c83f2012-04-13 09:57:10 -07001892 fq_logger.info("Sending flow add to switch:")
1893 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07001894 fc2.send_rem = False
1895 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
1896 ft.insert(fc2)
1897
1898 # Do barrier, to make sure all flows are in
1899
1900 self.assertTrue(sw.barrier(), "Barrier failed")
1901
1902 result = True
1903
1904 # Check for any error messages
1905
1906 if not sw.errors_verify(0):
1907 result = False
1908
1909 # Verify flow table
1910
1911 sw.flow_tbl = ft
1912 if not sw.flow_tbl_verify():
1913 result = False
1914
1915 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001916 fq_logger.info("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001917
1918
Howard Persh07d99e62012-04-09 15:26:57 -07001919# FLOW ADD 8
1920#
1921# OVERVIEW
1922# Add overlapping flows to switch, verify that overlapping flows are rejected
1923#
1924# PURPOSE
1925# - Test detection of overlapping flows by switch
1926# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
1927# - Test rejection of overlapping flows
1928# - Test defining overlapping flows does not corrupt flow table
1929#
1930# PARAMETERS
1931# None
1932#
1933# PROCESS
1934# 1. Delete all flows from switch
1935# 2. Generate flow definition F1
1936# 3. Generate flow definition F2, with key overlapping F1
1937# 4. Send flow add to switch, for F1
1938# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
1939# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
1940# was generated by switch
1941# 7. Verifiy flows configured in swtich
1942# 8. Test PASSED iff:
1943# - error message received, for overlapping flow
1944# - overlapping flow is not in flow table
1945# else test FAILED
1946
rootf6af1672012-04-06 09:46:29 -07001947class Flow_Add_8(basic.SimpleProtocol):
1948 """
1949 Test FLOW_ADD_8 from draft top-half test plan
1950
1951 INPUTS
1952 None
1953 """
1954
1955 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07001956 fq_logger.info("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001957
1958 # Clear all flows from switch
1959
Howard Persh5f3c83f2012-04-13 09:57:10 -07001960 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07001961 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001962 self.assertEqual(rc, 0, "Failed to delete all flows")
1963
1964 # Get switch capabilites
1965
Howard Persh5f3c83f2012-04-13 09:57:10 -07001966 fq_logger.info("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001967 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001968 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001969 self.assertTrue(sw.features_get(), "Get switch features failed")
1970 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1971
1972 # Dream up some flow information, i.e. space to chose from for
1973 # random flow parameter generation
1974
1975 fi = Flow_Info()
1976 fi.rand(10)
1977
1978 # Dream up a flow config, with at least 1 qualifier specified
1979
1980 fc = Flow_Cfg()
1981 while True:
1982 fc.rand(fi, \
1983 sw.tbl_stats.stats[0].wildcards, \
1984 sw.sw_features.actions, \
1985 sw.valid_ports \
1986 )
1987 fc = fc.canonical()
1988 if fc.match.wildcards != ofp.OFPFW_ALL:
1989 break
1990
1991 # Send it to the switch
1992
Howard Persh5f3c83f2012-04-13 09:57:10 -07001993 fq_logger.info("Sending flow add to switch:")
1994 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001995 ft = Flow_Tbl()
1996 fc.send_rem = False
1997 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1998 ft.insert(fc)
1999
2000 # Wildcard out one qualifier that was specified, to create an
2001 # overlapping flow
2002
2003 fc2 = copy.deepcopy(fc)
2004 for wi in shuffle(range(len(all_wildcards_list))):
2005 w = all_wildcards_list[wi]
2006 if (fc2.match.wildcards & w) == 0:
2007 break
2008 if w == ofp.OFPFW_NW_SRC_MASK:
2009 w = ofp.OFPFW_NW_SRC_ALL
2010 wn = "OFPFW_NW_SRC"
2011 elif w == ofp.OFPFW_NW_DST_MASK:
2012 w = ofp.OFPFW_NW_DST_ALL
2013 wn = "OFPFW_NW_DST"
2014 else:
2015 wn = all_wildcard_names[w]
Howard Persh5f3c83f2012-04-13 09:57:10 -07002016 fq_logger.info("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07002017 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07002018 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07002019
2020 # Send that to the switch, with overlap checking
2021
Howard Persh5f3c83f2012-04-13 09:57:10 -07002022 fq_logger.info("Sending flow add to switch:")
2023 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002024 fc2.send_rem = False
2025 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
2026
2027 # Do barrier, to make sure all flows are in
2028 self.assertTrue(sw.barrier(), "Barrier failed")
2029
2030 result = True
2031
2032 # Check for expected error message
2033
2034 if not sw.errors_verify(1, \
2035 ofp.OFPET_FLOW_MOD_FAILED, \
2036 ofp.OFPFMFC_OVERLAP \
2037 ):
2038 result = False
2039
2040 # Verify flow table
2041
2042 sw.flow_tbl = ft
2043 if not sw.flow_tbl_verify():
2044 result = False
2045
2046 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002047 fq_logger.info("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002048
2049
Howard Persh07d99e62012-04-09 15:26:57 -07002050# FLOW MODIFY 1
2051#
2052# OVERVIEW
2053# Strict modify of single existing flow
2054#
2055# PURPOSE
2056# - Verify that strict flow modify operates only on specified flow
2057# - Verify that flow is correctly modified
2058#
2059# PARAMETERS
2060# None
2061#
2062# PROCESS
2063# 1. Delete all flows from switch
2064# 2. Generate 1 flow F
2065# 3. Send flow add to switch, for flow F
2066# 4. Generate new action list for flow F, yielding F'
2067# 5. Send strict flow modify to switch, for flow F'
2068# 6. Verify flow table in switch
2069# 7. Test PASSED iff flow returned by switch is F'; else FAILED
2070
rootf6af1672012-04-06 09:46:29 -07002071class Flow_Mod_1(basic.SimpleProtocol):
2072 """
2073 Test FLOW_MOD_1 from draft top-half test plan
2074
2075 INPUTS
2076 None
2077 """
2078
2079 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002080 fq_logger.info("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002081
2082 # Clear all flows from switch
2083
Howard Persh5f3c83f2012-04-13 09:57:10 -07002084 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002085 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002086 self.assertEqual(rc, 0, "Failed to delete all flows")
2087
2088 # Get switch capabilites
2089
Howard Persh5f3c83f2012-04-13 09:57:10 -07002090 fq_logger.info("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002091 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002092 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002093 self.assertTrue(sw.features_get(), "Get switch features failed")
2094 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2095
2096 # Dream up some flow information, i.e. space to chose from for
2097 # random flow parameter generation
2098
2099 fi = Flow_Info()
2100 fi.rand(10)
2101
2102 # Dream up a flow config
2103
2104 fc = Flow_Cfg()
2105 fc.rand(fi, \
2106 sw.tbl_stats.stats[0].wildcards, \
2107 sw.sw_features.actions, \
2108 sw.valid_ports \
2109 )
2110 fc = fc.canonical()
2111
2112 # Send it to the switch
2113
Howard Persh5f3c83f2012-04-13 09:57:10 -07002114 fq_logger.info("Sending flow add to switch:")
2115 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002116 ft = Flow_Tbl()
2117 fc.send_rem = False
2118 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2119 ft.insert(fc)
2120
2121 # Dream up some different actions, with the same flow key
2122
2123 fc2 = copy.deepcopy(fc)
2124 while True:
2125 fc2.rand_mod(fi, \
2126 sw.sw_features.actions, \
2127 sw.valid_ports \
2128 )
2129 if fc2 != fc:
2130 break
2131
2132 # Send that to the switch
2133
Howard Persh5f3c83f2012-04-13 09:57:10 -07002134 fq_logger.info("Sending strict flow mod to switch:")
2135 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002136 fc2.send_rem = False
2137 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2138 ft.insert(fc2)
2139
2140 # Do barrier, to make sure all flows are in
2141
2142 self.assertTrue(sw.barrier(), "Barrier failed")
2143
2144 result = True
2145
2146 # Check for any error messages
2147
2148 if not sw.errors_verify(0):
2149 result = False
2150
2151 # Verify flow table
2152
2153 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002154 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002155 result = False
2156
2157 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002158 fq_logger.info("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002159
Howard Persh07d99e62012-04-09 15:26:57 -07002160
2161# FLOW MODIFY 2
2162#
2163# OVERVIEW
2164# Loose modify of mutiple flows
2165#
2166# PURPOSE
2167# - Verify that loose flow modify operates only on matching flows
2168# - Verify that matching flows are correctly modified
2169#
2170# PARAMETERS
2171# Name: num_flows
2172# Type: number
2173# Description:
2174# Number of flows to define
2175# Default: 100
2176#
2177# PROCESS
2178# 1. Delete all flows from switch
2179# 2. Generate <num_flows> distinct flow configurations
2180# 3. Send <num_flows> flow adds to switch
2181# 4. Pick 1 defined flow F at random
2182# 5. Create overlapping loose flow mod match criteria by repeatedly
2183# wildcarding out qualifiers in match of F => F',
2184# and create new actions list A' for F'
2185# 6. Send loose flow modify for F' to switch
2186# 7. Verify flow table in swtich
2187# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2188# are returned in step 7 above, each with correct (original or modified)
2189# action list;
2190# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002191
2192class Flow_Mod_2(basic.SimpleProtocol):
2193 """
2194 Test FLOW_MOD_2 from draft top-half test plan
2195
2196 INPUTS
2197 None
2198 """
2199
2200 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002201 fq_logger.info("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002202
Dan Talayco910a8282012-04-07 00:05:20 -07002203 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002204
2205 # Clear all flows from switch
2206
Howard Persh5f3c83f2012-04-13 09:57:10 -07002207 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002208 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002209 self.assertEqual(rc, 0, "Failed to delete all flows")
2210
2211 # Get switch capabilites
2212
Howard Persh5f3c83f2012-04-13 09:57:10 -07002213 fq_logger.info("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002214 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002215 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002216 self.assertTrue(sw.features_get(), "Get switch features failed")
2217 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2218
2219 # Dream up some flow information, i.e. space to chose from for
2220 # random flow parameter generation
2221
2222 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002223 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002224 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002225
2226 # Dream up some flows
2227
2228 ft = Flow_Tbl()
2229 ft.rand(sw, fi, num_flows)
2230
2231 # Send flow table to switch
2232
Howard Persh5f3c83f2012-04-13 09:57:10 -07002233 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002234 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07002235 fq_logger.info("Adding flow:")
2236 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002237 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2238
2239 # Do barrier, to make sure all flows are in
2240
2241 self.assertTrue(sw.barrier(), "Barrier failed")
2242
2243 result = True
2244
2245 # Check for any error messages
2246
2247 if not sw.errors_verify(0):
2248 result = False
2249
2250 # Verify flow table
2251
2252 sw.flow_tbl = ft
2253 if not sw.flow_tbl_verify():
2254 result = False
2255
2256 # Pick a random flow as a basis
Howard Persh5f3c83f2012-04-13 09:57:10 -07002257
2258 mfc = copy.deepcopy((ft.values())[0])
rootf6af1672012-04-06 09:46:29 -07002259 mfc.rand_mod(fi, sw.sw_features.actions, sw.valid_ports)
2260
2261 # Repeatedly wildcard qualifiers
2262
2263 for wi in shuffle(range(len(all_wildcards_list))):
2264 w = all_wildcards_list[wi]
2265 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2266 n = wildcard_get(mfc.match.wildcards, w)
2267 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002268 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2269 w, \
2270 random.randint(n + 1, 32) \
2271 )
rootf6af1672012-04-06 09:46:29 -07002272 else:
2273 continue
2274 else:
2275 if wildcard_get(mfc.match.wildcards, w) == 0:
2276 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2277 else:
2278 continue
2279 mfc = mfc.canonical()
2280
2281 # Count the number of flows that would be modified
2282
2283 n = 0
2284 for fc in ft.values():
2285 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2286 n = n + 1
2287
2288 # If more than 1, we found our loose delete flow spec
2289 if n > 1:
2290 break
2291
Howard Persh5f3c83f2012-04-13 09:57:10 -07002292 fq_logger.info("Modifying %d flows" % (n))
2293 fq_logger.info("Sending flow mod to switch:")
2294 fq_logger.info(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002295 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2296
2297 # Do barrier, to make sure all flows are in
2298 self.assertTrue(sw.barrier(), "Barrier failed")
2299
2300 # Check for error message
2301
2302 if not sw.errors_verify(0):
2303 result = False
2304
2305 # Apply flow mod to local flow table
2306
2307 for fc in ft.values():
2308 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002309 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002310
2311 # Verify flow table
2312
2313 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002314 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002315 result = False
2316
2317 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002318 fq_logger.info("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002319
2320
Howard Persh07d99e62012-04-09 15:26:57 -07002321# FLOW MODIFY 3
2322
2323# OVERVIEW
2324# Strict modify of non-existent flow
2325#
2326# PURPOSE
2327# Verify that strict modify of a non-existent flow is equivalent to a flow add
2328#
2329# PARAMETERS
2330# None
2331#
2332# PROCESS
2333# 1. Delete all flows from switch
2334# 2. Send single flow mod, as strict modify, to switch
2335# 3. Verify flow table in switch
2336# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2337
rootf6af1672012-04-06 09:46:29 -07002338class Flow_Mod_3(basic.SimpleProtocol):
2339 """
2340 Test FLOW_MOD_3 from draft top-half test plan
2341
2342 INPUTS
2343 None
2344 """
2345
2346 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002347 fq_logger.info("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002348
2349 # Clear all flows from switch
2350
Howard Persh5f3c83f2012-04-13 09:57:10 -07002351 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002352 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002353 self.assertEqual(rc, 0, "Failed to delete all flows")
2354
2355 # Get switch capabilites
2356
Howard Persh5f3c83f2012-04-13 09:57:10 -07002357 fq_logger.info("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002358 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002359 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002360 self.assertTrue(sw.features_get(), "Get switch features failed")
2361 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2362
2363 # Dream up some flow information, i.e. space to chose from for
2364 # random flow parameter generation
2365
2366 fi = Flow_Info()
2367 fi.rand(10)
2368
2369 # Dream up a flow config
2370
2371 fc = Flow_Cfg()
2372 fc.rand(fi, \
2373 sw.tbl_stats.stats[0].wildcards, \
2374 sw.sw_features.actions, \
2375 sw.valid_ports \
2376 )
2377 fc = fc.canonical()
2378
2379 # Send it to the switch
2380
Howard Persh5f3c83f2012-04-13 09:57:10 -07002381 fq_logger.info("Sending flow mod to switch:")
2382 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002383 ft = Flow_Tbl()
2384 fc.send_rem = False
2385 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2386 ft.insert(fc)
2387
2388 # Do barrier, to make sure all flows are in
2389
2390 self.assertTrue(sw.barrier(), "Barrier failed")
2391
2392 result = True
2393
2394 # Check for any error messages
2395
2396 if not sw.errors_verify(0):
2397 result = False
2398
2399 # Verify flow table
2400
2401 sw.flow_tbl = ft
2402 if not sw.flow_tbl_verify():
2403 result = False
2404
2405 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002406 fq_logger.info("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002407
2408
Howard Persh07d99e62012-04-09 15:26:57 -07002409# FLOW DELETE 1
2410#
2411# OVERVIEW
2412# Strict delete of single flow
2413#
2414# PURPOSE
2415# Verify correct operation of strict delete of single defined flow
2416#
2417# PARAMETERS
2418# None
2419#
2420# PROCESS
2421# 1. Delete all flows from switch
2422# 2. Send flow F to switch
2423# 3. Send strict flow delete for F to switch
2424# 4. Verify flow table in swtich
2425# 6. Test PASSED iff all flows sent to switch in step 2 above,
2426# less flow removed in step 3 above, are returned in step 4 above;
2427# else test FAILED
2428
rootf6af1672012-04-06 09:46:29 -07002429class Flow_Del_1(basic.SimpleProtocol):
2430 """
2431 Test FLOW_DEL_1 from draft top-half test plan
2432
2433 INPUTS
2434 None
2435 """
2436
2437 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002438 fq_logger.info("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002439
2440 # Clear all flows from switch
2441
Howard Persh5f3c83f2012-04-13 09:57:10 -07002442 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002443 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002444 self.assertEqual(rc, 0, "Failed to delete all flows")
2445
2446 # Get switch capabilites
2447
Howard Persh5f3c83f2012-04-13 09:57:10 -07002448 fq_logger.info("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002449 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002450 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002451 self.assertTrue(sw.features_get(), "Get switch features failed")
2452 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2453
2454 # Dream up some flow information, i.e. space to chose from for
2455 # random flow parameter generation
2456
2457 fi = Flow_Info()
2458 fi.rand(10)
2459
2460 # Dream up a flow config
2461
2462 fc = Flow_Cfg()
2463 fc.rand(fi, \
2464 sw.tbl_stats.stats[0].wildcards, \
2465 sw.sw_features.actions, \
2466 sw.valid_ports \
2467 )
2468 fc = fc.canonical()
2469
2470 # Send it to the switch
2471
Howard Persh5f3c83f2012-04-13 09:57:10 -07002472 fq_logger.info("Sending flow add to switch:")
2473 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002474 ft = Flow_Tbl()
2475 fc.send_rem = False
2476 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2477 ft.insert(fc)
2478
2479 # Dream up some different actions, with the same flow key
2480
2481 fc2 = copy.deepcopy(fc)
2482 while True:
2483 fc2.rand_mod(fi, \
2484 sw.sw_features.actions, \
2485 sw.valid_ports \
2486 )
2487 if fc2 != fc:
2488 break
2489
2490 # Delete strictly
2491
Howard Persh5f3c83f2012-04-13 09:57:10 -07002492 fq_logger.info("Sending strict flow del to switch:")
2493 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002494 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2495 ft.delete(fc)
2496
2497 # Do barrier, to make sure all flows are in
2498
2499 self.assertTrue(sw.barrier(), "Barrier failed")
2500
2501 result = True
2502
2503 # Check for any error messages
2504
2505 if not sw.errors_verify(0):
2506 result = False
2507
2508 # Verify flow table
2509
2510 sw.flow_tbl = ft
2511 if not sw.flow_tbl_verify():
2512 result = False
2513
2514 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002515 fq_logger.info("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002516
2517
Howard Persh07d99e62012-04-09 15:26:57 -07002518# FLOW DELETE 2
2519#
2520# OVERVIEW
2521# Loose delete of multiple flows
2522#
2523# PURPOSE
2524# - Verify correct operation of loose delete of multiple flows
2525#
2526# PARAMETERS
2527# Name: num_flows
2528# Type: number
2529# Description:
2530# Number of flows to define
2531# Default: 100
2532#
2533# PROCESS
2534# 1. Delete all flows from switch
2535# 2. Generate <num_flows> distinct flow configurations
2536# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2537# 4. Pick 1 defined flow F at random
2538# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2539# F' will match more than 1 existing flow key
2540# 6. Send loose flow delete for F' to switch
2541# 7. Verify flow table in switch
2542# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2543# removed in step 6 above (i.e. those that match F'), are returned
2544# in step 7 above;
2545# else test FAILED
2546
rootf6af1672012-04-06 09:46:29 -07002547class Flow_Del_2(basic.SimpleProtocol):
2548 """
2549 Test FLOW_DEL_2 from draft top-half test plan
2550
2551 INPUTS
2552 None
2553 """
2554
2555 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002556 fq_logger.info("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002557
Dan Talayco910a8282012-04-07 00:05:20 -07002558 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002559
2560 # Clear all flows from switch
2561
Howard Persh5f3c83f2012-04-13 09:57:10 -07002562 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002563 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002564 self.assertEqual(rc, 0, "Failed to delete all flows")
2565
2566 # Get switch capabilites
2567
Howard Persh5f3c83f2012-04-13 09:57:10 -07002568 fq_logger.info("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002569 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002570 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002571 self.assertTrue(sw.features_get(), "Get switch features failed")
2572 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2573
2574 # Dream up some flow information, i.e. space to chose from for
2575 # random flow parameter generation
2576
2577 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002578 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002579 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002580
2581 # Dream up some flows
2582
2583 ft = Flow_Tbl()
2584 ft.rand(sw, fi, num_flows)
2585
2586 # Send flow table to switch
2587
Howard Persh5f3c83f2012-04-13 09:57:10 -07002588 fq_logger.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002589 for fc in ft.values(): # Randomizes order of sending
Howard Persh5f3c83f2012-04-13 09:57:10 -07002590 fq_logger.info("Adding flow:")
2591 fq_logger.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002592 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2593
2594 # Do barrier, to make sure all flows are in
2595
2596 self.assertTrue(sw.barrier(), "Barrier failed")
2597
2598 result = True
2599
2600 # Check for any error messages
2601
2602 if not sw.errors_verify(0):
2603 result = False
2604
2605 # Verify flow table
2606
2607 sw.flow_tbl = ft
2608 if not sw.flow_tbl_verify():
2609 result = False
2610
2611 # Pick a random flow as a basis
2612
2613 dfc = copy.deepcopy(ft.values()[0])
2614 dfc.rand_mod(fi, sw.sw_features.actions, sw.valid_ports)
2615
2616 # Repeatedly wildcard qualifiers
2617
2618 for wi in shuffle(range(len(all_wildcards_list))):
2619 w = all_wildcards_list[wi]
2620 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2621 n = wildcard_get(dfc.match.wildcards, w)
2622 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002623 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2624 w, \
2625 random.randint(n + 1, 32) \
2626 )
rootf6af1672012-04-06 09:46:29 -07002627 else:
2628 continue
2629 else:
2630 if wildcard_get(dfc.match.wildcards, w) == 0:
2631 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2632 else:
2633 continue
2634 dfc = dfc.canonical()
2635
2636 # Count the number of flows that would be deleted
2637
2638 n = 0
2639 for fc in ft.values():
2640 if dfc.overlaps(fc, True):
2641 n = n + 1
2642
2643 # If more than 1, we found our loose delete flow spec
2644 if n > 1:
2645 break
2646
Howard Persh5f3c83f2012-04-13 09:57:10 -07002647 fq_logger.info("Deleting %d flows" % (n))
2648 fq_logger.info("Sending flow del to switch:")
2649 fq_logger.info(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002650 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2651
2652 # Do barrier, to make sure all flows are in
2653 self.assertTrue(sw.barrier(), "Barrier failed")
2654
2655 # Check for error message
2656
2657 if not sw.errors_verify(0):
2658 result = False
2659
2660 # Apply flow mod to local flow table
2661
2662 for fc in ft.values():
2663 if dfc.overlaps(fc, True):
2664 ft.delete(fc)
2665
2666 # Verify flow table
2667
2668 sw.flow_tbl = ft
2669 if not sw.flow_tbl_verify():
2670 result = False
2671
2672 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002673 fq_logger.info("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002674
2675
Howard Persh07d99e62012-04-09 15:26:57 -07002676# FLOW DELETE 4
2677#
2678# OVERVIEW
2679# Flow removed messages
2680#
2681# PURPOSE
2682# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2683# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2684#
2685# PARAMETERS
2686# None
2687#
2688# PROCESS
2689# 1. Delete all flows from switch
2690# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2691# 3. Send strict flow delete of flow to switch
2692# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2693# 5. Verify flow table in switch
2694# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2695# removed in step 3 above, are returned in step 5 above, and that
2696# asynch message was received; else test FAILED
2697
2698
rootf6af1672012-04-06 09:46:29 -07002699class Flow_Del_4(basic.SimpleProtocol):
2700 """
2701 Test FLOW_DEL_4 from draft top-half test plan
2702
2703 INPUTS
2704 None
2705 """
2706
2707 def runTest(self):
Howard Persh5f3c83f2012-04-13 09:57:10 -07002708 fq_logger.info("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002709
2710 # Clear all flows from switch
2711
Howard Persh5f3c83f2012-04-13 09:57:10 -07002712 fq_logger.info("Deleting all flows from switch")
Dan Talayco910a8282012-04-07 00:05:20 -07002713 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002714 self.assertEqual(rc, 0, "Failed to delete all flows")
2715
2716 # Get switch capabilites
2717
Howard Persh5f3c83f2012-04-13 09:57:10 -07002718 fq_logger.info("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002719 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002720 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002721 self.assertTrue(sw.features_get(), "Get switch features failed")
2722 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2723
2724 # Dream up some flow information, i.e. space to chose from for
2725 # random flow parameter generation
2726
2727 fi = Flow_Info()
2728 fi.rand(10)
2729
2730 # Dream up a flow config
2731
2732 fc = Flow_Cfg()
2733 fc.rand(fi, \
2734 sw.tbl_stats.stats[0].wildcards, \
2735 sw.sw_features.actions, \
2736 sw.valid_ports \
2737 )
2738 fc = fc.canonical()
2739
2740 # Send it to the switch. with "notify on removed"
2741
Howard Persh5f3c83f2012-04-13 09:57:10 -07002742 fq_logger.info("Sending flow add to switch:")
2743 fq_logger.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002744 ft = Flow_Tbl()
2745 fc.send_rem = True
2746 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2747 ft.insert(fc)
2748
2749 # Dream up some different actions, with the same flow key
2750
2751 fc2 = copy.deepcopy(fc)
2752 while True:
2753 fc2.rand_mod(fi, \
2754 sw.sw_features.actions, \
2755 sw.valid_ports \
2756 )
2757 if fc2 != fc:
2758 break
2759
2760 # Delete strictly
2761
Howard Persh5f3c83f2012-04-13 09:57:10 -07002762 fq_logger.info("Sending strict flow del to switch:")
2763 fq_logger.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002764 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2765 ft.delete(fc)
2766
2767 # Do barrier, to make sure all flows are in
2768
2769 self.assertTrue(sw.barrier(), "Barrier failed")
2770
2771 result = True
2772
2773 # Check for expected "removed" message
2774
Howard Persh3340d452012-04-06 16:45:21 -07002775 if not sw.errors_verify(0):
2776 result = False
2777
2778 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07002779 result = False
2780
2781 # Verify flow table
2782
2783 sw.flow_tbl = ft
2784 if not sw.flow_tbl_verify():
2785 result = False
2786
2787 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Howard Persh5f3c83f2012-04-13 09:57:10 -07002788 fq_logger.info("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002789