blob: a79c9f939a2951e87e99a8087f7c7dfba25a4d63 [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
378 def non_key_equal(self, x):
379 if self.cookie != x.cookie:
Howard Pershc7963582012-03-29 10:02:59 -0700380 return False
381 if self.idle_timeout != x.idle_timeout:
382 return False
383 if self.hard_timeout != x.hard_timeout:
384 return False
Dan Talayco910a8282012-04-07 00:05:20 -0700385 if True:
386 # For now, compare actions lists as unordered
root2843d2b2012-04-06 10:27:46 -0700387 aa = copy.deepcopy(x.actions.actions)
388 for a in self.actions.actions:
389 i = 0
390 while i < len(aa):
391 if a == aa[i]:
392 break
393 i = i + 1
394 if i < len(aa):
395 aa.pop(i)
396 else:
397 return False
398 return aa == []
399 else:
400 return self.actions == x.actions
rootf6af1672012-04-06 09:46:29 -0700401
root2843d2b2012-04-06 10:27:46 -0700402 def key_str(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700403 result = "priority=%d" % self.priority
404 # TBD - Would be nice if ofp_match.show() was better behaved
405 # (no newlines), and more intuitive (things in hex where approprate), etc.
rootf6af1672012-04-06 09:46:29 -0700406 result = result + (", wildcards=0x%x={" % (self.match.wildcards))
Howard Persh680b92a2012-03-31 13:34:35 -0700407 sep = ""
rootf6af1672012-04-06 09:46:29 -0700408 for w in all_wildcards_list:
409 if (self.match.wildcards & w) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700410 continue
411 if w == ofp.OFPFW_NW_SRC_MASK:
rootf6af1672012-04-06 09:46:29 -0700412 n = wildcard_get(self.match.wildcards, w)
413 if n > 0:
414 result = result + sep + ("OFPFW_NW_SRC(%d)" % (n))
Howard Persh680b92a2012-03-31 13:34:35 -0700415 elif w == ofp.OFPFW_NW_DST_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_DST(%d)" % (n))
Howard Persh680b92a2012-03-31 13:34:35 -0700419 else:
rootf6af1672012-04-06 09:46:29 -0700420 result = result + sep + all_wildcard_names[w]
Howard Persh680b92a2012-03-31 13:34:35 -0700421 sep = ", "
422 result = result +"}"
rootf6af1672012-04-06 09:46:29 -0700423 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700424 result = result + (", in_port=%d" % (self.match.in_port))
rootf6af1672012-04-06 09:46:29 -0700425 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700426 result = result + (", dl_dst=%s" \
427 % (dl_addr_to_str(self.match.dl_dst)) \
428 )
rootf6af1672012-04-06 09:46:29 -0700429 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700430 result = result + (", dl_src=%s" \
431 % (dl_addr_to_str(self.match.dl_src)) \
432 )
rootf6af1672012-04-06 09:46:29 -0700433 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700434 result = result + (", dl_vlan=%d" % (self.match.dl_vlan))
rootf6af1672012-04-06 09:46:29 -0700435 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700436 result = result + (", dl_vlan_pcp=%d" % (self.match.dl_vlan_pcp))
rootf6af1672012-04-06 09:46:29 -0700437 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700438 result = result + (", dl_type=0x%x" % (self.match.dl_type))
rootf6af1672012-04-06 09:46:29 -0700439 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700440 result = result + (", nw_tos=0x%x" % (self.match.nw_tos))
rootf6af1672012-04-06 09:46:29 -0700441 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700442 result = result + (", nw_proto=%d" % (self.match.nw_proto))
rootf6af1672012-04-06 09:46:29 -0700443 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700444 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700445 result = result + (", nw_src=%s" % \
446 (ip_addr_to_str(self.match.nw_src, 32 - n)) \
447 )
rootf6af1672012-04-06 09:46:29 -0700448 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700449 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700450 result = result + (", nw_dst=%s" % \
451 (ip_addr_to_str(self.match.nw_dst, 32 - n)) \
452 )
rootf6af1672012-04-06 09:46:29 -0700453 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700454 result = result + (", tp_src=%d" % self.match.tp_src)
rootf6af1672012-04-06 09:46:29 -0700455 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700456 result = result + (", tp_dst=%d" % self.match.tp_dst)
rootf6af1672012-04-06 09:46:29 -0700457 return result
458
459 def __eq__(self, x):
460 return (self.key_equal(x) and self.non_key_equal(x))
461
462 def __str__(self):
root2843d2b2012-04-06 10:27:46 -0700463 result = self.key_str()
464 result = result + (", cookie=%d" % self.cookie)
Howard Persh680b92a2012-03-31 13:34:35 -0700465 result = result + (", idle_timeout=%d" % self.idle_timeout)
466 result = result + (", hard_timeout=%d" % self.hard_timeout)
Howard Persh680b92a2012-03-31 13:34:35 -0700467 for a in self.actions.actions:
468 result = result + (", action=%s" % ofp.ofp_action_type_map[a.type])
469 if a.type == ofp.OFPAT_OUTPUT:
470 result = result + ("(%d)" % (a.port))
471 elif a.type == ofp.OFPAT_SET_VLAN_VID:
472 result = result + ("(%d)" % (a.vlan_vid))
473 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
474 result = result + ("(%d)" % (a.vlan_pcp))
475 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
476 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
477 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
478 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
479 elif a.type == ofp.OFPAT_SET_NW_TOS:
480 result = result + ("(0x%x)" % (a.nw_tos))
481 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
482 result = result + ("(%d)" % (a.tp_port))
483 elif a.type == ofp.OFPAT_ENQUEUE:
484 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
485 return result
Howard Pershc7963582012-03-29 10:02:59 -0700486
Dan Talayco910a8282012-04-07 00:05:20 -0700487 def rand_actions_ordered(self, fi, valid_actions, valid_ports):
Howard Persh3340d452012-04-06 16:45:21 -0700488 # Action lists are ordered, so pick an ordered random subset of
489 # supported actions
Howard Pershc1199d52012-04-11 14:21:32 -0700490
491 actions_force = test_param_get(fq_config, "actions_force", 0)
492
Dan Talayco910a8282012-04-07 00:05:20 -0700493 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh3340d452012-04-06 16:45:21 -0700494 supported_actions = []
495 for a in all_actions_list:
496 if ((1 << a) & valid_actions) != 0:
497 supported_actions.append(a)
498
Howard Pershc1199d52012-04-11 14:21:32 -0700499 actions \
500 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
501
502 for a in all_actions_list:
503 if ((1 << a) & actions_force) != 0:
504 actions.append(a)
505
506 actions = shuffle(actions)
Howard Persh3340d452012-04-06 16:45:21 -0700507
Howard Persh3340d452012-04-06 16:45:21 -0700508 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700509 for a in actions:
Dan Talayco910a8282012-04-07 00:05:20 -0700510 act = None
Howard Persh3340d452012-04-06 16:45:21 -0700511 if a == ofp.OFPAT_OUTPUT:
512 pass # OUTPUT actions must come last
513 elif a == ofp.OFPAT_SET_VLAN_VID:
514 act = action.action_set_vlan_vid()
515 act.vlan_vid = fi.rand_vlan()
Howard Persh3340d452012-04-06 16:45:21 -0700516 elif a == ofp.OFPAT_SET_VLAN_PCP:
517 act = action.action_set_vlan_pcp()
518 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Persh3340d452012-04-06 16:45:21 -0700519 elif a == ofp.OFPAT_STRIP_VLAN:
520 act = action.action_strip_vlan()
Howard Persh3340d452012-04-06 16:45:21 -0700521 elif a == ofp.OFPAT_SET_DL_SRC:
522 act = action.action_set_dl_src()
523 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700524 elif a == ofp.OFPAT_SET_DL_DST:
525 act = action.action_set_dl_dst()
526 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700527 elif a == ofp.OFPAT_SET_NW_SRC:
528 act = action.action_set_nw_src()
529 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700530 elif a == ofp.OFPAT_SET_NW_DST:
531 act = action.action_set_nw_dst()
532 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700533 elif a == ofp.OFPAT_SET_NW_TOS:
534 act = action.action_set_nw_tos()
535 act.nw_tos = fi.rand_ip_tos()
Howard Persh3340d452012-04-06 16:45:21 -0700536 elif a == ofp.OFPAT_SET_TP_SRC:
537 act = action.action_set_tp_src()
538 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700539 elif a == ofp.OFPAT_SET_TP_DST:
540 act = action.action_set_tp_dst()
541 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700542 elif a == ofp.OFPAT_ENQUEUE:
543 pass # Enqueue actions must come last
Dan Talayco910a8282012-04-07 00:05:20 -0700544 if act:
545 act.max_len = ACTION_MAX_LEN
546 self.actions.add(act)
547
Howard Persh3340d452012-04-06 16:45:21 -0700548 p = random.randint(1, 100)
Howard Pershc1199d52012-04-11 14:21:32 -0700549 if (((1 << ofp.OFPAT_ENQUEUE) & actions_force) != 0 or p <= 33) \
550 and ofp.OFPAT_ENQUEUE in actions:
551 # In not forecd, one third of the time, include ENQUEUE actions
552 # at end of list
Howard Persh3340d452012-04-06 16:45:21 -0700553 # At most 1 ENQUEUE action
554 act = action.action_enqueue()
555 act.port = rand_pick(valid_ports)
556 # TBD - Limits for queue number?
557 act.queue_id = random.randint(0, 7)
Dan Talayco910a8282012-04-07 00:05:20 -0700558 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700559 self.actions.add(act)
Howard Pershc1199d52012-04-11 14:21:32 -0700560 if (((1 << ofp.OFPAT_OUTPUT) & actions_force) != 0 \
561 or (p > 33 and p <= 66) \
562 ) \
563 and ofp.OFPAT_OUTPUT in actions:
Howard Persh3340d452012-04-06 16:45:21 -0700564 # One third of the time, include OUTPUT actions at end of list
565 port_idxs = shuffle(range(len(valid_ports)))
566 # Only 1 output action allowed if IN_PORT wildcarded
567 n = 1 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) != 0 \
568 else random.randint(1, len(valid_ports))
569 port_idxs = port_idxs[0 : n]
570 for pi in port_idxs:
571 act = action.action_output()
572 act.port = valid_ports[pi]
Dan Talayco910a8282012-04-07 00:05:20 -0700573 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700574 if act.port != ofp.OFPP_IN_PORT \
575 or wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
576 # OUTPUT(IN_PORT) only valid if OFPFW_IN_PORT not wildcarded
577 self.actions.add(act)
578 else:
579 # One third of the time, include neither
580 pass
581
582
583 # Randomize flow data for flow modifies (i.e. cookie and actions)
rootf6af1672012-04-06 09:46:29 -0700584 def rand_mod(self, fi, valid_actions, valid_ports):
585 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700586
Dan Talayco910a8282012-04-07 00:05:20 -0700587 # By default, test with conservative ordering conventions
588 # This should probably be indicated in a profile
589 if test_param_get(fq_config, "conservative_ordered_actions", True):
590 self.rand_actions_ordered(fi, valid_actions, valid_ports)
Howard Persh3340d452012-04-06 16:45:21 -0700591 return self
592
Howard Pershc1199d52012-04-11 14:21:32 -0700593 actions_force = test_param_get(fq_config, "actions_force", 0)
594
595 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh680b92a2012-03-31 13:34:35 -0700596 supported_actions = []
597 for a in all_actions_list:
598 if ((1 << a) & valid_actions) != 0:
599 supported_actions.append(a)
600
Howard Pershc1199d52012-04-11 14:21:32 -0700601 actions \
602 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
603
604 for a in all_actions_list:
605 if ((1 << a) & actions_force) != 0:
606 actions.append(a)
607
608 actions = shuffle(actions)
Howard Pershc7963582012-03-29 10:02:59 -0700609
610 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700611 for a in actions:
Howard Pershc7963582012-03-29 10:02:59 -0700612 if a == ofp.OFPAT_OUTPUT:
613 # TBD - Output actions are clustered in list, spread them out?
614 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700615 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700616 for pi in port_idxs:
617 act = action.action_output()
Howard Persh680b92a2012-03-31 13:34:35 -0700618 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700619 self.actions.add(act)
620 elif a == ofp.OFPAT_SET_VLAN_VID:
621 act = action.action_set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700622 act.vlan_vid = fi.rand_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700623 self.actions.add(act)
624 elif a == ofp.OFPAT_SET_VLAN_PCP:
Dan Talayco910a8282012-04-07 00:05:20 -0700625 act = action.action_set_vlan_pcp()
626 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700627 elif a == ofp.OFPAT_STRIP_VLAN:
628 act = action.action_strip_vlan()
629 self.actions.add(act)
630 elif a == ofp.OFPAT_SET_DL_SRC:
631 act = action.action_set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700632 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700633 self.actions.add(act)
634 elif a == ofp.OFPAT_SET_DL_DST:
635 act = action.action_set_dl_dst()
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_NW_SRC:
639 act = action.action_set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700640 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700641 self.actions.add(act)
642 elif a == ofp.OFPAT_SET_NW_DST:
643 act = action.action_set_nw_dst()
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_TOS:
647 act = action.action_set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700648 act.nw_tos = fi.rand_ip_tos()
Howard Pershc7963582012-03-29 10:02:59 -0700649 self.actions.add(act)
650 elif a == ofp.OFPAT_SET_TP_SRC:
651 act = action.action_set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700652 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700653 self.actions.add(act)
654 elif a == ofp.OFPAT_SET_TP_DST:
655 act = action.action_set_tp_dst()
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_ENQUEUE:
659 # TBD - Enqueue actions are clustered in list, spread them out?
660 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700661 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700662 for pi in port_idxs:
663 act = action.action_enqueue()
Howard Persh680b92a2012-03-31 13:34:35 -0700664 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700665 # TBD - Limits for queue number?
666 act.queue_id = random.randint(0, 7)
667 self.actions.add(act)
668
669 return self
670
rootf6af1672012-04-06 09:46:29 -0700671 # Randomize flow cfg
672 def rand(self, fi, valid_wildcards, valid_actions, valid_ports):
Howard Pershc1199d52012-04-11 14:21:32 -0700673 wildcards_force = test_param_get(fq_config, "wildcards_force", 0)
674
rootf6af1672012-04-06 09:46:29 -0700675 # Start with no wildcards, i.e. everything specified
676 self.match.wildcards = 0
Howard Pershc1199d52012-04-11 14:21:32 -0700677
678 if wildcards_force != 0:
679 exact = False
680 else:
681 # Make approx. 5% of flows exact
682 exact = (random.randint(1, 100) <= 5)
rootf6af1672012-04-06 09:46:29 -0700683
684 # For each qualifier Q,
685 # if (wildcarding is not supported for Q,
686 # or an exact flow is specified
687 # or a coin toss comes up heads),
688 # specify Q
689 # else
690 # wildcard Q
691
Howard Pershc1199d52012-04-11 14:21:32 -0700692 if wildcard_get(wildcards_force, ofp.OFPFW_IN_PORT) == 0 \
693 and (wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
694 or exact \
695 or flip_coin() \
696 ):
rootf6af1672012-04-06 09:46:29 -0700697 self.match.in_port = rand_pick(valid_ports)
698 else:
Howard Persh3340d452012-04-06 16:45:21 -0700699 self.match.wildcards = wildcard_set(self.match.wildcards, \
700 ofp.OFPFW_IN_PORT, \
701 1 \
702 )
rootf6af1672012-04-06 09:46:29 -0700703
Howard Pershc1199d52012-04-11 14:21:32 -0700704 if wildcard_get(wildcards_force, ofp.OFPFW_DL_DST) == 0 \
705 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
706 or exact \
707 or flip_coin() \
708 ):
rootf6af1672012-04-06 09:46:29 -0700709 self.match.dl_dst = fi.rand_dl_addr()
710 else:
Howard Persh3340d452012-04-06 16:45:21 -0700711 self.match.wildcards = wildcard_set(self.match.wildcards, \
712 ofp.OFPFW_DL_DST, \
713 1 \
714 )
rootf6af1672012-04-06 09:46:29 -0700715
Howard Pershc1199d52012-04-11 14:21:32 -0700716 if wildcard_get(wildcards_force, ofp.OFPFW_DL_SRC) == 0 \
717 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
718 or exact \
719 or flip_coin() \
720 ):
rootf6af1672012-04-06 09:46:29 -0700721 self.match.dl_src = fi.rand_dl_addr()
722 else:
Howard Persh3340d452012-04-06 16:45:21 -0700723 self.match.wildcards = wildcard_set(self.match.wildcards, \
724 ofp.OFPFW_DL_SRC, \
725 1 \
726 )
rootf6af1672012-04-06 09:46:29 -0700727
Howard Pershc1199d52012-04-11 14:21:32 -0700728 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN) == 0 \
729 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
730 or exact \
731 or flip_coin() \
732 ):
rootf6af1672012-04-06 09:46:29 -0700733 self.match.dl_vlan = fi.rand_vlan()
734 else:
Howard Persh3340d452012-04-06 16:45:21 -0700735 self.match.wildcards = wildcard_set(self.match.wildcards, \
736 ofp.OFPFW_DL_VLAN, \
737 1 \
738 )
rootf6af1672012-04-06 09:46:29 -0700739
Howard Pershc1199d52012-04-11 14:21:32 -0700740 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN_PCP) == 0 \
741 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
742 or exact \
743 or flip_coin() \
744 ):
745 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
746 else:
747 self.match.wildcards = wildcard_set(self.match.wildcards, \
748 ofp.OFPFW_DL_VLAN_PCP, \
749 1 \
750 )
751
752 if wildcard_get(wildcards_force, ofp.OFPFW_DL_TYPE) == 0 \
753 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
754 or exact \
755 or flip_coin() \
756 ):
rootf6af1672012-04-06 09:46:29 -0700757 self.match.dl_type = fi.rand_ethertype()
758 else:
Howard Persh3340d452012-04-06 16:45:21 -0700759 self.match.wildcards = wildcard_set(self.match.wildcards, \
760 ofp.OFPFW_DL_TYPE, \
761 1 \
762 )
rootf6af1672012-04-06 09:46:29 -0700763
Howard Pershc1199d52012-04-11 14:21:32 -0700764 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_SRC_MASK)
765 if n == 0:
766 if exact or flip_coin():
767 n = 0
768 else:
769 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
770 if n > 32:
771 n = 32
772 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700773 self.match.wildcards = wildcard_set(self.match.wildcards, \
774 ofp.OFPFW_NW_SRC_MASK, \
775 n \
776 )
rootf6af1672012-04-06 09:46:29 -0700777 if n < 32:
778 self.match.nw_src = fi.rand_ip_addr() & ~((1 << n) - 1)
779 # Specifying any IP address match other than all bits
780 # don't care requires that Ethertype is one of {IP, ARP}
781 if flip_coin():
782 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700783 self.match.wildcards = wildcard_set(self.match.wildcards, \
784 ofp.OFPFW_DL_TYPE, \
785 0 \
786 )
rootf6af1672012-04-06 09:46:29 -0700787
Howard Pershc1199d52012-04-11 14:21:32 -0700788 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_DST_MASK)
789 if n == 0:
790 if exact or flip_coin():
791 n = 0
792 else:
793 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
794 if n > 32:
795 n = 32
796 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700797 self.match.wildcards = wildcard_set(self.match.wildcards, \
798 ofp.OFPFW_NW_DST_MASK, \
799 n \
800 )
rootf6af1672012-04-06 09:46:29 -0700801 if n < 32:
802 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
803 # Specifying any IP address match other than all bits
804 # don't care requires that Ethertype is one of {IP, ARP}
805 if flip_coin():
806 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700807 self.match.wildcards = wildcard_set(self.match.wildcards, \
808 ofp.OFPFW_DL_TYPE, \
809 0 \
810 )
rootf6af1672012-04-06 09:46:29 -0700811
Howard Pershc1199d52012-04-11 14:21:32 -0700812 if wildcard_get(wildcards_force, ofp.OFPFW_NW_TOS) == 0 \
813 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
814 or exact \
815 or flip_coin() \
816 ):
rootf6af1672012-04-06 09:46:29 -0700817 self.match.nw_tos = fi.rand_ip_tos()
818 # Specifying a TOS value requires that Ethertype is IP
819 if flip_coin():
820 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700821 self.match.wildcards = wildcard_set(self.match.wildcards, \
822 ofp.OFPFW_DL_TYPE, \
823 0 \
824 )
rootf6af1672012-04-06 09:46:29 -0700825 else:
Howard Persh3340d452012-04-06 16:45:21 -0700826 self.match.wildcards = wildcard_set(self.match.wildcards, \
827 ofp.OFPFW_NW_TOS, \
828 1 \
829 )
rootf6af1672012-04-06 09:46:29 -0700830
Dan Talayco910a8282012-04-07 00:05:20 -0700831 # Known issue on OVS with specifying nw_proto w/o dl_type as IP
Howard Pershc1199d52012-04-11 14:21:32 -0700832 if wildcard_get(wildcards_force, ofp.OFPFW_NW_PROTO) == 0 \
833 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
834 or exact \
835 or flip_coin() \
836 ):
Dan Talayco910a8282012-04-07 00:05:20 -0700837 self.match.nw_proto = fi.rand_ip_proto()
838 # Specifying an IP protocol requires that Ethertype is IP
839 if flip_coin():
840 self.match.dl_type = 0x0800
841 self.match.wildcards = wildcard_set(self.match.wildcards, \
842 ofp.OFPFW_DL_TYPE, \
843 0 \
844 )
845 else:
Howard Persh3340d452012-04-06 16:45:21 -0700846 self.match.wildcards = wildcard_set(self.match.wildcards, \
847 ofp.OFPFW_NW_PROTO, \
848 1 \
849 )
Dan Talayco910a8282012-04-07 00:05:20 -0700850
Howard Pershc1199d52012-04-11 14:21:32 -0700851 if wildcard_get(wildcards_force, ofp.OFPFW_TP_SRC) == 0 \
852 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
853 or exact\
854 or flip_coin() \
855 ):
rootf6af1672012-04-06 09:46:29 -0700856 self.match.tp_src = fi.rand_l4_port()
857 # Specifying a L4 port requires that IP protcol is
858 # one of {ICMP, TCP, UDP}
859 if flip_coin():
860 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700861 self.match.wildcards = wildcard_set(self.match.wildcards, \
862 ofp.OFPFW_NW_PROTO, \
863 0 \
864 )
rootf6af1672012-04-06 09:46:29 -0700865 # Specifying a L4 port requirues that Ethertype is IP
866 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700867 self.match.wildcards = wildcard_set(self.match.wildcards, \
868 ofp.OFPFW_DL_TYPE, \
869 0 \
870 )
rootf6af1672012-04-06 09:46:29 -0700871 if self.match.nw_proto == 1:
872 self.match.tp_src = self.match.tp_src & 0xff
873 else:
Howard Persh3340d452012-04-06 16:45:21 -0700874 self.match.wildcards = wildcard_set(self.match.wildcards, \
875 ofp.OFPFW_TP_SRC, \
876 1 \
877 )
rootf6af1672012-04-06 09:46:29 -0700878
Howard Pershc1199d52012-04-11 14:21:32 -0700879 if wildcard_get(wildcards_force, ofp.OFPFW_TP_DST) == 0 \
880 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
881 or exact \
882 or flip_coin() \
883 ):
rootf6af1672012-04-06 09:46:29 -0700884 self.match.tp_dst = fi.rand_l4_port()
885 # Specifying a L4 port requires that IP protcol is
886 # one of {ICMP, TCP, UDP}
887 if flip_coin():
888 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700889 self.match.wildcards = wildcard_set(self.match.wildcards, \
890 ofp.OFPFW_NW_PROTO, \
891 0 \
892 )
rootf6af1672012-04-06 09:46:29 -0700893 # Specifying a L4 port requirues that Ethertype is IP
894 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700895 self.match.wildcards = wildcard_set(self.match.wildcards, \
896 ofp.OFPFW_DL_TYPE, \
897 0 \
898 )
rootf6af1672012-04-06 09:46:29 -0700899 if self.match.nw_proto == 1:
900 self.match.tp_dst = self.match.tp_dst & 0xff
901 else:
Howard Persh3340d452012-04-06 16:45:21 -0700902 self.match.wildcards = wildcard_set(self.match.wildcards, \
903 ofp.OFPFW_TP_DST, \
904 1 \
905 )
rootf6af1672012-04-06 09:46:29 -0700906
907 # If nothing is wildcarded, it is an exact flow spec -- some switches
Howard Persh3340d452012-04-06 16:45:21 -0700908 # (Open vSwitch, for one) *require* that exact flow specs
909 # have priority 65535.
910 self.priority = 65535 if self.match.wildcards == 0 \
911 else fi.rand_priority()
rootf6af1672012-04-06 09:46:29 -0700912
913 # N.B. Don't make the timeout too short, else the flow might
914 # disappear before we get a chance to check for it.
915 t = random.randint(0, 65535)
916 self.idle_timeout = 0 if t < 60 else t
917 t = random.randint(0, 65535)
918 self.hard_timeout = 0 if t < 60 else t
919
920 self.rand_mod(fi, valid_actions, valid_ports)
921
922 return self
923
924 # Return flow cfg in canonical form
Howard Persh3340d452012-04-06 16:45:21 -0700925 # - There are dependencies between flow qualifiers, e.g. it only makes
926 # sense to qualify nw_proto if dl_type is qualified to be 0x0800 (IP).
927 # The canonical form of flow match criteria will "wildcard out"
928 # all such cases.
rootf6af1672012-04-06 09:46:29 -0700929 def canonical(self):
930 result = copy.deepcopy(self)
Howard Persh07d99e62012-04-09 15:26:57 -0700931
932 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_VLAN) != 0:
933 result.match.wildcards = wildcard_set(result.match.wildcards, \
934 ofp.OFPFW_DL_VLAN_PCP, \
935 1 \
936 )
937
rootf6af1672012-04-06 09:46:29 -0700938 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
939 or result.match.dl_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700940 # dl_tyoe is wildcarded, or specified as something other
941 # than IP or ARP
Howard Persh07d99e62012-04-09 15:26:57 -0700942 # => nw_src, nw_dst, nw_proto cannot be specified,
943 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700944 result.match.wildcards = wildcard_set(result.match.wildcards, \
945 ofp.OFPFW_NW_SRC_MASK, \
946 32 \
947 )
948 result.match.wildcards = wildcard_set(result.match.wildcards, \
949 ofp.OFPFW_NW_DST_MASK, \
950 32 \
951 )
Howard Persh3340d452012-04-06 16:45:21 -0700952 result.match.wildcards = wildcard_set(result.match.wildcards, \
953 ofp.OFPFW_NW_PROTO, \
954 1 \
955 )
Howard Persh07d99e62012-04-09 15:26:57 -0700956
957 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
958 or result.match.dl_type != 0x0800:
959 # dl_type is wildcarded, or specified as something other than IP
960 # => nw_tos, tp_src and tp_dst cannot be specified,
961 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700962 result.match.wildcards = wildcard_set(result.match.wildcards, \
963 ofp.OFPFW_NW_TOS, \
964 1 \
965 )
966 result.match.wildcards = wildcard_set(result.match.wildcards, \
967 ofp.OFPFW_TP_SRC, \
968 1 \
969 )
970 result.match.wildcards = wildcard_set(result.match.wildcards, \
971 ofp.OFPFW_TP_DST, \
972 1 \
973 )
Howard Persh07d99e62012-04-09 15:26:57 -0700974 result.match.wildcards = wildcard_set(result.match.wildcards, \
975 ofp.OFPFW_NW_SRC_MASK, \
976 32 \
977 )
978 result.match.wildcards = wildcard_set(result.match.wildcards, \
979 ofp.OFPFW_NW_DST_MASK, \
980 32 \
981 )
982 result.match.wildcards = wildcard_set(result.match.wildcards, \
983 ofp.OFPFW_NW_PROTO, \
984 1 \
985 )
986
rootf6af1672012-04-06 09:46:29 -0700987 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
988 or result.match.nw_proto not in [1, 6, 17]:
Howard Persh3340d452012-04-06 16:45:21 -0700989 # nw_proto is wildcarded, or specified as something other than ICMP,
990 # TCP or UDP
rootf6af1672012-04-06 09:46:29 -0700991 # => tp_src and tp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700992 result.match.wildcards = wildcard_set(result.match.wildcards, \
993 ofp.OFPFW_TP_SRC, \
994 1 \
995 )
996 result.match.wildcards = wildcard_set(result.match.wildcards, \
997 ofp.OFPFW_TP_DST, \
998 1 \
999 )
rootf6af1672012-04-06 09:46:29 -07001000 return result
1001
Howard Persh680b92a2012-03-31 13:34:35 -07001002 # Overlap check
1003 # delf == True <=> Check for delete overlap, else add overlap
1004 # "Add overlap" is defined as there exists a packet that could match both the
1005 # receiver and argument flowspecs
1006 # "Delete overlap" is defined as the specificity of the argument flowspec
1007 # is greater than or equal to the specificity of the receiver flowspec
1008 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -07001009 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
1010 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001011 if self.match.in_port != x.match.in_port:
1012 return False # Both specified, and not equal
1013 elif delf:
1014 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001015 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
1016 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001017 if self.match.dl_vlan != x.match.dl_vlan:
1018 return False # Both specified, and not equal
1019 elif delf:
1020 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001021 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
1022 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001023 if self.match.dl_src != x.match.dl_src:
1024 return False # Both specified, and not equal
1025 elif delf:
1026 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001027 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
1028 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001029 if self.match.dl_dst != x.match.dl_dst:
1030 return False # Both specified, and not equal
1031 elif delf:
1032 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001033 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
1034 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001035 if self.match.dl_type != x.match.dl_type:
1036 return False # Both specified, and not equal
1037 elif delf:
1038 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -07001039 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
1040 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001041 if self.match.nw_proto != x.match.nw_proto:
1042 return False # Both specified, and not equal
1043 elif delf:
1044 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001045 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
1046 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001047 if self.match.tp_src != x.match.tp_src:
1048 return False # Both specified, and not equal
1049 elif delf:
1050 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001051 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
1052 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001053 if self.match.tp_dst != x.match.tp_dst:
1054 return False # Both specified, and not equal
1055 elif delf:
1056 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001057 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
1058 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001059 if delf and na < nb:
1060 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001061 if (na < 32 and nb < 32):
1062 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1063 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -07001064 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -07001065 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
1066 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001067 if delf and na < nb:
1068 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001069 if (na < 32 and nb < 32):
1070 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1071 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
rootf6af1672012-04-06 09:46:29 -07001072 return False # Overlapping bits not equal
1073 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
1074 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001075 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
1076 return False # Both specified, and not equal
1077 elif delf:
1078 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001079 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
1080 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001081 if self.match.nw_tos != x.match.nw_tos:
1082 return False # Both specified, and not equal
1083 elif delf:
1084 return False # Receiver more specific
1085 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -07001086
1087 def to_flow_mod_msg(self, msg):
1088 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -07001089 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001090 msg.idle_timeout = self.idle_timeout
1091 msg.hard_timeout = self.hard_timeout
1092 msg.priority = self.priority
1093 msg.actions = self.actions
1094 return msg
1095
1096 def from_flow_stat(self, msg):
1097 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -07001098 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001099 self.idle_timeout = msg.idle_timeout
1100 self.hard_timeout = msg.hard_timeout
1101 self.priority = msg.priority
1102 self.actions = msg.actions
1103
rootf6af1672012-04-06 09:46:29 -07001104 def from_flow_rem(self, msg):
1105 self.match = msg.match
1106 self.idle_timeout = msg.idle_timeout
1107 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -07001108
Howard Pershc7963582012-03-29 10:02:59 -07001109
rootf6af1672012-04-06 09:46:29 -07001110class Flow_Tbl:
1111 def clear(self):
1112 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001113
rootf6af1672012-04-06 09:46:29 -07001114 def __init__(self):
1115 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001116
rootf6af1672012-04-06 09:46:29 -07001117 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001118 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001119
1120 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001121 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001122
1123 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001124 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001125
1126 def values(self):
1127 return self.dict.values()
1128
1129 def count(self):
1130 return len(self.dict)
1131
1132 def rand(self, sw, fi, num_flows):
1133 self.clear()
1134 i = 0
1135 tbl = 0
1136 j = 0
1137 while i < num_flows:
1138 fc = Flow_Cfg()
1139 fc.rand(fi, \
1140 sw.tbl_stats.stats[tbl].wildcards, \
1141 sw.sw_features.actions, \
1142 sw.valid_ports \
1143 )
1144 fc = fc.canonical()
1145 if self.find(fc):
1146 continue
1147 fc.send_rem = False
1148 self.insert(fc)
1149 i = i + 1
1150 j = j + 1
1151 if j >= sw.tbl_stats.stats[tbl].max_entries:
1152 tbl = tbl + 1
1153 j = 0
1154
1155
Howard Persh3340d452012-04-06 16:45:21 -07001156error_msgs = []
1157removed_msgs = []
1158
1159def error_handler(self, msg, rawmsg):
Dan Talayco910a8282012-04-07 00:05:20 -07001160 fq_logger.debug("Got an ERROR message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001161 % (msg.type, msg.code) \
1162 )
Howard Persh07d99e62012-04-09 15:26:57 -07001163 fq_logger.debug("Message header:")
1164 fq_logger.debug(msg.header.show())
Howard Persh3340d452012-04-06 16:45:21 -07001165 global error_msgs
1166 error_msgs.append(msg)
1167 pass
1168
1169def removed_handler(self, msg, rawmsg):
Dan Talayco910a8282012-04-07 00:05:20 -07001170 fq_logger.debug("Got a REMOVED message")
Howard Persh07d99e62012-04-09 15:26:57 -07001171 fq_logger.debug("Message header:")
1172 fq_logger.debug(msg.header.show())
Howard Persh3340d452012-04-06 16:45:21 -07001173 global removed_msgs
1174 removed_msgs.append(msg)
1175 pass
1176
rootf6af1672012-04-06 09:46:29 -07001177class Switch:
1178 # Members:
1179 # controller - switch's test controller
1180 # sw_features - switch's OFPT_FEATURES_REPLY message
1181 # valid_ports - list of valid port numbers
1182 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1183 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1184 # flow_tbl - (test's idea of) switch's flow table
1185
1186 def __init__(self):
1187 self.controller = None
1188 self.sw_features = None
1189 self.valid_ports = []
1190 self.tbl_stats = None
1191 self.flow_stats = None
1192 self.flow_tbl = Flow_Tbl()
1193
Howard Persh3340d452012-04-06 16:45:21 -07001194 def controller_set(self, controller):
1195 self.controller = controller
1196 # Register error message handler
1197 global error_msgs
1198 error_msgs = []
1199 controller.register(ofp.OFPT_ERROR, error_handler)
1200 controller.register(ofp.OFPT_FLOW_REMOVED, removed_handler)
1201
rootf6af1672012-04-06 09:46:29 -07001202 def features_get(self):
1203 # Get switch features
1204 request = message.features_request()
1205 (self.sw_features, pkt) = self.controller.transact(request, timeout=2)
1206 if self.sw_features is None:
1207 return False
1208 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Howard Persh3340d452012-04-06 16:45:21 -07001209 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1210 # is that universal?
1211
1212 # TBD - There seems to be variability in which switches support which
1213 # ports; need to sort that out
1214 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1215# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1216# ofp.OFPP_NORMAL, \
1217# ofp.OFPP_FLOOD, \
1218# ofp.OFPP_ALL, \
1219# ofp.OFPP_CONTROLLER \
1220# ] \
1221# )
Howard Persh07d99e62012-04-09 15:26:57 -07001222 actions_override = test_param_get(fq_config, "actions", -1)
1223 if actions_override != -1:
1224 self.sw_features.actions = actions_override
Howard Pershc1199d52012-04-11 14:21:32 -07001225 ports_override = test_param_get(fq_config, "ports", [])
1226 if ports_override != []:
1227 self.valid_ports = ports_override
Howard Persh07d99e62012-04-09 15:26:57 -07001228
rootf6af1672012-04-06 09:46:29 -07001229 return True
1230
1231 def tbl_stats_get(self):
1232 # Get table stats
Howard Persh680b92a2012-03-31 13:34:35 -07001233 request = message.table_stats_request()
rootf6af1672012-04-06 09:46:29 -07001234 (self.tbl_stats, pkt) = self.controller.transact(request, timeout=2)
Howard Persh07d99e62012-04-09 15:26:57 -07001235 if self.tbl_stats is None:
1236 return False
1237 for ts in self.tbl_stats.stats:
1238 wildcards_override = test_param_get(fq_config, "wildcards", -1)
1239 if wildcards_override != -1:
1240 ts.wildcards = wildcards_override
1241 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001242
Howard Pershc1199d52012-04-11 14:21:32 -07001243 def flow_stats_get(self, limit = 10000):
rootf6af1672012-04-06 09:46:29 -07001244 request = message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -07001245 query_match = ofp.ofp_match()
1246 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001247 request.match = query_match
1248 request.table_id = 0xff
1249 request.out_port = ofp.OFPP_NONE;
Howard Persh3340d452012-04-06 16:45:21 -07001250 if self.controller.message_send(request) == -1:
1251 return False
1252 # <TBD>
1253 # Glue together successive reponse messages for stats reply.
1254 # Looking at the "more" flag and performing re-assembly
1255 # should be a part of the infrastructure.
1256 # </TBD>
1257 n = 0
1258 while True:
Howard Persh07d99e62012-04-09 15:26:57 -07001259 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY, 4)
Howard Persh3340d452012-04-06 16:45:21 -07001260 if resp is None:
Howard Pershc1199d52012-04-11 14:21:32 -07001261 return False # Did not get expected response
Howard Persh3340d452012-04-06 16:45:21 -07001262 if n == 0:
1263 self.flow_stats = resp
1264 else:
1265 self.flow_stats.stats.extend(resp.stats)
1266 n = n + 1
Howard Pershc1199d52012-04-11 14:21:32 -07001267 if len(self.flow_stats.stats) > limit:
1268 fq_logger.error("Too many flows returned")
1269 return False
1270 if (resp.flags & 1) == 0:
1271 break # No more responses expected
Howard Persh3340d452012-04-06 16:45:21 -07001272 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001273
rootf6af1672012-04-06 09:46:29 -07001274 def flow_add(self, flow_cfg, overlapf = False):
Howard Persh680b92a2012-03-31 13:34:35 -07001275 flow_mod_msg = message.flow_mod()
1276 flow_mod_msg.command = ofp.OFPFC_ADD
1277 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001278 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001279 if overlapf:
1280 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001281 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001282 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Howard Persh07d99e62012-04-09 15:26:57 -07001283 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Pershc1199d52012-04-11 14:21:32 -07001284 fq_logger.debug("Sending flow_mod(add), xid=%d"
1285 % (flow_mod_msg.header.xid)
1286 )
rootf6af1672012-04-06 09:46:29 -07001287 return (self.controller.message_send(flow_mod_msg) != -1)
Howard Persh680b92a2012-03-31 13:34:35 -07001288
rootf6af1672012-04-06 09:46:29 -07001289 def flow_mod(self, flow_cfg, strictf):
Howard Persh680b92a2012-03-31 13:34:35 -07001290 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001291 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf \
1292 else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -07001293 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001294 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001295 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Pershc1199d52012-04-11 14:21:32 -07001296 fq_logger.debug("Sending flow_mod(mod), xid=%d"
1297 % (flow_mod_msg.header.xid)
1298 )
rootf6af1672012-04-06 09:46:29 -07001299 return (self.controller.message_send(flow_mod_msg) != -1)
1300
1301 def flow_del(self, flow_cfg, strictf):
1302 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001303 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf \
1304 else ofp.OFPFC_DELETE
rootf6af1672012-04-06 09:46:29 -07001305 flow_mod_msg.buffer_id = 0xffffffff
1306 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001307 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001308 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001309 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Howard Pershc1199d52012-04-11 14:21:32 -07001310 fq_logger.debug("Sending flow_mod(del), xid=%d"
1311 % (flow_mod_msg.header.xid)
1312 )
rootf6af1672012-04-06 09:46:29 -07001313 return (self.controller.message_send(flow_mod_msg) != -1)
1314
1315 def barrier(self):
1316 barrier = message.barrier_request()
Howard Persh07d99e62012-04-09 15:26:57 -07001317 (resp, pkt) = self.controller.transact(barrier, 20)
rootf6af1672012-04-06 09:46:29 -07001318 return (resp is not None)
1319
Howard Persh3340d452012-04-06 16:45:21 -07001320 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001321 result = True
Howard Persh3340d452012-04-06 16:45:21 -07001322 global error_msgs
Dan Talayco910a8282012-04-07 00:05:20 -07001323 fq_logger.debug("Expecting %d error messages" % (num_exp))
Howard Persh3340d452012-04-06 16:45:21 -07001324 num_got = len(error_msgs)
Dan Talayco910a8282012-04-07 00:05:20 -07001325 fq_logger.debug("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001326 if num_got != num_exp:
Dan Talayco910a8282012-04-07 00:05:20 -07001327 fq_logger.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001328 result = False
1329 if num_exp == 0:
1330 return result
1331 elif num_exp == 1:
Dan Talayco910a8282012-04-07 00:05:20 -07001332 fq_logger.debug("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001333 % (type, code) \
1334 )
1335 f = False
1336 for e in error_msgs:
1337 if e.type == type and e.code == code:
Dan Talayco910a8282012-04-07 00:05:20 -07001338 fq_logger.debug("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001339 f = True
1340 if not f:
Dan Talayco910a8282012-04-07 00:05:20 -07001341 fq_logger.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001342 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001343 else:
Dan Talayco910a8282012-04-07 00:05:20 -07001344 fq_logger.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001345 result = False
1346 return result
1347
Howard Persh3340d452012-04-06 16:45:21 -07001348 def removed_verify(self, num_exp):
1349 result = True
1350 global removed_msgs
Dan Talayco910a8282012-04-07 00:05:20 -07001351 fq_logger.debug("Expecting %d removed messages" % (num_exp))
Howard Persh3340d452012-04-06 16:45:21 -07001352 num_got = len(removed_msgs)
Dan Talayco910a8282012-04-07 00:05:20 -07001353 fq_logger.debug("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001354 if num_got != num_exp:
Dan Talayco910a8282012-04-07 00:05:20 -07001355 fq_logger.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001356 result = False
1357 if num_exp < 2:
1358 return result
Dan Talayco910a8282012-04-07 00:05:20 -07001359 fq_logger.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001360 return False
1361
1362
Dan Talayco910a8282012-04-07 00:05:20 -07001363# fq_logger.debug("Expecting %d error messages" % (num))
Howard Persh3340d452012-04-06 16:45:21 -07001364# if num > 0:
Dan Talayco910a8282012-04-07 00:05:20 -07001365# fq_logger.debug("with type=%d code=%d" % (type, code))
Howard Persh3340d452012-04-06 16:45:21 -07001366# result = True
1367# n = 0
1368# while True:
1369# (errmsg, pkt) = self.controller.poll(ofp.OFPT_ERROR, 1)
1370# if errmsg is None:
1371# break
Dan Talayco910a8282012-04-07 00:05:20 -07001372# fq_logger.debug("Got error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001373# % (errmsg.type, errmsg.code) \
1374# )
1375# if num == 0 or errmsg.type != type or errmsg.code != code:
Dan Talayco910a8282012-04-07 00:05:20 -07001376# fq_logger.debug("Unexpected error message")
Howard Persh3340d452012-04-06 16:45:21 -07001377# result = False
1378# n = n + 1
1379# if n != num:
Dan Talayco910a8282012-04-07 00:05:20 -07001380# fq_logger.error("Received %d error messages" % (n))
Howard Persh3340d452012-04-06 16:45:21 -07001381# result = False
1382# return result
1383
rootf6af1672012-04-06 09:46:29 -07001384 def flow_tbl_verify(self):
1385 result = True
1386
1387 # Verify flow count in switch
Dan Talayco910a8282012-04-07 00:05:20 -07001388 fq_logger.debug("Reading table stats")
1389 fq_logger.debug("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001390 if not self.tbl_stats_get():
Dan Talayco910a8282012-04-07 00:05:20 -07001391 fq_logger.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001392 return False
1393 n = 0
1394 for ts in self.tbl_stats.stats:
1395 n = n + ts.active_count
Dan Talayco910a8282012-04-07 00:05:20 -07001396 fq_logger.debug("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001397 % (n) \
1398 )
1399 if n != self.flow_tbl.count():
Dan Talayco910a8282012-04-07 00:05:20 -07001400 fq_logger.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001401 result = False
1402
1403 # Read flows from switch
Dan Talayco910a8282012-04-07 00:05:20 -07001404 fq_logger.debug("Retrieving flows from switch")
1405 fq_logger.debug("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001406 if not self.flow_stats_get():
Dan Talayco910a8282012-04-07 00:05:20 -07001407 fq_logger.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001408 return False
Dan Talayco910a8282012-04-07 00:05:20 -07001409 fq_logger.debug("Retrieved %d flows" % (len(self.flow_stats.stats)))
rootf6af1672012-04-06 09:46:29 -07001410
1411 # Verify flows returned by switch
1412
1413 if len(self.flow_stats.stats) != self.flow_tbl.count():
Dan Talayco910a8282012-04-07 00:05:20 -07001414 fq_logger.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001415 result = False
1416
Dan Talayco910a8282012-04-07 00:05:20 -07001417 fq_logger.debug("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001418 for fc in self.flow_tbl.values():
1419 fc.matched = False
1420 for fs in self.flow_stats.stats:
1421 flow_in = Flow_Cfg()
1422 flow_in.from_flow_stat(fs)
Dan Talayco910a8282012-04-07 00:05:20 -07001423 fq_logger.debug("Received flow:")
1424 fq_logger.debug(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001425 fc = self.flow_tbl.find(flow_in)
1426 if fc is None:
Dan Talayco910a8282012-04-07 00:05:20 -07001427 fq_logger.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001428 result = False
1429 elif fc.matched:
Dan Talayco910a8282012-04-07 00:05:20 -07001430 fq_logger.error("re-matches defined flow:")
1431 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07001432 result = False
1433 else:
Dan Talayco910a8282012-04-07 00:05:20 -07001434 fq_logger.debug("matched")
rootf6af1672012-04-06 09:46:29 -07001435 if not flow_in == fc:
Dan Talayco910a8282012-04-07 00:05:20 -07001436 fq_logger.error("Non-key portions of flow do not match")
rootf6af1672012-04-06 09:46:29 -07001437 result = False
1438 fc.matched = True
1439 for fc in self.flow_tbl.values():
1440 if not fc.matched:
Dan Talayco910a8282012-04-07 00:05:20 -07001441 fq_logger.error("Defined flow:")
1442 fq_logger.error(str(fc))
1443 fq_logger.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001444 result = False
1445
1446 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001447
Howard Persh07d99e62012-04-09 15:26:57 -07001448# FLOW ADD 5
1449#
1450# OVERVIEW
1451# Add flows to switch, read back and verify flow configurations
1452#
1453# PURPOSE
1454# - Test acceptance of flow adds
1455# - Test ability of switch to process additions to flow table in random
1456# priority order
1457# - Test correctness of flow configuration responses
1458#
1459# PARAMETERS
1460#
1461# Name: num_flows
1462# Type: number
1463# Description:
1464# Number of flows to define; 0 => maximum number of flows, as determined
1465# from switch capabilities
1466# Default: 100
1467#
1468# PROCESS
1469# 1. Delete all flows from switch
1470# 2. Generate <num_flows> distinct flow configurations
1471# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1472# 4. Verify that no OFPT_ERROR responses were generated by switch
1473# 5. Retrieve flow stats from switch
1474# 6. Compare flow configurations returned by switch
1475# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1476# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001477
rootf6af1672012-04-06 09:46:29 -07001478class Flow_Add_5(basic.SimpleProtocol):
1479 """
1480 Test FLOW_ADD_5 from draft top-half test plan
1481
1482 INPUTS
1483 num_flows - Number of flows to generate
1484 """
Howard Persh680b92a2012-03-31 13:34:35 -07001485
rootf6af1672012-04-06 09:46:29 -07001486 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001487 fq_logger.debug("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001488
Dan Talayco910a8282012-04-07 00:05:20 -07001489 num_flows = test_param_get(fq_config, "num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001490
Howard Pershc7963582012-03-29 10:02:59 -07001491 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001492
Dan Talayco910a8282012-04-07 00:05:20 -07001493 fq_logger.debug("Deleting all flows from switch")
1494 rc = delete_all_flows(self.controller, fq_logger)
Howard Pershc7963582012-03-29 10:02:59 -07001495 self.assertEqual(rc, 0, "Failed to delete all flows")
1496
rootf6af1672012-04-06 09:46:29 -07001497 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001498
Dan Talayco910a8282012-04-07 00:05:20 -07001499 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001500 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001501 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001502 self.assertTrue(sw.features_get(), "Get switch features failed")
1503 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
Howard Pershc7963582012-03-29 10:02:59 -07001504
rootf6af1672012-04-06 09:46:29 -07001505 if num_flows == 0:
1506 # Number of flows requested was 0
1507 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001508
rootf6af1672012-04-06 09:46:29 -07001509 for ts in sw.tbl_stats.stats:
1510 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001511
Dan Talayco910a8282012-04-07 00:05:20 -07001512 fq_logger.debug("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001513
1514 # Dream up some flow information, i.e. space to chose from for
1515 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001516
rootf6af1672012-04-06 09:46:29 -07001517 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001518 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001519
rootf6af1672012-04-06 09:46:29 -07001520 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001521
rootf6af1672012-04-06 09:46:29 -07001522 ft = Flow_Tbl()
1523 ft.rand(sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001524
rootf6af1672012-04-06 09:46:29 -07001525 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001526
Dan Talayco910a8282012-04-07 00:05:20 -07001527 fq_logger.debug("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001528 for fc in ft.values(): # Randomizes order of sending
Dan Talayco910a8282012-04-07 00:05:20 -07001529 fq_logger.debug("Adding flow:")
1530 fq_logger.debug(str(fc));
rootf6af1672012-04-06 09:46:29 -07001531 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001532
rootf6af1672012-04-06 09:46:29 -07001533 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001534
rootf6af1672012-04-06 09:46:29 -07001535 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001536
rootf6af1672012-04-06 09:46:29 -07001537 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001538
rootf6af1672012-04-06 09:46:29 -07001539 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001540
rootf6af1672012-04-06 09:46:29 -07001541 if not sw.errors_verify(0):
1542 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001543
rootf6af1672012-04-06 09:46:29 -07001544 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001545
rootf6af1672012-04-06 09:46:29 -07001546 sw.flow_tbl = ft
1547 if not sw.flow_tbl_verify():
1548 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001549
rootf6af1672012-04-06 09:46:29 -07001550 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07001551 fq_logger.debug("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001552
Howard Pershc7963582012-03-29 10:02:59 -07001553
Howard Persh07d99e62012-04-09 15:26:57 -07001554# FLOW ADD 5_1
1555#
1556# OVERVIEW
1557# Verify handling of non-canonical flows
1558#
1559# PURPOSE
1560# - Test that switch detects and correctly responds to a non-canonical flow
1561# definition. A canonical flow is one that satisfies all match qualifier
1562# dependencies; a non-canonical flow is one that does not.
1563#
1564# PARAMETERS
1565# - None
1566#
1567# PROCESS
1568# 1. Delete all flows from switch
1569# 2. Generate 1 flow definition, which is different from its canonicalization
1570# 3. Send flow to switch
1571# 4. Retrieve flow from switch
1572# 5. Compare returned flow to canonical form of defined flow
1573# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1574
1575# Disabled.
1576# Should be DUT dependent.
1577test_prio["Flow_Add_5_1"] = -1
1578
rootf6af1672012-04-06 09:46:29 -07001579class Flow_Add_5_1(basic.SimpleProtocol):
1580 """
1581 Test FLOW_ADD_5.1 from draft top-half test plan
1582
1583 INPUTS
1584 None
1585 """
1586
1587 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001588 fq_logger.debug("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001589
Dan Talayco910a8282012-04-07 00:05:20 -07001590 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001591
1592 # Clear all flows from switch
1593
Dan Talayco910a8282012-04-07 00:05:20 -07001594 fq_logger.debug("Deleting all flows from switch")
1595 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001596 self.assertEqual(rc, 0, "Failed to delete all flows")
1597
1598 # Get switch capabilites
1599
Dan Talayco910a8282012-04-07 00:05:20 -07001600 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001601 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001602 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001603 self.assertTrue(sw.features_get(), "Get switch features failed")
1604 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1605
1606 # Dream up some flow information, i.e. space to chose from for
1607 # random flow parameter generation
1608
1609 fi = Flow_Info()
1610 fi.rand(10)
1611
1612 # Dream up a flow config that will be canonicalized by the switch
1613
1614 while True:
1615 fc = Flow_Cfg()
1616 fc.rand(fi, \
1617 sw.tbl_stats.stats[0].wildcards, \
1618 sw.sw_features.actions, \
1619 sw.valid_ports \
1620 )
1621 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001622 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001623 break
1624
1625 ft = Flow_Tbl()
1626 ft.insert(fcc)
1627
1628 # Send it to the switch
1629
Dan Talayco910a8282012-04-07 00:05:20 -07001630 fq_logger.debug("Sending flow add to switch:")
1631 fq_logger.debug(str(fc))
1632 fq_logger.debug("should be canonicalized as:")
1633 fq_logger.debug(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001634 fc.send_rem = False
1635 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1636
1637 # Do barrier, to make sure all flows are in
1638
1639 self.assertTrue(sw.barrier(), "Barrier failed")
1640
1641 result = True
1642
1643 # Check for any error messages
1644
1645 if not sw.errors_verify(0):
1646 result = False
1647
1648 # Verify flow table
1649
1650 sw.flow_tbl = ft
1651 if not sw.flow_tbl_verify():
1652 result = False
1653
1654 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07001655 fq_logger.debug("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001656
1657
Howard Persh07d99e62012-04-09 15:26:57 -07001658# FLOW ADD 6
1659#
1660# OVERVIEW
1661# Test flow table capacity
1662#
1663# PURPOSE
1664# - Test switch can accept as many flow definitions as it claims
1665# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1666# - Test that attempting to create flows beyond capacity does not corrupt
1667# flow table
1668#
1669# PARAMETERS
1670# None
1671#
1672# PROCESS
1673# 1. Delete all flows from switch
1674# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1675# to determine flow table size, N
1676# 3. Generate (N + 1) distinct flow configurations
1677# 4. Send N flow adds to switch, for flows generated in step 3 above
1678# 5. Verify flow table in switch
1679# 6. Send one more flow add to switch
1680# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1681# response was generated by switch, for last flow mod sent
1682# 7. Retrieve flow stats from switch
1683# 8. Verify flow table in switch
1684# 9. Test PASSED iff:
1685# - error message received, for correct flow
1686# - last flow definition sent to switch is not in flow table
1687# else test FAILED
1688
Howard Persh3340d452012-04-06 16:45:21 -07001689# Disabled because of bogus capacity reported by OVS.
1690# Should be DUT dependent.
1691test_prio["Flow_Add_6"] = -1
1692
rootf6af1672012-04-06 09:46:29 -07001693class Flow_Add_6(basic.SimpleProtocol):
1694 """
1695 Test FLOW_ADD_6 from draft top-half test plan
1696
1697 INPUTS
1698 num_flows - Number of flows to generate
1699 """
Howard Pershc7963582012-03-29 10:02:59 -07001700
1701 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001702 fq_logger.debug("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001703
rootf6af1672012-04-06 09:46:29 -07001704 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001705
Dan Talayco910a8282012-04-07 00:05:20 -07001706 fq_logger.debug("Deleting all flows from switch")
1707 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001708 self.assertEqual(rc, 0, "Failed to delete all flows")
1709
1710 # Get switch capabilites
1711
Dan Talayco910a8282012-04-07 00:05:20 -07001712 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001713 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001714 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001715 self.assertTrue(sw.features_get(), "Get switch features failed")
1716 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1717
root2843d2b2012-04-06 10:27:46 -07001718 num_flows = 0
rootf6af1672012-04-06 09:46:29 -07001719 for ts in sw.tbl_stats.stats:
1720 num_flows = num_flows + ts.max_entries
1721
Dan Talayco910a8282012-04-07 00:05:20 -07001722 fq_logger.debug("Switch capacity is %d flows" % (num_flows))
1723 fq_logger.debug("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001724
1725 # Dream up some flow information, i.e. space to chose from for
1726 # random flow parameter generation
1727
1728 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001729 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001730
1731 # Create a flow table, to switch's capacity
1732
1733 ft = Flow_Tbl()
1734 ft.rand(sw, fi, num_flows)
1735
1736 # Send flow table to switch
1737
Dan Talayco910a8282012-04-07 00:05:20 -07001738 fq_logger.debug("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001739 for fc in ft.values(): # Randomizes order of sending
Dan Talayco910a8282012-04-07 00:05:20 -07001740 fq_logger.debug("Adding flow:")
1741 fq_logger.debug(str(fc));
rootf6af1672012-04-06 09:46:29 -07001742 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1743
1744 # Do barrier, to make sure all flows are in
1745
1746 self.assertTrue(sw.barrier(), "Barrier failed")
1747
1748 result = True
1749
1750 # Check for any error messages
1751
1752 if not sw.errors_verify(0):
1753 result = False
1754
1755 # Dream up one more flow
1756
Dan Talayco910a8282012-04-07 00:05:20 -07001757 fq_logger.debug("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001758 while True:
1759 fc = Flow_Cfg()
1760 fc.rand(fi, \
Howard Persh07d99e62012-04-09 15:26:57 -07001761 sw.tbl_stats.stats[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001762 sw.sw_features.actions, \
1763 sw.valid_ports \
1764 )
1765 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001766 if not ft.find(fc):
1767 break
rootf6af1672012-04-06 09:46:29 -07001768
1769 # Send one-more flow
1770
1771 fc.send_rem = False
Dan Talayco910a8282012-04-07 00:05:20 -07001772 fq_logger.debug("Sending flow add switch")
1773 fq_logger.debug(str(fc));
rootf6af1672012-04-06 09:46:29 -07001774 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1775
1776 # Do barrier, to make sure all flows are in
1777
1778 self.assertTrue(sw.barrier(), "Barrier failed")
1779
1780 # Check for expected error message
1781
1782 if not sw.errors_verify(1, \
1783 ofp.OFPET_FLOW_MOD_FAILED, \
1784 ofp.OFPFMFC_ALL_TABLES_FULL \
1785 ):
1786 result = False
1787
1788 # Verify flow table
1789
1790 sw.flow_tbl = ft
1791 if not sw.flow_tbl_verify():
1792 result = False
1793
1794 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07001795 fq_logger.debug("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001796
1797
Howard Persh07d99e62012-04-09 15:26:57 -07001798# FLOW ADD 7
1799#
1800# OVERVIEW
1801# Test flow redefinition
1802#
1803# PURPOSE
1804# Verify that successive flow adds with same priority and match criteria
1805# overwrite in flow table
1806#
1807# PARAMETERS
1808# None
1809#
1810# PROCESS
1811# 1. Delete all flows from switch
1812# 2. Generate flow definition F1
1813# 3. Generate flow definition F2, with same key (priority and match) as F1,
1814# but with different actions
1815# 4. Send flow adds for F1 and F2 to switch
1816# 5. Verify flow definitions in switch
1817# 6. Test PASSED iff 1 flow returned by switch, matching configuration of F2;
1818# else test FAILED
1819
rootf6af1672012-04-06 09:46:29 -07001820class Flow_Add_7(basic.SimpleProtocol):
1821 """
1822 Test FLOW_ADD_7 from draft top-half test plan
1823
1824 INPUTS
1825 None
1826 """
1827
1828 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001829 fq_logger.debug("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001830
1831 # Clear all flows from switch
1832
Dan Talayco910a8282012-04-07 00:05:20 -07001833 fq_logger.debug("Deleting all flows from switch")
1834 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001835 self.assertEqual(rc, 0, "Failed to delete all flows")
1836
1837 # Get switch capabilites
1838
Dan Talayco910a8282012-04-07 00:05:20 -07001839 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001840 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001841 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001842 self.assertTrue(sw.features_get(), "Get switch features failed")
1843 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1844
1845 # Dream up some flow information, i.e. space to chose from for
1846 # random flow parameter generation
1847
1848 fi = Flow_Info()
1849 fi.rand(10)
1850
1851 # Dream up a flow config
1852
1853 fc = Flow_Cfg()
1854 fc.rand(fi, \
1855 sw.tbl_stats.stats[0].wildcards, \
1856 sw.sw_features.actions, \
1857 sw.valid_ports \
1858 )
1859 fc = fc.canonical()
1860
1861 # Send it to the switch
1862
Dan Talayco910a8282012-04-07 00:05:20 -07001863 fq_logger.debug("Sending flow add to switch:")
1864 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07001865 ft = Flow_Tbl()
1866 fc.send_rem = False
1867 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1868 ft.insert(fc)
1869
1870 # Dream up some different actions, with the same flow key
1871
1872 fc2 = copy.deepcopy(fc)
1873 while True:
1874 fc2.rand_mod(fi, \
1875 sw.sw_features.actions, \
1876 sw.valid_ports \
1877 )
1878 if fc2 != fc:
1879 break
1880
1881 # Send that to the switch
1882
Dan Talayco910a8282012-04-07 00:05:20 -07001883 fq_logger.debug("Sending flow add to switch:")
1884 fq_logger.debug(str(fc2))
rootf6af1672012-04-06 09:46:29 -07001885 fc2.send_rem = False
1886 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
1887 ft.insert(fc2)
1888
1889 # Do barrier, to make sure all flows are in
1890
1891 self.assertTrue(sw.barrier(), "Barrier failed")
1892
1893 result = True
1894
1895 # Check for any error messages
1896
1897 if not sw.errors_verify(0):
1898 result = False
1899
1900 # Verify flow table
1901
1902 sw.flow_tbl = ft
1903 if not sw.flow_tbl_verify():
1904 result = False
1905
1906 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07001907 fq_logger.debug("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001908
1909
Howard Persh07d99e62012-04-09 15:26:57 -07001910# FLOW ADD 8
1911#
1912# OVERVIEW
1913# Add overlapping flows to switch, verify that overlapping flows are rejected
1914#
1915# PURPOSE
1916# - Test detection of overlapping flows by switch
1917# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
1918# - Test rejection of overlapping flows
1919# - Test defining overlapping flows does not corrupt flow table
1920#
1921# PARAMETERS
1922# None
1923#
1924# PROCESS
1925# 1. Delete all flows from switch
1926# 2. Generate flow definition F1
1927# 3. Generate flow definition F2, with key overlapping F1
1928# 4. Send flow add to switch, for F1
1929# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
1930# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
1931# was generated by switch
1932# 7. Verifiy flows configured in swtich
1933# 8. Test PASSED iff:
1934# - error message received, for overlapping flow
1935# - overlapping flow is not in flow table
1936# else test FAILED
1937
rootf6af1672012-04-06 09:46:29 -07001938class Flow_Add_8(basic.SimpleProtocol):
1939 """
1940 Test FLOW_ADD_8 from draft top-half test plan
1941
1942 INPUTS
1943 None
1944 """
1945
1946 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001947 fq_logger.debug("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001948
1949 # Clear all flows from switch
1950
Dan Talayco910a8282012-04-07 00:05:20 -07001951 fq_logger.debug("Deleting all flows from switch")
1952 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001953 self.assertEqual(rc, 0, "Failed to delete all flows")
1954
1955 # Get switch capabilites
1956
Dan Talayco910a8282012-04-07 00:05:20 -07001957 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001958 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001959 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001960 self.assertTrue(sw.features_get(), "Get switch features failed")
1961 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1962
1963 # Dream up some flow information, i.e. space to chose from for
1964 # random flow parameter generation
1965
1966 fi = Flow_Info()
1967 fi.rand(10)
1968
1969 # Dream up a flow config, with at least 1 qualifier specified
1970
1971 fc = Flow_Cfg()
1972 while True:
1973 fc.rand(fi, \
1974 sw.tbl_stats.stats[0].wildcards, \
1975 sw.sw_features.actions, \
1976 sw.valid_ports \
1977 )
1978 fc = fc.canonical()
1979 if fc.match.wildcards != ofp.OFPFW_ALL:
1980 break
1981
1982 # Send it to the switch
1983
Dan Talayco910a8282012-04-07 00:05:20 -07001984 fq_logger.debug("Sending flow add to switch:")
1985 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07001986 ft = Flow_Tbl()
1987 fc.send_rem = False
1988 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1989 ft.insert(fc)
1990
1991 # Wildcard out one qualifier that was specified, to create an
1992 # overlapping flow
1993
1994 fc2 = copy.deepcopy(fc)
1995 for wi in shuffle(range(len(all_wildcards_list))):
1996 w = all_wildcards_list[wi]
1997 if (fc2.match.wildcards & w) == 0:
1998 break
1999 if w == ofp.OFPFW_NW_SRC_MASK:
2000 w = ofp.OFPFW_NW_SRC_ALL
2001 wn = "OFPFW_NW_SRC"
2002 elif w == ofp.OFPFW_NW_DST_MASK:
2003 w = ofp.OFPFW_NW_DST_ALL
2004 wn = "OFPFW_NW_DST"
2005 else:
2006 wn = all_wildcard_names[w]
Dan Talayco910a8282012-04-07 00:05:20 -07002007 fq_logger.debug("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07002008 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07002009 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07002010
2011 # Send that to the switch, with overlap checking
2012
Dan Talayco910a8282012-04-07 00:05:20 -07002013 fq_logger.debug("Sending flow add to switch:")
2014 fq_logger.debug(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002015 fc2.send_rem = False
2016 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
2017
2018 # Do barrier, to make sure all flows are in
2019 self.assertTrue(sw.barrier(), "Barrier failed")
2020
2021 result = True
2022
2023 # Check for expected error message
2024
2025 if not sw.errors_verify(1, \
2026 ofp.OFPET_FLOW_MOD_FAILED, \
2027 ofp.OFPFMFC_OVERLAP \
2028 ):
2029 result = False
2030
2031 # Verify flow table
2032
2033 sw.flow_tbl = ft
2034 if not sw.flow_tbl_verify():
2035 result = False
2036
2037 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07002038 fq_logger.debug("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002039
2040
Howard Persh07d99e62012-04-09 15:26:57 -07002041# FLOW MODIFY 1
2042#
2043# OVERVIEW
2044# Strict modify of single existing flow
2045#
2046# PURPOSE
2047# - Verify that strict flow modify operates only on specified flow
2048# - Verify that flow is correctly modified
2049#
2050# PARAMETERS
2051# None
2052#
2053# PROCESS
2054# 1. Delete all flows from switch
2055# 2. Generate 1 flow F
2056# 3. Send flow add to switch, for flow F
2057# 4. Generate new action list for flow F, yielding F'
2058# 5. Send strict flow modify to switch, for flow F'
2059# 6. Verify flow table in switch
2060# 7. Test PASSED iff flow returned by switch is F'; else FAILED
2061
rootf6af1672012-04-06 09:46:29 -07002062class Flow_Mod_1(basic.SimpleProtocol):
2063 """
2064 Test FLOW_MOD_1 from draft top-half test plan
2065
2066 INPUTS
2067 None
2068 """
2069
2070 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07002071 fq_logger.debug("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002072
2073 # Clear all flows from switch
2074
Dan Talayco910a8282012-04-07 00:05:20 -07002075 fq_logger.debug("Deleting all flows from switch")
2076 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002077 self.assertEqual(rc, 0, "Failed to delete all flows")
2078
2079 # Get switch capabilites
2080
Dan Talayco910a8282012-04-07 00:05:20 -07002081 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002082 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002083 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002084 self.assertTrue(sw.features_get(), "Get switch features failed")
2085 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2086
2087 # Dream up some flow information, i.e. space to chose from for
2088 # random flow parameter generation
2089
2090 fi = Flow_Info()
2091 fi.rand(10)
2092
2093 # Dream up a flow config
2094
2095 fc = Flow_Cfg()
2096 fc.rand(fi, \
2097 sw.tbl_stats.stats[0].wildcards, \
2098 sw.sw_features.actions, \
2099 sw.valid_ports \
2100 )
2101 fc = fc.canonical()
2102
2103 # Send it to the switch
2104
Dan Talayco910a8282012-04-07 00:05:20 -07002105 fq_logger.debug("Sending flow add to switch:")
2106 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07002107 ft = Flow_Tbl()
2108 fc.send_rem = False
2109 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2110 ft.insert(fc)
2111
2112 # Dream up some different actions, with the same flow key
2113
2114 fc2 = copy.deepcopy(fc)
2115 while True:
2116 fc2.rand_mod(fi, \
2117 sw.sw_features.actions, \
2118 sw.valid_ports \
2119 )
2120 if fc2 != fc:
2121 break
2122
Howard Persh07d99e62012-04-09 15:26:57 -07002123 fc2.cookie = fc.cookie
2124
rootf6af1672012-04-06 09:46:29 -07002125 # Send that to the switch
2126
Dan Talayco910a8282012-04-07 00:05:20 -07002127 fq_logger.debug("Sending strict flow mod to switch:")
2128 fq_logger.debug(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002129 fc2.send_rem = False
2130 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2131 ft.insert(fc2)
2132
2133 # Do barrier, to make sure all flows are in
2134
2135 self.assertTrue(sw.barrier(), "Barrier failed")
2136
2137 result = True
2138
2139 # Check for any error messages
2140
2141 if not sw.errors_verify(0):
2142 result = False
2143
2144 # Verify flow table
2145
2146 sw.flow_tbl = ft
2147 if not sw.flow_tbl_verify():
2148 result = False
2149
2150 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07002151 fq_logger.debug("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002152
Howard Persh07d99e62012-04-09 15:26:57 -07002153
2154# FLOW MODIFY 2
2155#
2156# OVERVIEW
2157# Loose modify of mutiple flows
2158#
2159# PURPOSE
2160# - Verify that loose flow modify operates only on matching flows
2161# - Verify that matching flows are correctly modified
2162#
2163# PARAMETERS
2164# Name: num_flows
2165# Type: number
2166# Description:
2167# Number of flows to define
2168# Default: 100
2169#
2170# PROCESS
2171# 1. Delete all flows from switch
2172# 2. Generate <num_flows> distinct flow configurations
2173# 3. Send <num_flows> flow adds to switch
2174# 4. Pick 1 defined flow F at random
2175# 5. Create overlapping loose flow mod match criteria by repeatedly
2176# wildcarding out qualifiers in match of F => F',
2177# and create new actions list A' for F'
2178# 6. Send loose flow modify for F' to switch
2179# 7. Verify flow table in swtich
2180# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2181# are returned in step 7 above, each with correct (original or modified)
2182# action list;
2183# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002184
2185class Flow_Mod_2(basic.SimpleProtocol):
2186 """
2187 Test FLOW_MOD_2 from draft top-half test plan
2188
2189 INPUTS
2190 None
2191 """
2192
2193 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07002194 fq_logger.debug("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002195
Dan Talayco910a8282012-04-07 00:05:20 -07002196 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002197
2198 # Clear all flows from switch
2199
Dan Talayco910a8282012-04-07 00:05:20 -07002200 fq_logger.debug("Deleting all flows from switch")
2201 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002202 self.assertEqual(rc, 0, "Failed to delete all flows")
2203
2204 # Get switch capabilites
2205
Dan Talayco910a8282012-04-07 00:05:20 -07002206 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002207 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002208 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002209 self.assertTrue(sw.features_get(), "Get switch features failed")
2210 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2211
2212 # Dream up some flow information, i.e. space to chose from for
2213 # random flow parameter generation
2214
2215 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002216 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002217 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002218
2219 # Dream up some flows
2220
2221 ft = Flow_Tbl()
2222 ft.rand(sw, fi, num_flows)
2223
2224 # Send flow table to switch
2225
Dan Talayco910a8282012-04-07 00:05:20 -07002226 fq_logger.debug("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002227 for fc in ft.values(): # Randomizes order of sending
Dan Talayco910a8282012-04-07 00:05:20 -07002228 fq_logger.debug("Adding flow:")
2229 fq_logger.debug(str(fc));
rootf6af1672012-04-06 09:46:29 -07002230 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2231
2232 # Do barrier, to make sure all flows are in
2233
2234 self.assertTrue(sw.barrier(), "Barrier failed")
2235
2236 result = True
2237
2238 # Check for any error messages
2239
2240 if not sw.errors_verify(0):
2241 result = False
2242
2243 # Verify flow table
2244
2245 sw.flow_tbl = ft
2246 if not sw.flow_tbl_verify():
2247 result = False
2248
2249 # Pick a random flow as a basis
2250
2251 mfc = copy.deepcopy(ft.values()[0])
2252 mfc.rand_mod(fi, sw.sw_features.actions, sw.valid_ports)
2253
2254 # Repeatedly wildcard qualifiers
2255
2256 for wi in shuffle(range(len(all_wildcards_list))):
2257 w = all_wildcards_list[wi]
2258 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2259 n = wildcard_get(mfc.match.wildcards, w)
2260 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002261 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2262 w, \
2263 random.randint(n + 1, 32) \
2264 )
rootf6af1672012-04-06 09:46:29 -07002265 else:
2266 continue
2267 else:
2268 if wildcard_get(mfc.match.wildcards, w) == 0:
2269 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2270 else:
2271 continue
2272 mfc = mfc.canonical()
2273
2274 # Count the number of flows that would be modified
2275
2276 n = 0
2277 for fc in ft.values():
2278 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2279 n = n + 1
2280
2281 # If more than 1, we found our loose delete flow spec
2282 if n > 1:
2283 break
2284
Dan Talayco910a8282012-04-07 00:05:20 -07002285 fq_logger.debug("Modifying %d flows" % (n))
2286 fq_logger.debug("Sending flow mod to switch:")
2287 fq_logger.debug(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002288 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2289
2290 # Do barrier, to make sure all flows are in
2291 self.assertTrue(sw.barrier(), "Barrier failed")
2292
2293 # Check for error message
2294
2295 if not sw.errors_verify(0):
2296 result = False
2297
2298 # Apply flow mod to local flow table
2299
2300 for fc in ft.values():
2301 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002302 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002303
2304 # Verify flow table
2305
2306 sw.flow_tbl = ft
2307 if not sw.flow_tbl_verify():
2308 result = False
2309
2310 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07002311 fq_logger.debug("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002312
2313
Howard Persh07d99e62012-04-09 15:26:57 -07002314# FLOW MODIFY 3
2315
2316# OVERVIEW
2317# Strict modify of non-existent flow
2318#
2319# PURPOSE
2320# Verify that strict modify of a non-existent flow is equivalent to a flow add
2321#
2322# PARAMETERS
2323# None
2324#
2325# PROCESS
2326# 1. Delete all flows from switch
2327# 2. Send single flow mod, as strict modify, to switch
2328# 3. Verify flow table in switch
2329# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2330
rootf6af1672012-04-06 09:46:29 -07002331class Flow_Mod_3(basic.SimpleProtocol):
2332 """
2333 Test FLOW_MOD_3 from draft top-half test plan
2334
2335 INPUTS
2336 None
2337 """
2338
2339 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07002340 fq_logger.debug("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002341
2342 # Clear all flows from switch
2343
Dan Talayco910a8282012-04-07 00:05:20 -07002344 fq_logger.debug("Deleting all flows from switch")
2345 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002346 self.assertEqual(rc, 0, "Failed to delete all flows")
2347
2348 # Get switch capabilites
2349
Dan Talayco910a8282012-04-07 00:05:20 -07002350 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002351 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002352 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002353 self.assertTrue(sw.features_get(), "Get switch features failed")
2354 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2355
2356 # Dream up some flow information, i.e. space to chose from for
2357 # random flow parameter generation
2358
2359 fi = Flow_Info()
2360 fi.rand(10)
2361
2362 # Dream up a flow config
2363
2364 fc = Flow_Cfg()
2365 fc.rand(fi, \
2366 sw.tbl_stats.stats[0].wildcards, \
2367 sw.sw_features.actions, \
2368 sw.valid_ports \
2369 )
2370 fc = fc.canonical()
2371
2372 # Send it to the switch
2373
Dan Talayco910a8282012-04-07 00:05:20 -07002374 fq_logger.debug("Sending flow mod to switch:")
2375 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07002376 ft = Flow_Tbl()
2377 fc.send_rem = False
2378 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2379 ft.insert(fc)
2380
2381 # Do barrier, to make sure all flows are in
2382
2383 self.assertTrue(sw.barrier(), "Barrier failed")
2384
2385 result = True
2386
2387 # Check for any error messages
2388
2389 if not sw.errors_verify(0):
2390 result = False
2391
2392 # Verify flow table
2393
2394 sw.flow_tbl = ft
2395 if not sw.flow_tbl_verify():
2396 result = False
2397
2398 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07002399 fq_logger.debug("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002400
2401
Howard Persh07d99e62012-04-09 15:26:57 -07002402# FLOW DELETE 1
2403#
2404# OVERVIEW
2405# Strict delete of single flow
2406#
2407# PURPOSE
2408# Verify correct operation of strict delete of single defined flow
2409#
2410# PARAMETERS
2411# None
2412#
2413# PROCESS
2414# 1. Delete all flows from switch
2415# 2. Send flow F to switch
2416# 3. Send strict flow delete for F to switch
2417# 4. Verify flow table in swtich
2418# 6. Test PASSED iff all flows sent to switch in step 2 above,
2419# less flow removed in step 3 above, are returned in step 4 above;
2420# else test FAILED
2421
rootf6af1672012-04-06 09:46:29 -07002422class Flow_Del_1(basic.SimpleProtocol):
2423 """
2424 Test FLOW_DEL_1 from draft top-half test plan
2425
2426 INPUTS
2427 None
2428 """
2429
2430 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07002431 fq_logger.debug("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002432
2433 # Clear all flows from switch
2434
Dan Talayco910a8282012-04-07 00:05:20 -07002435 fq_logger.debug("Deleting all flows from switch")
2436 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002437 self.assertEqual(rc, 0, "Failed to delete all flows")
2438
2439 # Get switch capabilites
2440
Dan Talayco910a8282012-04-07 00:05:20 -07002441 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002442 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002443 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002444 self.assertTrue(sw.features_get(), "Get switch features failed")
2445 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2446
2447 # Dream up some flow information, i.e. space to chose from for
2448 # random flow parameter generation
2449
2450 fi = Flow_Info()
2451 fi.rand(10)
2452
2453 # Dream up a flow config
2454
2455 fc = Flow_Cfg()
2456 fc.rand(fi, \
2457 sw.tbl_stats.stats[0].wildcards, \
2458 sw.sw_features.actions, \
2459 sw.valid_ports \
2460 )
2461 fc = fc.canonical()
2462
2463 # Send it to the switch
2464
Dan Talayco910a8282012-04-07 00:05:20 -07002465 fq_logger.debug("Sending flow add to switch:")
2466 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07002467 ft = Flow_Tbl()
2468 fc.send_rem = False
2469 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2470 ft.insert(fc)
2471
2472 # Dream up some different actions, with the same flow key
2473
2474 fc2 = copy.deepcopy(fc)
2475 while True:
2476 fc2.rand_mod(fi, \
2477 sw.sw_features.actions, \
2478 sw.valid_ports \
2479 )
2480 if fc2 != fc:
2481 break
2482
2483 # Delete strictly
2484
Dan Talayco910a8282012-04-07 00:05:20 -07002485 fq_logger.debug("Sending strict flow del to switch:")
2486 fq_logger.debug(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002487 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2488 ft.delete(fc)
2489
2490 # Do barrier, to make sure all flows are in
2491
2492 self.assertTrue(sw.barrier(), "Barrier failed")
2493
2494 result = True
2495
2496 # Check for any error messages
2497
2498 if not sw.errors_verify(0):
2499 result = False
2500
2501 # Verify flow table
2502
2503 sw.flow_tbl = ft
2504 if not sw.flow_tbl_verify():
2505 result = False
2506
2507 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07002508 fq_logger.debug("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002509
2510
Howard Persh07d99e62012-04-09 15:26:57 -07002511# FLOW DELETE 2
2512#
2513# OVERVIEW
2514# Loose delete of multiple flows
2515#
2516# PURPOSE
2517# - Verify correct operation of loose delete of multiple flows
2518#
2519# PARAMETERS
2520# Name: num_flows
2521# Type: number
2522# Description:
2523# Number of flows to define
2524# Default: 100
2525#
2526# PROCESS
2527# 1. Delete all flows from switch
2528# 2. Generate <num_flows> distinct flow configurations
2529# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2530# 4. Pick 1 defined flow F at random
2531# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2532# F' will match more than 1 existing flow key
2533# 6. Send loose flow delete for F' to switch
2534# 7. Verify flow table in switch
2535# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2536# removed in step 6 above (i.e. those that match F'), are returned
2537# in step 7 above;
2538# else test FAILED
2539
rootf6af1672012-04-06 09:46:29 -07002540class Flow_Del_2(basic.SimpleProtocol):
2541 """
2542 Test FLOW_DEL_2 from draft top-half test plan
2543
2544 INPUTS
2545 None
2546 """
2547
2548 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07002549 fq_logger.debug("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002550
Dan Talayco910a8282012-04-07 00:05:20 -07002551 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002552
2553 # Clear all flows from switch
2554
Dan Talayco910a8282012-04-07 00:05:20 -07002555 fq_logger.debug("Deleting all flows from switch")
2556 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002557 self.assertEqual(rc, 0, "Failed to delete all flows")
2558
2559 # Get switch capabilites
2560
Dan Talayco910a8282012-04-07 00:05:20 -07002561 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002562 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002563 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002564 self.assertTrue(sw.features_get(), "Get switch features failed")
2565 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2566
2567 # Dream up some flow information, i.e. space to chose from for
2568 # random flow parameter generation
2569
2570 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002571 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002572 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002573
2574 # Dream up some flows
2575
2576 ft = Flow_Tbl()
2577 ft.rand(sw, fi, num_flows)
2578
2579 # Send flow table to switch
2580
Dan Talayco910a8282012-04-07 00:05:20 -07002581 fq_logger.debug("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002582 for fc in ft.values(): # Randomizes order of sending
Dan Talayco910a8282012-04-07 00:05:20 -07002583 fq_logger.debug("Adding flow:")
2584 fq_logger.debug(str(fc));
rootf6af1672012-04-06 09:46:29 -07002585 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2586
2587 # Do barrier, to make sure all flows are in
2588
2589 self.assertTrue(sw.barrier(), "Barrier failed")
2590
2591 result = True
2592
2593 # Check for any error messages
2594
2595 if not sw.errors_verify(0):
2596 result = False
2597
2598 # Verify flow table
2599
2600 sw.flow_tbl = ft
2601 if not sw.flow_tbl_verify():
2602 result = False
2603
2604 # Pick a random flow as a basis
2605
2606 dfc = copy.deepcopy(ft.values()[0])
2607 dfc.rand_mod(fi, sw.sw_features.actions, sw.valid_ports)
2608
2609 # Repeatedly wildcard qualifiers
2610
2611 for wi in shuffle(range(len(all_wildcards_list))):
2612 w = all_wildcards_list[wi]
2613 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2614 n = wildcard_get(dfc.match.wildcards, w)
2615 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002616 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2617 w, \
2618 random.randint(n + 1, 32) \
2619 )
rootf6af1672012-04-06 09:46:29 -07002620 else:
2621 continue
2622 else:
2623 if wildcard_get(dfc.match.wildcards, w) == 0:
2624 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2625 else:
2626 continue
2627 dfc = dfc.canonical()
2628
2629 # Count the number of flows that would be deleted
2630
2631 n = 0
2632 for fc in ft.values():
2633 if dfc.overlaps(fc, True):
2634 n = n + 1
2635
2636 # If more than 1, we found our loose delete flow spec
2637 if n > 1:
2638 break
2639
Dan Talayco910a8282012-04-07 00:05:20 -07002640 fq_logger.debug("Deleting %d flows" % (n))
2641 fq_logger.debug("Sending flow del to switch:")
2642 fq_logger.debug(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002643 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2644
2645 # Do barrier, to make sure all flows are in
2646 self.assertTrue(sw.barrier(), "Barrier failed")
2647
2648 # Check for error message
2649
2650 if not sw.errors_verify(0):
2651 result = False
2652
2653 # Apply flow mod to local flow table
2654
2655 for fc in ft.values():
2656 if dfc.overlaps(fc, True):
2657 ft.delete(fc)
2658
2659 # Verify flow table
2660
2661 sw.flow_tbl = ft
2662 if not sw.flow_tbl_verify():
2663 result = False
2664
2665 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07002666 fq_logger.debug("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002667
2668
Howard Persh07d99e62012-04-09 15:26:57 -07002669# FLOW DELETE 4
2670#
2671# OVERVIEW
2672# Flow removed messages
2673#
2674# PURPOSE
2675# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2676# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2677#
2678# PARAMETERS
2679# None
2680#
2681# PROCESS
2682# 1. Delete all flows from switch
2683# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2684# 3. Send strict flow delete of flow to switch
2685# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2686# 5. Verify flow table in switch
2687# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2688# removed in step 3 above, are returned in step 5 above, and that
2689# asynch message was received; else test FAILED
2690
2691
rootf6af1672012-04-06 09:46:29 -07002692class Flow_Del_4(basic.SimpleProtocol):
2693 """
2694 Test FLOW_DEL_4 from draft top-half test plan
2695
2696 INPUTS
2697 None
2698 """
2699
2700 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07002701 fq_logger.debug("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002702
2703 # Clear all flows from switch
2704
Dan Talayco910a8282012-04-07 00:05:20 -07002705 fq_logger.debug("Deleting all flows from switch")
2706 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002707 self.assertEqual(rc, 0, "Failed to delete all flows")
2708
2709 # Get switch capabilites
2710
Dan Talayco910a8282012-04-07 00:05:20 -07002711 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002712 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002713 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002714 self.assertTrue(sw.features_get(), "Get switch features failed")
2715 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2716
2717 # Dream up some flow information, i.e. space to chose from for
2718 # random flow parameter generation
2719
2720 fi = Flow_Info()
2721 fi.rand(10)
2722
2723 # Dream up a flow config
2724
2725 fc = Flow_Cfg()
2726 fc.rand(fi, \
2727 sw.tbl_stats.stats[0].wildcards, \
2728 sw.sw_features.actions, \
2729 sw.valid_ports \
2730 )
2731 fc = fc.canonical()
2732
2733 # Send it to the switch. with "notify on removed"
2734
Dan Talayco910a8282012-04-07 00:05:20 -07002735 fq_logger.debug("Sending flow add to switch:")
2736 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07002737 ft = Flow_Tbl()
2738 fc.send_rem = True
2739 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2740 ft.insert(fc)
2741
2742 # Dream up some different actions, with the same flow key
2743
2744 fc2 = copy.deepcopy(fc)
2745 while True:
2746 fc2.rand_mod(fi, \
2747 sw.sw_features.actions, \
2748 sw.valid_ports \
2749 )
2750 if fc2 != fc:
2751 break
2752
2753 # Delete strictly
2754
Dan Talayco910a8282012-04-07 00:05:20 -07002755 fq_logger.debug("Sending strict flow del to switch:")
2756 fq_logger.debug(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002757 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2758 ft.delete(fc)
2759
2760 # Do barrier, to make sure all flows are in
2761
2762 self.assertTrue(sw.barrier(), "Barrier failed")
2763
2764 result = True
2765
2766 # Check for expected "removed" message
2767
Howard Persh3340d452012-04-06 16:45:21 -07002768 if not sw.errors_verify(0):
2769 result = False
2770
2771 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07002772 result = False
2773
2774 # Verify flow table
2775
2776 sw.flow_tbl = ft
2777 if not sw.flow_tbl_verify():
2778 result = False
2779
2780 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07002781 fq_logger.debug("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002782