blob: 9183ab22833cbf377c6a79ac3865ead805698db8 [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 Persh680b92a2012-03-31 13:34:35 -07007import math
Howard Pershc7963582012-03-29 10:02:59 -07008
9import logging
10
11import unittest
12import random
13
14import oftest.controller as controller
15import oftest.cstruct as ofp
16import oftest.message as message
17import oftest.dataplane as dataplane
18import oftest.action as action
19import oftest.action_list as action_list
20import oftest.parse as parse
21import pktact
22import basic
23
24from testutils import *
25from time import sleep
26
27#@var port_map Local copy of the configuration map from OF port
28# numbers to OS interfaces
29pa_port_map = None
30#@var pa_logger Local logger object
31pa_logger = None
32#@var pa_config Local copy of global configuration data
33pa_config = None
34
rootf6af1672012-04-06 09:46:29 -070035# For test priority
36test_prio = {}
37
38
Howard Pershc7963582012-03-29 10:02:59 -070039def test_set_init(config):
40 """
41 Set up function for packet action test classes
42
43 @param config The configuration dictionary; see oft
44 """
45
46 basic.test_set_init(config)
47
48 global pa_port_map
49 global pa_logger
50 global pa_config
51
52 pa_logger = logging.getLogger("pkt_act")
53 pa_logger.info("Initializing test set")
54 pa_port_map = config["port_map"]
55 pa_config = config
56
root2843d2b2012-04-06 10:27:46 -070057 # TBD - Doesn't seem to take effect at the right time...
58 if test_param_get(pa_config, "dut", "") == "ovs":
Howard Persh3340d452012-04-06 16:45:21 -070059 # Disable this test by default, since the flow capacity
60 # reported by OVS is bogus.
root2843d2b2012-04-06 10:27:46 -070061 test_prio["Flow_Add_6"] = -1
62
Howard Pershc7963582012-03-29 10:02:59 -070063
rootf6af1672012-04-06 09:46:29 -070064def flip_coin():
65 return random.randint(1, 100) <= 50
66
67
Howard Pershc7963582012-03-29 10:02:59 -070068def shuffle(list):
69 n = len(list)
70 lim = n * n
71 i = 0
72 while i < lim:
73 a = random.randint(0, n - 1)
74 b = random.randint(0, n - 1)
75 temp = list[a]
76 list[a] = list[b]
77 list[b] = temp
78 i = i + 1
79 return list
80
81
Howard Persh680b92a2012-03-31 13:34:35 -070082def rand_pick(list):
83 return list[random.randint(0, len(list) - 1)]
Howard Pershc7963582012-03-29 10:02:59 -070084
Howard Persh680b92a2012-03-31 13:34:35 -070085def rand_dl_addr():
86 return [random.randint(0, 255) & ~1,
87 random.randint(0, 255),
88 random.randint(0, 255),
89 random.randint(0, 255),
90 random.randint(0, 255),
91 random.randint(0, 255)
92 ]
Howard Pershc7963582012-03-29 10:02:59 -070093
94def rand_nw_addr():
95 return random.randint(0, (1 << 32) - 1)
96
97
rootf6af1672012-04-06 09:46:29 -070098class Flow_Info:
Howard Persh680b92a2012-03-31 13:34:35 -070099 # Members:
100 # priorities - list of flow priorities
101 # dl_addrs - list of MAC addresses
102 # vlans - list of VLAN ids
103 # ethertypes - list of Ethertypes
104 # ip_addrs - list of IP addresses
105 # ip_tos - list of IP TOS values
106 # ip_protos - list of IP protocols
107 # l4_ports - list of L4 ports
108
109 def __init__(self):
110 priorities = []
111 dl_addrs = []
112 vlans = []
113 ethertypes = []
114 ip_addrs = []
115 ip_tos = []
116 ip_protos = []
117 l4_ports = []
118
119 def rand(self, n):
120 self.priorities = []
121 i = 0
122 while i < n:
123 self.priorities.append(random.randint(1, 65534))
124 i = i + 1
125
126 self.dl_addrs = []
127 i = 0
128 while i < n:
129 self.dl_addrs.append(rand_dl_addr())
130 i = i + 1
131
132 self.vlans = []
133 i = 0
134 while i < n:
135 self.vlans.append(random.randint(1, 4094))
136 i = i + 1
137
rootf6af1672012-04-06 09:46:29 -0700138 self.ethertypes = [0x0800, 0x0806]
Howard Persh680b92a2012-03-31 13:34:35 -0700139 i = 0
140 while i < n:
141 self.ethertypes.append(random.randint(0, (1 << 16) - 1))
142 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700143 self.ethertypes = shuffle(self.ethertypes)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700144
145 self.ip_addrs = []
146 i = 0
147 while i < n:
148 self.ip_addrs.append(rand_nw_addr())
149 i = i + 1
150
151 self.ip_tos = []
152 i = 0
153 while i < n:
154 self.ip_tos.append(random.randint(0, (1 << 8) - 1) & ~3)
155 i = i + 1
156
rootf6af1672012-04-06 09:46:29 -0700157 self.ip_protos = [1, 6, 17]
Howard Persh680b92a2012-03-31 13:34:35 -0700158 i = 0
159 while i < n:
160 self.ip_protos.append(random.randint(0, (1 << 8) - 1))
161 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700162 self.ip_protos = shuffle(self.ip_protos)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700163
164 self.l4_ports = []
165 i = 0
166 while i < n:
167 self.l4_ports.append(random.randint(0, (1 << 16) - 1))
168 i = i + 1
169
170 def rand_priority(self):
171 return rand_pick(self.priorities)
172
173 def rand_dl_addr(self):
174 return rand_pick(self.dl_addrs)
175
176 def rand_vlan(self):
177 return rand_pick(self.vlans)
178
179 def rand_ethertype(self):
180 return rand_pick(self.ethertypes)
181
182 def rand_ip_addr(self):
183 return rand_pick(self.ip_addrs)
184
185 def rand_ip_tos(self):
186 return rand_pick(self.ip_tos)
187
188 def rand_ip_proto(self):
189 return rand_pick(self.ip_protos)
190
191 def rand_l4_port(self):
192 return rand_pick(self.l4_ports)
193
194
Howard Pershc7963582012-03-29 10:02:59 -0700195# TBD - These don't belong here
196
Howard Persh680b92a2012-03-31 13:34:35 -0700197all_wildcards_list = [ofp.OFPFW_IN_PORT,
Howard Persh680b92a2012-03-31 13:34:35 -0700198 ofp.OFPFW_DL_DST,
rootf6af1672012-04-06 09:46:29 -0700199 ofp.OFPFW_DL_SRC,
200 ofp.OFPFW_DL_VLAN,
201 ofp.OFPFW_DL_VLAN_PCP,
Howard Persh680b92a2012-03-31 13:34:35 -0700202 ofp.OFPFW_DL_TYPE,
rootf6af1672012-04-06 09:46:29 -0700203 ofp.OFPFW_NW_TOS,
Howard Persh680b92a2012-03-31 13:34:35 -0700204 ofp.OFPFW_NW_PROTO,
Howard Persh680b92a2012-03-31 13:34:35 -0700205 ofp.OFPFW_NW_SRC_MASK,
206 ofp.OFPFW_NW_DST_MASK,
rootf6af1672012-04-06 09:46:29 -0700207 ofp.OFPFW_TP_SRC,
208 ofp.OFPFW_TP_DST
Howard Persh680b92a2012-03-31 13:34:35 -0700209 ]
Howard Pershc7963582012-03-29 10:02:59 -0700210
Howard Persh3340d452012-04-06 16:45:21 -0700211# TBD - Need this because there are duplicates in ofp.ofp_flow_wildcards_map
212# -- FIX
rootf6af1672012-04-06 09:46:29 -0700213all_wildcard_names = {
214 1 : 'OFPFW_IN_PORT',
215 2 : 'OFPFW_DL_VLAN',
216 4 : 'OFPFW_DL_SRC',
217 8 : 'OFPFW_DL_DST',
218 16 : 'OFPFW_DL_TYPE',
219 32 : 'OFPFW_NW_PROTO',
220 64 : 'OFPFW_TP_SRC',
221 128 : 'OFPFW_TP_DST',
222 1048576 : 'OFPFW_DL_VLAN_PCP',
223 2097152 : 'OFPFW_NW_TOS'
224}
225
226
227def wildcard_set(x, w, val):
228 result = x
229 if w == ofp.OFPFW_NW_SRC_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700230 result = (result & ~ofp.OFPFW_NW_SRC_MASK) \
231 | (val << ofp.OFPFW_NW_SRC_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700232 elif w == ofp.OFPFW_NW_DST_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700233 result = (result & ~ofp.OFPFW_NW_DST_MASK) \
234 | (val << ofp.OFPFW_NW_DST_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700235 elif val == 0:
236 result = result & ~w
237 else:
238 result = result | w
239 return result
240
241def wildcard_get(x, w):
242 if w == ofp.OFPFW_NW_SRC_MASK:
243 return (x & ofp.OFPFW_NW_SRC_MASK) >> ofp.OFPFW_NW_SRC_SHIFT
244 if w == ofp.OFPFW_NW_DST_MASK:
245 return (x & ofp.OFPFW_NW_DST_MASK) >> ofp.OFPFW_NW_DST_SHIFT
246 return 1 if (x & w) != 0 else 0
247
Howard Pershc7963582012-03-29 10:02:59 -0700248
Howard Persh680b92a2012-03-31 13:34:35 -0700249all_actions_list = [ofp.OFPAT_OUTPUT,
250 ofp.OFPAT_SET_VLAN_VID,
251 ofp.OFPAT_SET_VLAN_PCP,
252 ofp.OFPAT_STRIP_VLAN,
253 ofp.OFPAT_SET_DL_SRC,
254 ofp.OFPAT_SET_DL_DST,
255 ofp.OFPAT_SET_NW_SRC,
256 ofp.OFPAT_SET_NW_DST,
257 ofp.OFPAT_SET_NW_TOS,
258 ofp.OFPAT_SET_TP_SRC,
259 ofp.OFPAT_SET_TP_DST,
260 ofp.OFPAT_ENQUEUE
261 ]
262
263def dl_addr_to_str(a):
264 return "%x:%x:%x:%x:%x:%x" % tuple(a)
265
266def ip_addr_to_str(a, n):
rootf6af1672012-04-06 09:46:29 -0700267 if n is not None:
268 a = a & ~((1 << (32 - n)) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700269 result = "%d.%d.%d.%d" % (a >> 24, \
270 (a >> 16) & 0xff, \
271 (a >> 8) & 0xff, \
272 a & 0xff \
273 )
274 if n is not None:
275 result = result + ("/%d" % (n))
276 return result
277
Howard Pershc7963582012-03-29 10:02:59 -0700278
rootf6af1672012-04-06 09:46:29 -0700279class Flow_Cfg:
Howard Pershc7963582012-03-29 10:02:59 -0700280 # Members:
281 # - match
282 # - idle_timeout
283 # - hard_timeout
284 # - priority
285 # - action_list
286
287 def __init__(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700288 self.priority = 0
Howard Pershc7963582012-03-29 10:02:59 -0700289 self.match = parse.ofp_match()
290 self.match.wildcards = ofp.OFPFW_ALL
291 self.idle_timeout = 0
292 self.hard_timeout = 0
Howard Pershc7963582012-03-29 10:02:59 -0700293 self.actions = action_list.action_list()
294
rootf6af1672012-04-06 09:46:29 -0700295 # {pri, match} is considered a flow key
296 def key_equal(self, x):
Howard Persh680b92a2012-03-31 13:34:35 -0700297 if self.priority != x.priority:
298 return False
299 # TBD - Should this logic be moved to ofp_match.__eq__()?
300 if self.match.wildcards != x.match.wildcards:
301 return False
rootf6af1672012-04-06 09:46:29 -0700302 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700303 and self.match.in_port != x.match.in_port:
304 return False
rootf6af1672012-04-06 09:46:29 -0700305 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700306 and self.match.dl_dst != x.match.dl_dst:
307 return False
rootf6af1672012-04-06 09:46:29 -0700308 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0 \
309 and self.match.dl_src != x.match.dl_src:
310 return False
311 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700312 and self.match.dl_vlan != x.match.dl_vlan:
313 return False
rootf6af1672012-04-06 09:46:29 -0700314 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700315 and self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
316 return False
rootf6af1672012-04-06 09:46:29 -0700317 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700318 and self.match.dl_type != x.match.dl_type:
319 return False
rootf6af1672012-04-06 09:46:29 -0700320 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700321 and self.match.nw_tos != x.match.nw_tos:
322 return False
rootf6af1672012-04-06 09:46:29 -0700323 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700324 and self.match.nw_proto != x.match.nw_proto:
325 return False
rootf6af1672012-04-06 09:46:29 -0700326 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
327 if n < 32:
328 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700329 if (self.match.nw_src & m) != (x.match.nw_src & m):
330 return False
rootf6af1672012-04-06 09:46:29 -0700331 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
332 if n < 32:
333 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700334 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
335 return False
rootf6af1672012-04-06 09:46:29 -0700336 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0 \
337 and self.match.tp_src != x.match.tp_src:
Howard Persh680b92a2012-03-31 13:34:35 -0700338 return False
rootf6af1672012-04-06 09:46:29 -0700339 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0 \
340 and self.match.tp_dst != x.match.tp_dst:
341 return False
342 return True
343
344 def non_key_equal(self, x):
345 if self.cookie != x.cookie:
Howard Pershc7963582012-03-29 10:02:59 -0700346 return False
347 if self.idle_timeout != x.idle_timeout:
348 return False
349 if self.hard_timeout != x.hard_timeout:
350 return False
root2843d2b2012-04-06 10:27:46 -0700351 if test_param_get(pa_config, "dut", "") == "argon":
Howard Persh3340d452012-04-06 16:45:21 -0700352 pa_logger.debug("Doing argon-style action comparison")
353 # Compare actions lists as unordered, since Argon may re-order
354 # action lists.
root2843d2b2012-04-06 10:27:46 -0700355 # This is in apparent violation of the spec.
356 aa = copy.deepcopy(x.actions.actions)
357 for a in self.actions.actions:
358 i = 0
359 while i < len(aa):
360 if a == aa[i]:
361 break
362 i = i + 1
363 if i < len(aa):
364 aa.pop(i)
365 else:
366 return False
367 return aa == []
368 else:
369 return self.actions == x.actions
rootf6af1672012-04-06 09:46:29 -0700370
root2843d2b2012-04-06 10:27:46 -0700371 def key_str(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700372 result = "priority=%d" % self.priority
373 # TBD - Would be nice if ofp_match.show() was better behaved
374 # (no newlines), and more intuitive (things in hex where approprate), etc.
rootf6af1672012-04-06 09:46:29 -0700375 result = result + (", wildcards=0x%x={" % (self.match.wildcards))
Howard Persh680b92a2012-03-31 13:34:35 -0700376 sep = ""
rootf6af1672012-04-06 09:46:29 -0700377 for w in all_wildcards_list:
378 if (self.match.wildcards & w) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700379 continue
380 if w == ofp.OFPFW_NW_SRC_MASK:
rootf6af1672012-04-06 09:46:29 -0700381 n = wildcard_get(self.match.wildcards, w)
382 if n > 0:
383 result = result + sep + ("OFPFW_NW_SRC(%d)" % (n))
Howard Persh680b92a2012-03-31 13:34:35 -0700384 elif w == ofp.OFPFW_NW_DST_MASK:
rootf6af1672012-04-06 09:46:29 -0700385 n = wildcard_get(self.match.wildcards, w)
386 if n > 0:
387 result = result + sep + ("OFPFW_NW_DST(%d)" % (n))
Howard Persh680b92a2012-03-31 13:34:35 -0700388 else:
rootf6af1672012-04-06 09:46:29 -0700389 result = result + sep + all_wildcard_names[w]
Howard Persh680b92a2012-03-31 13:34:35 -0700390 sep = ", "
391 result = result +"}"
rootf6af1672012-04-06 09:46:29 -0700392 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700393 result = result + (", in_port=%d" % (self.match.in_port))
rootf6af1672012-04-06 09:46:29 -0700394 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700395 result = result + (", dl_dst=%s" \
396 % (dl_addr_to_str(self.match.dl_dst)) \
397 )
rootf6af1672012-04-06 09:46:29 -0700398 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700399 result = result + (", dl_src=%s" \
400 % (dl_addr_to_str(self.match.dl_src)) \
401 )
rootf6af1672012-04-06 09:46:29 -0700402 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700403 result = result + (", dl_vlan=%d" % (self.match.dl_vlan))
rootf6af1672012-04-06 09:46:29 -0700404 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700405 result = result + (", dl_vlan_pcp=%d" % (self.match.dl_vlan_pcp))
rootf6af1672012-04-06 09:46:29 -0700406 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700407 result = result + (", dl_type=0x%x" % (self.match.dl_type))
rootf6af1672012-04-06 09:46:29 -0700408 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700409 result = result + (", nw_tos=0x%x" % (self.match.nw_tos))
rootf6af1672012-04-06 09:46:29 -0700410 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700411 result = result + (", nw_proto=%d" % (self.match.nw_proto))
rootf6af1672012-04-06 09:46:29 -0700412 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700413 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700414 result = result + (", nw_src=%s" % \
415 (ip_addr_to_str(self.match.nw_src, 32 - n)) \
416 )
rootf6af1672012-04-06 09:46:29 -0700417 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700418 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700419 result = result + (", nw_dst=%s" % \
420 (ip_addr_to_str(self.match.nw_dst, 32 - n)) \
421 )
rootf6af1672012-04-06 09:46:29 -0700422 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700423 result = result + (", tp_src=%d" % self.match.tp_src)
rootf6af1672012-04-06 09:46:29 -0700424 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700425 result = result + (", tp_dst=%d" % self.match.tp_dst)
rootf6af1672012-04-06 09:46:29 -0700426 return result
427
428 def __eq__(self, x):
429 return (self.key_equal(x) and self.non_key_equal(x))
430
431 def __str__(self):
root2843d2b2012-04-06 10:27:46 -0700432 result = self.key_str()
433 result = result + (", cookie=%d" % self.cookie)
Howard Persh680b92a2012-03-31 13:34:35 -0700434 result = result + (", idle_timeout=%d" % self.idle_timeout)
435 result = result + (", hard_timeout=%d" % self.hard_timeout)
Howard Persh680b92a2012-03-31 13:34:35 -0700436 for a in self.actions.actions:
437 result = result + (", action=%s" % ofp.ofp_action_type_map[a.type])
438 if a.type == ofp.OFPAT_OUTPUT:
439 result = result + ("(%d)" % (a.port))
440 elif a.type == ofp.OFPAT_SET_VLAN_VID:
441 result = result + ("(%d)" % (a.vlan_vid))
442 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
443 result = result + ("(%d)" % (a.vlan_pcp))
444 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
445 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
446 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
447 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
448 elif a.type == ofp.OFPAT_SET_NW_TOS:
449 result = result + ("(0x%x)" % (a.nw_tos))
450 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
451 result = result + ("(%d)" % (a.tp_port))
452 elif a.type == ofp.OFPAT_ENQUEUE:
453 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
454 return result
Howard Pershc7963582012-03-29 10:02:59 -0700455
Howard Persh3340d452012-04-06 16:45:21 -0700456 def rand_actions_argon(self, fi, valid_actions, valid_ports):
457 # Action lists are ordered, so pick an ordered random subset of
458 # supported actions
459 supported_actions = []
460 for a in all_actions_list:
461 if ((1 << a) & valid_actions) != 0:
462 supported_actions.append(a)
463
464 supported_actions = shuffle(supported_actions)
465 supported_actions \
466 = supported_actions[0 : random.randint(1, len(supported_actions))]
467
468 # The setting of max_len to 65535 is a hack, since that's what's
469 # returned by Argon for all actions (for now...)
470
471 self.actions = action_list.action_list()
472 for a in supported_actions:
473 if a == ofp.OFPAT_OUTPUT:
474 pass # OUTPUT actions must come last
475 elif a == ofp.OFPAT_SET_VLAN_VID:
476 act = action.action_set_vlan_vid()
477 act.vlan_vid = fi.rand_vlan()
478 act.max_len = 65535
479 self.actions.add(act)
480 elif a == ofp.OFPAT_SET_VLAN_PCP:
481 act = action.action_set_vlan_pcp()
482 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
483 act.max_len = 65535
484 self.actions.add(act)
485 elif a == ofp.OFPAT_STRIP_VLAN:
486 act = action.action_strip_vlan()
487 act.max_len = 65535
488 self.actions.add(act)
489 elif a == ofp.OFPAT_SET_DL_SRC:
490 act = action.action_set_dl_src()
491 act.dl_addr = fi.rand_dl_addr()
492 act.max_len = 65535
493 self.actions.add(act)
494 elif a == ofp.OFPAT_SET_DL_DST:
495 act = action.action_set_dl_dst()
496 act.dl_addr = fi.rand_dl_addr()
497 act.max_len = 65535
498 self.actions.add(act)
499 elif a == ofp.OFPAT_SET_NW_SRC:
500 act = action.action_set_nw_src()
501 act.nw_addr = fi.rand_ip_addr()
502 act.max_len = 65535
503 self.actions.add(act)
504 elif a == ofp.OFPAT_SET_NW_DST:
505 act = action.action_set_nw_dst()
506 act.nw_addr = fi.rand_ip_addr()
507 act.max_len = 65535
508 self.actions.add(act)
509 elif a == ofp.OFPAT_SET_NW_TOS:
510 act = action.action_set_nw_tos()
511 act.nw_tos = fi.rand_ip_tos()
512 act.max_len = 65535
513 self.actions.add(act)
514 elif a == ofp.OFPAT_SET_TP_SRC:
515 act = action.action_set_tp_src()
516 act.tp_port = fi.rand_l4_port()
517 act.max_len = 65535
518 self.actions.add(act)
519 elif a == ofp.OFPAT_SET_TP_DST:
520 act = action.action_set_tp_dst()
521 act.tp_port = fi.rand_l4_port()
522 act.max_len = 65535
523 self.actions.add(act)
524 elif a == ofp.OFPAT_ENQUEUE:
525 pass # Enqueue actions must come last
526
527 p = random.randint(1, 100)
528 if p <= 33:
529 # One third of the time, include ENQUEUE actions at end of list
530 # At most 1 ENQUEUE action
531 act = action.action_enqueue()
532 act.port = rand_pick(valid_ports)
533 # TBD - Limits for queue number?
534 act.queue_id = random.randint(0, 7)
535 act.max_len = 65535
536 self.actions.add(act)
537 elif p <= 66:
538 # One third of the time, include OUTPUT actions at end of list
539 port_idxs = shuffle(range(len(valid_ports)))
540 # Only 1 output action allowed if IN_PORT wildcarded
541 n = 1 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) != 0 \
542 else random.randint(1, len(valid_ports))
543 port_idxs = port_idxs[0 : n]
544 for pi in port_idxs:
545 act = action.action_output()
546 act.port = valid_ports[pi]
547 act.max_len = 65535
548 if act.port != ofp.OFPP_IN_PORT \
549 or wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
550 # OUTPUT(IN_PORT) only valid if OFPFW_IN_PORT not wildcarded
551 self.actions.add(act)
552 else:
553 # One third of the time, include neither
554 pass
555
556
557 # Randomize flow data for flow modifies (i.e. cookie and actions)
rootf6af1672012-04-06 09:46:29 -0700558 def rand_mod(self, fi, valid_actions, valid_ports):
559 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700560
Howard Persh3340d452012-04-06 16:45:21 -0700561 if test_param_get(pa_config, "dut", "") == "argon":
562 pa_logger.debug("Generating actions for argon")
563 self.rand_actions_argon(fi, valid_actions, valid_ports)
564 return self
565
Howard Persh680b92a2012-03-31 13:34:35 -0700566 # Action lists are ordered, so pick an ordered random subset of
567 # supported actions
568 supported_actions = []
569 for a in all_actions_list:
570 if ((1 << a) & valid_actions) != 0:
571 supported_actions.append(a)
572
573 supported_actions = shuffle(supported_actions)
574 supported_actions \
575 = supported_actions[0 : random.randint(1, len(supported_actions))]
Howard Pershc7963582012-03-29 10:02:59 -0700576
577 self.actions = action_list.action_list()
Howard Persh680b92a2012-03-31 13:34:35 -0700578 for a in supported_actions:
Howard Pershc7963582012-03-29 10:02:59 -0700579 if a == ofp.OFPAT_OUTPUT:
580 # TBD - Output actions are clustered in list, spread them out?
581 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700582 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700583 for pi in port_idxs:
584 act = action.action_output()
Howard Persh680b92a2012-03-31 13:34:35 -0700585 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700586 self.actions.add(act)
587 elif a == ofp.OFPAT_SET_VLAN_VID:
588 act = action.action_set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700589 act.vlan_vid = fi.rand_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700590 self.actions.add(act)
591 elif a == ofp.OFPAT_SET_VLAN_PCP:
root2843d2b2012-04-06 10:27:46 -0700592 if test_param_get(pa_config, "dut", "") == "indigo":
Howard Persh3340d452012-04-06 16:45:21 -0700593 pa_logger.debug("OFPAT_SET_VLAN_PCP broken on indigo")
594 pa_logger.debug("not using")
root2843d2b2012-04-06 10:27:46 -0700595 # Temporaily removed, broken in Indigo
596 pass
597 else:
598 act = action.action_set_vlan_pcp()
599 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700600 elif a == ofp.OFPAT_STRIP_VLAN:
601 act = action.action_strip_vlan()
602 self.actions.add(act)
603 elif a == ofp.OFPAT_SET_DL_SRC:
604 act = action.action_set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700605 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700606 self.actions.add(act)
607 elif a == ofp.OFPAT_SET_DL_DST:
608 act = action.action_set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700609 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700610 self.actions.add(act)
611 elif a == ofp.OFPAT_SET_NW_SRC:
612 act = action.action_set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700613 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700614 self.actions.add(act)
615 elif a == ofp.OFPAT_SET_NW_DST:
616 act = action.action_set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700617 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700618 self.actions.add(act)
619 elif a == ofp.OFPAT_SET_NW_TOS:
620 act = action.action_set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700621 act.nw_tos = fi.rand_ip_tos()
Howard Pershc7963582012-03-29 10:02:59 -0700622 self.actions.add(act)
623 elif a == ofp.OFPAT_SET_TP_SRC:
624 act = action.action_set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700625 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700626 self.actions.add(act)
627 elif a == ofp.OFPAT_SET_TP_DST:
628 act = action.action_set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700629 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700630 self.actions.add(act)
631 elif a == ofp.OFPAT_ENQUEUE:
632 # TBD - Enqueue actions are clustered in list, spread them out?
633 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700634 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700635 for pi in port_idxs:
636 act = action.action_enqueue()
Howard Persh680b92a2012-03-31 13:34:35 -0700637 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700638 # TBD - Limits for queue number?
639 act.queue_id = random.randint(0, 7)
640 self.actions.add(act)
641
642 return self
643
rootf6af1672012-04-06 09:46:29 -0700644 # Randomize flow cfg
645 def rand(self, fi, valid_wildcards, valid_actions, valid_ports):
646 # Start with no wildcards, i.e. everything specified
647 self.match.wildcards = 0
648
649 # Make approx. 5% of flows exact
650 exact = (random.randint(1, 100) <= 5)
651
652 # For each qualifier Q,
653 # if (wildcarding is not supported for Q,
654 # or an exact flow is specified
655 # or a coin toss comes up heads),
656 # specify Q
657 # else
658 # wildcard Q
659
660 if wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
661 or exact \
662 or flip_coin():
663 self.match.in_port = rand_pick(valid_ports)
664 else:
Howard Persh3340d452012-04-06 16:45:21 -0700665 self.match.wildcards = wildcard_set(self.match.wildcards, \
666 ofp.OFPFW_IN_PORT, \
667 1 \
668 )
rootf6af1672012-04-06 09:46:29 -0700669
670 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
671 or exact \
672 or flip_coin():
673 self.match.dl_dst = fi.rand_dl_addr()
674 else:
Howard Persh3340d452012-04-06 16:45:21 -0700675 self.match.wildcards = wildcard_set(self.match.wildcards, \
676 ofp.OFPFW_DL_DST, \
677 1 \
678 )
rootf6af1672012-04-06 09:46:29 -0700679
680 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
681 or exact \
682 or flip_coin():
683 self.match.dl_src = fi.rand_dl_addr()
684 else:
Howard Persh3340d452012-04-06 16:45:21 -0700685 self.match.wildcards = wildcard_set(self.match.wildcards, \
686 ofp.OFPFW_DL_SRC, \
687 1 \
688 )
rootf6af1672012-04-06 09:46:29 -0700689
690 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
691 or exact \
692 or flip_coin():
693 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
694 else:
Howard Persh3340d452012-04-06 16:45:21 -0700695 self.match.wildcards = wildcard_set(self.match.wildcards, \
696 ofp.OFPFW_DL_VLAN_PCP, \
697 1 \
698 )
rootf6af1672012-04-06 09:46:29 -0700699
700 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
701 or exact \
702 or flip_coin():
703 self.match.dl_vlan = fi.rand_vlan()
704 else:
Howard Persh3340d452012-04-06 16:45:21 -0700705 self.match.wildcards = wildcard_set(self.match.wildcards, \
706 ofp.OFPFW_DL_VLAN, \
707 1 \
708 )
rootf6af1672012-04-06 09:46:29 -0700709
710 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
711 or exact \
712 or flip_coin():
713 self.match.dl_type = fi.rand_ethertype()
714 else:
Howard Persh3340d452012-04-06 16:45:21 -0700715 self.match.wildcards = wildcard_set(self.match.wildcards, \
716 ofp.OFPFW_DL_TYPE, \
717 1 \
718 )
rootf6af1672012-04-06 09:46:29 -0700719
720 if exact or flip_coin():
721 n = 0
722 else:
723 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
724 if n > 32:
725 n = 32
726 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700727 self.match.wildcards = wildcard_set(self.match.wildcards, \
728 ofp.OFPFW_NW_SRC_MASK, \
729 n \
730 )
rootf6af1672012-04-06 09:46:29 -0700731 if n < 32:
732 self.match.nw_src = fi.rand_ip_addr() & ~((1 << n) - 1)
733 # Specifying any IP address match other than all bits
734 # don't care requires that Ethertype is one of {IP, ARP}
735 if flip_coin():
736 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700737 self.match.wildcards = wildcard_set(self.match.wildcards, \
738 ofp.OFPFW_DL_TYPE, \
739 0 \
740 )
rootf6af1672012-04-06 09:46:29 -0700741
742 if exact or flip_coin():
743 n = 0
744 else:
745 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
746 if n > 32:
747 n = 32
748 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700749 self.match.wildcards = wildcard_set(self.match.wildcards, \
750 ofp.OFPFW_NW_DST_MASK, \
751 n \
752 )
rootf6af1672012-04-06 09:46:29 -0700753 if n < 32:
754 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
755 # Specifying any IP address match other than all bits
756 # don't care requires that Ethertype is one of {IP, ARP}
757 if flip_coin():
758 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700759 self.match.wildcards = wildcard_set(self.match.wildcards, \
760 ofp.OFPFW_DL_TYPE, \
761 0 \
762 )
rootf6af1672012-04-06 09:46:29 -0700763
764 if wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
765 or exact \
766 or flip_coin():
767 self.match.nw_tos = fi.rand_ip_tos()
768 # Specifying a TOS value requires that Ethertype is IP
769 if flip_coin():
770 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700771 self.match.wildcards = wildcard_set(self.match.wildcards, \
772 ofp.OFPFW_DL_TYPE, \
773 0 \
774 )
rootf6af1672012-04-06 09:46:29 -0700775 else:
Howard Persh3340d452012-04-06 16:45:21 -0700776 self.match.wildcards = wildcard_set(self.match.wildcards, \
777 ofp.OFPFW_NW_TOS, \
778 1 \
779 )
rootf6af1672012-04-06 09:46:29 -0700780
root2843d2b2012-04-06 10:27:46 -0700781 if test_param_get(pa_config, "dut", "") == "ovs":
Howard Persh3340d452012-04-06 16:45:21 -0700782 pa_logger.debug("Flow canonicalization broken")
783 pa_logger.debug("for OFPFW_NW_PROTO on ovs, always wildcarding")
root2843d2b2012-04-06 10:27:46 -0700784 # Due to a bug in OVS, don't specify nw_proto on it's own.
Howard Persh3340d452012-04-06 16:45:21 -0700785 # OVS will allow specifying a value for nw_proto, even
786 # if dl_type is not specified as IP.
787 self.match.wildcards = wildcard_set(self.match.wildcards, \
788 ofp.OFPFW_NW_PROTO, \
789 1 \
790 )
root2843d2b2012-04-06 10:27:46 -0700791 else:
792 if wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
793 or exact \
794 or flip_coin():
795 self.match.nw_proto = fi.rand_ip_proto()
796 # Specifying an IP protocol requires that Ethertype is IP
797 if flip_coin():
798 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700799 self.match.wildcards = wildcard_set(self.match.wildcards, \
800 ofp.OFPFW_DL_TYPE, \
801 0 \
802 )
root2843d2b2012-04-06 10:27:46 -0700803 else:
Howard Persh3340d452012-04-06 16:45:21 -0700804 self.match.wildcards = wildcard_set(self.match.wildcards, \
805 ofp.OFPFW_NW_PROTO, \
806 1 \
807 )
rootf6af1672012-04-06 09:46:29 -0700808
809 if wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
810 or exact\
811 or flip_coin():
812 self.match.tp_src = fi.rand_l4_port()
813 # Specifying a L4 port requires that IP protcol is
814 # one of {ICMP, TCP, UDP}
815 if flip_coin():
816 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700817 self.match.wildcards = wildcard_set(self.match.wildcards, \
818 ofp.OFPFW_NW_PROTO, \
819 0 \
820 )
rootf6af1672012-04-06 09:46:29 -0700821 # Specifying a L4 port requirues that Ethertype is IP
822 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700823 self.match.wildcards = wildcard_set(self.match.wildcards, \
824 ofp.OFPFW_DL_TYPE, \
825 0 \
826 )
rootf6af1672012-04-06 09:46:29 -0700827 if self.match.nw_proto == 1:
828 self.match.tp_src = self.match.tp_src & 0xff
829 else:
Howard Persh3340d452012-04-06 16:45:21 -0700830 self.match.wildcards = wildcard_set(self.match.wildcards, \
831 ofp.OFPFW_TP_SRC, \
832 1 \
833 )
rootf6af1672012-04-06 09:46:29 -0700834
835 if wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
836 or exact \
837 or flip_coin():
838 self.match.tp_dst = fi.rand_l4_port()
839 # Specifying a L4 port requires that IP protcol is
840 # one of {ICMP, TCP, UDP}
841 if flip_coin():
842 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700843 self.match.wildcards = wildcard_set(self.match.wildcards, \
844 ofp.OFPFW_NW_PROTO, \
845 0 \
846 )
rootf6af1672012-04-06 09:46:29 -0700847 # Specifying a L4 port requirues that Ethertype is IP
848 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700849 self.match.wildcards = wildcard_set(self.match.wildcards, \
850 ofp.OFPFW_DL_TYPE, \
851 0 \
852 )
rootf6af1672012-04-06 09:46:29 -0700853 if self.match.nw_proto == 1:
854 self.match.tp_dst = self.match.tp_dst & 0xff
855 else:
Howard Persh3340d452012-04-06 16:45:21 -0700856 self.match.wildcards = wildcard_set(self.match.wildcards, \
857 ofp.OFPFW_TP_DST, \
858 1 \
859 )
rootf6af1672012-04-06 09:46:29 -0700860
861 # If nothing is wildcarded, it is an exact flow spec -- some switches
Howard Persh3340d452012-04-06 16:45:21 -0700862 # (Open vSwitch, for one) *require* that exact flow specs
863 # have priority 65535.
864 self.priority = 65535 if self.match.wildcards == 0 \
865 else fi.rand_priority()
rootf6af1672012-04-06 09:46:29 -0700866
867 # N.B. Don't make the timeout too short, else the flow might
868 # disappear before we get a chance to check for it.
869 t = random.randint(0, 65535)
870 self.idle_timeout = 0 if t < 60 else t
871 t = random.randint(0, 65535)
872 self.hard_timeout = 0 if t < 60 else t
873
874 self.rand_mod(fi, valid_actions, valid_ports)
875
876 return self
877
878 # Return flow cfg in canonical form
Howard Persh3340d452012-04-06 16:45:21 -0700879 # - There are dependencies between flow qualifiers, e.g. it only makes
880 # sense to qualify nw_proto if dl_type is qualified to be 0x0800 (IP).
881 # The canonical form of flow match criteria will "wildcard out"
882 # all such cases.
rootf6af1672012-04-06 09:46:29 -0700883 def canonical(self):
884 result = copy.deepcopy(self)
885 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
886 or result.match.dl_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700887 # dl_tyoe is wildcarded, or specified as something other
888 # than IP or ARP
rootf6af1672012-04-06 09:46:29 -0700889 # => nw_src and nw_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700890 result.match.wildcards = wildcard_set(result.match.wildcards, \
891 ofp.OFPFW_NW_SRC_MASK, \
892 32 \
893 )
894 result.match.wildcards = wildcard_set(result.match.wildcards, \
895 ofp.OFPFW_NW_DST_MASK, \
896 32 \
897 )
rootf6af1672012-04-06 09:46:29 -0700898 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
899 or result.match.dl_type != 0x0800:
900 # dl_type is wildcarded, or specified as something other than IP
Howard Persh3340d452012-04-06 16:45:21 -0700901 # => nw_proto, nw_tos, tp_src and tp_dst cannot be specified,
902 # must be wildcarded
903 result.match.wildcards = wildcard_set(result.match.wildcards, \
904 ofp.OFPFW_NW_PROTO, \
905 1 \
906 )
907 result.match.wildcards = wildcard_set(result.match.wildcards, \
908 ofp.OFPFW_NW_TOS, \
909 1 \
910 )
911 result.match.wildcards = wildcard_set(result.match.wildcards, \
912 ofp.OFPFW_TP_SRC, \
913 1 \
914 )
915 result.match.wildcards = wildcard_set(result.match.wildcards, \
916 ofp.OFPFW_TP_DST, \
917 1 \
918 )
rootf6af1672012-04-06 09:46:29 -0700919 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
920 or result.match.nw_proto not in [1, 6, 17]:
Howard Persh3340d452012-04-06 16:45:21 -0700921 # nw_proto is wildcarded, or specified as something other than ICMP,
922 # TCP or UDP
rootf6af1672012-04-06 09:46:29 -0700923 # => tp_src and tp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700924 result.match.wildcards = wildcard_set(result.match.wildcards, \
925 ofp.OFPFW_TP_SRC, \
926 1 \
927 )
928 result.match.wildcards = wildcard_set(result.match.wildcards, \
929 ofp.OFPFW_TP_DST, \
930 1 \
931 )
rootf6af1672012-04-06 09:46:29 -0700932 return result
933
Howard Persh680b92a2012-03-31 13:34:35 -0700934 # Overlap check
935 # delf == True <=> Check for delete overlap, else add overlap
936 # "Add overlap" is defined as there exists a packet that could match both the
937 # receiver and argument flowspecs
938 # "Delete overlap" is defined as the specificity of the argument flowspec
939 # is greater than or equal to the specificity of the receiver flowspec
940 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -0700941 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
942 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700943 if self.match.in_port != x.match.in_port:
944 return False # Both specified, and not equal
945 elif delf:
946 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700947 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
948 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700949 if self.match.dl_vlan != x.match.dl_vlan:
950 return False # Both specified, and not equal
951 elif delf:
952 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700953 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
954 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700955 if self.match.dl_src != x.match.dl_src:
956 return False # Both specified, and not equal
957 elif delf:
958 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700959 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
960 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700961 if self.match.dl_dst != x.match.dl_dst:
962 return False # Both specified, and not equal
963 elif delf:
964 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700965 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
966 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700967 if self.match.dl_type != x.match.dl_type:
968 return False # Both specified, and not equal
969 elif delf:
970 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -0700971 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
972 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700973 if self.match.nw_proto != x.match.nw_proto:
974 return False # Both specified, and not equal
975 elif delf:
976 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700977 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
978 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700979 if self.match.tp_src != x.match.tp_src:
980 return False # Both specified, and not equal
981 elif delf:
982 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700983 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
984 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700985 if self.match.tp_dst != x.match.tp_dst:
986 return False # Both specified, and not equal
987 elif delf:
988 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700989 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
990 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700991 if delf and na < nb:
992 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -0700993 if (na < 32 and nb < 32):
994 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
995 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -0700996 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -0700997 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
998 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700999 if delf and na < nb:
1000 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001001 if (na < 32 and nb < 32):
1002 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1003 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
rootf6af1672012-04-06 09:46:29 -07001004 return False # Overlapping bits not equal
1005 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
1006 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001007 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
1008 return False # Both specified, and not equal
1009 elif delf:
1010 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001011 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
1012 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001013 if self.match.nw_tos != x.match.nw_tos:
1014 return False # Both specified, and not equal
1015 elif delf:
1016 return False # Receiver more specific
1017 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -07001018
1019 def to_flow_mod_msg(self, msg):
1020 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -07001021 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001022 msg.idle_timeout = self.idle_timeout
1023 msg.hard_timeout = self.hard_timeout
1024 msg.priority = self.priority
1025 msg.actions = self.actions
1026 return msg
1027
1028 def from_flow_stat(self, msg):
1029 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -07001030 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001031 self.idle_timeout = msg.idle_timeout
1032 self.hard_timeout = msg.hard_timeout
1033 self.priority = msg.priority
1034 self.actions = msg.actions
1035
rootf6af1672012-04-06 09:46:29 -07001036 def from_flow_rem(self, msg):
1037 self.match = msg.match
1038 self.idle_timeout = msg.idle_timeout
1039 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -07001040
Howard Pershc7963582012-03-29 10:02:59 -07001041
rootf6af1672012-04-06 09:46:29 -07001042class Flow_Tbl:
1043 def clear(self):
1044 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001045
rootf6af1672012-04-06 09:46:29 -07001046 def __init__(self):
1047 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001048
rootf6af1672012-04-06 09:46:29 -07001049 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001050 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001051
1052 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001053 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001054
1055 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001056 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001057
1058 def values(self):
1059 return self.dict.values()
1060
1061 def count(self):
1062 return len(self.dict)
1063
1064 def rand(self, sw, fi, num_flows):
1065 self.clear()
1066 i = 0
1067 tbl = 0
1068 j = 0
1069 while i < num_flows:
1070 fc = Flow_Cfg()
1071 fc.rand(fi, \
1072 sw.tbl_stats.stats[tbl].wildcards, \
1073 sw.sw_features.actions, \
1074 sw.valid_ports \
1075 )
1076 fc = fc.canonical()
1077 if self.find(fc):
1078 continue
1079 fc.send_rem = False
1080 self.insert(fc)
1081 i = i + 1
1082 j = j + 1
1083 if j >= sw.tbl_stats.stats[tbl].max_entries:
1084 tbl = tbl + 1
1085 j = 0
1086
1087
Howard Persh3340d452012-04-06 16:45:21 -07001088error_msgs = []
1089removed_msgs = []
1090
1091def error_handler(self, msg, rawmsg):
1092 pa_logger.debug("Got an ERROR message, type=%d, code=%d" \
1093 % (msg.type, msg.code) \
1094 )
1095 global error_msgs
1096 error_msgs.append(msg)
1097 pass
1098
1099def removed_handler(self, msg, rawmsg):
1100 pa_logger.debug("Got a REMOVED message")
1101 global removed_msgs
1102 removed_msgs.append(msg)
1103 pass
1104
rootf6af1672012-04-06 09:46:29 -07001105class Switch:
1106 # Members:
1107 # controller - switch's test controller
1108 # sw_features - switch's OFPT_FEATURES_REPLY message
1109 # valid_ports - list of valid port numbers
1110 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1111 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1112 # flow_tbl - (test's idea of) switch's flow table
1113
1114 def __init__(self):
1115 self.controller = None
1116 self.sw_features = None
1117 self.valid_ports = []
1118 self.tbl_stats = None
1119 self.flow_stats = None
1120 self.flow_tbl = Flow_Tbl()
1121
Howard Persh3340d452012-04-06 16:45:21 -07001122 def controller_set(self, controller):
1123 self.controller = controller
1124 # Register error message handler
1125 global error_msgs
1126 error_msgs = []
1127 controller.register(ofp.OFPT_ERROR, error_handler)
1128 controller.register(ofp.OFPT_FLOW_REMOVED, removed_handler)
1129
rootf6af1672012-04-06 09:46:29 -07001130 def features_get(self):
1131 # Get switch features
1132 request = message.features_request()
1133 (self.sw_features, pkt) = self.controller.transact(request, timeout=2)
1134 if self.sw_features is None:
1135 return False
1136 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Howard Persh3340d452012-04-06 16:45:21 -07001137 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1138 # is that universal?
1139
1140 # TBD - There seems to be variability in which switches support which
1141 # ports; need to sort that out
1142 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1143# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1144# ofp.OFPP_NORMAL, \
1145# ofp.OFPP_FLOOD, \
1146# ofp.OFPP_ALL, \
1147# ofp.OFPP_CONTROLLER \
1148# ] \
1149# )
rootf6af1672012-04-06 09:46:29 -07001150 return True
1151
1152 def tbl_stats_get(self):
1153 # Get table stats
Howard Persh680b92a2012-03-31 13:34:35 -07001154 request = message.table_stats_request()
rootf6af1672012-04-06 09:46:29 -07001155 (self.tbl_stats, pkt) = self.controller.transact(request, timeout=2)
1156 return (self.tbl_stats is not None)
Howard Persh680b92a2012-03-31 13:34:35 -07001157
rootf6af1672012-04-06 09:46:29 -07001158 def flow_stats_get(self):
1159 request = message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -07001160 query_match = ofp.ofp_match()
1161 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001162 request.match = query_match
1163 request.table_id = 0xff
1164 request.out_port = ofp.OFPP_NONE;
Howard Persh3340d452012-04-06 16:45:21 -07001165 if self.controller.message_send(request) == -1:
1166 return False
1167 # <TBD>
1168 # Glue together successive reponse messages for stats reply.
1169 # Looking at the "more" flag and performing re-assembly
1170 # should be a part of the infrastructure.
1171 # </TBD>
1172 n = 0
1173 while True:
1174 # TBD - Check for "more" flag
1175 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY, 1)
1176 if resp is None:
1177 break
1178 if n == 0:
1179 self.flow_stats = resp
1180 else:
1181 self.flow_stats.stats.extend(resp.stats)
1182 n = n + 1
1183 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001184
rootf6af1672012-04-06 09:46:29 -07001185 def flow_add(self, flow_cfg, overlapf = False):
Howard Persh680b92a2012-03-31 13:34:35 -07001186 flow_mod_msg = message.flow_mod()
1187 flow_mod_msg.command = ofp.OFPFC_ADD
1188 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001189 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001190 if overlapf:
1191 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001192 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001193 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
rootf6af1672012-04-06 09:46:29 -07001194 return (self.controller.message_send(flow_mod_msg) != -1)
Howard Persh680b92a2012-03-31 13:34:35 -07001195
rootf6af1672012-04-06 09:46:29 -07001196 def flow_mod(self, flow_cfg, strictf):
Howard Persh680b92a2012-03-31 13:34:35 -07001197 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001198 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf \
1199 else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -07001200 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001201 flow_cfg.to_flow_mod_msg(flow_mod_msg)
1202 return (self.controller.message_send(flow_mod_msg) != -1)
1203
1204 def flow_del(self, flow_cfg, strictf):
1205 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001206 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf \
1207 else ofp.OFPFC_DELETE
rootf6af1672012-04-06 09:46:29 -07001208 flow_mod_msg.buffer_id = 0xffffffff
1209 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001210 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001211 flow_cfg.to_flow_mod_msg(flow_mod_msg)
1212 return (self.controller.message_send(flow_mod_msg) != -1)
1213
1214 def barrier(self):
1215 barrier = message.barrier_request()
1216 (resp, pkt) = self.controller.transact(barrier, 5)
1217 return (resp is not None)
1218
Howard Persh3340d452012-04-06 16:45:21 -07001219 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001220 result = True
Howard Persh3340d452012-04-06 16:45:21 -07001221 global error_msgs
1222 pa_logger.debug("Expecting %d error messages" % (num_exp))
1223 num_got = len(error_msgs)
1224 pa_logger.debug("Got %d error messages" % (num_got))
1225 if num_got != num_exp:
1226 pa_logger.error("Incorrect number of error messages received")
1227 result = False
1228 if num_exp == 0:
1229 return result
1230 elif num_exp == 1:
1231 pa_logger.debug("Expecting error message, type=%d, code=%d" \
1232 % (type, code) \
1233 )
1234 f = False
1235 for e in error_msgs:
1236 if e.type == type and e.code == code:
1237 pa_logger.debug("Got it")
1238 f = True
1239 if not f:
1240 pa_logger.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001241 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001242 else:
1243 pa_logger.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001244 result = False
1245 return result
1246
Howard Persh3340d452012-04-06 16:45:21 -07001247 def removed_verify(self, num_exp):
1248 result = True
1249 global removed_msgs
1250 pa_logger.debug("Expecting %d removed messages" % (num_exp))
1251 num_got = len(removed_msgs)
1252 pa_logger.debug("Got %d removed messages" % (num_got))
1253 if num_got != num_exp:
1254 pa_logger.error("Incorrect number of removed messages received")
1255 result = False
1256 if num_exp < 2:
1257 return result
1258 pa_logger.error("Can't expect more than 1 error message type")
1259 return False
1260
1261
1262# pa_logger.debug("Expecting %d error messages" % (num))
1263# if num > 0:
1264# pa_logger.debug("with type=%d code=%d" % (type, code))
1265# result = True
1266# n = 0
1267# while True:
1268# (errmsg, pkt) = self.controller.poll(ofp.OFPT_ERROR, 1)
1269# if errmsg is None:
1270# break
1271# pa_logger.debug("Got error message, type=%d, code=%d" \
1272# % (errmsg.type, errmsg.code) \
1273# )
1274# if num == 0 or errmsg.type != type or errmsg.code != code:
1275# pa_logger.debug("Unexpected error message")
1276# result = False
1277# n = n + 1
1278# if n != num:
1279# pa_logger.error("Received %d error messages" % (n))
1280# result = False
1281# return result
1282
rootf6af1672012-04-06 09:46:29 -07001283 def flow_tbl_verify(self):
1284 result = True
1285
1286 # Verify flow count in switch
1287 pa_logger.debug("Reading table stats")
1288 pa_logger.debug("Expecting %d flows" % (self.flow_tbl.count()))
1289 if not self.tbl_stats_get():
1290 pa_logger.error("Get table stats failed")
1291 return False
1292 n = 0
1293 for ts in self.tbl_stats.stats:
1294 n = n + ts.active_count
1295 pa_logger.debug("Table stats reported %d active flows" \
1296 % (n) \
1297 )
1298 if n != self.flow_tbl.count():
1299 pa_logger.error("Incorrect number of active flows reported")
1300 result = False
1301
1302 # Read flows from switch
1303 pa_logger.debug("Retrieving flows from switch")
1304 pa_logger.debug("Expecting %d flows" % (self.flow_tbl.count()))
1305 if not self.flow_stats_get():
1306 pa_logger.error("Get flow stats failed")
1307 return False
1308 pa_logger.debug("Retrieved %d flows" % (len(self.flow_stats.stats)))
1309
1310 # Verify flows returned by switch
1311
1312 if len(self.flow_stats.stats) != self.flow_tbl.count():
1313 pa_logger.error("Switch reported incorrect number of flows")
1314 result = False
1315
1316 pa_logger.debug("Verifying received flows")
1317 for fc in self.flow_tbl.values():
1318 fc.matched = False
1319 for fs in self.flow_stats.stats:
1320 flow_in = Flow_Cfg()
1321 flow_in.from_flow_stat(fs)
1322 pa_logger.debug("Received flow:")
1323 pa_logger.debug(str(flow_in))
1324 fc = self.flow_tbl.find(flow_in)
1325 if fc is None:
1326 pa_logger.error("does not match any defined flow")
1327 result = False
1328 elif fc.matched:
1329 pa_logger.error("re-matches defined flow:")
1330 pa_logger.debug(str(fc))
1331 result = False
1332 else:
1333 pa_logger.debug("matched")
1334 if not flow_in == fc:
1335 pa_logger.error("Non-key portions of flow do not match")
1336 result = False
1337 fc.matched = True
1338 for fc in self.flow_tbl.values():
1339 if not fc.matched:
1340 pa_logger.error("Defined flow:")
1341 pa_logger.error(str(fc))
1342 pa_logger.error("was not returned by switch")
1343 result = False
1344
1345 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001346
1347
rootf6af1672012-04-06 09:46:29 -07001348class Flow_Add_5(basic.SimpleProtocol):
1349 """
1350 Test FLOW_ADD_5 from draft top-half test plan
1351
1352 INPUTS
1353 num_flows - Number of flows to generate
1354 """
Howard Persh680b92a2012-03-31 13:34:35 -07001355
rootf6af1672012-04-06 09:46:29 -07001356 def runTest(self):
1357 pa_logger.debug("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001358
rootf6af1672012-04-06 09:46:29 -07001359 num_flows = test_param_get(pa_config, "num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001360
Howard Pershc7963582012-03-29 10:02:59 -07001361 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001362
1363 pa_logger.debug("Deleting all flows from switch")
Howard Pershc7963582012-03-29 10:02:59 -07001364 rc = delete_all_flows(self.controller, pa_logger)
1365 self.assertEqual(rc, 0, "Failed to delete all flows")
1366
rootf6af1672012-04-06 09:46:29 -07001367 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001368
rootf6af1672012-04-06 09:46:29 -07001369 pa_logger.debug("Getting switch capabilities")
1370 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001371 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001372 self.assertTrue(sw.features_get(), "Get switch features failed")
1373 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
Howard Pershc7963582012-03-29 10:02:59 -07001374
rootf6af1672012-04-06 09:46:29 -07001375 if num_flows == 0:
1376 # Number of flows requested was 0
1377 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001378
rootf6af1672012-04-06 09:46:29 -07001379 for ts in sw.tbl_stats.stats:
1380 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001381
rootf6af1672012-04-06 09:46:29 -07001382 pa_logger.debug("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001383
1384 # Dream up some flow information, i.e. space to chose from for
1385 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001386
rootf6af1672012-04-06 09:46:29 -07001387 fi = Flow_Info()
1388 fi.rand(2 * int(math.log(num_flows)))
Howard Pershc7963582012-03-29 10:02:59 -07001389
rootf6af1672012-04-06 09:46:29 -07001390 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001391
rootf6af1672012-04-06 09:46:29 -07001392 ft = Flow_Tbl()
1393 ft.rand(sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001394
rootf6af1672012-04-06 09:46:29 -07001395 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001396
rootf6af1672012-04-06 09:46:29 -07001397 pa_logger.debug("Sending flow adds to switch")
1398 for fc in ft.values(): # Randomizes order of sending
1399 pa_logger.debug("Adding flow:")
1400 pa_logger.debug(str(fc));
1401 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001402
rootf6af1672012-04-06 09:46:29 -07001403 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001404
rootf6af1672012-04-06 09:46:29 -07001405 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001406
rootf6af1672012-04-06 09:46:29 -07001407 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001408
rootf6af1672012-04-06 09:46:29 -07001409 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001410
rootf6af1672012-04-06 09:46:29 -07001411 if not sw.errors_verify(0):
1412 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001413
rootf6af1672012-04-06 09:46:29 -07001414 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001415
rootf6af1672012-04-06 09:46:29 -07001416 sw.flow_tbl = ft
1417 if not sw.flow_tbl_verify():
1418 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001419
rootf6af1672012-04-06 09:46:29 -07001420 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
1421 pa_logger.debug("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001422
Howard Pershc7963582012-03-29 10:02:59 -07001423
rootf6af1672012-04-06 09:46:29 -07001424class Flow_Add_5_1(basic.SimpleProtocol):
1425 """
1426 Test FLOW_ADD_5.1 from draft top-half test plan
1427
1428 INPUTS
1429 None
1430 """
1431
1432 def runTest(self):
1433 pa_logger.debug("Flow_Add_5_1 TEST BEGIN")
1434
1435 num_flows = test_param_get(pa_config, "num_flows", 100)
1436
1437 # Clear all flows from switch
1438
1439 pa_logger.debug("Deleting all flows from switch")
1440 rc = delete_all_flows(self.controller, pa_logger)
1441 self.assertEqual(rc, 0, "Failed to delete all flows")
1442
1443 # Get switch capabilites
1444
1445 pa_logger.debug("Getting switch capabilities")
1446 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001447 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001448 self.assertTrue(sw.features_get(), "Get switch features failed")
1449 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1450
1451 # Dream up some flow information, i.e. space to chose from for
1452 # random flow parameter generation
1453
1454 fi = Flow_Info()
1455 fi.rand(10)
1456
1457 # Dream up a flow config that will be canonicalized by the switch
1458
1459 while True:
1460 fc = Flow_Cfg()
1461 fc.rand(fi, \
1462 sw.tbl_stats.stats[0].wildcards, \
1463 sw.sw_features.actions, \
1464 sw.valid_ports \
1465 )
1466 fcc = fc.canonical()
1467 if fcc != fc:
1468 break
1469
1470 ft = Flow_Tbl()
1471 ft.insert(fcc)
1472
1473 # Send it to the switch
1474
1475 pa_logger.debug("Sending flow add to switch:")
1476 pa_logger.debug(str(fc))
1477 pa_logger.debug("should be canonicalized as:")
1478 pa_logger.debug(str(fcc))
1479 fc.send_rem = False
1480 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1481
1482 # Do barrier, to make sure all flows are in
1483
1484 self.assertTrue(sw.barrier(), "Barrier failed")
1485
1486 result = True
1487
1488 # Check for any error messages
1489
1490 if not sw.errors_verify(0):
1491 result = False
1492
1493 # Verify flow table
1494
1495 sw.flow_tbl = ft
1496 if not sw.flow_tbl_verify():
1497 result = False
1498
1499 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
1500 pa_logger.debug("Flow_Add_5_1 TEST PASSED")
1501
1502
Howard Persh3340d452012-04-06 16:45:21 -07001503# Disabled because of bogus capacity reported by OVS.
1504# Should be DUT dependent.
1505test_prio["Flow_Add_6"] = -1
1506
rootf6af1672012-04-06 09:46:29 -07001507class Flow_Add_6(basic.SimpleProtocol):
1508 """
1509 Test FLOW_ADD_6 from draft top-half test plan
1510
1511 INPUTS
1512 num_flows - Number of flows to generate
1513 """
Howard Pershc7963582012-03-29 10:02:59 -07001514
1515 def runTest(self):
rootf6af1672012-04-06 09:46:29 -07001516 pa_logger.debug("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001517
rootf6af1672012-04-06 09:46:29 -07001518 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001519
rootf6af1672012-04-06 09:46:29 -07001520 pa_logger.debug("Deleting all flows from switch")
1521 rc = delete_all_flows(self.controller, pa_logger)
1522 self.assertEqual(rc, 0, "Failed to delete all flows")
1523
1524 # Get switch capabilites
1525
1526 pa_logger.debug("Getting switch capabilities")
1527 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001528 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001529 self.assertTrue(sw.features_get(), "Get switch features failed")
1530 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1531
root2843d2b2012-04-06 10:27:46 -07001532 num_flows = 0
rootf6af1672012-04-06 09:46:29 -07001533 for ts in sw.tbl_stats.stats:
1534 num_flows = num_flows + ts.max_entries
1535
1536 pa_logger.debug("Switch capacity is %d flows" % (num_flows))
1537 pa_logger.debug("Generating %d flows" % (num_flows))
1538
1539 # Dream up some flow information, i.e. space to chose from for
1540 # random flow parameter generation
1541
1542 fi = Flow_Info()
1543 fi.rand(2 * int(math.log(num_flows)))
1544
1545 # Create a flow table, to switch's capacity
1546
1547 ft = Flow_Tbl()
1548 ft.rand(sw, fi, num_flows)
1549
1550 # Send flow table to switch
1551
1552 pa_logger.debug("Sending flow adds to switch")
1553 for fc in ft.values(): # Randomizes order of sending
1554 pa_logger.debug("Adding flow:")
1555 pa_logger.debug(str(fc));
1556 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1557
1558 # Do barrier, to make sure all flows are in
1559
1560 self.assertTrue(sw.barrier(), "Barrier failed")
1561
1562 result = True
1563
1564 # Check for any error messages
1565
1566 if not sw.errors_verify(0):
1567 result = False
1568
1569 # Dream up one more flow
1570
1571 pa_logger.debug("Creating one more flow")
1572 while True:
1573 fc = Flow_Cfg()
1574 fc.rand(fi, \
1575 sw.tbl_stats.stats[tbl].wildcards, \
1576 sw.sw_features.actions, \
1577 sw.valid_ports \
1578 )
1579 fc = fc.canonical()
1580 if ft.find(fc):
1581 continue
1582
1583 # Send one-more flow
1584
1585 fc.send_rem = False
1586 pa_logger.debug("Sending flow add switch")
1587 pa_logger.debug(str(fc));
1588 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1589
1590 # Do barrier, to make sure all flows are in
1591
1592 self.assertTrue(sw.barrier(), "Barrier failed")
1593
1594 # Check for expected error message
1595
1596 if not sw.errors_verify(1, \
1597 ofp.OFPET_FLOW_MOD_FAILED, \
1598 ofp.OFPFMFC_ALL_TABLES_FULL \
1599 ):
1600 result = False
1601
1602 # Verify flow table
1603
1604 sw.flow_tbl = ft
1605 if not sw.flow_tbl_verify():
1606 result = False
1607
1608 self.assertTrue(result, "Flow_add_6 TEST FAILED")
1609 pa_logger.debug("Flow_add_6 TEST PASSED")
1610
1611
1612class Flow_Add_7(basic.SimpleProtocol):
1613 """
1614 Test FLOW_ADD_7 from draft top-half test plan
1615
1616 INPUTS
1617 None
1618 """
1619
1620 def runTest(self):
1621 pa_logger.debug("Flow_Add_7 TEST BEGIN")
1622
1623 # Clear all flows from switch
1624
1625 pa_logger.debug("Deleting all flows from switch")
1626 rc = delete_all_flows(self.controller, pa_logger)
1627 self.assertEqual(rc, 0, "Failed to delete all flows")
1628
1629 # Get switch capabilites
1630
1631 pa_logger.debug("Getting switch capabilities")
1632 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001633 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001634 self.assertTrue(sw.features_get(), "Get switch features failed")
1635 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1636
1637 # Dream up some flow information, i.e. space to chose from for
1638 # random flow parameter generation
1639
1640 fi = Flow_Info()
1641 fi.rand(10)
1642
1643 # Dream up a flow config
1644
1645 fc = Flow_Cfg()
1646 fc.rand(fi, \
1647 sw.tbl_stats.stats[0].wildcards, \
1648 sw.sw_features.actions, \
1649 sw.valid_ports \
1650 )
1651 fc = fc.canonical()
1652
1653 # Send it to the switch
1654
1655 pa_logger.debug("Sending flow add to switch:")
1656 pa_logger.debug(str(fc))
1657 ft = Flow_Tbl()
1658 fc.send_rem = False
1659 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1660 ft.insert(fc)
1661
1662 # Dream up some different actions, with the same flow key
1663
1664 fc2 = copy.deepcopy(fc)
1665 while True:
1666 fc2.rand_mod(fi, \
1667 sw.sw_features.actions, \
1668 sw.valid_ports \
1669 )
1670 if fc2 != fc:
1671 break
1672
1673 # Send that to the switch
1674
1675 pa_logger.debug("Sending flow add to switch:")
1676 pa_logger.debug(str(fc2))
1677 fc2.send_rem = False
1678 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
1679 ft.insert(fc2)
1680
1681 # Do barrier, to make sure all flows are in
1682
1683 self.assertTrue(sw.barrier(), "Barrier failed")
1684
1685 result = True
1686
1687 # Check for any error messages
1688
1689 if not sw.errors_verify(0):
1690 result = False
1691
1692 # Verify flow table
1693
1694 sw.flow_tbl = ft
1695 if not sw.flow_tbl_verify():
1696 result = False
1697
1698 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
1699 pa_logger.debug("Flow_Add_7 TEST PASSED")
1700
1701
1702class Flow_Add_8(basic.SimpleProtocol):
1703 """
1704 Test FLOW_ADD_8 from draft top-half test plan
1705
1706 INPUTS
1707 None
1708 """
1709
1710 def runTest(self):
1711 pa_logger.debug("Flow_Add_8 TEST BEGIN")
1712
1713 # Clear all flows from switch
1714
1715 pa_logger.debug("Deleting all flows from switch")
1716 rc = delete_all_flows(self.controller, pa_logger)
1717 self.assertEqual(rc, 0, "Failed to delete all flows")
1718
1719 # Get switch capabilites
1720
1721 pa_logger.debug("Getting switch capabilities")
1722 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001723 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001724 self.assertTrue(sw.features_get(), "Get switch features failed")
1725 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1726
1727 # Dream up some flow information, i.e. space to chose from for
1728 # random flow parameter generation
1729
1730 fi = Flow_Info()
1731 fi.rand(10)
1732
1733 # Dream up a flow config, with at least 1 qualifier specified
1734
1735 fc = Flow_Cfg()
1736 while True:
1737 fc.rand(fi, \
1738 sw.tbl_stats.stats[0].wildcards, \
1739 sw.sw_features.actions, \
1740 sw.valid_ports \
1741 )
1742 fc = fc.canonical()
1743 if fc.match.wildcards != ofp.OFPFW_ALL:
1744 break
1745
1746 # Send it to the switch
1747
1748 pa_logger.debug("Sending flow add to switch:")
1749 pa_logger.debug(str(fc))
1750 ft = Flow_Tbl()
1751 fc.send_rem = False
1752 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1753 ft.insert(fc)
1754
1755 # Wildcard out one qualifier that was specified, to create an
1756 # overlapping flow
1757
1758 fc2 = copy.deepcopy(fc)
1759 for wi in shuffle(range(len(all_wildcards_list))):
1760 w = all_wildcards_list[wi]
1761 if (fc2.match.wildcards & w) == 0:
1762 break
1763 if w == ofp.OFPFW_NW_SRC_MASK:
1764 w = ofp.OFPFW_NW_SRC_ALL
1765 wn = "OFPFW_NW_SRC"
1766 elif w == ofp.OFPFW_NW_DST_MASK:
1767 w = ofp.OFPFW_NW_DST_ALL
1768 wn = "OFPFW_NW_DST"
1769 else:
1770 wn = all_wildcard_names[w]
1771 pa_logger.debug("Wildcarding out %s" % (wn))
1772 fc2.match.wildcards = fc2.match.wildcards | w
1773
1774 # Send that to the switch, with overlap checking
1775
1776 pa_logger.debug("Sending flow add to switch:")
1777 pa_logger.debug(str(fc2))
1778 fc2.send_rem = False
1779 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
1780
1781 # Do barrier, to make sure all flows are in
1782 self.assertTrue(sw.barrier(), "Barrier failed")
1783
1784 result = True
1785
1786 # Check for expected error message
1787
1788 if not sw.errors_verify(1, \
1789 ofp.OFPET_FLOW_MOD_FAILED, \
1790 ofp.OFPFMFC_OVERLAP \
1791 ):
1792 result = False
1793
1794 # Verify flow table
1795
1796 sw.flow_tbl = ft
1797 if not sw.flow_tbl_verify():
1798 result = False
1799
1800 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
1801 pa_logger.debug("Flow_Add_8 TEST PASSED")
1802
1803
1804class Flow_Mod_1(basic.SimpleProtocol):
1805 """
1806 Test FLOW_MOD_1 from draft top-half test plan
1807
1808 INPUTS
1809 None
1810 """
1811
1812 def runTest(self):
1813 pa_logger.debug("Flow_Mod_1 TEST BEGIN")
1814
1815 # Clear all flows from switch
1816
1817 pa_logger.debug("Deleting all flows from switch")
1818 rc = delete_all_flows(self.controller, pa_logger)
1819 self.assertEqual(rc, 0, "Failed to delete all flows")
1820
1821 # Get switch capabilites
1822
1823 pa_logger.debug("Getting switch capabilities")
1824 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001825 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001826 self.assertTrue(sw.features_get(), "Get switch features failed")
1827 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1828
1829 # Dream up some flow information, i.e. space to chose from for
1830 # random flow parameter generation
1831
1832 fi = Flow_Info()
1833 fi.rand(10)
1834
1835 # Dream up a flow config
1836
1837 fc = Flow_Cfg()
1838 fc.rand(fi, \
1839 sw.tbl_stats.stats[0].wildcards, \
1840 sw.sw_features.actions, \
1841 sw.valid_ports \
1842 )
1843 fc = fc.canonical()
1844
1845 # Send it to the switch
1846
1847 pa_logger.debug("Sending flow add to switch:")
1848 pa_logger.debug(str(fc))
1849 ft = Flow_Tbl()
1850 fc.send_rem = False
1851 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1852 ft.insert(fc)
1853
1854 # Dream up some different actions, with the same flow key
1855
1856 fc2 = copy.deepcopy(fc)
1857 while True:
1858 fc2.rand_mod(fi, \
1859 sw.sw_features.actions, \
1860 sw.valid_ports \
1861 )
1862 if fc2 != fc:
1863 break
1864
1865 # Send that to the switch
1866
1867 pa_logger.debug("Sending strict flow mod to switch:")
1868 pa_logger.debug(str(fc2))
1869 fc2.send_rem = False
1870 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
1871 ft.insert(fc2)
1872
1873 # Do barrier, to make sure all flows are in
1874
1875 self.assertTrue(sw.barrier(), "Barrier failed")
1876
1877 result = True
1878
1879 # Check for any error messages
1880
1881 if not sw.errors_verify(0):
1882 result = False
1883
1884 # Verify flow table
1885
1886 sw.flow_tbl = ft
1887 if not sw.flow_tbl_verify():
1888 result = False
1889
1890 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
1891 pa_logger.debug("Flow_Mod_1 TEST PASSED")
1892
1893
1894class Flow_Mod_2(basic.SimpleProtocol):
1895 """
1896 Test FLOW_MOD_2 from draft top-half test plan
1897
1898 INPUTS
1899 None
1900 """
1901
1902 def runTest(self):
1903 pa_logger.debug("Flow_Mod_2 TEST BEGIN")
1904
1905 num_flows = test_param_get(pa_config, "num_flows", 100)
1906
1907 # Clear all flows from switch
1908
1909 pa_logger.debug("Deleting all flows from switch")
1910 rc = delete_all_flows(self.controller, pa_logger)
1911 self.assertEqual(rc, 0, "Failed to delete all flows")
1912
1913 # Get switch capabilites
1914
1915 pa_logger.debug("Getting switch capabilities")
1916 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001917 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001918 self.assertTrue(sw.features_get(), "Get switch features failed")
1919 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1920
1921 # Dream up some flow information, i.e. space to chose from for
1922 # random flow parameter generation
1923
1924 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07001925 # Shrunk, to increase chance of meta-matches
1926 fi.rand(int(math.log(num_flows)) / 2)
rootf6af1672012-04-06 09:46:29 -07001927
1928 # Dream up some flows
1929
1930 ft = Flow_Tbl()
1931 ft.rand(sw, fi, num_flows)
1932
1933 # Send flow table to switch
1934
1935 pa_logger.debug("Sending flow adds to switch")
1936 for fc in ft.values(): # Randomizes order of sending
1937 pa_logger.debug("Adding flow:")
1938 pa_logger.debug(str(fc));
1939 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1940
1941 # Do barrier, to make sure all flows are in
1942
1943 self.assertTrue(sw.barrier(), "Barrier failed")
1944
1945 result = True
1946
1947 # Check for any error messages
1948
1949 if not sw.errors_verify(0):
1950 result = False
1951
1952 # Verify flow table
1953
1954 sw.flow_tbl = ft
1955 if not sw.flow_tbl_verify():
1956 result = False
1957
1958 # Pick a random flow as a basis
1959
1960 mfc = copy.deepcopy(ft.values()[0])
1961 mfc.rand_mod(fi, sw.sw_features.actions, sw.valid_ports)
1962
1963 # Repeatedly wildcard qualifiers
1964
1965 for wi in shuffle(range(len(all_wildcards_list))):
1966 w = all_wildcards_list[wi]
1967 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
1968 n = wildcard_get(mfc.match.wildcards, w)
1969 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07001970 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
1971 w, \
1972 random.randint(n + 1, 32) \
1973 )
rootf6af1672012-04-06 09:46:29 -07001974 else:
1975 continue
1976 else:
1977 if wildcard_get(mfc.match.wildcards, w) == 0:
1978 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
1979 else:
1980 continue
1981 mfc = mfc.canonical()
1982
1983 # Count the number of flows that would be modified
1984
1985 n = 0
1986 for fc in ft.values():
1987 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
1988 n = n + 1
1989
1990 # If more than 1, we found our loose delete flow spec
1991 if n > 1:
1992 break
1993
1994 pa_logger.debug("Modifying %d flows" % (n))
1995 pa_logger.debug("Sending flow mod to switch:")
1996 pa_logger.debug(str(mfc))
1997 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
1998
1999 # Do barrier, to make sure all flows are in
2000 self.assertTrue(sw.barrier(), "Barrier failed")
2001
2002 # Check for error message
2003
2004 if not sw.errors_verify(0):
2005 result = False
2006
2007 # Apply flow mod to local flow table
2008
2009 for fc in ft.values():
2010 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002011 fc.cookie = mfc.cookie
2012 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002013
2014 # Verify flow table
2015
2016 sw.flow_tbl = ft
2017 if not sw.flow_tbl_verify():
2018 result = False
2019
2020 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
2021 pa_logger.debug("Flow_Mod_2 TEST PASSED")
2022
2023
2024class Flow_Mod_3(basic.SimpleProtocol):
2025 """
2026 Test FLOW_MOD_3 from draft top-half test plan
2027
2028 INPUTS
2029 None
2030 """
2031
2032 def runTest(self):
2033 pa_logger.debug("Flow_Mod_3 TEST BEGIN")
2034
2035 # Clear all flows from switch
2036
2037 pa_logger.debug("Deleting all flows from switch")
2038 rc = delete_all_flows(self.controller, pa_logger)
2039 self.assertEqual(rc, 0, "Failed to delete all flows")
2040
2041 # Get switch capabilites
2042
2043 pa_logger.debug("Getting switch capabilities")
2044 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002045 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002046 self.assertTrue(sw.features_get(), "Get switch features failed")
2047 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2048
2049 # Dream up some flow information, i.e. space to chose from for
2050 # random flow parameter generation
2051
2052 fi = Flow_Info()
2053 fi.rand(10)
2054
2055 # Dream up a flow config
2056
2057 fc = Flow_Cfg()
2058 fc.rand(fi, \
2059 sw.tbl_stats.stats[0].wildcards, \
2060 sw.sw_features.actions, \
2061 sw.valid_ports \
2062 )
2063 fc = fc.canonical()
2064
2065 # Send it to the switch
2066
2067 pa_logger.debug("Sending flow mod to switch:")
2068 pa_logger.debug(str(fc))
2069 ft = Flow_Tbl()
2070 fc.send_rem = False
2071 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2072 ft.insert(fc)
2073
2074 # Do barrier, to make sure all flows are in
2075
2076 self.assertTrue(sw.barrier(), "Barrier failed")
2077
2078 result = True
2079
2080 # Check for any error messages
2081
2082 if not sw.errors_verify(0):
2083 result = False
2084
2085 # Verify flow table
2086
2087 sw.flow_tbl = ft
2088 if not sw.flow_tbl_verify():
2089 result = False
2090
2091 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
2092 pa_logger.debug("Flow_Mod_3 TEST PASSED")
2093
2094
2095class Flow_Del_1(basic.SimpleProtocol):
2096 """
2097 Test FLOW_DEL_1 from draft top-half test plan
2098
2099 INPUTS
2100 None
2101 """
2102
2103 def runTest(self):
2104 pa_logger.debug("Flow_Del_1 TEST BEGIN")
2105
2106 # Clear all flows from switch
2107
2108 pa_logger.debug("Deleting all flows from switch")
2109 rc = delete_all_flows(self.controller, pa_logger)
2110 self.assertEqual(rc, 0, "Failed to delete all flows")
2111
2112 # Get switch capabilites
2113
2114 pa_logger.debug("Getting switch capabilities")
2115 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002116 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002117 self.assertTrue(sw.features_get(), "Get switch features failed")
2118 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2119
2120 # Dream up some flow information, i.e. space to chose from for
2121 # random flow parameter generation
2122
2123 fi = Flow_Info()
2124 fi.rand(10)
2125
2126 # Dream up a flow config
2127
2128 fc = Flow_Cfg()
2129 fc.rand(fi, \
2130 sw.tbl_stats.stats[0].wildcards, \
2131 sw.sw_features.actions, \
2132 sw.valid_ports \
2133 )
2134 fc = fc.canonical()
2135
2136 # Send it to the switch
2137
2138 pa_logger.debug("Sending flow add to switch:")
2139 pa_logger.debug(str(fc))
2140 ft = Flow_Tbl()
2141 fc.send_rem = False
2142 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2143 ft.insert(fc)
2144
2145 # Dream up some different actions, with the same flow key
2146
2147 fc2 = copy.deepcopy(fc)
2148 while True:
2149 fc2.rand_mod(fi, \
2150 sw.sw_features.actions, \
2151 sw.valid_ports \
2152 )
2153 if fc2 != fc:
2154 break
2155
2156 # Delete strictly
2157
2158 pa_logger.debug("Sending strict flow del to switch:")
2159 pa_logger.debug(str(fc2))
2160 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2161 ft.delete(fc)
2162
2163 # Do barrier, to make sure all flows are in
2164
2165 self.assertTrue(sw.barrier(), "Barrier failed")
2166
2167 result = True
2168
2169 # Check for any error messages
2170
2171 if not sw.errors_verify(0):
2172 result = False
2173
2174 # Verify flow table
2175
2176 sw.flow_tbl = ft
2177 if not sw.flow_tbl_verify():
2178 result = False
2179
2180 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
2181 pa_logger.debug("Flow_Del_1 TEST PASSED")
2182
2183
2184class Flow_Del_2(basic.SimpleProtocol):
2185 """
2186 Test FLOW_DEL_2 from draft top-half test plan
2187
2188 INPUTS
2189 None
2190 """
2191
2192 def runTest(self):
2193 pa_logger.debug("Flow_Del_2 TEST BEGIN")
2194
2195 num_flows = test_param_get(pa_config, "num_flows", 100)
2196
2197 # Clear all flows from switch
2198
2199 pa_logger.debug("Deleting all flows from switch")
2200 rc = delete_all_flows(self.controller, pa_logger)
2201 self.assertEqual(rc, 0, "Failed to delete all flows")
2202
2203 # Get switch capabilites
2204
2205 pa_logger.debug("Getting switch capabilities")
2206 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002207 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002208 self.assertTrue(sw.features_get(), "Get switch features failed")
2209 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2210
2211 # Dream up some flow information, i.e. space to chose from for
2212 # random flow parameter generation
2213
2214 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002215 # Shrunk, to increase chance of meta-matches
2216 fi.rand(int(math.log(num_flows)) / 2)
rootf6af1672012-04-06 09:46:29 -07002217
2218 # Dream up some flows
2219
2220 ft = Flow_Tbl()
2221 ft.rand(sw, fi, num_flows)
2222
2223 # Send flow table to switch
2224
2225 pa_logger.debug("Sending flow adds to switch")
2226 for fc in ft.values(): # Randomizes order of sending
2227 pa_logger.debug("Adding flow:")
2228 pa_logger.debug(str(fc));
2229 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2230
2231 # Do barrier, to make sure all flows are in
2232
2233 self.assertTrue(sw.barrier(), "Barrier failed")
2234
2235 result = True
2236
2237 # Check for any error messages
2238
2239 if not sw.errors_verify(0):
2240 result = False
2241
2242 # Verify flow table
2243
2244 sw.flow_tbl = ft
2245 if not sw.flow_tbl_verify():
2246 result = False
2247
2248 # Pick a random flow as a basis
2249
2250 dfc = copy.deepcopy(ft.values()[0])
2251 dfc.rand_mod(fi, sw.sw_features.actions, sw.valid_ports)
2252
2253 # Repeatedly wildcard qualifiers
2254
2255 for wi in shuffle(range(len(all_wildcards_list))):
2256 w = all_wildcards_list[wi]
2257 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2258 n = wildcard_get(dfc.match.wildcards, w)
2259 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002260 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2261 w, \
2262 random.randint(n + 1, 32) \
2263 )
rootf6af1672012-04-06 09:46:29 -07002264 else:
2265 continue
2266 else:
2267 if wildcard_get(dfc.match.wildcards, w) == 0:
2268 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2269 else:
2270 continue
2271 dfc = dfc.canonical()
2272
2273 # Count the number of flows that would be deleted
2274
2275 n = 0
2276 for fc in ft.values():
2277 if dfc.overlaps(fc, True):
2278 n = n + 1
2279
2280 # If more than 1, we found our loose delete flow spec
2281 if n > 1:
2282 break
2283
2284 pa_logger.debug("Deleting %d flows" % (n))
2285 pa_logger.debug("Sending flow del to switch:")
2286 pa_logger.debug(str(dfc))
2287 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2288
2289 # Do barrier, to make sure all flows are in
2290 self.assertTrue(sw.barrier(), "Barrier failed")
2291
2292 # Check for error message
2293
2294 if not sw.errors_verify(0):
2295 result = False
2296
2297 # Apply flow mod to local flow table
2298
2299 for fc in ft.values():
2300 if dfc.overlaps(fc, True):
2301 ft.delete(fc)
2302
2303 # Verify flow table
2304
2305 sw.flow_tbl = ft
2306 if not sw.flow_tbl_verify():
2307 result = False
2308
2309 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
2310 pa_logger.debug("Flow_Del_2 TEST PASSED")
2311
2312
rootf6af1672012-04-06 09:46:29 -07002313class Flow_Del_4(basic.SimpleProtocol):
2314 """
2315 Test FLOW_DEL_4 from draft top-half test plan
2316
2317 INPUTS
2318 None
2319 """
2320
2321 def runTest(self):
2322 pa_logger.debug("Flow_Del_4 TEST BEGIN")
2323
2324 # Clear all flows from switch
2325
2326 pa_logger.debug("Deleting all flows from switch")
2327 rc = delete_all_flows(self.controller, pa_logger)
2328 self.assertEqual(rc, 0, "Failed to delete all flows")
2329
2330 # Get switch capabilites
2331
2332 pa_logger.debug("Getting switch capabilities")
2333 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002334 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002335 self.assertTrue(sw.features_get(), "Get switch features failed")
2336 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2337
2338 # Dream up some flow information, i.e. space to chose from for
2339 # random flow parameter generation
2340
2341 fi = Flow_Info()
2342 fi.rand(10)
2343
2344 # Dream up a flow config
2345
2346 fc = Flow_Cfg()
2347 fc.rand(fi, \
2348 sw.tbl_stats.stats[0].wildcards, \
2349 sw.sw_features.actions, \
2350 sw.valid_ports \
2351 )
2352 fc = fc.canonical()
2353
2354 # Send it to the switch. with "notify on removed"
2355
2356 pa_logger.debug("Sending flow add to switch:")
2357 pa_logger.debug(str(fc))
2358 ft = Flow_Tbl()
2359 fc.send_rem = True
2360 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2361 ft.insert(fc)
2362
2363 # Dream up some different actions, with the same flow key
2364
2365 fc2 = copy.deepcopy(fc)
2366 while True:
2367 fc2.rand_mod(fi, \
2368 sw.sw_features.actions, \
2369 sw.valid_ports \
2370 )
2371 if fc2 != fc:
2372 break
2373
2374 # Delete strictly
2375
2376 pa_logger.debug("Sending strict flow del to switch:")
2377 pa_logger.debug(str(fc2))
2378 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2379 ft.delete(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 expected "removed" message
2388
Howard Persh3340d452012-04-06 16:45:21 -07002389 if not sw.errors_verify(0):
2390 result = False
2391
2392 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07002393 result = False
2394
2395 # Verify flow table
2396
2397 sw.flow_tbl = ft
2398 if not sw.flow_tbl_verify():
2399 result = False
2400
2401 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
2402 pa_logger.debug("Flow_Del_4 TEST PASSED")
2403