blob: 271be11d028820d520a42338c80e90302888757d [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
70import oftest.cstruct as ofp
71import oftest.message as message
72import oftest.dataplane as dataplane
73import oftest.action as action
74import oftest.action_list as action_list
75import oftest.parse as parse
76import pktact
Rich Laneb90a1c42012-10-05 09:16:05 -070077import oftest.base_tests as base_tests
Howard Pershc7963582012-03-29 10:02:59 -070078
Rich Laneda3b5ad2012-10-03 09:05:32 -070079from oftest.testutils import *
Howard Pershc7963582012-03-29 10:02:59 -070080from time import sleep
81
Howard Pershc7963582012-03-29 10:02:59 -070082
rootf6af1672012-04-06 09:46:29 -070083def flip_coin():
84 return random.randint(1, 100) <= 50
85
86
Howard Pershc7963582012-03-29 10:02:59 -070087def shuffle(list):
88 n = len(list)
89 lim = n * n
90 i = 0
91 while i < lim:
92 a = random.randint(0, n - 1)
93 b = random.randint(0, n - 1)
94 temp = list[a]
95 list[a] = list[b]
96 list[b] = temp
97 i = i + 1
98 return list
99
100
Howard Persh680b92a2012-03-31 13:34:35 -0700101def rand_pick(list):
102 return list[random.randint(0, len(list) - 1)]
Howard Pershc7963582012-03-29 10:02:59 -0700103
Howard Persh680b92a2012-03-31 13:34:35 -0700104def rand_dl_addr():
105 return [random.randint(0, 255) & ~1,
106 random.randint(0, 255),
107 random.randint(0, 255),
108 random.randint(0, 255),
109 random.randint(0, 255),
110 random.randint(0, 255)
111 ]
Howard Pershc7963582012-03-29 10:02:59 -0700112
113def rand_nw_addr():
114 return random.randint(0, (1 << 32) - 1)
115
116
rootf6af1672012-04-06 09:46:29 -0700117class Flow_Info:
Howard Persh680b92a2012-03-31 13:34:35 -0700118 # Members:
119 # priorities - list of flow priorities
120 # dl_addrs - list of MAC addresses
121 # vlans - list of VLAN ids
122 # ethertypes - list of Ethertypes
123 # ip_addrs - list of IP addresses
124 # ip_tos - list of IP TOS values
125 # ip_protos - list of IP protocols
126 # l4_ports - list of L4 ports
127
128 def __init__(self):
129 priorities = []
130 dl_addrs = []
131 vlans = []
132 ethertypes = []
133 ip_addrs = []
134 ip_tos = []
135 ip_protos = []
136 l4_ports = []
137
138 def rand(self, n):
139 self.priorities = []
140 i = 0
141 while i < n:
142 self.priorities.append(random.randint(1, 65534))
143 i = i + 1
144
145 self.dl_addrs = []
146 i = 0
147 while i < n:
148 self.dl_addrs.append(rand_dl_addr())
149 i = i + 1
150
Rich Lane2014f9b2012-10-05 15:29:40 -0700151 if test_param_get("vlans", []) != []:
152 self.vlans = test_param_get("vlans", [])
Howard Pershb10a47a2012-08-21 13:54:47 -0700153
Rich Lane9a003812012-10-04 17:17:59 -0700154 logging.info("Overriding VLAN ids to:")
155 logging.info(self.vlans)
Howard Pershb10a47a2012-08-21 13:54:47 -0700156 else:
157 self.vlans = []
158 i = 0
159 while i < n:
160 self.vlans.append(random.randint(1, 4094))
161 i = i + 1
Howard Persh680b92a2012-03-31 13:34:35 -0700162
rootf6af1672012-04-06 09:46:29 -0700163 self.ethertypes = [0x0800, 0x0806]
Howard Persh680b92a2012-03-31 13:34:35 -0700164 i = 0
165 while i < n:
166 self.ethertypes.append(random.randint(0, (1 << 16) - 1))
167 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700168 self.ethertypes = shuffle(self.ethertypes)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700169
170 self.ip_addrs = []
171 i = 0
172 while i < n:
173 self.ip_addrs.append(rand_nw_addr())
174 i = i + 1
175
176 self.ip_tos = []
177 i = 0
178 while i < n:
179 self.ip_tos.append(random.randint(0, (1 << 8) - 1) & ~3)
180 i = i + 1
181
rootf6af1672012-04-06 09:46:29 -0700182 self.ip_protos = [1, 6, 17]
Howard Persh680b92a2012-03-31 13:34:35 -0700183 i = 0
184 while i < n:
185 self.ip_protos.append(random.randint(0, (1 << 8) - 1))
186 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700187 self.ip_protos = shuffle(self.ip_protos)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700188
189 self.l4_ports = []
190 i = 0
191 while i < n:
192 self.l4_ports.append(random.randint(0, (1 << 16) - 1))
193 i = i + 1
194
195 def rand_priority(self):
196 return rand_pick(self.priorities)
197
198 def rand_dl_addr(self):
199 return rand_pick(self.dl_addrs)
200
201 def rand_vlan(self):
202 return rand_pick(self.vlans)
203
204 def rand_ethertype(self):
205 return rand_pick(self.ethertypes)
206
207 def rand_ip_addr(self):
208 return rand_pick(self.ip_addrs)
209
210 def rand_ip_tos(self):
211 return rand_pick(self.ip_tos)
212
213 def rand_ip_proto(self):
214 return rand_pick(self.ip_protos)
215
216 def rand_l4_port(self):
217 return rand_pick(self.l4_ports)
218
219
Howard Pershc7963582012-03-29 10:02:59 -0700220# TBD - These don't belong here
221
Howard Persh680b92a2012-03-31 13:34:35 -0700222all_wildcards_list = [ofp.OFPFW_IN_PORT,
Howard Persh680b92a2012-03-31 13:34:35 -0700223 ofp.OFPFW_DL_DST,
rootf6af1672012-04-06 09:46:29 -0700224 ofp.OFPFW_DL_SRC,
225 ofp.OFPFW_DL_VLAN,
226 ofp.OFPFW_DL_VLAN_PCP,
Howard Persh680b92a2012-03-31 13:34:35 -0700227 ofp.OFPFW_DL_TYPE,
rootf6af1672012-04-06 09:46:29 -0700228 ofp.OFPFW_NW_TOS,
Howard Persh680b92a2012-03-31 13:34:35 -0700229 ofp.OFPFW_NW_PROTO,
Howard Persh680b92a2012-03-31 13:34:35 -0700230 ofp.OFPFW_NW_SRC_MASK,
231 ofp.OFPFW_NW_DST_MASK,
rootf6af1672012-04-06 09:46:29 -0700232 ofp.OFPFW_TP_SRC,
233 ofp.OFPFW_TP_DST
Howard Persh680b92a2012-03-31 13:34:35 -0700234 ]
Howard Pershc7963582012-03-29 10:02:59 -0700235
Howard Persh3340d452012-04-06 16:45:21 -0700236# TBD - Need this because there are duplicates in ofp.ofp_flow_wildcards_map
237# -- FIX
rootf6af1672012-04-06 09:46:29 -0700238all_wildcard_names = {
239 1 : 'OFPFW_IN_PORT',
240 2 : 'OFPFW_DL_VLAN',
241 4 : 'OFPFW_DL_SRC',
242 8 : 'OFPFW_DL_DST',
243 16 : 'OFPFW_DL_TYPE',
244 32 : 'OFPFW_NW_PROTO',
245 64 : 'OFPFW_TP_SRC',
246 128 : 'OFPFW_TP_DST',
247 1048576 : 'OFPFW_DL_VLAN_PCP',
248 2097152 : 'OFPFW_NW_TOS'
249}
250
rootf6af1672012-04-06 09:46:29 -0700251def wildcard_set(x, w, val):
252 result = x
253 if w == ofp.OFPFW_NW_SRC_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700254 result = (result & ~ofp.OFPFW_NW_SRC_MASK) \
255 | (val << ofp.OFPFW_NW_SRC_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700256 elif w == ofp.OFPFW_NW_DST_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700257 result = (result & ~ofp.OFPFW_NW_DST_MASK) \
258 | (val << ofp.OFPFW_NW_DST_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700259 elif val == 0:
260 result = result & ~w
261 else:
262 result = result | w
263 return result
264
265def wildcard_get(x, w):
266 if w == ofp.OFPFW_NW_SRC_MASK:
267 return (x & ofp.OFPFW_NW_SRC_MASK) >> ofp.OFPFW_NW_SRC_SHIFT
268 if w == ofp.OFPFW_NW_DST_MASK:
269 return (x & ofp.OFPFW_NW_DST_MASK) >> ofp.OFPFW_NW_DST_SHIFT
270 return 1 if (x & w) != 0 else 0
271
Howard Persh8d21c1f2012-04-20 15:57:29 -0700272def wildcards_to_str(wildcards):
273 result = "{"
274 sep = ""
275 for w in all_wildcards_list:
276 if (wildcards & w) == 0:
277 continue
278 if w == ofp.OFPFW_NW_SRC_MASK:
279 n = wildcard_get(wildcards, w)
280 if n > 0:
281 result = result + sep + ("OFPFW_NW_SRC(%d)" % (n))
282 elif w == ofp.OFPFW_NW_DST_MASK:
283 n = wildcard_get(wildcards, w)
284 if n > 0:
285 result = result + sep + ("OFPFW_NW_DST(%d)" % (n))
286 else:
287 result = result + sep + all_wildcard_names[w]
288 sep = ", "
289 result = result +"}"
290 return result
Howard Pershc7963582012-03-29 10:02:59 -0700291
Howard Persh680b92a2012-03-31 13:34:35 -0700292all_actions_list = [ofp.OFPAT_OUTPUT,
293 ofp.OFPAT_SET_VLAN_VID,
294 ofp.OFPAT_SET_VLAN_PCP,
295 ofp.OFPAT_STRIP_VLAN,
296 ofp.OFPAT_SET_DL_SRC,
297 ofp.OFPAT_SET_DL_DST,
298 ofp.OFPAT_SET_NW_SRC,
299 ofp.OFPAT_SET_NW_DST,
300 ofp.OFPAT_SET_NW_TOS,
301 ofp.OFPAT_SET_TP_SRC,
302 ofp.OFPAT_SET_TP_DST,
303 ofp.OFPAT_ENQUEUE
304 ]
305
Howard Persh8d21c1f2012-04-20 15:57:29 -0700306def actions_bmap_to_str(bm):
307 result = "{"
308 sep = ""
309 for a in all_actions_list:
310 if ((1 << a) & bm) != 0:
311 result = result + sep + ofp.ofp_action_type_map[a]
312 sep = ", "
313 result = result + "}"
314 return result
315
Howard Persh680b92a2012-03-31 13:34:35 -0700316def dl_addr_to_str(a):
317 return "%x:%x:%x:%x:%x:%x" % tuple(a)
318
319def ip_addr_to_str(a, n):
rootf6af1672012-04-06 09:46:29 -0700320 if n is not None:
321 a = a & ~((1 << (32 - n)) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700322 result = "%d.%d.%d.%d" % (a >> 24, \
323 (a >> 16) & 0xff, \
324 (a >> 8) & 0xff, \
325 a & 0xff \
326 )
327 if n is not None:
328 result = result + ("/%d" % (n))
329 return result
330
Howard Pershc7963582012-03-29 10:02:59 -0700331
rootf6af1672012-04-06 09:46:29 -0700332class Flow_Cfg:
Howard Pershc7963582012-03-29 10:02:59 -0700333 # Members:
334 # - match
335 # - idle_timeout
336 # - hard_timeout
337 # - priority
338 # - action_list
339
340 def __init__(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700341 self.priority = 0
Rich Laneed1fa2d2013-01-08 13:23:37 -0800342 self.match = ofp.ofp_match()
Howard Pershc7963582012-03-29 10:02:59 -0700343 self.match.wildcards = ofp.OFPFW_ALL
344 self.idle_timeout = 0
345 self.hard_timeout = 0
Howard Pershc7963582012-03-29 10:02:59 -0700346 self.actions = action_list.action_list()
347
rootf6af1672012-04-06 09:46:29 -0700348 # {pri, match} is considered a flow key
349 def key_equal(self, x):
Howard Persh680b92a2012-03-31 13:34:35 -0700350 if self.priority != x.priority:
351 return False
352 # TBD - Should this logic be moved to ofp_match.__eq__()?
353 if self.match.wildcards != x.match.wildcards:
354 return False
rootf6af1672012-04-06 09:46:29 -0700355 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700356 and self.match.in_port != x.match.in_port:
357 return False
rootf6af1672012-04-06 09:46:29 -0700358 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700359 and self.match.dl_dst != x.match.dl_dst:
360 return False
rootf6af1672012-04-06 09:46:29 -0700361 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0 \
362 and self.match.dl_src != x.match.dl_src:
363 return False
364 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700365 and self.match.dl_vlan != x.match.dl_vlan:
366 return False
rootf6af1672012-04-06 09:46:29 -0700367 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700368 and self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
369 return False
rootf6af1672012-04-06 09:46:29 -0700370 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700371 and self.match.dl_type != x.match.dl_type:
372 return False
rootf6af1672012-04-06 09:46:29 -0700373 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700374 and self.match.nw_tos != x.match.nw_tos:
375 return False
rootf6af1672012-04-06 09:46:29 -0700376 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700377 and self.match.nw_proto != x.match.nw_proto:
378 return False
rootf6af1672012-04-06 09:46:29 -0700379 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
380 if n < 32:
381 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700382 if (self.match.nw_src & m) != (x.match.nw_src & m):
383 return False
rootf6af1672012-04-06 09:46:29 -0700384 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
385 if n < 32:
386 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700387 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
388 return False
rootf6af1672012-04-06 09:46:29 -0700389 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0 \
390 and self.match.tp_src != x.match.tp_src:
Howard Persh680b92a2012-03-31 13:34:35 -0700391 return False
rootf6af1672012-04-06 09:46:29 -0700392 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0 \
393 and self.match.tp_dst != x.match.tp_dst:
394 return False
395 return True
396
Howard Persh5f3c83f2012-04-13 09:57:10 -0700397 def actions_equal(self, x):
Rich Lane2014f9b2012-10-05 15:29:40 -0700398 if test_param_get("conservative_ordered_actions", True):
Howard Persh5f3c83f2012-04-13 09:57:10 -0700399 # Compare actions lists as unordered
400
root2843d2b2012-04-06 10:27:46 -0700401 aa = copy.deepcopy(x.actions.actions)
402 for a in self.actions.actions:
403 i = 0
404 while i < len(aa):
405 if a == aa[i]:
406 break
407 i = i + 1
408 if i < len(aa):
409 aa.pop(i)
410 else:
411 return False
412 return aa == []
413 else:
414 return self.actions == x.actions
Howard Persh5f3c83f2012-04-13 09:57:10 -0700415
416 def non_key_equal(self, x):
417 if self.cookie != x.cookie:
418 return False
419 if self.idle_timeout != x.idle_timeout:
420 return False
421 if self.hard_timeout != x.hard_timeout:
422 return False
423 return self.actions_equal(x)
rootf6af1672012-04-06 09:46:29 -0700424
root2843d2b2012-04-06 10:27:46 -0700425 def key_str(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700426 result = "priority=%d" % self.priority
427 # TBD - Would be nice if ofp_match.show() was better behaved
428 # (no newlines), and more intuitive (things in hex where approprate), etc.
Howard Persh8d21c1f2012-04-20 15:57:29 -0700429 result = result + (", wildcards=0x%x=%s" \
430 % (self.match.wildcards, \
431 wildcards_to_str(self.match.wildcards) \
432 )
433 )
rootf6af1672012-04-06 09:46:29 -0700434 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700435 result = result + (", in_port=%d" % (self.match.in_port))
rootf6af1672012-04-06 09:46:29 -0700436 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700437 result = result + (", dl_dst=%s" \
438 % (dl_addr_to_str(self.match.dl_dst)) \
439 )
rootf6af1672012-04-06 09:46:29 -0700440 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700441 result = result + (", dl_src=%s" \
442 % (dl_addr_to_str(self.match.dl_src)) \
443 )
rootf6af1672012-04-06 09:46:29 -0700444 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700445 result = result + (", dl_vlan=%d" % (self.match.dl_vlan))
rootf6af1672012-04-06 09:46:29 -0700446 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700447 result = result + (", dl_vlan_pcp=%d" % (self.match.dl_vlan_pcp))
rootf6af1672012-04-06 09:46:29 -0700448 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700449 result = result + (", dl_type=0x%x" % (self.match.dl_type))
rootf6af1672012-04-06 09:46:29 -0700450 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700451 result = result + (", nw_tos=0x%x" % (self.match.nw_tos))
rootf6af1672012-04-06 09:46:29 -0700452 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700453 result = result + (", nw_proto=%d" % (self.match.nw_proto))
rootf6af1672012-04-06 09:46:29 -0700454 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700455 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700456 result = result + (", nw_src=%s" % \
457 (ip_addr_to_str(self.match.nw_src, 32 - n)) \
458 )
rootf6af1672012-04-06 09:46:29 -0700459 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700460 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700461 result = result + (", nw_dst=%s" % \
462 (ip_addr_to_str(self.match.nw_dst, 32 - n)) \
463 )
rootf6af1672012-04-06 09:46:29 -0700464 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700465 result = result + (", tp_src=%d" % self.match.tp_src)
rootf6af1672012-04-06 09:46:29 -0700466 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700467 result = result + (", tp_dst=%d" % self.match.tp_dst)
rootf6af1672012-04-06 09:46:29 -0700468 return result
469
470 def __eq__(self, x):
471 return (self.key_equal(x) and self.non_key_equal(x))
472
473 def __str__(self):
root2843d2b2012-04-06 10:27:46 -0700474 result = self.key_str()
475 result = result + (", cookie=%d" % self.cookie)
Howard Persh680b92a2012-03-31 13:34:35 -0700476 result = result + (", idle_timeout=%d" % self.idle_timeout)
477 result = result + (", hard_timeout=%d" % self.hard_timeout)
Howard Persh680b92a2012-03-31 13:34:35 -0700478 for a in self.actions.actions:
479 result = result + (", action=%s" % ofp.ofp_action_type_map[a.type])
480 if a.type == ofp.OFPAT_OUTPUT:
481 result = result + ("(%d)" % (a.port))
482 elif a.type == ofp.OFPAT_SET_VLAN_VID:
483 result = result + ("(%d)" % (a.vlan_vid))
484 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
485 result = result + ("(%d)" % (a.vlan_pcp))
486 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
487 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
488 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
489 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
490 elif a.type == ofp.OFPAT_SET_NW_TOS:
491 result = result + ("(0x%x)" % (a.nw_tos))
492 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
493 result = result + ("(%d)" % (a.tp_port))
494 elif a.type == ofp.OFPAT_ENQUEUE:
495 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
496 return result
Howard Pershc7963582012-03-29 10:02:59 -0700497
Howard Persh8d21c1f2012-04-20 15:57:29 -0700498 def rand_actions_ordered(self, fi, valid_actions, valid_ports, valid_queues):
Howard Persh3340d452012-04-06 16:45:21 -0700499 # Action lists are ordered, so pick an ordered random subset of
500 # supported actions
Howard Pershc1199d52012-04-11 14:21:32 -0700501
Rich Lane2014f9b2012-10-05 15:29:40 -0700502 actions_force = test_param_get("actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700503 if actions_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700504 logging.info("Forced actions:")
505 logging.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700506
Dan Talayco910a8282012-04-07 00:05:20 -0700507 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh3340d452012-04-06 16:45:21 -0700508 supported_actions = []
509 for a in all_actions_list:
510 if ((1 << a) & valid_actions) != 0:
511 supported_actions.append(a)
512
Howard Pershc1199d52012-04-11 14:21:32 -0700513 actions \
514 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
515
516 for a in all_actions_list:
517 if ((1 << a) & actions_force) != 0:
518 actions.append(a)
519
520 actions = shuffle(actions)
Howard Persh3340d452012-04-06 16:45:21 -0700521
Howard Persh6a3698d2012-08-21 14:26:39 -0700522 set_vlanf = False
523 strip_vlanf = False
Howard Persh3340d452012-04-06 16:45:21 -0700524 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700525 for a in actions:
Dan Talayco910a8282012-04-07 00:05:20 -0700526 act = None
Howard Persh3340d452012-04-06 16:45:21 -0700527 if a == ofp.OFPAT_OUTPUT:
528 pass # OUTPUT actions must come last
529 elif a == ofp.OFPAT_SET_VLAN_VID:
Howard Persh6a3698d2012-08-21 14:26:39 -0700530 if not strip_vlanf:
531 act = action.action_set_vlan_vid()
532 act.vlan_vid = fi.rand_vlan()
533 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700534 elif a == ofp.OFPAT_SET_VLAN_PCP:
Howard Persh6a3698d2012-08-21 14:26:39 -0700535 if not strip_vlanf:
536 act = action.action_set_vlan_pcp()
537 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
538 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700539 elif a == ofp.OFPAT_STRIP_VLAN:
Howard Persh6a3698d2012-08-21 14:26:39 -0700540 if not set_vlanf:
541 act = action.action_strip_vlan()
542 strip_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700543 elif a == ofp.OFPAT_SET_DL_SRC:
544 act = action.action_set_dl_src()
545 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700546 elif a == ofp.OFPAT_SET_DL_DST:
547 act = action.action_set_dl_dst()
548 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700549 elif a == ofp.OFPAT_SET_NW_SRC:
550 act = action.action_set_nw_src()
551 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700552 elif a == ofp.OFPAT_SET_NW_DST:
553 act = action.action_set_nw_dst()
554 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700555 elif a == ofp.OFPAT_SET_NW_TOS:
556 act = action.action_set_nw_tos()
557 act.nw_tos = fi.rand_ip_tos()
Howard Persh3340d452012-04-06 16:45:21 -0700558 elif a == ofp.OFPAT_SET_TP_SRC:
559 act = action.action_set_tp_src()
560 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700561 elif a == ofp.OFPAT_SET_TP_DST:
562 act = action.action_set_tp_dst()
563 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700564 elif a == ofp.OFPAT_ENQUEUE:
565 pass # Enqueue actions must come last
Dan Talayco910a8282012-04-07 00:05:20 -0700566 if act:
Dan Talayco910a8282012-04-07 00:05:20 -0700567 self.actions.add(act)
568
Howard Persh3340d452012-04-06 16:45:21 -0700569 p = random.randint(1, 100)
Howard Pershc1199d52012-04-11 14:21:32 -0700570 if (((1 << ofp.OFPAT_ENQUEUE) & actions_force) != 0 or p <= 33) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700571 and len(valid_queues) > 0 \
572 and ofp.OFPAT_ENQUEUE in actions:
Howard Pershc1199d52012-04-11 14:21:32 -0700573 # In not forecd, one third of the time, include ENQUEUE actions
574 # at end of list
Howard Persh3340d452012-04-06 16:45:21 -0700575 # At most 1 ENQUEUE action
576 act = action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700577 (act.port, act.queue_id) = rand_pick(valid_queues)
Howard Persh3340d452012-04-06 16:45:21 -0700578 self.actions.add(act)
Howard Pershc1199d52012-04-11 14:21:32 -0700579 if (((1 << ofp.OFPAT_OUTPUT) & actions_force) != 0 \
580 or (p > 33 and p <= 66) \
581 ) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700582 and len(valid_ports) > 0 \
Howard Pershc1199d52012-04-11 14:21:32 -0700583 and ofp.OFPAT_OUTPUT in actions:
Howard Persh3340d452012-04-06 16:45:21 -0700584 # One third of the time, include OUTPUT actions at end of list
585 port_idxs = shuffle(range(len(valid_ports)))
586 # Only 1 output action allowed if IN_PORT wildcarded
587 n = 1 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) != 0 \
588 else random.randint(1, len(valid_ports))
589 port_idxs = port_idxs[0 : n]
590 for pi in port_idxs:
591 act = action.action_output()
592 act.port = valid_ports[pi]
Howard Persh3340d452012-04-06 16:45:21 -0700593 if act.port != ofp.OFPP_IN_PORT \
594 or wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
595 # OUTPUT(IN_PORT) only valid if OFPFW_IN_PORT not wildcarded
596 self.actions.add(act)
597 else:
598 # One third of the time, include neither
599 pass
600
601
602 # Randomize flow data for flow modifies (i.e. cookie and actions)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700603 def rand_mod(self, fi, valid_actions, valid_ports, valid_queues):
rootf6af1672012-04-06 09:46:29 -0700604 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700605
Dan Talayco910a8282012-04-07 00:05:20 -0700606 # By default, test with conservative ordering conventions
607 # This should probably be indicated in a profile
Rich Lane2014f9b2012-10-05 15:29:40 -0700608 if test_param_get("conservative_ordered_actions", True):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700609 self.rand_actions_ordered(fi, valid_actions, valid_ports, valid_queues)
Howard Persh3340d452012-04-06 16:45:21 -0700610 return self
611
Rich Lane2014f9b2012-10-05 15:29:40 -0700612 actions_force = test_param_get("actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700613 if actions_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700614 logging.info("Forced actions:")
615 logging.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700616
617 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh680b92a2012-03-31 13:34:35 -0700618 supported_actions = []
619 for a in all_actions_list:
620 if ((1 << a) & valid_actions) != 0:
621 supported_actions.append(a)
622
Howard Pershc1199d52012-04-11 14:21:32 -0700623 actions \
624 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
625
626 for a in all_actions_list:
627 if ((1 << a) & actions_force) != 0:
628 actions.append(a)
629
630 actions = shuffle(actions)
Howard Pershc7963582012-03-29 10:02:59 -0700631
632 self.actions = action_list.action_list()
Howard Pershc1199d52012-04-11 14:21:32 -0700633 for a in actions:
Howard Pershc7963582012-03-29 10:02:59 -0700634 if a == ofp.OFPAT_OUTPUT:
635 # TBD - Output actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700636 if len(valid_ports) == 0:
637 continue
Howard Pershc7963582012-03-29 10:02:59 -0700638 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700639 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700640 for pi in port_idxs:
641 act = action.action_output()
Howard Persh680b92a2012-03-31 13:34:35 -0700642 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700643 self.actions.add(act)
644 elif a == ofp.OFPAT_SET_VLAN_VID:
645 act = action.action_set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700646 act.vlan_vid = fi.rand_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700647 self.actions.add(act)
648 elif a == ofp.OFPAT_SET_VLAN_PCP:
Dan Talayco910a8282012-04-07 00:05:20 -0700649 act = action.action_set_vlan_pcp()
650 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700651 elif a == ofp.OFPAT_STRIP_VLAN:
652 act = action.action_strip_vlan()
653 self.actions.add(act)
654 elif a == ofp.OFPAT_SET_DL_SRC:
655 act = action.action_set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700656 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700657 self.actions.add(act)
658 elif a == ofp.OFPAT_SET_DL_DST:
659 act = action.action_set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700660 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700661 self.actions.add(act)
662 elif a == ofp.OFPAT_SET_NW_SRC:
663 act = action.action_set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700664 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700665 self.actions.add(act)
666 elif a == ofp.OFPAT_SET_NW_DST:
667 act = action.action_set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700668 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700669 self.actions.add(act)
670 elif a == ofp.OFPAT_SET_NW_TOS:
671 act = action.action_set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700672 act.nw_tos = fi.rand_ip_tos()
Howard Pershc7963582012-03-29 10:02:59 -0700673 self.actions.add(act)
674 elif a == ofp.OFPAT_SET_TP_SRC:
675 act = action.action_set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700676 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700677 self.actions.add(act)
678 elif a == ofp.OFPAT_SET_TP_DST:
679 act = action.action_set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700680 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700681 self.actions.add(act)
682 elif a == ofp.OFPAT_ENQUEUE:
683 # TBD - Enqueue actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700684 if len(valid_queues) == 0:
685 continue
686 qidxs = shuffle(range(len(valid_queues)))
687 qidxs = qidxs[0 : random.randint(1, len(valid_queues))]
688 for qi in qidxs:
Howard Pershc7963582012-03-29 10:02:59 -0700689 act = action.action_enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700690 (act.port, act.queue_id) = valid_queues[qi]
Howard Pershc7963582012-03-29 10:02:59 -0700691 self.actions.add(act)
692
693 return self
694
rootf6af1672012-04-06 09:46:29 -0700695 # Randomize flow cfg
Ed Swierk99a74de2012-08-22 06:40:54 -0700696 def rand(self, fi, wildcards_force, valid_wildcards, valid_actions, valid_ports,
697 valid_queues):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700698 if wildcards_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700699 logging.info("Wildcards forced:")
700 logging.info(wildcards_to_str(wildcards_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700701
rootf6af1672012-04-06 09:46:29 -0700702 # Start with no wildcards, i.e. everything specified
703 self.match.wildcards = 0
Howard Pershc1199d52012-04-11 14:21:32 -0700704
705 if wildcards_force != 0:
706 exact = False
707 else:
708 # Make approx. 5% of flows exact
709 exact = (random.randint(1, 100) <= 5)
rootf6af1672012-04-06 09:46:29 -0700710
711 # For each qualifier Q,
712 # if (wildcarding is not supported for Q,
713 # or an exact flow is specified
714 # or a coin toss comes up heads),
715 # specify Q
716 # else
717 # wildcard Q
718
Howard Pershc1199d52012-04-11 14:21:32 -0700719 if wildcard_get(wildcards_force, ofp.OFPFW_IN_PORT) == 0 \
720 and (wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
721 or exact \
722 or flip_coin() \
723 ):
rootf6af1672012-04-06 09:46:29 -0700724 self.match.in_port = rand_pick(valid_ports)
725 else:
Howard Persh3340d452012-04-06 16:45:21 -0700726 self.match.wildcards = wildcard_set(self.match.wildcards, \
727 ofp.OFPFW_IN_PORT, \
728 1 \
729 )
rootf6af1672012-04-06 09:46:29 -0700730
Howard Pershc1199d52012-04-11 14:21:32 -0700731 if wildcard_get(wildcards_force, ofp.OFPFW_DL_DST) == 0 \
732 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
733 or exact \
734 or flip_coin() \
735 ):
rootf6af1672012-04-06 09:46:29 -0700736 self.match.dl_dst = fi.rand_dl_addr()
737 else:
Howard Persh3340d452012-04-06 16:45:21 -0700738 self.match.wildcards = wildcard_set(self.match.wildcards, \
739 ofp.OFPFW_DL_DST, \
740 1 \
741 )
rootf6af1672012-04-06 09:46:29 -0700742
Howard Pershc1199d52012-04-11 14:21:32 -0700743 if wildcard_get(wildcards_force, ofp.OFPFW_DL_SRC) == 0 \
744 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
745 or exact \
746 or flip_coin() \
747 ):
rootf6af1672012-04-06 09:46:29 -0700748 self.match.dl_src = fi.rand_dl_addr()
749 else:
Howard Persh3340d452012-04-06 16:45:21 -0700750 self.match.wildcards = wildcard_set(self.match.wildcards, \
751 ofp.OFPFW_DL_SRC, \
752 1 \
753 )
rootf6af1672012-04-06 09:46:29 -0700754
Howard Pershc1199d52012-04-11 14:21:32 -0700755 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN) == 0 \
756 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
757 or exact \
758 or flip_coin() \
759 ):
rootf6af1672012-04-06 09:46:29 -0700760 self.match.dl_vlan = fi.rand_vlan()
761 else:
Howard Persh3340d452012-04-06 16:45:21 -0700762 self.match.wildcards = wildcard_set(self.match.wildcards, \
763 ofp.OFPFW_DL_VLAN, \
764 1 \
765 )
rootf6af1672012-04-06 09:46:29 -0700766
Howard Pershc1199d52012-04-11 14:21:32 -0700767 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN_PCP) == 0 \
768 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
769 or exact \
770 or flip_coin() \
771 ):
772 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
773 else:
774 self.match.wildcards = wildcard_set(self.match.wildcards, \
775 ofp.OFPFW_DL_VLAN_PCP, \
776 1 \
777 )
778
779 if wildcard_get(wildcards_force, ofp.OFPFW_DL_TYPE) == 0 \
780 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
781 or exact \
782 or flip_coin() \
783 ):
rootf6af1672012-04-06 09:46:29 -0700784 self.match.dl_type = fi.rand_ethertype()
785 else:
Howard Persh3340d452012-04-06 16:45:21 -0700786 self.match.wildcards = wildcard_set(self.match.wildcards, \
787 ofp.OFPFW_DL_TYPE, \
788 1 \
789 )
rootf6af1672012-04-06 09:46:29 -0700790
Howard Pershc1199d52012-04-11 14:21:32 -0700791 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_SRC_MASK)
792 if n == 0:
793 if exact or flip_coin():
794 n = 0
795 else:
796 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
797 if n > 32:
798 n = 32
799 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700800 self.match.wildcards = wildcard_set(self.match.wildcards, \
801 ofp.OFPFW_NW_SRC_MASK, \
802 n \
803 )
rootf6af1672012-04-06 09:46:29 -0700804 if n < 32:
805 self.match.nw_src = fi.rand_ip_addr() & ~((1 << n) - 1)
806 # Specifying any IP address match other than all bits
807 # don't care requires that Ethertype is one of {IP, ARP}
808 if flip_coin():
809 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700810 self.match.wildcards = wildcard_set(self.match.wildcards, \
811 ofp.OFPFW_DL_TYPE, \
812 0 \
813 )
rootf6af1672012-04-06 09:46:29 -0700814
Howard Pershc1199d52012-04-11 14:21:32 -0700815 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_DST_MASK)
816 if n == 0:
817 if exact or flip_coin():
818 n = 0
819 else:
820 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
821 if n > 32:
822 n = 32
823 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700824 self.match.wildcards = wildcard_set(self.match.wildcards, \
825 ofp.OFPFW_NW_DST_MASK, \
826 n \
827 )
rootf6af1672012-04-06 09:46:29 -0700828 if n < 32:
829 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
830 # Specifying any IP address match other than all bits
831 # don't care requires that Ethertype is one of {IP, ARP}
832 if flip_coin():
833 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700834 self.match.wildcards = wildcard_set(self.match.wildcards, \
835 ofp.OFPFW_DL_TYPE, \
836 0 \
837 )
rootf6af1672012-04-06 09:46:29 -0700838
Howard Pershc1199d52012-04-11 14:21:32 -0700839 if wildcard_get(wildcards_force, ofp.OFPFW_NW_TOS) == 0 \
840 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
841 or exact \
842 or flip_coin() \
843 ):
rootf6af1672012-04-06 09:46:29 -0700844 self.match.nw_tos = fi.rand_ip_tos()
845 # Specifying a TOS value requires that Ethertype is IP
846 if flip_coin():
847 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700848 self.match.wildcards = wildcard_set(self.match.wildcards, \
849 ofp.OFPFW_DL_TYPE, \
850 0 \
851 )
rootf6af1672012-04-06 09:46:29 -0700852 else:
Howard Persh3340d452012-04-06 16:45:21 -0700853 self.match.wildcards = wildcard_set(self.match.wildcards, \
854 ofp.OFPFW_NW_TOS, \
855 1 \
856 )
rootf6af1672012-04-06 09:46:29 -0700857
Dan Talayco910a8282012-04-07 00:05:20 -0700858 # Known issue on OVS with specifying nw_proto w/o dl_type as IP
Howard Pershc1199d52012-04-11 14:21:32 -0700859 if wildcard_get(wildcards_force, ofp.OFPFW_NW_PROTO) == 0 \
860 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
861 or exact \
862 or flip_coin() \
863 ):
Dan Talayco910a8282012-04-07 00:05:20 -0700864 self.match.nw_proto = fi.rand_ip_proto()
865 # Specifying an IP protocol requires that Ethertype is IP
866 if flip_coin():
867 self.match.dl_type = 0x0800
868 self.match.wildcards = wildcard_set(self.match.wildcards, \
869 ofp.OFPFW_DL_TYPE, \
870 0 \
871 )
872 else:
Howard Persh3340d452012-04-06 16:45:21 -0700873 self.match.wildcards = wildcard_set(self.match.wildcards, \
874 ofp.OFPFW_NW_PROTO, \
875 1 \
876 )
Dan Talayco910a8282012-04-07 00:05:20 -0700877
Howard Pershc1199d52012-04-11 14:21:32 -0700878 if wildcard_get(wildcards_force, ofp.OFPFW_TP_SRC) == 0 \
879 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
880 or exact\
881 or flip_coin() \
882 ):
rootf6af1672012-04-06 09:46:29 -0700883 self.match.tp_src = fi.rand_l4_port()
884 # Specifying a L4 port requires that IP protcol is
885 # one of {ICMP, TCP, UDP}
886 if flip_coin():
887 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700888 self.match.wildcards = wildcard_set(self.match.wildcards, \
889 ofp.OFPFW_NW_PROTO, \
890 0 \
891 )
rootf6af1672012-04-06 09:46:29 -0700892 # Specifying a L4 port requirues that Ethertype is IP
893 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700894 self.match.wildcards = wildcard_set(self.match.wildcards, \
895 ofp.OFPFW_DL_TYPE, \
896 0 \
897 )
rootf6af1672012-04-06 09:46:29 -0700898 if self.match.nw_proto == 1:
899 self.match.tp_src = self.match.tp_src & 0xff
900 else:
Howard Persh3340d452012-04-06 16:45:21 -0700901 self.match.wildcards = wildcard_set(self.match.wildcards, \
902 ofp.OFPFW_TP_SRC, \
903 1 \
904 )
rootf6af1672012-04-06 09:46:29 -0700905
Howard Pershc1199d52012-04-11 14:21:32 -0700906 if wildcard_get(wildcards_force, ofp.OFPFW_TP_DST) == 0 \
907 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
908 or exact \
909 or flip_coin() \
910 ):
rootf6af1672012-04-06 09:46:29 -0700911 self.match.tp_dst = fi.rand_l4_port()
912 # Specifying a L4 port requires that IP protcol is
913 # one of {ICMP, TCP, UDP}
914 if flip_coin():
915 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700916 self.match.wildcards = wildcard_set(self.match.wildcards, \
917 ofp.OFPFW_NW_PROTO, \
918 0 \
919 )
rootf6af1672012-04-06 09:46:29 -0700920 # Specifying a L4 port requirues that Ethertype is IP
921 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700922 self.match.wildcards = wildcard_set(self.match.wildcards, \
923 ofp.OFPFW_DL_TYPE, \
924 0 \
925 )
rootf6af1672012-04-06 09:46:29 -0700926 if self.match.nw_proto == 1:
927 self.match.tp_dst = self.match.tp_dst & 0xff
928 else:
Howard Persh3340d452012-04-06 16:45:21 -0700929 self.match.wildcards = wildcard_set(self.match.wildcards, \
930 ofp.OFPFW_TP_DST, \
931 1 \
932 )
rootf6af1672012-04-06 09:46:29 -0700933
934 # If nothing is wildcarded, it is an exact flow spec -- some switches
Howard Persh3340d452012-04-06 16:45:21 -0700935 # (Open vSwitch, for one) *require* that exact flow specs
936 # have priority 65535.
937 self.priority = 65535 if self.match.wildcards == 0 \
938 else fi.rand_priority()
rootf6af1672012-04-06 09:46:29 -0700939
940 # N.B. Don't make the timeout too short, else the flow might
941 # disappear before we get a chance to check for it.
942 t = random.randint(0, 65535)
943 self.idle_timeout = 0 if t < 60 else t
944 t = random.randint(0, 65535)
945 self.hard_timeout = 0 if t < 60 else t
946
Howard Persh8d21c1f2012-04-20 15:57:29 -0700947 self.rand_mod(fi, valid_actions, valid_ports, valid_queues)
rootf6af1672012-04-06 09:46:29 -0700948
949 return self
950
951 # Return flow cfg in canonical form
Howard Persh3340d452012-04-06 16:45:21 -0700952 # - There are dependencies between flow qualifiers, e.g. it only makes
953 # sense to qualify nw_proto if dl_type is qualified to be 0x0800 (IP).
954 # The canonical form of flow match criteria will "wildcard out"
955 # all such cases.
rootf6af1672012-04-06 09:46:29 -0700956 def canonical(self):
957 result = copy.deepcopy(self)
Howard Persh07d99e62012-04-09 15:26:57 -0700958
959 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_VLAN) != 0:
960 result.match.wildcards = wildcard_set(result.match.wildcards, \
961 ofp.OFPFW_DL_VLAN_PCP, \
962 1 \
963 )
964
rootf6af1672012-04-06 09:46:29 -0700965 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
966 or result.match.dl_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700967 # dl_tyoe is wildcarded, or specified as something other
968 # than IP or ARP
Howard Persh07d99e62012-04-09 15:26:57 -0700969 # => nw_src, nw_dst, nw_proto cannot be specified,
970 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700971 result.match.wildcards = wildcard_set(result.match.wildcards, \
972 ofp.OFPFW_NW_SRC_MASK, \
973 32 \
974 )
975 result.match.wildcards = wildcard_set(result.match.wildcards, \
976 ofp.OFPFW_NW_DST_MASK, \
977 32 \
978 )
Howard Persh3340d452012-04-06 16:45:21 -0700979 result.match.wildcards = wildcard_set(result.match.wildcards, \
980 ofp.OFPFW_NW_PROTO, \
981 1 \
982 )
Howard Persh07d99e62012-04-09 15:26:57 -0700983
984 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
985 or result.match.dl_type != 0x0800:
986 # dl_type is wildcarded, or specified as something other than IP
987 # => nw_tos, tp_src and tp_dst cannot be specified,
988 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700989 result.match.wildcards = wildcard_set(result.match.wildcards, \
990 ofp.OFPFW_NW_TOS, \
991 1 \
992 )
993 result.match.wildcards = wildcard_set(result.match.wildcards, \
994 ofp.OFPFW_TP_SRC, \
995 1 \
996 )
997 result.match.wildcards = wildcard_set(result.match.wildcards, \
998 ofp.OFPFW_TP_DST, \
999 1 \
1000 )
Howard Persh07d99e62012-04-09 15:26:57 -07001001 result.match.wildcards = wildcard_set(result.match.wildcards, \
1002 ofp.OFPFW_NW_SRC_MASK, \
1003 32 \
1004 )
1005 result.match.wildcards = wildcard_set(result.match.wildcards, \
1006 ofp.OFPFW_NW_DST_MASK, \
1007 32 \
1008 )
1009 result.match.wildcards = wildcard_set(result.match.wildcards, \
1010 ofp.OFPFW_NW_PROTO, \
1011 1 \
1012 )
1013
rootf6af1672012-04-06 09:46:29 -07001014 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
1015 or result.match.nw_proto not in [1, 6, 17]:
Howard Persh3340d452012-04-06 16:45:21 -07001016 # nw_proto is wildcarded, or specified as something other than ICMP,
1017 # TCP or UDP
rootf6af1672012-04-06 09:46:29 -07001018 # => tp_src and tp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001019 result.match.wildcards = wildcard_set(result.match.wildcards, \
1020 ofp.OFPFW_TP_SRC, \
1021 1 \
1022 )
1023 result.match.wildcards = wildcard_set(result.match.wildcards, \
1024 ofp.OFPFW_TP_DST, \
1025 1 \
1026 )
rootf6af1672012-04-06 09:46:29 -07001027 return result
1028
Howard Persh680b92a2012-03-31 13:34:35 -07001029 # Overlap check
1030 # delf == True <=> Check for delete overlap, else add overlap
1031 # "Add overlap" is defined as there exists a packet that could match both the
1032 # receiver and argument flowspecs
1033 # "Delete overlap" is defined as the specificity of the argument flowspec
1034 # is greater than or equal to the specificity of the receiver flowspec
1035 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -07001036 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
1037 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001038 if self.match.in_port != x.match.in_port:
1039 return False # Both specified, and not equal
1040 elif delf:
1041 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001042 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
1043 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001044 if self.match.dl_vlan != x.match.dl_vlan:
1045 return False # Both specified, and not equal
1046 elif delf:
1047 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001048 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
1049 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001050 if self.match.dl_src != x.match.dl_src:
1051 return False # Both specified, and not equal
1052 elif delf:
1053 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001054 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
1055 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001056 if self.match.dl_dst != x.match.dl_dst:
1057 return False # Both specified, and not equal
1058 elif delf:
1059 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001060 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
1061 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001062 if self.match.dl_type != x.match.dl_type:
1063 return False # Both specified, and not equal
1064 elif delf:
1065 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -07001066 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
1067 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001068 if self.match.nw_proto != x.match.nw_proto:
1069 return False # Both specified, and not equal
1070 elif delf:
1071 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001072 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
1073 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001074 if self.match.tp_src != x.match.tp_src:
1075 return False # Both specified, and not equal
1076 elif delf:
1077 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001078 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
1079 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001080 if self.match.tp_dst != x.match.tp_dst:
1081 return False # Both specified, and not equal
1082 elif delf:
1083 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001084 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
1085 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001086 if delf and na < nb:
1087 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001088 if (na < 32 and nb < 32):
1089 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1090 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -07001091 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -07001092 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
1093 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001094 if delf and na < nb:
1095 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001096 if (na < 32 and nb < 32):
1097 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1098 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
rootf6af1672012-04-06 09:46:29 -07001099 return False # Overlapping bits not equal
1100 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
1101 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001102 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
1103 return False # Both specified, and not equal
1104 elif delf:
1105 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001106 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
1107 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001108 if self.match.nw_tos != x.match.nw_tos:
1109 return False # Both specified, and not equal
1110 elif delf:
1111 return False # Receiver more specific
1112 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -07001113
1114 def to_flow_mod_msg(self, msg):
1115 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -07001116 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001117 msg.idle_timeout = self.idle_timeout
1118 msg.hard_timeout = self.hard_timeout
1119 msg.priority = self.priority
1120 msg.actions = self.actions
1121 return msg
1122
1123 def from_flow_stat(self, msg):
1124 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -07001125 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001126 self.idle_timeout = msg.idle_timeout
1127 self.hard_timeout = msg.hard_timeout
1128 self.priority = msg.priority
1129 self.actions = msg.actions
1130
rootf6af1672012-04-06 09:46:29 -07001131 def from_flow_rem(self, msg):
1132 self.match = msg.match
1133 self.idle_timeout = msg.idle_timeout
1134 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -07001135
Howard Pershc7963582012-03-29 10:02:59 -07001136
rootf6af1672012-04-06 09:46:29 -07001137class Flow_Tbl:
1138 def clear(self):
1139 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001140
rootf6af1672012-04-06 09:46:29 -07001141 def __init__(self):
1142 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001143
rootf6af1672012-04-06 09:46:29 -07001144 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001145 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001146
1147 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001148 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001149
1150 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001151 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001152
1153 def values(self):
1154 return self.dict.values()
1155
1156 def count(self):
1157 return len(self.dict)
1158
Ed Swierk99a74de2012-08-22 06:40:54 -07001159 def rand(self, wildcards_force, sw, fi, num_flows):
rootf6af1672012-04-06 09:46:29 -07001160 self.clear()
1161 i = 0
1162 tbl = 0
1163 j = 0
1164 while i < num_flows:
1165 fc = Flow_Cfg()
1166 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001167 wildcards_force, \
rootf6af1672012-04-06 09:46:29 -07001168 sw.tbl_stats.stats[tbl].wildcards, \
1169 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001170 sw.valid_ports, \
1171 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001172 )
1173 fc = fc.canonical()
1174 if self.find(fc):
1175 continue
1176 fc.send_rem = False
1177 self.insert(fc)
1178 i = i + 1
1179 j = j + 1
1180 if j >= sw.tbl_stats.stats[tbl].max_entries:
1181 tbl = tbl + 1
1182 j = 0
1183
1184
1185class Switch:
1186 # Members:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001187 # controller - switch's test controller
1188 # sw_features - switch's OFPT_FEATURES_REPLY message
1189 # valid_ports - list of valid port numbers
1190 # valid_queues - list of valid [port, queue] pairs
1191 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1192 # queue_stats - switch's OFPT_STATS_REPLY message, for queue stats request
1193 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1194 # flow_tbl - (test's idea of) switch's flow table
rootf6af1672012-04-06 09:46:29 -07001195
1196 def __init__(self):
Howard Persh8d21c1f2012-04-20 15:57:29 -07001197 self.controller = None
1198 self.sw_features = None
1199 self.valid_ports = []
1200 self.valid_queues = []
1201 self.tbl_stats = None
1202 self.flow_stats = None
1203 self.flow_tbl = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001204 self.error_msgs = []
1205 self.removed_msgs = []
1206
1207 def error_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001208 logging.info("Got an ERROR message, type=%d, code=%d" \
Ed Swierk99a74de2012-08-22 06:40:54 -07001209 % (msg.type, msg.code) \
1210 )
Rich Lane9a003812012-10-04 17:17:59 -07001211 logging.info("Message header:")
1212 logging.info(msg.header.show())
Ed Swierk99a74de2012-08-22 06:40:54 -07001213 self.error_msgs.append(msg)
1214
1215 def removed_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001216 logging.info("Got a REMOVED message")
1217 logging.info("Message header:")
1218 logging.info(msg.header.show())
Ed Swierk99a74de2012-08-22 06:40:54 -07001219 self.removed_msgs.append(msg)
rootf6af1672012-04-06 09:46:29 -07001220
Howard Persh3340d452012-04-06 16:45:21 -07001221 def controller_set(self, controller):
1222 self.controller = controller
1223 # Register error message handler
Ed Swierk99a74de2012-08-22 06:40:54 -07001224 self.error_msgs = []
1225 self.removed_msgs = []
1226 controller.register(ofp.OFPT_ERROR, self.error_handler)
1227 controller.register(ofp.OFPT_FLOW_REMOVED, self.removed_handler)
Howard Persh3340d452012-04-06 16:45:21 -07001228
rootf6af1672012-04-06 09:46:29 -07001229 def features_get(self):
1230 # Get switch features
1231 request = message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001232 (self.sw_features, pkt) = self.controller.transact(request)
rootf6af1672012-04-06 09:46:29 -07001233 if self.sw_features is None:
Rich Lane9a003812012-10-04 17:17:59 -07001234 logging.error("Get switch features failed")
rootf6af1672012-04-06 09:46:29 -07001235 return False
1236 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Rich Lane9a003812012-10-04 17:17:59 -07001237 logging.info("Ports reported by switch:")
1238 logging.info(self.valid_ports)
Rich Lane2014f9b2012-10-05 15:29:40 -07001239 ports_override = test_param_get("ports", [])
Howard Persh8d21c1f2012-04-20 15:57:29 -07001240 if ports_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001241 logging.info("Overriding ports to:")
1242 logging.info(ports_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001243 self.valid_ports = ports_override
1244
Howard Persh3340d452012-04-06 16:45:21 -07001245 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1246 # is that universal?
1247
1248 # TBD - There seems to be variability in which switches support which
1249 # ports; need to sort that out
1250 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1251# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1252# ofp.OFPP_NORMAL, \
1253# ofp.OFPP_FLOOD, \
1254# ofp.OFPP_ALL, \
1255# ofp.OFPP_CONTROLLER \
1256# ] \
1257# )
Rich Lane9a003812012-10-04 17:17:59 -07001258 logging.info("Supported actions reported by switch:")
1259 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001260 % (self.sw_features.actions, \
1261 actions_bmap_to_str(self.sw_features.actions) \
1262 ) \
1263 )
Rich Lane2014f9b2012-10-05 15:29:40 -07001264 actions_override = test_param_get("actions", -1)
Howard Persh07d99e62012-04-09 15:26:57 -07001265 if actions_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001266 logging.info("Overriding supported actions to:")
1267 logging.info(actions_bmap_to_str(actions_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001268 self.sw_features.actions = actions_override
rootf6af1672012-04-06 09:46:29 -07001269 return True
1270
1271 def tbl_stats_get(self):
1272 # Get table stats
Howard Persh680b92a2012-03-31 13:34:35 -07001273 request = message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001274 (self.tbl_stats, pkt) = self.controller.transact(request)
Howard Persh07d99e62012-04-09 15:26:57 -07001275 if self.tbl_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001276 logging.error("Get table stats failed")
Howard Persh07d99e62012-04-09 15:26:57 -07001277 return False
Howard Persh8d21c1f2012-04-20 15:57:29 -07001278 i = 0
Howard Persh07d99e62012-04-09 15:26:57 -07001279 for ts in self.tbl_stats.stats:
Rich Lane9a003812012-10-04 17:17:59 -07001280 logging.info("Supported wildcards for table %d reported by switch:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001281 % (i)
1282 )
Rich Lane9a003812012-10-04 17:17:59 -07001283 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001284 % (ts.wildcards, \
1285 wildcards_to_str(ts.wildcards) \
1286 ) \
1287 )
Rich Lane2014f9b2012-10-05 15:29:40 -07001288 wildcards_override = test_param_get("wildcards", -1)
Howard Persh07d99e62012-04-09 15:26:57 -07001289 if wildcards_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001290 logging.info("Overriding supported wildcards for table %d to:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001291 % (i)
1292 )
Rich Lane9a003812012-10-04 17:17:59 -07001293 logging.info(wildcards_to_str(wildcards_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001294 ts.wildcards = wildcards_override
Howard Persh8d21c1f2012-04-20 15:57:29 -07001295 i = i + 1
Howard Persh07d99e62012-04-09 15:26:57 -07001296 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001297
Howard Persh8d21c1f2012-04-20 15:57:29 -07001298 def queue_stats_get(self):
1299 # Get queue stats
1300 request = message.queue_stats_request()
1301 request.port_no = ofp.OFPP_ALL
1302 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001303 (self.queue_stats, pkt) = self.controller.transact(request)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001304 if self.queue_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001305 logging.error("Get queue stats failed")
Howard Persh8d21c1f2012-04-20 15:57:29 -07001306 return False
1307 self.valid_queues = map(lambda x: (x.port_no, x.queue_id), \
1308 self.queue_stats.stats \
1309 )
Rich Lane9a003812012-10-04 17:17:59 -07001310 logging.info("(Port, queue) pairs reported by switch:")
1311 logging.info(self.valid_queues)
Rich Lane2014f9b2012-10-05 15:29:40 -07001312 queues_override = test_param_get("queues", [])
Howard Persh8d21c1f2012-04-20 15:57:29 -07001313 if queues_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001314 logging.info("Overriding (port, queue) pairs to:")
1315 logging.info(queues_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001316 self.valid_queues = queues_override
1317 return True
1318
1319 def connect(self, controller):
1320 # Connect to controller, and get all switch capabilities
1321 self.controller_set(controller)
1322 return (self.features_get() \
1323 and self.tbl_stats_get() \
1324 and self.queue_stats_get() \
1325 )
1326
Howard Pershc1199d52012-04-11 14:21:32 -07001327 def flow_stats_get(self, limit = 10000):
rootf6af1672012-04-06 09:46:29 -07001328 request = message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -07001329 query_match = ofp.ofp_match()
1330 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001331 request.match = query_match
1332 request.table_id = 0xff
1333 request.out_port = ofp.OFPP_NONE;
Rich Lane5c3151c2013-01-03 17:15:41 -08001334 self.controller.message_send(request)
Howard Persh3340d452012-04-06 16:45:21 -07001335 # <TBD>
1336 # Glue together successive reponse messages for stats reply.
1337 # Looking at the "more" flag and performing re-assembly
1338 # should be a part of the infrastructure.
1339 # </TBD>
1340 n = 0
1341 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -07001342 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY)
Howard Persh3340d452012-04-06 16:45:21 -07001343 if resp is None:
Howard Pershc1199d52012-04-11 14:21:32 -07001344 return False # Did not get expected response
Howard Persh3340d452012-04-06 16:45:21 -07001345 if n == 0:
1346 self.flow_stats = resp
1347 else:
1348 self.flow_stats.stats.extend(resp.stats)
1349 n = n + 1
Howard Pershc1199d52012-04-11 14:21:32 -07001350 if len(self.flow_stats.stats) > limit:
Rich Lane9a003812012-10-04 17:17:59 -07001351 logging.error("Too many flows returned")
Howard Pershc1199d52012-04-11 14:21:32 -07001352 return False
1353 if (resp.flags & 1) == 0:
1354 break # No more responses expected
Howard Persh3340d452012-04-06 16:45:21 -07001355 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001356
rootf6af1672012-04-06 09:46:29 -07001357 def flow_add(self, flow_cfg, overlapf = False):
Howard Persh680b92a2012-03-31 13:34:35 -07001358 flow_mod_msg = message.flow_mod()
1359 flow_mod_msg.command = ofp.OFPFC_ADD
1360 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001361 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001362 if overlapf:
1363 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001364 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001365 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Howard Persh07d99e62012-04-09 15:26:57 -07001366 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001367 logging.info("Sending flow_mod(add), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001368 % (flow_mod_msg.header.xid)
1369 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001370 self.controller.message_send(flow_mod_msg)
1371 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001372
rootf6af1672012-04-06 09:46:29 -07001373 def flow_mod(self, flow_cfg, strictf):
Howard Persh680b92a2012-03-31 13:34:35 -07001374 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001375 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf \
1376 else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -07001377 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001378 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001379 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001380 logging.info("Sending flow_mod(mod), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001381 % (flow_mod_msg.header.xid)
1382 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001383 self.controller.message_send(flow_mod_msg)
1384 return True
rootf6af1672012-04-06 09:46:29 -07001385
1386 def flow_del(self, flow_cfg, strictf):
1387 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001388 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf \
1389 else ofp.OFPFC_DELETE
rootf6af1672012-04-06 09:46:29 -07001390 flow_mod_msg.buffer_id = 0xffffffff
1391 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001392 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001393 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001394 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001395 logging.info("Sending flow_mod(del), xid=%d"
Howard Pershc1199d52012-04-11 14:21:32 -07001396 % (flow_mod_msg.header.xid)
1397 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001398 self.controller.message_send(flow_mod_msg)
1399 return True
rootf6af1672012-04-06 09:46:29 -07001400
1401 def barrier(self):
1402 barrier = message.barrier_request()
Dan Talaycoc689a792012-09-28 14:22:53 -07001403 (resp, pkt) = self.controller.transact(barrier, 30)
rootf6af1672012-04-06 09:46:29 -07001404 return (resp is not None)
1405
Howard Persh3340d452012-04-06 16:45:21 -07001406 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001407 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001408 logging.info("Expecting %d error messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001409 num_got = len(self.error_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001410 logging.info("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001411 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001412 logging.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001413 result = False
1414 if num_exp == 0:
1415 return result
1416 elif num_exp == 1:
Rich Lane9a003812012-10-04 17:17:59 -07001417 logging.info("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001418 % (type, code) \
1419 )
1420 f = False
Ed Swierk99a74de2012-08-22 06:40:54 -07001421 for e in self.error_msgs:
Howard Persh3340d452012-04-06 16:45:21 -07001422 if e.type == type and e.code == code:
Rich Lane9a003812012-10-04 17:17:59 -07001423 logging.info("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001424 f = True
1425 if not f:
Rich Lane9a003812012-10-04 17:17:59 -07001426 logging.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001427 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001428 else:
Rich Lane9a003812012-10-04 17:17:59 -07001429 logging.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001430 result = False
1431 return result
1432
Howard Persh3340d452012-04-06 16:45:21 -07001433 def removed_verify(self, num_exp):
1434 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001435 logging.info("Expecting %d removed messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001436 num_got = len(self.removed_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001437 logging.info("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001438 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001439 logging.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001440 result = False
1441 if num_exp < 2:
1442 return result
Rich Lane9a003812012-10-04 17:17:59 -07001443 logging.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001444 return False
1445
Howard Persh5f3c83f2012-04-13 09:57:10 -07001446 # modf == True <=> Verify for flow modify, else for add/delete
1447 def flow_tbl_verify(self, modf = False):
rootf6af1672012-04-06 09:46:29 -07001448 result = True
1449
1450 # Verify flow count in switch
Rich Lane9a003812012-10-04 17:17:59 -07001451 logging.info("Reading table stats")
1452 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001453 if not self.tbl_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001454 logging.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001455 return False
1456 n = 0
1457 for ts in self.tbl_stats.stats:
1458 n = n + ts.active_count
Rich Lane9a003812012-10-04 17:17:59 -07001459 logging.info("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001460 % (n) \
1461 )
1462 if n != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001463 logging.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001464 result = False
1465
1466 # Read flows from switch
Rich Lane9a003812012-10-04 17:17:59 -07001467 logging.info("Retrieving flows from switch")
1468 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001469 if not self.flow_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001470 logging.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001471 return False
Rich Lane9a003812012-10-04 17:17:59 -07001472 logging.info("Retrieved %d flows" % (len(self.flow_stats.stats)))
rootf6af1672012-04-06 09:46:29 -07001473
1474 # Verify flows returned by switch
1475
1476 if len(self.flow_stats.stats) != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001477 logging.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001478 result = False
1479
Rich Lane9a003812012-10-04 17:17:59 -07001480 logging.info("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001481 for fc in self.flow_tbl.values():
1482 fc.matched = False
1483 for fs in self.flow_stats.stats:
1484 flow_in = Flow_Cfg()
1485 flow_in.from_flow_stat(fs)
Rich Lane9a003812012-10-04 17:17:59 -07001486 logging.info("Received flow:")
1487 logging.info(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001488 fc = self.flow_tbl.find(flow_in)
1489 if fc is None:
Rich Lane9a003812012-10-04 17:17:59 -07001490 logging.error("Received flow:")
1491 logging.error(str(flow_in))
1492 logging.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001493 result = False
1494 elif fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001495 logging.error("Received flow:")
1496 logging.error(str(flow_in))
1497 logging.error("re-matches defined flow:")
1498 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001499 result = False
1500 else:
Rich Lane9a003812012-10-04 17:17:59 -07001501 logging.info("matched")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001502 if modf:
1503 # Check for modify
1504
1505 if flow_in.cookie != fc.cookie:
Rich Lane9a003812012-10-04 17:17:59 -07001506 logging.warning("Defined flow:")
1507 logging.warning(str(fc))
1508 logging.warning("Received flow:")
1509 logging.warning(str(flow_in))
1510 logging.warning("cookies do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001511 if not flow_in.actions_equal(fc):
Rich Lane9a003812012-10-04 17:17:59 -07001512 logging.error("Defined flow:")
1513 logging.error(str(fc))
1514 logging.error("Received flow:")
1515 logging.error(str(flow_in))
1516 logging.error("actions do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001517 else:
1518 # Check for add/delete
1519
1520 if not flow_in == fc:
Rich Lane9a003812012-10-04 17:17:59 -07001521 logging.error("Defined flow:")
1522 logging.error(str(fc))
1523 logging.error("Received flow:")
1524 logging.error(str(flow_in))
1525 logging.error("non-key portions of flow do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001526 result = False
rootf6af1672012-04-06 09:46:29 -07001527 fc.matched = True
1528 for fc in self.flow_tbl.values():
1529 if not fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001530 logging.error("Defined flow:")
1531 logging.error(str(fc))
1532 logging.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001533 result = False
1534
1535 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001536
Howard Persh9cab4822012-09-11 17:08:40 -07001537 def settle(self):
1538 time.sleep(2)
1539
Howard Persh07d99e62012-04-09 15:26:57 -07001540# FLOW ADD 5
1541#
1542# OVERVIEW
1543# Add flows to switch, read back and verify flow configurations
1544#
1545# PURPOSE
1546# - Test acceptance of flow adds
1547# - Test ability of switch to process additions to flow table in random
1548# priority order
1549# - Test correctness of flow configuration responses
1550#
1551# PARAMETERS
1552#
1553# Name: num_flows
1554# Type: number
1555# Description:
1556# Number of flows to define; 0 => maximum number of flows, as determined
1557# from switch capabilities
1558# Default: 100
1559#
1560# PROCESS
1561# 1. Delete all flows from switch
1562# 2. Generate <num_flows> distinct flow configurations
1563# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1564# 4. Verify that no OFPT_ERROR responses were generated by switch
1565# 5. Retrieve flow stats from switch
1566# 6. Compare flow configurations returned by switch
1567# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1568# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001569
Rich Laneb90a1c42012-10-05 09:16:05 -07001570class Flow_Add_5(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001571 """
1572 Test FLOW_ADD_5 from draft top-half test plan
1573
1574 INPUTS
1575 num_flows - Number of flows to generate
1576 """
Howard Persh680b92a2012-03-31 13:34:35 -07001577
rootf6af1672012-04-06 09:46:29 -07001578 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001579 logging.info("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001580
Rich Lane2014f9b2012-10-05 15:29:40 -07001581 num_flows = test_param_get("num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001582
Howard Pershc7963582012-03-29 10:02:59 -07001583 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001584
Rich Lane9a003812012-10-04 17:17:59 -07001585 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001586 delete_all_flows(self.controller)
Howard Pershc7963582012-03-29 10:02:59 -07001587
rootf6af1672012-04-06 09:46:29 -07001588 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001589
rootf6af1672012-04-06 09:46:29 -07001590 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001591 self.assertTrue(sw.connect(self.controller), \
1592 "Failed to connect to switch" \
1593 )
Howard Pershc7963582012-03-29 10:02:59 -07001594
rootf6af1672012-04-06 09:46:29 -07001595 if num_flows == 0:
1596 # Number of flows requested was 0
1597 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001598
rootf6af1672012-04-06 09:46:29 -07001599 for ts in sw.tbl_stats.stats:
1600 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001601
Rich Lane9a003812012-10-04 17:17:59 -07001602 logging.info("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001603
1604 # Dream up some flow information, i.e. space to chose from for
1605 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001606
rootf6af1672012-04-06 09:46:29 -07001607 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001608 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001609
rootf6af1672012-04-06 09:46:29 -07001610 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001611
rootf6af1672012-04-06 09:46:29 -07001612 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001613 ft.rand(required_wildcards(self), sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001614
rootf6af1672012-04-06 09:46:29 -07001615 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001616
Rich Lane9a003812012-10-04 17:17:59 -07001617 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001618 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001619 logging.info("Adding flow:")
1620 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001621 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001622
rootf6af1672012-04-06 09:46:29 -07001623 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001624
rootf6af1672012-04-06 09:46:29 -07001625 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001626
rootf6af1672012-04-06 09:46:29 -07001627 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001628
Howard Persh9cab4822012-09-11 17:08:40 -07001629 sw.settle() # Allow switch to settle and generate any notifications
1630
rootf6af1672012-04-06 09:46:29 -07001631 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001632
rootf6af1672012-04-06 09:46:29 -07001633 if not sw.errors_verify(0):
1634 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001635
rootf6af1672012-04-06 09:46:29 -07001636 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001637
rootf6af1672012-04-06 09:46:29 -07001638 sw.flow_tbl = ft
1639 if not sw.flow_tbl_verify():
1640 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001641
rootf6af1672012-04-06 09:46:29 -07001642 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001643 logging.info("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001644
Howard Pershc7963582012-03-29 10:02:59 -07001645
Howard Persh07d99e62012-04-09 15:26:57 -07001646# FLOW ADD 5_1
1647#
1648# OVERVIEW
1649# Verify handling of non-canonical flows
1650#
1651# PURPOSE
1652# - Test that switch detects and correctly responds to a non-canonical flow
1653# definition. A canonical flow is one that satisfies all match qualifier
1654# dependencies; a non-canonical flow is one that does not.
1655#
1656# PARAMETERS
1657# - None
1658#
1659# PROCESS
1660# 1. Delete all flows from switch
1661# 2. Generate 1 flow definition, which is different from its canonicalization
1662# 3. Send flow to switch
1663# 4. Retrieve flow from switch
1664# 5. Compare returned flow to canonical form of defined flow
1665# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1666
1667# Disabled.
1668# Should be DUT dependent.
Howard Persh07d99e62012-04-09 15:26:57 -07001669
Rich Lane0a4f6372013-01-02 14:40:22 -08001670@nonstandard
Rich Laneb90a1c42012-10-05 09:16:05 -07001671class Flow_Add_5_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001672 """
1673 Test FLOW_ADD_5.1 from draft top-half test plan
1674
1675 INPUTS
1676 None
1677 """
Rich Laned1d9c282012-10-04 22:07:10 -07001678
rootf6af1672012-04-06 09:46:29 -07001679 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001680 logging.info("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001681
Rich Lane2014f9b2012-10-05 15:29:40 -07001682 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001683
1684 # Clear all flows from switch
1685
Rich Lane9a003812012-10-04 17:17:59 -07001686 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001687 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001688
1689 # Get switch capabilites
1690
rootf6af1672012-04-06 09:46:29 -07001691 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001692 self.assertTrue(sw.connect(self.controller), \
1693 "Failed to connect to switch" \
1694 )
rootf6af1672012-04-06 09:46:29 -07001695
1696 # Dream up some flow information, i.e. space to chose from for
1697 # random flow parameter generation
1698
1699 fi = Flow_Info()
1700 fi.rand(10)
1701
1702 # Dream up a flow config that will be canonicalized by the switch
1703
1704 while True:
1705 fc = Flow_Cfg()
1706 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001707 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07001708 sw.tbl_stats.stats[0].wildcards, \
1709 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001710 sw.valid_ports, \
1711 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001712 )
1713 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001714 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001715 break
1716
1717 ft = Flow_Tbl()
1718 ft.insert(fcc)
1719
1720 # Send it to the switch
1721
Rich Lane9a003812012-10-04 17:17:59 -07001722 logging.info("Sending flow add to switch:")
1723 logging.info(str(fc))
1724 logging.info("should be canonicalized as:")
1725 logging.info(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001726 fc.send_rem = False
1727 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1728
1729 # Do barrier, to make sure all flows are in
1730
1731 self.assertTrue(sw.barrier(), "Barrier failed")
1732
1733 result = True
1734
Howard Persh9cab4822012-09-11 17:08:40 -07001735 sw.settle() # Allow switch to settle and generate any notifications
1736
rootf6af1672012-04-06 09:46:29 -07001737 # Check for any error messages
1738
1739 if not sw.errors_verify(0):
1740 result = False
1741
1742 # Verify flow table
1743
1744 sw.flow_tbl = ft
1745 if not sw.flow_tbl_verify():
1746 result = False
1747
1748 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001749 logging.info("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001750
1751
Howard Persh07d99e62012-04-09 15:26:57 -07001752# FLOW ADD 6
1753#
1754# OVERVIEW
1755# Test flow table capacity
1756#
1757# PURPOSE
1758# - Test switch can accept as many flow definitions as it claims
1759# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1760# - Test that attempting to create flows beyond capacity does not corrupt
1761# flow table
1762#
1763# PARAMETERS
1764# None
1765#
1766# PROCESS
1767# 1. Delete all flows from switch
1768# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1769# to determine flow table size, N
1770# 3. Generate (N + 1) distinct flow configurations
1771# 4. Send N flow adds to switch, for flows generated in step 3 above
1772# 5. Verify flow table in switch
1773# 6. Send one more flow add to switch
1774# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1775# response was generated by switch, for last flow mod sent
1776# 7. Retrieve flow stats from switch
1777# 8. Verify flow table in switch
1778# 9. Test PASSED iff:
1779# - error message received, for correct flow
1780# - last flow definition sent to switch is not in flow table
1781# else test FAILED
1782
Howard Persh3340d452012-04-06 16:45:21 -07001783# Disabled because of bogus capacity reported by OVS.
1784# Should be DUT dependent.
Howard Persh3340d452012-04-06 16:45:21 -07001785
Rich Lane0a4f6372013-01-02 14:40:22 -08001786@nonstandard
Rich Laneb90a1c42012-10-05 09:16:05 -07001787class Flow_Add_6(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001788 """
1789 Test FLOW_ADD_6 from draft top-half test plan
1790
1791 INPUTS
1792 num_flows - Number of flows to generate
1793 """
Howard Pershc7963582012-03-29 10:02:59 -07001794
1795 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001796 logging.info("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001797
rootf6af1672012-04-06 09:46:29 -07001798 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001799
Rich Lane9a003812012-10-04 17:17:59 -07001800 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001801 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001802
1803 # Get switch capabilites
1804
rootf6af1672012-04-06 09:46:29 -07001805 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001806 self.assertTrue(sw.connect(self.controller), \
1807 "Failed to connect to switch" \
1808 )
rootf6af1672012-04-06 09:46:29 -07001809
root2843d2b2012-04-06 10:27:46 -07001810 num_flows = 0
rootf6af1672012-04-06 09:46:29 -07001811 for ts in sw.tbl_stats.stats:
1812 num_flows = num_flows + ts.max_entries
1813
Rich Lane9a003812012-10-04 17:17:59 -07001814 logging.info("Switch capacity is %d flows" % (num_flows))
1815 logging.info("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001816
1817 # Dream up some flow information, i.e. space to chose from for
1818 # random flow parameter generation
1819
1820 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001821 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001822
1823 # Create a flow table, to switch's capacity
1824
1825 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001826 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07001827
1828 # Send flow table to switch
1829
Rich Lane9a003812012-10-04 17:17:59 -07001830 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001831 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001832 logging.info("Adding flow:")
1833 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001834 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1835
1836 # Do barrier, to make sure all flows are in
1837
1838 self.assertTrue(sw.barrier(), "Barrier failed")
1839
1840 result = True
1841
Howard Persh9cab4822012-09-11 17:08:40 -07001842 sw.settle() # Allow switch to settle and generate any notifications
1843
rootf6af1672012-04-06 09:46:29 -07001844 # Check for any error messages
1845
1846 if not sw.errors_verify(0):
1847 result = False
1848
1849 # Dream up one more flow
1850
Rich Lane9a003812012-10-04 17:17:59 -07001851 logging.info("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001852 while True:
1853 fc = Flow_Cfg()
1854 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001855 required_wildcards(self), \
Howard Persh07d99e62012-04-09 15:26:57 -07001856 sw.tbl_stats.stats[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001857 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001858 sw.valid_ports, \
1859 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001860 )
1861 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001862 if not ft.find(fc):
1863 break
rootf6af1672012-04-06 09:46:29 -07001864
1865 # Send one-more flow
1866
1867 fc.send_rem = False
Rich Lane9a003812012-10-04 17:17:59 -07001868 logging.info("Sending flow add switch")
1869 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001870 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1871
1872 # Do barrier, to make sure all flows are in
1873
1874 self.assertTrue(sw.barrier(), "Barrier failed")
1875
Howard Persh9cab4822012-09-11 17:08:40 -07001876 sw.settle() # Allow switch to settle and generate any notifications
1877
rootf6af1672012-04-06 09:46:29 -07001878 # Check for expected error message
1879
1880 if not sw.errors_verify(1, \
1881 ofp.OFPET_FLOW_MOD_FAILED, \
1882 ofp.OFPFMFC_ALL_TABLES_FULL \
1883 ):
1884 result = False
1885
1886 # Verify flow table
1887
1888 sw.flow_tbl = ft
1889 if not sw.flow_tbl_verify():
1890 result = False
1891
1892 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001893 logging.info("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001894
1895
Howard Persh07d99e62012-04-09 15:26:57 -07001896# FLOW ADD 7
1897#
1898# OVERVIEW
1899# Test flow redefinition
1900#
1901# PURPOSE
1902# Verify that successive flow adds with same priority and match criteria
1903# overwrite in flow table
1904#
1905# PARAMETERS
1906# None
1907#
1908# PROCESS
1909# 1. Delete all flows from switch
1910# 2. Generate flow definition F1
1911# 3. Generate flow definition F2, with same key (priority and match) as F1,
1912# but with different actions
1913# 4. Send flow adds for F1 and F2 to switch
1914# 5. Verify flow definitions in switch
1915# 6. Test PASSED iff 1 flow returned by switch, matching configuration of F2;
1916# else test FAILED
1917
Rich Laneb90a1c42012-10-05 09:16:05 -07001918class Flow_Add_7(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001919 """
1920 Test FLOW_ADD_7 from draft top-half test plan
1921
1922 INPUTS
1923 None
1924 """
1925
1926 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001927 logging.info("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001928
1929 # Clear all flows from switch
1930
Rich Lane9a003812012-10-04 17:17:59 -07001931 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001932 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001933
1934 # Get switch capabilites
1935
rootf6af1672012-04-06 09:46:29 -07001936 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001937 self.assertTrue(sw.connect(self.controller), \
1938 "Failed to connect to switch" \
1939 )
rootf6af1672012-04-06 09:46:29 -07001940
1941 # Dream up some flow information, i.e. space to chose from for
1942 # random flow parameter generation
1943
1944 fi = Flow_Info()
1945 fi.rand(10)
1946
1947 # Dream up a flow config
1948
1949 fc = Flow_Cfg()
1950 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001951 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07001952 sw.tbl_stats.stats[0].wildcards, \
1953 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001954 sw.valid_ports, \
1955 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001956 )
1957 fc = fc.canonical()
1958
1959 # Send it to the switch
1960
Rich Lane9a003812012-10-04 17:17:59 -07001961 logging.info("Sending flow add to switch:")
1962 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001963 ft = Flow_Tbl()
1964 fc.send_rem = False
1965 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1966 ft.insert(fc)
1967
1968 # Dream up some different actions, with the same flow key
1969
1970 fc2 = copy.deepcopy(fc)
1971 while True:
1972 fc2.rand_mod(fi, \
1973 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001974 sw.valid_ports, \
1975 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001976 )
1977 if fc2 != fc:
1978 break
1979
1980 # Send that to the switch
1981
Rich Lane9a003812012-10-04 17:17:59 -07001982 logging.info("Sending flow add to switch:")
1983 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07001984 fc2.send_rem = False
1985 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
1986 ft.insert(fc2)
1987
1988 # Do barrier, to make sure all flows are in
1989
1990 self.assertTrue(sw.barrier(), "Barrier failed")
1991
1992 result = True
1993
Howard Persh9cab4822012-09-11 17:08:40 -07001994 sw.settle() # Allow switch to settle and generate any notifications
1995
rootf6af1672012-04-06 09:46:29 -07001996 # Check for any error messages
1997
1998 if not sw.errors_verify(0):
1999 result = False
2000
2001 # Verify flow table
2002
2003 sw.flow_tbl = ft
2004 if not sw.flow_tbl_verify():
2005 result = False
2006
2007 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002008 logging.info("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002009
2010
Howard Persh07d99e62012-04-09 15:26:57 -07002011# FLOW ADD 8
2012#
2013# OVERVIEW
2014# Add overlapping flows to switch, verify that overlapping flows are rejected
2015#
2016# PURPOSE
2017# - Test detection of overlapping flows by switch
2018# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
2019# - Test rejection of overlapping flows
2020# - Test defining overlapping flows does not corrupt flow table
2021#
2022# PARAMETERS
2023# None
2024#
2025# PROCESS
2026# 1. Delete all flows from switch
2027# 2. Generate flow definition F1
2028# 3. Generate flow definition F2, with key overlapping F1
2029# 4. Send flow add to switch, for F1
2030# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
2031# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
2032# was generated by switch
2033# 7. Verifiy flows configured in swtich
2034# 8. Test PASSED iff:
2035# - error message received, for overlapping flow
2036# - overlapping flow is not in flow table
2037# else test FAILED
2038
Rich Laneb90a1c42012-10-05 09:16:05 -07002039class Flow_Add_8(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002040 """
2041 Test FLOW_ADD_8 from draft top-half test plan
2042
2043 INPUTS
2044 None
2045 """
2046
2047 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002048 logging.info("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002049
2050 # Clear all flows from switch
2051
Rich Lane9a003812012-10-04 17:17:59 -07002052 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002053 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002054
2055 # Get switch capabilites
2056
rootf6af1672012-04-06 09:46:29 -07002057 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002058 self.assertTrue(sw.connect(self.controller), \
2059 "Failed to connect to switch" \
2060 )
rootf6af1672012-04-06 09:46:29 -07002061
2062 # Dream up some flow information, i.e. space to chose from for
2063 # random flow parameter generation
2064
2065 fi = Flow_Info()
2066 fi.rand(10)
2067
2068 # Dream up a flow config, with at least 1 qualifier specified
2069
2070 fc = Flow_Cfg()
2071 while True:
2072 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002073 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002074 sw.tbl_stats.stats[0].wildcards, \
2075 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002076 sw.valid_ports, \
2077 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002078 )
2079 fc = fc.canonical()
2080 if fc.match.wildcards != ofp.OFPFW_ALL:
2081 break
2082
2083 # Send it to the switch
2084
Rich Lane9a003812012-10-04 17:17:59 -07002085 logging.info("Sending flow add to switch:")
2086 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002087 ft = Flow_Tbl()
2088 fc.send_rem = False
2089 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2090 ft.insert(fc)
2091
2092 # Wildcard out one qualifier that was specified, to create an
2093 # overlapping flow
2094
2095 fc2 = copy.deepcopy(fc)
2096 for wi in shuffle(range(len(all_wildcards_list))):
2097 w = all_wildcards_list[wi]
2098 if (fc2.match.wildcards & w) == 0:
2099 break
2100 if w == ofp.OFPFW_NW_SRC_MASK:
2101 w = ofp.OFPFW_NW_SRC_ALL
2102 wn = "OFPFW_NW_SRC"
2103 elif w == ofp.OFPFW_NW_DST_MASK:
2104 w = ofp.OFPFW_NW_DST_ALL
2105 wn = "OFPFW_NW_DST"
2106 else:
2107 wn = all_wildcard_names[w]
Rich Lane9a003812012-10-04 17:17:59 -07002108 logging.info("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07002109 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07002110 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07002111
2112 # Send that to the switch, with overlap checking
2113
Rich Lane9a003812012-10-04 17:17:59 -07002114 logging.info("Sending flow add to switch:")
2115 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002116 fc2.send_rem = False
2117 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
2118
2119 # Do barrier, to make sure all flows are in
2120 self.assertTrue(sw.barrier(), "Barrier failed")
2121
2122 result = True
2123
Howard Persh9cab4822012-09-11 17:08:40 -07002124 sw.settle() # Allow switch to settle and generate any notifications
2125
rootf6af1672012-04-06 09:46:29 -07002126 # Check for expected error message
2127
2128 if not sw.errors_verify(1, \
2129 ofp.OFPET_FLOW_MOD_FAILED, \
2130 ofp.OFPFMFC_OVERLAP \
2131 ):
2132 result = False
2133
2134 # Verify flow table
2135
2136 sw.flow_tbl = ft
2137 if not sw.flow_tbl_verify():
2138 result = False
2139
2140 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002141 logging.info("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002142
2143
Howard Persh07d99e62012-04-09 15:26:57 -07002144# FLOW MODIFY 1
2145#
2146# OVERVIEW
2147# Strict modify of single existing flow
2148#
2149# PURPOSE
2150# - Verify that strict flow modify operates only on specified flow
2151# - Verify that flow is correctly modified
2152#
2153# PARAMETERS
2154# None
2155#
2156# PROCESS
2157# 1. Delete all flows from switch
2158# 2. Generate 1 flow F
2159# 3. Send flow add to switch, for flow F
2160# 4. Generate new action list for flow F, yielding F'
2161# 5. Send strict flow modify to switch, for flow F'
2162# 6. Verify flow table in switch
2163# 7. Test PASSED iff flow returned by switch is F'; else FAILED
2164
Rich Laneb90a1c42012-10-05 09:16:05 -07002165class Flow_Mod_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002166 """
2167 Test FLOW_MOD_1 from draft top-half test plan
2168
2169 INPUTS
2170 None
2171 """
2172
2173 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002174 logging.info("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002175
2176 # Clear all flows from switch
2177
Rich Lane9a003812012-10-04 17:17:59 -07002178 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002179 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002180
2181 # Get switch capabilites
2182
rootf6af1672012-04-06 09:46:29 -07002183 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002184 self.assertTrue(sw.connect(self.controller), \
2185 "Failed to connect to switch" \
2186 )
rootf6af1672012-04-06 09:46:29 -07002187
2188 # Dream up some flow information, i.e. space to chose from for
2189 # random flow parameter generation
2190
2191 fi = Flow_Info()
2192 fi.rand(10)
2193
2194 # Dream up a flow config
2195
2196 fc = Flow_Cfg()
2197 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002198 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002199 sw.tbl_stats.stats[0].wildcards, \
2200 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002201 sw.valid_ports, \
2202 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002203 )
2204 fc = fc.canonical()
2205
2206 # Send it to the switch
2207
Rich Lane9a003812012-10-04 17:17:59 -07002208 logging.info("Sending flow add to switch:")
2209 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002210 ft = Flow_Tbl()
2211 fc.send_rem = False
2212 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2213 ft.insert(fc)
2214
2215 # Dream up some different actions, with the same flow key
2216
2217 fc2 = copy.deepcopy(fc)
2218 while True:
2219 fc2.rand_mod(fi, \
2220 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002221 sw.valid_ports, \
2222 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002223 )
2224 if fc2 != fc:
2225 break
2226
2227 # Send that to the switch
2228
Rich Lane9a003812012-10-04 17:17:59 -07002229 logging.info("Sending strict flow mod to switch:")
2230 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002231 fc2.send_rem = False
2232 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2233 ft.insert(fc2)
2234
2235 # Do barrier, to make sure all flows are in
2236
2237 self.assertTrue(sw.barrier(), "Barrier failed")
2238
2239 result = True
2240
Howard Persh9cab4822012-09-11 17:08:40 -07002241 sw.settle() # Allow switch to settle and generate any notifications
2242
rootf6af1672012-04-06 09:46:29 -07002243 # Check for any error messages
2244
2245 if not sw.errors_verify(0):
2246 result = False
2247
2248 # Verify flow table
2249
2250 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002251 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002252 result = False
2253
2254 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002255 logging.info("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002256
Howard Persh07d99e62012-04-09 15:26:57 -07002257
2258# FLOW MODIFY 2
2259#
2260# OVERVIEW
2261# Loose modify of mutiple flows
2262#
2263# PURPOSE
2264# - Verify that loose flow modify operates only on matching flows
2265# - Verify that matching flows are correctly modified
2266#
2267# PARAMETERS
2268# Name: num_flows
2269# Type: number
2270# Description:
2271# Number of flows to define
2272# Default: 100
2273#
2274# PROCESS
2275# 1. Delete all flows from switch
2276# 2. Generate <num_flows> distinct flow configurations
2277# 3. Send <num_flows> flow adds to switch
2278# 4. Pick 1 defined flow F at random
2279# 5. Create overlapping loose flow mod match criteria by repeatedly
2280# wildcarding out qualifiers in match of F => F',
2281# and create new actions list A' for F'
2282# 6. Send loose flow modify for F' to switch
2283# 7. Verify flow table in swtich
2284# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2285# are returned in step 7 above, each with correct (original or modified)
2286# action list;
2287# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002288
Rich Laneb90a1c42012-10-05 09:16:05 -07002289class Flow_Mod_2(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002290 """
2291 Test FLOW_MOD_2 from draft top-half test plan
2292
2293 INPUTS
2294 None
2295 """
2296
2297 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002298 logging.info("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002299
Rich Lane2014f9b2012-10-05 15:29:40 -07002300 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002301
2302 # Clear all flows from switch
2303
Rich Lane9a003812012-10-04 17:17:59 -07002304 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002305 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002306
2307 # Get switch capabilites
2308
rootf6af1672012-04-06 09:46:29 -07002309 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002310 self.assertTrue(sw.connect(self.controller), \
2311 "Failed to connect to switch" \
2312 )
rootf6af1672012-04-06 09:46:29 -07002313
2314 # Dream up some flow information, i.e. space to chose from for
2315 # random flow parameter generation
2316
2317 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002318 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002319 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002320
2321 # Dream up some flows
2322
2323 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002324 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002325
2326 # Send flow table to switch
2327
Rich Lane9a003812012-10-04 17:17:59 -07002328 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002329 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002330 logging.info("Adding flow:")
2331 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002332 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2333
2334 # Do barrier, to make sure all flows are in
2335
2336 self.assertTrue(sw.barrier(), "Barrier failed")
2337
2338 result = True
2339
Howard Persh9cab4822012-09-11 17:08:40 -07002340 sw.settle() # Allow switch to settle and generate any notifications
2341
rootf6af1672012-04-06 09:46:29 -07002342 # Check for any error messages
2343
2344 if not sw.errors_verify(0):
2345 result = False
2346
2347 # Verify flow table
2348
2349 sw.flow_tbl = ft
2350 if not sw.flow_tbl_verify():
2351 result = False
2352
2353 # Pick a random flow as a basis
Howard Persh5f3c83f2012-04-13 09:57:10 -07002354
2355 mfc = copy.deepcopy((ft.values())[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002356 mfc.rand_mod(fi, \
2357 sw.sw_features.actions, \
2358 sw.valid_ports, \
2359 sw.valid_queues \
2360 )
rootf6af1672012-04-06 09:46:29 -07002361
2362 # Repeatedly wildcard qualifiers
2363
2364 for wi in shuffle(range(len(all_wildcards_list))):
2365 w = all_wildcards_list[wi]
2366 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2367 n = wildcard_get(mfc.match.wildcards, w)
2368 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002369 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2370 w, \
2371 random.randint(n + 1, 32) \
2372 )
rootf6af1672012-04-06 09:46:29 -07002373 else:
2374 continue
2375 else:
2376 if wildcard_get(mfc.match.wildcards, w) == 0:
2377 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2378 else:
2379 continue
2380 mfc = mfc.canonical()
2381
2382 # Count the number of flows that would be modified
2383
2384 n = 0
2385 for fc in ft.values():
2386 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2387 n = n + 1
2388
2389 # If more than 1, we found our loose delete flow spec
2390 if n > 1:
2391 break
2392
Rich Lane9a003812012-10-04 17:17:59 -07002393 logging.info("Modifying %d flows" % (n))
2394 logging.info("Sending flow mod to switch:")
2395 logging.info(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002396 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2397
2398 # Do barrier, to make sure all flows are in
2399 self.assertTrue(sw.barrier(), "Barrier failed")
2400
Howard Persh9cab4822012-09-11 17:08:40 -07002401 sw.settle() # Allow switch to settle and generate any notifications
2402
rootf6af1672012-04-06 09:46:29 -07002403 # Check for error message
2404
2405 if not sw.errors_verify(0):
2406 result = False
2407
2408 # Apply flow mod to local flow table
2409
2410 for fc in ft.values():
2411 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002412 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002413
2414 # Verify flow table
2415
2416 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002417 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002418 result = False
2419
2420 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002421 logging.info("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002422
2423
Howard Persh07d99e62012-04-09 15:26:57 -07002424# FLOW MODIFY 3
2425
2426# OVERVIEW
2427# Strict modify of non-existent flow
2428#
2429# PURPOSE
2430# Verify that strict modify of a non-existent flow is equivalent to a flow add
2431#
2432# PARAMETERS
2433# None
2434#
2435# PROCESS
2436# 1. Delete all flows from switch
2437# 2. Send single flow mod, as strict modify, to switch
2438# 3. Verify flow table in switch
2439# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2440
Rich Laneb90a1c42012-10-05 09:16:05 -07002441class Flow_Mod_3(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002442 """
2443 Test FLOW_MOD_3 from draft top-half test plan
2444
2445 INPUTS
2446 None
2447 """
2448
2449 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002450 logging.info("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002451
2452 # Clear all flows from switch
2453
Rich Lane9a003812012-10-04 17:17:59 -07002454 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002455 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002456
2457 # Get switch capabilites
2458
rootf6af1672012-04-06 09:46:29 -07002459 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002460 self.assertTrue(sw.connect(self.controller), \
2461 "Failed to connect to switch" \
2462 )
rootf6af1672012-04-06 09:46:29 -07002463
2464 # Dream up some flow information, i.e. space to chose from for
2465 # random flow parameter generation
2466
2467 fi = Flow_Info()
2468 fi.rand(10)
2469
2470 # Dream up a flow config
2471
2472 fc = Flow_Cfg()
2473 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002474 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002475 sw.tbl_stats.stats[0].wildcards, \
2476 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002477 sw.valid_ports, \
2478 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002479 )
2480 fc = fc.canonical()
2481
2482 # Send it to the switch
2483
Rich Lane9a003812012-10-04 17:17:59 -07002484 logging.info("Sending flow mod to switch:")
2485 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002486 ft = Flow_Tbl()
2487 fc.send_rem = False
2488 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2489 ft.insert(fc)
2490
2491 # Do barrier, to make sure all flows are in
2492
2493 self.assertTrue(sw.barrier(), "Barrier failed")
2494
2495 result = True
2496
Howard Persh9cab4822012-09-11 17:08:40 -07002497 sw.settle() # Allow switch to settle and generate any notifications
2498
rootf6af1672012-04-06 09:46:29 -07002499 # Check for any error messages
2500
2501 if not sw.errors_verify(0):
2502 result = False
2503
2504 # Verify flow table
2505
2506 sw.flow_tbl = ft
2507 if not sw.flow_tbl_verify():
2508 result = False
2509
2510 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002511 logging.info("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002512
2513
Howard Persh8d21c1f2012-04-20 15:57:29 -07002514# FLOW MODIFY 3_1
2515
2516# OVERVIEW
2517# No-op modify
2518#
2519# PURPOSE
2520# Verify that modify of a flow with new actions same as old ones operates correctly
2521#
2522# PARAMETERS
2523# None
2524#
2525# PROCESS
2526# 1. Delete all flows from switch
2527# 2. Send single flow mod, as strict modify, to switch
2528# 3. Verify flow table in switch
2529# 4. Send same flow mod, as strict modify, to switch
2530# 5. Verify flow table in switch
2531# 6. Test PASSED iff flow defined in step 2 and 4 above verified; else FAILED
2532
Rich Laneb90a1c42012-10-05 09:16:05 -07002533class Flow_Mod_3_1(base_tests.SimpleProtocol):
Howard Persh8d21c1f2012-04-20 15:57:29 -07002534 """
2535 Test FLOW_MOD_3_1 from draft top-half test plan
2536
2537 INPUTS
2538 None
2539 """
2540
2541 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002542 logging.info("Flow_Mod_3_1 TEST BEGIN")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002543
2544 # Clear all flows from switch
2545
Rich Lane9a003812012-10-04 17:17:59 -07002546 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002547 delete_all_flows(self.controller)
Howard Persh8d21c1f2012-04-20 15:57:29 -07002548
2549 # Get switch capabilites
2550
2551 sw = Switch()
2552 self.assertTrue(sw.connect(self.controller), \
2553 "Failed to connect to switch" \
2554 )
2555
2556 # Dream up some flow information, i.e. space to chose from for
2557 # random flow parameter generation
2558
2559 fi = Flow_Info()
2560 fi.rand(10)
2561
2562 # Dream up a flow config
2563
2564 fc = Flow_Cfg()
2565 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002566 required_wildcards(self), \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002567 sw.tbl_stats.stats[0].wildcards, \
2568 sw.sw_features.actions, \
2569 sw.valid_ports, \
2570 sw.valid_queues \
2571 )
2572 fc = fc.canonical()
2573
2574 # Send it to the switch
2575
Rich Lane9a003812012-10-04 17:17:59 -07002576 logging.info("Sending flow mod to switch:")
2577 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002578 ft = Flow_Tbl()
2579 fc.send_rem = False
2580 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2581 ft.insert(fc)
2582
2583 # Do barrier, to make sure all flows are in
2584
2585 self.assertTrue(sw.barrier(), "Barrier failed")
2586
2587 result = True
2588
Howard Persh9cab4822012-09-11 17:08:40 -07002589 sw.settle() # Allow switch to settle and generate any notifications
2590
Howard Persh8d21c1f2012-04-20 15:57:29 -07002591 # Check for any error messages
2592
2593 if not sw.errors_verify(0):
2594 result = False
2595
2596 # Verify flow table
2597
2598 sw.flow_tbl = ft
2599 if not sw.flow_tbl_verify():
2600 result = False
2601
2602 # Send same flow to the switch again
2603
Rich Lane9a003812012-10-04 17:17:59 -07002604 logging.info("Sending flow mod to switch:")
2605 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002606 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2607
2608 # Do barrier, to make sure all flows are in
2609
2610 self.assertTrue(sw.barrier(), "Barrier failed")
2611
Howard Persh9cab4822012-09-11 17:08:40 -07002612 sw.settle() # Allow switch to settle and generate any notifications
2613
Howard Persh8d21c1f2012-04-20 15:57:29 -07002614 # Check for any error messages
2615
2616 if not sw.errors_verify(0):
2617 result = False
2618
2619 # Verify flow table
2620
2621 if not sw.flow_tbl_verify():
2622 result = False
2623
2624 self.assertTrue(result, "Flow_Mod_3_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002625 logging.info("Flow_Mod_3_1 TEST PASSED")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002626
2627
Howard Persh07d99e62012-04-09 15:26:57 -07002628# FLOW DELETE 1
2629#
2630# OVERVIEW
2631# Strict delete of single flow
2632#
2633# PURPOSE
2634# Verify correct operation of strict delete of single defined flow
2635#
2636# PARAMETERS
2637# None
2638#
2639# PROCESS
2640# 1. Delete all flows from switch
2641# 2. Send flow F to switch
2642# 3. Send strict flow delete for F to switch
2643# 4. Verify flow table in swtich
2644# 6. Test PASSED iff all flows sent to switch in step 2 above,
2645# less flow removed in step 3 above, are returned in step 4 above;
2646# else test FAILED
2647
Rich Laneb90a1c42012-10-05 09:16:05 -07002648class Flow_Del_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002649 """
2650 Test FLOW_DEL_1 from draft top-half test plan
2651
2652 INPUTS
2653 None
2654 """
2655
2656 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002657 logging.info("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002658
2659 # Clear all flows from switch
2660
Rich Lane9a003812012-10-04 17:17:59 -07002661 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002662 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002663
2664 # Get switch capabilites
2665
rootf6af1672012-04-06 09:46:29 -07002666 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002667 self.assertTrue(sw.connect(self.controller), \
2668 "Failed to connect to switch" \
2669 )
rootf6af1672012-04-06 09:46:29 -07002670
2671 # Dream up some flow information, i.e. space to chose from for
2672 # random flow parameter generation
2673
2674 fi = Flow_Info()
2675 fi.rand(10)
2676
2677 # Dream up a flow config
2678
2679 fc = Flow_Cfg()
2680 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002681 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002682 sw.tbl_stats.stats[0].wildcards, \
2683 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002684 sw.valid_ports, \
2685 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002686 )
2687 fc = fc.canonical()
2688
2689 # Send it to the switch
2690
Rich Lane9a003812012-10-04 17:17:59 -07002691 logging.info("Sending flow add to switch:")
2692 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002693 ft = Flow_Tbl()
2694 fc.send_rem = False
2695 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2696 ft.insert(fc)
2697
2698 # Dream up some different actions, with the same flow key
2699
2700 fc2 = copy.deepcopy(fc)
2701 while True:
2702 fc2.rand_mod(fi, \
2703 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002704 sw.valid_ports, \
2705 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002706 )
2707 if fc2 != fc:
2708 break
2709
2710 # Delete strictly
2711
Rich Lane9a003812012-10-04 17:17:59 -07002712 logging.info("Sending strict flow del to switch:")
2713 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002714 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2715 ft.delete(fc)
2716
2717 # Do barrier, to make sure all flows are in
2718
2719 self.assertTrue(sw.barrier(), "Barrier failed")
2720
2721 result = True
2722
Howard Persh9cab4822012-09-11 17:08:40 -07002723 sw.settle() # Allow switch to settle and generate any notifications
2724
rootf6af1672012-04-06 09:46:29 -07002725 # Check for any error messages
2726
2727 if not sw.errors_verify(0):
2728 result = False
2729
2730 # Verify flow table
2731
2732 sw.flow_tbl = ft
2733 if not sw.flow_tbl_verify():
2734 result = False
2735
2736 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002737 logging.info("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002738
2739
Howard Persh07d99e62012-04-09 15:26:57 -07002740# FLOW DELETE 2
2741#
2742# OVERVIEW
2743# Loose delete of multiple flows
2744#
2745# PURPOSE
2746# - Verify correct operation of loose delete of multiple flows
2747#
2748# PARAMETERS
2749# Name: num_flows
2750# Type: number
2751# Description:
2752# Number of flows to define
2753# Default: 100
2754#
2755# PROCESS
2756# 1. Delete all flows from switch
2757# 2. Generate <num_flows> distinct flow configurations
2758# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2759# 4. Pick 1 defined flow F at random
2760# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2761# F' will match more than 1 existing flow key
2762# 6. Send loose flow delete for F' to switch
2763# 7. Verify flow table in switch
2764# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2765# removed in step 6 above (i.e. those that match F'), are returned
2766# in step 7 above;
2767# else test FAILED
2768
Rich Laneb90a1c42012-10-05 09:16:05 -07002769class Flow_Del_2(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002770 """
2771 Test FLOW_DEL_2 from draft top-half test plan
2772
2773 INPUTS
2774 None
2775 """
2776
2777 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002778 logging.info("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002779
Rich Lane2014f9b2012-10-05 15:29:40 -07002780 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002781
2782 # Clear all flows from switch
2783
Rich Lane9a003812012-10-04 17:17:59 -07002784 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002785 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002786
2787 # Get switch capabilites
2788
rootf6af1672012-04-06 09:46:29 -07002789 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002790 self.assertTrue(sw.connect(self.controller), \
2791 "Failed to connect to switch" \
2792 )
rootf6af1672012-04-06 09:46:29 -07002793
2794 # Dream up some flow information, i.e. space to chose from for
2795 # random flow parameter generation
2796
2797 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002798 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002799 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002800
2801 # Dream up some flows
2802
2803 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002804 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002805
2806 # Send flow table to switch
2807
Rich Lane9a003812012-10-04 17:17:59 -07002808 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002809 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002810 logging.info("Adding flow:")
2811 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002812 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2813
2814 # Do barrier, to make sure all flows are in
2815
2816 self.assertTrue(sw.barrier(), "Barrier failed")
2817
2818 result = True
2819
Howard Persh9cab4822012-09-11 17:08:40 -07002820 sw.settle() # Allow switch to settle and generate any notifications
2821
rootf6af1672012-04-06 09:46:29 -07002822 # Check for any error messages
2823
2824 if not sw.errors_verify(0):
2825 result = False
2826
2827 # Verify flow table
2828
2829 sw.flow_tbl = ft
2830 if not sw.flow_tbl_verify():
2831 result = False
2832
2833 # Pick a random flow as a basis
2834
2835 dfc = copy.deepcopy(ft.values()[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002836 dfc.rand_mod(fi, \
2837 sw.sw_features.actions, \
2838 sw.valid_ports, \
2839 sw.valid_queues \
2840 )
rootf6af1672012-04-06 09:46:29 -07002841
2842 # Repeatedly wildcard qualifiers
2843
2844 for wi in shuffle(range(len(all_wildcards_list))):
2845 w = all_wildcards_list[wi]
2846 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2847 n = wildcard_get(dfc.match.wildcards, w)
2848 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002849 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2850 w, \
2851 random.randint(n + 1, 32) \
2852 )
rootf6af1672012-04-06 09:46:29 -07002853 else:
2854 continue
2855 else:
2856 if wildcard_get(dfc.match.wildcards, w) == 0:
2857 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2858 else:
2859 continue
2860 dfc = dfc.canonical()
2861
2862 # Count the number of flows that would be deleted
2863
2864 n = 0
2865 for fc in ft.values():
2866 if dfc.overlaps(fc, True):
2867 n = n + 1
2868
2869 # If more than 1, we found our loose delete flow spec
2870 if n > 1:
2871 break
2872
Rich Lane9a003812012-10-04 17:17:59 -07002873 logging.info("Deleting %d flows" % (n))
2874 logging.info("Sending flow del to switch:")
2875 logging.info(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002876 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2877
2878 # Do barrier, to make sure all flows are in
2879 self.assertTrue(sw.barrier(), "Barrier failed")
2880
Howard Persh9cab4822012-09-11 17:08:40 -07002881 sw.settle() # Allow switch to settle and generate any notifications
2882
rootf6af1672012-04-06 09:46:29 -07002883 # Check for error message
2884
2885 if not sw.errors_verify(0):
2886 result = False
2887
2888 # Apply flow mod to local flow table
2889
2890 for fc in ft.values():
2891 if dfc.overlaps(fc, True):
2892 ft.delete(fc)
2893
2894 # Verify flow table
2895
2896 sw.flow_tbl = ft
2897 if not sw.flow_tbl_verify():
2898 result = False
2899
2900 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002901 logging.info("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002902
2903
Howard Persh07d99e62012-04-09 15:26:57 -07002904# FLOW DELETE 4
2905#
2906# OVERVIEW
2907# Flow removed messages
2908#
2909# PURPOSE
2910# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2911# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2912#
2913# PARAMETERS
2914# None
2915#
2916# PROCESS
2917# 1. Delete all flows from switch
2918# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2919# 3. Send strict flow delete of flow to switch
2920# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2921# 5. Verify flow table in switch
2922# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2923# removed in step 3 above, are returned in step 5 above, and that
2924# asynch message was received; else test FAILED
2925
2926
Rich Laneb90a1c42012-10-05 09:16:05 -07002927class Flow_Del_4(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002928 """
2929 Test FLOW_DEL_4 from draft top-half test plan
2930
2931 INPUTS
2932 None
2933 """
2934
2935 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002936 logging.info("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002937
2938 # Clear all flows from switch
2939
Rich Lane9a003812012-10-04 17:17:59 -07002940 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002941 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002942
2943 # Get switch capabilites
2944
rootf6af1672012-04-06 09:46:29 -07002945 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002946 self.assertTrue(sw.connect(self.controller), \
2947 "Failed to connect to switch" \
2948 )
rootf6af1672012-04-06 09:46:29 -07002949
2950 # Dream up some flow information, i.e. space to chose from for
2951 # random flow parameter generation
2952
2953 fi = Flow_Info()
2954 fi.rand(10)
2955
2956 # Dream up a flow config
2957
2958 fc = Flow_Cfg()
2959 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002960 required_wildcards(self), \
rootf6af1672012-04-06 09:46:29 -07002961 sw.tbl_stats.stats[0].wildcards, \
2962 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002963 sw.valid_ports, \
2964 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002965 )
2966 fc = fc.canonical()
2967
2968 # Send it to the switch. with "notify on removed"
2969
Rich Lane9a003812012-10-04 17:17:59 -07002970 logging.info("Sending flow add to switch:")
2971 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002972 ft = Flow_Tbl()
2973 fc.send_rem = True
2974 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2975 ft.insert(fc)
2976
2977 # Dream up some different actions, with the same flow key
2978
2979 fc2 = copy.deepcopy(fc)
2980 while True:
2981 fc2.rand_mod(fi, \
2982 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002983 sw.valid_ports, \
2984 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002985 )
2986 if fc2 != fc:
2987 break
2988
2989 # Delete strictly
2990
Rich Lane9a003812012-10-04 17:17:59 -07002991 logging.info("Sending strict flow del to switch:")
2992 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002993 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2994 ft.delete(fc)
2995
2996 # Do barrier, to make sure all flows are in
2997
2998 self.assertTrue(sw.barrier(), "Barrier failed")
2999
3000 result = True
3001
Howard Persh9cab4822012-09-11 17:08:40 -07003002 sw.settle() # Allow switch to settle and generate any notifications
3003
rootf6af1672012-04-06 09:46:29 -07003004 # Check for expected "removed" message
3005
Howard Persh3340d452012-04-06 16:45:21 -07003006 if not sw.errors_verify(0):
3007 result = False
3008
3009 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07003010 result = False
3011
3012 # Verify flow table
3013
3014 sw.flow_tbl = ft
3015 if not sw.flow_tbl_verify():
3016 result = False
3017
3018 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07003019 logging.info("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07003020