blob: 2d5c7b56a8b457b8e7c32789fbcc7282ee69bb77 [file] [log] [blame]
Howard Pershc7963582012-03-29 10:02:59 -07001"""
2Flow query test case.
3
Howard Persh3340d452012-04-06 16:45:21 -07004Attempts to fill switch to capacity with randomized flows, and ensure that
5they all are read back correctly.
Howard Pershc7963582012-03-29 10:02:59 -07006"""
Howard Persh07d99e62012-04-09 15:26:57 -07007
8# COMMON TEST PARAMETERS
9#
10# Name: wildcards
11# Type: number
12# Description:
13# Overrides bitmap of supported wildcards reported by switch
14# Default: none
15#
Howard Pershc1199d52012-04-11 14:21:32 -070016# Name: wildcards_force
17# Type: number
18# Description:
19# Bitmap of wildcards to always be set
20# Default: none
21#
Howard Persh07d99e62012-04-09 15:26:57 -070022# Name: actions
23# Type: number
24# Description:
25# Overrides bitmap of supported actions reported by switch
26# Default: none
27#
Howard Pershc1199d52012-04-11 14:21:32 -070028# Name: actions_force
29# Type: number
30# Description:
31# Bitmap of actions to always be used
32# Default: none
33#
34# Name: ports
35# Type: list of OF port numbers
36# Description:
37# Override list of OF port numbers reported by switch
38# Default: none
39#
Howard Persh8d21c1f2012-04-20 15:57:29 -070040# Name: queues
41# Type: list of OF (port-number, queue-id) pairs
42# Description:
43# Override list of OF (port-number, queue-id) pairs returned by switch
44# Default: none
45#
Howard Pershb10a47a2012-08-21 13:54:47 -070046# Name: vlans
47# Type: list of VLAN ids
48# Description:
49# Override VLAN ids used in tests to given list
50# Default: []
51#
Howard Persh07d99e62012-04-09 15:26:57 -070052# Name: conservative_ordered_actions
53# Type: boolean (True or False)
54# Description:
55# Compare flow actions lists as unordered
56# Default: True
57
58
Howard Persh680b92a2012-03-31 13:34:35 -070059import math
Howard Pershc7963582012-03-29 10:02:59 -070060
61import logging
62
63import unittest
64import random
Howard Persh9cab4822012-09-11 17:08:40 -070065import time
Rich Lane3c7cf7f2013-01-11 18:04:56 -080066import copy
Howard Pershc7963582012-03-29 10:02:59 -070067
Rich Lane477f4812012-10-04 22:49:00 -070068from oftest import config
Howard Pershc7963582012-03-29 10:02:59 -070069import oftest.controller as controller
Rich Laned7b0ffa2013-03-08 15:53:42 -080070import ofp
Howard Pershc7963582012-03-29 10:02:59 -070071import oftest.dataplane as dataplane
Howard Pershc7963582012-03-29 10:02:59 -070072import oftest.parse as parse
73import pktact
Rich Laneb90a1c42012-10-05 09:16:05 -070074import oftest.base_tests as base_tests
Howard Pershc7963582012-03-29 10:02:59 -070075
Rich Laneda3b5ad2012-10-03 09:05:32 -070076from oftest.testutils import *
Howard Pershc7963582012-03-29 10:02:59 -070077from time import sleep
78
Howard Pershc7963582012-03-29 10:02:59 -070079
rootf6af1672012-04-06 09:46:29 -070080def flip_coin():
81 return random.randint(1, 100) <= 50
82
83
Howard Pershc7963582012-03-29 10:02:59 -070084def shuffle(list):
85 n = len(list)
86 lim = n * n
87 i = 0
88 while i < lim:
89 a = random.randint(0, n - 1)
90 b = random.randint(0, n - 1)
91 temp = list[a]
92 list[a] = list[b]
93 list[b] = temp
94 i = i + 1
95 return list
96
97
Howard Persh680b92a2012-03-31 13:34:35 -070098def rand_pick(list):
99 return list[random.randint(0, len(list) - 1)]
Howard Pershc7963582012-03-29 10:02:59 -0700100
Howard Persh680b92a2012-03-31 13:34:35 -0700101def rand_dl_addr():
102 return [random.randint(0, 255) & ~1,
103 random.randint(0, 255),
104 random.randint(0, 255),
105 random.randint(0, 255),
106 random.randint(0, 255),
107 random.randint(0, 255)
108 ]
Howard Pershc7963582012-03-29 10:02:59 -0700109
110def rand_nw_addr():
111 return random.randint(0, (1 << 32) - 1)
112
113
rootf6af1672012-04-06 09:46:29 -0700114class Flow_Info:
Howard Persh680b92a2012-03-31 13:34:35 -0700115 # Members:
116 # priorities - list of flow priorities
117 # dl_addrs - list of MAC addresses
118 # vlans - list of VLAN ids
119 # ethertypes - list of Ethertypes
120 # ip_addrs - list of IP addresses
121 # ip_tos - list of IP TOS values
122 # ip_protos - list of IP protocols
123 # l4_ports - list of L4 ports
124
125 def __init__(self):
126 priorities = []
127 dl_addrs = []
128 vlans = []
129 ethertypes = []
130 ip_addrs = []
131 ip_tos = []
132 ip_protos = []
133 l4_ports = []
134
135 def rand(self, n):
136 self.priorities = []
137 i = 0
138 while i < n:
139 self.priorities.append(random.randint(1, 65534))
140 i = i + 1
141
142 self.dl_addrs = []
143 i = 0
144 while i < n:
145 self.dl_addrs.append(rand_dl_addr())
146 i = i + 1
147
Rich Lane2014f9b2012-10-05 15:29:40 -0700148 if test_param_get("vlans", []) != []:
149 self.vlans = test_param_get("vlans", [])
Howard Pershb10a47a2012-08-21 13:54:47 -0700150
Rich Lane9a003812012-10-04 17:17:59 -0700151 logging.info("Overriding VLAN ids to:")
152 logging.info(self.vlans)
Howard Pershb10a47a2012-08-21 13:54:47 -0700153 else:
154 self.vlans = []
155 i = 0
156 while i < n:
157 self.vlans.append(random.randint(1, 4094))
158 i = i + 1
Howard Persh680b92a2012-03-31 13:34:35 -0700159
rootf6af1672012-04-06 09:46:29 -0700160 self.ethertypes = [0x0800, 0x0806]
Howard Persh680b92a2012-03-31 13:34:35 -0700161 i = 0
162 while i < n:
163 self.ethertypes.append(random.randint(0, (1 << 16) - 1))
164 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700165 self.ethertypes = shuffle(self.ethertypes)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700166
167 self.ip_addrs = []
168 i = 0
169 while i < n:
170 self.ip_addrs.append(rand_nw_addr())
171 i = i + 1
172
173 self.ip_tos = []
174 i = 0
175 while i < n:
176 self.ip_tos.append(random.randint(0, (1 << 8) - 1) & ~3)
177 i = i + 1
178
rootf6af1672012-04-06 09:46:29 -0700179 self.ip_protos = [1, 6, 17]
Howard Persh680b92a2012-03-31 13:34:35 -0700180 i = 0
181 while i < n:
182 self.ip_protos.append(random.randint(0, (1 << 8) - 1))
183 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700184 self.ip_protos = shuffle(self.ip_protos)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700185
186 self.l4_ports = []
187 i = 0
188 while i < n:
189 self.l4_ports.append(random.randint(0, (1 << 16) - 1))
190 i = i + 1
191
192 def rand_priority(self):
193 return rand_pick(self.priorities)
194
195 def rand_dl_addr(self):
196 return rand_pick(self.dl_addrs)
197
198 def rand_vlan(self):
199 return rand_pick(self.vlans)
200
201 def rand_ethertype(self):
202 return rand_pick(self.ethertypes)
203
204 def rand_ip_addr(self):
205 return rand_pick(self.ip_addrs)
206
207 def rand_ip_tos(self):
208 return rand_pick(self.ip_tos)
209
210 def rand_ip_proto(self):
211 return rand_pick(self.ip_protos)
212
213 def rand_l4_port(self):
214 return rand_pick(self.l4_ports)
215
216
Howard Pershc7963582012-03-29 10:02:59 -0700217# TBD - These don't belong here
218
Howard Persh680b92a2012-03-31 13:34:35 -0700219all_wildcards_list = [ofp.OFPFW_IN_PORT,
Howard Persh680b92a2012-03-31 13:34:35 -0700220 ofp.OFPFW_DL_DST,
rootf6af1672012-04-06 09:46:29 -0700221 ofp.OFPFW_DL_SRC,
222 ofp.OFPFW_DL_VLAN,
223 ofp.OFPFW_DL_VLAN_PCP,
Howard Persh680b92a2012-03-31 13:34:35 -0700224 ofp.OFPFW_DL_TYPE,
rootf6af1672012-04-06 09:46:29 -0700225 ofp.OFPFW_NW_TOS,
Howard Persh680b92a2012-03-31 13:34:35 -0700226 ofp.OFPFW_NW_PROTO,
Howard Persh680b92a2012-03-31 13:34:35 -0700227 ofp.OFPFW_NW_SRC_MASK,
228 ofp.OFPFW_NW_DST_MASK,
rootf6af1672012-04-06 09:46:29 -0700229 ofp.OFPFW_TP_SRC,
230 ofp.OFPFW_TP_DST
Howard Persh680b92a2012-03-31 13:34:35 -0700231 ]
Howard Pershc7963582012-03-29 10:02:59 -0700232
Howard Persh3340d452012-04-06 16:45:21 -0700233# TBD - Need this because there are duplicates in ofp.ofp_flow_wildcards_map
234# -- FIX
rootf6af1672012-04-06 09:46:29 -0700235all_wildcard_names = {
236 1 : 'OFPFW_IN_PORT',
237 2 : 'OFPFW_DL_VLAN',
238 4 : 'OFPFW_DL_SRC',
239 8 : 'OFPFW_DL_DST',
240 16 : 'OFPFW_DL_TYPE',
241 32 : 'OFPFW_NW_PROTO',
242 64 : 'OFPFW_TP_SRC',
243 128 : 'OFPFW_TP_DST',
244 1048576 : 'OFPFW_DL_VLAN_PCP',
245 2097152 : 'OFPFW_NW_TOS'
246}
247
rootf6af1672012-04-06 09:46:29 -0700248def wildcard_set(x, w, val):
249 result = x
250 if w == ofp.OFPFW_NW_SRC_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700251 result = (result & ~ofp.OFPFW_NW_SRC_MASK) \
252 | (val << ofp.OFPFW_NW_SRC_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700253 elif w == ofp.OFPFW_NW_DST_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700254 result = (result & ~ofp.OFPFW_NW_DST_MASK) \
255 | (val << ofp.OFPFW_NW_DST_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700256 elif val == 0:
257 result = result & ~w
258 else:
259 result = result | w
260 return result
261
262def wildcard_get(x, w):
263 if w == ofp.OFPFW_NW_SRC_MASK:
264 return (x & ofp.OFPFW_NW_SRC_MASK) >> ofp.OFPFW_NW_SRC_SHIFT
265 if w == ofp.OFPFW_NW_DST_MASK:
266 return (x & ofp.OFPFW_NW_DST_MASK) >> ofp.OFPFW_NW_DST_SHIFT
267 return 1 if (x & w) != 0 else 0
268
Howard Persh8d21c1f2012-04-20 15:57:29 -0700269def wildcards_to_str(wildcards):
270 result = "{"
271 sep = ""
272 for w in all_wildcards_list:
273 if (wildcards & w) == 0:
274 continue
275 if w == ofp.OFPFW_NW_SRC_MASK:
276 n = wildcard_get(wildcards, w)
277 if n > 0:
278 result = result + sep + ("OFPFW_NW_SRC(%d)" % (n))
279 elif w == ofp.OFPFW_NW_DST_MASK:
280 n = wildcard_get(wildcards, w)
281 if n > 0:
282 result = result + sep + ("OFPFW_NW_DST(%d)" % (n))
283 else:
284 result = result + sep + all_wildcard_names[w]
285 sep = ", "
286 result = result +"}"
287 return result
Howard Pershc7963582012-03-29 10:02:59 -0700288
Howard Persh680b92a2012-03-31 13:34:35 -0700289all_actions_list = [ofp.OFPAT_OUTPUT,
290 ofp.OFPAT_SET_VLAN_VID,
291 ofp.OFPAT_SET_VLAN_PCP,
292 ofp.OFPAT_STRIP_VLAN,
293 ofp.OFPAT_SET_DL_SRC,
294 ofp.OFPAT_SET_DL_DST,
295 ofp.OFPAT_SET_NW_SRC,
296 ofp.OFPAT_SET_NW_DST,
297 ofp.OFPAT_SET_NW_TOS,
298 ofp.OFPAT_SET_TP_SRC,
299 ofp.OFPAT_SET_TP_DST,
300 ofp.OFPAT_ENQUEUE
301 ]
302
Howard Persh8d21c1f2012-04-20 15:57:29 -0700303def actions_bmap_to_str(bm):
304 result = "{"
305 sep = ""
306 for a in all_actions_list:
307 if ((1 << a) & bm) != 0:
308 result = result + sep + ofp.ofp_action_type_map[a]
309 sep = ", "
310 result = result + "}"
311 return result
312
Howard Persh680b92a2012-03-31 13:34:35 -0700313def dl_addr_to_str(a):
314 return "%x:%x:%x:%x:%x:%x" % tuple(a)
315
316def ip_addr_to_str(a, n):
rootf6af1672012-04-06 09:46:29 -0700317 if n is not None:
318 a = a & ~((1 << (32 - n)) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700319 result = "%d.%d.%d.%d" % (a >> 24, \
320 (a >> 16) & 0xff, \
321 (a >> 8) & 0xff, \
322 a & 0xff \
323 )
324 if n is not None:
325 result = result + ("/%d" % (n))
326 return result
327
Howard Pershc7963582012-03-29 10:02:59 -0700328
rootf6af1672012-04-06 09:46:29 -0700329class Flow_Cfg:
Howard Pershc7963582012-03-29 10:02:59 -0700330 # Members:
331 # - match
332 # - idle_timeout
333 # - hard_timeout
334 # - priority
Rich Lane62e96852013-03-11 12:04:45 -0700335 # - actions
Howard Pershc7963582012-03-29 10:02:59 -0700336
337 def __init__(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700338 self.priority = 0
Rich Laneed1fa2d2013-01-08 13:23:37 -0800339 self.match = ofp.ofp_match()
Howard Pershc7963582012-03-29 10:02:59 -0700340 self.match.wildcards = ofp.OFPFW_ALL
341 self.idle_timeout = 0
342 self.hard_timeout = 0
Rich Lane62e96852013-03-11 12:04:45 -0700343 self.actions = []
Howard Pershc7963582012-03-29 10:02:59 -0700344
rootf6af1672012-04-06 09:46:29 -0700345 # {pri, match} is considered a flow key
346 def key_equal(self, x):
Howard Persh680b92a2012-03-31 13:34:35 -0700347 if self.priority != x.priority:
348 return False
349 # TBD - Should this logic be moved to ofp_match.__eq__()?
350 if self.match.wildcards != x.match.wildcards:
351 return False
rootf6af1672012-04-06 09:46:29 -0700352 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700353 and self.match.in_port != x.match.in_port:
354 return False
rootf6af1672012-04-06 09:46:29 -0700355 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700356 and self.match.dl_dst != x.match.dl_dst:
357 return False
rootf6af1672012-04-06 09:46:29 -0700358 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0 \
359 and self.match.dl_src != x.match.dl_src:
360 return False
361 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700362 and self.match.dl_vlan != x.match.dl_vlan:
363 return False
rootf6af1672012-04-06 09:46:29 -0700364 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700365 and self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
366 return False
rootf6af1672012-04-06 09:46:29 -0700367 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700368 and self.match.dl_type != x.match.dl_type:
369 return False
rootf6af1672012-04-06 09:46:29 -0700370 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700371 and self.match.nw_tos != x.match.nw_tos:
372 return False
rootf6af1672012-04-06 09:46:29 -0700373 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700374 and self.match.nw_proto != x.match.nw_proto:
375 return False
rootf6af1672012-04-06 09:46:29 -0700376 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
377 if n < 32:
378 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700379 if (self.match.nw_src & m) != (x.match.nw_src & m):
380 return False
rootf6af1672012-04-06 09:46:29 -0700381 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
382 if n < 32:
383 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700384 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
385 return False
rootf6af1672012-04-06 09:46:29 -0700386 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0 \
387 and self.match.tp_src != x.match.tp_src:
Howard Persh680b92a2012-03-31 13:34:35 -0700388 return False
rootf6af1672012-04-06 09:46:29 -0700389 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0 \
390 and self.match.tp_dst != x.match.tp_dst:
391 return False
392 return True
393
Howard Persh5f3c83f2012-04-13 09:57:10 -0700394 def actions_equal(self, x):
Rich Lane2014f9b2012-10-05 15:29:40 -0700395 if test_param_get("conservative_ordered_actions", True):
Howard Persh5f3c83f2012-04-13 09:57:10 -0700396 # Compare actions lists as unordered
397
Rich Lane62e96852013-03-11 12:04:45 -0700398 aa = copy.deepcopy(x.actions)
399 for a in self.actions:
root2843d2b2012-04-06 10:27:46 -0700400 i = 0
401 while i < len(aa):
402 if a == aa[i]:
403 break
404 i = i + 1
405 if i < len(aa):
406 aa.pop(i)
407 else:
408 return False
409 return aa == []
410 else:
411 return self.actions == x.actions
Howard Persh5f3c83f2012-04-13 09:57:10 -0700412
413 def non_key_equal(self, x):
414 if self.cookie != x.cookie:
415 return False
416 if self.idle_timeout != x.idle_timeout:
417 return False
418 if self.hard_timeout != x.hard_timeout:
419 return False
420 return self.actions_equal(x)
rootf6af1672012-04-06 09:46:29 -0700421
root2843d2b2012-04-06 10:27:46 -0700422 def key_str(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700423 result = "priority=%d" % self.priority
424 # TBD - Would be nice if ofp_match.show() was better behaved
425 # (no newlines), and more intuitive (things in hex where approprate), etc.
Howard Persh8d21c1f2012-04-20 15:57:29 -0700426 result = result + (", wildcards=0x%x=%s" \
427 % (self.match.wildcards, \
428 wildcards_to_str(self.match.wildcards) \
429 )
430 )
rootf6af1672012-04-06 09:46:29 -0700431 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700432 result = result + (", in_port=%d" % (self.match.in_port))
rootf6af1672012-04-06 09:46:29 -0700433 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700434 result = result + (", dl_dst=%s" \
435 % (dl_addr_to_str(self.match.dl_dst)) \
436 )
rootf6af1672012-04-06 09:46:29 -0700437 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700438 result = result + (", dl_src=%s" \
439 % (dl_addr_to_str(self.match.dl_src)) \
440 )
rootf6af1672012-04-06 09:46:29 -0700441 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700442 result = result + (", dl_vlan=%d" % (self.match.dl_vlan))
rootf6af1672012-04-06 09:46:29 -0700443 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700444 result = result + (", dl_vlan_pcp=%d" % (self.match.dl_vlan_pcp))
rootf6af1672012-04-06 09:46:29 -0700445 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700446 result = result + (", dl_type=0x%x" % (self.match.dl_type))
rootf6af1672012-04-06 09:46:29 -0700447 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700448 result = result + (", nw_tos=0x%x" % (self.match.nw_tos))
rootf6af1672012-04-06 09:46:29 -0700449 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700450 result = result + (", nw_proto=%d" % (self.match.nw_proto))
rootf6af1672012-04-06 09:46:29 -0700451 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700452 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700453 result = result + (", nw_src=%s" % \
454 (ip_addr_to_str(self.match.nw_src, 32 - n)) \
455 )
rootf6af1672012-04-06 09:46:29 -0700456 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700457 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700458 result = result + (", nw_dst=%s" % \
459 (ip_addr_to_str(self.match.nw_dst, 32 - n)) \
460 )
rootf6af1672012-04-06 09:46:29 -0700461 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700462 result = result + (", tp_src=%d" % self.match.tp_src)
rootf6af1672012-04-06 09:46:29 -0700463 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700464 result = result + (", tp_dst=%d" % self.match.tp_dst)
rootf6af1672012-04-06 09:46:29 -0700465 return result
466
467 def __eq__(self, x):
468 return (self.key_equal(x) and self.non_key_equal(x))
469
470 def __str__(self):
root2843d2b2012-04-06 10:27:46 -0700471 result = self.key_str()
472 result = result + (", cookie=%d" % self.cookie)
Howard Persh680b92a2012-03-31 13:34:35 -0700473 result = result + (", idle_timeout=%d" % self.idle_timeout)
474 result = result + (", hard_timeout=%d" % self.hard_timeout)
Rich Lane62e96852013-03-11 12:04:45 -0700475 for a in self.actions:
Howard Persh680b92a2012-03-31 13:34:35 -0700476 result = result + (", action=%s" % ofp.ofp_action_type_map[a.type])
477 if a.type == ofp.OFPAT_OUTPUT:
478 result = result + ("(%d)" % (a.port))
479 elif a.type == ofp.OFPAT_SET_VLAN_VID:
480 result = result + ("(%d)" % (a.vlan_vid))
481 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
482 result = result + ("(%d)" % (a.vlan_pcp))
483 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
484 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
485 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
486 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
487 elif a.type == ofp.OFPAT_SET_NW_TOS:
488 result = result + ("(0x%x)" % (a.nw_tos))
489 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
490 result = result + ("(%d)" % (a.tp_port))
491 elif a.type == ofp.OFPAT_ENQUEUE:
492 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
493 return result
Howard Pershc7963582012-03-29 10:02:59 -0700494
Howard Persh8d21c1f2012-04-20 15:57:29 -0700495 def rand_actions_ordered(self, fi, valid_actions, valid_ports, valid_queues):
Howard Persh3340d452012-04-06 16:45:21 -0700496 # Action lists are ordered, so pick an ordered random subset of
497 # supported actions
Howard Pershc1199d52012-04-11 14:21:32 -0700498
Rich Lane2014f9b2012-10-05 15:29:40 -0700499 actions_force = test_param_get("actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700500 if actions_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700501 logging.info("Forced actions:")
502 logging.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700503
Dan Talayco910a8282012-04-07 00:05:20 -0700504 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh3340d452012-04-06 16:45:21 -0700505 supported_actions = []
506 for a in all_actions_list:
507 if ((1 << a) & valid_actions) != 0:
508 supported_actions.append(a)
509
Howard Pershc1199d52012-04-11 14:21:32 -0700510 actions \
511 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
512
513 for a in all_actions_list:
514 if ((1 << a) & actions_force) != 0:
515 actions.append(a)
516
517 actions = shuffle(actions)
Howard Persh3340d452012-04-06 16:45:21 -0700518
Howard Persh6a3698d2012-08-21 14:26:39 -0700519 set_vlanf = False
520 strip_vlanf = False
Rich Lane62e96852013-03-11 12:04:45 -0700521 self.actions = []
Howard Pershc1199d52012-04-11 14:21:32 -0700522 for a in actions:
Dan Talayco910a8282012-04-07 00:05:20 -0700523 act = None
Howard Persh3340d452012-04-06 16:45:21 -0700524 if a == ofp.OFPAT_OUTPUT:
525 pass # OUTPUT actions must come last
526 elif a == ofp.OFPAT_SET_VLAN_VID:
Howard Persh6a3698d2012-08-21 14:26:39 -0700527 if not strip_vlanf:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800528 act = ofp.action.set_vlan_vid()
Howard Persh6a3698d2012-08-21 14:26:39 -0700529 act.vlan_vid = fi.rand_vlan()
530 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700531 elif a == ofp.OFPAT_SET_VLAN_PCP:
Howard Persh6a3698d2012-08-21 14:26:39 -0700532 if not strip_vlanf:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800533 act = ofp.action.set_vlan_pcp()
Howard Persh6a3698d2012-08-21 14:26:39 -0700534 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
535 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700536 elif a == ofp.OFPAT_STRIP_VLAN:
Howard Persh6a3698d2012-08-21 14:26:39 -0700537 if not set_vlanf:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800538 act = ofp.action.strip_vlan()
Howard Persh6a3698d2012-08-21 14:26:39 -0700539 strip_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700540 elif a == ofp.OFPAT_SET_DL_SRC:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800541 act = ofp.action.set_dl_src()
Howard Persh3340d452012-04-06 16:45:21 -0700542 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700543 elif a == ofp.OFPAT_SET_DL_DST:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800544 act = ofp.action.set_dl_dst()
Howard Persh3340d452012-04-06 16:45:21 -0700545 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700546 elif a == ofp.OFPAT_SET_NW_SRC:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800547 act = ofp.action.set_nw_src()
Howard Persh3340d452012-04-06 16:45:21 -0700548 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700549 elif a == ofp.OFPAT_SET_NW_DST:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800550 act = ofp.action.set_nw_dst()
Howard Persh3340d452012-04-06 16:45:21 -0700551 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700552 elif a == ofp.OFPAT_SET_NW_TOS:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800553 act = ofp.action.set_nw_tos()
Howard Persh3340d452012-04-06 16:45:21 -0700554 act.nw_tos = fi.rand_ip_tos()
Howard Persh3340d452012-04-06 16:45:21 -0700555 elif a == ofp.OFPAT_SET_TP_SRC:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800556 act = ofp.action.set_tp_src()
Howard Persh3340d452012-04-06 16:45:21 -0700557 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700558 elif a == ofp.OFPAT_SET_TP_DST:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800559 act = ofp.action.set_tp_dst()
Howard Persh3340d452012-04-06 16:45:21 -0700560 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700561 elif a == ofp.OFPAT_ENQUEUE:
562 pass # Enqueue actions must come last
Dan Talayco910a8282012-04-07 00:05:20 -0700563 if act:
Rich Lanec495d9e2013-03-08 17:43:36 -0800564 self.actions.append(act)
Dan Talayco910a8282012-04-07 00:05:20 -0700565
Howard Persh3340d452012-04-06 16:45:21 -0700566 p = random.randint(1, 100)
Howard Pershc1199d52012-04-11 14:21:32 -0700567 if (((1 << ofp.OFPAT_ENQUEUE) & actions_force) != 0 or p <= 33) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700568 and len(valid_queues) > 0 \
569 and ofp.OFPAT_ENQUEUE in actions:
Howard Pershc1199d52012-04-11 14:21:32 -0700570 # In not forecd, one third of the time, include ENQUEUE actions
571 # at end of list
Howard Persh3340d452012-04-06 16:45:21 -0700572 # At most 1 ENQUEUE action
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800573 act = ofp.action.enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700574 (act.port, act.queue_id) = rand_pick(valid_queues)
Rich Lanec495d9e2013-03-08 17:43:36 -0800575 self.actions.append(act)
Howard Pershc1199d52012-04-11 14:21:32 -0700576 if (((1 << ofp.OFPAT_OUTPUT) & actions_force) != 0 \
577 or (p > 33 and p <= 66) \
578 ) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700579 and len(valid_ports) > 0 \
Howard Pershc1199d52012-04-11 14:21:32 -0700580 and ofp.OFPAT_OUTPUT in actions:
Howard Persh3340d452012-04-06 16:45:21 -0700581 # One third of the time, include OUTPUT actions at end of list
582 port_idxs = shuffle(range(len(valid_ports)))
583 # Only 1 output action allowed if IN_PORT wildcarded
584 n = 1 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) != 0 \
585 else random.randint(1, len(valid_ports))
586 port_idxs = port_idxs[0 : n]
587 for pi in port_idxs:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800588 act = ofp.action.output()
Howard Persh3340d452012-04-06 16:45:21 -0700589 act.port = valid_ports[pi]
Howard Persh3340d452012-04-06 16:45:21 -0700590 if act.port != ofp.OFPP_IN_PORT \
591 or wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
592 # OUTPUT(IN_PORT) only valid if OFPFW_IN_PORT not wildcarded
Rich Lanec495d9e2013-03-08 17:43:36 -0800593 self.actions.append(act)
Howard Persh3340d452012-04-06 16:45:21 -0700594 else:
595 # One third of the time, include neither
596 pass
597
598
599 # Randomize flow data for flow modifies (i.e. cookie and actions)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700600 def rand_mod(self, fi, valid_actions, valid_ports, valid_queues):
rootf6af1672012-04-06 09:46:29 -0700601 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700602
Dan Talayco910a8282012-04-07 00:05:20 -0700603 # By default, test with conservative ordering conventions
604 # This should probably be indicated in a profile
Rich Lane2014f9b2012-10-05 15:29:40 -0700605 if test_param_get("conservative_ordered_actions", True):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700606 self.rand_actions_ordered(fi, valid_actions, valid_ports, valid_queues)
Howard Persh3340d452012-04-06 16:45:21 -0700607 return self
608
Rich Lane2014f9b2012-10-05 15:29:40 -0700609 actions_force = test_param_get("actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700610 if actions_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700611 logging.info("Forced actions:")
612 logging.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700613
614 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh680b92a2012-03-31 13:34:35 -0700615 supported_actions = []
616 for a in all_actions_list:
617 if ((1 << a) & valid_actions) != 0:
618 supported_actions.append(a)
619
Howard Pershc1199d52012-04-11 14:21:32 -0700620 actions \
621 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
622
623 for a in all_actions_list:
624 if ((1 << a) & actions_force) != 0:
625 actions.append(a)
626
627 actions = shuffle(actions)
Howard Pershc7963582012-03-29 10:02:59 -0700628
Rich Lane62e96852013-03-11 12:04:45 -0700629 self.actions = []
Howard Pershc1199d52012-04-11 14:21:32 -0700630 for a in actions:
Howard Pershc7963582012-03-29 10:02:59 -0700631 if a == ofp.OFPAT_OUTPUT:
632 # TBD - Output actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700633 if len(valid_ports) == 0:
634 continue
Howard Pershc7963582012-03-29 10:02:59 -0700635 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700636 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700637 for pi in port_idxs:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800638 act = ofp.action.output()
Howard Persh680b92a2012-03-31 13:34:35 -0700639 act.port = valid_ports[pi]
Rich Lanec495d9e2013-03-08 17:43:36 -0800640 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700641 elif a == ofp.OFPAT_SET_VLAN_VID:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800642 act = ofp.action.set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700643 act.vlan_vid = fi.rand_vlan()
Rich Lanec495d9e2013-03-08 17:43:36 -0800644 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700645 elif a == ofp.OFPAT_SET_VLAN_PCP:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800646 act = ofp.action.set_vlan_pcp()
Dan Talayco910a8282012-04-07 00:05:20 -0700647 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700648 elif a == ofp.OFPAT_STRIP_VLAN:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800649 act = ofp.action.strip_vlan()
Rich Lanec495d9e2013-03-08 17:43:36 -0800650 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700651 elif a == ofp.OFPAT_SET_DL_SRC:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800652 act = ofp.action.set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700653 act.dl_addr = fi.rand_dl_addr()
Rich Lanec495d9e2013-03-08 17:43:36 -0800654 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700655 elif a == ofp.OFPAT_SET_DL_DST:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800656 act = ofp.action.set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700657 act.dl_addr = fi.rand_dl_addr()
Rich Lanec495d9e2013-03-08 17:43:36 -0800658 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700659 elif a == ofp.OFPAT_SET_NW_SRC:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800660 act = ofp.action.set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700661 act.nw_addr = fi.rand_ip_addr()
Rich Lanec495d9e2013-03-08 17:43:36 -0800662 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700663 elif a == ofp.OFPAT_SET_NW_DST:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800664 act = ofp.action.set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700665 act.nw_addr = fi.rand_ip_addr()
Rich Lanec495d9e2013-03-08 17:43:36 -0800666 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700667 elif a == ofp.OFPAT_SET_NW_TOS:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800668 act = ofp.action.set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700669 act.nw_tos = fi.rand_ip_tos()
Rich Lanec495d9e2013-03-08 17:43:36 -0800670 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700671 elif a == ofp.OFPAT_SET_TP_SRC:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800672 act = ofp.action.set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700673 act.tp_port = fi.rand_l4_port()
Rich Lanec495d9e2013-03-08 17:43:36 -0800674 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700675 elif a == ofp.OFPAT_SET_TP_DST:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800676 act = ofp.action.set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700677 act.tp_port = fi.rand_l4_port()
Rich Lanec495d9e2013-03-08 17:43:36 -0800678 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700679 elif a == ofp.OFPAT_ENQUEUE:
680 # TBD - Enqueue actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700681 if len(valid_queues) == 0:
682 continue
683 qidxs = shuffle(range(len(valid_queues)))
684 qidxs = qidxs[0 : random.randint(1, len(valid_queues))]
685 for qi in qidxs:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800686 act = ofp.action.enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700687 (act.port, act.queue_id) = valid_queues[qi]
Rich Lanec495d9e2013-03-08 17:43:36 -0800688 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700689
690 return self
691
rootf6af1672012-04-06 09:46:29 -0700692 # Randomize flow cfg
Ed Swierk99a74de2012-08-22 06:40:54 -0700693 def rand(self, fi, wildcards_force, valid_wildcards, valid_actions, valid_ports,
694 valid_queues):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700695 if wildcards_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700696 logging.info("Wildcards forced:")
697 logging.info(wildcards_to_str(wildcards_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700698
rootf6af1672012-04-06 09:46:29 -0700699 # Start with no wildcards, i.e. everything specified
700 self.match.wildcards = 0
Howard Pershc1199d52012-04-11 14:21:32 -0700701
702 if wildcards_force != 0:
703 exact = False
704 else:
705 # Make approx. 5% of flows exact
706 exact = (random.randint(1, 100) <= 5)
rootf6af1672012-04-06 09:46:29 -0700707
708 # For each qualifier Q,
709 # if (wildcarding is not supported for Q,
710 # or an exact flow is specified
711 # or a coin toss comes up heads),
712 # specify Q
713 # else
714 # wildcard Q
715
Howard Pershc1199d52012-04-11 14:21:32 -0700716 if wildcard_get(wildcards_force, ofp.OFPFW_IN_PORT) == 0 \
717 and (wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
718 or exact \
719 or flip_coin() \
720 ):
rootf6af1672012-04-06 09:46:29 -0700721 self.match.in_port = rand_pick(valid_ports)
722 else:
Howard Persh3340d452012-04-06 16:45:21 -0700723 self.match.wildcards = wildcard_set(self.match.wildcards, \
724 ofp.OFPFW_IN_PORT, \
725 1 \
726 )
rootf6af1672012-04-06 09:46:29 -0700727
Howard Pershc1199d52012-04-11 14:21:32 -0700728 if wildcard_get(wildcards_force, ofp.OFPFW_DL_DST) == 0 \
729 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
730 or exact \
731 or flip_coin() \
732 ):
rootf6af1672012-04-06 09:46:29 -0700733 self.match.dl_dst = fi.rand_dl_addr()
734 else:
Howard Persh3340d452012-04-06 16:45:21 -0700735 self.match.wildcards = wildcard_set(self.match.wildcards, \
736 ofp.OFPFW_DL_DST, \
737 1 \
738 )
rootf6af1672012-04-06 09:46:29 -0700739
Howard Pershc1199d52012-04-11 14:21:32 -0700740 if wildcard_get(wildcards_force, ofp.OFPFW_DL_SRC) == 0 \
741 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
742 or exact \
743 or flip_coin() \
744 ):
rootf6af1672012-04-06 09:46:29 -0700745 self.match.dl_src = fi.rand_dl_addr()
746 else:
Howard Persh3340d452012-04-06 16:45:21 -0700747 self.match.wildcards = wildcard_set(self.match.wildcards, \
748 ofp.OFPFW_DL_SRC, \
749 1 \
750 )
rootf6af1672012-04-06 09:46:29 -0700751
Howard Pershc1199d52012-04-11 14:21:32 -0700752 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN) == 0 \
753 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
754 or exact \
755 or flip_coin() \
756 ):
rootf6af1672012-04-06 09:46:29 -0700757 self.match.dl_vlan = fi.rand_vlan()
758 else:
Howard Persh3340d452012-04-06 16:45:21 -0700759 self.match.wildcards = wildcard_set(self.match.wildcards, \
760 ofp.OFPFW_DL_VLAN, \
761 1 \
762 )
rootf6af1672012-04-06 09:46:29 -0700763
Howard Pershc1199d52012-04-11 14:21:32 -0700764 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN_PCP) == 0 \
765 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
766 or exact \
767 or flip_coin() \
768 ):
769 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
770 else:
771 self.match.wildcards = wildcard_set(self.match.wildcards, \
772 ofp.OFPFW_DL_VLAN_PCP, \
773 1 \
774 )
775
776 if wildcard_get(wildcards_force, ofp.OFPFW_DL_TYPE) == 0 \
777 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
778 or exact \
779 or flip_coin() \
780 ):
rootf6af1672012-04-06 09:46:29 -0700781 self.match.dl_type = fi.rand_ethertype()
782 else:
Howard Persh3340d452012-04-06 16:45:21 -0700783 self.match.wildcards = wildcard_set(self.match.wildcards, \
784 ofp.OFPFW_DL_TYPE, \
785 1 \
786 )
rootf6af1672012-04-06 09:46:29 -0700787
Howard Pershc1199d52012-04-11 14:21:32 -0700788 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_SRC_MASK)
789 if n == 0:
790 if exact or flip_coin():
791 n = 0
792 else:
793 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
794 if n > 32:
795 n = 32
796 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700797 self.match.wildcards = wildcard_set(self.match.wildcards, \
798 ofp.OFPFW_NW_SRC_MASK, \
799 n \
800 )
rootf6af1672012-04-06 09:46:29 -0700801 if n < 32:
802 self.match.nw_src = fi.rand_ip_addr() & ~((1 << n) - 1)
803 # Specifying any IP address match other than all bits
804 # don't care requires that Ethertype is one of {IP, ARP}
805 if flip_coin():
806 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700807 self.match.wildcards = wildcard_set(self.match.wildcards, \
808 ofp.OFPFW_DL_TYPE, \
809 0 \
810 )
rootf6af1672012-04-06 09:46:29 -0700811
Howard Pershc1199d52012-04-11 14:21:32 -0700812 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_DST_MASK)
813 if n == 0:
814 if exact or flip_coin():
815 n = 0
816 else:
817 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
818 if n > 32:
819 n = 32
820 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700821 self.match.wildcards = wildcard_set(self.match.wildcards, \
822 ofp.OFPFW_NW_DST_MASK, \
823 n \
824 )
rootf6af1672012-04-06 09:46:29 -0700825 if n < 32:
826 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
827 # Specifying any IP address match other than all bits
828 # don't care requires that Ethertype is one of {IP, ARP}
829 if flip_coin():
830 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700831 self.match.wildcards = wildcard_set(self.match.wildcards, \
832 ofp.OFPFW_DL_TYPE, \
833 0 \
834 )
rootf6af1672012-04-06 09:46:29 -0700835
Howard Pershc1199d52012-04-11 14:21:32 -0700836 if wildcard_get(wildcards_force, ofp.OFPFW_NW_TOS) == 0 \
837 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
838 or exact \
839 or flip_coin() \
840 ):
rootf6af1672012-04-06 09:46:29 -0700841 self.match.nw_tos = fi.rand_ip_tos()
842 # Specifying a TOS value requires that Ethertype is IP
843 if flip_coin():
844 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700845 self.match.wildcards = wildcard_set(self.match.wildcards, \
846 ofp.OFPFW_DL_TYPE, \
847 0 \
848 )
rootf6af1672012-04-06 09:46:29 -0700849 else:
Howard Persh3340d452012-04-06 16:45:21 -0700850 self.match.wildcards = wildcard_set(self.match.wildcards, \
851 ofp.OFPFW_NW_TOS, \
852 1 \
853 )
rootf6af1672012-04-06 09:46:29 -0700854
Dan Talayco910a8282012-04-07 00:05:20 -0700855 # Known issue on OVS with specifying nw_proto w/o dl_type as IP
Howard Pershc1199d52012-04-11 14:21:32 -0700856 if wildcard_get(wildcards_force, ofp.OFPFW_NW_PROTO) == 0 \
857 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
858 or exact \
859 or flip_coin() \
860 ):
Dan Talayco910a8282012-04-07 00:05:20 -0700861 self.match.nw_proto = fi.rand_ip_proto()
862 # Specifying an IP protocol requires that Ethertype is IP
863 if flip_coin():
864 self.match.dl_type = 0x0800
865 self.match.wildcards = wildcard_set(self.match.wildcards, \
866 ofp.OFPFW_DL_TYPE, \
867 0 \
868 )
869 else:
Howard Persh3340d452012-04-06 16:45:21 -0700870 self.match.wildcards = wildcard_set(self.match.wildcards, \
871 ofp.OFPFW_NW_PROTO, \
872 1 \
873 )
Dan Talayco910a8282012-04-07 00:05:20 -0700874
Howard Pershc1199d52012-04-11 14:21:32 -0700875 if wildcard_get(wildcards_force, ofp.OFPFW_TP_SRC) == 0 \
876 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
877 or exact\
878 or flip_coin() \
879 ):
rootf6af1672012-04-06 09:46:29 -0700880 self.match.tp_src = fi.rand_l4_port()
881 # Specifying a L4 port requires that IP protcol is
882 # one of {ICMP, TCP, UDP}
883 if flip_coin():
884 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700885 self.match.wildcards = wildcard_set(self.match.wildcards, \
886 ofp.OFPFW_NW_PROTO, \
887 0 \
888 )
rootf6af1672012-04-06 09:46:29 -0700889 # Specifying a L4 port requirues that Ethertype is IP
890 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700891 self.match.wildcards = wildcard_set(self.match.wildcards, \
892 ofp.OFPFW_DL_TYPE, \
893 0 \
894 )
rootf6af1672012-04-06 09:46:29 -0700895 if self.match.nw_proto == 1:
896 self.match.tp_src = self.match.tp_src & 0xff
897 else:
Howard Persh3340d452012-04-06 16:45:21 -0700898 self.match.wildcards = wildcard_set(self.match.wildcards, \
899 ofp.OFPFW_TP_SRC, \
900 1 \
901 )
rootf6af1672012-04-06 09:46:29 -0700902
Howard Pershc1199d52012-04-11 14:21:32 -0700903 if wildcard_get(wildcards_force, ofp.OFPFW_TP_DST) == 0 \
904 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
905 or exact \
906 or flip_coin() \
907 ):
rootf6af1672012-04-06 09:46:29 -0700908 self.match.tp_dst = fi.rand_l4_port()
909 # Specifying a L4 port requires that IP protcol is
910 # one of {ICMP, TCP, UDP}
911 if flip_coin():
912 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700913 self.match.wildcards = wildcard_set(self.match.wildcards, \
914 ofp.OFPFW_NW_PROTO, \
915 0 \
916 )
rootf6af1672012-04-06 09:46:29 -0700917 # Specifying a L4 port requirues that Ethertype is IP
918 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700919 self.match.wildcards = wildcard_set(self.match.wildcards, \
920 ofp.OFPFW_DL_TYPE, \
921 0 \
922 )
rootf6af1672012-04-06 09:46:29 -0700923 if self.match.nw_proto == 1:
924 self.match.tp_dst = self.match.tp_dst & 0xff
925 else:
Howard Persh3340d452012-04-06 16:45:21 -0700926 self.match.wildcards = wildcard_set(self.match.wildcards, \
927 ofp.OFPFW_TP_DST, \
928 1 \
929 )
rootf6af1672012-04-06 09:46:29 -0700930
931 # If nothing is wildcarded, it is an exact flow spec -- some switches
Howard Persh3340d452012-04-06 16:45:21 -0700932 # (Open vSwitch, for one) *require* that exact flow specs
933 # have priority 65535.
934 self.priority = 65535 if self.match.wildcards == 0 \
935 else fi.rand_priority()
rootf6af1672012-04-06 09:46:29 -0700936
937 # N.B. Don't make the timeout too short, else the flow might
938 # disappear before we get a chance to check for it.
939 t = random.randint(0, 65535)
940 self.idle_timeout = 0 if t < 60 else t
941 t = random.randint(0, 65535)
942 self.hard_timeout = 0 if t < 60 else t
943
Howard Persh8d21c1f2012-04-20 15:57:29 -0700944 self.rand_mod(fi, valid_actions, valid_ports, valid_queues)
rootf6af1672012-04-06 09:46:29 -0700945
946 return self
947
948 # Return flow cfg in canonical form
Howard Persh3340d452012-04-06 16:45:21 -0700949 # - There are dependencies between flow qualifiers, e.g. it only makes
950 # sense to qualify nw_proto if dl_type is qualified to be 0x0800 (IP).
951 # The canonical form of flow match criteria will "wildcard out"
952 # all such cases.
rootf6af1672012-04-06 09:46:29 -0700953 def canonical(self):
954 result = copy.deepcopy(self)
Howard Persh07d99e62012-04-09 15:26:57 -0700955
956 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_VLAN) != 0:
957 result.match.wildcards = wildcard_set(result.match.wildcards, \
958 ofp.OFPFW_DL_VLAN_PCP, \
959 1 \
960 )
961
rootf6af1672012-04-06 09:46:29 -0700962 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
963 or result.match.dl_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700964 # dl_tyoe is wildcarded, or specified as something other
965 # than IP or ARP
Howard Persh07d99e62012-04-09 15:26:57 -0700966 # => nw_src, nw_dst, nw_proto cannot be specified,
967 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700968 result.match.wildcards = wildcard_set(result.match.wildcards, \
969 ofp.OFPFW_NW_SRC_MASK, \
970 32 \
971 )
972 result.match.wildcards = wildcard_set(result.match.wildcards, \
973 ofp.OFPFW_NW_DST_MASK, \
974 32 \
975 )
Howard Persh3340d452012-04-06 16:45:21 -0700976 result.match.wildcards = wildcard_set(result.match.wildcards, \
977 ofp.OFPFW_NW_PROTO, \
978 1 \
979 )
Howard Persh07d99e62012-04-09 15:26:57 -0700980
981 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
982 or result.match.dl_type != 0x0800:
983 # dl_type is wildcarded, or specified as something other than IP
984 # => nw_tos, tp_src and tp_dst cannot be specified,
985 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700986 result.match.wildcards = wildcard_set(result.match.wildcards, \
987 ofp.OFPFW_NW_TOS, \
988 1 \
989 )
990 result.match.wildcards = wildcard_set(result.match.wildcards, \
991 ofp.OFPFW_TP_SRC, \
992 1 \
993 )
994 result.match.wildcards = wildcard_set(result.match.wildcards, \
995 ofp.OFPFW_TP_DST, \
996 1 \
997 )
Howard Persh07d99e62012-04-09 15:26:57 -0700998 result.match.wildcards = wildcard_set(result.match.wildcards, \
999 ofp.OFPFW_NW_SRC_MASK, \
1000 32 \
1001 )
1002 result.match.wildcards = wildcard_set(result.match.wildcards, \
1003 ofp.OFPFW_NW_DST_MASK, \
1004 32 \
1005 )
1006 result.match.wildcards = wildcard_set(result.match.wildcards, \
1007 ofp.OFPFW_NW_PROTO, \
1008 1 \
1009 )
1010
rootf6af1672012-04-06 09:46:29 -07001011 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
1012 or result.match.nw_proto not in [1, 6, 17]:
Howard Persh3340d452012-04-06 16:45:21 -07001013 # nw_proto is wildcarded, or specified as something other than ICMP,
1014 # TCP or UDP
rootf6af1672012-04-06 09:46:29 -07001015 # => tp_src and tp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001016 result.match.wildcards = wildcard_set(result.match.wildcards, \
1017 ofp.OFPFW_TP_SRC, \
1018 1 \
1019 )
1020 result.match.wildcards = wildcard_set(result.match.wildcards, \
1021 ofp.OFPFW_TP_DST, \
1022 1 \
1023 )
rootf6af1672012-04-06 09:46:29 -07001024 return result
1025
Howard Persh680b92a2012-03-31 13:34:35 -07001026 # Overlap check
1027 # delf == True <=> Check for delete overlap, else add overlap
1028 # "Add overlap" is defined as there exists a packet that could match both the
1029 # receiver and argument flowspecs
1030 # "Delete overlap" is defined as the specificity of the argument flowspec
1031 # is greater than or equal to the specificity of the receiver flowspec
1032 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -07001033 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
1034 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001035 if self.match.in_port != x.match.in_port:
1036 return False # Both specified, and not equal
1037 elif delf:
1038 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001039 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
1040 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001041 if self.match.dl_vlan != x.match.dl_vlan:
1042 return False # Both specified, and not equal
1043 elif delf:
1044 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001045 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
1046 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001047 if self.match.dl_src != x.match.dl_src:
1048 return False # Both specified, and not equal
1049 elif delf:
1050 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001051 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
1052 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001053 if self.match.dl_dst != x.match.dl_dst:
1054 return False # Both specified, and not equal
1055 elif delf:
1056 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001057 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
1058 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001059 if self.match.dl_type != x.match.dl_type:
1060 return False # Both specified, and not equal
1061 elif delf:
1062 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -07001063 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
1064 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001065 if self.match.nw_proto != x.match.nw_proto:
1066 return False # Both specified, and not equal
1067 elif delf:
1068 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001069 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
1070 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001071 if self.match.tp_src != x.match.tp_src:
1072 return False # Both specified, and not equal
1073 elif delf:
1074 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001075 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
1076 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001077 if self.match.tp_dst != x.match.tp_dst:
1078 return False # Both specified, and not equal
1079 elif delf:
1080 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001081 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
1082 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001083 if delf and na < nb:
1084 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001085 if (na < 32 and nb < 32):
1086 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1087 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -07001088 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -07001089 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
1090 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001091 if delf and na < nb:
1092 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001093 if (na < 32 and nb < 32):
1094 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1095 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
rootf6af1672012-04-06 09:46:29 -07001096 return False # Overlapping bits not equal
1097 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
1098 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001099 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
1100 return False # Both specified, and not equal
1101 elif delf:
1102 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001103 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
1104 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001105 if self.match.nw_tos != x.match.nw_tos:
1106 return False # Both specified, and not equal
1107 elif delf:
1108 return False # Receiver more specific
1109 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -07001110
1111 def to_flow_mod_msg(self, msg):
1112 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -07001113 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001114 msg.idle_timeout = self.idle_timeout
1115 msg.hard_timeout = self.hard_timeout
1116 msg.priority = self.priority
1117 msg.actions = self.actions
1118 return msg
1119
1120 def from_flow_stat(self, msg):
1121 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -07001122 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001123 self.idle_timeout = msg.idle_timeout
1124 self.hard_timeout = msg.hard_timeout
1125 self.priority = msg.priority
1126 self.actions = msg.actions
1127
rootf6af1672012-04-06 09:46:29 -07001128 def from_flow_rem(self, msg):
1129 self.match = msg.match
1130 self.idle_timeout = msg.idle_timeout
1131 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -07001132
Howard Pershc7963582012-03-29 10:02:59 -07001133
rootf6af1672012-04-06 09:46:29 -07001134class Flow_Tbl:
1135 def clear(self):
1136 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001137
rootf6af1672012-04-06 09:46:29 -07001138 def __init__(self):
1139 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001140
rootf6af1672012-04-06 09:46:29 -07001141 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001142 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001143
1144 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001145 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001146
1147 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001148 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001149
1150 def values(self):
1151 return self.dict.values()
1152
1153 def count(self):
1154 return len(self.dict)
1155
Ed Swierk99a74de2012-08-22 06:40:54 -07001156 def rand(self, wildcards_force, sw, fi, num_flows):
rootf6af1672012-04-06 09:46:29 -07001157 self.clear()
1158 i = 0
1159 tbl = 0
1160 j = 0
1161 while i < num_flows:
1162 fc = Flow_Cfg()
1163 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001164 wildcards_force, \
rootf6af1672012-04-06 09:46:29 -07001165 sw.tbl_stats.stats[tbl].wildcards, \
1166 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001167 sw.valid_ports, \
1168 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001169 )
1170 fc = fc.canonical()
1171 if self.find(fc):
1172 continue
1173 fc.send_rem = False
1174 self.insert(fc)
1175 i = i + 1
1176 j = j + 1
1177 if j >= sw.tbl_stats.stats[tbl].max_entries:
1178 tbl = tbl + 1
1179 j = 0
1180
1181
1182class Switch:
1183 # Members:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001184 # controller - switch's test controller
1185 # sw_features - switch's OFPT_FEATURES_REPLY message
1186 # valid_ports - list of valid port numbers
1187 # valid_queues - list of valid [port, queue] pairs
1188 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1189 # queue_stats - switch's OFPT_STATS_REPLY message, for queue stats request
1190 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1191 # flow_tbl - (test's idea of) switch's flow table
rootf6af1672012-04-06 09:46:29 -07001192
1193 def __init__(self):
Howard Persh8d21c1f2012-04-20 15:57:29 -07001194 self.controller = None
1195 self.sw_features = None
1196 self.valid_ports = []
1197 self.valid_queues = []
1198 self.tbl_stats = None
1199 self.flow_stats = None
1200 self.flow_tbl = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001201 self.error_msgs = []
1202 self.removed_msgs = []
1203
1204 def error_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001205 logging.info("Got an ERROR message, type=%d, code=%d" \
Ed Swierk99a74de2012-08-22 06:40:54 -07001206 % (msg.type, msg.code) \
1207 )
Rich Lane9a003812012-10-04 17:17:59 -07001208 logging.info("Message header:")
1209 logging.info(msg.header.show())
Ed Swierk99a74de2012-08-22 06:40:54 -07001210 self.error_msgs.append(msg)
1211
1212 def removed_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001213 logging.info("Got a REMOVED message")
1214 logging.info("Message header:")
1215 logging.info(msg.header.show())
Ed Swierk99a74de2012-08-22 06:40:54 -07001216 self.removed_msgs.append(msg)
rootf6af1672012-04-06 09:46:29 -07001217
Howard Persh3340d452012-04-06 16:45:21 -07001218 def controller_set(self, controller):
1219 self.controller = controller
1220 # Register error message handler
Ed Swierk99a74de2012-08-22 06:40:54 -07001221 self.error_msgs = []
1222 self.removed_msgs = []
1223 controller.register(ofp.OFPT_ERROR, self.error_handler)
1224 controller.register(ofp.OFPT_FLOW_REMOVED, self.removed_handler)
Howard Persh3340d452012-04-06 16:45:21 -07001225
rootf6af1672012-04-06 09:46:29 -07001226 def features_get(self):
1227 # Get switch features
Rich Lane28fa9272013-03-08 16:00:25 -08001228 request = ofp.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001229 (self.sw_features, pkt) = self.controller.transact(request)
rootf6af1672012-04-06 09:46:29 -07001230 if self.sw_features is None:
Rich Lane9a003812012-10-04 17:17:59 -07001231 logging.error("Get switch features failed")
rootf6af1672012-04-06 09:46:29 -07001232 return False
1233 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Rich Lane9a003812012-10-04 17:17:59 -07001234 logging.info("Ports reported by switch:")
1235 logging.info(self.valid_ports)
Rich Lane2014f9b2012-10-05 15:29:40 -07001236 ports_override = test_param_get("ports", [])
Howard Persh8d21c1f2012-04-20 15:57:29 -07001237 if ports_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001238 logging.info("Overriding ports to:")
1239 logging.info(ports_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001240 self.valid_ports = ports_override
1241
Howard Persh3340d452012-04-06 16:45:21 -07001242 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1243 # is that universal?
1244
1245 # TBD - There seems to be variability in which switches support which
1246 # ports; need to sort that out
1247 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1248# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1249# ofp.OFPP_NORMAL, \
1250# ofp.OFPP_FLOOD, \
1251# ofp.OFPP_ALL, \
1252# ofp.OFPP_CONTROLLER \
1253# ] \
1254# )
Rich Lane9a003812012-10-04 17:17:59 -07001255 logging.info("Supported actions reported by switch:")
1256 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001257 % (self.sw_features.actions, \
1258 actions_bmap_to_str(self.sw_features.actions) \
1259 ) \
1260 )
Rich Lane2014f9b2012-10-05 15:29:40 -07001261 actions_override = test_param_get("actions", -1)
Howard Persh07d99e62012-04-09 15:26:57 -07001262 if actions_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001263 logging.info("Overriding supported actions to:")
1264 logging.info(actions_bmap_to_str(actions_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001265 self.sw_features.actions = actions_override
rootf6af1672012-04-06 09:46:29 -07001266 return True
1267
1268 def tbl_stats_get(self):
1269 # Get table stats
Rich Lane28fa9272013-03-08 16:00:25 -08001270 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001271 (self.tbl_stats, pkt) = self.controller.transact(request)
Howard Persh07d99e62012-04-09 15:26:57 -07001272 if self.tbl_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001273 logging.error("Get table stats failed")
Howard Persh07d99e62012-04-09 15:26:57 -07001274 return False
Howard Persh8d21c1f2012-04-20 15:57:29 -07001275 i = 0
Howard Persh07d99e62012-04-09 15:26:57 -07001276 for ts in self.tbl_stats.stats:
Rich Lane9a003812012-10-04 17:17:59 -07001277 logging.info("Supported wildcards for table %d reported by switch:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001278 % (i)
1279 )
Rich Lane9a003812012-10-04 17:17:59 -07001280 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001281 % (ts.wildcards, \
1282 wildcards_to_str(ts.wildcards) \
1283 ) \
1284 )
Rich Lane2014f9b2012-10-05 15:29:40 -07001285 wildcards_override = test_param_get("wildcards", -1)
Howard Persh07d99e62012-04-09 15:26:57 -07001286 if wildcards_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001287 logging.info("Overriding supported wildcards for table %d to:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001288 % (i)
1289 )
Rich Lane9a003812012-10-04 17:17:59 -07001290 logging.info(wildcards_to_str(wildcards_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001291 ts.wildcards = wildcards_override
Howard Persh8d21c1f2012-04-20 15:57:29 -07001292 i = i + 1
Howard Persh07d99e62012-04-09 15:26:57 -07001293 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001294
Howard Persh8d21c1f2012-04-20 15:57:29 -07001295 def queue_stats_get(self):
1296 # Get queue stats
Rich Lane28fa9272013-03-08 16:00:25 -08001297 request = ofp.message.queue_stats_request()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001298 request.port_no = ofp.OFPP_ALL
1299 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001300 (self.queue_stats, pkt) = self.controller.transact(request)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001301 if self.queue_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001302 logging.error("Get queue stats failed")
Howard Persh8d21c1f2012-04-20 15:57:29 -07001303 return False
1304 self.valid_queues = map(lambda x: (x.port_no, x.queue_id), \
1305 self.queue_stats.stats \
1306 )
Rich Lane9a003812012-10-04 17:17:59 -07001307 logging.info("(Port, queue) pairs reported by switch:")
1308 logging.info(self.valid_queues)
Rich Lane2014f9b2012-10-05 15:29:40 -07001309 queues_override = test_param_get("queues", [])
Howard Persh8d21c1f2012-04-20 15:57:29 -07001310 if queues_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001311 logging.info("Overriding (port, queue) pairs to:")
1312 logging.info(queues_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001313 self.valid_queues = queues_override
1314 return True
1315
1316 def connect(self, controller):
1317 # Connect to controller, and get all switch capabilities
1318 self.controller_set(controller)
1319 return (self.features_get() \
1320 and self.tbl_stats_get() \
1321 and self.queue_stats_get() \
1322 )
1323
Howard Pershc1199d52012-04-11 14:21:32 -07001324 def flow_stats_get(self, limit = 10000):
Rich Lane28fa9272013-03-08 16:00:25 -08001325 request = ofp.message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -07001326 query_match = ofp.ofp_match()
1327 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001328 request.match = query_match
1329 request.table_id = 0xff
1330 request.out_port = ofp.OFPP_NONE;
Rich Lane5c3151c2013-01-03 17:15:41 -08001331 self.controller.message_send(request)
Howard Persh3340d452012-04-06 16:45:21 -07001332 # <TBD>
1333 # Glue together successive reponse messages for stats reply.
1334 # Looking at the "more" flag and performing re-assembly
1335 # should be a part of the infrastructure.
1336 # </TBD>
1337 n = 0
1338 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -07001339 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY)
Howard Persh3340d452012-04-06 16:45:21 -07001340 if resp is None:
Howard Pershc1199d52012-04-11 14:21:32 -07001341 return False # Did not get expected response
Howard Persh3340d452012-04-06 16:45:21 -07001342 if n == 0:
1343 self.flow_stats = resp
1344 else:
1345 self.flow_stats.stats.extend(resp.stats)
1346 n = n + 1
Howard Pershc1199d52012-04-11 14:21:32 -07001347 if len(self.flow_stats.stats) > limit:
Rich Lane9a003812012-10-04 17:17:59 -07001348 logging.error("Too many flows returned")
Howard Pershc1199d52012-04-11 14:21:32 -07001349 return False
1350 if (resp.flags & 1) == 0:
1351 break # No more responses expected
Howard Persh3340d452012-04-06 16:45:21 -07001352 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001353
rootf6af1672012-04-06 09:46:29 -07001354 def flow_add(self, flow_cfg, overlapf = False):
Rich Lane28fa9272013-03-08 16:00:25 -08001355 flow_mod_msg = ofp.message.flow_mod()
Howard Persh680b92a2012-03-31 13:34:35 -07001356 flow_mod_msg.command = ofp.OFPFC_ADD
1357 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001358 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001359 if overlapf:
1360 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001361 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001362 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Howard Persh07d99e62012-04-09 15:26:57 -07001363 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001364 logging.info("Sending flow_mod(add), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001365 % (flow_mod_msg.header.xid)
1366 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001367 self.controller.message_send(flow_mod_msg)
1368 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001369
rootf6af1672012-04-06 09:46:29 -07001370 def flow_mod(self, flow_cfg, strictf):
Rich Lane28fa9272013-03-08 16:00:25 -08001371 flow_mod_msg = ofp.message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001372 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf \
1373 else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -07001374 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001375 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001376 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001377 logging.info("Sending flow_mod(mod), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001378 % (flow_mod_msg.header.xid)
1379 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001380 self.controller.message_send(flow_mod_msg)
1381 return True
rootf6af1672012-04-06 09:46:29 -07001382
1383 def flow_del(self, flow_cfg, strictf):
Rich Lane28fa9272013-03-08 16:00:25 -08001384 flow_mod_msg = ofp.message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001385 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf \
1386 else ofp.OFPFC_DELETE
rootf6af1672012-04-06 09:46:29 -07001387 flow_mod_msg.buffer_id = 0xffffffff
1388 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001389 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001390 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001391 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001392 logging.info("Sending flow_mod(del), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001393 % (flow_mod_msg.header.xid)
1394 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001395 self.controller.message_send(flow_mod_msg)
1396 return True
rootf6af1672012-04-06 09:46:29 -07001397
1398 def barrier(self):
Rich Lane28fa9272013-03-08 16:00:25 -08001399 barrier = ofp.message.barrier_request()
Dan Talaycoc689a792012-09-28 14:22:53 -07001400 (resp, pkt) = self.controller.transact(barrier, 30)
rootf6af1672012-04-06 09:46:29 -07001401 return (resp is not None)
1402
Howard Persh3340d452012-04-06 16:45:21 -07001403 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001404 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001405 logging.info("Expecting %d error messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001406 num_got = len(self.error_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001407 logging.info("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001408 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001409 logging.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001410 result = False
1411 if num_exp == 0:
1412 return result
1413 elif num_exp == 1:
Rich Lane9a003812012-10-04 17:17:59 -07001414 logging.info("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001415 % (type, code) \
1416 )
1417 f = False
Ed Swierk99a74de2012-08-22 06:40:54 -07001418 for e in self.error_msgs:
Howard Persh3340d452012-04-06 16:45:21 -07001419 if e.type == type and e.code == code:
Rich Lane9a003812012-10-04 17:17:59 -07001420 logging.info("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001421 f = True
1422 if not f:
Rich Lane9a003812012-10-04 17:17:59 -07001423 logging.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001424 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001425 else:
Rich Lane9a003812012-10-04 17:17:59 -07001426 logging.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001427 result = False
1428 return result
1429
Howard Persh3340d452012-04-06 16:45:21 -07001430 def removed_verify(self, num_exp):
1431 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001432 logging.info("Expecting %d removed messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001433 num_got = len(self.removed_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001434 logging.info("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001435 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001436 logging.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001437 result = False
1438 if num_exp < 2:
1439 return result
Rich Lane9a003812012-10-04 17:17:59 -07001440 logging.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001441 return False
1442
Howard Persh5f3c83f2012-04-13 09:57:10 -07001443 # modf == True <=> Verify for flow modify, else for add/delete
1444 def flow_tbl_verify(self, modf = False):
rootf6af1672012-04-06 09:46:29 -07001445 result = True
1446
1447 # Verify flow count in switch
Rich Lane9a003812012-10-04 17:17:59 -07001448 logging.info("Reading table stats")
1449 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001450 if not self.tbl_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001451 logging.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001452 return False
1453 n = 0
1454 for ts in self.tbl_stats.stats:
1455 n = n + ts.active_count
Rich Lane9a003812012-10-04 17:17:59 -07001456 logging.info("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001457 % (n) \
1458 )
1459 if n != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001460 logging.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001461 result = False
1462
1463 # Read flows from switch
Rich Lane9a003812012-10-04 17:17:59 -07001464 logging.info("Retrieving flows from switch")
1465 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001466 if not self.flow_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001467 logging.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001468 return False
Rich Lane9a003812012-10-04 17:17:59 -07001469 logging.info("Retrieved %d flows" % (len(self.flow_stats.stats)))
rootf6af1672012-04-06 09:46:29 -07001470
1471 # Verify flows returned by switch
1472
1473 if len(self.flow_stats.stats) != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001474 logging.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001475 result = False
1476
Rich Lane9a003812012-10-04 17:17:59 -07001477 logging.info("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001478 for fc in self.flow_tbl.values():
1479 fc.matched = False
1480 for fs in self.flow_stats.stats:
1481 flow_in = Flow_Cfg()
1482 flow_in.from_flow_stat(fs)
Rich Lane9a003812012-10-04 17:17:59 -07001483 logging.info("Received flow:")
1484 logging.info(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001485 fc = self.flow_tbl.find(flow_in)
1486 if fc is None:
Rich Lane9a003812012-10-04 17:17:59 -07001487 logging.error("Received flow:")
1488 logging.error(str(flow_in))
1489 logging.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001490 result = False
1491 elif fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001492 logging.error("Received flow:")
1493 logging.error(str(flow_in))
1494 logging.error("re-matches defined flow:")
1495 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001496 result = False
1497 else:
Rich Lane9a003812012-10-04 17:17:59 -07001498 logging.info("matched")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001499 if modf:
1500 # Check for modify
1501
1502 if flow_in.cookie != fc.cookie:
Rich Lane9a003812012-10-04 17:17:59 -07001503 logging.warning("Defined flow:")
1504 logging.warning(str(fc))
1505 logging.warning("Received flow:")
1506 logging.warning(str(flow_in))
1507 logging.warning("cookies do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001508 if not flow_in.actions_equal(fc):
Rich Lane9a003812012-10-04 17:17:59 -07001509 logging.error("Defined flow:")
1510 logging.error(str(fc))
1511 logging.error("Received flow:")
1512 logging.error(str(flow_in))
1513 logging.error("actions do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001514 else:
1515 # Check for add/delete
1516
1517 if not flow_in == fc:
Rich Lane9a003812012-10-04 17:17:59 -07001518 logging.error("Defined flow:")
1519 logging.error(str(fc))
1520 logging.error("Received flow:")
1521 logging.error(str(flow_in))
1522 logging.error("non-key portions of flow do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001523 result = False
rootf6af1672012-04-06 09:46:29 -07001524 fc.matched = True
1525 for fc in self.flow_tbl.values():
1526 if not fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001527 logging.error("Defined flow:")
1528 logging.error(str(fc))
1529 logging.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001530 result = False
1531
1532 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001533
Howard Persh9cab4822012-09-11 17:08:40 -07001534 def settle(self):
1535 time.sleep(2)
1536
Howard Persh07d99e62012-04-09 15:26:57 -07001537# FLOW ADD 5
1538#
1539# OVERVIEW
1540# Add flows to switch, read back and verify flow configurations
1541#
1542# PURPOSE
1543# - Test acceptance of flow adds
1544# - Test ability of switch to process additions to flow table in random
1545# priority order
1546# - Test correctness of flow configuration responses
1547#
1548# PARAMETERS
1549#
1550# Name: num_flows
1551# Type: number
1552# Description:
1553# Number of flows to define; 0 => maximum number of flows, as determined
1554# from switch capabilities
1555# Default: 100
1556#
1557# PROCESS
1558# 1. Delete all flows from switch
1559# 2. Generate <num_flows> distinct flow configurations
1560# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1561# 4. Verify that no OFPT_ERROR responses were generated by switch
1562# 5. Retrieve flow stats from switch
1563# 6. Compare flow configurations returned by switch
1564# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1565# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001566
Rich Laneb90a1c42012-10-05 09:16:05 -07001567class Flow_Add_5(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001568 """
1569 Test FLOW_ADD_5 from draft top-half test plan
1570
1571 INPUTS
1572 num_flows - Number of flows to generate
1573 """
Howard Persh680b92a2012-03-31 13:34:35 -07001574
rootf6af1672012-04-06 09:46:29 -07001575 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001576 logging.info("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001577
Rich Lane2014f9b2012-10-05 15:29:40 -07001578 num_flows = test_param_get("num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001579
Howard Pershc7963582012-03-29 10:02:59 -07001580 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001581
Rich Lane9a003812012-10-04 17:17:59 -07001582 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001583 delete_all_flows(self.controller)
Howard Pershc7963582012-03-29 10:02:59 -07001584
rootf6af1672012-04-06 09:46:29 -07001585 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001586
rootf6af1672012-04-06 09:46:29 -07001587 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001588 self.assertTrue(sw.connect(self.controller), \
1589 "Failed to connect to switch" \
1590 )
Howard Pershc7963582012-03-29 10:02:59 -07001591
rootf6af1672012-04-06 09:46:29 -07001592 if num_flows == 0:
1593 # Number of flows requested was 0
1594 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001595
rootf6af1672012-04-06 09:46:29 -07001596 for ts in sw.tbl_stats.stats:
1597 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001598
Rich Lane9a003812012-10-04 17:17:59 -07001599 logging.info("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001600
1601 # Dream up some flow information, i.e. space to chose from for
1602 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001603
rootf6af1672012-04-06 09:46:29 -07001604 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001605 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001606
rootf6af1672012-04-06 09:46:29 -07001607 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001608
rootf6af1672012-04-06 09:46:29 -07001609 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001610 ft.rand(required_wildcards(self), sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001611
rootf6af1672012-04-06 09:46:29 -07001612 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001613
Rich Lane9a003812012-10-04 17:17:59 -07001614 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001615 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001616 logging.info("Adding flow:")
1617 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001618 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001619
rootf6af1672012-04-06 09:46:29 -07001620 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001621
rootf6af1672012-04-06 09:46:29 -07001622 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001623
rootf6af1672012-04-06 09:46:29 -07001624 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001625
Howard Persh9cab4822012-09-11 17:08:40 -07001626 sw.settle() # Allow switch to settle and generate any notifications
1627
rootf6af1672012-04-06 09:46:29 -07001628 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001629
rootf6af1672012-04-06 09:46:29 -07001630 if not sw.errors_verify(0):
1631 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001632
rootf6af1672012-04-06 09:46:29 -07001633 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001634
rootf6af1672012-04-06 09:46:29 -07001635 sw.flow_tbl = ft
1636 if not sw.flow_tbl_verify():
1637 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001638
rootf6af1672012-04-06 09:46:29 -07001639 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001640 logging.info("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001641
Howard Pershc7963582012-03-29 10:02:59 -07001642
Howard Persh07d99e62012-04-09 15:26:57 -07001643# FLOW ADD 5_1
1644#
1645# OVERVIEW
1646# Verify handling of non-canonical flows
1647#
1648# PURPOSE
1649# - Test that switch detects and correctly responds to a non-canonical flow
1650# definition. A canonical flow is one that satisfies all match qualifier
1651# dependencies; a non-canonical flow is one that does not.
1652#
1653# PARAMETERS
1654# - None
1655#
1656# PROCESS
1657# 1. Delete all flows from switch
1658# 2. Generate 1 flow definition, which is different from its canonicalization
1659# 3. Send flow to switch
1660# 4. Retrieve flow from switch
1661# 5. Compare returned flow to canonical form of defined flow
1662# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1663
1664# Disabled.
1665# Should be DUT dependent.
Howard Persh07d99e62012-04-09 15:26:57 -07001666
Rich Lane0a4f6372013-01-02 14:40:22 -08001667@nonstandard
Rich Laneb90a1c42012-10-05 09:16:05 -07001668class Flow_Add_5_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001669 """
1670 Test FLOW_ADD_5.1 from draft top-half test plan
1671
1672 INPUTS
1673 None
1674 """
Rich Laned1d9c282012-10-04 22:07:10 -07001675
rootf6af1672012-04-06 09:46:29 -07001676 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001677 logging.info("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001678
Rich Lane2014f9b2012-10-05 15:29:40 -07001679 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001680
1681 # Clear all flows from switch
1682
Rich Lane9a003812012-10-04 17:17:59 -07001683 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001684 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001685
1686 # Get switch capabilites
1687
rootf6af1672012-04-06 09:46:29 -07001688 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001689 self.assertTrue(sw.connect(self.controller), \
1690 "Failed to connect to switch" \
1691 )
rootf6af1672012-04-06 09:46:29 -07001692
1693 # Dream up some flow information, i.e. space to chose from for
1694 # random flow parameter generation
1695
1696 fi = Flow_Info()
1697 fi.rand(10)
1698
1699 # Dream up a flow config that will be canonicalized by the switch
1700
1701 while True:
1702 fc = Flow_Cfg()
1703 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001704 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07001705 sw.tbl_stats.stats[0].wildcards, \
1706 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001707 sw.valid_ports, \
1708 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001709 )
1710 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001711 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001712 break
1713
1714 ft = Flow_Tbl()
1715 ft.insert(fcc)
1716
1717 # Send it to the switch
1718
Rich Lane9a003812012-10-04 17:17:59 -07001719 logging.info("Sending flow add to switch:")
1720 logging.info(str(fc))
1721 logging.info("should be canonicalized as:")
1722 logging.info(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001723 fc.send_rem = False
1724 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1725
1726 # Do barrier, to make sure all flows are in
1727
1728 self.assertTrue(sw.barrier(), "Barrier failed")
1729
1730 result = True
1731
Howard Persh9cab4822012-09-11 17:08:40 -07001732 sw.settle() # Allow switch to settle and generate any notifications
1733
rootf6af1672012-04-06 09:46:29 -07001734 # Check for any error messages
1735
1736 if not sw.errors_verify(0):
1737 result = False
1738
1739 # Verify flow table
1740
1741 sw.flow_tbl = ft
1742 if not sw.flow_tbl_verify():
1743 result = False
1744
1745 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001746 logging.info("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001747
1748
Howard Persh07d99e62012-04-09 15:26:57 -07001749# FLOW ADD 6
1750#
1751# OVERVIEW
1752# Test flow table capacity
1753#
1754# PURPOSE
1755# - Test switch can accept as many flow definitions as it claims
1756# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1757# - Test that attempting to create flows beyond capacity does not corrupt
1758# flow table
1759#
1760# PARAMETERS
1761# None
1762#
1763# PROCESS
1764# 1. Delete all flows from switch
1765# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1766# to determine flow table size, N
1767# 3. Generate (N + 1) distinct flow configurations
1768# 4. Send N flow adds to switch, for flows generated in step 3 above
1769# 5. Verify flow table in switch
1770# 6. Send one more flow add to switch
1771# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1772# response was generated by switch, for last flow mod sent
1773# 7. Retrieve flow stats from switch
1774# 8. Verify flow table in switch
1775# 9. Test PASSED iff:
1776# - error message received, for correct flow
1777# - last flow definition sent to switch is not in flow table
1778# else test FAILED
1779
Howard Persh3340d452012-04-06 16:45:21 -07001780# Disabled because of bogus capacity reported by OVS.
1781# Should be DUT dependent.
Howard Persh3340d452012-04-06 16:45:21 -07001782
Rich Lane0a4f6372013-01-02 14:40:22 -08001783@nonstandard
Rich Laneb90a1c42012-10-05 09:16:05 -07001784class Flow_Add_6(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001785 """
1786 Test FLOW_ADD_6 from draft top-half test plan
1787
1788 INPUTS
1789 num_flows - Number of flows to generate
1790 """
Howard Pershc7963582012-03-29 10:02:59 -07001791
1792 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001793 logging.info("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001794
rootf6af1672012-04-06 09:46:29 -07001795 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001796
Rich Lane9a003812012-10-04 17:17:59 -07001797 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001798 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001799
1800 # Get switch capabilites
1801
rootf6af1672012-04-06 09:46:29 -07001802 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001803 self.assertTrue(sw.connect(self.controller), \
1804 "Failed to connect to switch" \
1805 )
rootf6af1672012-04-06 09:46:29 -07001806
root2843d2b2012-04-06 10:27:46 -07001807 num_flows = 0
rootf6af1672012-04-06 09:46:29 -07001808 for ts in sw.tbl_stats.stats:
1809 num_flows = num_flows + ts.max_entries
1810
Rich Lane9a003812012-10-04 17:17:59 -07001811 logging.info("Switch capacity is %d flows" % (num_flows))
1812 logging.info("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001813
1814 # Dream up some flow information, i.e. space to chose from for
1815 # random flow parameter generation
1816
1817 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001818 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001819
1820 # Create a flow table, to switch's capacity
1821
1822 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001823 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07001824
1825 # Send flow table to switch
1826
Rich Lane9a003812012-10-04 17:17:59 -07001827 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001828 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001829 logging.info("Adding flow:")
1830 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001831 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1832
1833 # Do barrier, to make sure all flows are in
1834
1835 self.assertTrue(sw.barrier(), "Barrier failed")
1836
1837 result = True
1838
Howard Persh9cab4822012-09-11 17:08:40 -07001839 sw.settle() # Allow switch to settle and generate any notifications
1840
rootf6af1672012-04-06 09:46:29 -07001841 # Check for any error messages
1842
1843 if not sw.errors_verify(0):
1844 result = False
1845
1846 # Dream up one more flow
1847
Rich Lane9a003812012-10-04 17:17:59 -07001848 logging.info("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001849 while True:
1850 fc = Flow_Cfg()
1851 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001852 required_wildcards(self), \
Howard Persh07d99e62012-04-09 15:26:57 -07001853 sw.tbl_stats.stats[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001854 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001855 sw.valid_ports, \
1856 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001857 )
1858 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001859 if not ft.find(fc):
1860 break
rootf6af1672012-04-06 09:46:29 -07001861
1862 # Send one-more flow
1863
1864 fc.send_rem = False
Rich Lane9a003812012-10-04 17:17:59 -07001865 logging.info("Sending flow add switch")
1866 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001867 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1868
1869 # Do barrier, to make sure all flows are in
1870
1871 self.assertTrue(sw.barrier(), "Barrier failed")
1872
Howard Persh9cab4822012-09-11 17:08:40 -07001873 sw.settle() # Allow switch to settle and generate any notifications
1874
rootf6af1672012-04-06 09:46:29 -07001875 # Check for expected error message
1876
1877 if not sw.errors_verify(1, \
1878 ofp.OFPET_FLOW_MOD_FAILED, \
1879 ofp.OFPFMFC_ALL_TABLES_FULL \
1880 ):
1881 result = False
1882
1883 # Verify flow table
1884
1885 sw.flow_tbl = ft
1886 if not sw.flow_tbl_verify():
1887 result = False
1888
1889 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001890 logging.info("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001891
1892
Howard Persh07d99e62012-04-09 15:26:57 -07001893# FLOW ADD 7
1894#
1895# OVERVIEW
1896# Test flow redefinition
1897#
1898# PURPOSE
1899# Verify that successive flow adds with same priority and match criteria
1900# overwrite in flow table
1901#
1902# PARAMETERS
1903# None
1904#
1905# PROCESS
1906# 1. Delete all flows from switch
1907# 2. Generate flow definition F1
1908# 3. Generate flow definition F2, with same key (priority and match) as F1,
1909# but with different actions
1910# 4. Send flow adds for F1 and F2 to switch
1911# 5. Verify flow definitions in switch
1912# 6. Test PASSED iff 1 flow returned by switch, matching configuration of F2;
1913# else test FAILED
1914
Rich Laneb90a1c42012-10-05 09:16:05 -07001915class Flow_Add_7(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001916 """
1917 Test FLOW_ADD_7 from draft top-half test plan
1918
1919 INPUTS
1920 None
1921 """
1922
1923 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001924 logging.info("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001925
1926 # Clear all flows from switch
1927
Rich Lane9a003812012-10-04 17:17:59 -07001928 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001929 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001930
1931 # Get switch capabilites
1932
rootf6af1672012-04-06 09:46:29 -07001933 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001934 self.assertTrue(sw.connect(self.controller), \
1935 "Failed to connect to switch" \
1936 )
rootf6af1672012-04-06 09:46:29 -07001937
1938 # Dream up some flow information, i.e. space to chose from for
1939 # random flow parameter generation
1940
1941 fi = Flow_Info()
1942 fi.rand(10)
1943
1944 # Dream up a flow config
1945
1946 fc = Flow_Cfg()
1947 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001948 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07001949 sw.tbl_stats.stats[0].wildcards, \
1950 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001951 sw.valid_ports, \
1952 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001953 )
1954 fc = fc.canonical()
1955
1956 # Send it to the switch
1957
Rich Lane9a003812012-10-04 17:17:59 -07001958 logging.info("Sending flow add to switch:")
1959 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001960 ft = Flow_Tbl()
1961 fc.send_rem = False
1962 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1963 ft.insert(fc)
1964
1965 # Dream up some different actions, with the same flow key
1966
1967 fc2 = copy.deepcopy(fc)
1968 while True:
1969 fc2.rand_mod(fi, \
1970 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001971 sw.valid_ports, \
1972 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001973 )
1974 if fc2 != fc:
1975 break
1976
1977 # Send that to the switch
1978
Rich Lane9a003812012-10-04 17:17:59 -07001979 logging.info("Sending flow add to switch:")
1980 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07001981 fc2.send_rem = False
1982 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
1983 ft.insert(fc2)
1984
1985 # Do barrier, to make sure all flows are in
1986
1987 self.assertTrue(sw.barrier(), "Barrier failed")
1988
1989 result = True
1990
Howard Persh9cab4822012-09-11 17:08:40 -07001991 sw.settle() # Allow switch to settle and generate any notifications
1992
rootf6af1672012-04-06 09:46:29 -07001993 # Check for any error messages
1994
1995 if not sw.errors_verify(0):
1996 result = False
1997
1998 # Verify flow table
1999
2000 sw.flow_tbl = ft
2001 if not sw.flow_tbl_verify():
2002 result = False
2003
2004 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002005 logging.info("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002006
2007
Howard Persh07d99e62012-04-09 15:26:57 -07002008# FLOW ADD 8
2009#
2010# OVERVIEW
2011# Add overlapping flows to switch, verify that overlapping flows are rejected
2012#
2013# PURPOSE
2014# - Test detection of overlapping flows by switch
2015# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
2016# - Test rejection of overlapping flows
2017# - Test defining overlapping flows does not corrupt flow table
2018#
2019# PARAMETERS
2020# None
2021#
2022# PROCESS
2023# 1. Delete all flows from switch
2024# 2. Generate flow definition F1
2025# 3. Generate flow definition F2, with key overlapping F1
2026# 4. Send flow add to switch, for F1
2027# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
2028# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
2029# was generated by switch
2030# 7. Verifiy flows configured in swtich
2031# 8. Test PASSED iff:
2032# - error message received, for overlapping flow
2033# - overlapping flow is not in flow table
2034# else test FAILED
2035
Rich Laneb90a1c42012-10-05 09:16:05 -07002036class Flow_Add_8(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002037 """
2038 Test FLOW_ADD_8 from draft top-half test plan
2039
2040 INPUTS
2041 None
2042 """
2043
2044 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002045 logging.info("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002046
2047 # Clear all flows from switch
2048
Rich Lane9a003812012-10-04 17:17:59 -07002049 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002050 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002051
2052 # Get switch capabilites
2053
rootf6af1672012-04-06 09:46:29 -07002054 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002055 self.assertTrue(sw.connect(self.controller), \
2056 "Failed to connect to switch" \
2057 )
rootf6af1672012-04-06 09:46:29 -07002058
2059 # Dream up some flow information, i.e. space to chose from for
2060 # random flow parameter generation
2061
2062 fi = Flow_Info()
2063 fi.rand(10)
2064
2065 # Dream up a flow config, with at least 1 qualifier specified
2066
2067 fc = Flow_Cfg()
2068 while True:
2069 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002070 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002071 sw.tbl_stats.stats[0].wildcards, \
2072 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002073 sw.valid_ports, \
2074 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002075 )
2076 fc = fc.canonical()
2077 if fc.match.wildcards != ofp.OFPFW_ALL:
2078 break
2079
2080 # Send it to the switch
2081
Rich Lane9a003812012-10-04 17:17:59 -07002082 logging.info("Sending flow add to switch:")
2083 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002084 ft = Flow_Tbl()
2085 fc.send_rem = False
2086 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2087 ft.insert(fc)
2088
2089 # Wildcard out one qualifier that was specified, to create an
2090 # overlapping flow
2091
2092 fc2 = copy.deepcopy(fc)
2093 for wi in shuffle(range(len(all_wildcards_list))):
2094 w = all_wildcards_list[wi]
2095 if (fc2.match.wildcards & w) == 0:
2096 break
2097 if w == ofp.OFPFW_NW_SRC_MASK:
2098 w = ofp.OFPFW_NW_SRC_ALL
2099 wn = "OFPFW_NW_SRC"
2100 elif w == ofp.OFPFW_NW_DST_MASK:
2101 w = ofp.OFPFW_NW_DST_ALL
2102 wn = "OFPFW_NW_DST"
2103 else:
2104 wn = all_wildcard_names[w]
Rich Lane9a003812012-10-04 17:17:59 -07002105 logging.info("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07002106 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07002107 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07002108
2109 # Send that to the switch, with overlap checking
2110
Rich Lane9a003812012-10-04 17:17:59 -07002111 logging.info("Sending flow add to switch:")
2112 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002113 fc2.send_rem = False
2114 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
2115
2116 # Do barrier, to make sure all flows are in
2117 self.assertTrue(sw.barrier(), "Barrier failed")
2118
2119 result = True
2120
Howard Persh9cab4822012-09-11 17:08:40 -07002121 sw.settle() # Allow switch to settle and generate any notifications
2122
rootf6af1672012-04-06 09:46:29 -07002123 # Check for expected error message
2124
2125 if not sw.errors_verify(1, \
2126 ofp.OFPET_FLOW_MOD_FAILED, \
2127 ofp.OFPFMFC_OVERLAP \
2128 ):
2129 result = False
2130
2131 # Verify flow table
2132
2133 sw.flow_tbl = ft
2134 if not sw.flow_tbl_verify():
2135 result = False
2136
2137 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002138 logging.info("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002139
2140
Howard Persh07d99e62012-04-09 15:26:57 -07002141# FLOW MODIFY 1
2142#
2143# OVERVIEW
2144# Strict modify of single existing flow
2145#
2146# PURPOSE
2147# - Verify that strict flow modify operates only on specified flow
2148# - Verify that flow is correctly modified
2149#
2150# PARAMETERS
2151# None
2152#
2153# PROCESS
2154# 1. Delete all flows from switch
2155# 2. Generate 1 flow F
2156# 3. Send flow add to switch, for flow F
2157# 4. Generate new action list for flow F, yielding F'
2158# 5. Send strict flow modify to switch, for flow F'
2159# 6. Verify flow table in switch
2160# 7. Test PASSED iff flow returned by switch is F'; else FAILED
2161
Rich Laneb90a1c42012-10-05 09:16:05 -07002162class Flow_Mod_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002163 """
2164 Test FLOW_MOD_1 from draft top-half test plan
2165
2166 INPUTS
2167 None
2168 """
2169
2170 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002171 logging.info("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002172
2173 # Clear all flows from switch
2174
Rich Lane9a003812012-10-04 17:17:59 -07002175 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002176 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002177
2178 # Get switch capabilites
2179
rootf6af1672012-04-06 09:46:29 -07002180 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002181 self.assertTrue(sw.connect(self.controller), \
2182 "Failed to connect to switch" \
2183 )
rootf6af1672012-04-06 09:46:29 -07002184
2185 # Dream up some flow information, i.e. space to chose from for
2186 # random flow parameter generation
2187
2188 fi = Flow_Info()
2189 fi.rand(10)
2190
2191 # Dream up a flow config
2192
2193 fc = Flow_Cfg()
2194 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002195 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002196 sw.tbl_stats.stats[0].wildcards, \
2197 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002198 sw.valid_ports, \
2199 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002200 )
2201 fc = fc.canonical()
2202
2203 # Send it to the switch
2204
Rich Lane9a003812012-10-04 17:17:59 -07002205 logging.info("Sending flow add to switch:")
2206 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002207 ft = Flow_Tbl()
2208 fc.send_rem = False
2209 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2210 ft.insert(fc)
2211
2212 # Dream up some different actions, with the same flow key
2213
2214 fc2 = copy.deepcopy(fc)
2215 while True:
2216 fc2.rand_mod(fi, \
2217 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002218 sw.valid_ports, \
2219 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002220 )
2221 if fc2 != fc:
2222 break
2223
2224 # Send that to the switch
2225
Rich Lane9a003812012-10-04 17:17:59 -07002226 logging.info("Sending strict flow mod to switch:")
2227 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002228 fc2.send_rem = False
2229 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2230 ft.insert(fc2)
2231
2232 # Do barrier, to make sure all flows are in
2233
2234 self.assertTrue(sw.barrier(), "Barrier failed")
2235
2236 result = True
2237
Howard Persh9cab4822012-09-11 17:08:40 -07002238 sw.settle() # Allow switch to settle and generate any notifications
2239
rootf6af1672012-04-06 09:46:29 -07002240 # Check for any error messages
2241
2242 if not sw.errors_verify(0):
2243 result = False
2244
2245 # Verify flow table
2246
2247 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002248 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002249 result = False
2250
2251 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002252 logging.info("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002253
Howard Persh07d99e62012-04-09 15:26:57 -07002254
2255# FLOW MODIFY 2
2256#
2257# OVERVIEW
2258# Loose modify of mutiple flows
2259#
2260# PURPOSE
2261# - Verify that loose flow modify operates only on matching flows
2262# - Verify that matching flows are correctly modified
2263#
2264# PARAMETERS
2265# Name: num_flows
2266# Type: number
2267# Description:
2268# Number of flows to define
2269# Default: 100
2270#
2271# PROCESS
2272# 1. Delete all flows from switch
2273# 2. Generate <num_flows> distinct flow configurations
2274# 3. Send <num_flows> flow adds to switch
2275# 4. Pick 1 defined flow F at random
2276# 5. Create overlapping loose flow mod match criteria by repeatedly
2277# wildcarding out qualifiers in match of F => F',
2278# and create new actions list A' for F'
2279# 6. Send loose flow modify for F' to switch
2280# 7. Verify flow table in swtich
2281# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2282# are returned in step 7 above, each with correct (original or modified)
2283# action list;
2284# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002285
Rich Laneb90a1c42012-10-05 09:16:05 -07002286class Flow_Mod_2(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002287 """
2288 Test FLOW_MOD_2 from draft top-half test plan
2289
2290 INPUTS
2291 None
2292 """
2293
2294 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002295 logging.info("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002296
Rich Lane2014f9b2012-10-05 15:29:40 -07002297 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002298
2299 # Clear all flows from switch
2300
Rich Lane9a003812012-10-04 17:17:59 -07002301 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002302 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002303
2304 # Get switch capabilites
2305
rootf6af1672012-04-06 09:46:29 -07002306 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002307 self.assertTrue(sw.connect(self.controller), \
2308 "Failed to connect to switch" \
2309 )
rootf6af1672012-04-06 09:46:29 -07002310
2311 # Dream up some flow information, i.e. space to chose from for
2312 # random flow parameter generation
2313
2314 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002315 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002316 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002317
2318 # Dream up some flows
2319
2320 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002321 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002322
2323 # Send flow table to switch
2324
Rich Lane9a003812012-10-04 17:17:59 -07002325 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002326 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002327 logging.info("Adding flow:")
2328 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002329 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2330
2331 # Do barrier, to make sure all flows are in
2332
2333 self.assertTrue(sw.barrier(), "Barrier failed")
2334
2335 result = True
2336
Howard Persh9cab4822012-09-11 17:08:40 -07002337 sw.settle() # Allow switch to settle and generate any notifications
2338
rootf6af1672012-04-06 09:46:29 -07002339 # Check for any error messages
2340
2341 if not sw.errors_verify(0):
2342 result = False
2343
2344 # Verify flow table
2345
2346 sw.flow_tbl = ft
2347 if not sw.flow_tbl_verify():
2348 result = False
2349
2350 # Pick a random flow as a basis
Howard Persh5f3c83f2012-04-13 09:57:10 -07002351
2352 mfc = copy.deepcopy((ft.values())[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002353 mfc.rand_mod(fi, \
2354 sw.sw_features.actions, \
2355 sw.valid_ports, \
2356 sw.valid_queues \
2357 )
rootf6af1672012-04-06 09:46:29 -07002358
2359 # Repeatedly wildcard qualifiers
2360
2361 for wi in shuffle(range(len(all_wildcards_list))):
2362 w = all_wildcards_list[wi]
2363 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2364 n = wildcard_get(mfc.match.wildcards, w)
2365 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002366 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2367 w, \
2368 random.randint(n + 1, 32) \
2369 )
rootf6af1672012-04-06 09:46:29 -07002370 else:
2371 continue
2372 else:
2373 if wildcard_get(mfc.match.wildcards, w) == 0:
2374 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2375 else:
2376 continue
2377 mfc = mfc.canonical()
2378
2379 # Count the number of flows that would be modified
2380
2381 n = 0
2382 for fc in ft.values():
2383 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2384 n = n + 1
2385
2386 # If more than 1, we found our loose delete flow spec
2387 if n > 1:
2388 break
2389
Rich Lane9a003812012-10-04 17:17:59 -07002390 logging.info("Modifying %d flows" % (n))
2391 logging.info("Sending flow mod to switch:")
2392 logging.info(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002393 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2394
2395 # Do barrier, to make sure all flows are in
2396 self.assertTrue(sw.barrier(), "Barrier failed")
2397
Howard Persh9cab4822012-09-11 17:08:40 -07002398 sw.settle() # Allow switch to settle and generate any notifications
2399
rootf6af1672012-04-06 09:46:29 -07002400 # Check for error message
2401
2402 if not sw.errors_verify(0):
2403 result = False
2404
2405 # Apply flow mod to local flow table
2406
2407 for fc in ft.values():
2408 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002409 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002410
2411 # Verify flow table
2412
2413 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002414 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002415 result = False
2416
2417 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002418 logging.info("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002419
2420
Howard Persh07d99e62012-04-09 15:26:57 -07002421# FLOW MODIFY 3
2422
2423# OVERVIEW
2424# Strict modify of non-existent flow
2425#
2426# PURPOSE
2427# Verify that strict modify of a non-existent flow is equivalent to a flow add
2428#
2429# PARAMETERS
2430# None
2431#
2432# PROCESS
2433# 1. Delete all flows from switch
2434# 2. Send single flow mod, as strict modify, to switch
2435# 3. Verify flow table in switch
2436# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2437
Rich Laneb90a1c42012-10-05 09:16:05 -07002438class Flow_Mod_3(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002439 """
2440 Test FLOW_MOD_3 from draft top-half test plan
2441
2442 INPUTS
2443 None
2444 """
2445
2446 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002447 logging.info("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002448
2449 # Clear all flows from switch
2450
Rich Lane9a003812012-10-04 17:17:59 -07002451 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002452 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002453
2454 # Get switch capabilites
2455
rootf6af1672012-04-06 09:46:29 -07002456 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002457 self.assertTrue(sw.connect(self.controller), \
2458 "Failed to connect to switch" \
2459 )
rootf6af1672012-04-06 09:46:29 -07002460
2461 # Dream up some flow information, i.e. space to chose from for
2462 # random flow parameter generation
2463
2464 fi = Flow_Info()
2465 fi.rand(10)
2466
2467 # Dream up a flow config
2468
2469 fc = Flow_Cfg()
2470 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002471 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002472 sw.tbl_stats.stats[0].wildcards, \
2473 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002474 sw.valid_ports, \
2475 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002476 )
2477 fc = fc.canonical()
2478
2479 # Send it to the switch
2480
Rich Lane9a003812012-10-04 17:17:59 -07002481 logging.info("Sending flow mod to switch:")
2482 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002483 ft = Flow_Tbl()
2484 fc.send_rem = False
2485 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2486 ft.insert(fc)
2487
2488 # Do barrier, to make sure all flows are in
2489
2490 self.assertTrue(sw.barrier(), "Barrier failed")
2491
2492 result = True
2493
Howard Persh9cab4822012-09-11 17:08:40 -07002494 sw.settle() # Allow switch to settle and generate any notifications
2495
rootf6af1672012-04-06 09:46:29 -07002496 # Check for any error messages
2497
2498 if not sw.errors_verify(0):
2499 result = False
2500
2501 # Verify flow table
2502
2503 sw.flow_tbl = ft
2504 if not sw.flow_tbl_verify():
2505 result = False
2506
2507 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002508 logging.info("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002509
2510
Howard Persh8d21c1f2012-04-20 15:57:29 -07002511# FLOW MODIFY 3_1
2512
2513# OVERVIEW
2514# No-op modify
2515#
2516# PURPOSE
2517# Verify that modify of a flow with new actions same as old ones operates correctly
2518#
2519# PARAMETERS
2520# None
2521#
2522# PROCESS
2523# 1. Delete all flows from switch
2524# 2. Send single flow mod, as strict modify, to switch
2525# 3. Verify flow table in switch
2526# 4. Send same flow mod, as strict modify, to switch
2527# 5. Verify flow table in switch
2528# 6. Test PASSED iff flow defined in step 2 and 4 above verified; else FAILED
2529
Rich Laneb90a1c42012-10-05 09:16:05 -07002530class Flow_Mod_3_1(base_tests.SimpleProtocol):
Howard Persh8d21c1f2012-04-20 15:57:29 -07002531 """
2532 Test FLOW_MOD_3_1 from draft top-half test plan
2533
2534 INPUTS
2535 None
2536 """
2537
2538 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002539 logging.info("Flow_Mod_3_1 TEST BEGIN")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002540
2541 # Clear all flows from switch
2542
Rich Lane9a003812012-10-04 17:17:59 -07002543 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002544 delete_all_flows(self.controller)
Howard Persh8d21c1f2012-04-20 15:57:29 -07002545
2546 # Get switch capabilites
2547
2548 sw = Switch()
2549 self.assertTrue(sw.connect(self.controller), \
2550 "Failed to connect to switch" \
2551 )
2552
2553 # Dream up some flow information, i.e. space to chose from for
2554 # random flow parameter generation
2555
2556 fi = Flow_Info()
2557 fi.rand(10)
2558
2559 # Dream up a flow config
2560
2561 fc = Flow_Cfg()
2562 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002563 required_wildcards(self), \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002564 sw.tbl_stats.stats[0].wildcards, \
2565 sw.sw_features.actions, \
2566 sw.valid_ports, \
2567 sw.valid_queues \
2568 )
2569 fc = fc.canonical()
2570
2571 # Send it to the switch
2572
Rich Lane9a003812012-10-04 17:17:59 -07002573 logging.info("Sending flow mod to switch:")
2574 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002575 ft = Flow_Tbl()
2576 fc.send_rem = False
2577 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2578 ft.insert(fc)
2579
2580 # Do barrier, to make sure all flows are in
2581
2582 self.assertTrue(sw.barrier(), "Barrier failed")
2583
2584 result = True
2585
Howard Persh9cab4822012-09-11 17:08:40 -07002586 sw.settle() # Allow switch to settle and generate any notifications
2587
Howard Persh8d21c1f2012-04-20 15:57:29 -07002588 # Check for any error messages
2589
2590 if not sw.errors_verify(0):
2591 result = False
2592
2593 # Verify flow table
2594
2595 sw.flow_tbl = ft
2596 if not sw.flow_tbl_verify():
2597 result = False
2598
2599 # Send same flow to the switch again
2600
Rich Lane9a003812012-10-04 17:17:59 -07002601 logging.info("Sending flow mod to switch:")
2602 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002603 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2604
2605 # Do barrier, to make sure all flows are in
2606
2607 self.assertTrue(sw.barrier(), "Barrier failed")
2608
Howard Persh9cab4822012-09-11 17:08:40 -07002609 sw.settle() # Allow switch to settle and generate any notifications
2610
Howard Persh8d21c1f2012-04-20 15:57:29 -07002611 # Check for any error messages
2612
2613 if not sw.errors_verify(0):
2614 result = False
2615
2616 # Verify flow table
2617
2618 if not sw.flow_tbl_verify():
2619 result = False
2620
2621 self.assertTrue(result, "Flow_Mod_3_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002622 logging.info("Flow_Mod_3_1 TEST PASSED")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002623
2624
Howard Persh07d99e62012-04-09 15:26:57 -07002625# FLOW DELETE 1
2626#
2627# OVERVIEW
2628# Strict delete of single flow
2629#
2630# PURPOSE
2631# Verify correct operation of strict delete of single defined flow
2632#
2633# PARAMETERS
2634# None
2635#
2636# PROCESS
2637# 1. Delete all flows from switch
2638# 2. Send flow F to switch
2639# 3. Send strict flow delete for F to switch
2640# 4. Verify flow table in swtich
2641# 6. Test PASSED iff all flows sent to switch in step 2 above,
2642# less flow removed in step 3 above, are returned in step 4 above;
2643# else test FAILED
2644
Rich Laneb90a1c42012-10-05 09:16:05 -07002645class Flow_Del_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002646 """
2647 Test FLOW_DEL_1 from draft top-half test plan
2648
2649 INPUTS
2650 None
2651 """
2652
2653 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002654 logging.info("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002655
2656 # Clear all flows from switch
2657
Rich Lane9a003812012-10-04 17:17:59 -07002658 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002659 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002660
2661 # Get switch capabilites
2662
rootf6af1672012-04-06 09:46:29 -07002663 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002664 self.assertTrue(sw.connect(self.controller), \
2665 "Failed to connect to switch" \
2666 )
rootf6af1672012-04-06 09:46:29 -07002667
2668 # Dream up some flow information, i.e. space to chose from for
2669 # random flow parameter generation
2670
2671 fi = Flow_Info()
2672 fi.rand(10)
2673
2674 # Dream up a flow config
2675
2676 fc = Flow_Cfg()
2677 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002678 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002679 sw.tbl_stats.stats[0].wildcards, \
2680 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002681 sw.valid_ports, \
2682 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002683 )
2684 fc = fc.canonical()
2685
2686 # Send it to the switch
2687
Rich Lane9a003812012-10-04 17:17:59 -07002688 logging.info("Sending flow add to switch:")
2689 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002690 ft = Flow_Tbl()
2691 fc.send_rem = False
2692 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2693 ft.insert(fc)
2694
2695 # Dream up some different actions, with the same flow key
2696
2697 fc2 = copy.deepcopy(fc)
2698 while True:
2699 fc2.rand_mod(fi, \
2700 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002701 sw.valid_ports, \
2702 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002703 )
2704 if fc2 != fc:
2705 break
2706
2707 # Delete strictly
2708
Rich Lane9a003812012-10-04 17:17:59 -07002709 logging.info("Sending strict flow del to switch:")
2710 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002711 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2712 ft.delete(fc)
2713
2714 # Do barrier, to make sure all flows are in
2715
2716 self.assertTrue(sw.barrier(), "Barrier failed")
2717
2718 result = True
2719
Howard Persh9cab4822012-09-11 17:08:40 -07002720 sw.settle() # Allow switch to settle and generate any notifications
2721
rootf6af1672012-04-06 09:46:29 -07002722 # Check for any error messages
2723
2724 if not sw.errors_verify(0):
2725 result = False
2726
2727 # Verify flow table
2728
2729 sw.flow_tbl = ft
2730 if not sw.flow_tbl_verify():
2731 result = False
2732
2733 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002734 logging.info("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002735
2736
Howard Persh07d99e62012-04-09 15:26:57 -07002737# FLOW DELETE 2
2738#
2739# OVERVIEW
2740# Loose delete of multiple flows
2741#
2742# PURPOSE
2743# - Verify correct operation of loose delete of multiple flows
2744#
2745# PARAMETERS
2746# Name: num_flows
2747# Type: number
2748# Description:
2749# Number of flows to define
2750# Default: 100
2751#
2752# PROCESS
2753# 1. Delete all flows from switch
2754# 2. Generate <num_flows> distinct flow configurations
2755# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2756# 4. Pick 1 defined flow F at random
2757# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2758# F' will match more than 1 existing flow key
2759# 6. Send loose flow delete for F' to switch
2760# 7. Verify flow table in switch
2761# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2762# removed in step 6 above (i.e. those that match F'), are returned
2763# in step 7 above;
2764# else test FAILED
2765
Rich Laneb90a1c42012-10-05 09:16:05 -07002766class Flow_Del_2(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002767 """
2768 Test FLOW_DEL_2 from draft top-half test plan
2769
2770 INPUTS
2771 None
2772 """
2773
2774 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002775 logging.info("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002776
Rich Lane2014f9b2012-10-05 15:29:40 -07002777 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002778
2779 # Clear all flows from switch
2780
Rich Lane9a003812012-10-04 17:17:59 -07002781 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002782 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002783
2784 # Get switch capabilites
2785
rootf6af1672012-04-06 09:46:29 -07002786 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002787 self.assertTrue(sw.connect(self.controller), \
2788 "Failed to connect to switch" \
2789 )
rootf6af1672012-04-06 09:46:29 -07002790
2791 # Dream up some flow information, i.e. space to chose from for
2792 # random flow parameter generation
2793
2794 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002795 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002796 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002797
2798 # Dream up some flows
2799
2800 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002801 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002802
2803 # Send flow table to switch
2804
Rich Lane9a003812012-10-04 17:17:59 -07002805 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002806 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002807 logging.info("Adding flow:")
2808 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002809 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2810
2811 # Do barrier, to make sure all flows are in
2812
2813 self.assertTrue(sw.barrier(), "Barrier failed")
2814
2815 result = True
2816
Howard Persh9cab4822012-09-11 17:08:40 -07002817 sw.settle() # Allow switch to settle and generate any notifications
2818
rootf6af1672012-04-06 09:46:29 -07002819 # Check for any error messages
2820
2821 if not sw.errors_verify(0):
2822 result = False
2823
2824 # Verify flow table
2825
2826 sw.flow_tbl = ft
2827 if not sw.flow_tbl_verify():
2828 result = False
2829
2830 # Pick a random flow as a basis
2831
2832 dfc = copy.deepcopy(ft.values()[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002833 dfc.rand_mod(fi, \
2834 sw.sw_features.actions, \
2835 sw.valid_ports, \
2836 sw.valid_queues \
2837 )
rootf6af1672012-04-06 09:46:29 -07002838
2839 # Repeatedly wildcard qualifiers
2840
2841 for wi in shuffle(range(len(all_wildcards_list))):
2842 w = all_wildcards_list[wi]
2843 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2844 n = wildcard_get(dfc.match.wildcards, w)
2845 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002846 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2847 w, \
2848 random.randint(n + 1, 32) \
2849 )
rootf6af1672012-04-06 09:46:29 -07002850 else:
2851 continue
2852 else:
2853 if wildcard_get(dfc.match.wildcards, w) == 0:
2854 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2855 else:
2856 continue
2857 dfc = dfc.canonical()
2858
2859 # Count the number of flows that would be deleted
2860
2861 n = 0
2862 for fc in ft.values():
2863 if dfc.overlaps(fc, True):
2864 n = n + 1
2865
2866 # If more than 1, we found our loose delete flow spec
2867 if n > 1:
2868 break
2869
Rich Lane9a003812012-10-04 17:17:59 -07002870 logging.info("Deleting %d flows" % (n))
2871 logging.info("Sending flow del to switch:")
2872 logging.info(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002873 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2874
2875 # Do barrier, to make sure all flows are in
2876 self.assertTrue(sw.barrier(), "Barrier failed")
2877
Howard Persh9cab4822012-09-11 17:08:40 -07002878 sw.settle() # Allow switch to settle and generate any notifications
2879
rootf6af1672012-04-06 09:46:29 -07002880 # Check for error message
2881
2882 if not sw.errors_verify(0):
2883 result = False
2884
2885 # Apply flow mod to local flow table
2886
2887 for fc in ft.values():
2888 if dfc.overlaps(fc, True):
2889 ft.delete(fc)
2890
2891 # Verify flow table
2892
2893 sw.flow_tbl = ft
2894 if not sw.flow_tbl_verify():
2895 result = False
2896
2897 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002898 logging.info("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002899
2900
Howard Persh07d99e62012-04-09 15:26:57 -07002901# FLOW DELETE 4
2902#
2903# OVERVIEW
2904# Flow removed messages
2905#
2906# PURPOSE
2907# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2908# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2909#
2910# PARAMETERS
2911# None
2912#
2913# PROCESS
2914# 1. Delete all flows from switch
2915# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2916# 3. Send strict flow delete of flow to switch
2917# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2918# 5. Verify flow table in switch
2919# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2920# removed in step 3 above, are returned in step 5 above, and that
2921# asynch message was received; else test FAILED
2922
2923
Rich Laneb90a1c42012-10-05 09:16:05 -07002924class Flow_Del_4(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002925 """
2926 Test FLOW_DEL_4 from draft top-half test plan
2927
2928 INPUTS
2929 None
2930 """
2931
2932 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002933 logging.info("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002934
2935 # Clear all flows from switch
2936
Rich Lane9a003812012-10-04 17:17:59 -07002937 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002938 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002939
2940 # Get switch capabilites
2941
rootf6af1672012-04-06 09:46:29 -07002942 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002943 self.assertTrue(sw.connect(self.controller), \
2944 "Failed to connect to switch" \
2945 )
rootf6af1672012-04-06 09:46:29 -07002946
2947 # Dream up some flow information, i.e. space to chose from for
2948 # random flow parameter generation
2949
2950 fi = Flow_Info()
2951 fi.rand(10)
2952
2953 # Dream up a flow config
2954
2955 fc = Flow_Cfg()
2956 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002957 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002958 sw.tbl_stats.stats[0].wildcards, \
2959 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002960 sw.valid_ports, \
2961 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002962 )
2963 fc = fc.canonical()
2964
2965 # Send it to the switch. with "notify on removed"
2966
Rich Lane9a003812012-10-04 17:17:59 -07002967 logging.info("Sending flow add to switch:")
2968 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002969 ft = Flow_Tbl()
2970 fc.send_rem = True
2971 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2972 ft.insert(fc)
2973
2974 # Dream up some different actions, with the same flow key
2975
2976 fc2 = copy.deepcopy(fc)
2977 while True:
2978 fc2.rand_mod(fi, \
2979 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002980 sw.valid_ports, \
2981 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002982 )
2983 if fc2 != fc:
2984 break
2985
2986 # Delete strictly
2987
Rich Lane9a003812012-10-04 17:17:59 -07002988 logging.info("Sending strict flow del to switch:")
2989 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002990 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2991 ft.delete(fc)
2992
2993 # Do barrier, to make sure all flows are in
2994
2995 self.assertTrue(sw.barrier(), "Barrier failed")
2996
2997 result = True
2998
Howard Persh9cab4822012-09-11 17:08:40 -07002999 sw.settle() # Allow switch to settle and generate any notifications
3000
rootf6af1672012-04-06 09:46:29 -07003001 # Check for expected "removed" message
3002
Howard Persh3340d452012-04-06 16:45:21 -07003003 if not sw.errors_verify(0):
3004 result = False
3005
3006 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07003007 result = False
3008
3009 # Verify flow table
3010
3011 sw.flow_tbl = ft
3012 if not sw.flow_tbl_verify():
3013 result = False
3014
3015 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07003016 logging.info("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07003017