blob: f8990ac011c20031dca7cec5dfb457afc0609cd1 [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
Dan Talayco910a8282012-04-07 00:05:20 -070029fq_port_map = None
30#@var fq_logger Local logger object
31fq_logger = None
32#@var fq_config Local copy of global configuration data
33fq_config = None
Howard Pershc7963582012-03-29 10:02:59 -070034
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
Dan Talayco910a8282012-04-07 00:05:20 -070048 global fq_port_map
49 global fq_logger
50 global fq_config
Howard Pershc7963582012-03-29 10:02:59 -070051
Dan Talayco910a8282012-04-07 00:05:20 -070052 fq_logger = logging.getLogger("flowq")
53 fq_logger.info("Initializing test set")
54 fq_port_map = config["port_map"]
55 fq_config = config
root2843d2b2012-04-06 10:27:46 -070056
Howard Pershc7963582012-03-29 10:02:59 -070057
rootf6af1672012-04-06 09:46:29 -070058def flip_coin():
59 return random.randint(1, 100) <= 50
60
61
Howard Pershc7963582012-03-29 10:02:59 -070062def shuffle(list):
63 n = len(list)
64 lim = n * n
65 i = 0
66 while i < lim:
67 a = random.randint(0, n - 1)
68 b = random.randint(0, n - 1)
69 temp = list[a]
70 list[a] = list[b]
71 list[b] = temp
72 i = i + 1
73 return list
74
75
Howard Persh680b92a2012-03-31 13:34:35 -070076def rand_pick(list):
77 return list[random.randint(0, len(list) - 1)]
Howard Pershc7963582012-03-29 10:02:59 -070078
Howard Persh680b92a2012-03-31 13:34:35 -070079def rand_dl_addr():
80 return [random.randint(0, 255) & ~1,
81 random.randint(0, 255),
82 random.randint(0, 255),
83 random.randint(0, 255),
84 random.randint(0, 255),
85 random.randint(0, 255)
86 ]
Howard Pershc7963582012-03-29 10:02:59 -070087
88def rand_nw_addr():
89 return random.randint(0, (1 << 32) - 1)
90
91
rootf6af1672012-04-06 09:46:29 -070092class Flow_Info:
Howard Persh680b92a2012-03-31 13:34:35 -070093 # Members:
94 # priorities - list of flow priorities
95 # dl_addrs - list of MAC addresses
96 # vlans - list of VLAN ids
97 # ethertypes - list of Ethertypes
98 # ip_addrs - list of IP addresses
99 # ip_tos - list of IP TOS values
100 # ip_protos - list of IP protocols
101 # l4_ports - list of L4 ports
102
103 def __init__(self):
104 priorities = []
105 dl_addrs = []
106 vlans = []
107 ethertypes = []
108 ip_addrs = []
109 ip_tos = []
110 ip_protos = []
111 l4_ports = []
112
113 def rand(self, n):
114 self.priorities = []
115 i = 0
116 while i < n:
117 self.priorities.append(random.randint(1, 65534))
118 i = i + 1
119
120 self.dl_addrs = []
121 i = 0
122 while i < n:
123 self.dl_addrs.append(rand_dl_addr())
124 i = i + 1
125
126 self.vlans = []
127 i = 0
128 while i < n:
129 self.vlans.append(random.randint(1, 4094))
130 i = i + 1
131
rootf6af1672012-04-06 09:46:29 -0700132 self.ethertypes = [0x0800, 0x0806]
Howard Persh680b92a2012-03-31 13:34:35 -0700133 i = 0
134 while i < n:
135 self.ethertypes.append(random.randint(0, (1 << 16) - 1))
136 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700137 self.ethertypes = shuffle(self.ethertypes)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700138
139 self.ip_addrs = []
140 i = 0
141 while i < n:
142 self.ip_addrs.append(rand_nw_addr())
143 i = i + 1
144
145 self.ip_tos = []
146 i = 0
147 while i < n:
148 self.ip_tos.append(random.randint(0, (1 << 8) - 1) & ~3)
149 i = i + 1
150
rootf6af1672012-04-06 09:46:29 -0700151 self.ip_protos = [1, 6, 17]
Howard Persh680b92a2012-03-31 13:34:35 -0700152 i = 0
153 while i < n:
154 self.ip_protos.append(random.randint(0, (1 << 8) - 1))
155 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700156 self.ip_protos = shuffle(self.ip_protos)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700157
158 self.l4_ports = []
159 i = 0
160 while i < n:
161 self.l4_ports.append(random.randint(0, (1 << 16) - 1))
162 i = i + 1
163
164 def rand_priority(self):
165 return rand_pick(self.priorities)
166
167 def rand_dl_addr(self):
168 return rand_pick(self.dl_addrs)
169
170 def rand_vlan(self):
171 return rand_pick(self.vlans)
172
173 def rand_ethertype(self):
174 return rand_pick(self.ethertypes)
175
176 def rand_ip_addr(self):
177 return rand_pick(self.ip_addrs)
178
179 def rand_ip_tos(self):
180 return rand_pick(self.ip_tos)
181
182 def rand_ip_proto(self):
183 return rand_pick(self.ip_protos)
184
185 def rand_l4_port(self):
186 return rand_pick(self.l4_ports)
187
188
Howard Pershc7963582012-03-29 10:02:59 -0700189# TBD - These don't belong here
190
Howard Persh680b92a2012-03-31 13:34:35 -0700191all_wildcards_list = [ofp.OFPFW_IN_PORT,
Howard Persh680b92a2012-03-31 13:34:35 -0700192 ofp.OFPFW_DL_DST,
rootf6af1672012-04-06 09:46:29 -0700193 ofp.OFPFW_DL_SRC,
194 ofp.OFPFW_DL_VLAN,
195 ofp.OFPFW_DL_VLAN_PCP,
Howard Persh680b92a2012-03-31 13:34:35 -0700196 ofp.OFPFW_DL_TYPE,
rootf6af1672012-04-06 09:46:29 -0700197 ofp.OFPFW_NW_TOS,
Howard Persh680b92a2012-03-31 13:34:35 -0700198 ofp.OFPFW_NW_PROTO,
Howard Persh680b92a2012-03-31 13:34:35 -0700199 ofp.OFPFW_NW_SRC_MASK,
200 ofp.OFPFW_NW_DST_MASK,
rootf6af1672012-04-06 09:46:29 -0700201 ofp.OFPFW_TP_SRC,
202 ofp.OFPFW_TP_DST
Howard Persh680b92a2012-03-31 13:34:35 -0700203 ]
Howard Pershc7963582012-03-29 10:02:59 -0700204
Howard Persh3340d452012-04-06 16:45:21 -0700205# TBD - Need this because there are duplicates in ofp.ofp_flow_wildcards_map
206# -- FIX
rootf6af1672012-04-06 09:46:29 -0700207all_wildcard_names = {
208 1 : 'OFPFW_IN_PORT',
209 2 : 'OFPFW_DL_VLAN',
210 4 : 'OFPFW_DL_SRC',
211 8 : 'OFPFW_DL_DST',
212 16 : 'OFPFW_DL_TYPE',
213 32 : 'OFPFW_NW_PROTO',
214 64 : 'OFPFW_TP_SRC',
215 128 : 'OFPFW_TP_DST',
216 1048576 : 'OFPFW_DL_VLAN_PCP',
217 2097152 : 'OFPFW_NW_TOS'
218}
219
220
221def wildcard_set(x, w, val):
222 result = x
223 if w == ofp.OFPFW_NW_SRC_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700224 result = (result & ~ofp.OFPFW_NW_SRC_MASK) \
225 | (val << ofp.OFPFW_NW_SRC_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700226 elif w == ofp.OFPFW_NW_DST_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700227 result = (result & ~ofp.OFPFW_NW_DST_MASK) \
228 | (val << ofp.OFPFW_NW_DST_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700229 elif val == 0:
230 result = result & ~w
231 else:
232 result = result | w
233 return result
234
235def wildcard_get(x, w):
236 if w == ofp.OFPFW_NW_SRC_MASK:
237 return (x & ofp.OFPFW_NW_SRC_MASK) >> ofp.OFPFW_NW_SRC_SHIFT
238 if w == ofp.OFPFW_NW_DST_MASK:
239 return (x & ofp.OFPFW_NW_DST_MASK) >> ofp.OFPFW_NW_DST_SHIFT
240 return 1 if (x & w) != 0 else 0
241
Howard Pershc7963582012-03-29 10:02:59 -0700242
Howard Persh680b92a2012-03-31 13:34:35 -0700243all_actions_list = [ofp.OFPAT_OUTPUT,
244 ofp.OFPAT_SET_VLAN_VID,
245 ofp.OFPAT_SET_VLAN_PCP,
246 ofp.OFPAT_STRIP_VLAN,
247 ofp.OFPAT_SET_DL_SRC,
248 ofp.OFPAT_SET_DL_DST,
249 ofp.OFPAT_SET_NW_SRC,
250 ofp.OFPAT_SET_NW_DST,
251 ofp.OFPAT_SET_NW_TOS,
252 ofp.OFPAT_SET_TP_SRC,
253 ofp.OFPAT_SET_TP_DST,
254 ofp.OFPAT_ENQUEUE
255 ]
256
257def dl_addr_to_str(a):
258 return "%x:%x:%x:%x:%x:%x" % tuple(a)
259
260def ip_addr_to_str(a, n):
rootf6af1672012-04-06 09:46:29 -0700261 if n is not None:
262 a = a & ~((1 << (32 - n)) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700263 result = "%d.%d.%d.%d" % (a >> 24, \
264 (a >> 16) & 0xff, \
265 (a >> 8) & 0xff, \
266 a & 0xff \
267 )
268 if n is not None:
269 result = result + ("/%d" % (n))
270 return result
271
Howard Pershc7963582012-03-29 10:02:59 -0700272
rootf6af1672012-04-06 09:46:29 -0700273class Flow_Cfg:
Howard Pershc7963582012-03-29 10:02:59 -0700274 # Members:
275 # - match
276 # - idle_timeout
277 # - hard_timeout
278 # - priority
279 # - action_list
280
281 def __init__(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700282 self.priority = 0
Howard Pershc7963582012-03-29 10:02:59 -0700283 self.match = parse.ofp_match()
284 self.match.wildcards = ofp.OFPFW_ALL
285 self.idle_timeout = 0
286 self.hard_timeout = 0
Howard Pershc7963582012-03-29 10:02:59 -0700287 self.actions = action_list.action_list()
288
rootf6af1672012-04-06 09:46:29 -0700289 # {pri, match} is considered a flow key
290 def key_equal(self, x):
Howard Persh680b92a2012-03-31 13:34:35 -0700291 if self.priority != x.priority:
292 return False
293 # TBD - Should this logic be moved to ofp_match.__eq__()?
294 if self.match.wildcards != x.match.wildcards:
295 return False
rootf6af1672012-04-06 09:46:29 -0700296 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700297 and self.match.in_port != x.match.in_port:
298 return False
rootf6af1672012-04-06 09:46:29 -0700299 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700300 and self.match.dl_dst != x.match.dl_dst:
301 return False
rootf6af1672012-04-06 09:46:29 -0700302 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0 \
303 and self.match.dl_src != x.match.dl_src:
304 return False
305 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700306 and self.match.dl_vlan != x.match.dl_vlan:
307 return False
rootf6af1672012-04-06 09:46:29 -0700308 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700309 and self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
310 return False
rootf6af1672012-04-06 09:46:29 -0700311 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700312 and self.match.dl_type != x.match.dl_type:
313 return False
rootf6af1672012-04-06 09:46:29 -0700314 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700315 and self.match.nw_tos != x.match.nw_tos:
316 return False
rootf6af1672012-04-06 09:46:29 -0700317 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700318 and self.match.nw_proto != x.match.nw_proto:
319 return False
rootf6af1672012-04-06 09:46:29 -0700320 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
321 if n < 32:
322 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700323 if (self.match.nw_src & m) != (x.match.nw_src & m):
324 return False
rootf6af1672012-04-06 09:46:29 -0700325 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
326 if n < 32:
327 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700328 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
329 return False
rootf6af1672012-04-06 09:46:29 -0700330 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0 \
331 and self.match.tp_src != x.match.tp_src:
Howard Persh680b92a2012-03-31 13:34:35 -0700332 return False
rootf6af1672012-04-06 09:46:29 -0700333 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0 \
334 and self.match.tp_dst != x.match.tp_dst:
335 return False
336 return True
337
338 def non_key_equal(self, x):
339 if self.cookie != x.cookie:
Howard Pershc7963582012-03-29 10:02:59 -0700340 return False
341 if self.idle_timeout != x.idle_timeout:
342 return False
343 if self.hard_timeout != x.hard_timeout:
344 return False
Dan Talayco910a8282012-04-07 00:05:20 -0700345 if True:
346 # For now, compare actions lists as unordered
root2843d2b2012-04-06 10:27:46 -0700347 aa = copy.deepcopy(x.actions.actions)
348 for a in self.actions.actions:
349 i = 0
350 while i < len(aa):
351 if a == aa[i]:
352 break
353 i = i + 1
354 if i < len(aa):
355 aa.pop(i)
356 else:
357 return False
358 return aa == []
359 else:
360 return self.actions == x.actions
rootf6af1672012-04-06 09:46:29 -0700361
root2843d2b2012-04-06 10:27:46 -0700362 def key_str(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700363 result = "priority=%d" % self.priority
364 # TBD - Would be nice if ofp_match.show() was better behaved
365 # (no newlines), and more intuitive (things in hex where approprate), etc.
rootf6af1672012-04-06 09:46:29 -0700366 result = result + (", wildcards=0x%x={" % (self.match.wildcards))
Howard Persh680b92a2012-03-31 13:34:35 -0700367 sep = ""
rootf6af1672012-04-06 09:46:29 -0700368 for w in all_wildcards_list:
369 if (self.match.wildcards & w) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700370 continue
371 if w == ofp.OFPFW_NW_SRC_MASK:
rootf6af1672012-04-06 09:46:29 -0700372 n = wildcard_get(self.match.wildcards, w)
373 if n > 0:
374 result = result + sep + ("OFPFW_NW_SRC(%d)" % (n))
Howard Persh680b92a2012-03-31 13:34:35 -0700375 elif w == ofp.OFPFW_NW_DST_MASK:
rootf6af1672012-04-06 09:46:29 -0700376 n = wildcard_get(self.match.wildcards, w)
377 if n > 0:
378 result = result + sep + ("OFPFW_NW_DST(%d)" % (n))
Howard Persh680b92a2012-03-31 13:34:35 -0700379 else:
rootf6af1672012-04-06 09:46:29 -0700380 result = result + sep + all_wildcard_names[w]
Howard Persh680b92a2012-03-31 13:34:35 -0700381 sep = ", "
382 result = result +"}"
rootf6af1672012-04-06 09:46:29 -0700383 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700384 result = result + (", in_port=%d" % (self.match.in_port))
rootf6af1672012-04-06 09:46:29 -0700385 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700386 result = result + (", dl_dst=%s" \
387 % (dl_addr_to_str(self.match.dl_dst)) \
388 )
rootf6af1672012-04-06 09:46:29 -0700389 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700390 result = result + (", dl_src=%s" \
391 % (dl_addr_to_str(self.match.dl_src)) \
392 )
rootf6af1672012-04-06 09:46:29 -0700393 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700394 result = result + (", dl_vlan=%d" % (self.match.dl_vlan))
rootf6af1672012-04-06 09:46:29 -0700395 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700396 result = result + (", dl_vlan_pcp=%d" % (self.match.dl_vlan_pcp))
rootf6af1672012-04-06 09:46:29 -0700397 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700398 result = result + (", dl_type=0x%x" % (self.match.dl_type))
rootf6af1672012-04-06 09:46:29 -0700399 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700400 result = result + (", nw_tos=0x%x" % (self.match.nw_tos))
rootf6af1672012-04-06 09:46:29 -0700401 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700402 result = result + (", nw_proto=%d" % (self.match.nw_proto))
rootf6af1672012-04-06 09:46:29 -0700403 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700404 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700405 result = result + (", nw_src=%s" % \
406 (ip_addr_to_str(self.match.nw_src, 32 - n)) \
407 )
rootf6af1672012-04-06 09:46:29 -0700408 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700409 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700410 result = result + (", nw_dst=%s" % \
411 (ip_addr_to_str(self.match.nw_dst, 32 - n)) \
412 )
rootf6af1672012-04-06 09:46:29 -0700413 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700414 result = result + (", tp_src=%d" % self.match.tp_src)
rootf6af1672012-04-06 09:46:29 -0700415 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700416 result = result + (", tp_dst=%d" % self.match.tp_dst)
rootf6af1672012-04-06 09:46:29 -0700417 return result
418
419 def __eq__(self, x):
420 return (self.key_equal(x) and self.non_key_equal(x))
421
422 def __str__(self):
root2843d2b2012-04-06 10:27:46 -0700423 result = self.key_str()
424 result = result + (", cookie=%d" % self.cookie)
Howard Persh680b92a2012-03-31 13:34:35 -0700425 result = result + (", idle_timeout=%d" % self.idle_timeout)
426 result = result + (", hard_timeout=%d" % self.hard_timeout)
Howard Persh680b92a2012-03-31 13:34:35 -0700427 for a in self.actions.actions:
428 result = result + (", action=%s" % ofp.ofp_action_type_map[a.type])
429 if a.type == ofp.OFPAT_OUTPUT:
430 result = result + ("(%d)" % (a.port))
431 elif a.type == ofp.OFPAT_SET_VLAN_VID:
432 result = result + ("(%d)" % (a.vlan_vid))
433 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
434 result = result + ("(%d)" % (a.vlan_pcp))
435 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
436 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
437 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
438 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
439 elif a.type == ofp.OFPAT_SET_NW_TOS:
440 result = result + ("(0x%x)" % (a.nw_tos))
441 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
442 result = result + ("(%d)" % (a.tp_port))
443 elif a.type == ofp.OFPAT_ENQUEUE:
444 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
445 return result
Howard Pershc7963582012-03-29 10:02:59 -0700446
Dan Talayco910a8282012-04-07 00:05:20 -0700447 def rand_actions_ordered(self, fi, valid_actions, valid_ports):
Howard Persh3340d452012-04-06 16:45:21 -0700448 # Action lists are ordered, so pick an ordered random subset of
449 # supported actions
Dan Talayco910a8282012-04-07 00:05:20 -0700450 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh3340d452012-04-06 16:45:21 -0700451 supported_actions = []
452 for a in all_actions_list:
453 if ((1 << a) & valid_actions) != 0:
454 supported_actions.append(a)
455
456 supported_actions = shuffle(supported_actions)
457 supported_actions \
458 = supported_actions[0 : random.randint(1, len(supported_actions))]
459
Howard Persh3340d452012-04-06 16:45:21 -0700460 self.actions = action_list.action_list()
461 for a in supported_actions:
Dan Talayco910a8282012-04-07 00:05:20 -0700462 act = None
Howard Persh3340d452012-04-06 16:45:21 -0700463 if a == ofp.OFPAT_OUTPUT:
464 pass # OUTPUT actions must come last
465 elif a == ofp.OFPAT_SET_VLAN_VID:
466 act = action.action_set_vlan_vid()
467 act.vlan_vid = fi.rand_vlan()
Howard Persh3340d452012-04-06 16:45:21 -0700468 elif a == ofp.OFPAT_SET_VLAN_PCP:
469 act = action.action_set_vlan_pcp()
470 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Persh3340d452012-04-06 16:45:21 -0700471 elif a == ofp.OFPAT_STRIP_VLAN:
472 act = action.action_strip_vlan()
Howard Persh3340d452012-04-06 16:45:21 -0700473 elif a == ofp.OFPAT_SET_DL_SRC:
474 act = action.action_set_dl_src()
475 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700476 elif a == ofp.OFPAT_SET_DL_DST:
477 act = action.action_set_dl_dst()
478 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700479 elif a == ofp.OFPAT_SET_NW_SRC:
480 act = action.action_set_nw_src()
481 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700482 elif a == ofp.OFPAT_SET_NW_DST:
483 act = action.action_set_nw_dst()
484 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700485 elif a == ofp.OFPAT_SET_NW_TOS:
486 act = action.action_set_nw_tos()
487 act.nw_tos = fi.rand_ip_tos()
Howard Persh3340d452012-04-06 16:45:21 -0700488 elif a == ofp.OFPAT_SET_TP_SRC:
489 act = action.action_set_tp_src()
490 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700491 elif a == ofp.OFPAT_SET_TP_DST:
492 act = action.action_set_tp_dst()
493 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700494 elif a == ofp.OFPAT_ENQUEUE:
495 pass # Enqueue actions must come last
Dan Talayco910a8282012-04-07 00:05:20 -0700496 if act:
497 act.max_len = ACTION_MAX_LEN
498 self.actions.add(act)
499
Howard Persh3340d452012-04-06 16:45:21 -0700500 p = random.randint(1, 100)
501 if p <= 33:
502 # One third of the time, include ENQUEUE actions at end of list
503 # At most 1 ENQUEUE action
504 act = action.action_enqueue()
505 act.port = rand_pick(valid_ports)
506 # TBD - Limits for queue number?
507 act.queue_id = random.randint(0, 7)
Dan Talayco910a8282012-04-07 00:05:20 -0700508 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700509 self.actions.add(act)
510 elif p <= 66:
511 # One third of the time, include OUTPUT actions at end of list
512 port_idxs = shuffle(range(len(valid_ports)))
513 # Only 1 output action allowed if IN_PORT wildcarded
514 n = 1 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) != 0 \
515 else random.randint(1, len(valid_ports))
516 port_idxs = port_idxs[0 : n]
517 for pi in port_idxs:
518 act = action.action_output()
519 act.port = valid_ports[pi]
Dan Talayco910a8282012-04-07 00:05:20 -0700520 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700521 if act.port != ofp.OFPP_IN_PORT \
522 or wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
523 # OUTPUT(IN_PORT) only valid if OFPFW_IN_PORT not wildcarded
524 self.actions.add(act)
525 else:
526 # One third of the time, include neither
527 pass
528
529
530 # Randomize flow data for flow modifies (i.e. cookie and actions)
rootf6af1672012-04-06 09:46:29 -0700531 def rand_mod(self, fi, valid_actions, valid_ports):
532 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700533
Dan Talayco910a8282012-04-07 00:05:20 -0700534 # By default, test with conservative ordering conventions
535 # This should probably be indicated in a profile
536 if test_param_get(fq_config, "conservative_ordered_actions", True):
537 self.rand_actions_ordered(fi, valid_actions, valid_ports)
Howard Persh3340d452012-04-06 16:45:21 -0700538 return self
539
Howard Persh680b92a2012-03-31 13:34:35 -0700540 # Action lists are ordered, so pick an ordered random subset of
541 # supported actions
542 supported_actions = []
543 for a in all_actions_list:
544 if ((1 << a) & valid_actions) != 0:
545 supported_actions.append(a)
546
547 supported_actions = shuffle(supported_actions)
548 supported_actions \
549 = supported_actions[0 : random.randint(1, len(supported_actions))]
Howard Pershc7963582012-03-29 10:02:59 -0700550
551 self.actions = action_list.action_list()
Howard Persh680b92a2012-03-31 13:34:35 -0700552 for a in supported_actions:
Howard Pershc7963582012-03-29 10:02:59 -0700553 if a == ofp.OFPAT_OUTPUT:
554 # TBD - Output actions are clustered in list, spread them out?
555 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700556 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700557 for pi in port_idxs:
558 act = action.action_output()
Howard Persh680b92a2012-03-31 13:34:35 -0700559 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700560 self.actions.add(act)
561 elif a == ofp.OFPAT_SET_VLAN_VID:
562 act = action.action_set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700563 act.vlan_vid = fi.rand_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700564 self.actions.add(act)
565 elif a == ofp.OFPAT_SET_VLAN_PCP:
Dan Talayco910a8282012-04-07 00:05:20 -0700566 act = action.action_set_vlan_pcp()
567 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700568 elif a == ofp.OFPAT_STRIP_VLAN:
569 act = action.action_strip_vlan()
570 self.actions.add(act)
571 elif a == ofp.OFPAT_SET_DL_SRC:
572 act = action.action_set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700573 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700574 self.actions.add(act)
575 elif a == ofp.OFPAT_SET_DL_DST:
576 act = action.action_set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700577 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700578 self.actions.add(act)
579 elif a == ofp.OFPAT_SET_NW_SRC:
580 act = action.action_set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700581 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700582 self.actions.add(act)
583 elif a == ofp.OFPAT_SET_NW_DST:
584 act = action.action_set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700585 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700586 self.actions.add(act)
587 elif a == ofp.OFPAT_SET_NW_TOS:
588 act = action.action_set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700589 act.nw_tos = fi.rand_ip_tos()
Howard Pershc7963582012-03-29 10:02:59 -0700590 self.actions.add(act)
591 elif a == ofp.OFPAT_SET_TP_SRC:
592 act = action.action_set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700593 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700594 self.actions.add(act)
595 elif a == ofp.OFPAT_SET_TP_DST:
596 act = action.action_set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700597 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700598 self.actions.add(act)
599 elif a == ofp.OFPAT_ENQUEUE:
600 # TBD - Enqueue actions are clustered in list, spread them out?
601 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700602 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700603 for pi in port_idxs:
604 act = action.action_enqueue()
Howard Persh680b92a2012-03-31 13:34:35 -0700605 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700606 # TBD - Limits for queue number?
607 act.queue_id = random.randint(0, 7)
608 self.actions.add(act)
609
610 return self
611
rootf6af1672012-04-06 09:46:29 -0700612 # Randomize flow cfg
613 def rand(self, fi, valid_wildcards, valid_actions, valid_ports):
614 # Start with no wildcards, i.e. everything specified
615 self.match.wildcards = 0
616
617 # Make approx. 5% of flows exact
618 exact = (random.randint(1, 100) <= 5)
619
620 # For each qualifier Q,
621 # if (wildcarding is not supported for Q,
622 # or an exact flow is specified
623 # or a coin toss comes up heads),
624 # specify Q
625 # else
626 # wildcard Q
627
628 if wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
629 or exact \
630 or flip_coin():
631 self.match.in_port = rand_pick(valid_ports)
632 else:
Howard Persh3340d452012-04-06 16:45:21 -0700633 self.match.wildcards = wildcard_set(self.match.wildcards, \
634 ofp.OFPFW_IN_PORT, \
635 1 \
636 )
rootf6af1672012-04-06 09:46:29 -0700637
638 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
639 or exact \
640 or flip_coin():
641 self.match.dl_dst = fi.rand_dl_addr()
642 else:
Howard Persh3340d452012-04-06 16:45:21 -0700643 self.match.wildcards = wildcard_set(self.match.wildcards, \
644 ofp.OFPFW_DL_DST, \
645 1 \
646 )
rootf6af1672012-04-06 09:46:29 -0700647
648 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
649 or exact \
650 or flip_coin():
651 self.match.dl_src = fi.rand_dl_addr()
652 else:
Howard Persh3340d452012-04-06 16:45:21 -0700653 self.match.wildcards = wildcard_set(self.match.wildcards, \
654 ofp.OFPFW_DL_SRC, \
655 1 \
656 )
rootf6af1672012-04-06 09:46:29 -0700657
658 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
659 or exact \
660 or flip_coin():
661 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
662 else:
Howard Persh3340d452012-04-06 16:45:21 -0700663 self.match.wildcards = wildcard_set(self.match.wildcards, \
664 ofp.OFPFW_DL_VLAN_PCP, \
665 1 \
666 )
rootf6af1672012-04-06 09:46:29 -0700667
668 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
669 or exact \
670 or flip_coin():
671 self.match.dl_vlan = fi.rand_vlan()
672 else:
Howard Persh3340d452012-04-06 16:45:21 -0700673 self.match.wildcards = wildcard_set(self.match.wildcards, \
674 ofp.OFPFW_DL_VLAN, \
675 1 \
676 )
rootf6af1672012-04-06 09:46:29 -0700677
678 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
679 or exact \
680 or flip_coin():
681 self.match.dl_type = fi.rand_ethertype()
682 else:
Howard Persh3340d452012-04-06 16:45:21 -0700683 self.match.wildcards = wildcard_set(self.match.wildcards, \
684 ofp.OFPFW_DL_TYPE, \
685 1 \
686 )
rootf6af1672012-04-06 09:46:29 -0700687
688 if exact or flip_coin():
689 n = 0
690 else:
691 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
692 if n > 32:
693 n = 32
694 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700695 self.match.wildcards = wildcard_set(self.match.wildcards, \
696 ofp.OFPFW_NW_SRC_MASK, \
697 n \
698 )
rootf6af1672012-04-06 09:46:29 -0700699 if n < 32:
700 self.match.nw_src = fi.rand_ip_addr() & ~((1 << n) - 1)
701 # Specifying any IP address match other than all bits
702 # don't care requires that Ethertype is one of {IP, ARP}
703 if flip_coin():
704 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700705 self.match.wildcards = wildcard_set(self.match.wildcards, \
706 ofp.OFPFW_DL_TYPE, \
707 0 \
708 )
rootf6af1672012-04-06 09:46:29 -0700709
710 if exact or flip_coin():
711 n = 0
712 else:
713 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
714 if n > 32:
715 n = 32
716 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700717 self.match.wildcards = wildcard_set(self.match.wildcards, \
718 ofp.OFPFW_NW_DST_MASK, \
719 n \
720 )
rootf6af1672012-04-06 09:46:29 -0700721 if n < 32:
722 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
723 # Specifying any IP address match other than all bits
724 # don't care requires that Ethertype is one of {IP, ARP}
725 if flip_coin():
726 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700727 self.match.wildcards = wildcard_set(self.match.wildcards, \
728 ofp.OFPFW_DL_TYPE, \
729 0 \
730 )
rootf6af1672012-04-06 09:46:29 -0700731
732 if wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
733 or exact \
734 or flip_coin():
735 self.match.nw_tos = fi.rand_ip_tos()
736 # Specifying a TOS value requires that Ethertype is IP
737 if flip_coin():
738 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700739 self.match.wildcards = wildcard_set(self.match.wildcards, \
740 ofp.OFPFW_DL_TYPE, \
741 0 \
742 )
rootf6af1672012-04-06 09:46:29 -0700743 else:
Howard Persh3340d452012-04-06 16:45:21 -0700744 self.match.wildcards = wildcard_set(self.match.wildcards, \
745 ofp.OFPFW_NW_TOS, \
746 1 \
747 )
rootf6af1672012-04-06 09:46:29 -0700748
Dan Talayco910a8282012-04-07 00:05:20 -0700749 # Known issue on OVS with specifying nw_proto w/o dl_type as IP
750 if wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
751 or exact \
752 or flip_coin():
753 self.match.nw_proto = fi.rand_ip_proto()
754 # Specifying an IP protocol requires that Ethertype is IP
755 if flip_coin():
756 self.match.dl_type = 0x0800
757 self.match.wildcards = wildcard_set(self.match.wildcards, \
758 ofp.OFPFW_DL_TYPE, \
759 0 \
760 )
761 else:
Howard Persh3340d452012-04-06 16:45:21 -0700762 self.match.wildcards = wildcard_set(self.match.wildcards, \
763 ofp.OFPFW_NW_PROTO, \
764 1 \
765 )
Dan Talayco910a8282012-04-07 00:05:20 -0700766
rootf6af1672012-04-06 09:46:29 -0700767 if wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
768 or exact\
769 or flip_coin():
770 self.match.tp_src = fi.rand_l4_port()
771 # Specifying a L4 port requires that IP protcol is
772 # one of {ICMP, TCP, UDP}
773 if flip_coin():
774 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700775 self.match.wildcards = wildcard_set(self.match.wildcards, \
776 ofp.OFPFW_NW_PROTO, \
777 0 \
778 )
rootf6af1672012-04-06 09:46:29 -0700779 # Specifying a L4 port requirues that Ethertype is IP
780 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700781 self.match.wildcards = wildcard_set(self.match.wildcards, \
782 ofp.OFPFW_DL_TYPE, \
783 0 \
784 )
rootf6af1672012-04-06 09:46:29 -0700785 if self.match.nw_proto == 1:
786 self.match.tp_src = self.match.tp_src & 0xff
787 else:
Howard Persh3340d452012-04-06 16:45:21 -0700788 self.match.wildcards = wildcard_set(self.match.wildcards, \
789 ofp.OFPFW_TP_SRC, \
790 1 \
791 )
rootf6af1672012-04-06 09:46:29 -0700792
793 if wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
794 or exact \
795 or flip_coin():
796 self.match.tp_dst = fi.rand_l4_port()
797 # Specifying a L4 port requires that IP protcol is
798 # one of {ICMP, TCP, UDP}
799 if flip_coin():
800 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700801 self.match.wildcards = wildcard_set(self.match.wildcards, \
802 ofp.OFPFW_NW_PROTO, \
803 0 \
804 )
rootf6af1672012-04-06 09:46:29 -0700805 # Specifying a L4 port requirues that Ethertype is IP
806 self.match.dl_type = 0x0800
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 if self.match.nw_proto == 1:
812 self.match.tp_dst = self.match.tp_dst & 0xff
813 else:
Howard Persh3340d452012-04-06 16:45:21 -0700814 self.match.wildcards = wildcard_set(self.match.wildcards, \
815 ofp.OFPFW_TP_DST, \
816 1 \
817 )
rootf6af1672012-04-06 09:46:29 -0700818
819 # If nothing is wildcarded, it is an exact flow spec -- some switches
Howard Persh3340d452012-04-06 16:45:21 -0700820 # (Open vSwitch, for one) *require* that exact flow specs
821 # have priority 65535.
822 self.priority = 65535 if self.match.wildcards == 0 \
823 else fi.rand_priority()
rootf6af1672012-04-06 09:46:29 -0700824
825 # N.B. Don't make the timeout too short, else the flow might
826 # disappear before we get a chance to check for it.
827 t = random.randint(0, 65535)
828 self.idle_timeout = 0 if t < 60 else t
829 t = random.randint(0, 65535)
830 self.hard_timeout = 0 if t < 60 else t
831
832 self.rand_mod(fi, valid_actions, valid_ports)
833
834 return self
835
836 # Return flow cfg in canonical form
Howard Persh3340d452012-04-06 16:45:21 -0700837 # - There are dependencies between flow qualifiers, e.g. it only makes
838 # sense to qualify nw_proto if dl_type is qualified to be 0x0800 (IP).
839 # The canonical form of flow match criteria will "wildcard out"
840 # all such cases.
rootf6af1672012-04-06 09:46:29 -0700841 def canonical(self):
842 result = copy.deepcopy(self)
843 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
844 or result.match.dl_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700845 # dl_tyoe is wildcarded, or specified as something other
846 # than IP or ARP
rootf6af1672012-04-06 09:46:29 -0700847 # => nw_src and nw_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700848 result.match.wildcards = wildcard_set(result.match.wildcards, \
849 ofp.OFPFW_NW_SRC_MASK, \
850 32 \
851 )
852 result.match.wildcards = wildcard_set(result.match.wildcards, \
853 ofp.OFPFW_NW_DST_MASK, \
854 32 \
855 )
rootf6af1672012-04-06 09:46:29 -0700856 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
857 or result.match.dl_type != 0x0800:
858 # dl_type is wildcarded, or specified as something other than IP
Howard Persh3340d452012-04-06 16:45:21 -0700859 # => nw_proto, nw_tos, tp_src and tp_dst cannot be specified,
860 # must be wildcarded
861 result.match.wildcards = wildcard_set(result.match.wildcards, \
862 ofp.OFPFW_NW_PROTO, \
863 1 \
864 )
865 result.match.wildcards = wildcard_set(result.match.wildcards, \
866 ofp.OFPFW_NW_TOS, \
867 1 \
868 )
869 result.match.wildcards = wildcard_set(result.match.wildcards, \
870 ofp.OFPFW_TP_SRC, \
871 1 \
872 )
873 result.match.wildcards = wildcard_set(result.match.wildcards, \
874 ofp.OFPFW_TP_DST, \
875 1 \
876 )
rootf6af1672012-04-06 09:46:29 -0700877 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
878 or result.match.nw_proto not in [1, 6, 17]:
Howard Persh3340d452012-04-06 16:45:21 -0700879 # nw_proto is wildcarded, or specified as something other than ICMP,
880 # TCP or UDP
rootf6af1672012-04-06 09:46:29 -0700881 # => tp_src and tp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700882 result.match.wildcards = wildcard_set(result.match.wildcards, \
883 ofp.OFPFW_TP_SRC, \
884 1 \
885 )
886 result.match.wildcards = wildcard_set(result.match.wildcards, \
887 ofp.OFPFW_TP_DST, \
888 1 \
889 )
rootf6af1672012-04-06 09:46:29 -0700890 return result
891
Howard Persh680b92a2012-03-31 13:34:35 -0700892 # Overlap check
893 # delf == True <=> Check for delete overlap, else add overlap
894 # "Add overlap" is defined as there exists a packet that could match both the
895 # receiver and argument flowspecs
896 # "Delete overlap" is defined as the specificity of the argument flowspec
897 # is greater than or equal to the specificity of the receiver flowspec
898 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -0700899 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
900 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700901 if self.match.in_port != x.match.in_port:
902 return False # Both specified, and not equal
903 elif delf:
904 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700905 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
906 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700907 if self.match.dl_vlan != x.match.dl_vlan:
908 return False # Both specified, and not equal
909 elif delf:
910 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700911 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
912 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700913 if self.match.dl_src != x.match.dl_src:
914 return False # Both specified, and not equal
915 elif delf:
916 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700917 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
918 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700919 if self.match.dl_dst != x.match.dl_dst:
920 return False # Both specified, and not equal
921 elif delf:
922 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700923 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
924 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700925 if self.match.dl_type != x.match.dl_type:
926 return False # Both specified, and not equal
927 elif delf:
928 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -0700929 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
930 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700931 if self.match.nw_proto != x.match.nw_proto:
932 return False # Both specified, and not equal
933 elif delf:
934 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700935 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
936 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700937 if self.match.tp_src != x.match.tp_src:
938 return False # Both specified, and not equal
939 elif delf:
940 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700941 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
942 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700943 if self.match.tp_dst != x.match.tp_dst:
944 return False # Both specified, and not equal
945 elif delf:
946 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700947 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
948 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700949 if delf and na < nb:
950 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -0700951 if (na < 32 and nb < 32):
952 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
953 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -0700954 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -0700955 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
956 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700957 if delf and na < nb:
958 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -0700959 if (na < 32 and nb < 32):
960 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
961 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
rootf6af1672012-04-06 09:46:29 -0700962 return False # Overlapping bits not equal
963 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
964 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700965 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
966 return False # Both specified, and not equal
967 elif delf:
968 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700969 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
970 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700971 if self.match.nw_tos != x.match.nw_tos:
972 return False # Both specified, and not equal
973 elif delf:
974 return False # Receiver more specific
975 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -0700976
977 def to_flow_mod_msg(self, msg):
978 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -0700979 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -0700980 msg.idle_timeout = self.idle_timeout
981 msg.hard_timeout = self.hard_timeout
982 msg.priority = self.priority
983 msg.actions = self.actions
984 return msg
985
986 def from_flow_stat(self, msg):
987 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -0700988 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -0700989 self.idle_timeout = msg.idle_timeout
990 self.hard_timeout = msg.hard_timeout
991 self.priority = msg.priority
992 self.actions = msg.actions
993
rootf6af1672012-04-06 09:46:29 -0700994 def from_flow_rem(self, msg):
995 self.match = msg.match
996 self.idle_timeout = msg.idle_timeout
997 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -0700998
Howard Pershc7963582012-03-29 10:02:59 -0700999
rootf6af1672012-04-06 09:46:29 -07001000class Flow_Tbl:
1001 def clear(self):
1002 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001003
rootf6af1672012-04-06 09:46:29 -07001004 def __init__(self):
1005 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001006
rootf6af1672012-04-06 09:46:29 -07001007 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001008 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001009
1010 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001011 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001012
1013 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001014 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001015
1016 def values(self):
1017 return self.dict.values()
1018
1019 def count(self):
1020 return len(self.dict)
1021
1022 def rand(self, sw, fi, num_flows):
1023 self.clear()
1024 i = 0
1025 tbl = 0
1026 j = 0
1027 while i < num_flows:
1028 fc = Flow_Cfg()
1029 fc.rand(fi, \
1030 sw.tbl_stats.stats[tbl].wildcards, \
1031 sw.sw_features.actions, \
1032 sw.valid_ports \
1033 )
1034 fc = fc.canonical()
1035 if self.find(fc):
1036 continue
1037 fc.send_rem = False
1038 self.insert(fc)
1039 i = i + 1
1040 j = j + 1
1041 if j >= sw.tbl_stats.stats[tbl].max_entries:
1042 tbl = tbl + 1
1043 j = 0
1044
1045
Howard Persh3340d452012-04-06 16:45:21 -07001046error_msgs = []
1047removed_msgs = []
1048
1049def error_handler(self, msg, rawmsg):
Dan Talayco910a8282012-04-07 00:05:20 -07001050 fq_logger.debug("Got an ERROR message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001051 % (msg.type, msg.code) \
1052 )
1053 global error_msgs
1054 error_msgs.append(msg)
1055 pass
1056
1057def removed_handler(self, msg, rawmsg):
Dan Talayco910a8282012-04-07 00:05:20 -07001058 fq_logger.debug("Got a REMOVED message")
Howard Persh3340d452012-04-06 16:45:21 -07001059 global removed_msgs
1060 removed_msgs.append(msg)
1061 pass
1062
rootf6af1672012-04-06 09:46:29 -07001063class Switch:
1064 # Members:
1065 # controller - switch's test controller
1066 # sw_features - switch's OFPT_FEATURES_REPLY message
1067 # valid_ports - list of valid port numbers
1068 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1069 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1070 # flow_tbl - (test's idea of) switch's flow table
1071
1072 def __init__(self):
1073 self.controller = None
1074 self.sw_features = None
1075 self.valid_ports = []
1076 self.tbl_stats = None
1077 self.flow_stats = None
1078 self.flow_tbl = Flow_Tbl()
1079
Howard Persh3340d452012-04-06 16:45:21 -07001080 def controller_set(self, controller):
1081 self.controller = controller
1082 # Register error message handler
1083 global error_msgs
1084 error_msgs = []
1085 controller.register(ofp.OFPT_ERROR, error_handler)
1086 controller.register(ofp.OFPT_FLOW_REMOVED, removed_handler)
1087
rootf6af1672012-04-06 09:46:29 -07001088 def features_get(self):
1089 # Get switch features
1090 request = message.features_request()
1091 (self.sw_features, pkt) = self.controller.transact(request, timeout=2)
1092 if self.sw_features is None:
1093 return False
1094 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Howard Persh3340d452012-04-06 16:45:21 -07001095 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1096 # is that universal?
1097
1098 # TBD - There seems to be variability in which switches support which
1099 # ports; need to sort that out
1100 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1101# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1102# ofp.OFPP_NORMAL, \
1103# ofp.OFPP_FLOOD, \
1104# ofp.OFPP_ALL, \
1105# ofp.OFPP_CONTROLLER \
1106# ] \
1107# )
rootf6af1672012-04-06 09:46:29 -07001108 return True
1109
1110 def tbl_stats_get(self):
1111 # Get table stats
Howard Persh680b92a2012-03-31 13:34:35 -07001112 request = message.table_stats_request()
rootf6af1672012-04-06 09:46:29 -07001113 (self.tbl_stats, pkt) = self.controller.transact(request, timeout=2)
1114 return (self.tbl_stats is not None)
Howard Persh680b92a2012-03-31 13:34:35 -07001115
rootf6af1672012-04-06 09:46:29 -07001116 def flow_stats_get(self):
1117 request = message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -07001118 query_match = ofp.ofp_match()
1119 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001120 request.match = query_match
1121 request.table_id = 0xff
1122 request.out_port = ofp.OFPP_NONE;
Howard Persh3340d452012-04-06 16:45:21 -07001123 if self.controller.message_send(request) == -1:
1124 return False
1125 # <TBD>
1126 # Glue together successive reponse messages for stats reply.
1127 # Looking at the "more" flag and performing re-assembly
1128 # should be a part of the infrastructure.
1129 # </TBD>
1130 n = 0
1131 while True:
1132 # TBD - Check for "more" flag
1133 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY, 1)
1134 if resp is None:
1135 break
1136 if n == 0:
1137 self.flow_stats = resp
1138 else:
1139 self.flow_stats.stats.extend(resp.stats)
1140 n = n + 1
1141 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001142
rootf6af1672012-04-06 09:46:29 -07001143 def flow_add(self, flow_cfg, overlapf = False):
Howard Persh680b92a2012-03-31 13:34:35 -07001144 flow_mod_msg = message.flow_mod()
1145 flow_mod_msg.command = ofp.OFPFC_ADD
1146 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001147 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001148 if overlapf:
1149 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001150 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001151 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
rootf6af1672012-04-06 09:46:29 -07001152 return (self.controller.message_send(flow_mod_msg) != -1)
Howard Persh680b92a2012-03-31 13:34:35 -07001153
rootf6af1672012-04-06 09:46:29 -07001154 def flow_mod(self, flow_cfg, strictf):
Howard Persh680b92a2012-03-31 13:34:35 -07001155 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001156 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf \
1157 else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -07001158 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001159 flow_cfg.to_flow_mod_msg(flow_mod_msg)
1160 return (self.controller.message_send(flow_mod_msg) != -1)
1161
1162 def flow_del(self, flow_cfg, strictf):
1163 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001164 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf \
1165 else ofp.OFPFC_DELETE
rootf6af1672012-04-06 09:46:29 -07001166 flow_mod_msg.buffer_id = 0xffffffff
1167 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001168 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001169 flow_cfg.to_flow_mod_msg(flow_mod_msg)
1170 return (self.controller.message_send(flow_mod_msg) != -1)
1171
1172 def barrier(self):
1173 barrier = message.barrier_request()
1174 (resp, pkt) = self.controller.transact(barrier, 5)
1175 return (resp is not None)
1176
Howard Persh3340d452012-04-06 16:45:21 -07001177 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001178 result = True
Howard Persh3340d452012-04-06 16:45:21 -07001179 global error_msgs
Dan Talayco910a8282012-04-07 00:05:20 -07001180 fq_logger.debug("Expecting %d error messages" % (num_exp))
Howard Persh3340d452012-04-06 16:45:21 -07001181 num_got = len(error_msgs)
Dan Talayco910a8282012-04-07 00:05:20 -07001182 fq_logger.debug("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001183 if num_got != num_exp:
Dan Talayco910a8282012-04-07 00:05:20 -07001184 fq_logger.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001185 result = False
1186 if num_exp == 0:
1187 return result
1188 elif num_exp == 1:
Dan Talayco910a8282012-04-07 00:05:20 -07001189 fq_logger.debug("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001190 % (type, code) \
1191 )
1192 f = False
1193 for e in error_msgs:
1194 if e.type == type and e.code == code:
Dan Talayco910a8282012-04-07 00:05:20 -07001195 fq_logger.debug("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001196 f = True
1197 if not f:
Dan Talayco910a8282012-04-07 00:05:20 -07001198 fq_logger.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001199 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001200 else:
Dan Talayco910a8282012-04-07 00:05:20 -07001201 fq_logger.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001202 result = False
1203 return result
1204
Howard Persh3340d452012-04-06 16:45:21 -07001205 def removed_verify(self, num_exp):
1206 result = True
1207 global removed_msgs
Dan Talayco910a8282012-04-07 00:05:20 -07001208 fq_logger.debug("Expecting %d removed messages" % (num_exp))
Howard Persh3340d452012-04-06 16:45:21 -07001209 num_got = len(removed_msgs)
Dan Talayco910a8282012-04-07 00:05:20 -07001210 fq_logger.debug("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001211 if num_got != num_exp:
Dan Talayco910a8282012-04-07 00:05:20 -07001212 fq_logger.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001213 result = False
1214 if num_exp < 2:
1215 return result
Dan Talayco910a8282012-04-07 00:05:20 -07001216 fq_logger.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001217 return False
1218
1219
Dan Talayco910a8282012-04-07 00:05:20 -07001220# fq_logger.debug("Expecting %d error messages" % (num))
Howard Persh3340d452012-04-06 16:45:21 -07001221# if num > 0:
Dan Talayco910a8282012-04-07 00:05:20 -07001222# fq_logger.debug("with type=%d code=%d" % (type, code))
Howard Persh3340d452012-04-06 16:45:21 -07001223# result = True
1224# n = 0
1225# while True:
1226# (errmsg, pkt) = self.controller.poll(ofp.OFPT_ERROR, 1)
1227# if errmsg is None:
1228# break
Dan Talayco910a8282012-04-07 00:05:20 -07001229# fq_logger.debug("Got error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001230# % (errmsg.type, errmsg.code) \
1231# )
1232# if num == 0 or errmsg.type != type or errmsg.code != code:
Dan Talayco910a8282012-04-07 00:05:20 -07001233# fq_logger.debug("Unexpected error message")
Howard Persh3340d452012-04-06 16:45:21 -07001234# result = False
1235# n = n + 1
1236# if n != num:
Dan Talayco910a8282012-04-07 00:05:20 -07001237# fq_logger.error("Received %d error messages" % (n))
Howard Persh3340d452012-04-06 16:45:21 -07001238# result = False
1239# return result
1240
rootf6af1672012-04-06 09:46:29 -07001241 def flow_tbl_verify(self):
1242 result = True
1243
1244 # Verify flow count in switch
Dan Talayco910a8282012-04-07 00:05:20 -07001245 fq_logger.debug("Reading table stats")
1246 fq_logger.debug("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001247 if not self.tbl_stats_get():
Dan Talayco910a8282012-04-07 00:05:20 -07001248 fq_logger.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001249 return False
1250 n = 0
1251 for ts in self.tbl_stats.stats:
1252 n = n + ts.active_count
Dan Talayco910a8282012-04-07 00:05:20 -07001253 fq_logger.debug("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001254 % (n) \
1255 )
1256 if n != self.flow_tbl.count():
Dan Talayco910a8282012-04-07 00:05:20 -07001257 fq_logger.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001258 result = False
1259
1260 # Read flows from switch
Dan Talayco910a8282012-04-07 00:05:20 -07001261 fq_logger.debug("Retrieving flows from switch")
1262 fq_logger.debug("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001263 if not self.flow_stats_get():
Dan Talayco910a8282012-04-07 00:05:20 -07001264 fq_logger.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001265 return False
Dan Talayco910a8282012-04-07 00:05:20 -07001266 fq_logger.debug("Retrieved %d flows" % (len(self.flow_stats.stats)))
rootf6af1672012-04-06 09:46:29 -07001267
1268 # Verify flows returned by switch
1269
1270 if len(self.flow_stats.stats) != self.flow_tbl.count():
Dan Talayco910a8282012-04-07 00:05:20 -07001271 fq_logger.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001272 result = False
1273
Dan Talayco910a8282012-04-07 00:05:20 -07001274 fq_logger.debug("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001275 for fc in self.flow_tbl.values():
1276 fc.matched = False
1277 for fs in self.flow_stats.stats:
1278 flow_in = Flow_Cfg()
1279 flow_in.from_flow_stat(fs)
Dan Talayco910a8282012-04-07 00:05:20 -07001280 fq_logger.debug("Received flow:")
1281 fq_logger.debug(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001282 fc = self.flow_tbl.find(flow_in)
1283 if fc is None:
Dan Talayco910a8282012-04-07 00:05:20 -07001284 fq_logger.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001285 result = False
1286 elif fc.matched:
Dan Talayco910a8282012-04-07 00:05:20 -07001287 fq_logger.error("re-matches defined flow:")
1288 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07001289 result = False
1290 else:
Dan Talayco910a8282012-04-07 00:05:20 -07001291 fq_logger.debug("matched")
rootf6af1672012-04-06 09:46:29 -07001292 if not flow_in == fc:
Dan Talayco910a8282012-04-07 00:05:20 -07001293 fq_logger.error("Non-key portions of flow do not match")
rootf6af1672012-04-06 09:46:29 -07001294 result = False
1295 fc.matched = True
1296 for fc in self.flow_tbl.values():
1297 if not fc.matched:
Dan Talayco910a8282012-04-07 00:05:20 -07001298 fq_logger.error("Defined flow:")
1299 fq_logger.error(str(fc))
1300 fq_logger.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001301 result = False
1302
1303 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001304
1305
rootf6af1672012-04-06 09:46:29 -07001306class Flow_Add_5(basic.SimpleProtocol):
1307 """
1308 Test FLOW_ADD_5 from draft top-half test plan
1309
1310 INPUTS
1311 num_flows - Number of flows to generate
1312 """
Howard Persh680b92a2012-03-31 13:34:35 -07001313
rootf6af1672012-04-06 09:46:29 -07001314 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001315 fq_logger.debug("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001316
Dan Talayco910a8282012-04-07 00:05:20 -07001317 num_flows = test_param_get(fq_config, "num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001318
Howard Pershc7963582012-03-29 10:02:59 -07001319 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001320
Dan Talayco910a8282012-04-07 00:05:20 -07001321 fq_logger.debug("Deleting all flows from switch")
1322 rc = delete_all_flows(self.controller, fq_logger)
Howard Pershc7963582012-03-29 10:02:59 -07001323 self.assertEqual(rc, 0, "Failed to delete all flows")
1324
rootf6af1672012-04-06 09:46:29 -07001325 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001326
Dan Talayco910a8282012-04-07 00:05:20 -07001327 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001328 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001329 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001330 self.assertTrue(sw.features_get(), "Get switch features failed")
1331 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
Howard Pershc7963582012-03-29 10:02:59 -07001332
rootf6af1672012-04-06 09:46:29 -07001333 if num_flows == 0:
1334 # Number of flows requested was 0
1335 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001336
rootf6af1672012-04-06 09:46:29 -07001337 for ts in sw.tbl_stats.stats:
1338 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001339
Dan Talayco910a8282012-04-07 00:05:20 -07001340 fq_logger.debug("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001341
1342 # Dream up some flow information, i.e. space to chose from for
1343 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001344
rootf6af1672012-04-06 09:46:29 -07001345 fi = Flow_Info()
1346 fi.rand(2 * int(math.log(num_flows)))
Howard Pershc7963582012-03-29 10:02:59 -07001347
rootf6af1672012-04-06 09:46:29 -07001348 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001349
rootf6af1672012-04-06 09:46:29 -07001350 ft = Flow_Tbl()
1351 ft.rand(sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001352
rootf6af1672012-04-06 09:46:29 -07001353 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001354
Dan Talayco910a8282012-04-07 00:05:20 -07001355 fq_logger.debug("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001356 for fc in ft.values(): # Randomizes order of sending
Dan Talayco910a8282012-04-07 00:05:20 -07001357 fq_logger.debug("Adding flow:")
1358 fq_logger.debug(str(fc));
rootf6af1672012-04-06 09:46:29 -07001359 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001360
rootf6af1672012-04-06 09:46:29 -07001361 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001362
rootf6af1672012-04-06 09:46:29 -07001363 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001364
rootf6af1672012-04-06 09:46:29 -07001365 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001366
rootf6af1672012-04-06 09:46:29 -07001367 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001368
rootf6af1672012-04-06 09:46:29 -07001369 if not sw.errors_verify(0):
1370 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001371
rootf6af1672012-04-06 09:46:29 -07001372 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001373
rootf6af1672012-04-06 09:46:29 -07001374 sw.flow_tbl = ft
1375 if not sw.flow_tbl_verify():
1376 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001377
rootf6af1672012-04-06 09:46:29 -07001378 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07001379 fq_logger.debug("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001380
Howard Pershc7963582012-03-29 10:02:59 -07001381
rootf6af1672012-04-06 09:46:29 -07001382class Flow_Add_5_1(basic.SimpleProtocol):
1383 """
1384 Test FLOW_ADD_5.1 from draft top-half test plan
1385
1386 INPUTS
1387 None
1388 """
1389
1390 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001391 fq_logger.debug("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001392
Dan Talayco910a8282012-04-07 00:05:20 -07001393 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001394
1395 # Clear all flows from switch
1396
Dan Talayco910a8282012-04-07 00:05:20 -07001397 fq_logger.debug("Deleting all flows from switch")
1398 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001399 self.assertEqual(rc, 0, "Failed to delete all flows")
1400
1401 # Get switch capabilites
1402
Dan Talayco910a8282012-04-07 00:05:20 -07001403 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001404 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001405 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001406 self.assertTrue(sw.features_get(), "Get switch features failed")
1407 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1408
1409 # Dream up some flow information, i.e. space to chose from for
1410 # random flow parameter generation
1411
1412 fi = Flow_Info()
1413 fi.rand(10)
1414
1415 # Dream up a flow config that will be canonicalized by the switch
1416
1417 while True:
1418 fc = Flow_Cfg()
1419 fc.rand(fi, \
1420 sw.tbl_stats.stats[0].wildcards, \
1421 sw.sw_features.actions, \
1422 sw.valid_ports \
1423 )
1424 fcc = fc.canonical()
1425 if fcc != fc:
1426 break
1427
1428 ft = Flow_Tbl()
1429 ft.insert(fcc)
1430
1431 # Send it to the switch
1432
Dan Talayco910a8282012-04-07 00:05:20 -07001433 fq_logger.debug("Sending flow add to switch:")
1434 fq_logger.debug(str(fc))
1435 fq_logger.debug("should be canonicalized as:")
1436 fq_logger.debug(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001437 fc.send_rem = False
1438 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1439
1440 # Do barrier, to make sure all flows are in
1441
1442 self.assertTrue(sw.barrier(), "Barrier failed")
1443
1444 result = True
1445
1446 # Check for any error messages
1447
1448 if not sw.errors_verify(0):
1449 result = False
1450
1451 # Verify flow table
1452
1453 sw.flow_tbl = ft
1454 if not sw.flow_tbl_verify():
1455 result = False
1456
1457 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07001458 fq_logger.debug("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001459
1460
Howard Persh3340d452012-04-06 16:45:21 -07001461# Disabled because of bogus capacity reported by OVS.
1462# Should be DUT dependent.
1463test_prio["Flow_Add_6"] = -1
1464
rootf6af1672012-04-06 09:46:29 -07001465class Flow_Add_6(basic.SimpleProtocol):
1466 """
1467 Test FLOW_ADD_6 from draft top-half test plan
1468
1469 INPUTS
1470 num_flows - Number of flows to generate
1471 """
Howard Pershc7963582012-03-29 10:02:59 -07001472
1473 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001474 fq_logger.debug("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001475
rootf6af1672012-04-06 09:46:29 -07001476 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001477
Dan Talayco910a8282012-04-07 00:05:20 -07001478 fq_logger.debug("Deleting all flows from switch")
1479 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001480 self.assertEqual(rc, 0, "Failed to delete all flows")
1481
1482 # Get switch capabilites
1483
Dan Talayco910a8282012-04-07 00:05:20 -07001484 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001485 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001486 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001487 self.assertTrue(sw.features_get(), "Get switch features failed")
1488 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1489
root2843d2b2012-04-06 10:27:46 -07001490 num_flows = 0
rootf6af1672012-04-06 09:46:29 -07001491 for ts in sw.tbl_stats.stats:
1492 num_flows = num_flows + ts.max_entries
1493
Dan Talayco910a8282012-04-07 00:05:20 -07001494 fq_logger.debug("Switch capacity is %d flows" % (num_flows))
1495 fq_logger.debug("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001496
1497 # Dream up some flow information, i.e. space to chose from for
1498 # random flow parameter generation
1499
1500 fi = Flow_Info()
1501 fi.rand(2 * int(math.log(num_flows)))
1502
1503 # Create a flow table, to switch's capacity
1504
1505 ft = Flow_Tbl()
1506 ft.rand(sw, fi, num_flows)
1507
1508 # Send flow table to switch
1509
Dan Talayco910a8282012-04-07 00:05:20 -07001510 fq_logger.debug("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001511 for fc in ft.values(): # Randomizes order of sending
Dan Talayco910a8282012-04-07 00:05:20 -07001512 fq_logger.debug("Adding flow:")
1513 fq_logger.debug(str(fc));
rootf6af1672012-04-06 09:46:29 -07001514 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1515
1516 # Do barrier, to make sure all flows are in
1517
1518 self.assertTrue(sw.barrier(), "Barrier failed")
1519
1520 result = True
1521
1522 # Check for any error messages
1523
1524 if not sw.errors_verify(0):
1525 result = False
1526
1527 # Dream up one more flow
1528
Dan Talayco910a8282012-04-07 00:05:20 -07001529 fq_logger.debug("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001530 while True:
1531 fc = Flow_Cfg()
1532 fc.rand(fi, \
1533 sw.tbl_stats.stats[tbl].wildcards, \
1534 sw.sw_features.actions, \
1535 sw.valid_ports \
1536 )
1537 fc = fc.canonical()
1538 if ft.find(fc):
1539 continue
1540
1541 # Send one-more flow
1542
1543 fc.send_rem = False
Dan Talayco910a8282012-04-07 00:05:20 -07001544 fq_logger.debug("Sending flow add switch")
1545 fq_logger.debug(str(fc));
rootf6af1672012-04-06 09:46:29 -07001546 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1547
1548 # Do barrier, to make sure all flows are in
1549
1550 self.assertTrue(sw.barrier(), "Barrier failed")
1551
1552 # Check for expected error message
1553
1554 if not sw.errors_verify(1, \
1555 ofp.OFPET_FLOW_MOD_FAILED, \
1556 ofp.OFPFMFC_ALL_TABLES_FULL \
1557 ):
1558 result = False
1559
1560 # Verify flow table
1561
1562 sw.flow_tbl = ft
1563 if not sw.flow_tbl_verify():
1564 result = False
1565
1566 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07001567 fq_logger.debug("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001568
1569
1570class Flow_Add_7(basic.SimpleProtocol):
1571 """
1572 Test FLOW_ADD_7 from draft top-half test plan
1573
1574 INPUTS
1575 None
1576 """
1577
1578 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001579 fq_logger.debug("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001580
1581 # Clear all flows from switch
1582
Dan Talayco910a8282012-04-07 00:05:20 -07001583 fq_logger.debug("Deleting all flows from switch")
1584 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001585 self.assertEqual(rc, 0, "Failed to delete all flows")
1586
1587 # Get switch capabilites
1588
Dan Talayco910a8282012-04-07 00:05:20 -07001589 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001590 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001591 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001592 self.assertTrue(sw.features_get(), "Get switch features failed")
1593 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1594
1595 # Dream up some flow information, i.e. space to chose from for
1596 # random flow parameter generation
1597
1598 fi = Flow_Info()
1599 fi.rand(10)
1600
1601 # Dream up a flow config
1602
1603 fc = Flow_Cfg()
1604 fc.rand(fi, \
1605 sw.tbl_stats.stats[0].wildcards, \
1606 sw.sw_features.actions, \
1607 sw.valid_ports \
1608 )
1609 fc = fc.canonical()
1610
1611 # Send it to the switch
1612
Dan Talayco910a8282012-04-07 00:05:20 -07001613 fq_logger.debug("Sending flow add to switch:")
1614 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07001615 ft = Flow_Tbl()
1616 fc.send_rem = False
1617 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1618 ft.insert(fc)
1619
1620 # Dream up some different actions, with the same flow key
1621
1622 fc2 = copy.deepcopy(fc)
1623 while True:
1624 fc2.rand_mod(fi, \
1625 sw.sw_features.actions, \
1626 sw.valid_ports \
1627 )
1628 if fc2 != fc:
1629 break
1630
1631 # Send that to the switch
1632
Dan Talayco910a8282012-04-07 00:05:20 -07001633 fq_logger.debug("Sending flow add to switch:")
1634 fq_logger.debug(str(fc2))
rootf6af1672012-04-06 09:46:29 -07001635 fc2.send_rem = False
1636 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
1637 ft.insert(fc2)
1638
1639 # Do barrier, to make sure all flows are in
1640
1641 self.assertTrue(sw.barrier(), "Barrier failed")
1642
1643 result = True
1644
1645 # Check for any error messages
1646
1647 if not sw.errors_verify(0):
1648 result = False
1649
1650 # Verify flow table
1651
1652 sw.flow_tbl = ft
1653 if not sw.flow_tbl_verify():
1654 result = False
1655
1656 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07001657 fq_logger.debug("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001658
1659
1660class Flow_Add_8(basic.SimpleProtocol):
1661 """
1662 Test FLOW_ADD_8 from draft top-half test plan
1663
1664 INPUTS
1665 None
1666 """
1667
1668 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001669 fq_logger.debug("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001670
1671 # Clear all flows from switch
1672
Dan Talayco910a8282012-04-07 00:05:20 -07001673 fq_logger.debug("Deleting all flows from switch")
1674 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001675 self.assertEqual(rc, 0, "Failed to delete all flows")
1676
1677 # Get switch capabilites
1678
Dan Talayco910a8282012-04-07 00:05:20 -07001679 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001680 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001681 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001682 self.assertTrue(sw.features_get(), "Get switch features failed")
1683 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1684
1685 # Dream up some flow information, i.e. space to chose from for
1686 # random flow parameter generation
1687
1688 fi = Flow_Info()
1689 fi.rand(10)
1690
1691 # Dream up a flow config, with at least 1 qualifier specified
1692
1693 fc = Flow_Cfg()
1694 while True:
1695 fc.rand(fi, \
1696 sw.tbl_stats.stats[0].wildcards, \
1697 sw.sw_features.actions, \
1698 sw.valid_ports \
1699 )
1700 fc = fc.canonical()
1701 if fc.match.wildcards != ofp.OFPFW_ALL:
1702 break
1703
1704 # Send it to the switch
1705
Dan Talayco910a8282012-04-07 00:05:20 -07001706 fq_logger.debug("Sending flow add to switch:")
1707 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07001708 ft = Flow_Tbl()
1709 fc.send_rem = False
1710 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1711 ft.insert(fc)
1712
1713 # Wildcard out one qualifier that was specified, to create an
1714 # overlapping flow
1715
1716 fc2 = copy.deepcopy(fc)
1717 for wi in shuffle(range(len(all_wildcards_list))):
1718 w = all_wildcards_list[wi]
1719 if (fc2.match.wildcards & w) == 0:
1720 break
1721 if w == ofp.OFPFW_NW_SRC_MASK:
1722 w = ofp.OFPFW_NW_SRC_ALL
1723 wn = "OFPFW_NW_SRC"
1724 elif w == ofp.OFPFW_NW_DST_MASK:
1725 w = ofp.OFPFW_NW_DST_ALL
1726 wn = "OFPFW_NW_DST"
1727 else:
1728 wn = all_wildcard_names[w]
Dan Talayco910a8282012-04-07 00:05:20 -07001729 fq_logger.debug("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07001730 fc2.match.wildcards = fc2.match.wildcards | w
1731
1732 # Send that to the switch, with overlap checking
1733
Dan Talayco910a8282012-04-07 00:05:20 -07001734 fq_logger.debug("Sending flow add to switch:")
1735 fq_logger.debug(str(fc2))
rootf6af1672012-04-06 09:46:29 -07001736 fc2.send_rem = False
1737 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
1738
1739 # Do barrier, to make sure all flows are in
1740 self.assertTrue(sw.barrier(), "Barrier failed")
1741
1742 result = True
1743
1744 # Check for expected error message
1745
1746 if not sw.errors_verify(1, \
1747 ofp.OFPET_FLOW_MOD_FAILED, \
1748 ofp.OFPFMFC_OVERLAP \
1749 ):
1750 result = False
1751
1752 # Verify flow table
1753
1754 sw.flow_tbl = ft
1755 if not sw.flow_tbl_verify():
1756 result = False
1757
1758 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07001759 fq_logger.debug("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001760
1761
1762class Flow_Mod_1(basic.SimpleProtocol):
1763 """
1764 Test FLOW_MOD_1 from draft top-half test plan
1765
1766 INPUTS
1767 None
1768 """
1769
1770 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001771 fq_logger.debug("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001772
1773 # Clear all flows from switch
1774
Dan Talayco910a8282012-04-07 00:05:20 -07001775 fq_logger.debug("Deleting all flows from switch")
1776 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001777 self.assertEqual(rc, 0, "Failed to delete all flows")
1778
1779 # Get switch capabilites
1780
Dan Talayco910a8282012-04-07 00:05:20 -07001781 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001782 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001783 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001784 self.assertTrue(sw.features_get(), "Get switch features failed")
1785 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1786
1787 # Dream up some flow information, i.e. space to chose from for
1788 # random flow parameter generation
1789
1790 fi = Flow_Info()
1791 fi.rand(10)
1792
1793 # Dream up a flow config
1794
1795 fc = Flow_Cfg()
1796 fc.rand(fi, \
1797 sw.tbl_stats.stats[0].wildcards, \
1798 sw.sw_features.actions, \
1799 sw.valid_ports \
1800 )
1801 fc = fc.canonical()
1802
1803 # Send it to the switch
1804
Dan Talayco910a8282012-04-07 00:05:20 -07001805 fq_logger.debug("Sending flow add to switch:")
1806 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07001807 ft = Flow_Tbl()
1808 fc.send_rem = False
1809 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1810 ft.insert(fc)
1811
1812 # Dream up some different actions, with the same flow key
1813
1814 fc2 = copy.deepcopy(fc)
1815 while True:
1816 fc2.rand_mod(fi, \
1817 sw.sw_features.actions, \
1818 sw.valid_ports \
1819 )
1820 if fc2 != fc:
1821 break
1822
1823 # Send that to the switch
1824
Dan Talayco910a8282012-04-07 00:05:20 -07001825 fq_logger.debug("Sending strict flow mod to switch:")
1826 fq_logger.debug(str(fc2))
rootf6af1672012-04-06 09:46:29 -07001827 fc2.send_rem = False
1828 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
1829 ft.insert(fc2)
1830
1831 # Do barrier, to make sure all flows are in
1832
1833 self.assertTrue(sw.barrier(), "Barrier failed")
1834
1835 result = True
1836
1837 # Check for any error messages
1838
1839 if not sw.errors_verify(0):
1840 result = False
1841
1842 # Verify flow table
1843
1844 sw.flow_tbl = ft
1845 if not sw.flow_tbl_verify():
1846 result = False
1847
1848 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07001849 fq_logger.debug("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001850
1851
1852class Flow_Mod_2(basic.SimpleProtocol):
1853 """
1854 Test FLOW_MOD_2 from draft top-half test plan
1855
1856 INPUTS
1857 None
1858 """
1859
1860 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001861 fq_logger.debug("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001862
Dan Talayco910a8282012-04-07 00:05:20 -07001863 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001864
1865 # Clear all flows from switch
1866
Dan Talayco910a8282012-04-07 00:05:20 -07001867 fq_logger.debug("Deleting all flows from switch")
1868 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001869 self.assertEqual(rc, 0, "Failed to delete all flows")
1870
1871 # Get switch capabilites
1872
Dan Talayco910a8282012-04-07 00:05:20 -07001873 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001874 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001875 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001876 self.assertTrue(sw.features_get(), "Get switch features failed")
1877 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1878
1879 # Dream up some flow information, i.e. space to chose from for
1880 # random flow parameter generation
1881
1882 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07001883 # Shrunk, to increase chance of meta-matches
1884 fi.rand(int(math.log(num_flows)) / 2)
rootf6af1672012-04-06 09:46:29 -07001885
1886 # Dream up some flows
1887
1888 ft = Flow_Tbl()
1889 ft.rand(sw, fi, num_flows)
1890
1891 # Send flow table to switch
1892
Dan Talayco910a8282012-04-07 00:05:20 -07001893 fq_logger.debug("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001894 for fc in ft.values(): # Randomizes order of sending
Dan Talayco910a8282012-04-07 00:05:20 -07001895 fq_logger.debug("Adding flow:")
1896 fq_logger.debug(str(fc));
rootf6af1672012-04-06 09:46:29 -07001897 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1898
1899 # Do barrier, to make sure all flows are in
1900
1901 self.assertTrue(sw.barrier(), "Barrier failed")
1902
1903 result = True
1904
1905 # Check for any error messages
1906
1907 if not sw.errors_verify(0):
1908 result = False
1909
1910 # Verify flow table
1911
1912 sw.flow_tbl = ft
1913 if not sw.flow_tbl_verify():
1914 result = False
1915
1916 # Pick a random flow as a basis
1917
1918 mfc = copy.deepcopy(ft.values()[0])
1919 mfc.rand_mod(fi, sw.sw_features.actions, sw.valid_ports)
1920
1921 # Repeatedly wildcard qualifiers
1922
1923 for wi in shuffle(range(len(all_wildcards_list))):
1924 w = all_wildcards_list[wi]
1925 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
1926 n = wildcard_get(mfc.match.wildcards, w)
1927 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07001928 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
1929 w, \
1930 random.randint(n + 1, 32) \
1931 )
rootf6af1672012-04-06 09:46:29 -07001932 else:
1933 continue
1934 else:
1935 if wildcard_get(mfc.match.wildcards, w) == 0:
1936 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
1937 else:
1938 continue
1939 mfc = mfc.canonical()
1940
1941 # Count the number of flows that would be modified
1942
1943 n = 0
1944 for fc in ft.values():
1945 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
1946 n = n + 1
1947
1948 # If more than 1, we found our loose delete flow spec
1949 if n > 1:
1950 break
1951
Dan Talayco910a8282012-04-07 00:05:20 -07001952 fq_logger.debug("Modifying %d flows" % (n))
1953 fq_logger.debug("Sending flow mod to switch:")
1954 fq_logger.debug(str(mfc))
rootf6af1672012-04-06 09:46:29 -07001955 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
1956
1957 # Do barrier, to make sure all flows are in
1958 self.assertTrue(sw.barrier(), "Barrier failed")
1959
1960 # Check for error message
1961
1962 if not sw.errors_verify(0):
1963 result = False
1964
1965 # Apply flow mod to local flow table
1966
1967 for fc in ft.values():
1968 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07001969 fc.cookie = mfc.cookie
1970 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07001971
1972 # Verify flow table
1973
1974 sw.flow_tbl = ft
1975 if not sw.flow_tbl_verify():
1976 result = False
1977
1978 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07001979 fq_logger.debug("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001980
1981
1982class Flow_Mod_3(basic.SimpleProtocol):
1983 """
1984 Test FLOW_MOD_3 from draft top-half test plan
1985
1986 INPUTS
1987 None
1988 """
1989
1990 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001991 fq_logger.debug("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001992
1993 # Clear all flows from switch
1994
Dan Talayco910a8282012-04-07 00:05:20 -07001995 fq_logger.debug("Deleting all flows from switch")
1996 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001997 self.assertEqual(rc, 0, "Failed to delete all flows")
1998
1999 # Get switch capabilites
2000
Dan Talayco910a8282012-04-07 00:05:20 -07002001 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002002 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002003 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002004 self.assertTrue(sw.features_get(), "Get switch features failed")
2005 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2006
2007 # Dream up some flow information, i.e. space to chose from for
2008 # random flow parameter generation
2009
2010 fi = Flow_Info()
2011 fi.rand(10)
2012
2013 # Dream up a flow config
2014
2015 fc = Flow_Cfg()
2016 fc.rand(fi, \
2017 sw.tbl_stats.stats[0].wildcards, \
2018 sw.sw_features.actions, \
2019 sw.valid_ports \
2020 )
2021 fc = fc.canonical()
2022
2023 # Send it to the switch
2024
Dan Talayco910a8282012-04-07 00:05:20 -07002025 fq_logger.debug("Sending flow mod to switch:")
2026 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07002027 ft = Flow_Tbl()
2028 fc.send_rem = False
2029 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2030 ft.insert(fc)
2031
2032 # Do barrier, to make sure all flows are in
2033
2034 self.assertTrue(sw.barrier(), "Barrier failed")
2035
2036 result = True
2037
2038 # Check for any error messages
2039
2040 if not sw.errors_verify(0):
2041 result = False
2042
2043 # Verify flow table
2044
2045 sw.flow_tbl = ft
2046 if not sw.flow_tbl_verify():
2047 result = False
2048
2049 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07002050 fq_logger.debug("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002051
2052
2053class Flow_Del_1(basic.SimpleProtocol):
2054 """
2055 Test FLOW_DEL_1 from draft top-half test plan
2056
2057 INPUTS
2058 None
2059 """
2060
2061 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07002062 fq_logger.debug("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002063
2064 # Clear all flows from switch
2065
Dan Talayco910a8282012-04-07 00:05:20 -07002066 fq_logger.debug("Deleting all flows from switch")
2067 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002068 self.assertEqual(rc, 0, "Failed to delete all flows")
2069
2070 # Get switch capabilites
2071
Dan Talayco910a8282012-04-07 00:05:20 -07002072 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002073 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002074 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002075 self.assertTrue(sw.features_get(), "Get switch features failed")
2076 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2077
2078 # Dream up some flow information, i.e. space to chose from for
2079 # random flow parameter generation
2080
2081 fi = Flow_Info()
2082 fi.rand(10)
2083
2084 # Dream up a flow config
2085
2086 fc = Flow_Cfg()
2087 fc.rand(fi, \
2088 sw.tbl_stats.stats[0].wildcards, \
2089 sw.sw_features.actions, \
2090 sw.valid_ports \
2091 )
2092 fc = fc.canonical()
2093
2094 # Send it to the switch
2095
Dan Talayco910a8282012-04-07 00:05:20 -07002096 fq_logger.debug("Sending flow add to switch:")
2097 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07002098 ft = Flow_Tbl()
2099 fc.send_rem = False
2100 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2101 ft.insert(fc)
2102
2103 # Dream up some different actions, with the same flow key
2104
2105 fc2 = copy.deepcopy(fc)
2106 while True:
2107 fc2.rand_mod(fi, \
2108 sw.sw_features.actions, \
2109 sw.valid_ports \
2110 )
2111 if fc2 != fc:
2112 break
2113
2114 # Delete strictly
2115
Dan Talayco910a8282012-04-07 00:05:20 -07002116 fq_logger.debug("Sending strict flow del to switch:")
2117 fq_logger.debug(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002118 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2119 ft.delete(fc)
2120
2121 # Do barrier, to make sure all flows are in
2122
2123 self.assertTrue(sw.barrier(), "Barrier failed")
2124
2125 result = True
2126
2127 # Check for any error messages
2128
2129 if not sw.errors_verify(0):
2130 result = False
2131
2132 # Verify flow table
2133
2134 sw.flow_tbl = ft
2135 if not sw.flow_tbl_verify():
2136 result = False
2137
2138 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07002139 fq_logger.debug("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002140
2141
2142class Flow_Del_2(basic.SimpleProtocol):
2143 """
2144 Test FLOW_DEL_2 from draft top-half test plan
2145
2146 INPUTS
2147 None
2148 """
2149
2150 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07002151 fq_logger.debug("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002152
Dan Talayco910a8282012-04-07 00:05:20 -07002153 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002154
2155 # Clear all flows from switch
2156
Dan Talayco910a8282012-04-07 00:05:20 -07002157 fq_logger.debug("Deleting all flows from switch")
2158 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002159 self.assertEqual(rc, 0, "Failed to delete all flows")
2160
2161 # Get switch capabilites
2162
Dan Talayco910a8282012-04-07 00:05:20 -07002163 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002164 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002165 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002166 self.assertTrue(sw.features_get(), "Get switch features failed")
2167 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2168
2169 # Dream up some flow information, i.e. space to chose from for
2170 # random flow parameter generation
2171
2172 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002173 # Shrunk, to increase chance of meta-matches
2174 fi.rand(int(math.log(num_flows)) / 2)
rootf6af1672012-04-06 09:46:29 -07002175
2176 # Dream up some flows
2177
2178 ft = Flow_Tbl()
2179 ft.rand(sw, fi, num_flows)
2180
2181 # Send flow table to switch
2182
Dan Talayco910a8282012-04-07 00:05:20 -07002183 fq_logger.debug("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002184 for fc in ft.values(): # Randomizes order of sending
Dan Talayco910a8282012-04-07 00:05:20 -07002185 fq_logger.debug("Adding flow:")
2186 fq_logger.debug(str(fc));
rootf6af1672012-04-06 09:46:29 -07002187 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2188
2189 # Do barrier, to make sure all flows are in
2190
2191 self.assertTrue(sw.barrier(), "Barrier failed")
2192
2193 result = True
2194
2195 # Check for any error messages
2196
2197 if not sw.errors_verify(0):
2198 result = False
2199
2200 # Verify flow table
2201
2202 sw.flow_tbl = ft
2203 if not sw.flow_tbl_verify():
2204 result = False
2205
2206 # Pick a random flow as a basis
2207
2208 dfc = copy.deepcopy(ft.values()[0])
2209 dfc.rand_mod(fi, sw.sw_features.actions, sw.valid_ports)
2210
2211 # Repeatedly wildcard qualifiers
2212
2213 for wi in shuffle(range(len(all_wildcards_list))):
2214 w = all_wildcards_list[wi]
2215 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2216 n = wildcard_get(dfc.match.wildcards, w)
2217 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002218 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2219 w, \
2220 random.randint(n + 1, 32) \
2221 )
rootf6af1672012-04-06 09:46:29 -07002222 else:
2223 continue
2224 else:
2225 if wildcard_get(dfc.match.wildcards, w) == 0:
2226 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2227 else:
2228 continue
2229 dfc = dfc.canonical()
2230
2231 # Count the number of flows that would be deleted
2232
2233 n = 0
2234 for fc in ft.values():
2235 if dfc.overlaps(fc, True):
2236 n = n + 1
2237
2238 # If more than 1, we found our loose delete flow spec
2239 if n > 1:
2240 break
2241
Dan Talayco910a8282012-04-07 00:05:20 -07002242 fq_logger.debug("Deleting %d flows" % (n))
2243 fq_logger.debug("Sending flow del to switch:")
2244 fq_logger.debug(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002245 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2246
2247 # Do barrier, to make sure all flows are in
2248 self.assertTrue(sw.barrier(), "Barrier failed")
2249
2250 # Check for error message
2251
2252 if not sw.errors_verify(0):
2253 result = False
2254
2255 # Apply flow mod to local flow table
2256
2257 for fc in ft.values():
2258 if dfc.overlaps(fc, True):
2259 ft.delete(fc)
2260
2261 # Verify flow table
2262
2263 sw.flow_tbl = ft
2264 if not sw.flow_tbl_verify():
2265 result = False
2266
2267 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07002268 fq_logger.debug("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002269
2270
rootf6af1672012-04-06 09:46:29 -07002271class Flow_Del_4(basic.SimpleProtocol):
2272 """
2273 Test FLOW_DEL_4 from draft top-half test plan
2274
2275 INPUTS
2276 None
2277 """
2278
2279 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07002280 fq_logger.debug("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002281
2282 # Clear all flows from switch
2283
Dan Talayco910a8282012-04-07 00:05:20 -07002284 fq_logger.debug("Deleting all flows from switch")
2285 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002286 self.assertEqual(rc, 0, "Failed to delete all flows")
2287
2288 # Get switch capabilites
2289
Dan Talayco910a8282012-04-07 00:05:20 -07002290 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002291 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002292 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002293 self.assertTrue(sw.features_get(), "Get switch features failed")
2294 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2295
2296 # Dream up some flow information, i.e. space to chose from for
2297 # random flow parameter generation
2298
2299 fi = Flow_Info()
2300 fi.rand(10)
2301
2302 # Dream up a flow config
2303
2304 fc = Flow_Cfg()
2305 fc.rand(fi, \
2306 sw.tbl_stats.stats[0].wildcards, \
2307 sw.sw_features.actions, \
2308 sw.valid_ports \
2309 )
2310 fc = fc.canonical()
2311
2312 # Send it to the switch. with "notify on removed"
2313
Dan Talayco910a8282012-04-07 00:05:20 -07002314 fq_logger.debug("Sending flow add to switch:")
2315 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07002316 ft = Flow_Tbl()
2317 fc.send_rem = True
2318 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2319 ft.insert(fc)
2320
2321 # Dream up some different actions, with the same flow key
2322
2323 fc2 = copy.deepcopy(fc)
2324 while True:
2325 fc2.rand_mod(fi, \
2326 sw.sw_features.actions, \
2327 sw.valid_ports \
2328 )
2329 if fc2 != fc:
2330 break
2331
2332 # Delete strictly
2333
Dan Talayco910a8282012-04-07 00:05:20 -07002334 fq_logger.debug("Sending strict flow del to switch:")
2335 fq_logger.debug(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002336 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2337 ft.delete(fc)
2338
2339 # Do barrier, to make sure all flows are in
2340
2341 self.assertTrue(sw.barrier(), "Barrier failed")
2342
2343 result = True
2344
2345 # Check for expected "removed" message
2346
Howard Persh3340d452012-04-06 16:45:21 -07002347 if not sw.errors_verify(0):
2348 result = False
2349
2350 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07002351 result = False
2352
2353 # Verify flow table
2354
2355 sw.flow_tbl = ft
2356 if not sw.flow_tbl_verify():
2357 result = False
2358
2359 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07002360 fq_logger.debug("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002361