blob: 8d29213a96d27bec60af41cb881b137b5ae65630 [file] [log] [blame]
Howard Pershc7963582012-03-29 10:02:59 -07001"""
2Flow query test case.
3
4Attempts to fill switch to capacity with randomized flows, and ensure that they all are read back correctly.
5"""
Howard Persh680b92a2012-03-31 13:34:35 -07006import math
Howard Pershc7963582012-03-29 10:02:59 -07007
8import logging
9
10import unittest
11import random
12
13import oftest.controller as controller
14import oftest.cstruct as ofp
15import oftest.message as message
16import oftest.dataplane as dataplane
17import oftest.action as action
18import oftest.action_list as action_list
19import oftest.parse as parse
20import pktact
21import basic
22
23from testutils import *
24from time import sleep
25
26#@var port_map Local copy of the configuration map from OF port
27# numbers to OS interfaces
28pa_port_map = None
29#@var pa_logger Local logger object
30pa_logger = None
31#@var pa_config Local copy of global configuration data
32pa_config = None
33
rootf6af1672012-04-06 09:46:29 -070034# For test priority
35test_prio = {}
36
37
Howard Pershc7963582012-03-29 10:02:59 -070038def test_set_init(config):
39 """
40 Set up function for packet action test classes
41
42 @param config The configuration dictionary; see oft
43 """
44
45 basic.test_set_init(config)
46
47 global pa_port_map
48 global pa_logger
49 global pa_config
50
51 pa_logger = logging.getLogger("pkt_act")
52 pa_logger.info("Initializing test set")
53 pa_port_map = config["port_map"]
54 pa_config = config
55
56
rootf6af1672012-04-06 09:46:29 -070057def flip_coin():
58 return random.randint(1, 100) <= 50
59
60
Howard Pershc7963582012-03-29 10:02:59 -070061def shuffle(list):
62 n = len(list)
63 lim = n * n
64 i = 0
65 while i < lim:
66 a = random.randint(0, n - 1)
67 b = random.randint(0, n - 1)
68 temp = list[a]
69 list[a] = list[b]
70 list[b] = temp
71 i = i + 1
72 return list
73
74
Howard Persh680b92a2012-03-31 13:34:35 -070075def rand_pick(list):
76 return list[random.randint(0, len(list) - 1)]
Howard Pershc7963582012-03-29 10:02:59 -070077
Howard Persh680b92a2012-03-31 13:34:35 -070078def rand_dl_addr():
79 return [random.randint(0, 255) & ~1,
80 random.randint(0, 255),
81 random.randint(0, 255),
82 random.randint(0, 255),
83 random.randint(0, 255),
84 random.randint(0, 255)
85 ]
Howard Pershc7963582012-03-29 10:02:59 -070086
87def rand_nw_addr():
88 return random.randint(0, (1 << 32) - 1)
89
90
rootf6af1672012-04-06 09:46:29 -070091class Flow_Info:
Howard Persh680b92a2012-03-31 13:34:35 -070092 # Members:
93 # priorities - list of flow priorities
94 # dl_addrs - list of MAC addresses
95 # vlans - list of VLAN ids
96 # ethertypes - list of Ethertypes
97 # ip_addrs - list of IP addresses
98 # ip_tos - list of IP TOS values
99 # ip_protos - list of IP protocols
100 # l4_ports - list of L4 ports
101
102 def __init__(self):
103 priorities = []
104 dl_addrs = []
105 vlans = []
106 ethertypes = []
107 ip_addrs = []
108 ip_tos = []
109 ip_protos = []
110 l4_ports = []
111
112 def rand(self, n):
113 self.priorities = []
114 i = 0
115 while i < n:
116 self.priorities.append(random.randint(1, 65534))
117 i = i + 1
118
119 self.dl_addrs = []
120 i = 0
121 while i < n:
122 self.dl_addrs.append(rand_dl_addr())
123 i = i + 1
124
125 self.vlans = []
126 i = 0
127 while i < n:
128 self.vlans.append(random.randint(1, 4094))
129 i = i + 1
130
rootf6af1672012-04-06 09:46:29 -0700131 self.ethertypes = [0x0800, 0x0806]
Howard Persh680b92a2012-03-31 13:34:35 -0700132 i = 0
133 while i < n:
134 self.ethertypes.append(random.randint(0, (1 << 16) - 1))
135 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700136 self.ethertypes = shuffle(self.ethertypes)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700137
138 self.ip_addrs = []
139 i = 0
140 while i < n:
141 self.ip_addrs.append(rand_nw_addr())
142 i = i + 1
143
144 self.ip_tos = []
145 i = 0
146 while i < n:
147 self.ip_tos.append(random.randint(0, (1 << 8) - 1) & ~3)
148 i = i + 1
149
rootf6af1672012-04-06 09:46:29 -0700150 self.ip_protos = [1, 6, 17]
Howard Persh680b92a2012-03-31 13:34:35 -0700151 i = 0
152 while i < n:
153 self.ip_protos.append(random.randint(0, (1 << 8) - 1))
154 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700155 self.ip_protos = shuffle(self.ip_protos)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700156
157 self.l4_ports = []
158 i = 0
159 while i < n:
160 self.l4_ports.append(random.randint(0, (1 << 16) - 1))
161 i = i + 1
162
163 def rand_priority(self):
164 return rand_pick(self.priorities)
165
166 def rand_dl_addr(self):
167 return rand_pick(self.dl_addrs)
168
169 def rand_vlan(self):
170 return rand_pick(self.vlans)
171
172 def rand_ethertype(self):
173 return rand_pick(self.ethertypes)
174
175 def rand_ip_addr(self):
176 return rand_pick(self.ip_addrs)
177
178 def rand_ip_tos(self):
179 return rand_pick(self.ip_tos)
180
181 def rand_ip_proto(self):
182 return rand_pick(self.ip_protos)
183
184 def rand_l4_port(self):
185 return rand_pick(self.l4_ports)
186
187
Howard Pershc7963582012-03-29 10:02:59 -0700188# TBD - These don't belong here
189
Howard Persh680b92a2012-03-31 13:34:35 -0700190all_wildcards_list = [ofp.OFPFW_IN_PORT,
Howard Persh680b92a2012-03-31 13:34:35 -0700191 ofp.OFPFW_DL_DST,
rootf6af1672012-04-06 09:46:29 -0700192 ofp.OFPFW_DL_SRC,
193 ofp.OFPFW_DL_VLAN,
194 ofp.OFPFW_DL_VLAN_PCP,
Howard Persh680b92a2012-03-31 13:34:35 -0700195 ofp.OFPFW_DL_TYPE,
rootf6af1672012-04-06 09:46:29 -0700196 ofp.OFPFW_NW_TOS,
Howard Persh680b92a2012-03-31 13:34:35 -0700197 ofp.OFPFW_NW_PROTO,
Howard Persh680b92a2012-03-31 13:34:35 -0700198 ofp.OFPFW_NW_SRC_MASK,
199 ofp.OFPFW_NW_DST_MASK,
rootf6af1672012-04-06 09:46:29 -0700200 ofp.OFPFW_TP_SRC,
201 ofp.OFPFW_TP_DST
Howard Persh680b92a2012-03-31 13:34:35 -0700202 ]
Howard Pershc7963582012-03-29 10:02:59 -0700203
rootf6af1672012-04-06 09:46:29 -0700204# TBD - Need this because there are duplicates in ofp.ofp_flow_wildcards_map -- FIX
205all_wildcard_names = {
206 1 : 'OFPFW_IN_PORT',
207 2 : 'OFPFW_DL_VLAN',
208 4 : 'OFPFW_DL_SRC',
209 8 : 'OFPFW_DL_DST',
210 16 : 'OFPFW_DL_TYPE',
211 32 : 'OFPFW_NW_PROTO',
212 64 : 'OFPFW_TP_SRC',
213 128 : 'OFPFW_TP_DST',
214 1048576 : 'OFPFW_DL_VLAN_PCP',
215 2097152 : 'OFPFW_NW_TOS'
216}
217
218
219def wildcard_set(x, w, val):
220 result = x
221 if w == ofp.OFPFW_NW_SRC_MASK:
222 result = (result & ~ofp.OFPFW_NW_SRC_MASK) | (val << ofp.OFPFW_NW_SRC_SHIFT)
223 elif w == ofp.OFPFW_NW_DST_MASK:
224 result = (result & ~ofp.OFPFW_NW_DST_MASK) | (val << ofp.OFPFW_NW_DST_SHIFT)
225 elif val == 0:
226 result = result & ~w
227 else:
228 result = result | w
229 return result
230
231def wildcard_get(x, w):
232 if w == ofp.OFPFW_NW_SRC_MASK:
233 return (x & ofp.OFPFW_NW_SRC_MASK) >> ofp.OFPFW_NW_SRC_SHIFT
234 if w == ofp.OFPFW_NW_DST_MASK:
235 return (x & ofp.OFPFW_NW_DST_MASK) >> ofp.OFPFW_NW_DST_SHIFT
236 return 1 if (x & w) != 0 else 0
237
Howard Pershc7963582012-03-29 10:02:59 -0700238
Howard Persh680b92a2012-03-31 13:34:35 -0700239all_actions_list = [ofp.OFPAT_OUTPUT,
240 ofp.OFPAT_SET_VLAN_VID,
241 ofp.OFPAT_SET_VLAN_PCP,
242 ofp.OFPAT_STRIP_VLAN,
243 ofp.OFPAT_SET_DL_SRC,
244 ofp.OFPAT_SET_DL_DST,
245 ofp.OFPAT_SET_NW_SRC,
246 ofp.OFPAT_SET_NW_DST,
247 ofp.OFPAT_SET_NW_TOS,
248 ofp.OFPAT_SET_TP_SRC,
249 ofp.OFPAT_SET_TP_DST,
250 ofp.OFPAT_ENQUEUE
251 ]
252
253def dl_addr_to_str(a):
254 return "%x:%x:%x:%x:%x:%x" % tuple(a)
255
256def ip_addr_to_str(a, n):
rootf6af1672012-04-06 09:46:29 -0700257 if n is not None:
258 a = a & ~((1 << (32 - n)) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700259 result = "%d.%d.%d.%d" % (a >> 24, \
260 (a >> 16) & 0xff, \
261 (a >> 8) & 0xff, \
262 a & 0xff \
263 )
264 if n is not None:
265 result = result + ("/%d" % (n))
266 return result
267
Howard Pershc7963582012-03-29 10:02:59 -0700268
rootf6af1672012-04-06 09:46:29 -0700269class Flow_Cfg:
Howard Pershc7963582012-03-29 10:02:59 -0700270 # Members:
271 # - match
272 # - idle_timeout
273 # - hard_timeout
274 # - priority
275 # - action_list
276
277 def __init__(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700278 self.priority = 0
Howard Pershc7963582012-03-29 10:02:59 -0700279 self.match = parse.ofp_match()
280 self.match.wildcards = ofp.OFPFW_ALL
281 self.idle_timeout = 0
282 self.hard_timeout = 0
Howard Pershc7963582012-03-29 10:02:59 -0700283 self.actions = action_list.action_list()
284
rootf6af1672012-04-06 09:46:29 -0700285 # {pri, match} is considered a flow key
286 def key_equal(self, x):
Howard Persh680b92a2012-03-31 13:34:35 -0700287 if self.priority != x.priority:
288 return False
289 # TBD - Should this logic be moved to ofp_match.__eq__()?
290 if self.match.wildcards != x.match.wildcards:
291 return False
rootf6af1672012-04-06 09:46:29 -0700292 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700293 and self.match.in_port != x.match.in_port:
294 return False
rootf6af1672012-04-06 09:46:29 -0700295 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700296 and self.match.dl_dst != x.match.dl_dst:
297 return False
rootf6af1672012-04-06 09:46:29 -0700298 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0 \
299 and self.match.dl_src != x.match.dl_src:
300 return False
301 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700302 and self.match.dl_vlan != x.match.dl_vlan:
303 return False
rootf6af1672012-04-06 09:46:29 -0700304 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700305 and self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
306 return False
rootf6af1672012-04-06 09:46:29 -0700307 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700308 and self.match.dl_type != x.match.dl_type:
309 return False
rootf6af1672012-04-06 09:46:29 -0700310 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700311 and self.match.nw_tos != x.match.nw_tos:
312 return False
rootf6af1672012-04-06 09:46:29 -0700313 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700314 and self.match.nw_proto != x.match.nw_proto:
315 return False
rootf6af1672012-04-06 09:46:29 -0700316 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
317 if n < 32:
318 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700319 if (self.match.nw_src & m) != (x.match.nw_src & m):
320 return False
rootf6af1672012-04-06 09:46:29 -0700321 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
322 if n < 32:
323 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700324 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
325 return False
rootf6af1672012-04-06 09:46:29 -0700326 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0 \
327 and self.match.tp_src != x.match.tp_src:
Howard Persh680b92a2012-03-31 13:34:35 -0700328 return False
rootf6af1672012-04-06 09:46:29 -0700329 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0 \
330 and self.match.tp_dst != x.match.tp_dst:
331 return False
332 return True
333
334 def non_key_equal(self, x):
335 if self.cookie != x.cookie:
Howard Pershc7963582012-03-29 10:02:59 -0700336 return False
337 if self.idle_timeout != x.idle_timeout:
338 return False
339 if self.hard_timeout != x.hard_timeout:
340 return False
rootf6af1672012-04-06 09:46:29 -0700341 # Compare actions lists as unordered, since Argon may re-order action lists.
342 # This is in apparent violation of the spec.
343 # TBD - Verify, or create option in test to check ordered/unordered
344 aa = copy.deepcopy(x.actions.actions)
345 for a in self.actions.actions:
346 i = 0
347 while i < len(aa):
348 if a == aa[i]:
349 break
350 i = i + 1
351 if i < len(aa):
352 aa.pop(i)
353 else:
354 return False
355 return aa == []
356
357 def flow_key_str(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700358 result = "priority=%d" % self.priority
359 # TBD - Would be nice if ofp_match.show() was better behaved
360 # (no newlines), and more intuitive (things in hex where approprate), etc.
rootf6af1672012-04-06 09:46:29 -0700361 result = result + (", wildcards=0x%x={" % (self.match.wildcards))
Howard Persh680b92a2012-03-31 13:34:35 -0700362 sep = ""
rootf6af1672012-04-06 09:46:29 -0700363 for w in all_wildcards_list:
364 if (self.match.wildcards & w) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700365 continue
366 if w == ofp.OFPFW_NW_SRC_MASK:
rootf6af1672012-04-06 09:46:29 -0700367 n = wildcard_get(self.match.wildcards, w)
368 if n > 0:
369 result = result + sep + ("OFPFW_NW_SRC(%d)" % (n))
Howard Persh680b92a2012-03-31 13:34:35 -0700370 elif w == ofp.OFPFW_NW_DST_MASK:
rootf6af1672012-04-06 09:46:29 -0700371 n = wildcard_get(self.match.wildcards, w)
372 if n > 0:
373 result = result + sep + ("OFPFW_NW_DST(%d)" % (n))
Howard Persh680b92a2012-03-31 13:34:35 -0700374 else:
rootf6af1672012-04-06 09:46:29 -0700375 result = result + sep + all_wildcard_names[w]
Howard Persh680b92a2012-03-31 13:34:35 -0700376 sep = ", "
377 result = result +"}"
rootf6af1672012-04-06 09:46:29 -0700378 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700379 result = result + (", in_port=%d" % (self.match.in_port))
rootf6af1672012-04-06 09:46:29 -0700380 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700381 result = result + (", dl_dst=%s" % (dl_addr_to_str(self.match.dl_dst)))
rootf6af1672012-04-06 09:46:29 -0700382 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
383 result = result + (", dl_src=%s" % (dl_addr_to_str(self.match.dl_src)))
384 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700385 result = result + (", dl_vlan=%d" % (self.match.dl_vlan))
rootf6af1672012-04-06 09:46:29 -0700386 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700387 result = result + (", dl_vlan_pcp=%d" % (self.match.dl_vlan_pcp))
rootf6af1672012-04-06 09:46:29 -0700388 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700389 result = result + (", dl_type=0x%x" % (self.match.dl_type))
rootf6af1672012-04-06 09:46:29 -0700390 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700391 result = result + (", nw_tos=0x%x" % (self.match.nw_tos))
rootf6af1672012-04-06 09:46:29 -0700392 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700393 result = result + (", nw_proto=%d" % (self.match.nw_proto))
rootf6af1672012-04-06 09:46:29 -0700394 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700395 if n < 32:
rootf6af1672012-04-06 09:46:29 -0700396 result = result + (", nw_src=%s" % (ip_addr_to_str(self.match.nw_src, 32 - n)))
397 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700398 if n < 32:
rootf6af1672012-04-06 09:46:29 -0700399 result = result + (", nw_dst=%s" % (ip_addr_to_str(self.match.nw_dst, 32 - n)))
400 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700401 result = result + (", tp_src=%d" % self.match.tp_src)
rootf6af1672012-04-06 09:46:29 -0700402 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700403 result = result + (", tp_dst=%d" % self.match.tp_dst)
rootf6af1672012-04-06 09:46:29 -0700404 return result
405
406 def __eq__(self, x):
407 return (self.key_equal(x) and self.non_key_equal(x))
408
409 def __str__(self):
410 result = self.flow_key_str()
Howard Persh680b92a2012-03-31 13:34:35 -0700411 result = result + (", idle_timeout=%d" % self.idle_timeout)
412 result = result + (", hard_timeout=%d" % self.hard_timeout)
Howard Persh680b92a2012-03-31 13:34:35 -0700413 for a in self.actions.actions:
414 result = result + (", action=%s" % ofp.ofp_action_type_map[a.type])
415 if a.type == ofp.OFPAT_OUTPUT:
416 result = result + ("(%d)" % (a.port))
417 elif a.type == ofp.OFPAT_SET_VLAN_VID:
418 result = result + ("(%d)" % (a.vlan_vid))
419 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
420 result = result + ("(%d)" % (a.vlan_pcp))
421 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
422 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
423 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
424 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
425 elif a.type == ofp.OFPAT_SET_NW_TOS:
426 result = result + ("(0x%x)" % (a.nw_tos))
427 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
428 result = result + ("(%d)" % (a.tp_port))
429 elif a.type == ofp.OFPAT_ENQUEUE:
430 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
431 return result
Howard Pershc7963582012-03-29 10:02:59 -0700432
rootf6af1672012-04-06 09:46:29 -0700433 # Randomize flow data for flow modifies
434 def rand_mod(self, fi, valid_actions, valid_ports):
435 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700436
Howard Persh680b92a2012-03-31 13:34:35 -0700437 # Action lists are ordered, so pick an ordered random subset of
438 # supported actions
439 supported_actions = []
440 for a in all_actions_list:
441 if ((1 << a) & valid_actions) != 0:
442 supported_actions.append(a)
443
444 supported_actions = shuffle(supported_actions)
445 supported_actions \
446 = supported_actions[0 : random.randint(1, len(supported_actions))]
Howard Pershc7963582012-03-29 10:02:59 -0700447
448 self.actions = action_list.action_list()
Howard Persh680b92a2012-03-31 13:34:35 -0700449 for a in supported_actions:
Howard Pershc7963582012-03-29 10:02:59 -0700450 if a == ofp.OFPAT_OUTPUT:
451 # TBD - Output actions are clustered in list, spread them out?
452 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700453 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700454 for pi in port_idxs:
455 act = action.action_output()
Howard Persh680b92a2012-03-31 13:34:35 -0700456 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700457 self.actions.add(act)
458 elif a == ofp.OFPAT_SET_VLAN_VID:
459 act = action.action_set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700460 act.vlan_vid = fi.rand_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700461 self.actions.add(act)
462 elif a == ofp.OFPAT_SET_VLAN_PCP:
463 # TBD - Temporaily removed, broken in Indigo
464 #act = action.action_set_vlan_pcp()
465 #act.vlan_pcp = random.randint(0, (1 << 3) - 1)
466 pass
467 elif a == ofp.OFPAT_STRIP_VLAN:
468 act = action.action_strip_vlan()
469 self.actions.add(act)
470 elif a == ofp.OFPAT_SET_DL_SRC:
471 act = action.action_set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700472 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700473 self.actions.add(act)
474 elif a == ofp.OFPAT_SET_DL_DST:
475 act = action.action_set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700476 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700477 self.actions.add(act)
478 elif a == ofp.OFPAT_SET_NW_SRC:
479 act = action.action_set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700480 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700481 self.actions.add(act)
482 elif a == ofp.OFPAT_SET_NW_DST:
483 act = action.action_set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700484 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700485 self.actions.add(act)
486 elif a == ofp.OFPAT_SET_NW_TOS:
487 act = action.action_set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700488 act.nw_tos = fi.rand_ip_tos()
Howard Pershc7963582012-03-29 10:02:59 -0700489 self.actions.add(act)
490 elif a == ofp.OFPAT_SET_TP_SRC:
491 act = action.action_set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700492 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700493 self.actions.add(act)
494 elif a == ofp.OFPAT_SET_TP_DST:
495 act = action.action_set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700496 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700497 self.actions.add(act)
498 elif a == ofp.OFPAT_ENQUEUE:
499 # TBD - Enqueue actions are clustered in list, spread them out?
500 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700501 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700502 for pi in port_idxs:
503 act = action.action_enqueue()
Howard Persh680b92a2012-03-31 13:34:35 -0700504 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700505 # TBD - Limits for queue number?
506 act.queue_id = random.randint(0, 7)
507 self.actions.add(act)
508
509 return self
510
rootf6af1672012-04-06 09:46:29 -0700511 # Randomize flow cfg
512 def rand(self, fi, valid_wildcards, valid_actions, valid_ports):
513 # Start with no wildcards, i.e. everything specified
514 self.match.wildcards = 0
515
516 # Make approx. 5% of flows exact
517 exact = (random.randint(1, 100) <= 5)
518
519 # For each qualifier Q,
520 # if (wildcarding is not supported for Q,
521 # or an exact flow is specified
522 # or a coin toss comes up heads),
523 # specify Q
524 # else
525 # wildcard Q
526
527 if wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
528 or exact \
529 or flip_coin():
530 self.match.in_port = rand_pick(valid_ports)
531 else:
532 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_IN_PORT, 1)
533
534 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
535 or exact \
536 or flip_coin():
537 self.match.dl_dst = fi.rand_dl_addr()
538 else:
539 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_DST, 1)
540
541 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
542 or exact \
543 or flip_coin():
544 self.match.dl_src = fi.rand_dl_addr()
545 else:
546 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_SRC, 1)
547
548 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
549 or exact \
550 or flip_coin():
551 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
552 else:
553 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP, 1)
554
555 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
556 or exact \
557 or flip_coin():
558 self.match.dl_vlan = fi.rand_vlan()
559 else:
560 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_VLAN, 1)
561
562 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
563 or exact \
564 or flip_coin():
565 self.match.dl_type = fi.rand_ethertype()
566 else:
567 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_TYPE, 1)
568
569 if exact or flip_coin():
570 n = 0
571 else:
572 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
573 if n > 32:
574 n = 32
575 n = random.randint(0, n)
576 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK, n)
577 if n < 32:
578 self.match.nw_src = fi.rand_ip_addr() & ~((1 << n) - 1)
579 # Specifying any IP address match other than all bits
580 # don't care requires that Ethertype is one of {IP, ARP}
581 if flip_coin():
582 self.match.dl_type = rand_pick([0x0800, 0x0806])
583 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_TYPE, 0)
584
585 if exact or flip_coin():
586 n = 0
587 else:
588 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
589 if n > 32:
590 n = 32
591 n = random.randint(0, n)
592 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_NW_DST_MASK, n)
593 if n < 32:
594 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
595 # Specifying any IP address match other than all bits
596 # don't care requires that Ethertype is one of {IP, ARP}
597 if flip_coin():
598 self.match.dl_type = rand_pick([0x0800, 0x0806])
599 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_TYPE, 0)
600
601 if wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
602 or exact \
603 or flip_coin():
604 self.match.nw_tos = fi.rand_ip_tos()
605 # Specifying a TOS value requires that Ethertype is IP
606 if flip_coin():
607 self.match.dl_type = 0x0800
608 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_TYPE, 0)
609 else:
610 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_NW_TOS, 1)
611
612# <TBD>
613# Due to a bug in OVS, don't specify nw_proto on it's own.
614# OVS will allow specifying a value for nw_proto, even if dl_type is not
615# specified as IP.
616# REMOVE FOR ARGON TESTING, AND BE SURE ABOUT INDENTATION
617# </TBD>
618# if wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
619# or exact \
620# or flip_coin():
621# self.match.nw_proto = fi.rand_ip_proto()
622# # Specifying an IP protocol requires that Ethertype is IP
623# if flip_coin():
624# self.match.dl_type = 0x0800
625# self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_TYPE, 0)
626# else:
627 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_NW_PROTO, 1)
628
629 if wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
630 or exact\
631 or flip_coin():
632 self.match.tp_src = fi.rand_l4_port()
633 # Specifying a L4 port requires that IP protcol is
634 # one of {ICMP, TCP, UDP}
635 if flip_coin():
636 self.match.nw_proto = rand_pick([1, 6, 17])
637 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_NW_PROTO, 0)
638 # Specifying a L4 port requirues that Ethertype is IP
639 self.match.dl_type = 0x0800
640 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_TYPE, 0)
641 if self.match.nw_proto == 1:
642 self.match.tp_src = self.match.tp_src & 0xff
643 else:
644 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_TP_SRC, 1)
645
646 if wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
647 or exact \
648 or flip_coin():
649 self.match.tp_dst = fi.rand_l4_port()
650 # Specifying a L4 port requires that IP protcol is
651 # one of {ICMP, TCP, UDP}
652 if flip_coin():
653 self.match.nw_proto = rand_pick([1, 6, 17])
654 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_NW_PROTO, 0)
655 # Specifying a L4 port requirues that Ethertype is IP
656 self.match.dl_type = 0x0800
657 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_DL_TYPE, 0)
658 if self.match.nw_proto == 1:
659 self.match.tp_dst = self.match.tp_dst & 0xff
660 else:
661 self.match.wildcards = wildcard_set(self.match.wildcards, ofp.OFPFW_TP_DST, 1)
662
663 # If nothing is wildcarded, it is an exact flow spec -- some switches
664 # (Open vSwitch, for one) *require* that exact flow specs have priority 65535.
665 self.priority = 65535 if self.match.wildcards == 0 else fi.rand_priority()
666
667 # N.B. Don't make the timeout too short, else the flow might
668 # disappear before we get a chance to check for it.
669 t = random.randint(0, 65535)
670 self.idle_timeout = 0 if t < 60 else t
671 t = random.randint(0, 65535)
672 self.hard_timeout = 0 if t < 60 else t
673
674 self.rand_mod(fi, valid_actions, valid_ports)
675
676 return self
677
678 # Return flow cfg in canonical form
679 # - There are dependencies between flow qualifiers, e.g. it only makes sense to qualify nw_proto if dl_type is qualified to be 0x0800 (IP).
680 # The canonical form of flow match criteria will "wildcard out" all such cases.
681 def canonical(self):
682 result = copy.deepcopy(self)
683 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
684 or result.match.dl_type not in [0x0800, 0x0806]:
685 # dl_tyoe is wildcarded, or specified as something other than IP or ARP
686 # => nw_src and nw_dst cannot be specified, must be wildcarded
687 result.match.wildcards = wildcard_set(result.match.wildcards, ofp.OFPFW_NW_SRC_MASK, 32)
688 result.match.wildcards = wildcard_set(result.match.wildcards, ofp.OFPFW_NW_DST_MASK, 32)
689 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
690 or result.match.dl_type != 0x0800:
691 # dl_type is wildcarded, or specified as something other than IP
692 # => nw_proto, nw_tos, tp_src and tp_dst cannot be specified, must be wildcarded
693 result.match.wildcards = wildcard_set(result.match.wildcards, ofp.OFPFW_NW_PROTO, 1)
694 result.match.wildcards = wildcard_set(result.match.wildcards, ofp.OFPFW_NW_TOS, 1)
695 result.match.wildcards = wildcard_set(result.match.wildcards, ofp.OFPFW_TP_SRC, 1)
696 result.match.wildcards = wildcard_set(result.match.wildcards, ofp.OFPFW_TP_DST, 1)
697 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
698 or result.match.nw_proto not in [1, 6, 17]:
699 # nw_proto is wildcarded, or specified as something other than ICMP, TCP or UDP
700 # => tp_src and tp_dst cannot be specified, must be wildcarded
701 result.match.wildcards = wildcard_set(result.match.wildcards, ofp.OFPFW_TP_SRC, 1)
702 result.match.wildcards = wildcard_set(result.match.wildcards, ofp.OFPFW_TP_DST, 1)
703 return result
704
Howard Persh680b92a2012-03-31 13:34:35 -0700705 # Overlap check
706 # delf == True <=> Check for delete overlap, else add overlap
707 # "Add overlap" is defined as there exists a packet that could match both the
708 # receiver and argument flowspecs
709 # "Delete overlap" is defined as the specificity of the argument flowspec
710 # is greater than or equal to the specificity of the receiver flowspec
711 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -0700712 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
713 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700714 if self.match.in_port != x.match.in_port:
715 return False # Both specified, and not equal
716 elif delf:
717 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700718 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
719 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700720 if self.match.dl_vlan != x.match.dl_vlan:
721 return False # Both specified, and not equal
722 elif delf:
723 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700724 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
725 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700726 if self.match.dl_src != x.match.dl_src:
727 return False # Both specified, and not equal
728 elif delf:
729 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700730 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
731 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700732 if self.match.dl_dst != x.match.dl_dst:
733 return False # Both specified, and not equal
734 elif delf:
735 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700736 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
737 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700738 if self.match.dl_type != x.match.dl_type:
739 return False # Both specified, and not equal
740 elif delf:
741 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -0700742 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
743 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700744 if self.match.nw_proto != x.match.nw_proto:
745 return False # Both specified, and not equal
746 elif delf:
747 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700748 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
749 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700750 if self.match.tp_src != x.match.tp_src:
751 return False # Both specified, and not equal
752 elif delf:
753 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700754 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
755 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700756 if self.match.tp_dst != x.match.tp_dst:
757 return False # Both specified, and not equal
758 elif delf:
759 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700760 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
761 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700762 if delf and na < nb:
763 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -0700764 if (na < 32 and nb < 32):
765 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
766 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -0700767 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -0700768 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
769 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700770 if delf and na < nb:
771 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -0700772 if (na < 32 and nb < 32):
773 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
774 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
rootf6af1672012-04-06 09:46:29 -0700775 return False # Overlapping bits not equal
776 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
777 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700778 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
779 return False # Both specified, and not equal
780 elif delf:
781 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700782 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
783 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700784 if self.match.nw_tos != x.match.nw_tos:
785 return False # Both specified, and not equal
786 elif delf:
787 return False # Receiver more specific
788 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -0700789
790 def to_flow_mod_msg(self, msg):
791 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -0700792 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -0700793 msg.idle_timeout = self.idle_timeout
794 msg.hard_timeout = self.hard_timeout
795 msg.priority = self.priority
796 msg.actions = self.actions
797 return msg
798
799 def from_flow_stat(self, msg):
800 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -0700801 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -0700802 self.idle_timeout = msg.idle_timeout
803 self.hard_timeout = msg.hard_timeout
804 self.priority = msg.priority
805 self.actions = msg.actions
806
rootf6af1672012-04-06 09:46:29 -0700807 def from_flow_rem(self, msg):
808 self.match = msg.match
809 self.idle_timeout = msg.idle_timeout
810 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -0700811
Howard Pershc7963582012-03-29 10:02:59 -0700812
rootf6af1672012-04-06 09:46:29 -0700813class Flow_Tbl:
814 def clear(self):
815 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -0700816
rootf6af1672012-04-06 09:46:29 -0700817 def __init__(self):
818 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -0700819
rootf6af1672012-04-06 09:46:29 -0700820 def find(self, f):
821 return self.dict.get(f.flow_key_str(), None)
822
823 def insert(self, f):
824 self.dict[f.flow_key_str()] = f
825
826 def delete(self, f):
827 del self.dict[f.flow_key_str()]
828
829 def values(self):
830 return self.dict.values()
831
832 def count(self):
833 return len(self.dict)
834
835 def rand(self, sw, fi, num_flows):
836 self.clear()
837 i = 0
838 tbl = 0
839 j = 0
840 while i < num_flows:
841 fc = Flow_Cfg()
842 fc.rand(fi, \
843 sw.tbl_stats.stats[tbl].wildcards, \
844 sw.sw_features.actions, \
845 sw.valid_ports \
846 )
847 fc = fc.canonical()
848 if self.find(fc):
849 continue
850 fc.send_rem = False
851 self.insert(fc)
852 i = i + 1
853 j = j + 1
854 if j >= sw.tbl_stats.stats[tbl].max_entries:
855 tbl = tbl + 1
856 j = 0
857
858
859class Switch:
860 # Members:
861 # controller - switch's test controller
862 # sw_features - switch's OFPT_FEATURES_REPLY message
863 # valid_ports - list of valid port numbers
864 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
865 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
866 # flow_tbl - (test's idea of) switch's flow table
867
868 def __init__(self):
869 self.controller = None
870 self.sw_features = None
871 self.valid_ports = []
872 self.tbl_stats = None
873 self.flow_stats = None
874 self.flow_tbl = Flow_Tbl()
875
876 def features_get(self):
877 # Get switch features
878 request = message.features_request()
879 (self.sw_features, pkt) = self.controller.transact(request, timeout=2)
880 if self.sw_features is None:
881 return False
882 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
883 return True
884
885 def tbl_stats_get(self):
886 # Get table stats
Howard Persh680b92a2012-03-31 13:34:35 -0700887 request = message.table_stats_request()
rootf6af1672012-04-06 09:46:29 -0700888 (self.tbl_stats, pkt) = self.controller.transact(request, timeout=2)
889 return (self.tbl_stats is not None)
Howard Persh680b92a2012-03-31 13:34:35 -0700890
rootf6af1672012-04-06 09:46:29 -0700891 def flow_stats_get(self):
892 request = message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -0700893 query_match = ofp.ofp_match()
894 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -0700895 request.match = query_match
896 request.table_id = 0xff
897 request.out_port = ofp.OFPP_NONE;
898 (self.flow_stats, pkt) = self.controller.transact(request, timeout=2)
899 return (self.flow_stats is not None)
Howard Persh680b92a2012-03-31 13:34:35 -0700900
rootf6af1672012-04-06 09:46:29 -0700901 def flow_add(self, flow_cfg, overlapf = False):
Howard Persh680b92a2012-03-31 13:34:35 -0700902 flow_mod_msg = message.flow_mod()
903 flow_mod_msg.command = ofp.OFPFC_ADD
904 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -0700905 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -0700906 if overlapf:
907 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -0700908 if flow_cfg.send_rem:
909 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
910 return (self.controller.message_send(flow_mod_msg) != -1)
Howard Persh680b92a2012-03-31 13:34:35 -0700911
rootf6af1672012-04-06 09:46:29 -0700912 def flow_mod(self, flow_cfg, strictf):
Howard Persh680b92a2012-03-31 13:34:35 -0700913 flow_mod_msg = message.flow_mod()
rootf6af1672012-04-06 09:46:29 -0700914 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -0700915 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -0700916 flow_cfg.to_flow_mod_msg(flow_mod_msg)
917 return (self.controller.message_send(flow_mod_msg) != -1)
918
919 def flow_del(self, flow_cfg, strictf):
920 flow_mod_msg = message.flow_mod()
921 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf else ofp.OFPFC_DELETE
922 flow_mod_msg.buffer_id = 0xffffffff
923 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -0700924 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -0700925 flow_cfg.to_flow_mod_msg(flow_mod_msg)
926 return (self.controller.message_send(flow_mod_msg) != -1)
927
928 def barrier(self):
929 barrier = message.barrier_request()
930 (resp, pkt) = self.controller.transact(barrier, 5)
931 return (resp is not None)
932
933 def errors_verify(self, num, type = 0, code = 0):
934 pa_logger.debug("Expecting %d error messages" % (num))
935 if num > 0:
936 pa_logger.debug("with type=%d code=%d" % (type, code))
937 result = True
938 n = 0
939 while True:
940 (errmsg, pkt) = self.controller.poll(ofp.OFPT_ERROR, 1)
941 if errmsg is None:
942 break
943 pa_logger.debug("Got error message, type=%d, code=%d" \
944 % (errmsg.type, errmsg.code) \
Howard Persh680b92a2012-03-31 13:34:35 -0700945 )
rootf6af1672012-04-06 09:46:29 -0700946 if num == 0 or errmsg.type != type or errmsg.code != code:
947 pa_logger.debug("Unexpected error message")
948 result = False
949 n = n + 1
950 if n != num:
951 pa_logger.error("Received %d error messages" % (n))
952 result = False
953 return result
954
955 def flow_tbl_verify(self):
956 result = True
957
958 # Verify flow count in switch
959 pa_logger.debug("Reading table stats")
960 pa_logger.debug("Expecting %d flows" % (self.flow_tbl.count()))
961 if not self.tbl_stats_get():
962 pa_logger.error("Get table stats failed")
963 return False
964 n = 0
965 for ts in self.tbl_stats.stats:
966 n = n + ts.active_count
967 pa_logger.debug("Table stats reported %d active flows" \
968 % (n) \
969 )
970 if n != self.flow_tbl.count():
971 pa_logger.error("Incorrect number of active flows reported")
972 result = False
973
974 # Read flows from switch
975 pa_logger.debug("Retrieving flows from switch")
976 pa_logger.debug("Expecting %d flows" % (self.flow_tbl.count()))
977 if not self.flow_stats_get():
978 pa_logger.error("Get flow stats failed")
979 return False
980 pa_logger.debug("Retrieved %d flows" % (len(self.flow_stats.stats)))
981
982 # Verify flows returned by switch
983
984 if len(self.flow_stats.stats) != self.flow_tbl.count():
985 pa_logger.error("Switch reported incorrect number of flows")
986 result = False
987
988 pa_logger.debug("Verifying received flows")
989 for fc in self.flow_tbl.values():
990 fc.matched = False
991 for fs in self.flow_stats.stats:
992 flow_in = Flow_Cfg()
993 flow_in.from_flow_stat(fs)
994 pa_logger.debug("Received flow:")
995 pa_logger.debug(str(flow_in))
996 fc = self.flow_tbl.find(flow_in)
997 if fc is None:
998 pa_logger.error("does not match any defined flow")
999 result = False
1000 elif fc.matched:
1001 pa_logger.error("re-matches defined flow:")
1002 pa_logger.debug(str(fc))
1003 result = False
1004 else:
1005 pa_logger.debug("matched")
1006 if not flow_in == fc:
1007 pa_logger.error("Non-key portions of flow do not match")
1008 result = False
1009 fc.matched = True
1010 for fc in self.flow_tbl.values():
1011 if not fc.matched:
1012 pa_logger.error("Defined flow:")
1013 pa_logger.error(str(fc))
1014 pa_logger.error("was not returned by switch")
1015 result = False
1016
1017 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001018
1019
rootf6af1672012-04-06 09:46:29 -07001020class Flow_Add_5(basic.SimpleProtocol):
1021 """
1022 Test FLOW_ADD_5 from draft top-half test plan
1023
1024 INPUTS
1025 num_flows - Number of flows to generate
1026 """
Howard Persh680b92a2012-03-31 13:34:35 -07001027
rootf6af1672012-04-06 09:46:29 -07001028 def runTest(self):
1029 pa_logger.debug("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001030
rootf6af1672012-04-06 09:46:29 -07001031 num_flows = test_param_get(pa_config, "num_flows", 100)
1032
Howard Pershc7963582012-03-29 10:02:59 -07001033 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001034
1035 pa_logger.debug("Deleting all flows from switch")
Howard Pershc7963582012-03-29 10:02:59 -07001036 rc = delete_all_flows(self.controller, pa_logger)
1037 self.assertEqual(rc, 0, "Failed to delete all flows")
1038
rootf6af1672012-04-06 09:46:29 -07001039 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001040
rootf6af1672012-04-06 09:46:29 -07001041 pa_logger.debug("Getting switch capabilities")
1042 sw = Switch()
1043 sw.controller = self.controller
1044 self.assertTrue(sw.features_get(), "Get switch features failed")
1045 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
Howard Pershc7963582012-03-29 10:02:59 -07001046
rootf6af1672012-04-06 09:46:29 -07001047 if num_flows == 0:
1048 # Number of flows requested was 0
1049 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001050
rootf6af1672012-04-06 09:46:29 -07001051 for ts in sw.tbl_stats.stats:
1052 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001053
rootf6af1672012-04-06 09:46:29 -07001054 pa_logger.debug("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001055
1056 # Dream up some flow information, i.e. space to chose from for
1057 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001058
rootf6af1672012-04-06 09:46:29 -07001059 fi = Flow_Info()
1060 fi.rand(2 * int(math.log(num_flows)))
Howard Pershc7963582012-03-29 10:02:59 -07001061
rootf6af1672012-04-06 09:46:29 -07001062 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001063
rootf6af1672012-04-06 09:46:29 -07001064 ft = Flow_Tbl()
1065 ft.rand(sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001066
rootf6af1672012-04-06 09:46:29 -07001067 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001068
rootf6af1672012-04-06 09:46:29 -07001069 pa_logger.debug("Sending flow adds to switch")
1070 for fc in ft.values(): # Randomizes order of sending
1071 pa_logger.debug("Adding flow:")
1072 pa_logger.debug(str(fc));
1073 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001074
rootf6af1672012-04-06 09:46:29 -07001075 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001076
rootf6af1672012-04-06 09:46:29 -07001077 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001078
rootf6af1672012-04-06 09:46:29 -07001079 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001080
rootf6af1672012-04-06 09:46:29 -07001081 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001082
rootf6af1672012-04-06 09:46:29 -07001083 if not sw.errors_verify(0):
1084 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001085
rootf6af1672012-04-06 09:46:29 -07001086 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001087
rootf6af1672012-04-06 09:46:29 -07001088 sw.flow_tbl = ft
1089 if not sw.flow_tbl_verify():
1090 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001091
rootf6af1672012-04-06 09:46:29 -07001092 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
1093 pa_logger.debug("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001094
Howard Pershc7963582012-03-29 10:02:59 -07001095
rootf6af1672012-04-06 09:46:29 -07001096class Flow_Add_5_1(basic.SimpleProtocol):
1097 """
1098 Test FLOW_ADD_5.1 from draft top-half test plan
1099
1100 INPUTS
1101 None
1102 """
1103
1104 def runTest(self):
1105 pa_logger.debug("Flow_Add_5_1 TEST BEGIN")
1106
1107 num_flows = test_param_get(pa_config, "num_flows", 100)
1108
1109 # Clear all flows from switch
1110
1111 pa_logger.debug("Deleting all flows from switch")
1112 rc = delete_all_flows(self.controller, pa_logger)
1113 self.assertEqual(rc, 0, "Failed to delete all flows")
1114
1115 # Get switch capabilites
1116
1117 pa_logger.debug("Getting switch capabilities")
1118 sw = Switch()
1119 sw.controller = self.controller
1120 self.assertTrue(sw.features_get(), "Get switch features failed")
1121 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1122
1123 # Dream up some flow information, i.e. space to chose from for
1124 # random flow parameter generation
1125
1126 fi = Flow_Info()
1127 fi.rand(10)
1128
1129 # Dream up a flow config that will be canonicalized by the switch
1130
1131 while True:
1132 fc = Flow_Cfg()
1133 fc.rand(fi, \
1134 sw.tbl_stats.stats[0].wildcards, \
1135 sw.sw_features.actions, \
1136 sw.valid_ports \
1137 )
1138 fcc = fc.canonical()
1139 if fcc != fc:
1140 break
1141
1142 ft = Flow_Tbl()
1143 ft.insert(fcc)
1144
1145 # Send it to the switch
1146
1147 pa_logger.debug("Sending flow add to switch:")
1148 pa_logger.debug(str(fc))
1149 pa_logger.debug("should be canonicalized as:")
1150 pa_logger.debug(str(fcc))
1151 fc.send_rem = False
1152 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1153
1154 # Do barrier, to make sure all flows are in
1155
1156 self.assertTrue(sw.barrier(), "Barrier failed")
1157
1158 result = True
1159
1160 # Check for any error messages
1161
1162 if not sw.errors_verify(0):
1163 result = False
1164
1165 # Verify flow table
1166
1167 sw.flow_tbl = ft
1168 if not sw.flow_tbl_verify():
1169 result = False
1170
1171 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
1172 pa_logger.debug("Flow_Add_5_1 TEST PASSED")
1173
1174
1175# Disable this test by default, since the flow capacity reported by OVS is bogus.
1176test_prio["Flow_Add_6"] = -1
1177
1178class Flow_Add_6(basic.SimpleProtocol):
1179 """
1180 Test FLOW_ADD_6 from draft top-half test plan
1181
1182 INPUTS
1183 num_flows - Number of flows to generate
1184 """
Howard Pershc7963582012-03-29 10:02:59 -07001185
1186 def runTest(self):
rootf6af1672012-04-06 09:46:29 -07001187 pa_logger.debug("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001188
rootf6af1672012-04-06 09:46:29 -07001189 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001190
rootf6af1672012-04-06 09:46:29 -07001191 pa_logger.debug("Deleting all flows from switch")
1192 rc = delete_all_flows(self.controller, pa_logger)
1193 self.assertEqual(rc, 0, "Failed to delete all flows")
1194
1195 # Get switch capabilites
1196
1197 pa_logger.debug("Getting switch capabilities")
1198 sw = Switch()
1199 sw.controller = self.controller
1200 self.assertTrue(sw.features_get(), "Get switch features failed")
1201 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1202
1203 for ts in sw.tbl_stats.stats:
1204 num_flows = num_flows + ts.max_entries
1205
1206 pa_logger.debug("Switch capacity is %d flows" % (num_flows))
1207 pa_logger.debug("Generating %d flows" % (num_flows))
1208
1209 # Dream up some flow information, i.e. space to chose from for
1210 # random flow parameter generation
1211
1212 fi = Flow_Info()
1213 fi.rand(2 * int(math.log(num_flows)))
1214
1215 # Create a flow table, to switch's capacity
1216
1217 ft = Flow_Tbl()
1218 ft.rand(sw, fi, num_flows)
1219
1220 # Send flow table to switch
1221
1222 pa_logger.debug("Sending flow adds to switch")
1223 for fc in ft.values(): # Randomizes order of sending
1224 pa_logger.debug("Adding flow:")
1225 pa_logger.debug(str(fc));
1226 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1227
1228 # Do barrier, to make sure all flows are in
1229
1230 self.assertTrue(sw.barrier(), "Barrier failed")
1231
1232 result = True
1233
1234 # Check for any error messages
1235
1236 if not sw.errors_verify(0):
1237 result = False
1238
1239 # Dream up one more flow
1240
1241 pa_logger.debug("Creating one more flow")
1242 while True:
1243 fc = Flow_Cfg()
1244 fc.rand(fi, \
1245 sw.tbl_stats.stats[tbl].wildcards, \
1246 sw.sw_features.actions, \
1247 sw.valid_ports \
1248 )
1249 fc = fc.canonical()
1250 if ft.find(fc):
1251 continue
1252
1253 # Send one-more flow
1254
1255 fc.send_rem = False
1256 pa_logger.debug("Sending flow add switch")
1257 pa_logger.debug(str(fc));
1258 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1259
1260 # Do barrier, to make sure all flows are in
1261
1262 self.assertTrue(sw.barrier(), "Barrier failed")
1263
1264 # Check for expected error message
1265
1266 if not sw.errors_verify(1, \
1267 ofp.OFPET_FLOW_MOD_FAILED, \
1268 ofp.OFPFMFC_ALL_TABLES_FULL \
1269 ):
1270 result = False
1271
1272 # Verify flow table
1273
1274 sw.flow_tbl = ft
1275 if not sw.flow_tbl_verify():
1276 result = False
1277
1278 self.assertTrue(result, "Flow_add_6 TEST FAILED")
1279 pa_logger.debug("Flow_add_6 TEST PASSED")
1280
1281
1282class Flow_Add_7(basic.SimpleProtocol):
1283 """
1284 Test FLOW_ADD_7 from draft top-half test plan
1285
1286 INPUTS
1287 None
1288 """
1289
1290 def runTest(self):
1291 pa_logger.debug("Flow_Add_7 TEST BEGIN")
1292
1293 # Clear all flows from switch
1294
1295 pa_logger.debug("Deleting all flows from switch")
1296 rc = delete_all_flows(self.controller, pa_logger)
1297 self.assertEqual(rc, 0, "Failed to delete all flows")
1298
1299 # Get switch capabilites
1300
1301 pa_logger.debug("Getting switch capabilities")
1302 sw = Switch()
1303 sw.controller = self.controller
1304 self.assertTrue(sw.features_get(), "Get switch features failed")
1305 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1306
1307 # Dream up some flow information, i.e. space to chose from for
1308 # random flow parameter generation
1309
1310 fi = Flow_Info()
1311 fi.rand(10)
1312
1313 # Dream up a flow config
1314
1315 fc = Flow_Cfg()
1316 fc.rand(fi, \
1317 sw.tbl_stats.stats[0].wildcards, \
1318 sw.sw_features.actions, \
1319 sw.valid_ports \
1320 )
1321 fc = fc.canonical()
1322
1323 # Send it to the switch
1324
1325 pa_logger.debug("Sending flow add to switch:")
1326 pa_logger.debug(str(fc))
1327 ft = Flow_Tbl()
1328 fc.send_rem = False
1329 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1330 ft.insert(fc)
1331
1332 # Dream up some different actions, with the same flow key
1333
1334 fc2 = copy.deepcopy(fc)
1335 while True:
1336 fc2.rand_mod(fi, \
1337 sw.sw_features.actions, \
1338 sw.valid_ports \
1339 )
1340 if fc2 != fc:
1341 break
1342
1343 # Send that to the switch
1344
1345 pa_logger.debug("Sending flow add to switch:")
1346 pa_logger.debug(str(fc2))
1347 fc2.send_rem = False
1348 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
1349 ft.insert(fc2)
1350
1351 # Do barrier, to make sure all flows are in
1352
1353 self.assertTrue(sw.barrier(), "Barrier failed")
1354
1355 result = True
1356
1357 # Check for any error messages
1358
1359 if not sw.errors_verify(0):
1360 result = False
1361
1362 # Verify flow table
1363
1364 sw.flow_tbl = ft
1365 if not sw.flow_tbl_verify():
1366 result = False
1367
1368 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
1369 pa_logger.debug("Flow_Add_7 TEST PASSED")
1370
1371
1372class Flow_Add_8(basic.SimpleProtocol):
1373 """
1374 Test FLOW_ADD_8 from draft top-half test plan
1375
1376 INPUTS
1377 None
1378 """
1379
1380 def runTest(self):
1381 pa_logger.debug("Flow_Add_8 TEST BEGIN")
1382
1383 # Clear all flows from switch
1384
1385 pa_logger.debug("Deleting all flows from switch")
1386 rc = delete_all_flows(self.controller, pa_logger)
1387 self.assertEqual(rc, 0, "Failed to delete all flows")
1388
1389 # Get switch capabilites
1390
1391 pa_logger.debug("Getting switch capabilities")
1392 sw = Switch()
1393 sw.controller = self.controller
1394 self.assertTrue(sw.features_get(), "Get switch features failed")
1395 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1396
1397 # Dream up some flow information, i.e. space to chose from for
1398 # random flow parameter generation
1399
1400 fi = Flow_Info()
1401 fi.rand(10)
1402
1403 # Dream up a flow config, with at least 1 qualifier specified
1404
1405 fc = Flow_Cfg()
1406 while True:
1407 fc.rand(fi, \
1408 sw.tbl_stats.stats[0].wildcards, \
1409 sw.sw_features.actions, \
1410 sw.valid_ports \
1411 )
1412 fc = fc.canonical()
1413 if fc.match.wildcards != ofp.OFPFW_ALL:
1414 break
1415
1416 # Send it to the switch
1417
1418 pa_logger.debug("Sending flow add to switch:")
1419 pa_logger.debug(str(fc))
1420 ft = Flow_Tbl()
1421 fc.send_rem = False
1422 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1423 ft.insert(fc)
1424
1425 # Wildcard out one qualifier that was specified, to create an
1426 # overlapping flow
1427
1428 fc2 = copy.deepcopy(fc)
1429 for wi in shuffle(range(len(all_wildcards_list))):
1430 w = all_wildcards_list[wi]
1431 if (fc2.match.wildcards & w) == 0:
1432 break
1433 if w == ofp.OFPFW_NW_SRC_MASK:
1434 w = ofp.OFPFW_NW_SRC_ALL
1435 wn = "OFPFW_NW_SRC"
1436 elif w == ofp.OFPFW_NW_DST_MASK:
1437 w = ofp.OFPFW_NW_DST_ALL
1438 wn = "OFPFW_NW_DST"
1439 else:
1440 wn = all_wildcard_names[w]
1441 pa_logger.debug("Wildcarding out %s" % (wn))
1442 fc2.match.wildcards = fc2.match.wildcards | w
1443
1444 # Send that to the switch, with overlap checking
1445
1446 pa_logger.debug("Sending flow add to switch:")
1447 pa_logger.debug(str(fc2))
1448 fc2.send_rem = False
1449 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
1450
1451 # Do barrier, to make sure all flows are in
1452 self.assertTrue(sw.barrier(), "Barrier failed")
1453
1454 result = True
1455
1456 # Check for expected error message
1457
1458 if not sw.errors_verify(1, \
1459 ofp.OFPET_FLOW_MOD_FAILED, \
1460 ofp.OFPFMFC_OVERLAP \
1461 ):
1462 result = False
1463
1464 # Verify flow table
1465
1466 sw.flow_tbl = ft
1467 if not sw.flow_tbl_verify():
1468 result = False
1469
1470 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
1471 pa_logger.debug("Flow_Add_8 TEST PASSED")
1472
1473
1474class Flow_Mod_1(basic.SimpleProtocol):
1475 """
1476 Test FLOW_MOD_1 from draft top-half test plan
1477
1478 INPUTS
1479 None
1480 """
1481
1482 def runTest(self):
1483 pa_logger.debug("Flow_Mod_1 TEST BEGIN")
1484
1485 # Clear all flows from switch
1486
1487 pa_logger.debug("Deleting all flows from switch")
1488 rc = delete_all_flows(self.controller, pa_logger)
1489 self.assertEqual(rc, 0, "Failed to delete all flows")
1490
1491 # Get switch capabilites
1492
1493 pa_logger.debug("Getting switch capabilities")
1494 sw = Switch()
1495 sw.controller = self.controller
1496 self.assertTrue(sw.features_get(), "Get switch features failed")
1497 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1498
1499 # Dream up some flow information, i.e. space to chose from for
1500 # random flow parameter generation
1501
1502 fi = Flow_Info()
1503 fi.rand(10)
1504
1505 # Dream up a flow config
1506
1507 fc = Flow_Cfg()
1508 fc.rand(fi, \
1509 sw.tbl_stats.stats[0].wildcards, \
1510 sw.sw_features.actions, \
1511 sw.valid_ports \
1512 )
1513 fc = fc.canonical()
1514
1515 # Send it to the switch
1516
1517 pa_logger.debug("Sending flow add to switch:")
1518 pa_logger.debug(str(fc))
1519 ft = Flow_Tbl()
1520 fc.send_rem = False
1521 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1522 ft.insert(fc)
1523
1524 # Dream up some different actions, with the same flow key
1525
1526 fc2 = copy.deepcopy(fc)
1527 while True:
1528 fc2.rand_mod(fi, \
1529 sw.sw_features.actions, \
1530 sw.valid_ports \
1531 )
1532 if fc2 != fc:
1533 break
1534
1535 # Send that to the switch
1536
1537 pa_logger.debug("Sending strict flow mod to switch:")
1538 pa_logger.debug(str(fc2))
1539 fc2.send_rem = False
1540 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
1541 ft.insert(fc2)
1542
1543 # Do barrier, to make sure all flows are in
1544
1545 self.assertTrue(sw.barrier(), "Barrier failed")
1546
1547 result = True
1548
1549 # Check for any error messages
1550
1551 if not sw.errors_verify(0):
1552 result = False
1553
1554 # Verify flow table
1555
1556 sw.flow_tbl = ft
1557 if not sw.flow_tbl_verify():
1558 result = False
1559
1560 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
1561 pa_logger.debug("Flow_Mod_1 TEST PASSED")
1562
1563
1564class Flow_Mod_2(basic.SimpleProtocol):
1565 """
1566 Test FLOW_MOD_2 from draft top-half test plan
1567
1568 INPUTS
1569 None
1570 """
1571
1572 def runTest(self):
1573 pa_logger.debug("Flow_Mod_2 TEST BEGIN")
1574
1575 num_flows = test_param_get(pa_config, "num_flows", 100)
1576
1577 # Clear all flows from switch
1578
1579 pa_logger.debug("Deleting all flows from switch")
1580 rc = delete_all_flows(self.controller, pa_logger)
1581 self.assertEqual(rc, 0, "Failed to delete all flows")
1582
1583 # Get switch capabilites
1584
1585 pa_logger.debug("Getting switch capabilities")
1586 sw = Switch()
1587 sw.controller = self.controller
1588 self.assertTrue(sw.features_get(), "Get switch features failed")
1589 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1590
1591 # Dream up some flow information, i.e. space to chose from for
1592 # random flow parameter generation
1593
1594 fi = Flow_Info()
1595 fi.rand(int(math.log(num_flows)) / 2) # Shrunk, to increase chance of meta-matches
1596
1597 # Dream up some flows
1598
1599 ft = Flow_Tbl()
1600 ft.rand(sw, fi, num_flows)
1601
1602 # Send flow table to switch
1603
1604 pa_logger.debug("Sending flow adds to switch")
1605 for fc in ft.values(): # Randomizes order of sending
1606 pa_logger.debug("Adding flow:")
1607 pa_logger.debug(str(fc));
1608 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1609
1610 # Do barrier, to make sure all flows are in
1611
1612 self.assertTrue(sw.barrier(), "Barrier failed")
1613
1614 result = True
1615
1616 # Check for any error messages
1617
1618 if not sw.errors_verify(0):
1619 result = False
1620
1621 # Verify flow table
1622
1623 sw.flow_tbl = ft
1624 if not sw.flow_tbl_verify():
1625 result = False
1626
1627 # Pick a random flow as a basis
1628
1629 mfc = copy.deepcopy(ft.values()[0])
1630 mfc.rand_mod(fi, sw.sw_features.actions, sw.valid_ports)
1631
1632 # Repeatedly wildcard qualifiers
1633
1634 for wi in shuffle(range(len(all_wildcards_list))):
1635 w = all_wildcards_list[wi]
1636 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
1637 n = wildcard_get(mfc.match.wildcards, w)
1638 if n < 32:
1639 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, random.randint(n + 1, 32))
1640 else:
1641 continue
1642 else:
1643 if wildcard_get(mfc.match.wildcards, w) == 0:
1644 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
1645 else:
1646 continue
1647 mfc = mfc.canonical()
1648
1649 # Count the number of flows that would be modified
1650
1651 n = 0
1652 for fc in ft.values():
1653 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
1654 n = n + 1
1655
1656 # If more than 1, we found our loose delete flow spec
1657 if n > 1:
1658 break
1659
1660 pa_logger.debug("Modifying %d flows" % (n))
1661 pa_logger.debug("Sending flow mod to switch:")
1662 pa_logger.debug(str(mfc))
1663 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
1664
1665 # Do barrier, to make sure all flows are in
1666 self.assertTrue(sw.barrier(), "Barrier failed")
1667
1668 # Check for error message
1669
1670 if not sw.errors_verify(0):
1671 result = False
1672
1673 # Apply flow mod to local flow table
1674
1675 for fc in ft.values():
1676 if mfc.overlaps(fc, True):
1677 fc.idle_timeout = mfc.idle_timeout
1678 fc.hard_timeout = mfc.hard_timeout
1679 fc.actions = mfc.actions
1680
1681 # Verify flow table
1682
1683 sw.flow_tbl = ft
1684 if not sw.flow_tbl_verify():
1685 result = False
1686
1687 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
1688 pa_logger.debug("Flow_Mod_2 TEST PASSED")
1689
1690
1691class Flow_Mod_3(basic.SimpleProtocol):
1692 """
1693 Test FLOW_MOD_3 from draft top-half test plan
1694
1695 INPUTS
1696 None
1697 """
1698
1699 def runTest(self):
1700 pa_logger.debug("Flow_Mod_3 TEST BEGIN")
1701
1702 # Clear all flows from switch
1703
1704 pa_logger.debug("Deleting all flows from switch")
1705 rc = delete_all_flows(self.controller, pa_logger)
1706 self.assertEqual(rc, 0, "Failed to delete all flows")
1707
1708 # Get switch capabilites
1709
1710 pa_logger.debug("Getting switch capabilities")
1711 sw = Switch()
1712 sw.controller = self.controller
1713 self.assertTrue(sw.features_get(), "Get switch features failed")
1714 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1715
1716 # Dream up some flow information, i.e. space to chose from for
1717 # random flow parameter generation
1718
1719 fi = Flow_Info()
1720 fi.rand(10)
1721
1722 # Dream up a flow config
1723
1724 fc = Flow_Cfg()
1725 fc.rand(fi, \
1726 sw.tbl_stats.stats[0].wildcards, \
1727 sw.sw_features.actions, \
1728 sw.valid_ports \
1729 )
1730 fc = fc.canonical()
1731
1732 # Send it to the switch
1733
1734 pa_logger.debug("Sending flow mod to switch:")
1735 pa_logger.debug(str(fc))
1736 ft = Flow_Tbl()
1737 fc.send_rem = False
1738 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
1739 ft.insert(fc)
1740
1741 # Do barrier, to make sure all flows are in
1742
1743 self.assertTrue(sw.barrier(), "Barrier failed")
1744
1745 result = True
1746
1747 # Check for any error messages
1748
1749 if not sw.errors_verify(0):
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_Mod_3 TEST FAILED")
1759 pa_logger.debug("Flow_Mod_3 TEST PASSED")
1760
1761
1762class Flow_Del_1(basic.SimpleProtocol):
1763 """
1764 Test FLOW_DEL_1 from draft top-half test plan
1765
1766 INPUTS
1767 None
1768 """
1769
1770 def runTest(self):
1771 pa_logger.debug("Flow_Del_1 TEST BEGIN")
1772
1773 # Clear all flows from switch
1774
1775 pa_logger.debug("Deleting all flows from switch")
1776 rc = delete_all_flows(self.controller, pa_logger)
1777 self.assertEqual(rc, 0, "Failed to delete all flows")
1778
1779 # Get switch capabilites
1780
1781 pa_logger.debug("Getting switch capabilities")
1782 sw = Switch()
1783 sw.controller = self.controller
1784 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
1805 pa_logger.debug("Sending flow add to switch:")
1806 pa_logger.debug(str(fc))
1807 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 # Delete strictly
1824
1825 pa_logger.debug("Sending strict flow del to switch:")
1826 pa_logger.debug(str(fc2))
1827 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
1828 ft.delete(fc)
1829
1830 # Do barrier, to make sure all flows are in
1831
1832 self.assertTrue(sw.barrier(), "Barrier failed")
1833
1834 result = True
1835
1836 # Check for any error messages
1837
1838 if not sw.errors_verify(0):
1839 result = False
1840
1841 # Verify flow table
1842
1843 sw.flow_tbl = ft
1844 if not sw.flow_tbl_verify():
1845 result = False
1846
1847 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
1848 pa_logger.debug("Flow_Del_1 TEST PASSED")
1849
1850
1851class Flow_Del_2(basic.SimpleProtocol):
1852 """
1853 Test FLOW_DEL_2 from draft top-half test plan
1854
1855 INPUTS
1856 None
1857 """
1858
1859 def runTest(self):
1860 pa_logger.debug("Flow_Del_2 TEST BEGIN")
1861
1862 num_flows = test_param_get(pa_config, "num_flows", 100)
1863
1864 # Clear all flows from switch
1865
1866 pa_logger.debug("Deleting all flows from switch")
1867 rc = delete_all_flows(self.controller, pa_logger)
1868 self.assertEqual(rc, 0, "Failed to delete all flows")
1869
1870 # Get switch capabilites
1871
1872 pa_logger.debug("Getting switch capabilities")
1873 sw = Switch()
1874 sw.controller = self.controller
1875 self.assertTrue(sw.features_get(), "Get switch features failed")
1876 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1877
1878 # Dream up some flow information, i.e. space to chose from for
1879 # random flow parameter generation
1880
1881 fi = Flow_Info()
1882 fi.rand(int(math.log(num_flows)) / 2) # Shrunk, to increase chance of meta-matches
1883
1884 # Dream up some flows
1885
1886 ft = Flow_Tbl()
1887 ft.rand(sw, fi, num_flows)
1888
1889 # Send flow table to switch
1890
1891 pa_logger.debug("Sending flow adds to switch")
1892 for fc in ft.values(): # Randomizes order of sending
1893 pa_logger.debug("Adding flow:")
1894 pa_logger.debug(str(fc));
1895 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1896
1897 # Do barrier, to make sure all flows are in
1898
1899 self.assertTrue(sw.barrier(), "Barrier failed")
1900
1901 result = True
1902
1903 # Check for any error messages
1904
1905 if not sw.errors_verify(0):
1906 result = False
1907
1908 # Verify flow table
1909
1910 sw.flow_tbl = ft
1911 if not sw.flow_tbl_verify():
1912 result = False
1913
1914 # Pick a random flow as a basis
1915
1916 dfc = copy.deepcopy(ft.values()[0])
1917 dfc.rand_mod(fi, sw.sw_features.actions, sw.valid_ports)
1918
1919 # Repeatedly wildcard qualifiers
1920
1921 for wi in shuffle(range(len(all_wildcards_list))):
1922 w = all_wildcards_list[wi]
1923 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
1924 n = wildcard_get(dfc.match.wildcards, w)
1925 if n < 32:
1926 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, random.randint(n + 1, 32))
1927 else:
1928 continue
1929 else:
1930 if wildcard_get(dfc.match.wildcards, w) == 0:
1931 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
1932 else:
1933 continue
1934 dfc = dfc.canonical()
1935
1936 # Count the number of flows that would be deleted
1937
1938 n = 0
1939 for fc in ft.values():
1940 if dfc.overlaps(fc, True):
1941 n = n + 1
1942
1943 # If more than 1, we found our loose delete flow spec
1944 if n > 1:
1945 break
1946
1947 pa_logger.debug("Deleting %d flows" % (n))
1948 pa_logger.debug("Sending flow del to switch:")
1949 pa_logger.debug(str(dfc))
1950 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
1951
1952 # Do barrier, to make sure all flows are in
1953 self.assertTrue(sw.barrier(), "Barrier failed")
1954
1955 # Check for error message
1956
1957 if not sw.errors_verify(0):
1958 result = False
1959
1960 # Apply flow mod to local flow table
1961
1962 for fc in ft.values():
1963 if dfc.overlaps(fc, True):
1964 ft.delete(fc)
1965
1966 # Verify flow table
1967
1968 sw.flow_tbl = ft
1969 if not sw.flow_tbl_verify():
1970 result = False
1971
1972 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
1973 pa_logger.debug("Flow_Del_2 TEST PASSED")
1974
1975
1976# Disable this test by default, there seems to be an issue with error message reporting
1977test_prio["Flow_Del_4"] = -1
1978
1979class Flow_Del_4(basic.SimpleProtocol):
1980 """
1981 Test FLOW_DEL_4 from draft top-half test plan
1982
1983 INPUTS
1984 None
1985 """
1986
1987 def runTest(self):
1988 pa_logger.debug("Flow_Del_4 TEST BEGIN")
1989
1990 # Clear all flows from switch
1991
1992 pa_logger.debug("Deleting all flows from switch")
1993 rc = delete_all_flows(self.controller, pa_logger)
1994 self.assertEqual(rc, 0, "Failed to delete all flows")
1995
1996 # Get switch capabilites
1997
1998 pa_logger.debug("Getting switch capabilities")
1999 sw = Switch()
2000 sw.controller = self.controller
2001 self.assertTrue(sw.features_get(), "Get switch features failed")
2002 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2003
2004 # Dream up some flow information, i.e. space to chose from for
2005 # random flow parameter generation
2006
2007 fi = Flow_Info()
2008 fi.rand(10)
2009
2010 # Dream up a flow config
2011
2012 fc = Flow_Cfg()
2013 fc.rand(fi, \
2014 sw.tbl_stats.stats[0].wildcards, \
2015 sw.sw_features.actions, \
2016 sw.valid_ports \
2017 )
2018 fc = fc.canonical()
2019
2020 # Send it to the switch. with "notify on removed"
2021
2022 pa_logger.debug("Sending flow add to switch:")
2023 pa_logger.debug(str(fc))
2024 ft = Flow_Tbl()
2025 fc.send_rem = True
2026 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2027 ft.insert(fc)
2028
2029 # Dream up some different actions, with the same flow key
2030
2031 fc2 = copy.deepcopy(fc)
2032 while True:
2033 fc2.rand_mod(fi, \
2034 sw.sw_features.actions, \
2035 sw.valid_ports \
2036 )
2037 if fc2 != fc:
2038 break
2039
2040 # Delete strictly
2041
2042 pa_logger.debug("Sending strict flow del to switch:")
2043 pa_logger.debug(str(fc2))
2044 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2045 ft.delete(fc)
2046
2047 # Do barrier, to make sure all flows are in
2048
2049 self.assertTrue(sw.barrier(), "Barrier failed")
2050
2051 result = True
2052
2053 # Check for expected "removed" message
2054
2055 if not sw.errors_verify(1, \
2056 ofp.OFPT_FLOW_REMOVED, \
2057 ofp.OFPRR_DELETE \
2058 ):
2059 result = False
2060
2061 # Verify flow table
2062
2063 sw.flow_tbl = ft
2064 if not sw.flow_tbl_verify():
2065 result = False
2066
2067 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
2068 pa_logger.debug("Flow_Del_4 TEST PASSED")
2069