blob: 0bbf3ee515cca54209ae81434a811d3ad15238e7 [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.action_list as action_list
73import oftest.parse as parse
74import pktact
Rich Laneb90a1c42012-10-05 09:16:05 -070075import oftest.base_tests as base_tests
Howard Pershc7963582012-03-29 10:02:59 -070076
Rich Laneda3b5ad2012-10-03 09:05:32 -070077from oftest.testutils import *
Howard Pershc7963582012-03-29 10:02:59 -070078from time import sleep
79
Howard Pershc7963582012-03-29 10:02:59 -070080
rootf6af1672012-04-06 09:46:29 -070081def flip_coin():
82 return random.randint(1, 100) <= 50
83
84
Howard Pershc7963582012-03-29 10:02:59 -070085def shuffle(list):
86 n = len(list)
87 lim = n * n
88 i = 0
89 while i < lim:
90 a = random.randint(0, n - 1)
91 b = random.randint(0, n - 1)
92 temp = list[a]
93 list[a] = list[b]
94 list[b] = temp
95 i = i + 1
96 return list
97
98
Howard Persh680b92a2012-03-31 13:34:35 -070099def rand_pick(list):
100 return list[random.randint(0, len(list) - 1)]
Howard Pershc7963582012-03-29 10:02:59 -0700101
Howard Persh680b92a2012-03-31 13:34:35 -0700102def rand_dl_addr():
103 return [random.randint(0, 255) & ~1,
104 random.randint(0, 255),
105 random.randint(0, 255),
106 random.randint(0, 255),
107 random.randint(0, 255),
108 random.randint(0, 255)
109 ]
Howard Pershc7963582012-03-29 10:02:59 -0700110
111def rand_nw_addr():
112 return random.randint(0, (1 << 32) - 1)
113
114
rootf6af1672012-04-06 09:46:29 -0700115class Flow_Info:
Howard Persh680b92a2012-03-31 13:34:35 -0700116 # Members:
117 # priorities - list of flow priorities
118 # dl_addrs - list of MAC addresses
119 # vlans - list of VLAN ids
120 # ethertypes - list of Ethertypes
121 # ip_addrs - list of IP addresses
122 # ip_tos - list of IP TOS values
123 # ip_protos - list of IP protocols
124 # l4_ports - list of L4 ports
125
126 def __init__(self):
127 priorities = []
128 dl_addrs = []
129 vlans = []
130 ethertypes = []
131 ip_addrs = []
132 ip_tos = []
133 ip_protos = []
134 l4_ports = []
135
136 def rand(self, n):
137 self.priorities = []
138 i = 0
139 while i < n:
140 self.priorities.append(random.randint(1, 65534))
141 i = i + 1
142
143 self.dl_addrs = []
144 i = 0
145 while i < n:
146 self.dl_addrs.append(rand_dl_addr())
147 i = i + 1
148
Rich Lane2014f9b2012-10-05 15:29:40 -0700149 if test_param_get("vlans", []) != []:
150 self.vlans = test_param_get("vlans", [])
Howard Pershb10a47a2012-08-21 13:54:47 -0700151
Rich Lane9a003812012-10-04 17:17:59 -0700152 logging.info("Overriding VLAN ids to:")
153 logging.info(self.vlans)
Howard Pershb10a47a2012-08-21 13:54:47 -0700154 else:
155 self.vlans = []
156 i = 0
157 while i < n:
158 self.vlans.append(random.randint(1, 4094))
159 i = i + 1
Howard Persh680b92a2012-03-31 13:34:35 -0700160
rootf6af1672012-04-06 09:46:29 -0700161 self.ethertypes = [0x0800, 0x0806]
Howard Persh680b92a2012-03-31 13:34:35 -0700162 i = 0
163 while i < n:
164 self.ethertypes.append(random.randint(0, (1 << 16) - 1))
165 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700166 self.ethertypes = shuffle(self.ethertypes)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700167
168 self.ip_addrs = []
169 i = 0
170 while i < n:
171 self.ip_addrs.append(rand_nw_addr())
172 i = i + 1
173
174 self.ip_tos = []
175 i = 0
176 while i < n:
177 self.ip_tos.append(random.randint(0, (1 << 8) - 1) & ~3)
178 i = i + 1
179
rootf6af1672012-04-06 09:46:29 -0700180 self.ip_protos = [1, 6, 17]
Howard Persh680b92a2012-03-31 13:34:35 -0700181 i = 0
182 while i < n:
183 self.ip_protos.append(random.randint(0, (1 << 8) - 1))
184 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700185 self.ip_protos = shuffle(self.ip_protos)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700186
187 self.l4_ports = []
188 i = 0
189 while i < n:
190 self.l4_ports.append(random.randint(0, (1 << 16) - 1))
191 i = i + 1
192
193 def rand_priority(self):
194 return rand_pick(self.priorities)
195
196 def rand_dl_addr(self):
197 return rand_pick(self.dl_addrs)
198
199 def rand_vlan(self):
200 return rand_pick(self.vlans)
201
202 def rand_ethertype(self):
203 return rand_pick(self.ethertypes)
204
205 def rand_ip_addr(self):
206 return rand_pick(self.ip_addrs)
207
208 def rand_ip_tos(self):
209 return rand_pick(self.ip_tos)
210
211 def rand_ip_proto(self):
212 return rand_pick(self.ip_protos)
213
214 def rand_l4_port(self):
215 return rand_pick(self.l4_ports)
216
217
Howard Pershc7963582012-03-29 10:02:59 -0700218# TBD - These don't belong here
219
Howard Persh680b92a2012-03-31 13:34:35 -0700220all_wildcards_list = [ofp.OFPFW_IN_PORT,
Howard Persh680b92a2012-03-31 13:34:35 -0700221 ofp.OFPFW_DL_DST,
rootf6af1672012-04-06 09:46:29 -0700222 ofp.OFPFW_DL_SRC,
223 ofp.OFPFW_DL_VLAN,
224 ofp.OFPFW_DL_VLAN_PCP,
Howard Persh680b92a2012-03-31 13:34:35 -0700225 ofp.OFPFW_DL_TYPE,
rootf6af1672012-04-06 09:46:29 -0700226 ofp.OFPFW_NW_TOS,
Howard Persh680b92a2012-03-31 13:34:35 -0700227 ofp.OFPFW_NW_PROTO,
Howard Persh680b92a2012-03-31 13:34:35 -0700228 ofp.OFPFW_NW_SRC_MASK,
229 ofp.OFPFW_NW_DST_MASK,
rootf6af1672012-04-06 09:46:29 -0700230 ofp.OFPFW_TP_SRC,
231 ofp.OFPFW_TP_DST
Howard Persh680b92a2012-03-31 13:34:35 -0700232 ]
Howard Pershc7963582012-03-29 10:02:59 -0700233
Howard Persh3340d452012-04-06 16:45:21 -0700234# TBD - Need this because there are duplicates in ofp.ofp_flow_wildcards_map
235# -- FIX
rootf6af1672012-04-06 09:46:29 -0700236all_wildcard_names = {
237 1 : 'OFPFW_IN_PORT',
238 2 : 'OFPFW_DL_VLAN',
239 4 : 'OFPFW_DL_SRC',
240 8 : 'OFPFW_DL_DST',
241 16 : 'OFPFW_DL_TYPE',
242 32 : 'OFPFW_NW_PROTO',
243 64 : 'OFPFW_TP_SRC',
244 128 : 'OFPFW_TP_DST',
245 1048576 : 'OFPFW_DL_VLAN_PCP',
246 2097152 : 'OFPFW_NW_TOS'
247}
248
rootf6af1672012-04-06 09:46:29 -0700249def wildcard_set(x, w, val):
250 result = x
251 if w == ofp.OFPFW_NW_SRC_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700252 result = (result & ~ofp.OFPFW_NW_SRC_MASK) \
253 | (val << ofp.OFPFW_NW_SRC_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700254 elif w == ofp.OFPFW_NW_DST_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700255 result = (result & ~ofp.OFPFW_NW_DST_MASK) \
256 | (val << ofp.OFPFW_NW_DST_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700257 elif val == 0:
258 result = result & ~w
259 else:
260 result = result | w
261 return result
262
263def wildcard_get(x, w):
264 if w == ofp.OFPFW_NW_SRC_MASK:
265 return (x & ofp.OFPFW_NW_SRC_MASK) >> ofp.OFPFW_NW_SRC_SHIFT
266 if w == ofp.OFPFW_NW_DST_MASK:
267 return (x & ofp.OFPFW_NW_DST_MASK) >> ofp.OFPFW_NW_DST_SHIFT
268 return 1 if (x & w) != 0 else 0
269
Howard Persh8d21c1f2012-04-20 15:57:29 -0700270def wildcards_to_str(wildcards):
271 result = "{"
272 sep = ""
273 for w in all_wildcards_list:
274 if (wildcards & w) == 0:
275 continue
276 if w == ofp.OFPFW_NW_SRC_MASK:
277 n = wildcard_get(wildcards, w)
278 if n > 0:
279 result = result + sep + ("OFPFW_NW_SRC(%d)" % (n))
280 elif w == ofp.OFPFW_NW_DST_MASK:
281 n = wildcard_get(wildcards, w)
282 if n > 0:
283 result = result + sep + ("OFPFW_NW_DST(%d)" % (n))
284 else:
285 result = result + sep + all_wildcard_names[w]
286 sep = ", "
287 result = result +"}"
288 return result
Howard Pershc7963582012-03-29 10:02:59 -0700289
Howard Persh680b92a2012-03-31 13:34:35 -0700290all_actions_list = [ofp.OFPAT_OUTPUT,
291 ofp.OFPAT_SET_VLAN_VID,
292 ofp.OFPAT_SET_VLAN_PCP,
293 ofp.OFPAT_STRIP_VLAN,
294 ofp.OFPAT_SET_DL_SRC,
295 ofp.OFPAT_SET_DL_DST,
296 ofp.OFPAT_SET_NW_SRC,
297 ofp.OFPAT_SET_NW_DST,
298 ofp.OFPAT_SET_NW_TOS,
299 ofp.OFPAT_SET_TP_SRC,
300 ofp.OFPAT_SET_TP_DST,
301 ofp.OFPAT_ENQUEUE
302 ]
303
Howard Persh8d21c1f2012-04-20 15:57:29 -0700304def actions_bmap_to_str(bm):
305 result = "{"
306 sep = ""
307 for a in all_actions_list:
308 if ((1 << a) & bm) != 0:
309 result = result + sep + ofp.ofp_action_type_map[a]
310 sep = ", "
311 result = result + "}"
312 return result
313
Howard Persh680b92a2012-03-31 13:34:35 -0700314def dl_addr_to_str(a):
315 return "%x:%x:%x:%x:%x:%x" % tuple(a)
316
317def ip_addr_to_str(a, n):
rootf6af1672012-04-06 09:46:29 -0700318 if n is not None:
319 a = a & ~((1 << (32 - n)) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700320 result = "%d.%d.%d.%d" % (a >> 24, \
321 (a >> 16) & 0xff, \
322 (a >> 8) & 0xff, \
323 a & 0xff \
324 )
325 if n is not None:
326 result = result + ("/%d" % (n))
327 return result
328
Howard Pershc7963582012-03-29 10:02:59 -0700329
rootf6af1672012-04-06 09:46:29 -0700330class Flow_Cfg:
Howard Pershc7963582012-03-29 10:02:59 -0700331 # Members:
332 # - match
333 # - idle_timeout
334 # - hard_timeout
335 # - priority
336 # - action_list
337
338 def __init__(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700339 self.priority = 0
Rich Laneed1fa2d2013-01-08 13:23:37 -0800340 self.match = ofp.ofp_match()
Howard Pershc7963582012-03-29 10:02:59 -0700341 self.match.wildcards = ofp.OFPFW_ALL
342 self.idle_timeout = 0
343 self.hard_timeout = 0
Howard Pershc7963582012-03-29 10:02:59 -0700344 self.actions = action_list.action_list()
345
rootf6af1672012-04-06 09:46:29 -0700346 # {pri, match} is considered a flow key
347 def key_equal(self, x):
Howard Persh680b92a2012-03-31 13:34:35 -0700348 if self.priority != x.priority:
349 return False
350 # TBD - Should this logic be moved to ofp_match.__eq__()?
351 if self.match.wildcards != x.match.wildcards:
352 return False
rootf6af1672012-04-06 09:46:29 -0700353 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700354 and self.match.in_port != x.match.in_port:
355 return False
rootf6af1672012-04-06 09:46:29 -0700356 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700357 and self.match.dl_dst != x.match.dl_dst:
358 return False
rootf6af1672012-04-06 09:46:29 -0700359 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0 \
360 and self.match.dl_src != x.match.dl_src:
361 return False
362 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700363 and self.match.dl_vlan != x.match.dl_vlan:
364 return False
rootf6af1672012-04-06 09:46:29 -0700365 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700366 and self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
367 return False
rootf6af1672012-04-06 09:46:29 -0700368 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700369 and self.match.dl_type != x.match.dl_type:
370 return False
rootf6af1672012-04-06 09:46:29 -0700371 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700372 and self.match.nw_tos != x.match.nw_tos:
373 return False
rootf6af1672012-04-06 09:46:29 -0700374 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700375 and self.match.nw_proto != x.match.nw_proto:
376 return False
rootf6af1672012-04-06 09:46:29 -0700377 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
378 if n < 32:
379 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700380 if (self.match.nw_src & m) != (x.match.nw_src & m):
381 return False
rootf6af1672012-04-06 09:46:29 -0700382 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
383 if n < 32:
384 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700385 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
386 return False
rootf6af1672012-04-06 09:46:29 -0700387 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0 \
388 and self.match.tp_src != x.match.tp_src:
Howard Persh680b92a2012-03-31 13:34:35 -0700389 return False
rootf6af1672012-04-06 09:46:29 -0700390 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0 \
391 and self.match.tp_dst != x.match.tp_dst:
392 return False
393 return True
394
Howard Persh5f3c83f2012-04-13 09:57:10 -0700395 def actions_equal(self, x):
Rich Lane2014f9b2012-10-05 15:29:40 -0700396 if test_param_get("conservative_ordered_actions", True):
Howard Persh5f3c83f2012-04-13 09:57:10 -0700397 # Compare actions lists as unordered
398
root2843d2b2012-04-06 10:27:46 -0700399 aa = copy.deepcopy(x.actions.actions)
400 for a in self.actions.actions:
401 i = 0
402 while i < len(aa):
403 if a == aa[i]:
404 break
405 i = i + 1
406 if i < len(aa):
407 aa.pop(i)
408 else:
409 return False
410 return aa == []
411 else:
412 return self.actions == x.actions
Howard Persh5f3c83f2012-04-13 09:57:10 -0700413
414 def non_key_equal(self, x):
415 if self.cookie != x.cookie:
416 return False
417 if self.idle_timeout != x.idle_timeout:
418 return False
419 if self.hard_timeout != x.hard_timeout:
420 return False
421 return self.actions_equal(x)
rootf6af1672012-04-06 09:46:29 -0700422
root2843d2b2012-04-06 10:27:46 -0700423 def key_str(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700424 result = "priority=%d" % self.priority
425 # TBD - Would be nice if ofp_match.show() was better behaved
426 # (no newlines), and more intuitive (things in hex where approprate), etc.
Howard Persh8d21c1f2012-04-20 15:57:29 -0700427 result = result + (", wildcards=0x%x=%s" \
428 % (self.match.wildcards, \
429 wildcards_to_str(self.match.wildcards) \
430 )
431 )
rootf6af1672012-04-06 09:46:29 -0700432 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700433 result = result + (", in_port=%d" % (self.match.in_port))
rootf6af1672012-04-06 09:46:29 -0700434 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700435 result = result + (", dl_dst=%s" \
436 % (dl_addr_to_str(self.match.dl_dst)) \
437 )
rootf6af1672012-04-06 09:46:29 -0700438 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700439 result = result + (", dl_src=%s" \
440 % (dl_addr_to_str(self.match.dl_src)) \
441 )
rootf6af1672012-04-06 09:46:29 -0700442 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700443 result = result + (", dl_vlan=%d" % (self.match.dl_vlan))
rootf6af1672012-04-06 09:46:29 -0700444 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700445 result = result + (", dl_vlan_pcp=%d" % (self.match.dl_vlan_pcp))
rootf6af1672012-04-06 09:46:29 -0700446 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700447 result = result + (", dl_type=0x%x" % (self.match.dl_type))
rootf6af1672012-04-06 09:46:29 -0700448 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700449 result = result + (", nw_tos=0x%x" % (self.match.nw_tos))
rootf6af1672012-04-06 09:46:29 -0700450 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700451 result = result + (", nw_proto=%d" % (self.match.nw_proto))
rootf6af1672012-04-06 09:46:29 -0700452 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700453 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700454 result = result + (", nw_src=%s" % \
455 (ip_addr_to_str(self.match.nw_src, 32 - n)) \
456 )
rootf6af1672012-04-06 09:46:29 -0700457 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700458 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700459 result = result + (", nw_dst=%s" % \
460 (ip_addr_to_str(self.match.nw_dst, 32 - n)) \
461 )
rootf6af1672012-04-06 09:46:29 -0700462 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700463 result = result + (", tp_src=%d" % self.match.tp_src)
rootf6af1672012-04-06 09:46:29 -0700464 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700465 result = result + (", tp_dst=%d" % self.match.tp_dst)
rootf6af1672012-04-06 09:46:29 -0700466 return result
467
468 def __eq__(self, x):
469 return (self.key_equal(x) and self.non_key_equal(x))
470
471 def __str__(self):
root2843d2b2012-04-06 10:27:46 -0700472 result = self.key_str()
473 result = result + (", cookie=%d" % self.cookie)
Howard Persh680b92a2012-03-31 13:34:35 -0700474 result = result + (", idle_timeout=%d" % self.idle_timeout)
475 result = result + (", hard_timeout=%d" % self.hard_timeout)
Howard Persh680b92a2012-03-31 13:34:35 -0700476 for a in self.actions.actions:
477 result = result + (", action=%s" % ofp.ofp_action_type_map[a.type])
478 if a.type == ofp.OFPAT_OUTPUT:
479 result = result + ("(%d)" % (a.port))
480 elif a.type == ofp.OFPAT_SET_VLAN_VID:
481 result = result + ("(%d)" % (a.vlan_vid))
482 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
483 result = result + ("(%d)" % (a.vlan_pcp))
484 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
485 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
486 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
487 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
488 elif a.type == ofp.OFPAT_SET_NW_TOS:
489 result = result + ("(0x%x)" % (a.nw_tos))
490 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
491 result = result + ("(%d)" % (a.tp_port))
492 elif a.type == ofp.OFPAT_ENQUEUE:
493 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
494 return result
Howard Pershc7963582012-03-29 10:02:59 -0700495
Howard Persh8d21c1f2012-04-20 15:57:29 -0700496 def rand_actions_ordered(self, fi, valid_actions, valid_ports, valid_queues):
Howard Persh3340d452012-04-06 16:45:21 -0700497 # Action lists are ordered, so pick an ordered random subset of
498 # supported actions
Howard Pershc1199d52012-04-11 14:21:32 -0700499
Rich Lane2014f9b2012-10-05 15:29:40 -0700500 actions_force = test_param_get("actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700501 if actions_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700502 logging.info("Forced actions:")
503 logging.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700504
Dan Talayco910a8282012-04-07 00:05:20 -0700505 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh3340d452012-04-06 16:45:21 -0700506 supported_actions = []
507 for a in all_actions_list:
508 if ((1 << a) & valid_actions) != 0:
509 supported_actions.append(a)
510
Howard Pershc1199d52012-04-11 14:21:32 -0700511 actions \
512 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
513
514 for a in all_actions_list:
515 if ((1 << a) & actions_force) != 0:
516 actions.append(a)
517
518 actions = shuffle(actions)
Howard Persh3340d452012-04-06 16:45:21 -0700519
Howard Persh6a3698d2012-08-21 14:26:39 -0700520 set_vlanf = False
521 strip_vlanf = False
Howard Persh3340d452012-04-06 16:45:21 -0700522 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700523 for a in actions:
Dan Talayco910a8282012-04-07 00:05:20 -0700524 act = None
Howard Persh3340d452012-04-06 16:45:21 -0700525 if a == ofp.OFPAT_OUTPUT:
526 pass # OUTPUT actions must come last
527 elif a == ofp.OFPAT_SET_VLAN_VID:
Howard Persh6a3698d2012-08-21 14:26:39 -0700528 if not strip_vlanf:
Rich Lane28fa9272013-03-08 16:00:25 -0800529 act = ofp.action.action_set_vlan_vid()
Howard Persh6a3698d2012-08-21 14:26:39 -0700530 act.vlan_vid = fi.rand_vlan()
531 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700532 elif a == ofp.OFPAT_SET_VLAN_PCP:
Howard Persh6a3698d2012-08-21 14:26:39 -0700533 if not strip_vlanf:
Rich Lane28fa9272013-03-08 16:00:25 -0800534 act = ofp.action.action_set_vlan_pcp()
Howard Persh6a3698d2012-08-21 14:26:39 -0700535 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
536 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700537 elif a == ofp.OFPAT_STRIP_VLAN:
Howard Persh6a3698d2012-08-21 14:26:39 -0700538 if not set_vlanf:
Rich Lane28fa9272013-03-08 16:00:25 -0800539 act = ofp.action.action_strip_vlan()
Howard Persh6a3698d2012-08-21 14:26:39 -0700540 strip_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700541 elif a == ofp.OFPAT_SET_DL_SRC:
Rich Lane28fa9272013-03-08 16:00:25 -0800542 act = ofp.action.action_set_dl_src()
Howard Persh3340d452012-04-06 16:45:21 -0700543 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700544 elif a == ofp.OFPAT_SET_DL_DST:
Rich Lane28fa9272013-03-08 16:00:25 -0800545 act = ofp.action.action_set_dl_dst()
Howard Persh3340d452012-04-06 16:45:21 -0700546 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700547 elif a == ofp.OFPAT_SET_NW_SRC:
Rich Lane28fa9272013-03-08 16:00:25 -0800548 act = ofp.action.action_set_nw_src()
Howard Persh3340d452012-04-06 16:45:21 -0700549 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700550 elif a == ofp.OFPAT_SET_NW_DST:
Rich Lane28fa9272013-03-08 16:00:25 -0800551 act = ofp.action.action_set_nw_dst()
Howard Persh3340d452012-04-06 16:45:21 -0700552 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700553 elif a == ofp.OFPAT_SET_NW_TOS:
Rich Lane28fa9272013-03-08 16:00:25 -0800554 act = ofp.action.action_set_nw_tos()
Howard Persh3340d452012-04-06 16:45:21 -0700555 act.nw_tos = fi.rand_ip_tos()
Howard Persh3340d452012-04-06 16:45:21 -0700556 elif a == ofp.OFPAT_SET_TP_SRC:
Rich Lane28fa9272013-03-08 16:00:25 -0800557 act = ofp.action.action_set_tp_src()
Howard Persh3340d452012-04-06 16:45:21 -0700558 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700559 elif a == ofp.OFPAT_SET_TP_DST:
Rich Lane28fa9272013-03-08 16:00:25 -0800560 act = ofp.action.action_set_tp_dst()
Howard Persh3340d452012-04-06 16:45:21 -0700561 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700562 elif a == ofp.OFPAT_ENQUEUE:
563 pass # Enqueue actions must come last
Dan Talayco910a8282012-04-07 00:05:20 -0700564 if act:
Dan Talayco910a8282012-04-07 00:05:20 -0700565 self.actions.add(act)
566
Howard Persh3340d452012-04-06 16:45:21 -0700567 p = random.randint(1, 100)
Howard Pershc1199d52012-04-11 14:21:32 -0700568 if (((1 << ofp.OFPAT_ENQUEUE) & actions_force) != 0 or p <= 33) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700569 and len(valid_queues) > 0 \
570 and ofp.OFPAT_ENQUEUE in actions:
Howard Pershc1199d52012-04-11 14:21:32 -0700571 # In not forecd, one third of the time, include ENQUEUE actions
572 # at end of list
Howard Persh3340d452012-04-06 16:45:21 -0700573 # At most 1 ENQUEUE action
Rich Lane28fa9272013-03-08 16:00:25 -0800574 act = ofp.action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700575 (act.port, act.queue_id) = rand_pick(valid_queues)
Howard Persh3340d452012-04-06 16:45:21 -0700576 self.actions.add(act)
Howard Pershc1199d52012-04-11 14:21:32 -0700577 if (((1 << ofp.OFPAT_OUTPUT) & actions_force) != 0 \
578 or (p > 33 and p <= 66) \
579 ) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700580 and len(valid_ports) > 0 \
Howard Pershc1199d52012-04-11 14:21:32 -0700581 and ofp.OFPAT_OUTPUT in actions:
Howard Persh3340d452012-04-06 16:45:21 -0700582 # One third of the time, include OUTPUT actions at end of list
583 port_idxs = shuffle(range(len(valid_ports)))
584 # Only 1 output action allowed if IN_PORT wildcarded
585 n = 1 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) != 0 \
586 else random.randint(1, len(valid_ports))
587 port_idxs = port_idxs[0 : n]
588 for pi in port_idxs:
Rich Lane28fa9272013-03-08 16:00:25 -0800589 act = ofp.action.action_output()
Howard Persh3340d452012-04-06 16:45:21 -0700590 act.port = valid_ports[pi]
Howard Persh3340d452012-04-06 16:45:21 -0700591 if act.port != ofp.OFPP_IN_PORT \
592 or wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
593 # OUTPUT(IN_PORT) only valid if OFPFW_IN_PORT not wildcarded
594 self.actions.add(act)
595 else:
596 # One third of the time, include neither
597 pass
598
599
600 # Randomize flow data for flow modifies (i.e. cookie and actions)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700601 def rand_mod(self, fi, valid_actions, valid_ports, valid_queues):
rootf6af1672012-04-06 09:46:29 -0700602 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700603
Dan Talayco910a8282012-04-07 00:05:20 -0700604 # By default, test with conservative ordering conventions
605 # This should probably be indicated in a profile
Rich Lane2014f9b2012-10-05 15:29:40 -0700606 if test_param_get("conservative_ordered_actions", True):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700607 self.rand_actions_ordered(fi, valid_actions, valid_ports, valid_queues)
Howard Persh3340d452012-04-06 16:45:21 -0700608 return self
609
Rich Lane2014f9b2012-10-05 15:29:40 -0700610 actions_force = test_param_get("actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700611 if actions_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700612 logging.info("Forced actions:")
613 logging.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700614
615 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh680b92a2012-03-31 13:34:35 -0700616 supported_actions = []
617 for a in all_actions_list:
618 if ((1 << a) & valid_actions) != 0:
619 supported_actions.append(a)
620
Howard Pershc1199d52012-04-11 14:21:32 -0700621 actions \
622 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
623
624 for a in all_actions_list:
625 if ((1 << a) & actions_force) != 0:
626 actions.append(a)
627
628 actions = shuffle(actions)
Howard Pershc7963582012-03-29 10:02:59 -0700629
630 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700631 for a in actions:
Howard Pershc7963582012-03-29 10:02:59 -0700632 if a == ofp.OFPAT_OUTPUT:
633 # TBD - Output actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700634 if len(valid_ports) == 0:
635 continue
Howard Pershc7963582012-03-29 10:02:59 -0700636 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700637 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700638 for pi in port_idxs:
Rich Lane28fa9272013-03-08 16:00:25 -0800639 act = ofp.action.action_output()
Howard Persh680b92a2012-03-31 13:34:35 -0700640 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700641 self.actions.add(act)
642 elif a == ofp.OFPAT_SET_VLAN_VID:
Rich Lane28fa9272013-03-08 16:00:25 -0800643 act = ofp.action.action_set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700644 act.vlan_vid = fi.rand_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700645 self.actions.add(act)
646 elif a == ofp.OFPAT_SET_VLAN_PCP:
Rich Lane28fa9272013-03-08 16:00:25 -0800647 act = ofp.action.action_set_vlan_pcp()
Dan Talayco910a8282012-04-07 00:05:20 -0700648 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700649 elif a == ofp.OFPAT_STRIP_VLAN:
Rich Lane28fa9272013-03-08 16:00:25 -0800650 act = ofp.action.action_strip_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700651 self.actions.add(act)
652 elif a == ofp.OFPAT_SET_DL_SRC:
Rich Lane28fa9272013-03-08 16:00:25 -0800653 act = ofp.action.action_set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700654 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700655 self.actions.add(act)
656 elif a == ofp.OFPAT_SET_DL_DST:
Rich Lane28fa9272013-03-08 16:00:25 -0800657 act = ofp.action.action_set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700658 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700659 self.actions.add(act)
660 elif a == ofp.OFPAT_SET_NW_SRC:
Rich Lane28fa9272013-03-08 16:00:25 -0800661 act = ofp.action.action_set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700662 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700663 self.actions.add(act)
664 elif a == ofp.OFPAT_SET_NW_DST:
Rich Lane28fa9272013-03-08 16:00:25 -0800665 act = ofp.action.action_set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700666 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700667 self.actions.add(act)
668 elif a == ofp.OFPAT_SET_NW_TOS:
Rich Lane28fa9272013-03-08 16:00:25 -0800669 act = ofp.action.action_set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700670 act.nw_tos = fi.rand_ip_tos()
Howard Pershc7963582012-03-29 10:02:59 -0700671 self.actions.add(act)
672 elif a == ofp.OFPAT_SET_TP_SRC:
Rich Lane28fa9272013-03-08 16:00:25 -0800673 act = ofp.action.action_set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700674 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700675 self.actions.add(act)
676 elif a == ofp.OFPAT_SET_TP_DST:
Rich Lane28fa9272013-03-08 16:00:25 -0800677 act = ofp.action.action_set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700678 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700679 self.actions.add(act)
680 elif a == ofp.OFPAT_ENQUEUE:
681 # TBD - Enqueue actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700682 if len(valid_queues) == 0:
683 continue
684 qidxs = shuffle(range(len(valid_queues)))
685 qidxs = qidxs[0 : random.randint(1, len(valid_queues))]
686 for qi in qidxs:
Rich Lane28fa9272013-03-08 16:00:25 -0800687 act = ofp.action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700688 (act.port, act.queue_id) = valid_queues[qi]
Howard Pershc7963582012-03-29 10:02:59 -0700689 self.actions.add(act)
690
691 return self
692
rootf6af1672012-04-06 09:46:29 -0700693 # Randomize flow cfg
Ed Swierk99a74de2012-08-22 06:40:54 -0700694 def rand(self, fi, wildcards_force, valid_wildcards, valid_actions, valid_ports,
695 valid_queues):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700696 if wildcards_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700697 logging.info("Wildcards forced:")
698 logging.info(wildcards_to_str(wildcards_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700699
rootf6af1672012-04-06 09:46:29 -0700700 # Start with no wildcards, i.e. everything specified
701 self.match.wildcards = 0
Howard Pershc1199d52012-04-11 14:21:32 -0700702
703 if wildcards_force != 0:
704 exact = False
705 else:
706 # Make approx. 5% of flows exact
707 exact = (random.randint(1, 100) <= 5)
rootf6af1672012-04-06 09:46:29 -0700708
709 # For each qualifier Q,
710 # if (wildcarding is not supported for Q,
711 # or an exact flow is specified
712 # or a coin toss comes up heads),
713 # specify Q
714 # else
715 # wildcard Q
716
Howard Pershc1199d52012-04-11 14:21:32 -0700717 if wildcard_get(wildcards_force, ofp.OFPFW_IN_PORT) == 0 \
718 and (wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
719 or exact \
720 or flip_coin() \
721 ):
rootf6af1672012-04-06 09:46:29 -0700722 self.match.in_port = rand_pick(valid_ports)
723 else:
Howard Persh3340d452012-04-06 16:45:21 -0700724 self.match.wildcards = wildcard_set(self.match.wildcards, \
725 ofp.OFPFW_IN_PORT, \
726 1 \
727 )
rootf6af1672012-04-06 09:46:29 -0700728
Howard Pershc1199d52012-04-11 14:21:32 -0700729 if wildcard_get(wildcards_force, ofp.OFPFW_DL_DST) == 0 \
730 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
731 or exact \
732 or flip_coin() \
733 ):
rootf6af1672012-04-06 09:46:29 -0700734 self.match.dl_dst = fi.rand_dl_addr()
735 else:
Howard Persh3340d452012-04-06 16:45:21 -0700736 self.match.wildcards = wildcard_set(self.match.wildcards, \
737 ofp.OFPFW_DL_DST, \
738 1 \
739 )
rootf6af1672012-04-06 09:46:29 -0700740
Howard Pershc1199d52012-04-11 14:21:32 -0700741 if wildcard_get(wildcards_force, ofp.OFPFW_DL_SRC) == 0 \
742 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
743 or exact \
744 or flip_coin() \
745 ):
rootf6af1672012-04-06 09:46:29 -0700746 self.match.dl_src = fi.rand_dl_addr()
747 else:
Howard Persh3340d452012-04-06 16:45:21 -0700748 self.match.wildcards = wildcard_set(self.match.wildcards, \
749 ofp.OFPFW_DL_SRC, \
750 1 \
751 )
rootf6af1672012-04-06 09:46:29 -0700752
Howard Pershc1199d52012-04-11 14:21:32 -0700753 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN) == 0 \
754 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
755 or exact \
756 or flip_coin() \
757 ):
rootf6af1672012-04-06 09:46:29 -0700758 self.match.dl_vlan = fi.rand_vlan()
759 else:
Howard Persh3340d452012-04-06 16:45:21 -0700760 self.match.wildcards = wildcard_set(self.match.wildcards, \
761 ofp.OFPFW_DL_VLAN, \
762 1 \
763 )
rootf6af1672012-04-06 09:46:29 -0700764
Howard Pershc1199d52012-04-11 14:21:32 -0700765 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN_PCP) == 0 \
766 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
767 or exact \
768 or flip_coin() \
769 ):
770 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
771 else:
772 self.match.wildcards = wildcard_set(self.match.wildcards, \
773 ofp.OFPFW_DL_VLAN_PCP, \
774 1 \
775 )
776
777 if wildcard_get(wildcards_force, ofp.OFPFW_DL_TYPE) == 0 \
778 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
779 or exact \
780 or flip_coin() \
781 ):
rootf6af1672012-04-06 09:46:29 -0700782 self.match.dl_type = fi.rand_ethertype()
783 else:
Howard Persh3340d452012-04-06 16:45:21 -0700784 self.match.wildcards = wildcard_set(self.match.wildcards, \
785 ofp.OFPFW_DL_TYPE, \
786 1 \
787 )
rootf6af1672012-04-06 09:46:29 -0700788
Howard Pershc1199d52012-04-11 14:21:32 -0700789 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_SRC_MASK)
790 if n == 0:
791 if exact or flip_coin():
792 n = 0
793 else:
794 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
795 if n > 32:
796 n = 32
797 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700798 self.match.wildcards = wildcard_set(self.match.wildcards, \
799 ofp.OFPFW_NW_SRC_MASK, \
800 n \
801 )
rootf6af1672012-04-06 09:46:29 -0700802 if n < 32:
803 self.match.nw_src = fi.rand_ip_addr() & ~((1 << n) - 1)
804 # Specifying any IP address match other than all bits
805 # don't care requires that Ethertype is one of {IP, ARP}
806 if flip_coin():
807 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700808 self.match.wildcards = wildcard_set(self.match.wildcards, \
809 ofp.OFPFW_DL_TYPE, \
810 0 \
811 )
rootf6af1672012-04-06 09:46:29 -0700812
Howard Pershc1199d52012-04-11 14:21:32 -0700813 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_DST_MASK)
814 if n == 0:
815 if exact or flip_coin():
816 n = 0
817 else:
818 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
819 if n > 32:
820 n = 32
821 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700822 self.match.wildcards = wildcard_set(self.match.wildcards, \
823 ofp.OFPFW_NW_DST_MASK, \
824 n \
825 )
rootf6af1672012-04-06 09:46:29 -0700826 if n < 32:
827 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
828 # Specifying any IP address match other than all bits
829 # don't care requires that Ethertype is one of {IP, ARP}
830 if flip_coin():
831 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700832 self.match.wildcards = wildcard_set(self.match.wildcards, \
833 ofp.OFPFW_DL_TYPE, \
834 0 \
835 )
rootf6af1672012-04-06 09:46:29 -0700836
Howard Pershc1199d52012-04-11 14:21:32 -0700837 if wildcard_get(wildcards_force, ofp.OFPFW_NW_TOS) == 0 \
838 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
839 or exact \
840 or flip_coin() \
841 ):
rootf6af1672012-04-06 09:46:29 -0700842 self.match.nw_tos = fi.rand_ip_tos()
843 # Specifying a TOS value requires that Ethertype is IP
844 if flip_coin():
845 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700846 self.match.wildcards = wildcard_set(self.match.wildcards, \
847 ofp.OFPFW_DL_TYPE, \
848 0 \
849 )
rootf6af1672012-04-06 09:46:29 -0700850 else:
Howard Persh3340d452012-04-06 16:45:21 -0700851 self.match.wildcards = wildcard_set(self.match.wildcards, \
852 ofp.OFPFW_NW_TOS, \
853 1 \
854 )
rootf6af1672012-04-06 09:46:29 -0700855
Dan Talayco910a8282012-04-07 00:05:20 -0700856 # Known issue on OVS with specifying nw_proto w/o dl_type as IP
Howard Pershc1199d52012-04-11 14:21:32 -0700857 if wildcard_get(wildcards_force, ofp.OFPFW_NW_PROTO) == 0 \
858 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
859 or exact \
860 or flip_coin() \
861 ):
Dan Talayco910a8282012-04-07 00:05:20 -0700862 self.match.nw_proto = fi.rand_ip_proto()
863 # Specifying an IP protocol requires that Ethertype is IP
864 if flip_coin():
865 self.match.dl_type = 0x0800
866 self.match.wildcards = wildcard_set(self.match.wildcards, \
867 ofp.OFPFW_DL_TYPE, \
868 0 \
869 )
870 else:
Howard Persh3340d452012-04-06 16:45:21 -0700871 self.match.wildcards = wildcard_set(self.match.wildcards, \
872 ofp.OFPFW_NW_PROTO, \
873 1 \
874 )
Dan Talayco910a8282012-04-07 00:05:20 -0700875
Howard Pershc1199d52012-04-11 14:21:32 -0700876 if wildcard_get(wildcards_force, ofp.OFPFW_TP_SRC) == 0 \
877 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
878 or exact\
879 or flip_coin() \
880 ):
rootf6af1672012-04-06 09:46:29 -0700881 self.match.tp_src = fi.rand_l4_port()
882 # Specifying a L4 port requires that IP protcol is
883 # one of {ICMP, TCP, UDP}
884 if flip_coin():
885 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700886 self.match.wildcards = wildcard_set(self.match.wildcards, \
887 ofp.OFPFW_NW_PROTO, \
888 0 \
889 )
rootf6af1672012-04-06 09:46:29 -0700890 # Specifying a L4 port requirues that Ethertype is IP
891 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700892 self.match.wildcards = wildcard_set(self.match.wildcards, \
893 ofp.OFPFW_DL_TYPE, \
894 0 \
895 )
rootf6af1672012-04-06 09:46:29 -0700896 if self.match.nw_proto == 1:
897 self.match.tp_src = self.match.tp_src & 0xff
898 else:
Howard Persh3340d452012-04-06 16:45:21 -0700899 self.match.wildcards = wildcard_set(self.match.wildcards, \
900 ofp.OFPFW_TP_SRC, \
901 1 \
902 )
rootf6af1672012-04-06 09:46:29 -0700903
Howard Pershc1199d52012-04-11 14:21:32 -0700904 if wildcard_get(wildcards_force, ofp.OFPFW_TP_DST) == 0 \
905 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
906 or exact \
907 or flip_coin() \
908 ):
rootf6af1672012-04-06 09:46:29 -0700909 self.match.tp_dst = fi.rand_l4_port()
910 # Specifying a L4 port requires that IP protcol is
911 # one of {ICMP, TCP, UDP}
912 if flip_coin():
913 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700914 self.match.wildcards = wildcard_set(self.match.wildcards, \
915 ofp.OFPFW_NW_PROTO, \
916 0 \
917 )
rootf6af1672012-04-06 09:46:29 -0700918 # Specifying a L4 port requirues that Ethertype is IP
919 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700920 self.match.wildcards = wildcard_set(self.match.wildcards, \
921 ofp.OFPFW_DL_TYPE, \
922 0 \
923 )
rootf6af1672012-04-06 09:46:29 -0700924 if self.match.nw_proto == 1:
925 self.match.tp_dst = self.match.tp_dst & 0xff
926 else:
Howard Persh3340d452012-04-06 16:45:21 -0700927 self.match.wildcards = wildcard_set(self.match.wildcards, \
928 ofp.OFPFW_TP_DST, \
929 1 \
930 )
rootf6af1672012-04-06 09:46:29 -0700931
932 # If nothing is wildcarded, it is an exact flow spec -- some switches
Howard Persh3340d452012-04-06 16:45:21 -0700933 # (Open vSwitch, for one) *require* that exact flow specs
934 # have priority 65535.
935 self.priority = 65535 if self.match.wildcards == 0 \
936 else fi.rand_priority()
rootf6af1672012-04-06 09:46:29 -0700937
938 # N.B. Don't make the timeout too short, else the flow might
939 # disappear before we get a chance to check for it.
940 t = random.randint(0, 65535)
941 self.idle_timeout = 0 if t < 60 else t
942 t = random.randint(0, 65535)
943 self.hard_timeout = 0 if t < 60 else t
944
Howard Persh8d21c1f2012-04-20 15:57:29 -0700945 self.rand_mod(fi, valid_actions, valid_ports, valid_queues)
rootf6af1672012-04-06 09:46:29 -0700946
947 return self
948
949 # Return flow cfg in canonical form
Howard Persh3340d452012-04-06 16:45:21 -0700950 # - There are dependencies between flow qualifiers, e.g. it only makes
951 # sense to qualify nw_proto if dl_type is qualified to be 0x0800 (IP).
952 # The canonical form of flow match criteria will "wildcard out"
953 # all such cases.
rootf6af1672012-04-06 09:46:29 -0700954 def canonical(self):
955 result = copy.deepcopy(self)
Howard Persh07d99e62012-04-09 15:26:57 -0700956
957 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_VLAN) != 0:
958 result.match.wildcards = wildcard_set(result.match.wildcards, \
959 ofp.OFPFW_DL_VLAN_PCP, \
960 1 \
961 )
962
rootf6af1672012-04-06 09:46:29 -0700963 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
964 or result.match.dl_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700965 # dl_tyoe is wildcarded, or specified as something other
966 # than IP or ARP
Howard Persh07d99e62012-04-09 15:26:57 -0700967 # => nw_src, nw_dst, nw_proto cannot be specified,
968 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700969 result.match.wildcards = wildcard_set(result.match.wildcards, \
970 ofp.OFPFW_NW_SRC_MASK, \
971 32 \
972 )
973 result.match.wildcards = wildcard_set(result.match.wildcards, \
974 ofp.OFPFW_NW_DST_MASK, \
975 32 \
976 )
Howard Persh3340d452012-04-06 16:45:21 -0700977 result.match.wildcards = wildcard_set(result.match.wildcards, \
978 ofp.OFPFW_NW_PROTO, \
979 1 \
980 )
Howard Persh07d99e62012-04-09 15:26:57 -0700981
982 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
983 or result.match.dl_type != 0x0800:
984 # dl_type is wildcarded, or specified as something other than IP
985 # => nw_tos, tp_src and tp_dst cannot be specified,
986 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700987 result.match.wildcards = wildcard_set(result.match.wildcards, \
988 ofp.OFPFW_NW_TOS, \
989 1 \
990 )
991 result.match.wildcards = wildcard_set(result.match.wildcards, \
992 ofp.OFPFW_TP_SRC, \
993 1 \
994 )
995 result.match.wildcards = wildcard_set(result.match.wildcards, \
996 ofp.OFPFW_TP_DST, \
997 1 \
998 )
Howard Persh07d99e62012-04-09 15:26:57 -0700999 result.match.wildcards = wildcard_set(result.match.wildcards, \
1000 ofp.OFPFW_NW_SRC_MASK, \
1001 32 \
1002 )
1003 result.match.wildcards = wildcard_set(result.match.wildcards, \
1004 ofp.OFPFW_NW_DST_MASK, \
1005 32 \
1006 )
1007 result.match.wildcards = wildcard_set(result.match.wildcards, \
1008 ofp.OFPFW_NW_PROTO, \
1009 1 \
1010 )
1011
rootf6af1672012-04-06 09:46:29 -07001012 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
1013 or result.match.nw_proto not in [1, 6, 17]:
Howard Persh3340d452012-04-06 16:45:21 -07001014 # nw_proto is wildcarded, or specified as something other than ICMP,
1015 # TCP or UDP
rootf6af1672012-04-06 09:46:29 -07001016 # => tp_src and tp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001017 result.match.wildcards = wildcard_set(result.match.wildcards, \
1018 ofp.OFPFW_TP_SRC, \
1019 1 \
1020 )
1021 result.match.wildcards = wildcard_set(result.match.wildcards, \
1022 ofp.OFPFW_TP_DST, \
1023 1 \
1024 )
rootf6af1672012-04-06 09:46:29 -07001025 return result
1026
Howard Persh680b92a2012-03-31 13:34:35 -07001027 # Overlap check
1028 # delf == True <=> Check for delete overlap, else add overlap
1029 # "Add overlap" is defined as there exists a packet that could match both the
1030 # receiver and argument flowspecs
1031 # "Delete overlap" is defined as the specificity of the argument flowspec
1032 # is greater than or equal to the specificity of the receiver flowspec
1033 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -07001034 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
1035 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001036 if self.match.in_port != x.match.in_port:
1037 return False # Both specified, and not equal
1038 elif delf:
1039 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001040 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
1041 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001042 if self.match.dl_vlan != x.match.dl_vlan:
1043 return False # Both specified, and not equal
1044 elif delf:
1045 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001046 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
1047 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001048 if self.match.dl_src != x.match.dl_src:
1049 return False # Both specified, and not equal
1050 elif delf:
1051 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001052 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
1053 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001054 if self.match.dl_dst != x.match.dl_dst:
1055 return False # Both specified, and not equal
1056 elif delf:
1057 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001058 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
1059 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001060 if self.match.dl_type != x.match.dl_type:
1061 return False # Both specified, and not equal
1062 elif delf:
1063 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -07001064 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
1065 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001066 if self.match.nw_proto != x.match.nw_proto:
1067 return False # Both specified, and not equal
1068 elif delf:
1069 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001070 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
1071 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001072 if self.match.tp_src != x.match.tp_src:
1073 return False # Both specified, and not equal
1074 elif delf:
1075 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001076 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
1077 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001078 if self.match.tp_dst != x.match.tp_dst:
1079 return False # Both specified, and not equal
1080 elif delf:
1081 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001082 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
1083 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001084 if delf and na < nb:
1085 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001086 if (na < 32 and nb < 32):
1087 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1088 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -07001089 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -07001090 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
1091 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001092 if delf and na < nb:
1093 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001094 if (na < 32 and nb < 32):
1095 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1096 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
rootf6af1672012-04-06 09:46:29 -07001097 return False # Overlapping bits not equal
1098 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
1099 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001100 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
1101 return False # Both specified, and not equal
1102 elif delf:
1103 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001104 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
1105 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001106 if self.match.nw_tos != x.match.nw_tos:
1107 return False # Both specified, and not equal
1108 elif delf:
1109 return False # Receiver more specific
1110 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -07001111
1112 def to_flow_mod_msg(self, msg):
1113 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -07001114 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001115 msg.idle_timeout = self.idle_timeout
1116 msg.hard_timeout = self.hard_timeout
1117 msg.priority = self.priority
1118 msg.actions = self.actions
1119 return msg
1120
1121 def from_flow_stat(self, msg):
1122 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -07001123 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001124 self.idle_timeout = msg.idle_timeout
1125 self.hard_timeout = msg.hard_timeout
1126 self.priority = msg.priority
1127 self.actions = msg.actions
1128
rootf6af1672012-04-06 09:46:29 -07001129 def from_flow_rem(self, msg):
1130 self.match = msg.match
1131 self.idle_timeout = msg.idle_timeout
1132 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -07001133
Howard Pershc7963582012-03-29 10:02:59 -07001134
rootf6af1672012-04-06 09:46:29 -07001135class Flow_Tbl:
1136 def clear(self):
1137 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001138
rootf6af1672012-04-06 09:46:29 -07001139 def __init__(self):
1140 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001141
rootf6af1672012-04-06 09:46:29 -07001142 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001143 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001144
1145 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001146 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001147
1148 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001149 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001150
1151 def values(self):
1152 return self.dict.values()
1153
1154 def count(self):
1155 return len(self.dict)
1156
Ed Swierk99a74de2012-08-22 06:40:54 -07001157 def rand(self, wildcards_force, sw, fi, num_flows):
rootf6af1672012-04-06 09:46:29 -07001158 self.clear()
1159 i = 0
1160 tbl = 0
1161 j = 0
1162 while i < num_flows:
1163 fc = Flow_Cfg()
1164 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001165 wildcards_force, \
rootf6af1672012-04-06 09:46:29 -07001166 sw.tbl_stats.stats[tbl].wildcards, \
1167 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001168 sw.valid_ports, \
1169 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001170 )
1171 fc = fc.canonical()
1172 if self.find(fc):
1173 continue
1174 fc.send_rem = False
1175 self.insert(fc)
1176 i = i + 1
1177 j = j + 1
1178 if j >= sw.tbl_stats.stats[tbl].max_entries:
1179 tbl = tbl + 1
1180 j = 0
1181
1182
1183class Switch:
1184 # Members:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001185 # controller - switch's test controller
1186 # sw_features - switch's OFPT_FEATURES_REPLY message
1187 # valid_ports - list of valid port numbers
1188 # valid_queues - list of valid [port, queue] pairs
1189 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1190 # queue_stats - switch's OFPT_STATS_REPLY message, for queue stats request
1191 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1192 # flow_tbl - (test's idea of) switch's flow table
rootf6af1672012-04-06 09:46:29 -07001193
1194 def __init__(self):
Howard Persh8d21c1f2012-04-20 15:57:29 -07001195 self.controller = None
1196 self.sw_features = None
1197 self.valid_ports = []
1198 self.valid_queues = []
1199 self.tbl_stats = None
1200 self.flow_stats = None
1201 self.flow_tbl = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001202 self.error_msgs = []
1203 self.removed_msgs = []
1204
1205 def error_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001206 logging.info("Got an ERROR message, type=%d, code=%d" \
Ed Swierk99a74de2012-08-22 06:40:54 -07001207 % (msg.type, msg.code) \
1208 )
Rich Lane9a003812012-10-04 17:17:59 -07001209 logging.info("Message header:")
1210 logging.info(msg.header.show())
Ed Swierk99a74de2012-08-22 06:40:54 -07001211 self.error_msgs.append(msg)
1212
1213 def removed_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001214 logging.info("Got a REMOVED message")
1215 logging.info("Message header:")
1216 logging.info(msg.header.show())
Ed Swierk99a74de2012-08-22 06:40:54 -07001217 self.removed_msgs.append(msg)
rootf6af1672012-04-06 09:46:29 -07001218
Howard Persh3340d452012-04-06 16:45:21 -07001219 def controller_set(self, controller):
1220 self.controller = controller
1221 # Register error message handler
Ed Swierk99a74de2012-08-22 06:40:54 -07001222 self.error_msgs = []
1223 self.removed_msgs = []
1224 controller.register(ofp.OFPT_ERROR, self.error_handler)
1225 controller.register(ofp.OFPT_FLOW_REMOVED, self.removed_handler)
Howard Persh3340d452012-04-06 16:45:21 -07001226
rootf6af1672012-04-06 09:46:29 -07001227 def features_get(self):
1228 # Get switch features
Rich Lane28fa9272013-03-08 16:00:25 -08001229 request = ofp.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001230 (self.sw_features, pkt) = self.controller.transact(request)
rootf6af1672012-04-06 09:46:29 -07001231 if self.sw_features is None:
Rich Lane9a003812012-10-04 17:17:59 -07001232 logging.error("Get switch features failed")
rootf6af1672012-04-06 09:46:29 -07001233 return False
1234 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Rich Lane9a003812012-10-04 17:17:59 -07001235 logging.info("Ports reported by switch:")
1236 logging.info(self.valid_ports)
Rich Lane2014f9b2012-10-05 15:29:40 -07001237 ports_override = test_param_get("ports", [])
Howard Persh8d21c1f2012-04-20 15:57:29 -07001238 if ports_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001239 logging.info("Overriding ports to:")
1240 logging.info(ports_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001241 self.valid_ports = ports_override
1242
Howard Persh3340d452012-04-06 16:45:21 -07001243 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1244 # is that universal?
1245
1246 # TBD - There seems to be variability in which switches support which
1247 # ports; need to sort that out
1248 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1249# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1250# ofp.OFPP_NORMAL, \
1251# ofp.OFPP_FLOOD, \
1252# ofp.OFPP_ALL, \
1253# ofp.OFPP_CONTROLLER \
1254# ] \
1255# )
Rich Lane9a003812012-10-04 17:17:59 -07001256 logging.info("Supported actions reported by switch:")
1257 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001258 % (self.sw_features.actions, \
1259 actions_bmap_to_str(self.sw_features.actions) \
1260 ) \
1261 )
Rich Lane2014f9b2012-10-05 15:29:40 -07001262 actions_override = test_param_get("actions", -1)
Howard Persh07d99e62012-04-09 15:26:57 -07001263 if actions_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001264 logging.info("Overriding supported actions to:")
1265 logging.info(actions_bmap_to_str(actions_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001266 self.sw_features.actions = actions_override
rootf6af1672012-04-06 09:46:29 -07001267 return True
1268
1269 def tbl_stats_get(self):
1270 # Get table stats
Rich Lane28fa9272013-03-08 16:00:25 -08001271 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001272 (self.tbl_stats, pkt) = self.controller.transact(request)
Howard Persh07d99e62012-04-09 15:26:57 -07001273 if self.tbl_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001274 logging.error("Get table stats failed")
Howard Persh07d99e62012-04-09 15:26:57 -07001275 return False
Howard Persh8d21c1f2012-04-20 15:57:29 -07001276 i = 0
Howard Persh07d99e62012-04-09 15:26:57 -07001277 for ts in self.tbl_stats.stats:
Rich Lane9a003812012-10-04 17:17:59 -07001278 logging.info("Supported wildcards for table %d reported by switch:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001279 % (i)
1280 )
Rich Lane9a003812012-10-04 17:17:59 -07001281 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001282 % (ts.wildcards, \
1283 wildcards_to_str(ts.wildcards) \
1284 ) \
1285 )
Rich Lane2014f9b2012-10-05 15:29:40 -07001286 wildcards_override = test_param_get("wildcards", -1)
Howard Persh07d99e62012-04-09 15:26:57 -07001287 if wildcards_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001288 logging.info("Overriding supported wildcards for table %d to:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001289 % (i)
1290 )
Rich Lane9a003812012-10-04 17:17:59 -07001291 logging.info(wildcards_to_str(wildcards_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001292 ts.wildcards = wildcards_override
Howard Persh8d21c1f2012-04-20 15:57:29 -07001293 i = i + 1
Howard Persh07d99e62012-04-09 15:26:57 -07001294 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001295
Howard Persh8d21c1f2012-04-20 15:57:29 -07001296 def queue_stats_get(self):
1297 # Get queue stats
Rich Lane28fa9272013-03-08 16:00:25 -08001298 request = ofp.message.queue_stats_request()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001299 request.port_no = ofp.OFPP_ALL
1300 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001301 (self.queue_stats, pkt) = self.controller.transact(request)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001302 if self.queue_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001303 logging.error("Get queue stats failed")
Howard Persh8d21c1f2012-04-20 15:57:29 -07001304 return False
1305 self.valid_queues = map(lambda x: (x.port_no, x.queue_id), \
1306 self.queue_stats.stats \
1307 )
Rich Lane9a003812012-10-04 17:17:59 -07001308 logging.info("(Port, queue) pairs reported by switch:")
1309 logging.info(self.valid_queues)
Rich Lane2014f9b2012-10-05 15:29:40 -07001310 queues_override = test_param_get("queues", [])
Howard Persh8d21c1f2012-04-20 15:57:29 -07001311 if queues_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001312 logging.info("Overriding (port, queue) pairs to:")
1313 logging.info(queues_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001314 self.valid_queues = queues_override
1315 return True
1316
1317 def connect(self, controller):
1318 # Connect to controller, and get all switch capabilities
1319 self.controller_set(controller)
1320 return (self.features_get() \
1321 and self.tbl_stats_get() \
1322 and self.queue_stats_get() \
1323 )
1324
Howard Pershc1199d52012-04-11 14:21:32 -07001325 def flow_stats_get(self, limit = 10000):
Rich Lane28fa9272013-03-08 16:00:25 -08001326 request = ofp.message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -07001327 query_match = ofp.ofp_match()
1328 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001329 request.match = query_match
1330 request.table_id = 0xff
1331 request.out_port = ofp.OFPP_NONE;
Rich Lane5c3151c2013-01-03 17:15:41 -08001332 self.controller.message_send(request)
Howard Persh3340d452012-04-06 16:45:21 -07001333 # <TBD>
1334 # Glue together successive reponse messages for stats reply.
1335 # Looking at the "more" flag and performing re-assembly
1336 # should be a part of the infrastructure.
1337 # </TBD>
1338 n = 0
1339 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -07001340 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY)
Howard Persh3340d452012-04-06 16:45:21 -07001341 if resp is None:
Howard Pershc1199d52012-04-11 14:21:32 -07001342 return False # Did not get expected response
Howard Persh3340d452012-04-06 16:45:21 -07001343 if n == 0:
1344 self.flow_stats = resp
1345 else:
1346 self.flow_stats.stats.extend(resp.stats)
1347 n = n + 1
Howard Pershc1199d52012-04-11 14:21:32 -07001348 if len(self.flow_stats.stats) > limit:
Rich Lane9a003812012-10-04 17:17:59 -07001349 logging.error("Too many flows returned")
Howard Pershc1199d52012-04-11 14:21:32 -07001350 return False
1351 if (resp.flags & 1) == 0:
1352 break # No more responses expected
Howard Persh3340d452012-04-06 16:45:21 -07001353 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001354
rootf6af1672012-04-06 09:46:29 -07001355 def flow_add(self, flow_cfg, overlapf = False):
Rich Lane28fa9272013-03-08 16:00:25 -08001356 flow_mod_msg = ofp.message.flow_mod()
Howard Persh680b92a2012-03-31 13:34:35 -07001357 flow_mod_msg.command = ofp.OFPFC_ADD
1358 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001359 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001360 if overlapf:
1361 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001362 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001363 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Howard Persh07d99e62012-04-09 15:26:57 -07001364 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001365 logging.info("Sending flow_mod(add), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001366 % (flow_mod_msg.header.xid)
1367 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001368 self.controller.message_send(flow_mod_msg)
1369 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001370
rootf6af1672012-04-06 09:46:29 -07001371 def flow_mod(self, flow_cfg, strictf):
Rich Lane28fa9272013-03-08 16:00:25 -08001372 flow_mod_msg = ofp.message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001373 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf \
1374 else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -07001375 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001376 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001377 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001378 logging.info("Sending flow_mod(mod), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001379 % (flow_mod_msg.header.xid)
1380 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001381 self.controller.message_send(flow_mod_msg)
1382 return True
rootf6af1672012-04-06 09:46:29 -07001383
1384 def flow_del(self, flow_cfg, strictf):
Rich Lane28fa9272013-03-08 16:00:25 -08001385 flow_mod_msg = ofp.message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001386 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf \
1387 else ofp.OFPFC_DELETE
rootf6af1672012-04-06 09:46:29 -07001388 flow_mod_msg.buffer_id = 0xffffffff
1389 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001390 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001391 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001392 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001393 logging.info("Sending flow_mod(del), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001394 % (flow_mod_msg.header.xid)
1395 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001396 self.controller.message_send(flow_mod_msg)
1397 return True
rootf6af1672012-04-06 09:46:29 -07001398
1399 def barrier(self):
Rich Lane28fa9272013-03-08 16:00:25 -08001400 barrier = ofp.message.barrier_request()
Dan Talaycoc689a792012-09-28 14:22:53 -07001401 (resp, pkt) = self.controller.transact(barrier, 30)
rootf6af1672012-04-06 09:46:29 -07001402 return (resp is not None)
1403
Howard Persh3340d452012-04-06 16:45:21 -07001404 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001405 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001406 logging.info("Expecting %d error messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001407 num_got = len(self.error_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001408 logging.info("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001409 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001410 logging.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001411 result = False
1412 if num_exp == 0:
1413 return result
1414 elif num_exp == 1:
Rich Lane9a003812012-10-04 17:17:59 -07001415 logging.info("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001416 % (type, code) \
1417 )
1418 f = False
Ed Swierk99a74de2012-08-22 06:40:54 -07001419 for e in self.error_msgs:
Howard Persh3340d452012-04-06 16:45:21 -07001420 if e.type == type and e.code == code:
Rich Lane9a003812012-10-04 17:17:59 -07001421 logging.info("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001422 f = True
1423 if not f:
Rich Lane9a003812012-10-04 17:17:59 -07001424 logging.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001425 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001426 else:
Rich Lane9a003812012-10-04 17:17:59 -07001427 logging.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001428 result = False
1429 return result
1430
Howard Persh3340d452012-04-06 16:45:21 -07001431 def removed_verify(self, num_exp):
1432 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001433 logging.info("Expecting %d removed messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001434 num_got = len(self.removed_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001435 logging.info("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001436 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001437 logging.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001438 result = False
1439 if num_exp < 2:
1440 return result
Rich Lane9a003812012-10-04 17:17:59 -07001441 logging.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001442 return False
1443
Howard Persh5f3c83f2012-04-13 09:57:10 -07001444 # modf == True <=> Verify for flow modify, else for add/delete
1445 def flow_tbl_verify(self, modf = False):
rootf6af1672012-04-06 09:46:29 -07001446 result = True
1447
1448 # Verify flow count in switch
Rich Lane9a003812012-10-04 17:17:59 -07001449 logging.info("Reading table stats")
1450 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001451 if not self.tbl_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001452 logging.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001453 return False
1454 n = 0
1455 for ts in self.tbl_stats.stats:
1456 n = n + ts.active_count
Rich Lane9a003812012-10-04 17:17:59 -07001457 logging.info("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001458 % (n) \
1459 )
1460 if n != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001461 logging.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001462 result = False
1463
1464 # Read flows from switch
Rich Lane9a003812012-10-04 17:17:59 -07001465 logging.info("Retrieving flows from switch")
1466 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001467 if not self.flow_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001468 logging.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001469 return False
Rich Lane9a003812012-10-04 17:17:59 -07001470 logging.info("Retrieved %d flows" % (len(self.flow_stats.stats)))
rootf6af1672012-04-06 09:46:29 -07001471
1472 # Verify flows returned by switch
1473
1474 if len(self.flow_stats.stats) != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001475 logging.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001476 result = False
1477
Rich Lane9a003812012-10-04 17:17:59 -07001478 logging.info("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001479 for fc in self.flow_tbl.values():
1480 fc.matched = False
1481 for fs in self.flow_stats.stats:
1482 flow_in = Flow_Cfg()
1483 flow_in.from_flow_stat(fs)
Rich Lane9a003812012-10-04 17:17:59 -07001484 logging.info("Received flow:")
1485 logging.info(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001486 fc = self.flow_tbl.find(flow_in)
1487 if fc is None:
Rich Lane9a003812012-10-04 17:17:59 -07001488 logging.error("Received flow:")
1489 logging.error(str(flow_in))
1490 logging.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001491 result = False
1492 elif fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001493 logging.error("Received flow:")
1494 logging.error(str(flow_in))
1495 logging.error("re-matches defined flow:")
1496 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001497 result = False
1498 else:
Rich Lane9a003812012-10-04 17:17:59 -07001499 logging.info("matched")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001500 if modf:
1501 # Check for modify
1502
1503 if flow_in.cookie != fc.cookie:
Rich Lane9a003812012-10-04 17:17:59 -07001504 logging.warning("Defined flow:")
1505 logging.warning(str(fc))
1506 logging.warning("Received flow:")
1507 logging.warning(str(flow_in))
1508 logging.warning("cookies do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001509 if not flow_in.actions_equal(fc):
Rich Lane9a003812012-10-04 17:17:59 -07001510 logging.error("Defined flow:")
1511 logging.error(str(fc))
1512 logging.error("Received flow:")
1513 logging.error(str(flow_in))
1514 logging.error("actions do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001515 else:
1516 # Check for add/delete
1517
1518 if not flow_in == fc:
Rich Lane9a003812012-10-04 17:17:59 -07001519 logging.error("Defined flow:")
1520 logging.error(str(fc))
1521 logging.error("Received flow:")
1522 logging.error(str(flow_in))
1523 logging.error("non-key portions of flow do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001524 result = False
rootf6af1672012-04-06 09:46:29 -07001525 fc.matched = True
1526 for fc in self.flow_tbl.values():
1527 if not fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001528 logging.error("Defined flow:")
1529 logging.error(str(fc))
1530 logging.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001531 result = False
1532
1533 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001534
Howard Persh9cab4822012-09-11 17:08:40 -07001535 def settle(self):
1536 time.sleep(2)
1537
Howard Persh07d99e62012-04-09 15:26:57 -07001538# FLOW ADD 5
1539#
1540# OVERVIEW
1541# Add flows to switch, read back and verify flow configurations
1542#
1543# PURPOSE
1544# - Test acceptance of flow adds
1545# - Test ability of switch to process additions to flow table in random
1546# priority order
1547# - Test correctness of flow configuration responses
1548#
1549# PARAMETERS
1550#
1551# Name: num_flows
1552# Type: number
1553# Description:
1554# Number of flows to define; 0 => maximum number of flows, as determined
1555# from switch capabilities
1556# Default: 100
1557#
1558# PROCESS
1559# 1. Delete all flows from switch
1560# 2. Generate <num_flows> distinct flow configurations
1561# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1562# 4. Verify that no OFPT_ERROR responses were generated by switch
1563# 5. Retrieve flow stats from switch
1564# 6. Compare flow configurations returned by switch
1565# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1566# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001567
Rich Laneb90a1c42012-10-05 09:16:05 -07001568class Flow_Add_5(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001569 """
1570 Test FLOW_ADD_5 from draft top-half test plan
1571
1572 INPUTS
1573 num_flows - Number of flows to generate
1574 """
Howard Persh680b92a2012-03-31 13:34:35 -07001575
rootf6af1672012-04-06 09:46:29 -07001576 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001577 logging.info("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001578
Rich Lane2014f9b2012-10-05 15:29:40 -07001579 num_flows = test_param_get("num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001580
Howard Pershc7963582012-03-29 10:02:59 -07001581 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001582
Rich Lane9a003812012-10-04 17:17:59 -07001583 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001584 delete_all_flows(self.controller)
Howard Pershc7963582012-03-29 10:02:59 -07001585
rootf6af1672012-04-06 09:46:29 -07001586 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001587
rootf6af1672012-04-06 09:46:29 -07001588 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001589 self.assertTrue(sw.connect(self.controller), \
1590 "Failed to connect to switch" \
1591 )
Howard Pershc7963582012-03-29 10:02:59 -07001592
rootf6af1672012-04-06 09:46:29 -07001593 if num_flows == 0:
1594 # Number of flows requested was 0
1595 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001596
rootf6af1672012-04-06 09:46:29 -07001597 for ts in sw.tbl_stats.stats:
1598 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001599
Rich Lane9a003812012-10-04 17:17:59 -07001600 logging.info("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001601
1602 # Dream up some flow information, i.e. space to chose from for
1603 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001604
rootf6af1672012-04-06 09:46:29 -07001605 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001606 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001607
rootf6af1672012-04-06 09:46:29 -07001608 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001609
rootf6af1672012-04-06 09:46:29 -07001610 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001611 ft.rand(required_wildcards(self), sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001612
rootf6af1672012-04-06 09:46:29 -07001613 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001614
Rich Lane9a003812012-10-04 17:17:59 -07001615 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001616 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001617 logging.info("Adding flow:")
1618 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001619 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001620
rootf6af1672012-04-06 09:46:29 -07001621 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001622
rootf6af1672012-04-06 09:46:29 -07001623 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001624
rootf6af1672012-04-06 09:46:29 -07001625 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001626
Howard Persh9cab4822012-09-11 17:08:40 -07001627 sw.settle() # Allow switch to settle and generate any notifications
1628
rootf6af1672012-04-06 09:46:29 -07001629 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001630
rootf6af1672012-04-06 09:46:29 -07001631 if not sw.errors_verify(0):
1632 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001633
rootf6af1672012-04-06 09:46:29 -07001634 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001635
rootf6af1672012-04-06 09:46:29 -07001636 sw.flow_tbl = ft
1637 if not sw.flow_tbl_verify():
1638 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001639
rootf6af1672012-04-06 09:46:29 -07001640 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001641 logging.info("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001642
Howard Pershc7963582012-03-29 10:02:59 -07001643
Howard Persh07d99e62012-04-09 15:26:57 -07001644# FLOW ADD 5_1
1645#
1646# OVERVIEW
1647# Verify handling of non-canonical flows
1648#
1649# PURPOSE
1650# - Test that switch detects and correctly responds to a non-canonical flow
1651# definition. A canonical flow is one that satisfies all match qualifier
1652# dependencies; a non-canonical flow is one that does not.
1653#
1654# PARAMETERS
1655# - None
1656#
1657# PROCESS
1658# 1. Delete all flows from switch
1659# 2. Generate 1 flow definition, which is different from its canonicalization
1660# 3. Send flow to switch
1661# 4. Retrieve flow from switch
1662# 5. Compare returned flow to canonical form of defined flow
1663# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1664
1665# Disabled.
1666# Should be DUT dependent.
Howard Persh07d99e62012-04-09 15:26:57 -07001667
Rich Lane0a4f6372013-01-02 14:40:22 -08001668@nonstandard
Rich Laneb90a1c42012-10-05 09:16:05 -07001669class Flow_Add_5_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001670 """
1671 Test FLOW_ADD_5.1 from draft top-half test plan
1672
1673 INPUTS
1674 None
1675 """
Rich Laned1d9c282012-10-04 22:07:10 -07001676
rootf6af1672012-04-06 09:46:29 -07001677 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001678 logging.info("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001679
Rich Lane2014f9b2012-10-05 15:29:40 -07001680 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001681
1682 # Clear all flows from switch
1683
Rich Lane9a003812012-10-04 17:17:59 -07001684 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001685 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001686
1687 # Get switch capabilites
1688
rootf6af1672012-04-06 09:46:29 -07001689 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001690 self.assertTrue(sw.connect(self.controller), \
1691 "Failed to connect to switch" \
1692 )
rootf6af1672012-04-06 09:46:29 -07001693
1694 # Dream up some flow information, i.e. space to chose from for
1695 # random flow parameter generation
1696
1697 fi = Flow_Info()
1698 fi.rand(10)
1699
1700 # Dream up a flow config that will be canonicalized by the switch
1701
1702 while True:
1703 fc = Flow_Cfg()
1704 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001705 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07001706 sw.tbl_stats.stats[0].wildcards, \
1707 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001708 sw.valid_ports, \
1709 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001710 )
1711 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001712 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001713 break
1714
1715 ft = Flow_Tbl()
1716 ft.insert(fcc)
1717
1718 # Send it to the switch
1719
Rich Lane9a003812012-10-04 17:17:59 -07001720 logging.info("Sending flow add to switch:")
1721 logging.info(str(fc))
1722 logging.info("should be canonicalized as:")
1723 logging.info(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001724 fc.send_rem = False
1725 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1726
1727 # Do barrier, to make sure all flows are in
1728
1729 self.assertTrue(sw.barrier(), "Barrier failed")
1730
1731 result = True
1732
Howard Persh9cab4822012-09-11 17:08:40 -07001733 sw.settle() # Allow switch to settle and generate any notifications
1734
rootf6af1672012-04-06 09:46:29 -07001735 # Check for any error messages
1736
1737 if not sw.errors_verify(0):
1738 result = False
1739
1740 # Verify flow table
1741
1742 sw.flow_tbl = ft
1743 if not sw.flow_tbl_verify():
1744 result = False
1745
1746 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001747 logging.info("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001748
1749
Howard Persh07d99e62012-04-09 15:26:57 -07001750# FLOW ADD 6
1751#
1752# OVERVIEW
1753# Test flow table capacity
1754#
1755# PURPOSE
1756# - Test switch can accept as many flow definitions as it claims
1757# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1758# - Test that attempting to create flows beyond capacity does not corrupt
1759# flow table
1760#
1761# PARAMETERS
1762# None
1763#
1764# PROCESS
1765# 1. Delete all flows from switch
1766# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1767# to determine flow table size, N
1768# 3. Generate (N + 1) distinct flow configurations
1769# 4. Send N flow adds to switch, for flows generated in step 3 above
1770# 5. Verify flow table in switch
1771# 6. Send one more flow add to switch
1772# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1773# response was generated by switch, for last flow mod sent
1774# 7. Retrieve flow stats from switch
1775# 8. Verify flow table in switch
1776# 9. Test PASSED iff:
1777# - error message received, for correct flow
1778# - last flow definition sent to switch is not in flow table
1779# else test FAILED
1780
Howard Persh3340d452012-04-06 16:45:21 -07001781# Disabled because of bogus capacity reported by OVS.
1782# Should be DUT dependent.
Howard Persh3340d452012-04-06 16:45:21 -07001783
Rich Lane0a4f6372013-01-02 14:40:22 -08001784@nonstandard
Rich Laneb90a1c42012-10-05 09:16:05 -07001785class Flow_Add_6(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001786 """
1787 Test FLOW_ADD_6 from draft top-half test plan
1788
1789 INPUTS
1790 num_flows - Number of flows to generate
1791 """
Howard Pershc7963582012-03-29 10:02:59 -07001792
1793 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001794 logging.info("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001795
rootf6af1672012-04-06 09:46:29 -07001796 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001797
Rich Lane9a003812012-10-04 17:17:59 -07001798 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001799 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001800
1801 # Get switch capabilites
1802
rootf6af1672012-04-06 09:46:29 -07001803 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001804 self.assertTrue(sw.connect(self.controller), \
1805 "Failed to connect to switch" \
1806 )
rootf6af1672012-04-06 09:46:29 -07001807
root2843d2b2012-04-06 10:27:46 -07001808 num_flows = 0
rootf6af1672012-04-06 09:46:29 -07001809 for ts in sw.tbl_stats.stats:
1810 num_flows = num_flows + ts.max_entries
1811
Rich Lane9a003812012-10-04 17:17:59 -07001812 logging.info("Switch capacity is %d flows" % (num_flows))
1813 logging.info("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001814
1815 # Dream up some flow information, i.e. space to chose from for
1816 # random flow parameter generation
1817
1818 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001819 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001820
1821 # Create a flow table, to switch's capacity
1822
1823 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001824 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07001825
1826 # Send flow table to switch
1827
Rich Lane9a003812012-10-04 17:17:59 -07001828 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001829 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001830 logging.info("Adding flow:")
1831 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001832 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1833
1834 # Do barrier, to make sure all flows are in
1835
1836 self.assertTrue(sw.barrier(), "Barrier failed")
1837
1838 result = True
1839
Howard Persh9cab4822012-09-11 17:08:40 -07001840 sw.settle() # Allow switch to settle and generate any notifications
1841
rootf6af1672012-04-06 09:46:29 -07001842 # Check for any error messages
1843
1844 if not sw.errors_verify(0):
1845 result = False
1846
1847 # Dream up one more flow
1848
Rich Lane9a003812012-10-04 17:17:59 -07001849 logging.info("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001850 while True:
1851 fc = Flow_Cfg()
1852 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001853 required_wildcards(self), \
Howard Persh07d99e62012-04-09 15:26:57 -07001854 sw.tbl_stats.stats[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001855 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001856 sw.valid_ports, \
1857 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001858 )
1859 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001860 if not ft.find(fc):
1861 break
rootf6af1672012-04-06 09:46:29 -07001862
1863 # Send one-more flow
1864
1865 fc.send_rem = False
Rich Lane9a003812012-10-04 17:17:59 -07001866 logging.info("Sending flow add switch")
1867 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001868 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1869
1870 # Do barrier, to make sure all flows are in
1871
1872 self.assertTrue(sw.barrier(), "Barrier failed")
1873
Howard Persh9cab4822012-09-11 17:08:40 -07001874 sw.settle() # Allow switch to settle and generate any notifications
1875
rootf6af1672012-04-06 09:46:29 -07001876 # Check for expected error message
1877
1878 if not sw.errors_verify(1, \
1879 ofp.OFPET_FLOW_MOD_FAILED, \
1880 ofp.OFPFMFC_ALL_TABLES_FULL \
1881 ):
1882 result = False
1883
1884 # Verify flow table
1885
1886 sw.flow_tbl = ft
1887 if not sw.flow_tbl_verify():
1888 result = False
1889
1890 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001891 logging.info("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001892
1893
Howard Persh07d99e62012-04-09 15:26:57 -07001894# FLOW ADD 7
1895#
1896# OVERVIEW
1897# Test flow redefinition
1898#
1899# PURPOSE
1900# Verify that successive flow adds with same priority and match criteria
1901# overwrite in flow table
1902#
1903# PARAMETERS
1904# None
1905#
1906# PROCESS
1907# 1. Delete all flows from switch
1908# 2. Generate flow definition F1
1909# 3. Generate flow definition F2, with same key (priority and match) as F1,
1910# but with different actions
1911# 4. Send flow adds for F1 and F2 to switch
1912# 5. Verify flow definitions in switch
1913# 6. Test PASSED iff 1 flow returned by switch, matching configuration of F2;
1914# else test FAILED
1915
Rich Laneb90a1c42012-10-05 09:16:05 -07001916class Flow_Add_7(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001917 """
1918 Test FLOW_ADD_7 from draft top-half test plan
1919
1920 INPUTS
1921 None
1922 """
1923
1924 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001925 logging.info("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001926
1927 # Clear all flows from switch
1928
Rich Lane9a003812012-10-04 17:17:59 -07001929 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001930 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001931
1932 # Get switch capabilites
1933
rootf6af1672012-04-06 09:46:29 -07001934 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001935 self.assertTrue(sw.connect(self.controller), \
1936 "Failed to connect to switch" \
1937 )
rootf6af1672012-04-06 09:46:29 -07001938
1939 # Dream up some flow information, i.e. space to chose from for
1940 # random flow parameter generation
1941
1942 fi = Flow_Info()
1943 fi.rand(10)
1944
1945 # Dream up a flow config
1946
1947 fc = Flow_Cfg()
1948 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001949 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07001950 sw.tbl_stats.stats[0].wildcards, \
1951 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001952 sw.valid_ports, \
1953 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001954 )
1955 fc = fc.canonical()
1956
1957 # Send it to the switch
1958
Rich Lane9a003812012-10-04 17:17:59 -07001959 logging.info("Sending flow add to switch:")
1960 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001961 ft = Flow_Tbl()
1962 fc.send_rem = False
1963 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1964 ft.insert(fc)
1965
1966 # Dream up some different actions, with the same flow key
1967
1968 fc2 = copy.deepcopy(fc)
1969 while True:
1970 fc2.rand_mod(fi, \
1971 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001972 sw.valid_ports, \
1973 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001974 )
1975 if fc2 != fc:
1976 break
1977
1978 # Send that to the switch
1979
Rich Lane9a003812012-10-04 17:17:59 -07001980 logging.info("Sending flow add to switch:")
1981 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07001982 fc2.send_rem = False
1983 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
1984 ft.insert(fc2)
1985
1986 # Do barrier, to make sure all flows are in
1987
1988 self.assertTrue(sw.barrier(), "Barrier failed")
1989
1990 result = True
1991
Howard Persh9cab4822012-09-11 17:08:40 -07001992 sw.settle() # Allow switch to settle and generate any notifications
1993
rootf6af1672012-04-06 09:46:29 -07001994 # Check for any error messages
1995
1996 if not sw.errors_verify(0):
1997 result = False
1998
1999 # Verify flow table
2000
2001 sw.flow_tbl = ft
2002 if not sw.flow_tbl_verify():
2003 result = False
2004
2005 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002006 logging.info("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002007
2008
Howard Persh07d99e62012-04-09 15:26:57 -07002009# FLOW ADD 8
2010#
2011# OVERVIEW
2012# Add overlapping flows to switch, verify that overlapping flows are rejected
2013#
2014# PURPOSE
2015# - Test detection of overlapping flows by switch
2016# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
2017# - Test rejection of overlapping flows
2018# - Test defining overlapping flows does not corrupt flow table
2019#
2020# PARAMETERS
2021# None
2022#
2023# PROCESS
2024# 1. Delete all flows from switch
2025# 2. Generate flow definition F1
2026# 3. Generate flow definition F2, with key overlapping F1
2027# 4. Send flow add to switch, for F1
2028# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
2029# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
2030# was generated by switch
2031# 7. Verifiy flows configured in swtich
2032# 8. Test PASSED iff:
2033# - error message received, for overlapping flow
2034# - overlapping flow is not in flow table
2035# else test FAILED
2036
Rich Laneb90a1c42012-10-05 09:16:05 -07002037class Flow_Add_8(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002038 """
2039 Test FLOW_ADD_8 from draft top-half test plan
2040
2041 INPUTS
2042 None
2043 """
2044
2045 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002046 logging.info("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002047
2048 # Clear all flows from switch
2049
Rich Lane9a003812012-10-04 17:17:59 -07002050 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002051 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002052
2053 # Get switch capabilites
2054
rootf6af1672012-04-06 09:46:29 -07002055 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002056 self.assertTrue(sw.connect(self.controller), \
2057 "Failed to connect to switch" \
2058 )
rootf6af1672012-04-06 09:46:29 -07002059
2060 # Dream up some flow information, i.e. space to chose from for
2061 # random flow parameter generation
2062
2063 fi = Flow_Info()
2064 fi.rand(10)
2065
2066 # Dream up a flow config, with at least 1 qualifier specified
2067
2068 fc = Flow_Cfg()
2069 while True:
2070 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002071 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002072 sw.tbl_stats.stats[0].wildcards, \
2073 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002074 sw.valid_ports, \
2075 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002076 )
2077 fc = fc.canonical()
2078 if fc.match.wildcards != ofp.OFPFW_ALL:
2079 break
2080
2081 # Send it to the switch
2082
Rich Lane9a003812012-10-04 17:17:59 -07002083 logging.info("Sending flow add to switch:")
2084 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002085 ft = Flow_Tbl()
2086 fc.send_rem = False
2087 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2088 ft.insert(fc)
2089
2090 # Wildcard out one qualifier that was specified, to create an
2091 # overlapping flow
2092
2093 fc2 = copy.deepcopy(fc)
2094 for wi in shuffle(range(len(all_wildcards_list))):
2095 w = all_wildcards_list[wi]
2096 if (fc2.match.wildcards & w) == 0:
2097 break
2098 if w == ofp.OFPFW_NW_SRC_MASK:
2099 w = ofp.OFPFW_NW_SRC_ALL
2100 wn = "OFPFW_NW_SRC"
2101 elif w == ofp.OFPFW_NW_DST_MASK:
2102 w = ofp.OFPFW_NW_DST_ALL
2103 wn = "OFPFW_NW_DST"
2104 else:
2105 wn = all_wildcard_names[w]
Rich Lane9a003812012-10-04 17:17:59 -07002106 logging.info("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07002107 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07002108 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07002109
2110 # Send that to the switch, with overlap checking
2111
Rich Lane9a003812012-10-04 17:17:59 -07002112 logging.info("Sending flow add to switch:")
2113 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002114 fc2.send_rem = False
2115 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
2116
2117 # Do barrier, to make sure all flows are in
2118 self.assertTrue(sw.barrier(), "Barrier failed")
2119
2120 result = True
2121
Howard Persh9cab4822012-09-11 17:08:40 -07002122 sw.settle() # Allow switch to settle and generate any notifications
2123
rootf6af1672012-04-06 09:46:29 -07002124 # Check for expected error message
2125
2126 if not sw.errors_verify(1, \
2127 ofp.OFPET_FLOW_MOD_FAILED, \
2128 ofp.OFPFMFC_OVERLAP \
2129 ):
2130 result = False
2131
2132 # Verify flow table
2133
2134 sw.flow_tbl = ft
2135 if not sw.flow_tbl_verify():
2136 result = False
2137
2138 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002139 logging.info("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002140
2141
Howard Persh07d99e62012-04-09 15:26:57 -07002142# FLOW MODIFY 1
2143#
2144# OVERVIEW
2145# Strict modify of single existing flow
2146#
2147# PURPOSE
2148# - Verify that strict flow modify operates only on specified flow
2149# - Verify that flow is correctly modified
2150#
2151# PARAMETERS
2152# None
2153#
2154# PROCESS
2155# 1. Delete all flows from switch
2156# 2. Generate 1 flow F
2157# 3. Send flow add to switch, for flow F
2158# 4. Generate new action list for flow F, yielding F'
2159# 5. Send strict flow modify to switch, for flow F'
2160# 6. Verify flow table in switch
2161# 7. Test PASSED iff flow returned by switch is F'; else FAILED
2162
Rich Laneb90a1c42012-10-05 09:16:05 -07002163class Flow_Mod_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002164 """
2165 Test FLOW_MOD_1 from draft top-half test plan
2166
2167 INPUTS
2168 None
2169 """
2170
2171 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002172 logging.info("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002173
2174 # Clear all flows from switch
2175
Rich Lane9a003812012-10-04 17:17:59 -07002176 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002177 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002178
2179 # Get switch capabilites
2180
rootf6af1672012-04-06 09:46:29 -07002181 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002182 self.assertTrue(sw.connect(self.controller), \
2183 "Failed to connect to switch" \
2184 )
rootf6af1672012-04-06 09:46:29 -07002185
2186 # Dream up some flow information, i.e. space to chose from for
2187 # random flow parameter generation
2188
2189 fi = Flow_Info()
2190 fi.rand(10)
2191
2192 # Dream up a flow config
2193
2194 fc = Flow_Cfg()
2195 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002196 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002197 sw.tbl_stats.stats[0].wildcards, \
2198 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002199 sw.valid_ports, \
2200 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002201 )
2202 fc = fc.canonical()
2203
2204 # Send it to the switch
2205
Rich Lane9a003812012-10-04 17:17:59 -07002206 logging.info("Sending flow add to switch:")
2207 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002208 ft = Flow_Tbl()
2209 fc.send_rem = False
2210 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2211 ft.insert(fc)
2212
2213 # Dream up some different actions, with the same flow key
2214
2215 fc2 = copy.deepcopy(fc)
2216 while True:
2217 fc2.rand_mod(fi, \
2218 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002219 sw.valid_ports, \
2220 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002221 )
2222 if fc2 != fc:
2223 break
2224
2225 # Send that to the switch
2226
Rich Lane9a003812012-10-04 17:17:59 -07002227 logging.info("Sending strict flow mod to switch:")
2228 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002229 fc2.send_rem = False
2230 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2231 ft.insert(fc2)
2232
2233 # Do barrier, to make sure all flows are in
2234
2235 self.assertTrue(sw.barrier(), "Barrier failed")
2236
2237 result = True
2238
Howard Persh9cab4822012-09-11 17:08:40 -07002239 sw.settle() # Allow switch to settle and generate any notifications
2240
rootf6af1672012-04-06 09:46:29 -07002241 # Check for any error messages
2242
2243 if not sw.errors_verify(0):
2244 result = False
2245
2246 # Verify flow table
2247
2248 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002249 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002250 result = False
2251
2252 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002253 logging.info("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002254
Howard Persh07d99e62012-04-09 15:26:57 -07002255
2256# FLOW MODIFY 2
2257#
2258# OVERVIEW
2259# Loose modify of mutiple flows
2260#
2261# PURPOSE
2262# - Verify that loose flow modify operates only on matching flows
2263# - Verify that matching flows are correctly modified
2264#
2265# PARAMETERS
2266# Name: num_flows
2267# Type: number
2268# Description:
2269# Number of flows to define
2270# Default: 100
2271#
2272# PROCESS
2273# 1. Delete all flows from switch
2274# 2. Generate <num_flows> distinct flow configurations
2275# 3. Send <num_flows> flow adds to switch
2276# 4. Pick 1 defined flow F at random
2277# 5. Create overlapping loose flow mod match criteria by repeatedly
2278# wildcarding out qualifiers in match of F => F',
2279# and create new actions list A' for F'
2280# 6. Send loose flow modify for F' to switch
2281# 7. Verify flow table in swtich
2282# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2283# are returned in step 7 above, each with correct (original or modified)
2284# action list;
2285# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002286
Rich Laneb90a1c42012-10-05 09:16:05 -07002287class Flow_Mod_2(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002288 """
2289 Test FLOW_MOD_2 from draft top-half test plan
2290
2291 INPUTS
2292 None
2293 """
2294
2295 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002296 logging.info("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002297
Rich Lane2014f9b2012-10-05 15:29:40 -07002298 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002299
2300 # Clear all flows from switch
2301
Rich Lane9a003812012-10-04 17:17:59 -07002302 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002303 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002304
2305 # Get switch capabilites
2306
rootf6af1672012-04-06 09:46:29 -07002307 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002308 self.assertTrue(sw.connect(self.controller), \
2309 "Failed to connect to switch" \
2310 )
rootf6af1672012-04-06 09:46:29 -07002311
2312 # Dream up some flow information, i.e. space to chose from for
2313 # random flow parameter generation
2314
2315 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002316 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002317 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002318
2319 # Dream up some flows
2320
2321 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002322 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002323
2324 # Send flow table to switch
2325
Rich Lane9a003812012-10-04 17:17:59 -07002326 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002327 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002328 logging.info("Adding flow:")
2329 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002330 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2331
2332 # Do barrier, to make sure all flows are in
2333
2334 self.assertTrue(sw.barrier(), "Barrier failed")
2335
2336 result = True
2337
Howard Persh9cab4822012-09-11 17:08:40 -07002338 sw.settle() # Allow switch to settle and generate any notifications
2339
rootf6af1672012-04-06 09:46:29 -07002340 # Check for any error messages
2341
2342 if not sw.errors_verify(0):
2343 result = False
2344
2345 # Verify flow table
2346
2347 sw.flow_tbl = ft
2348 if not sw.flow_tbl_verify():
2349 result = False
2350
2351 # Pick a random flow as a basis
Howard Persh5f3c83f2012-04-13 09:57:10 -07002352
2353 mfc = copy.deepcopy((ft.values())[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002354 mfc.rand_mod(fi, \
2355 sw.sw_features.actions, \
2356 sw.valid_ports, \
2357 sw.valid_queues \
2358 )
rootf6af1672012-04-06 09:46:29 -07002359
2360 # Repeatedly wildcard qualifiers
2361
2362 for wi in shuffle(range(len(all_wildcards_list))):
2363 w = all_wildcards_list[wi]
2364 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2365 n = wildcard_get(mfc.match.wildcards, w)
2366 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002367 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2368 w, \
2369 random.randint(n + 1, 32) \
2370 )
rootf6af1672012-04-06 09:46:29 -07002371 else:
2372 continue
2373 else:
2374 if wildcard_get(mfc.match.wildcards, w) == 0:
2375 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2376 else:
2377 continue
2378 mfc = mfc.canonical()
2379
2380 # Count the number of flows that would be modified
2381
2382 n = 0
2383 for fc in ft.values():
2384 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2385 n = n + 1
2386
2387 # If more than 1, we found our loose delete flow spec
2388 if n > 1:
2389 break
2390
Rich Lane9a003812012-10-04 17:17:59 -07002391 logging.info("Modifying %d flows" % (n))
2392 logging.info("Sending flow mod to switch:")
2393 logging.info(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002394 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2395
2396 # Do barrier, to make sure all flows are in
2397 self.assertTrue(sw.barrier(), "Barrier failed")
2398
Howard Persh9cab4822012-09-11 17:08:40 -07002399 sw.settle() # Allow switch to settle and generate any notifications
2400
rootf6af1672012-04-06 09:46:29 -07002401 # Check for error message
2402
2403 if not sw.errors_verify(0):
2404 result = False
2405
2406 # Apply flow mod to local flow table
2407
2408 for fc in ft.values():
2409 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002410 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002411
2412 # Verify flow table
2413
2414 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002415 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002416 result = False
2417
2418 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002419 logging.info("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002420
2421
Howard Persh07d99e62012-04-09 15:26:57 -07002422# FLOW MODIFY 3
2423
2424# OVERVIEW
2425# Strict modify of non-existent flow
2426#
2427# PURPOSE
2428# Verify that strict modify of a non-existent flow is equivalent to a flow add
2429#
2430# PARAMETERS
2431# None
2432#
2433# PROCESS
2434# 1. Delete all flows from switch
2435# 2. Send single flow mod, as strict modify, to switch
2436# 3. Verify flow table in switch
2437# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2438
Rich Laneb90a1c42012-10-05 09:16:05 -07002439class Flow_Mod_3(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002440 """
2441 Test FLOW_MOD_3 from draft top-half test plan
2442
2443 INPUTS
2444 None
2445 """
2446
2447 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002448 logging.info("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002449
2450 # Clear all flows from switch
2451
Rich Lane9a003812012-10-04 17:17:59 -07002452 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002453 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002454
2455 # Get switch capabilites
2456
rootf6af1672012-04-06 09:46:29 -07002457 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002458 self.assertTrue(sw.connect(self.controller), \
2459 "Failed to connect to switch" \
2460 )
rootf6af1672012-04-06 09:46:29 -07002461
2462 # Dream up some flow information, i.e. space to chose from for
2463 # random flow parameter generation
2464
2465 fi = Flow_Info()
2466 fi.rand(10)
2467
2468 # Dream up a flow config
2469
2470 fc = Flow_Cfg()
2471 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002472 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002473 sw.tbl_stats.stats[0].wildcards, \
2474 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002475 sw.valid_ports, \
2476 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002477 )
2478 fc = fc.canonical()
2479
2480 # Send it to the switch
2481
Rich Lane9a003812012-10-04 17:17:59 -07002482 logging.info("Sending flow mod to switch:")
2483 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002484 ft = Flow_Tbl()
2485 fc.send_rem = False
2486 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2487 ft.insert(fc)
2488
2489 # Do barrier, to make sure all flows are in
2490
2491 self.assertTrue(sw.barrier(), "Barrier failed")
2492
2493 result = True
2494
Howard Persh9cab4822012-09-11 17:08:40 -07002495 sw.settle() # Allow switch to settle and generate any notifications
2496
rootf6af1672012-04-06 09:46:29 -07002497 # Check for any error messages
2498
2499 if not sw.errors_verify(0):
2500 result = False
2501
2502 # Verify flow table
2503
2504 sw.flow_tbl = ft
2505 if not sw.flow_tbl_verify():
2506 result = False
2507
2508 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002509 logging.info("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002510
2511
Howard Persh8d21c1f2012-04-20 15:57:29 -07002512# FLOW MODIFY 3_1
2513
2514# OVERVIEW
2515# No-op modify
2516#
2517# PURPOSE
2518# Verify that modify of a flow with new actions same as old ones operates correctly
2519#
2520# PARAMETERS
2521# None
2522#
2523# PROCESS
2524# 1. Delete all flows from switch
2525# 2. Send single flow mod, as strict modify, to switch
2526# 3. Verify flow table in switch
2527# 4. Send same flow mod, as strict modify, to switch
2528# 5. Verify flow table in switch
2529# 6. Test PASSED iff flow defined in step 2 and 4 above verified; else FAILED
2530
Rich Laneb90a1c42012-10-05 09:16:05 -07002531class Flow_Mod_3_1(base_tests.SimpleProtocol):
Howard Persh8d21c1f2012-04-20 15:57:29 -07002532 """
2533 Test FLOW_MOD_3_1 from draft top-half test plan
2534
2535 INPUTS
2536 None
2537 """
2538
2539 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002540 logging.info("Flow_Mod_3_1 TEST BEGIN")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002541
2542 # Clear all flows from switch
2543
Rich Lane9a003812012-10-04 17:17:59 -07002544 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002545 delete_all_flows(self.controller)
Howard Persh8d21c1f2012-04-20 15:57:29 -07002546
2547 # Get switch capabilites
2548
2549 sw = Switch()
2550 self.assertTrue(sw.connect(self.controller), \
2551 "Failed to connect to switch" \
2552 )
2553
2554 # Dream up some flow information, i.e. space to chose from for
2555 # random flow parameter generation
2556
2557 fi = Flow_Info()
2558 fi.rand(10)
2559
2560 # Dream up a flow config
2561
2562 fc = Flow_Cfg()
2563 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002564 required_wildcards(self), \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002565 sw.tbl_stats.stats[0].wildcards, \
2566 sw.sw_features.actions, \
2567 sw.valid_ports, \
2568 sw.valid_queues \
2569 )
2570 fc = fc.canonical()
2571
2572 # Send it to the switch
2573
Rich Lane9a003812012-10-04 17:17:59 -07002574 logging.info("Sending flow mod to switch:")
2575 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002576 ft = Flow_Tbl()
2577 fc.send_rem = False
2578 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2579 ft.insert(fc)
2580
2581 # Do barrier, to make sure all flows are in
2582
2583 self.assertTrue(sw.barrier(), "Barrier failed")
2584
2585 result = True
2586
Howard Persh9cab4822012-09-11 17:08:40 -07002587 sw.settle() # Allow switch to settle and generate any notifications
2588
Howard Persh8d21c1f2012-04-20 15:57:29 -07002589 # Check for any error messages
2590
2591 if not sw.errors_verify(0):
2592 result = False
2593
2594 # Verify flow table
2595
2596 sw.flow_tbl = ft
2597 if not sw.flow_tbl_verify():
2598 result = False
2599
2600 # Send same flow to the switch again
2601
Rich Lane9a003812012-10-04 17:17:59 -07002602 logging.info("Sending flow mod to switch:")
2603 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002604 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2605
2606 # Do barrier, to make sure all flows are in
2607
2608 self.assertTrue(sw.barrier(), "Barrier failed")
2609
Howard Persh9cab4822012-09-11 17:08:40 -07002610 sw.settle() # Allow switch to settle and generate any notifications
2611
Howard Persh8d21c1f2012-04-20 15:57:29 -07002612 # Check for any error messages
2613
2614 if not sw.errors_verify(0):
2615 result = False
2616
2617 # Verify flow table
2618
2619 if not sw.flow_tbl_verify():
2620 result = False
2621
2622 self.assertTrue(result, "Flow_Mod_3_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002623 logging.info("Flow_Mod_3_1 TEST PASSED")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002624
2625
Howard Persh07d99e62012-04-09 15:26:57 -07002626# FLOW DELETE 1
2627#
2628# OVERVIEW
2629# Strict delete of single flow
2630#
2631# PURPOSE
2632# Verify correct operation of strict delete of single defined flow
2633#
2634# PARAMETERS
2635# None
2636#
2637# PROCESS
2638# 1. Delete all flows from switch
2639# 2. Send flow F to switch
2640# 3. Send strict flow delete for F to switch
2641# 4. Verify flow table in swtich
2642# 6. Test PASSED iff all flows sent to switch in step 2 above,
2643# less flow removed in step 3 above, are returned in step 4 above;
2644# else test FAILED
2645
Rich Laneb90a1c42012-10-05 09:16:05 -07002646class Flow_Del_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002647 """
2648 Test FLOW_DEL_1 from draft top-half test plan
2649
2650 INPUTS
2651 None
2652 """
2653
2654 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002655 logging.info("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002656
2657 # Clear all flows from switch
2658
Rich Lane9a003812012-10-04 17:17:59 -07002659 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002660 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002661
2662 # Get switch capabilites
2663
rootf6af1672012-04-06 09:46:29 -07002664 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002665 self.assertTrue(sw.connect(self.controller), \
2666 "Failed to connect to switch" \
2667 )
rootf6af1672012-04-06 09:46:29 -07002668
2669 # Dream up some flow information, i.e. space to chose from for
2670 # random flow parameter generation
2671
2672 fi = Flow_Info()
2673 fi.rand(10)
2674
2675 # Dream up a flow config
2676
2677 fc = Flow_Cfg()
2678 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002679 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002680 sw.tbl_stats.stats[0].wildcards, \
2681 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002682 sw.valid_ports, \
2683 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002684 )
2685 fc = fc.canonical()
2686
2687 # Send it to the switch
2688
Rich Lane9a003812012-10-04 17:17:59 -07002689 logging.info("Sending flow add to switch:")
2690 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002691 ft = Flow_Tbl()
2692 fc.send_rem = False
2693 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2694 ft.insert(fc)
2695
2696 # Dream up some different actions, with the same flow key
2697
2698 fc2 = copy.deepcopy(fc)
2699 while True:
2700 fc2.rand_mod(fi, \
2701 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002702 sw.valid_ports, \
2703 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002704 )
2705 if fc2 != fc:
2706 break
2707
2708 # Delete strictly
2709
Rich Lane9a003812012-10-04 17:17:59 -07002710 logging.info("Sending strict flow del to switch:")
2711 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002712 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2713 ft.delete(fc)
2714
2715 # Do barrier, to make sure all flows are in
2716
2717 self.assertTrue(sw.barrier(), "Barrier failed")
2718
2719 result = True
2720
Howard Persh9cab4822012-09-11 17:08:40 -07002721 sw.settle() # Allow switch to settle and generate any notifications
2722
rootf6af1672012-04-06 09:46:29 -07002723 # Check for any error messages
2724
2725 if not sw.errors_verify(0):
2726 result = False
2727
2728 # Verify flow table
2729
2730 sw.flow_tbl = ft
2731 if not sw.flow_tbl_verify():
2732 result = False
2733
2734 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002735 logging.info("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002736
2737
Howard Persh07d99e62012-04-09 15:26:57 -07002738# FLOW DELETE 2
2739#
2740# OVERVIEW
2741# Loose delete of multiple flows
2742#
2743# PURPOSE
2744# - Verify correct operation of loose delete of multiple flows
2745#
2746# PARAMETERS
2747# Name: num_flows
2748# Type: number
2749# Description:
2750# Number of flows to define
2751# Default: 100
2752#
2753# PROCESS
2754# 1. Delete all flows from switch
2755# 2. Generate <num_flows> distinct flow configurations
2756# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2757# 4. Pick 1 defined flow F at random
2758# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2759# F' will match more than 1 existing flow key
2760# 6. Send loose flow delete for F' to switch
2761# 7. Verify flow table in switch
2762# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2763# removed in step 6 above (i.e. those that match F'), are returned
2764# in step 7 above;
2765# else test FAILED
2766
Rich Laneb90a1c42012-10-05 09:16:05 -07002767class Flow_Del_2(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002768 """
2769 Test FLOW_DEL_2 from draft top-half test plan
2770
2771 INPUTS
2772 None
2773 """
2774
2775 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002776 logging.info("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002777
Rich Lane2014f9b2012-10-05 15:29:40 -07002778 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002779
2780 # Clear all flows from switch
2781
Rich Lane9a003812012-10-04 17:17:59 -07002782 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002783 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002784
2785 # Get switch capabilites
2786
rootf6af1672012-04-06 09:46:29 -07002787 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002788 self.assertTrue(sw.connect(self.controller), \
2789 "Failed to connect to switch" \
2790 )
rootf6af1672012-04-06 09:46:29 -07002791
2792 # Dream up some flow information, i.e. space to chose from for
2793 # random flow parameter generation
2794
2795 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002796 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002797 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002798
2799 # Dream up some flows
2800
2801 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002802 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002803
2804 # Send flow table to switch
2805
Rich Lane9a003812012-10-04 17:17:59 -07002806 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002807 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002808 logging.info("Adding flow:")
2809 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002810 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2811
2812 # Do barrier, to make sure all flows are in
2813
2814 self.assertTrue(sw.barrier(), "Barrier failed")
2815
2816 result = True
2817
Howard Persh9cab4822012-09-11 17:08:40 -07002818 sw.settle() # Allow switch to settle and generate any notifications
2819
rootf6af1672012-04-06 09:46:29 -07002820 # Check for any error messages
2821
2822 if not sw.errors_verify(0):
2823 result = False
2824
2825 # Verify flow table
2826
2827 sw.flow_tbl = ft
2828 if not sw.flow_tbl_verify():
2829 result = False
2830
2831 # Pick a random flow as a basis
2832
2833 dfc = copy.deepcopy(ft.values()[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002834 dfc.rand_mod(fi, \
2835 sw.sw_features.actions, \
2836 sw.valid_ports, \
2837 sw.valid_queues \
2838 )
rootf6af1672012-04-06 09:46:29 -07002839
2840 # Repeatedly wildcard qualifiers
2841
2842 for wi in shuffle(range(len(all_wildcards_list))):
2843 w = all_wildcards_list[wi]
2844 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2845 n = wildcard_get(dfc.match.wildcards, w)
2846 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002847 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2848 w, \
2849 random.randint(n + 1, 32) \
2850 )
rootf6af1672012-04-06 09:46:29 -07002851 else:
2852 continue
2853 else:
2854 if wildcard_get(dfc.match.wildcards, w) == 0:
2855 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2856 else:
2857 continue
2858 dfc = dfc.canonical()
2859
2860 # Count the number of flows that would be deleted
2861
2862 n = 0
2863 for fc in ft.values():
2864 if dfc.overlaps(fc, True):
2865 n = n + 1
2866
2867 # If more than 1, we found our loose delete flow spec
2868 if n > 1:
2869 break
2870
Rich Lane9a003812012-10-04 17:17:59 -07002871 logging.info("Deleting %d flows" % (n))
2872 logging.info("Sending flow del to switch:")
2873 logging.info(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002874 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2875
2876 # Do barrier, to make sure all flows are in
2877 self.assertTrue(sw.barrier(), "Barrier failed")
2878
Howard Persh9cab4822012-09-11 17:08:40 -07002879 sw.settle() # Allow switch to settle and generate any notifications
2880
rootf6af1672012-04-06 09:46:29 -07002881 # Check for error message
2882
2883 if not sw.errors_verify(0):
2884 result = False
2885
2886 # Apply flow mod to local flow table
2887
2888 for fc in ft.values():
2889 if dfc.overlaps(fc, True):
2890 ft.delete(fc)
2891
2892 # Verify flow table
2893
2894 sw.flow_tbl = ft
2895 if not sw.flow_tbl_verify():
2896 result = False
2897
2898 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002899 logging.info("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002900
2901
Howard Persh07d99e62012-04-09 15:26:57 -07002902# FLOW DELETE 4
2903#
2904# OVERVIEW
2905# Flow removed messages
2906#
2907# PURPOSE
2908# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2909# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2910#
2911# PARAMETERS
2912# None
2913#
2914# PROCESS
2915# 1. Delete all flows from switch
2916# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2917# 3. Send strict flow delete of flow to switch
2918# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2919# 5. Verify flow table in switch
2920# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2921# removed in step 3 above, are returned in step 5 above, and that
2922# asynch message was received; else test FAILED
2923
2924
Rich Laneb90a1c42012-10-05 09:16:05 -07002925class Flow_Del_4(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002926 """
2927 Test FLOW_DEL_4 from draft top-half test plan
2928
2929 INPUTS
2930 None
2931 """
2932
2933 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002934 logging.info("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002935
2936 # Clear all flows from switch
2937
Rich Lane9a003812012-10-04 17:17:59 -07002938 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002939 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002940
2941 # Get switch capabilites
2942
rootf6af1672012-04-06 09:46:29 -07002943 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002944 self.assertTrue(sw.connect(self.controller), \
2945 "Failed to connect to switch" \
2946 )
rootf6af1672012-04-06 09:46:29 -07002947
2948 # Dream up some flow information, i.e. space to chose from for
2949 # random flow parameter generation
2950
2951 fi = Flow_Info()
2952 fi.rand(10)
2953
2954 # Dream up a flow config
2955
2956 fc = Flow_Cfg()
2957 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002958 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002959 sw.tbl_stats.stats[0].wildcards, \
2960 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002961 sw.valid_ports, \
2962 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002963 )
2964 fc = fc.canonical()
2965
2966 # Send it to the switch. with "notify on removed"
2967
Rich Lane9a003812012-10-04 17:17:59 -07002968 logging.info("Sending flow add to switch:")
2969 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002970 ft = Flow_Tbl()
2971 fc.send_rem = True
2972 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2973 ft.insert(fc)
2974
2975 # Dream up some different actions, with the same flow key
2976
2977 fc2 = copy.deepcopy(fc)
2978 while True:
2979 fc2.rand_mod(fi, \
2980 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002981 sw.valid_ports, \
2982 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002983 )
2984 if fc2 != fc:
2985 break
2986
2987 # Delete strictly
2988
Rich Lane9a003812012-10-04 17:17:59 -07002989 logging.info("Sending strict flow del to switch:")
2990 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002991 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2992 ft.delete(fc)
2993
2994 # Do barrier, to make sure all flows are in
2995
2996 self.assertTrue(sw.barrier(), "Barrier failed")
2997
2998 result = True
2999
Howard Persh9cab4822012-09-11 17:08:40 -07003000 sw.settle() # Allow switch to settle and generate any notifications
3001
rootf6af1672012-04-06 09:46:29 -07003002 # Check for expected "removed" message
3003
Howard Persh3340d452012-04-06 16:45:21 -07003004 if not sw.errors_verify(0):
3005 result = False
3006
3007 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07003008 result = False
3009
3010 # Verify flow table
3011
3012 sw.flow_tbl = ft
3013 if not sw.flow_tbl_verify():
3014 result = False
3015
3016 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07003017 logging.info("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07003018