blob: 68d4e1fc0cb95fe083543ab166d013e7f844a6d6 [file] [log] [blame]
Howard Pershc7963582012-03-29 10:02:59 -07001"""
2Flow query test case.
3
Howard Persh3340d452012-04-06 16:45:21 -07004Attempts to fill switch to capacity with randomized flows, and ensure that
5they all are read back correctly.
Howard Pershc7963582012-03-29 10:02:59 -07006"""
Howard Persh07d99e62012-04-09 15:26:57 -07007
8# COMMON TEST PARAMETERS
9#
10# Name: wildcards
11# Type: number
12# Description:
13# Overrides bitmap of supported wildcards reported by switch
14# Default: none
15#
Howard Pershc1199d52012-04-11 14:21:32 -070016# Name: wildcards_force
17# Type: number
18# Description:
19# Bitmap of wildcards to always be set
20# Default: none
21#
Howard Persh07d99e62012-04-09 15:26:57 -070022# Name: actions
23# Type: number
24# Description:
25# Overrides bitmap of supported actions reported by switch
26# Default: none
27#
Howard Pershc1199d52012-04-11 14:21:32 -070028# Name: actions_force
29# Type: number
30# Description:
31# Bitmap of actions to always be used
32# Default: none
33#
34# Name: ports
35# Type: list of OF port numbers
36# Description:
37# Override list of OF port numbers reported by switch
38# Default: none
39#
Howard Persh8d21c1f2012-04-20 15:57:29 -070040# Name: queues
41# Type: list of OF (port-number, queue-id) pairs
42# Description:
43# Override list of OF (port-number, queue-id) pairs returned by switch
44# Default: none
45#
Howard Pershb10a47a2012-08-21 13:54:47 -070046# Name: vlans
47# Type: list of VLAN ids
48# Description:
49# Override VLAN ids used in tests to given list
50# Default: []
51#
Howard Persh07d99e62012-04-09 15:26:57 -070052# Name: conservative_ordered_actions
53# Type: boolean (True or False)
54# Description:
55# Compare flow actions lists as unordered
56# Default: True
57
58
Howard Persh680b92a2012-03-31 13:34:35 -070059import math
Howard Pershc7963582012-03-29 10:02:59 -070060
61import logging
62
63import unittest
64import random
Howard Persh9cab4822012-09-11 17:08:40 -070065import time
Rich Lane3c7cf7f2013-01-11 18:04:56 -080066import copy
Howard Pershc7963582012-03-29 10:02:59 -070067
Rich Lane477f4812012-10-04 22:49:00 -070068from oftest import config
Howard Pershc7963582012-03-29 10:02:59 -070069import oftest.controller as controller
Rich Laned7b0ffa2013-03-08 15:53:42 -080070import ofp
Howard Pershc7963582012-03-29 10:02:59 -070071import oftest.dataplane as dataplane
Howard Pershc7963582012-03-29 10:02:59 -070072import oftest.parse as parse
73import pktact
Rich Laneb90a1c42012-10-05 09:16:05 -070074import oftest.base_tests as base_tests
Howard Pershc7963582012-03-29 10:02:59 -070075
Rich Laneda3b5ad2012-10-03 09:05:32 -070076from oftest.testutils import *
Howard Pershc7963582012-03-29 10:02:59 -070077from time import sleep
78
Howard Pershc7963582012-03-29 10:02:59 -070079
rootf6af1672012-04-06 09:46:29 -070080def flip_coin():
81 return random.randint(1, 100) <= 50
82
83
Howard Pershc7963582012-03-29 10:02:59 -070084def shuffle(list):
85 n = len(list)
86 lim = n * n
87 i = 0
88 while i < lim:
89 a = random.randint(0, n - 1)
90 b = random.randint(0, n - 1)
91 temp = list[a]
92 list[a] = list[b]
93 list[b] = temp
94 i = i + 1
95 return list
96
97
Howard Persh680b92a2012-03-31 13:34:35 -070098def rand_pick(list):
99 return list[random.randint(0, len(list) - 1)]
Howard Pershc7963582012-03-29 10:02:59 -0700100
Howard Persh680b92a2012-03-31 13:34:35 -0700101def rand_dl_addr():
102 return [random.randint(0, 255) & ~1,
103 random.randint(0, 255),
104 random.randint(0, 255),
105 random.randint(0, 255),
106 random.randint(0, 255),
107 random.randint(0, 255)
108 ]
Howard Pershc7963582012-03-29 10:02:59 -0700109
110def rand_nw_addr():
111 return random.randint(0, (1 << 32) - 1)
112
113
rootf6af1672012-04-06 09:46:29 -0700114class Flow_Info:
Howard Persh680b92a2012-03-31 13:34:35 -0700115 # Members:
116 # priorities - list of flow priorities
117 # dl_addrs - list of MAC addresses
118 # vlans - list of VLAN ids
119 # ethertypes - list of Ethertypes
120 # ip_addrs - list of IP addresses
121 # ip_tos - list of IP TOS values
122 # ip_protos - list of IP protocols
123 # l4_ports - list of L4 ports
124
125 def __init__(self):
126 priorities = []
127 dl_addrs = []
128 vlans = []
129 ethertypes = []
130 ip_addrs = []
131 ip_tos = []
132 ip_protos = []
133 l4_ports = []
134
135 def rand(self, n):
136 self.priorities = []
137 i = 0
138 while i < n:
139 self.priorities.append(random.randint(1, 65534))
140 i = i + 1
141
142 self.dl_addrs = []
143 i = 0
144 while i < n:
145 self.dl_addrs.append(rand_dl_addr())
146 i = i + 1
147
Rich Lane2014f9b2012-10-05 15:29:40 -0700148 if test_param_get("vlans", []) != []:
149 self.vlans = test_param_get("vlans", [])
Howard Pershb10a47a2012-08-21 13:54:47 -0700150
Rich Lane9a003812012-10-04 17:17:59 -0700151 logging.info("Overriding VLAN ids to:")
152 logging.info(self.vlans)
Howard Pershb10a47a2012-08-21 13:54:47 -0700153 else:
154 self.vlans = []
155 i = 0
156 while i < n:
157 self.vlans.append(random.randint(1, 4094))
158 i = i + 1
Howard Persh680b92a2012-03-31 13:34:35 -0700159
rootf6af1672012-04-06 09:46:29 -0700160 self.ethertypes = [0x0800, 0x0806]
Howard Persh680b92a2012-03-31 13:34:35 -0700161 i = 0
162 while i < n:
163 self.ethertypes.append(random.randint(0, (1 << 16) - 1))
164 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700165 self.ethertypes = shuffle(self.ethertypes)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700166
167 self.ip_addrs = []
168 i = 0
169 while i < n:
170 self.ip_addrs.append(rand_nw_addr())
171 i = i + 1
172
173 self.ip_tos = []
174 i = 0
175 while i < n:
176 self.ip_tos.append(random.randint(0, (1 << 8) - 1) & ~3)
177 i = i + 1
178
rootf6af1672012-04-06 09:46:29 -0700179 self.ip_protos = [1, 6, 17]
Howard Persh680b92a2012-03-31 13:34:35 -0700180 i = 0
181 while i < n:
182 self.ip_protos.append(random.randint(0, (1 << 8) - 1))
183 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700184 self.ip_protos = shuffle(self.ip_protos)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700185
186 self.l4_ports = []
187 i = 0
188 while i < n:
189 self.l4_ports.append(random.randint(0, (1 << 16) - 1))
190 i = i + 1
191
192 def rand_priority(self):
193 return rand_pick(self.priorities)
194
195 def rand_dl_addr(self):
196 return rand_pick(self.dl_addrs)
197
198 def rand_vlan(self):
199 return rand_pick(self.vlans)
200
201 def rand_ethertype(self):
202 return rand_pick(self.ethertypes)
203
204 def rand_ip_addr(self):
205 return rand_pick(self.ip_addrs)
206
207 def rand_ip_tos(self):
208 return rand_pick(self.ip_tos)
209
210 def rand_ip_proto(self):
211 return rand_pick(self.ip_protos)
212
213 def rand_l4_port(self):
214 return rand_pick(self.l4_ports)
215
216
Howard Pershc7963582012-03-29 10:02:59 -0700217# TBD - These don't belong here
218
Howard Persh680b92a2012-03-31 13:34:35 -0700219all_wildcards_list = [ofp.OFPFW_IN_PORT,
Howard Persh680b92a2012-03-31 13:34:35 -0700220 ofp.OFPFW_DL_DST,
rootf6af1672012-04-06 09:46:29 -0700221 ofp.OFPFW_DL_SRC,
222 ofp.OFPFW_DL_VLAN,
223 ofp.OFPFW_DL_VLAN_PCP,
Howard Persh680b92a2012-03-31 13:34:35 -0700224 ofp.OFPFW_DL_TYPE,
rootf6af1672012-04-06 09:46:29 -0700225 ofp.OFPFW_NW_TOS,
Howard Persh680b92a2012-03-31 13:34:35 -0700226 ofp.OFPFW_NW_PROTO,
Howard Persh680b92a2012-03-31 13:34:35 -0700227 ofp.OFPFW_NW_SRC_MASK,
228 ofp.OFPFW_NW_DST_MASK,
rootf6af1672012-04-06 09:46:29 -0700229 ofp.OFPFW_TP_SRC,
230 ofp.OFPFW_TP_DST
Howard Persh680b92a2012-03-31 13:34:35 -0700231 ]
Howard Pershc7963582012-03-29 10:02:59 -0700232
Howard Persh3340d452012-04-06 16:45:21 -0700233# TBD - Need this because there are duplicates in ofp.ofp_flow_wildcards_map
234# -- FIX
rootf6af1672012-04-06 09:46:29 -0700235all_wildcard_names = {
236 1 : 'OFPFW_IN_PORT',
237 2 : 'OFPFW_DL_VLAN',
238 4 : 'OFPFW_DL_SRC',
239 8 : 'OFPFW_DL_DST',
240 16 : 'OFPFW_DL_TYPE',
241 32 : 'OFPFW_NW_PROTO',
242 64 : 'OFPFW_TP_SRC',
243 128 : 'OFPFW_TP_DST',
244 1048576 : 'OFPFW_DL_VLAN_PCP',
245 2097152 : 'OFPFW_NW_TOS'
246}
247
rootf6af1672012-04-06 09:46:29 -0700248def wildcard_set(x, w, val):
249 result = x
250 if w == ofp.OFPFW_NW_SRC_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700251 result = (result & ~ofp.OFPFW_NW_SRC_MASK) \
252 | (val << ofp.OFPFW_NW_SRC_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700253 elif w == ofp.OFPFW_NW_DST_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700254 result = (result & ~ofp.OFPFW_NW_DST_MASK) \
255 | (val << ofp.OFPFW_NW_DST_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700256 elif val == 0:
257 result = result & ~w
258 else:
259 result = result | w
260 return result
261
262def wildcard_get(x, w):
263 if w == ofp.OFPFW_NW_SRC_MASK:
264 return (x & ofp.OFPFW_NW_SRC_MASK) >> ofp.OFPFW_NW_SRC_SHIFT
265 if w == ofp.OFPFW_NW_DST_MASK:
266 return (x & ofp.OFPFW_NW_DST_MASK) >> ofp.OFPFW_NW_DST_SHIFT
267 return 1 if (x & w) != 0 else 0
268
Howard Persh8d21c1f2012-04-20 15:57:29 -0700269def wildcards_to_str(wildcards):
270 result = "{"
271 sep = ""
272 for w in all_wildcards_list:
273 if (wildcards & w) == 0:
274 continue
275 if w == ofp.OFPFW_NW_SRC_MASK:
276 n = wildcard_get(wildcards, w)
277 if n > 0:
278 result = result + sep + ("OFPFW_NW_SRC(%d)" % (n))
279 elif w == ofp.OFPFW_NW_DST_MASK:
280 n = wildcard_get(wildcards, w)
281 if n > 0:
282 result = result + sep + ("OFPFW_NW_DST(%d)" % (n))
283 else:
284 result = result + sep + all_wildcard_names[w]
285 sep = ", "
286 result = result +"}"
287 return result
Howard Pershc7963582012-03-29 10:02:59 -0700288
Howard Persh680b92a2012-03-31 13:34:35 -0700289all_actions_list = [ofp.OFPAT_OUTPUT,
290 ofp.OFPAT_SET_VLAN_VID,
291 ofp.OFPAT_SET_VLAN_PCP,
292 ofp.OFPAT_STRIP_VLAN,
293 ofp.OFPAT_SET_DL_SRC,
294 ofp.OFPAT_SET_DL_DST,
295 ofp.OFPAT_SET_NW_SRC,
296 ofp.OFPAT_SET_NW_DST,
297 ofp.OFPAT_SET_NW_TOS,
298 ofp.OFPAT_SET_TP_SRC,
299 ofp.OFPAT_SET_TP_DST,
300 ofp.OFPAT_ENQUEUE
301 ]
302
Howard Persh8d21c1f2012-04-20 15:57:29 -0700303def actions_bmap_to_str(bm):
304 result = "{"
305 sep = ""
306 for a in all_actions_list:
307 if ((1 << a) & bm) != 0:
308 result = result + sep + ofp.ofp_action_type_map[a]
309 sep = ", "
310 result = result + "}"
311 return result
312
Howard Persh680b92a2012-03-31 13:34:35 -0700313def dl_addr_to_str(a):
314 return "%x:%x:%x:%x:%x:%x" % tuple(a)
315
316def ip_addr_to_str(a, n):
rootf6af1672012-04-06 09:46:29 -0700317 if n is not None:
318 a = a & ~((1 << (32 - n)) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700319 result = "%d.%d.%d.%d" % (a >> 24, \
320 (a >> 16) & 0xff, \
321 (a >> 8) & 0xff, \
322 a & 0xff \
323 )
324 if n is not None:
325 result = result + ("/%d" % (n))
326 return result
327
Howard Pershc7963582012-03-29 10:02:59 -0700328
rootf6af1672012-04-06 09:46:29 -0700329class Flow_Cfg:
Howard Pershc7963582012-03-29 10:02:59 -0700330 # Members:
331 # - match
332 # - idle_timeout
333 # - hard_timeout
334 # - priority
Rich Lane62e96852013-03-11 12:04:45 -0700335 # - actions
Howard Pershc7963582012-03-29 10:02:59 -0700336
337 def __init__(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700338 self.priority = 0
Rich Laneed1fa2d2013-01-08 13:23:37 -0800339 self.match = ofp.ofp_match()
Howard Pershc7963582012-03-29 10:02:59 -0700340 self.match.wildcards = ofp.OFPFW_ALL
341 self.idle_timeout = 0
342 self.hard_timeout = 0
Rich Lane62e96852013-03-11 12:04:45 -0700343 self.actions = []
Howard Pershc7963582012-03-29 10:02:59 -0700344
rootf6af1672012-04-06 09:46:29 -0700345 # {pri, match} is considered a flow key
346 def key_equal(self, x):
Howard Persh680b92a2012-03-31 13:34:35 -0700347 if self.priority != x.priority:
348 return False
349 # TBD - Should this logic be moved to ofp_match.__eq__()?
350 if self.match.wildcards != x.match.wildcards:
351 return False
rootf6af1672012-04-06 09:46:29 -0700352 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700353 and self.match.in_port != x.match.in_port:
354 return False
rootf6af1672012-04-06 09:46:29 -0700355 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700356 and self.match.eth_dst != x.match.eth_dst:
Howard Persh680b92a2012-03-31 13:34:35 -0700357 return False
rootf6af1672012-04-06 09:46:29 -0700358 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700359 and self.match.eth_src != x.match.eth_src:
rootf6af1672012-04-06 09:46:29 -0700360 return False
361 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700362 and self.match.vlan_vid != x.match.vlan_vid:
Howard Persh680b92a2012-03-31 13:34:35 -0700363 return False
rootf6af1672012-04-06 09:46:29 -0700364 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700365 and self.match.vlan_pcp != x.match.vlan_pcp:
Howard Persh680b92a2012-03-31 13:34:35 -0700366 return False
rootf6af1672012-04-06 09:46:29 -0700367 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700368 and self.match.eth_type != x.match.eth_type:
Howard Persh680b92a2012-03-31 13:34:35 -0700369 return False
rootf6af1672012-04-06 09:46:29 -0700370 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700371 and self.match.ip_dscp != x.match.ip_dscp:
Howard Persh680b92a2012-03-31 13:34:35 -0700372 return False
rootf6af1672012-04-06 09:46:29 -0700373 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700374 and self.match.ip_proto != x.match.ip_proto:
Howard Persh680b92a2012-03-31 13:34:35 -0700375 return False
rootf6af1672012-04-06 09:46:29 -0700376 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
377 if n < 32:
378 m = ~((1 << n) - 1)
Rich Laned0478ff2013-03-11 12:46:58 -0700379 if (self.match.ipv4_src & m) != (x.match.ipv4_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -0700380 return False
rootf6af1672012-04-06 09:46:29 -0700381 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
382 if n < 32:
383 m = ~((1 << n) - 1)
Rich Laned0478ff2013-03-11 12:46:58 -0700384 if (self.match.ipv4_dst & m) != (x.match.ipv4_dst & m):
Howard Persh680b92a2012-03-31 13:34:35 -0700385 return False
rootf6af1672012-04-06 09:46:29 -0700386 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700387 and self.match.tcp_src != x.match.tcp_src:
Howard Persh680b92a2012-03-31 13:34:35 -0700388 return False
rootf6af1672012-04-06 09:46:29 -0700389 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700390 and self.match.tcp_dst != x.match.tcp_dst:
rootf6af1672012-04-06 09:46:29 -0700391 return False
392 return True
393
Howard Persh5f3c83f2012-04-13 09:57:10 -0700394 def actions_equal(self, x):
Rich Lane2014f9b2012-10-05 15:29:40 -0700395 if test_param_get("conservative_ordered_actions", True):
Howard Persh5f3c83f2012-04-13 09:57:10 -0700396 # Compare actions lists as unordered
397
Rich Lane62e96852013-03-11 12:04:45 -0700398 aa = copy.deepcopy(x.actions)
399 for a in self.actions:
root2843d2b2012-04-06 10:27:46 -0700400 i = 0
401 while i < len(aa):
402 if a == aa[i]:
403 break
404 i = i + 1
405 if i < len(aa):
406 aa.pop(i)
407 else:
408 return False
409 return aa == []
410 else:
411 return self.actions == x.actions
Howard Persh5f3c83f2012-04-13 09:57:10 -0700412
413 def non_key_equal(self, x):
414 if self.cookie != x.cookie:
415 return False
416 if self.idle_timeout != x.idle_timeout:
417 return False
418 if self.hard_timeout != x.hard_timeout:
419 return False
420 return self.actions_equal(x)
rootf6af1672012-04-06 09:46:29 -0700421
root2843d2b2012-04-06 10:27:46 -0700422 def key_str(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700423 result = "priority=%d" % self.priority
424 # TBD - Would be nice if ofp_match.show() was better behaved
425 # (no newlines), and more intuitive (things in hex where approprate), etc.
Howard Persh8d21c1f2012-04-20 15:57:29 -0700426 result = result + (", wildcards=0x%x=%s" \
427 % (self.match.wildcards, \
428 wildcards_to_str(self.match.wildcards) \
429 )
430 )
rootf6af1672012-04-06 09:46:29 -0700431 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700432 result = result + (", in_port=%d" % (self.match.in_port))
rootf6af1672012-04-06 09:46:29 -0700433 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -0700434 result = result + (", eth_dst=%s" \
435 % (dl_addr_to_str(self.match.eth_dst)) \
Howard Persh3340d452012-04-06 16:45:21 -0700436 )
rootf6af1672012-04-06 09:46:29 -0700437 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -0700438 result = result + (", eth_src=%s" \
439 % (dl_addr_to_str(self.match.eth_src)) \
Howard Persh3340d452012-04-06 16:45:21 -0700440 )
rootf6af1672012-04-06 09:46:29 -0700441 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -0700442 result = result + (", vlan_vid=%d" % (self.match.vlan_vid))
rootf6af1672012-04-06 09:46:29 -0700443 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -0700444 result = result + (", vlan_pcp=%d" % (self.match.vlan_pcp))
rootf6af1672012-04-06 09:46:29 -0700445 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -0700446 result = result + (", eth_type=0x%x" % (self.match.eth_type))
rootf6af1672012-04-06 09:46:29 -0700447 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -0700448 result = result + (", ip_dscp=0x%x" % (self.match.ip_dscp))
rootf6af1672012-04-06 09:46:29 -0700449 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -0700450 result = result + (", ip_proto=%d" % (self.match.ip_proto))
rootf6af1672012-04-06 09:46:29 -0700451 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700452 if n < 32:
Rich Laned0478ff2013-03-11 12:46:58 -0700453 result = result + (", ipv4_src=%s" % \
454 (ip_addr_to_str(self.match.ipv4_src, 32 - n)) \
Howard Persh3340d452012-04-06 16:45:21 -0700455 )
rootf6af1672012-04-06 09:46:29 -0700456 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700457 if n < 32:
Rich Laned0478ff2013-03-11 12:46:58 -0700458 result = result + (", ipv4_dst=%s" % \
459 (ip_addr_to_str(self.match.ipv4_dst, 32 - n)) \
Howard Persh3340d452012-04-06 16:45:21 -0700460 )
rootf6af1672012-04-06 09:46:29 -0700461 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -0700462 result = result + (", tcp_src=%d" % self.match.tcp_src)
rootf6af1672012-04-06 09:46:29 -0700463 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -0700464 result = result + (", tcp_dst=%d" % self.match.tcp_dst)
rootf6af1672012-04-06 09:46:29 -0700465 return result
466
467 def __eq__(self, x):
468 return (self.key_equal(x) and self.non_key_equal(x))
469
470 def __str__(self):
root2843d2b2012-04-06 10:27:46 -0700471 result = self.key_str()
472 result = result + (", cookie=%d" % self.cookie)
Howard Persh680b92a2012-03-31 13:34:35 -0700473 result = result + (", idle_timeout=%d" % self.idle_timeout)
474 result = result + (", hard_timeout=%d" % self.hard_timeout)
Rich Lane62e96852013-03-11 12:04:45 -0700475 for a in self.actions:
Howard Persh680b92a2012-03-31 13:34:35 -0700476 result = result + (", action=%s" % ofp.ofp_action_type_map[a.type])
477 if a.type == ofp.OFPAT_OUTPUT:
478 result = result + ("(%d)" % (a.port))
479 elif a.type == ofp.OFPAT_SET_VLAN_VID:
480 result = result + ("(%d)" % (a.vlan_vid))
481 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
482 result = result + ("(%d)" % (a.vlan_pcp))
483 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
484 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
485 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
486 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
487 elif a.type == ofp.OFPAT_SET_NW_TOS:
488 result = result + ("(0x%x)" % (a.nw_tos))
489 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
490 result = result + ("(%d)" % (a.tp_port))
491 elif a.type == ofp.OFPAT_ENQUEUE:
492 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
493 return result
Howard Pershc7963582012-03-29 10:02:59 -0700494
Howard Persh8d21c1f2012-04-20 15:57:29 -0700495 def rand_actions_ordered(self, fi, valid_actions, valid_ports, valid_queues):
Howard Persh3340d452012-04-06 16:45:21 -0700496 # Action lists are ordered, so pick an ordered random subset of
497 # supported actions
Howard Pershc1199d52012-04-11 14:21:32 -0700498
Rich Lane2014f9b2012-10-05 15:29:40 -0700499 actions_force = test_param_get("actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700500 if actions_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700501 logging.info("Forced actions:")
502 logging.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700503
Dan Talayco910a8282012-04-07 00:05:20 -0700504 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh3340d452012-04-06 16:45:21 -0700505 supported_actions = []
506 for a in all_actions_list:
507 if ((1 << a) & valid_actions) != 0:
508 supported_actions.append(a)
509
Howard Pershc1199d52012-04-11 14:21:32 -0700510 actions \
511 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
512
513 for a in all_actions_list:
514 if ((1 << a) & actions_force) != 0:
515 actions.append(a)
516
517 actions = shuffle(actions)
Howard Persh3340d452012-04-06 16:45:21 -0700518
Howard Persh6a3698d2012-08-21 14:26:39 -0700519 set_vlanf = False
520 strip_vlanf = False
Rich Lane62e96852013-03-11 12:04:45 -0700521 self.actions = []
Howard Pershc1199d52012-04-11 14:21:32 -0700522 for a in actions:
Dan Talayco910a8282012-04-07 00:05:20 -0700523 act = None
Howard Persh3340d452012-04-06 16:45:21 -0700524 if a == ofp.OFPAT_OUTPUT:
525 pass # OUTPUT actions must come last
526 elif a == ofp.OFPAT_SET_VLAN_VID:
Howard Persh6a3698d2012-08-21 14:26:39 -0700527 if not strip_vlanf:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800528 act = ofp.action.set_vlan_vid()
Howard Persh6a3698d2012-08-21 14:26:39 -0700529 act.vlan_vid = fi.rand_vlan()
530 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700531 elif a == ofp.OFPAT_SET_VLAN_PCP:
Howard Persh6a3698d2012-08-21 14:26:39 -0700532 if not strip_vlanf:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800533 act = ofp.action.set_vlan_pcp()
Howard Persh6a3698d2012-08-21 14:26:39 -0700534 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
535 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700536 elif a == ofp.OFPAT_STRIP_VLAN:
Howard Persh6a3698d2012-08-21 14:26:39 -0700537 if not set_vlanf:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800538 act = ofp.action.strip_vlan()
Howard Persh6a3698d2012-08-21 14:26:39 -0700539 strip_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700540 elif a == ofp.OFPAT_SET_DL_SRC:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800541 act = ofp.action.set_dl_src()
Howard Persh3340d452012-04-06 16:45:21 -0700542 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700543 elif a == ofp.OFPAT_SET_DL_DST:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800544 act = ofp.action.set_dl_dst()
Howard Persh3340d452012-04-06 16:45:21 -0700545 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700546 elif a == ofp.OFPAT_SET_NW_SRC:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800547 act = ofp.action.set_nw_src()
Howard Persh3340d452012-04-06 16:45:21 -0700548 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700549 elif a == ofp.OFPAT_SET_NW_DST:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800550 act = ofp.action.set_nw_dst()
Howard Persh3340d452012-04-06 16:45:21 -0700551 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700552 elif a == ofp.OFPAT_SET_NW_TOS:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800553 act = ofp.action.set_nw_tos()
Rich Laned0478ff2013-03-11 12:46:58 -0700554 act.ip_dscp = fi.rand_ip_tos()
Howard Persh3340d452012-04-06 16:45:21 -0700555 elif a == ofp.OFPAT_SET_TP_SRC:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800556 act = ofp.action.set_tp_src()
Howard Persh3340d452012-04-06 16:45:21 -0700557 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700558 elif a == ofp.OFPAT_SET_TP_DST:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800559 act = ofp.action.set_tp_dst()
Howard Persh3340d452012-04-06 16:45:21 -0700560 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700561 elif a == ofp.OFPAT_ENQUEUE:
562 pass # Enqueue actions must come last
Dan Talayco910a8282012-04-07 00:05:20 -0700563 if act:
Rich Lanec495d9e2013-03-08 17:43:36 -0800564 self.actions.append(act)
Dan Talayco910a8282012-04-07 00:05:20 -0700565
Howard Persh3340d452012-04-06 16:45:21 -0700566 p = random.randint(1, 100)
Howard Pershc1199d52012-04-11 14:21:32 -0700567 if (((1 << ofp.OFPAT_ENQUEUE) & actions_force) != 0 or p <= 33) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700568 and len(valid_queues) > 0 \
569 and ofp.OFPAT_ENQUEUE in actions:
Howard Pershc1199d52012-04-11 14:21:32 -0700570 # In not forecd, one third of the time, include ENQUEUE actions
571 # at end of list
Howard Persh3340d452012-04-06 16:45:21 -0700572 # At most 1 ENQUEUE action
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800573 act = ofp.action.enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700574 (act.port, act.queue_id) = rand_pick(valid_queues)
Rich Lanec495d9e2013-03-08 17:43:36 -0800575 self.actions.append(act)
Howard Pershc1199d52012-04-11 14:21:32 -0700576 if (((1 << ofp.OFPAT_OUTPUT) & actions_force) != 0 \
577 or (p > 33 and p <= 66) \
578 ) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700579 and len(valid_ports) > 0 \
Howard Pershc1199d52012-04-11 14:21:32 -0700580 and ofp.OFPAT_OUTPUT in actions:
Howard Persh3340d452012-04-06 16:45:21 -0700581 # One third of the time, include OUTPUT actions at end of list
582 port_idxs = shuffle(range(len(valid_ports)))
583 # Only 1 output action allowed if IN_PORT wildcarded
584 n = 1 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) != 0 \
585 else random.randint(1, len(valid_ports))
586 port_idxs = port_idxs[0 : n]
587 for pi in port_idxs:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800588 act = ofp.action.output()
Howard Persh3340d452012-04-06 16:45:21 -0700589 act.port = valid_ports[pi]
Howard Persh3340d452012-04-06 16:45:21 -0700590 if act.port != ofp.OFPP_IN_PORT \
591 or wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
592 # OUTPUT(IN_PORT) only valid if OFPFW_IN_PORT not wildcarded
Rich Lanec495d9e2013-03-08 17:43:36 -0800593 self.actions.append(act)
Howard Persh3340d452012-04-06 16:45:21 -0700594 else:
595 # One third of the time, include neither
596 pass
597
598
599 # Randomize flow data for flow modifies (i.e. cookie and actions)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700600 def rand_mod(self, fi, valid_actions, valid_ports, valid_queues):
rootf6af1672012-04-06 09:46:29 -0700601 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700602
Dan Talayco910a8282012-04-07 00:05:20 -0700603 # By default, test with conservative ordering conventions
604 # This should probably be indicated in a profile
Rich Lane2014f9b2012-10-05 15:29:40 -0700605 if test_param_get("conservative_ordered_actions", True):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700606 self.rand_actions_ordered(fi, valid_actions, valid_ports, valid_queues)
Howard Persh3340d452012-04-06 16:45:21 -0700607 return self
608
Rich Lane2014f9b2012-10-05 15:29:40 -0700609 actions_force = test_param_get("actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700610 if actions_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700611 logging.info("Forced actions:")
612 logging.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700613
614 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh680b92a2012-03-31 13:34:35 -0700615 supported_actions = []
616 for a in all_actions_list:
617 if ((1 << a) & valid_actions) != 0:
618 supported_actions.append(a)
619
Howard Pershc1199d52012-04-11 14:21:32 -0700620 actions \
621 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
622
623 for a in all_actions_list:
624 if ((1 << a) & actions_force) != 0:
625 actions.append(a)
626
627 actions = shuffle(actions)
Howard Pershc7963582012-03-29 10:02:59 -0700628
Rich Lane62e96852013-03-11 12:04:45 -0700629 self.actions = []
Howard Pershc1199d52012-04-11 14:21:32 -0700630 for a in actions:
Howard Pershc7963582012-03-29 10:02:59 -0700631 if a == ofp.OFPAT_OUTPUT:
632 # TBD - Output actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700633 if len(valid_ports) == 0:
634 continue
Howard Pershc7963582012-03-29 10:02:59 -0700635 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700636 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700637 for pi in port_idxs:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800638 act = ofp.action.output()
Howard Persh680b92a2012-03-31 13:34:35 -0700639 act.port = valid_ports[pi]
Rich Lanec495d9e2013-03-08 17:43:36 -0800640 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700641 elif a == ofp.OFPAT_SET_VLAN_VID:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800642 act = ofp.action.set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700643 act.vlan_vid = fi.rand_vlan()
Rich Lanec495d9e2013-03-08 17:43:36 -0800644 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700645 elif a == ofp.OFPAT_SET_VLAN_PCP:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800646 act = ofp.action.set_vlan_pcp()
Dan Talayco910a8282012-04-07 00:05:20 -0700647 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700648 elif a == ofp.OFPAT_STRIP_VLAN:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800649 act = ofp.action.strip_vlan()
Rich Lanec495d9e2013-03-08 17:43:36 -0800650 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700651 elif a == ofp.OFPAT_SET_DL_SRC:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800652 act = ofp.action.set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700653 act.dl_addr = fi.rand_dl_addr()
Rich Lanec495d9e2013-03-08 17:43:36 -0800654 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700655 elif a == ofp.OFPAT_SET_DL_DST:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800656 act = ofp.action.set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700657 act.dl_addr = fi.rand_dl_addr()
Rich Lanec495d9e2013-03-08 17:43:36 -0800658 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700659 elif a == ofp.OFPAT_SET_NW_SRC:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800660 act = ofp.action.set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700661 act.nw_addr = fi.rand_ip_addr()
Rich Lanec495d9e2013-03-08 17:43:36 -0800662 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700663 elif a == ofp.OFPAT_SET_NW_DST:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800664 act = ofp.action.set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700665 act.nw_addr = fi.rand_ip_addr()
Rich Lanec495d9e2013-03-08 17:43:36 -0800666 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700667 elif a == ofp.OFPAT_SET_NW_TOS:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800668 act = ofp.action.set_nw_tos()
Rich Laned0478ff2013-03-11 12:46:58 -0700669 act.ip_dscp = fi.rand_ip_tos()
Rich Lanec495d9e2013-03-08 17:43:36 -0800670 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700671 elif a == ofp.OFPAT_SET_TP_SRC:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800672 act = ofp.action.set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700673 act.tp_port = fi.rand_l4_port()
Rich Lanec495d9e2013-03-08 17:43:36 -0800674 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700675 elif a == ofp.OFPAT_SET_TP_DST:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800676 act = ofp.action.set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700677 act.tp_port = fi.rand_l4_port()
Rich Lanec495d9e2013-03-08 17:43:36 -0800678 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700679 elif a == ofp.OFPAT_ENQUEUE:
680 # TBD - Enqueue actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700681 if len(valid_queues) == 0:
682 continue
683 qidxs = shuffle(range(len(valid_queues)))
684 qidxs = qidxs[0 : random.randint(1, len(valid_queues))]
685 for qi in qidxs:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800686 act = ofp.action.enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700687 (act.port, act.queue_id) = valid_queues[qi]
Rich Lanec495d9e2013-03-08 17:43:36 -0800688 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700689
690 return self
691
rootf6af1672012-04-06 09:46:29 -0700692 # Randomize flow cfg
Ed Swierk99a74de2012-08-22 06:40:54 -0700693 def rand(self, fi, wildcards_force, valid_wildcards, valid_actions, valid_ports,
694 valid_queues):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700695 if wildcards_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700696 logging.info("Wildcards forced:")
697 logging.info(wildcards_to_str(wildcards_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700698
rootf6af1672012-04-06 09:46:29 -0700699 # Start with no wildcards, i.e. everything specified
700 self.match.wildcards = 0
Howard Pershc1199d52012-04-11 14:21:32 -0700701
702 if wildcards_force != 0:
703 exact = False
704 else:
705 # Make approx. 5% of flows exact
706 exact = (random.randint(1, 100) <= 5)
rootf6af1672012-04-06 09:46:29 -0700707
708 # For each qualifier Q,
709 # if (wildcarding is not supported for Q,
710 # or an exact flow is specified
711 # or a coin toss comes up heads),
712 # specify Q
713 # else
714 # wildcard Q
715
Howard Pershc1199d52012-04-11 14:21:32 -0700716 if wildcard_get(wildcards_force, ofp.OFPFW_IN_PORT) == 0 \
717 and (wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
718 or exact \
719 or flip_coin() \
720 ):
rootf6af1672012-04-06 09:46:29 -0700721 self.match.in_port = rand_pick(valid_ports)
722 else:
Howard Persh3340d452012-04-06 16:45:21 -0700723 self.match.wildcards = wildcard_set(self.match.wildcards, \
724 ofp.OFPFW_IN_PORT, \
725 1 \
726 )
rootf6af1672012-04-06 09:46:29 -0700727
Howard Pershc1199d52012-04-11 14:21:32 -0700728 if wildcard_get(wildcards_force, ofp.OFPFW_DL_DST) == 0 \
729 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
730 or exact \
731 or flip_coin() \
732 ):
Rich Laned0478ff2013-03-11 12:46:58 -0700733 self.match.eth_dst = fi.rand_dl_addr()
rootf6af1672012-04-06 09:46:29 -0700734 else:
Howard Persh3340d452012-04-06 16:45:21 -0700735 self.match.wildcards = wildcard_set(self.match.wildcards, \
736 ofp.OFPFW_DL_DST, \
737 1 \
738 )
rootf6af1672012-04-06 09:46:29 -0700739
Howard Pershc1199d52012-04-11 14:21:32 -0700740 if wildcard_get(wildcards_force, ofp.OFPFW_DL_SRC) == 0 \
741 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
742 or exact \
743 or flip_coin() \
744 ):
Rich Laned0478ff2013-03-11 12:46:58 -0700745 self.match.eth_src = fi.rand_dl_addr()
rootf6af1672012-04-06 09:46:29 -0700746 else:
Howard Persh3340d452012-04-06 16:45:21 -0700747 self.match.wildcards = wildcard_set(self.match.wildcards, \
748 ofp.OFPFW_DL_SRC, \
749 1 \
750 )
rootf6af1672012-04-06 09:46:29 -0700751
Howard Pershc1199d52012-04-11 14:21:32 -0700752 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN) == 0 \
753 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
754 or exact \
755 or flip_coin() \
756 ):
Rich Laned0478ff2013-03-11 12:46:58 -0700757 self.match.vlan_vid = fi.rand_vlan()
rootf6af1672012-04-06 09:46:29 -0700758 else:
Howard Persh3340d452012-04-06 16:45:21 -0700759 self.match.wildcards = wildcard_set(self.match.wildcards, \
760 ofp.OFPFW_DL_VLAN, \
761 1 \
762 )
rootf6af1672012-04-06 09:46:29 -0700763
Howard Pershc1199d52012-04-11 14:21:32 -0700764 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN_PCP) == 0 \
765 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
766 or exact \
767 or flip_coin() \
768 ):
Rich Laned0478ff2013-03-11 12:46:58 -0700769 self.match.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc1199d52012-04-11 14:21:32 -0700770 else:
771 self.match.wildcards = wildcard_set(self.match.wildcards, \
772 ofp.OFPFW_DL_VLAN_PCP, \
773 1 \
774 )
775
776 if wildcard_get(wildcards_force, ofp.OFPFW_DL_TYPE) == 0 \
777 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
778 or exact \
779 or flip_coin() \
780 ):
Rich Laned0478ff2013-03-11 12:46:58 -0700781 self.match.eth_type = fi.rand_ethertype()
rootf6af1672012-04-06 09:46:29 -0700782 else:
Howard Persh3340d452012-04-06 16:45:21 -0700783 self.match.wildcards = wildcard_set(self.match.wildcards, \
784 ofp.OFPFW_DL_TYPE, \
785 1 \
786 )
rootf6af1672012-04-06 09:46:29 -0700787
Howard Pershc1199d52012-04-11 14:21:32 -0700788 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_SRC_MASK)
789 if n == 0:
790 if exact or flip_coin():
791 n = 0
792 else:
793 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
794 if n > 32:
795 n = 32
796 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700797 self.match.wildcards = wildcard_set(self.match.wildcards, \
798 ofp.OFPFW_NW_SRC_MASK, \
799 n \
800 )
rootf6af1672012-04-06 09:46:29 -0700801 if n < 32:
Rich Laned0478ff2013-03-11 12:46:58 -0700802 self.match.ipv4_src = fi.rand_ip_addr() & ~((1 << n) - 1)
rootf6af1672012-04-06 09:46:29 -0700803 # Specifying any IP address match other than all bits
804 # don't care requires that Ethertype is one of {IP, ARP}
805 if flip_coin():
Rich Laned0478ff2013-03-11 12:46:58 -0700806 self.match.eth_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700807 self.match.wildcards = wildcard_set(self.match.wildcards, \
808 ofp.OFPFW_DL_TYPE, \
809 0 \
810 )
rootf6af1672012-04-06 09:46:29 -0700811
Howard Pershc1199d52012-04-11 14:21:32 -0700812 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_DST_MASK)
813 if n == 0:
814 if exact or flip_coin():
815 n = 0
816 else:
817 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
818 if n > 32:
819 n = 32
820 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700821 self.match.wildcards = wildcard_set(self.match.wildcards, \
822 ofp.OFPFW_NW_DST_MASK, \
823 n \
824 )
rootf6af1672012-04-06 09:46:29 -0700825 if n < 32:
Rich Laned0478ff2013-03-11 12:46:58 -0700826 self.match.ipv4_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
rootf6af1672012-04-06 09:46:29 -0700827 # Specifying any IP address match other than all bits
828 # don't care requires that Ethertype is one of {IP, ARP}
829 if flip_coin():
Rich Laned0478ff2013-03-11 12:46:58 -0700830 self.match.eth_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700831 self.match.wildcards = wildcard_set(self.match.wildcards, \
832 ofp.OFPFW_DL_TYPE, \
833 0 \
834 )
rootf6af1672012-04-06 09:46:29 -0700835
Howard Pershc1199d52012-04-11 14:21:32 -0700836 if wildcard_get(wildcards_force, ofp.OFPFW_NW_TOS) == 0 \
837 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
838 or exact \
839 or flip_coin() \
840 ):
Rich Laned0478ff2013-03-11 12:46:58 -0700841 self.match.ip_dscp = fi.rand_ip_tos()
rootf6af1672012-04-06 09:46:29 -0700842 # Specifying a TOS value requires that Ethertype is IP
843 if flip_coin():
Rich Laned0478ff2013-03-11 12:46:58 -0700844 self.match.eth_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700845 self.match.wildcards = wildcard_set(self.match.wildcards, \
846 ofp.OFPFW_DL_TYPE, \
847 0 \
848 )
rootf6af1672012-04-06 09:46:29 -0700849 else:
Howard Persh3340d452012-04-06 16:45:21 -0700850 self.match.wildcards = wildcard_set(self.match.wildcards, \
851 ofp.OFPFW_NW_TOS, \
852 1 \
853 )
rootf6af1672012-04-06 09:46:29 -0700854
Rich Laned0478ff2013-03-11 12:46:58 -0700855 # Known issue on OVS with specifying ip_proto w/o eth_type as IP
Howard Pershc1199d52012-04-11 14:21:32 -0700856 if wildcard_get(wildcards_force, ofp.OFPFW_NW_PROTO) == 0 \
857 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
858 or exact \
859 or flip_coin() \
860 ):
Rich Laned0478ff2013-03-11 12:46:58 -0700861 self.match.ip_proto = fi.rand_ip_proto()
Dan Talayco910a8282012-04-07 00:05:20 -0700862 # Specifying an IP protocol requires that Ethertype is IP
863 if flip_coin():
Rich Laned0478ff2013-03-11 12:46:58 -0700864 self.match.eth_type = 0x0800
Dan Talayco910a8282012-04-07 00:05:20 -0700865 self.match.wildcards = wildcard_set(self.match.wildcards, \
866 ofp.OFPFW_DL_TYPE, \
867 0 \
868 )
869 else:
Howard Persh3340d452012-04-06 16:45:21 -0700870 self.match.wildcards = wildcard_set(self.match.wildcards, \
871 ofp.OFPFW_NW_PROTO, \
872 1 \
873 )
Dan Talayco910a8282012-04-07 00:05:20 -0700874
Howard Pershc1199d52012-04-11 14:21:32 -0700875 if wildcard_get(wildcards_force, ofp.OFPFW_TP_SRC) == 0 \
876 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
877 or exact\
878 or flip_coin() \
879 ):
Rich Laned0478ff2013-03-11 12:46:58 -0700880 self.match.tcp_src = fi.rand_l4_port()
rootf6af1672012-04-06 09:46:29 -0700881 # Specifying a L4 port requires that IP protcol is
882 # one of {ICMP, TCP, UDP}
883 if flip_coin():
Rich Laned0478ff2013-03-11 12:46:58 -0700884 self.match.ip_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700885 self.match.wildcards = wildcard_set(self.match.wildcards, \
886 ofp.OFPFW_NW_PROTO, \
887 0 \
888 )
rootf6af1672012-04-06 09:46:29 -0700889 # Specifying a L4 port requirues that Ethertype is IP
Rich Laned0478ff2013-03-11 12:46:58 -0700890 self.match.eth_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700891 self.match.wildcards = wildcard_set(self.match.wildcards, \
892 ofp.OFPFW_DL_TYPE, \
893 0 \
894 )
Rich Laned0478ff2013-03-11 12:46:58 -0700895 if self.match.ip_proto == 1:
896 self.match.tcp_src = self.match.tcp_src & 0xff
rootf6af1672012-04-06 09:46:29 -0700897 else:
Howard Persh3340d452012-04-06 16:45:21 -0700898 self.match.wildcards = wildcard_set(self.match.wildcards, \
899 ofp.OFPFW_TP_SRC, \
900 1 \
901 )
rootf6af1672012-04-06 09:46:29 -0700902
Howard Pershc1199d52012-04-11 14:21:32 -0700903 if wildcard_get(wildcards_force, ofp.OFPFW_TP_DST) == 0 \
904 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
905 or exact \
906 or flip_coin() \
907 ):
Rich Laned0478ff2013-03-11 12:46:58 -0700908 self.match.tcp_dst = fi.rand_l4_port()
rootf6af1672012-04-06 09:46:29 -0700909 # Specifying a L4 port requires that IP protcol is
910 # one of {ICMP, TCP, UDP}
911 if flip_coin():
Rich Laned0478ff2013-03-11 12:46:58 -0700912 self.match.ip_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700913 self.match.wildcards = wildcard_set(self.match.wildcards, \
914 ofp.OFPFW_NW_PROTO, \
915 0 \
916 )
rootf6af1672012-04-06 09:46:29 -0700917 # Specifying a L4 port requirues that Ethertype is IP
Rich Laned0478ff2013-03-11 12:46:58 -0700918 self.match.eth_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700919 self.match.wildcards = wildcard_set(self.match.wildcards, \
920 ofp.OFPFW_DL_TYPE, \
921 0 \
922 )
Rich Laned0478ff2013-03-11 12:46:58 -0700923 if self.match.ip_proto == 1:
924 self.match.tcp_dst = self.match.tcp_dst & 0xff
rootf6af1672012-04-06 09:46:29 -0700925 else:
Howard Persh3340d452012-04-06 16:45:21 -0700926 self.match.wildcards = wildcard_set(self.match.wildcards, \
927 ofp.OFPFW_TP_DST, \
928 1 \
929 )
rootf6af1672012-04-06 09:46:29 -0700930
931 # If nothing is wildcarded, it is an exact flow spec -- some switches
Howard Persh3340d452012-04-06 16:45:21 -0700932 # (Open vSwitch, for one) *require* that exact flow specs
933 # have priority 65535.
934 self.priority = 65535 if self.match.wildcards == 0 \
935 else fi.rand_priority()
rootf6af1672012-04-06 09:46:29 -0700936
937 # N.B. Don't make the timeout too short, else the flow might
938 # disappear before we get a chance to check for it.
939 t = random.randint(0, 65535)
940 self.idle_timeout = 0 if t < 60 else t
941 t = random.randint(0, 65535)
942 self.hard_timeout = 0 if t < 60 else t
943
Howard Persh8d21c1f2012-04-20 15:57:29 -0700944 self.rand_mod(fi, valid_actions, valid_ports, valid_queues)
rootf6af1672012-04-06 09:46:29 -0700945
946 return self
947
948 # Return flow cfg in canonical form
Howard Persh3340d452012-04-06 16:45:21 -0700949 # - There are dependencies between flow qualifiers, e.g. it only makes
Rich Laned0478ff2013-03-11 12:46:58 -0700950 # sense to qualify ip_proto if eth_type is qualified to be 0x0800 (IP).
Howard Persh3340d452012-04-06 16:45:21 -0700951 # The canonical form of flow match criteria will "wildcard out"
952 # all such cases.
rootf6af1672012-04-06 09:46:29 -0700953 def canonical(self):
954 result = copy.deepcopy(self)
Howard Persh07d99e62012-04-09 15:26:57 -0700955
956 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_VLAN) != 0:
957 result.match.wildcards = wildcard_set(result.match.wildcards, \
958 ofp.OFPFW_DL_VLAN_PCP, \
959 1 \
960 )
961
rootf6af1672012-04-06 09:46:29 -0700962 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700963 or result.match.eth_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700964 # dl_tyoe is wildcarded, or specified as something other
965 # than IP or ARP
Rich Laned0478ff2013-03-11 12:46:58 -0700966 # => ipv4_src, ipv4_dst, ip_proto cannot be specified,
Howard Persh07d99e62012-04-09 15:26:57 -0700967 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700968 result.match.wildcards = wildcard_set(result.match.wildcards, \
969 ofp.OFPFW_NW_SRC_MASK, \
970 32 \
971 )
972 result.match.wildcards = wildcard_set(result.match.wildcards, \
973 ofp.OFPFW_NW_DST_MASK, \
974 32 \
975 )
Howard Persh3340d452012-04-06 16:45:21 -0700976 result.match.wildcards = wildcard_set(result.match.wildcards, \
977 ofp.OFPFW_NW_PROTO, \
978 1 \
979 )
Howard Persh07d99e62012-04-09 15:26:57 -0700980
981 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700982 or result.match.eth_type != 0x0800:
983 # eth_type is wildcarded, or specified as something other than IP
984 # => ip_dscp, tcp_src and tcp_dst cannot be specified,
Howard Persh07d99e62012-04-09 15:26:57 -0700985 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700986 result.match.wildcards = wildcard_set(result.match.wildcards, \
987 ofp.OFPFW_NW_TOS, \
988 1 \
989 )
990 result.match.wildcards = wildcard_set(result.match.wildcards, \
991 ofp.OFPFW_TP_SRC, \
992 1 \
993 )
994 result.match.wildcards = wildcard_set(result.match.wildcards, \
995 ofp.OFPFW_TP_DST, \
996 1 \
997 )
Howard Persh07d99e62012-04-09 15:26:57 -0700998 result.match.wildcards = wildcard_set(result.match.wildcards, \
999 ofp.OFPFW_NW_SRC_MASK, \
1000 32 \
1001 )
1002 result.match.wildcards = wildcard_set(result.match.wildcards, \
1003 ofp.OFPFW_NW_DST_MASK, \
1004 32 \
1005 )
1006 result.match.wildcards = wildcard_set(result.match.wildcards, \
1007 ofp.OFPFW_NW_PROTO, \
1008 1 \
1009 )
1010
rootf6af1672012-04-06 09:46:29 -07001011 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
Rich Laned0478ff2013-03-11 12:46:58 -07001012 or result.match.ip_proto not in [1, 6, 17]:
1013 # ip_proto is wildcarded, or specified as something other than ICMP,
Howard Persh3340d452012-04-06 16:45:21 -07001014 # TCP or UDP
Rich Laned0478ff2013-03-11 12:46:58 -07001015 # => tcp_src and tcp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001016 result.match.wildcards = wildcard_set(result.match.wildcards, \
1017 ofp.OFPFW_TP_SRC, \
1018 1 \
1019 )
1020 result.match.wildcards = wildcard_set(result.match.wildcards, \
1021 ofp.OFPFW_TP_DST, \
1022 1 \
1023 )
rootf6af1672012-04-06 09:46:29 -07001024 return result
1025
Howard Persh680b92a2012-03-31 13:34:35 -07001026 # Overlap check
1027 # delf == True <=> Check for delete overlap, else add overlap
1028 # "Add overlap" is defined as there exists a packet that could match both the
1029 # receiver and argument flowspecs
1030 # "Delete overlap" is defined as the specificity of the argument flowspec
1031 # is greater than or equal to the specificity of the receiver flowspec
1032 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -07001033 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
1034 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001035 if self.match.in_port != x.match.in_port:
1036 return False # Both specified, and not equal
1037 elif delf:
1038 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001039 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
1040 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001041 if self.match.vlan_vid != x.match.vlan_vid:
Howard Persh680b92a2012-03-31 13:34:35 -07001042 return False # Both specified, and not equal
1043 elif delf:
1044 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001045 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
1046 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001047 if self.match.eth_src != x.match.eth_src:
Howard Persh680b92a2012-03-31 13:34:35 -07001048 return False # Both specified, and not equal
1049 elif delf:
1050 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001051 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
1052 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001053 if self.match.eth_dst != x.match.eth_dst:
Howard Persh680b92a2012-03-31 13:34:35 -07001054 return False # Both specified, and not equal
1055 elif delf:
1056 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001057 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
1058 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001059 if self.match.eth_type != x.match.eth_type:
Howard Persh680b92a2012-03-31 13:34:35 -07001060 return False # Both specified, and not equal
1061 elif delf:
1062 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -07001063 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
1064 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001065 if self.match.ip_proto != x.match.ip_proto:
Howard Persh680b92a2012-03-31 13:34:35 -07001066 return False # Both specified, and not equal
1067 elif delf:
1068 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001069 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
1070 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001071 if self.match.tcp_src != x.match.tcp_src:
Howard Persh680b92a2012-03-31 13:34:35 -07001072 return False # Both specified, and not equal
1073 elif delf:
1074 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001075 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
1076 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001077 if self.match.tcp_dst != x.match.tcp_dst:
Howard Persh680b92a2012-03-31 13:34:35 -07001078 return False # Both specified, and not equal
1079 elif delf:
1080 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001081 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
1082 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001083 if delf and na < nb:
1084 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001085 if (na < 32 and nb < 32):
1086 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
Rich Laned0478ff2013-03-11 12:46:58 -07001087 if (self.match.ipv4_src & m) != (x.match.ipv4_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -07001088 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -07001089 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
1090 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001091 if delf and na < nb:
1092 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001093 if (na < 32 and nb < 32):
1094 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
Rich Laned0478ff2013-03-11 12:46:58 -07001095 if (self.match.ipv4_dst & m) != (x.match.ipv4_dst & m):
rootf6af1672012-04-06 09:46:29 -07001096 return False # Overlapping bits not equal
1097 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
1098 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001099 if self.match.vlan_pcp != x.match.vlan_pcp:
Howard Persh680b92a2012-03-31 13:34:35 -07001100 return False # Both specified, and not equal
1101 elif delf:
1102 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001103 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
1104 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001105 if self.match.ip_dscp != x.match.ip_dscp:
Howard Persh680b92a2012-03-31 13:34:35 -07001106 return False # Both specified, and not equal
1107 elif delf:
1108 return False # Receiver more specific
1109 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -07001110
1111 def to_flow_mod_msg(self, msg):
1112 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -07001113 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001114 msg.idle_timeout = self.idle_timeout
1115 msg.hard_timeout = self.hard_timeout
1116 msg.priority = self.priority
1117 msg.actions = self.actions
1118 return msg
1119
1120 def from_flow_stat(self, msg):
1121 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -07001122 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001123 self.idle_timeout = msg.idle_timeout
1124 self.hard_timeout = msg.hard_timeout
1125 self.priority = msg.priority
1126 self.actions = msg.actions
1127
rootf6af1672012-04-06 09:46:29 -07001128 def from_flow_rem(self, msg):
1129 self.match = msg.match
1130 self.idle_timeout = msg.idle_timeout
1131 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -07001132
Howard Pershc7963582012-03-29 10:02:59 -07001133
rootf6af1672012-04-06 09:46:29 -07001134class Flow_Tbl:
1135 def clear(self):
1136 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001137
rootf6af1672012-04-06 09:46:29 -07001138 def __init__(self):
1139 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001140
rootf6af1672012-04-06 09:46:29 -07001141 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001142 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001143
1144 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001145 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001146
1147 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001148 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001149
1150 def values(self):
1151 return self.dict.values()
1152
1153 def count(self):
1154 return len(self.dict)
1155
Ed Swierk99a74de2012-08-22 06:40:54 -07001156 def rand(self, wildcards_force, sw, fi, num_flows):
rootf6af1672012-04-06 09:46:29 -07001157 self.clear()
1158 i = 0
1159 tbl = 0
1160 j = 0
1161 while i < num_flows:
1162 fc = Flow_Cfg()
1163 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001164 wildcards_force, \
Rich Lane5fd6faf2013-03-11 13:30:20 -07001165 sw.tbl_stats.entries[tbl].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001166 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001167 sw.valid_ports, \
1168 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001169 )
1170 fc = fc.canonical()
1171 if self.find(fc):
1172 continue
1173 fc.send_rem = False
1174 self.insert(fc)
1175 i = i + 1
1176 j = j + 1
Rich Lane5fd6faf2013-03-11 13:30:20 -07001177 if j >= sw.tbl_stats.entries[tbl].max_entries:
rootf6af1672012-04-06 09:46:29 -07001178 tbl = tbl + 1
1179 j = 0
1180
1181
1182class Switch:
1183 # Members:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001184 # controller - switch's test controller
1185 # sw_features - switch's OFPT_FEATURES_REPLY message
1186 # valid_ports - list of valid port numbers
1187 # valid_queues - list of valid [port, queue] pairs
1188 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1189 # queue_stats - switch's OFPT_STATS_REPLY message, for queue stats request
1190 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1191 # flow_tbl - (test's idea of) switch's flow table
rootf6af1672012-04-06 09:46:29 -07001192
1193 def __init__(self):
Howard Persh8d21c1f2012-04-20 15:57:29 -07001194 self.controller = None
1195 self.sw_features = None
1196 self.valid_ports = []
1197 self.valid_queues = []
1198 self.tbl_stats = None
1199 self.flow_stats = None
1200 self.flow_tbl = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001201 self.error_msgs = []
1202 self.removed_msgs = []
1203
1204 def error_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001205 logging.info("Got an ERROR message, type=%d, code=%d" \
Rich Laneb73808c2013-03-11 15:22:23 -07001206 % (msg.err_type, msg.code) \
Ed Swierk99a74de2012-08-22 06:40:54 -07001207 )
Ed Swierk99a74de2012-08-22 06:40:54 -07001208 self.error_msgs.append(msg)
1209
1210 def removed_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001211 logging.info("Got a REMOVED message")
Ed Swierk99a74de2012-08-22 06:40:54 -07001212 self.removed_msgs.append(msg)
rootf6af1672012-04-06 09:46:29 -07001213
Howard Persh3340d452012-04-06 16:45:21 -07001214 def controller_set(self, controller):
1215 self.controller = controller
1216 # Register error message handler
Ed Swierk99a74de2012-08-22 06:40:54 -07001217 self.error_msgs = []
1218 self.removed_msgs = []
1219 controller.register(ofp.OFPT_ERROR, self.error_handler)
1220 controller.register(ofp.OFPT_FLOW_REMOVED, self.removed_handler)
Howard Persh3340d452012-04-06 16:45:21 -07001221
rootf6af1672012-04-06 09:46:29 -07001222 def features_get(self):
1223 # Get switch features
Rich Lane28fa9272013-03-08 16:00:25 -08001224 request = ofp.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001225 (self.sw_features, pkt) = self.controller.transact(request)
rootf6af1672012-04-06 09:46:29 -07001226 if self.sw_features is None:
Rich Lane9a003812012-10-04 17:17:59 -07001227 logging.error("Get switch features failed")
rootf6af1672012-04-06 09:46:29 -07001228 return False
1229 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Rich Lane9a003812012-10-04 17:17:59 -07001230 logging.info("Ports reported by switch:")
1231 logging.info(self.valid_ports)
Rich Lane2014f9b2012-10-05 15:29:40 -07001232 ports_override = test_param_get("ports", [])
Howard Persh8d21c1f2012-04-20 15:57:29 -07001233 if ports_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001234 logging.info("Overriding ports to:")
1235 logging.info(ports_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001236 self.valid_ports = ports_override
1237
Howard Persh3340d452012-04-06 16:45:21 -07001238 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1239 # is that universal?
1240
1241 # TBD - There seems to be variability in which switches support which
1242 # ports; need to sort that out
1243 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1244# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1245# ofp.OFPP_NORMAL, \
1246# ofp.OFPP_FLOOD, \
1247# ofp.OFPP_ALL, \
1248# ofp.OFPP_CONTROLLER \
1249# ] \
1250# )
Rich Lane9a003812012-10-04 17:17:59 -07001251 logging.info("Supported actions reported by switch:")
1252 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001253 % (self.sw_features.actions, \
1254 actions_bmap_to_str(self.sw_features.actions) \
1255 ) \
1256 )
Rich Lane2014f9b2012-10-05 15:29:40 -07001257 actions_override = test_param_get("actions", -1)
Howard Persh07d99e62012-04-09 15:26:57 -07001258 if actions_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001259 logging.info("Overriding supported actions to:")
1260 logging.info(actions_bmap_to_str(actions_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001261 self.sw_features.actions = actions_override
rootf6af1672012-04-06 09:46:29 -07001262 return True
1263
1264 def tbl_stats_get(self):
1265 # Get table stats
Rich Lane28fa9272013-03-08 16:00:25 -08001266 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001267 (self.tbl_stats, pkt) = self.controller.transact(request)
Howard Persh07d99e62012-04-09 15:26:57 -07001268 if self.tbl_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001269 logging.error("Get table stats failed")
Howard Persh07d99e62012-04-09 15:26:57 -07001270 return False
Howard Persh8d21c1f2012-04-20 15:57:29 -07001271 i = 0
Rich Lane5fd6faf2013-03-11 13:30:20 -07001272 for ts in self.tbl_stats.entries:
Rich Lane9a003812012-10-04 17:17:59 -07001273 logging.info("Supported wildcards for table %d reported by switch:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001274 % (i)
1275 )
Rich Lane9a003812012-10-04 17:17:59 -07001276 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001277 % (ts.wildcards, \
1278 wildcards_to_str(ts.wildcards) \
1279 ) \
1280 )
Rich Lane2014f9b2012-10-05 15:29:40 -07001281 wildcards_override = test_param_get("wildcards", -1)
Howard Persh07d99e62012-04-09 15:26:57 -07001282 if wildcards_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001283 logging.info("Overriding supported wildcards for table %d to:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001284 % (i)
1285 )
Rich Lane9a003812012-10-04 17:17:59 -07001286 logging.info(wildcards_to_str(wildcards_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001287 ts.wildcards = wildcards_override
Howard Persh8d21c1f2012-04-20 15:57:29 -07001288 i = i + 1
Howard Persh07d99e62012-04-09 15:26:57 -07001289 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001290
Howard Persh8d21c1f2012-04-20 15:57:29 -07001291 def queue_stats_get(self):
1292 # Get queue stats
Rich Lane28fa9272013-03-08 16:00:25 -08001293 request = ofp.message.queue_stats_request()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001294 request.port_no = ofp.OFPP_ALL
1295 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001296 (self.queue_stats, pkt) = self.controller.transact(request)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001297 if self.queue_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001298 logging.error("Get queue stats failed")
Howard Persh8d21c1f2012-04-20 15:57:29 -07001299 return False
1300 self.valid_queues = map(lambda x: (x.port_no, x.queue_id), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07001301 self.queue_stats.entries \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001302 )
Rich Lane9a003812012-10-04 17:17:59 -07001303 logging.info("(Port, queue) pairs reported by switch:")
1304 logging.info(self.valid_queues)
Rich Lane2014f9b2012-10-05 15:29:40 -07001305 queues_override = test_param_get("queues", [])
Howard Persh8d21c1f2012-04-20 15:57:29 -07001306 if queues_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001307 logging.info("Overriding (port, queue) pairs to:")
1308 logging.info(queues_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001309 self.valid_queues = queues_override
1310 return True
1311
1312 def connect(self, controller):
1313 # Connect to controller, and get all switch capabilities
1314 self.controller_set(controller)
1315 return (self.features_get() \
1316 and self.tbl_stats_get() \
1317 and self.queue_stats_get() \
1318 )
1319
Howard Pershc1199d52012-04-11 14:21:32 -07001320 def flow_stats_get(self, limit = 10000):
Rich Lane28fa9272013-03-08 16:00:25 -08001321 request = ofp.message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -07001322 query_match = ofp.ofp_match()
1323 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001324 request.match = query_match
1325 request.table_id = 0xff
1326 request.out_port = ofp.OFPP_NONE;
Rich Lane5c3151c2013-01-03 17:15:41 -08001327 self.controller.message_send(request)
Howard Persh3340d452012-04-06 16:45:21 -07001328 # <TBD>
1329 # Glue together successive reponse messages for stats reply.
1330 # Looking at the "more" flag and performing re-assembly
1331 # should be a part of the infrastructure.
1332 # </TBD>
1333 n = 0
1334 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -07001335 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY)
Howard Persh3340d452012-04-06 16:45:21 -07001336 if resp is None:
Howard Pershc1199d52012-04-11 14:21:32 -07001337 return False # Did not get expected response
Howard Persh3340d452012-04-06 16:45:21 -07001338 if n == 0:
1339 self.flow_stats = resp
1340 else:
Rich Lane5fd6faf2013-03-11 13:30:20 -07001341 self.flow_stats.entries.extend(resp.entries)
Howard Persh3340d452012-04-06 16:45:21 -07001342 n = n + 1
Rich Lane5fd6faf2013-03-11 13:30:20 -07001343 if len(self.flow_stats.entries) > limit:
Rich Lane9a003812012-10-04 17:17:59 -07001344 logging.error("Too many flows returned")
Howard Pershc1199d52012-04-11 14:21:32 -07001345 return False
1346 if (resp.flags & 1) == 0:
1347 break # No more responses expected
Howard Persh3340d452012-04-06 16:45:21 -07001348 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001349
rootf6af1672012-04-06 09:46:29 -07001350 def flow_add(self, flow_cfg, overlapf = False):
Rich Lane28fa9272013-03-08 16:00:25 -08001351 flow_mod_msg = ofp.message.flow_mod()
Howard Persh680b92a2012-03-31 13:34:35 -07001352 flow_mod_msg.command = ofp.OFPFC_ADD
1353 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001354 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001355 if overlapf:
1356 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001357 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001358 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Rich Laneb73808c2013-03-11 15:22:23 -07001359 flow_mod_msg.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001360 logging.info("Sending flow_mod(add), xid=%d"
Rich Laneb73808c2013-03-11 15:22:23 -07001361 % (flow_mod_msg.xid)
Howard Pershc1199d52012-04-11 14:21:32 -07001362 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001363 self.controller.message_send(flow_mod_msg)
1364 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001365
rootf6af1672012-04-06 09:46:29 -07001366 def flow_mod(self, flow_cfg, strictf):
Rich Lane28fa9272013-03-08 16:00:25 -08001367 flow_mod_msg = ofp.message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001368 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf \
1369 else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -07001370 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001371 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Rich Laneb73808c2013-03-11 15:22:23 -07001372 flow_mod_msg.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001373 logging.info("Sending flow_mod(mod), xid=%d"
Rich Laneb73808c2013-03-11 15:22:23 -07001374 % (flow_mod_msg.xid)
Howard Pershc1199d52012-04-11 14:21:32 -07001375 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001376 self.controller.message_send(flow_mod_msg)
1377 return True
rootf6af1672012-04-06 09:46:29 -07001378
1379 def flow_del(self, flow_cfg, strictf):
Rich Lane28fa9272013-03-08 16:00:25 -08001380 flow_mod_msg = ofp.message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001381 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf \
1382 else ofp.OFPFC_DELETE
rootf6af1672012-04-06 09:46:29 -07001383 flow_mod_msg.buffer_id = 0xffffffff
1384 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001385 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001386 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Rich Laneb73808c2013-03-11 15:22:23 -07001387 flow_mod_msg.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001388 logging.info("Sending flow_mod(del), xid=%d"
Rich Laneb73808c2013-03-11 15:22:23 -07001389 % (flow_mod_msg.xid)
Howard Pershc1199d52012-04-11 14:21:32 -07001390 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001391 self.controller.message_send(flow_mod_msg)
1392 return True
rootf6af1672012-04-06 09:46:29 -07001393
1394 def barrier(self):
Rich Lane28fa9272013-03-08 16:00:25 -08001395 barrier = ofp.message.barrier_request()
Dan Talaycoc689a792012-09-28 14:22:53 -07001396 (resp, pkt) = self.controller.transact(barrier, 30)
rootf6af1672012-04-06 09:46:29 -07001397 return (resp is not None)
1398
Howard Persh3340d452012-04-06 16:45:21 -07001399 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001400 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001401 logging.info("Expecting %d error messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001402 num_got = len(self.error_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001403 logging.info("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001404 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001405 logging.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001406 result = False
1407 if num_exp == 0:
1408 return result
1409 elif num_exp == 1:
Rich Lane9a003812012-10-04 17:17:59 -07001410 logging.info("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001411 % (type, code) \
1412 )
1413 f = False
Ed Swierk99a74de2012-08-22 06:40:54 -07001414 for e in self.error_msgs:
Rich Laneb73808c2013-03-11 15:22:23 -07001415 if e.err_type == type and e.code == code:
Rich Lane9a003812012-10-04 17:17:59 -07001416 logging.info("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001417 f = True
1418 if not f:
Rich Lane9a003812012-10-04 17:17:59 -07001419 logging.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001420 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001421 else:
Rich Lane9a003812012-10-04 17:17:59 -07001422 logging.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001423 result = False
1424 return result
1425
Howard Persh3340d452012-04-06 16:45:21 -07001426 def removed_verify(self, num_exp):
1427 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001428 logging.info("Expecting %d removed messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001429 num_got = len(self.removed_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001430 logging.info("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001431 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001432 logging.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001433 result = False
1434 if num_exp < 2:
1435 return result
Rich Lane9a003812012-10-04 17:17:59 -07001436 logging.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001437 return False
1438
Howard Persh5f3c83f2012-04-13 09:57:10 -07001439 # modf == True <=> Verify for flow modify, else for add/delete
1440 def flow_tbl_verify(self, modf = False):
rootf6af1672012-04-06 09:46:29 -07001441 result = True
1442
1443 # Verify flow count in switch
Rich Lane9a003812012-10-04 17:17:59 -07001444 logging.info("Reading table stats")
1445 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001446 if not self.tbl_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001447 logging.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001448 return False
1449 n = 0
Rich Lane5fd6faf2013-03-11 13:30:20 -07001450 for ts in self.tbl_stats.entries:
rootf6af1672012-04-06 09:46:29 -07001451 n = n + ts.active_count
Rich Lane9a003812012-10-04 17:17:59 -07001452 logging.info("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001453 % (n) \
1454 )
1455 if n != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001456 logging.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001457 result = False
1458
1459 # Read flows from switch
Rich Lane9a003812012-10-04 17:17:59 -07001460 logging.info("Retrieving flows from switch")
1461 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001462 if not self.flow_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001463 logging.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001464 return False
Rich Lane5fd6faf2013-03-11 13:30:20 -07001465 logging.info("Retrieved %d flows" % (len(self.flow_stats.entries)))
rootf6af1672012-04-06 09:46:29 -07001466
1467 # Verify flows returned by switch
1468
Rich Lane5fd6faf2013-03-11 13:30:20 -07001469 if len(self.flow_stats.entries) != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001470 logging.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001471 result = False
1472
Rich Lane9a003812012-10-04 17:17:59 -07001473 logging.info("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001474 for fc in self.flow_tbl.values():
1475 fc.matched = False
Rich Lane5fd6faf2013-03-11 13:30:20 -07001476 for fs in self.flow_stats.entries:
rootf6af1672012-04-06 09:46:29 -07001477 flow_in = Flow_Cfg()
1478 flow_in.from_flow_stat(fs)
Rich Lane9a003812012-10-04 17:17:59 -07001479 logging.info("Received flow:")
1480 logging.info(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001481 fc = self.flow_tbl.find(flow_in)
1482 if fc is None:
Rich Lane9a003812012-10-04 17:17:59 -07001483 logging.error("Received flow:")
1484 logging.error(str(flow_in))
1485 logging.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001486 result = False
1487 elif fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001488 logging.error("Received flow:")
1489 logging.error(str(flow_in))
1490 logging.error("re-matches defined flow:")
1491 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001492 result = False
1493 else:
Rich Lane9a003812012-10-04 17:17:59 -07001494 logging.info("matched")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001495 if modf:
1496 # Check for modify
1497
1498 if flow_in.cookie != fc.cookie:
Rich Lane9a003812012-10-04 17:17:59 -07001499 logging.warning("Defined flow:")
1500 logging.warning(str(fc))
1501 logging.warning("Received flow:")
1502 logging.warning(str(flow_in))
1503 logging.warning("cookies do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001504 if not flow_in.actions_equal(fc):
Rich Lane9a003812012-10-04 17:17:59 -07001505 logging.error("Defined flow:")
1506 logging.error(str(fc))
1507 logging.error("Received flow:")
1508 logging.error(str(flow_in))
1509 logging.error("actions do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001510 else:
1511 # Check for add/delete
1512
1513 if not flow_in == fc:
Rich Lane9a003812012-10-04 17:17:59 -07001514 logging.error("Defined flow:")
1515 logging.error(str(fc))
1516 logging.error("Received flow:")
1517 logging.error(str(flow_in))
1518 logging.error("non-key portions of flow do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001519 result = False
rootf6af1672012-04-06 09:46:29 -07001520 fc.matched = True
1521 for fc in self.flow_tbl.values():
1522 if not fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001523 logging.error("Defined flow:")
1524 logging.error(str(fc))
1525 logging.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001526 result = False
1527
1528 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001529
Howard Persh9cab4822012-09-11 17:08:40 -07001530 def settle(self):
1531 time.sleep(2)
1532
Howard Persh07d99e62012-04-09 15:26:57 -07001533# FLOW ADD 5
1534#
1535# OVERVIEW
1536# Add flows to switch, read back and verify flow configurations
1537#
1538# PURPOSE
1539# - Test acceptance of flow adds
1540# - Test ability of switch to process additions to flow table in random
1541# priority order
1542# - Test correctness of flow configuration responses
1543#
1544# PARAMETERS
1545#
1546# Name: num_flows
1547# Type: number
1548# Description:
1549# Number of flows to define; 0 => maximum number of flows, as determined
1550# from switch capabilities
1551# Default: 100
1552#
1553# PROCESS
1554# 1. Delete all flows from switch
1555# 2. Generate <num_flows> distinct flow configurations
1556# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1557# 4. Verify that no OFPT_ERROR responses were generated by switch
1558# 5. Retrieve flow stats from switch
1559# 6. Compare flow configurations returned by switch
1560# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1561# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001562
Rich Laneb90a1c42012-10-05 09:16:05 -07001563class Flow_Add_5(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001564 """
1565 Test FLOW_ADD_5 from draft top-half test plan
1566
1567 INPUTS
1568 num_flows - Number of flows to generate
1569 """
Howard Persh680b92a2012-03-31 13:34:35 -07001570
rootf6af1672012-04-06 09:46:29 -07001571 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001572 logging.info("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001573
Rich Lane2014f9b2012-10-05 15:29:40 -07001574 num_flows = test_param_get("num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001575
Howard Pershc7963582012-03-29 10:02:59 -07001576 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001577
Rich Lane9a003812012-10-04 17:17:59 -07001578 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001579 delete_all_flows(self.controller)
Howard Pershc7963582012-03-29 10:02:59 -07001580
rootf6af1672012-04-06 09:46:29 -07001581 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001582
rootf6af1672012-04-06 09:46:29 -07001583 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001584 self.assertTrue(sw.connect(self.controller), \
1585 "Failed to connect to switch" \
1586 )
Howard Pershc7963582012-03-29 10:02:59 -07001587
rootf6af1672012-04-06 09:46:29 -07001588 if num_flows == 0:
1589 # Number of flows requested was 0
1590 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001591
Rich Lane5fd6faf2013-03-11 13:30:20 -07001592 for ts in sw.tbl_stats.entries:
rootf6af1672012-04-06 09:46:29 -07001593 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001594
Rich Lane9a003812012-10-04 17:17:59 -07001595 logging.info("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001596
1597 # Dream up some flow information, i.e. space to chose from for
1598 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001599
rootf6af1672012-04-06 09:46:29 -07001600 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001601 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001602
rootf6af1672012-04-06 09:46:29 -07001603 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001604
rootf6af1672012-04-06 09:46:29 -07001605 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001606 ft.rand(required_wildcards(self), sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001607
rootf6af1672012-04-06 09:46:29 -07001608 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001609
Rich Lane9a003812012-10-04 17:17:59 -07001610 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001611 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001612 logging.info("Adding flow:")
1613 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001614 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001615
rootf6af1672012-04-06 09:46:29 -07001616 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001617
rootf6af1672012-04-06 09:46:29 -07001618 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001619
rootf6af1672012-04-06 09:46:29 -07001620 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001621
Howard Persh9cab4822012-09-11 17:08:40 -07001622 sw.settle() # Allow switch to settle and generate any notifications
1623
rootf6af1672012-04-06 09:46:29 -07001624 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001625
rootf6af1672012-04-06 09:46:29 -07001626 if not sw.errors_verify(0):
1627 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001628
rootf6af1672012-04-06 09:46:29 -07001629 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001630
rootf6af1672012-04-06 09:46:29 -07001631 sw.flow_tbl = ft
1632 if not sw.flow_tbl_verify():
1633 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001634
rootf6af1672012-04-06 09:46:29 -07001635 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001636 logging.info("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001637
Howard Pershc7963582012-03-29 10:02:59 -07001638
Howard Persh07d99e62012-04-09 15:26:57 -07001639# FLOW ADD 5_1
1640#
1641# OVERVIEW
1642# Verify handling of non-canonical flows
1643#
1644# PURPOSE
1645# - Test that switch detects and correctly responds to a non-canonical flow
1646# definition. A canonical flow is one that satisfies all match qualifier
1647# dependencies; a non-canonical flow is one that does not.
1648#
1649# PARAMETERS
1650# - None
1651#
1652# PROCESS
1653# 1. Delete all flows from switch
1654# 2. Generate 1 flow definition, which is different from its canonicalization
1655# 3. Send flow to switch
1656# 4. Retrieve flow from switch
1657# 5. Compare returned flow to canonical form of defined flow
1658# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1659
1660# Disabled.
1661# Should be DUT dependent.
Howard Persh07d99e62012-04-09 15:26:57 -07001662
Rich Lane0a4f6372013-01-02 14:40:22 -08001663@nonstandard
Rich Laneb90a1c42012-10-05 09:16:05 -07001664class Flow_Add_5_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001665 """
1666 Test FLOW_ADD_5.1 from draft top-half test plan
1667
1668 INPUTS
1669 None
1670 """
Rich Laned1d9c282012-10-04 22:07:10 -07001671
rootf6af1672012-04-06 09:46:29 -07001672 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001673 logging.info("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001674
Rich Lane2014f9b2012-10-05 15:29:40 -07001675 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001676
1677 # Clear all flows from switch
1678
Rich Lane9a003812012-10-04 17:17:59 -07001679 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001680 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001681
1682 # Get switch capabilites
1683
rootf6af1672012-04-06 09:46:29 -07001684 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001685 self.assertTrue(sw.connect(self.controller), \
1686 "Failed to connect to switch" \
1687 )
rootf6af1672012-04-06 09:46:29 -07001688
1689 # Dream up some flow information, i.e. space to chose from for
1690 # random flow parameter generation
1691
1692 fi = Flow_Info()
1693 fi.rand(10)
1694
1695 # Dream up a flow config that will be canonicalized by the switch
1696
1697 while True:
1698 fc = Flow_Cfg()
1699 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001700 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07001701 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001702 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001703 sw.valid_ports, \
1704 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001705 )
1706 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001707 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001708 break
1709
1710 ft = Flow_Tbl()
1711 ft.insert(fcc)
1712
1713 # Send it to the switch
1714
Rich Lane9a003812012-10-04 17:17:59 -07001715 logging.info("Sending flow add to switch:")
1716 logging.info(str(fc))
1717 logging.info("should be canonicalized as:")
1718 logging.info(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001719 fc.send_rem = False
1720 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1721
1722 # Do barrier, to make sure all flows are in
1723
1724 self.assertTrue(sw.barrier(), "Barrier failed")
1725
1726 result = True
1727
Howard Persh9cab4822012-09-11 17:08:40 -07001728 sw.settle() # Allow switch to settle and generate any notifications
1729
rootf6af1672012-04-06 09:46:29 -07001730 # Check for any error messages
1731
1732 if not sw.errors_verify(0):
1733 result = False
1734
1735 # Verify flow table
1736
1737 sw.flow_tbl = ft
1738 if not sw.flow_tbl_verify():
1739 result = False
1740
1741 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001742 logging.info("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001743
1744
Howard Persh07d99e62012-04-09 15:26:57 -07001745# FLOW ADD 6
1746#
1747# OVERVIEW
1748# Test flow table capacity
1749#
1750# PURPOSE
1751# - Test switch can accept as many flow definitions as it claims
1752# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1753# - Test that attempting to create flows beyond capacity does not corrupt
1754# flow table
1755#
1756# PARAMETERS
1757# None
1758#
1759# PROCESS
1760# 1. Delete all flows from switch
1761# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1762# to determine flow table size, N
1763# 3. Generate (N + 1) distinct flow configurations
1764# 4. Send N flow adds to switch, for flows generated in step 3 above
1765# 5. Verify flow table in switch
1766# 6. Send one more flow add to switch
1767# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1768# response was generated by switch, for last flow mod sent
1769# 7. Retrieve flow stats from switch
1770# 8. Verify flow table in switch
1771# 9. Test PASSED iff:
1772# - error message received, for correct flow
1773# - last flow definition sent to switch is not in flow table
1774# else test FAILED
1775
Howard Persh3340d452012-04-06 16:45:21 -07001776# Disabled because of bogus capacity reported by OVS.
1777# Should be DUT dependent.
Howard Persh3340d452012-04-06 16:45:21 -07001778
Rich Lane0a4f6372013-01-02 14:40:22 -08001779@nonstandard
Rich Laneb90a1c42012-10-05 09:16:05 -07001780class Flow_Add_6(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001781 """
1782 Test FLOW_ADD_6 from draft top-half test plan
1783
1784 INPUTS
1785 num_flows - Number of flows to generate
1786 """
Howard Pershc7963582012-03-29 10:02:59 -07001787
1788 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001789 logging.info("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001790
rootf6af1672012-04-06 09:46:29 -07001791 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001792
Rich Lane9a003812012-10-04 17:17:59 -07001793 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001794 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001795
1796 # Get switch capabilites
1797
rootf6af1672012-04-06 09:46:29 -07001798 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001799 self.assertTrue(sw.connect(self.controller), \
1800 "Failed to connect to switch" \
1801 )
rootf6af1672012-04-06 09:46:29 -07001802
root2843d2b2012-04-06 10:27:46 -07001803 num_flows = 0
Rich Lane5fd6faf2013-03-11 13:30:20 -07001804 for ts in sw.tbl_stats.entries:
rootf6af1672012-04-06 09:46:29 -07001805 num_flows = num_flows + ts.max_entries
1806
Rich Lane9a003812012-10-04 17:17:59 -07001807 logging.info("Switch capacity is %d flows" % (num_flows))
1808 logging.info("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001809
1810 # Dream up some flow information, i.e. space to chose from for
1811 # random flow parameter generation
1812
1813 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001814 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001815
1816 # Create a flow table, to switch's capacity
1817
1818 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001819 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07001820
1821 # Send flow table to switch
1822
Rich Lane9a003812012-10-04 17:17:59 -07001823 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001824 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001825 logging.info("Adding flow:")
1826 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001827 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1828
1829 # Do barrier, to make sure all flows are in
1830
1831 self.assertTrue(sw.barrier(), "Barrier failed")
1832
1833 result = True
1834
Howard Persh9cab4822012-09-11 17:08:40 -07001835 sw.settle() # Allow switch to settle and generate any notifications
1836
rootf6af1672012-04-06 09:46:29 -07001837 # Check for any error messages
1838
1839 if not sw.errors_verify(0):
1840 result = False
1841
1842 # Dream up one more flow
1843
Rich Lane9a003812012-10-04 17:17:59 -07001844 logging.info("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001845 while True:
1846 fc = Flow_Cfg()
1847 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001848 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07001849 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001850 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001851 sw.valid_ports, \
1852 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001853 )
1854 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001855 if not ft.find(fc):
1856 break
rootf6af1672012-04-06 09:46:29 -07001857
1858 # Send one-more flow
1859
1860 fc.send_rem = False
Rich Lane9a003812012-10-04 17:17:59 -07001861 logging.info("Sending flow add switch")
1862 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001863 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1864
1865 # Do barrier, to make sure all flows are in
1866
1867 self.assertTrue(sw.barrier(), "Barrier failed")
1868
Howard Persh9cab4822012-09-11 17:08:40 -07001869 sw.settle() # Allow switch to settle and generate any notifications
1870
rootf6af1672012-04-06 09:46:29 -07001871 # Check for expected error message
1872
1873 if not sw.errors_verify(1, \
1874 ofp.OFPET_FLOW_MOD_FAILED, \
1875 ofp.OFPFMFC_ALL_TABLES_FULL \
1876 ):
1877 result = False
1878
1879 # Verify flow table
1880
1881 sw.flow_tbl = ft
1882 if not sw.flow_tbl_verify():
1883 result = False
1884
1885 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001886 logging.info("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001887
1888
Howard Persh07d99e62012-04-09 15:26:57 -07001889# FLOW ADD 7
1890#
1891# OVERVIEW
1892# Test flow redefinition
1893#
1894# PURPOSE
1895# Verify that successive flow adds with same priority and match criteria
1896# overwrite in flow table
1897#
1898# PARAMETERS
1899# None
1900#
1901# PROCESS
1902# 1. Delete all flows from switch
1903# 2. Generate flow definition F1
1904# 3. Generate flow definition F2, with same key (priority and match) as F1,
1905# but with different actions
1906# 4. Send flow adds for F1 and F2 to switch
1907# 5. Verify flow definitions in switch
1908# 6. Test PASSED iff 1 flow returned by switch, matching configuration of F2;
1909# else test FAILED
1910
Rich Laneb90a1c42012-10-05 09:16:05 -07001911class Flow_Add_7(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001912 """
1913 Test FLOW_ADD_7 from draft top-half test plan
1914
1915 INPUTS
1916 None
1917 """
1918
1919 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001920 logging.info("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001921
1922 # Clear all flows from switch
1923
Rich Lane9a003812012-10-04 17:17:59 -07001924 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001925 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001926
1927 # Get switch capabilites
1928
rootf6af1672012-04-06 09:46:29 -07001929 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001930 self.assertTrue(sw.connect(self.controller), \
1931 "Failed to connect to switch" \
1932 )
rootf6af1672012-04-06 09:46:29 -07001933
1934 # Dream up some flow information, i.e. space to chose from for
1935 # random flow parameter generation
1936
1937 fi = Flow_Info()
1938 fi.rand(10)
1939
1940 # Dream up a flow config
1941
1942 fc = Flow_Cfg()
1943 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001944 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07001945 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001946 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001947 sw.valid_ports, \
1948 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001949 )
1950 fc = fc.canonical()
1951
1952 # Send it to the switch
1953
Rich Lane9a003812012-10-04 17:17:59 -07001954 logging.info("Sending flow add to switch:")
1955 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001956 ft = Flow_Tbl()
1957 fc.send_rem = False
1958 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1959 ft.insert(fc)
1960
1961 # Dream up some different actions, with the same flow key
1962
1963 fc2 = copy.deepcopy(fc)
1964 while True:
1965 fc2.rand_mod(fi, \
1966 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001967 sw.valid_ports, \
1968 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001969 )
1970 if fc2 != fc:
1971 break
1972
1973 # Send that to the switch
1974
Rich Lane9a003812012-10-04 17:17:59 -07001975 logging.info("Sending flow add to switch:")
1976 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07001977 fc2.send_rem = False
1978 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
1979 ft.insert(fc2)
1980
1981 # Do barrier, to make sure all flows are in
1982
1983 self.assertTrue(sw.barrier(), "Barrier failed")
1984
1985 result = True
1986
Howard Persh9cab4822012-09-11 17:08:40 -07001987 sw.settle() # Allow switch to settle and generate any notifications
1988
rootf6af1672012-04-06 09:46:29 -07001989 # Check for any error messages
1990
1991 if not sw.errors_verify(0):
1992 result = False
1993
1994 # Verify flow table
1995
1996 sw.flow_tbl = ft
1997 if not sw.flow_tbl_verify():
1998 result = False
1999
2000 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002001 logging.info("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002002
2003
Howard Persh07d99e62012-04-09 15:26:57 -07002004# FLOW ADD 8
2005#
2006# OVERVIEW
2007# Add overlapping flows to switch, verify that overlapping flows are rejected
2008#
2009# PURPOSE
2010# - Test detection of overlapping flows by switch
2011# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
2012# - Test rejection of overlapping flows
2013# - Test defining overlapping flows does not corrupt flow table
2014#
2015# PARAMETERS
2016# None
2017#
2018# PROCESS
2019# 1. Delete all flows from switch
2020# 2. Generate flow definition F1
2021# 3. Generate flow definition F2, with key overlapping F1
2022# 4. Send flow add to switch, for F1
2023# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
2024# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
2025# was generated by switch
2026# 7. Verifiy flows configured in swtich
2027# 8. Test PASSED iff:
2028# - error message received, for overlapping flow
2029# - overlapping flow is not in flow table
2030# else test FAILED
2031
Rich Laneb90a1c42012-10-05 09:16:05 -07002032class Flow_Add_8(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002033 """
2034 Test FLOW_ADD_8 from draft top-half test plan
2035
2036 INPUTS
2037 None
2038 """
2039
2040 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002041 logging.info("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002042
2043 # Clear all flows from switch
2044
Rich Lane9a003812012-10-04 17:17:59 -07002045 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002046 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002047
2048 # Get switch capabilites
2049
rootf6af1672012-04-06 09:46:29 -07002050 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002051 self.assertTrue(sw.connect(self.controller), \
2052 "Failed to connect to switch" \
2053 )
rootf6af1672012-04-06 09:46:29 -07002054
2055 # Dream up some flow information, i.e. space to chose from for
2056 # random flow parameter generation
2057
2058 fi = Flow_Info()
2059 fi.rand(10)
2060
2061 # Dream up a flow config, with at least 1 qualifier specified
2062
2063 fc = Flow_Cfg()
2064 while True:
2065 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002066 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002067 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002068 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002069 sw.valid_ports, \
2070 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002071 )
2072 fc = fc.canonical()
2073 if fc.match.wildcards != ofp.OFPFW_ALL:
2074 break
2075
2076 # Send it to the switch
2077
Rich Lane9a003812012-10-04 17:17:59 -07002078 logging.info("Sending flow add to switch:")
2079 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002080 ft = Flow_Tbl()
2081 fc.send_rem = False
2082 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2083 ft.insert(fc)
2084
2085 # Wildcard out one qualifier that was specified, to create an
2086 # overlapping flow
2087
2088 fc2 = copy.deepcopy(fc)
2089 for wi in shuffle(range(len(all_wildcards_list))):
2090 w = all_wildcards_list[wi]
2091 if (fc2.match.wildcards & w) == 0:
2092 break
2093 if w == ofp.OFPFW_NW_SRC_MASK:
2094 w = ofp.OFPFW_NW_SRC_ALL
2095 wn = "OFPFW_NW_SRC"
2096 elif w == ofp.OFPFW_NW_DST_MASK:
2097 w = ofp.OFPFW_NW_DST_ALL
2098 wn = "OFPFW_NW_DST"
2099 else:
2100 wn = all_wildcard_names[w]
Rich Lane9a003812012-10-04 17:17:59 -07002101 logging.info("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07002102 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07002103 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07002104
2105 # Send that to the switch, with overlap checking
2106
Rich Lane9a003812012-10-04 17:17:59 -07002107 logging.info("Sending flow add to switch:")
2108 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002109 fc2.send_rem = False
2110 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
2111
2112 # Do barrier, to make sure all flows are in
2113 self.assertTrue(sw.barrier(), "Barrier failed")
2114
2115 result = True
2116
Howard Persh9cab4822012-09-11 17:08:40 -07002117 sw.settle() # Allow switch to settle and generate any notifications
2118
rootf6af1672012-04-06 09:46:29 -07002119 # Check for expected error message
2120
2121 if not sw.errors_verify(1, \
2122 ofp.OFPET_FLOW_MOD_FAILED, \
2123 ofp.OFPFMFC_OVERLAP \
2124 ):
2125 result = False
2126
2127 # Verify flow table
2128
2129 sw.flow_tbl = ft
2130 if not sw.flow_tbl_verify():
2131 result = False
2132
2133 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002134 logging.info("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002135
2136
Howard Persh07d99e62012-04-09 15:26:57 -07002137# FLOW MODIFY 1
2138#
2139# OVERVIEW
2140# Strict modify of single existing flow
2141#
2142# PURPOSE
2143# - Verify that strict flow modify operates only on specified flow
2144# - Verify that flow is correctly modified
2145#
2146# PARAMETERS
2147# None
2148#
2149# PROCESS
2150# 1. Delete all flows from switch
2151# 2. Generate 1 flow F
2152# 3. Send flow add to switch, for flow F
2153# 4. Generate new action list for flow F, yielding F'
2154# 5. Send strict flow modify to switch, for flow F'
2155# 6. Verify flow table in switch
2156# 7. Test PASSED iff flow returned by switch is F'; else FAILED
2157
Rich Laneb90a1c42012-10-05 09:16:05 -07002158class Flow_Mod_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002159 """
2160 Test FLOW_MOD_1 from draft top-half test plan
2161
2162 INPUTS
2163 None
2164 """
2165
2166 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002167 logging.info("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002168
2169 # Clear all flows from switch
2170
Rich Lane9a003812012-10-04 17:17:59 -07002171 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002172 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002173
2174 # Get switch capabilites
2175
rootf6af1672012-04-06 09:46:29 -07002176 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002177 self.assertTrue(sw.connect(self.controller), \
2178 "Failed to connect to switch" \
2179 )
rootf6af1672012-04-06 09:46:29 -07002180
2181 # Dream up some flow information, i.e. space to chose from for
2182 # random flow parameter generation
2183
2184 fi = Flow_Info()
2185 fi.rand(10)
2186
2187 # Dream up a flow config
2188
2189 fc = Flow_Cfg()
2190 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002191 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002192 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002193 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002194 sw.valid_ports, \
2195 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002196 )
2197 fc = fc.canonical()
2198
2199 # Send it to the switch
2200
Rich Lane9a003812012-10-04 17:17:59 -07002201 logging.info("Sending flow add to switch:")
2202 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002203 ft = Flow_Tbl()
2204 fc.send_rem = False
2205 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2206 ft.insert(fc)
2207
2208 # Dream up some different actions, with the same flow key
2209
2210 fc2 = copy.deepcopy(fc)
2211 while True:
2212 fc2.rand_mod(fi, \
2213 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002214 sw.valid_ports, \
2215 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002216 )
2217 if fc2 != fc:
2218 break
2219
2220 # Send that to the switch
2221
Rich Lane9a003812012-10-04 17:17:59 -07002222 logging.info("Sending strict flow mod to switch:")
2223 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002224 fc2.send_rem = False
2225 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2226 ft.insert(fc2)
2227
2228 # Do barrier, to make sure all flows are in
2229
2230 self.assertTrue(sw.barrier(), "Barrier failed")
2231
2232 result = True
2233
Howard Persh9cab4822012-09-11 17:08:40 -07002234 sw.settle() # Allow switch to settle and generate any notifications
2235
rootf6af1672012-04-06 09:46:29 -07002236 # Check for any error messages
2237
2238 if not sw.errors_verify(0):
2239 result = False
2240
2241 # Verify flow table
2242
2243 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002244 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002245 result = False
2246
2247 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002248 logging.info("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002249
Howard Persh07d99e62012-04-09 15:26:57 -07002250
2251# FLOW MODIFY 2
2252#
2253# OVERVIEW
2254# Loose modify of mutiple flows
2255#
2256# PURPOSE
2257# - Verify that loose flow modify operates only on matching flows
2258# - Verify that matching flows are correctly modified
2259#
2260# PARAMETERS
2261# Name: num_flows
2262# Type: number
2263# Description:
2264# Number of flows to define
2265# Default: 100
2266#
2267# PROCESS
2268# 1. Delete all flows from switch
2269# 2. Generate <num_flows> distinct flow configurations
2270# 3. Send <num_flows> flow adds to switch
2271# 4. Pick 1 defined flow F at random
2272# 5. Create overlapping loose flow mod match criteria by repeatedly
2273# wildcarding out qualifiers in match of F => F',
2274# and create new actions list A' for F'
2275# 6. Send loose flow modify for F' to switch
2276# 7. Verify flow table in swtich
2277# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2278# are returned in step 7 above, each with correct (original or modified)
2279# action list;
2280# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002281
Rich Laneb90a1c42012-10-05 09:16:05 -07002282class Flow_Mod_2(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002283 """
2284 Test FLOW_MOD_2 from draft top-half test plan
2285
2286 INPUTS
2287 None
2288 """
2289
2290 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002291 logging.info("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002292
Rich Lane2014f9b2012-10-05 15:29:40 -07002293 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002294
2295 # Clear all flows from switch
2296
Rich Lane9a003812012-10-04 17:17:59 -07002297 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002298 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002299
2300 # Get switch capabilites
2301
rootf6af1672012-04-06 09:46:29 -07002302 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002303 self.assertTrue(sw.connect(self.controller), \
2304 "Failed to connect to switch" \
2305 )
rootf6af1672012-04-06 09:46:29 -07002306
2307 # Dream up some flow information, i.e. space to chose from for
2308 # random flow parameter generation
2309
2310 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002311 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002312 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002313
2314 # Dream up some flows
2315
2316 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002317 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002318
2319 # Send flow table to switch
2320
Rich Lane9a003812012-10-04 17:17:59 -07002321 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002322 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002323 logging.info("Adding flow:")
2324 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002325 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2326
2327 # Do barrier, to make sure all flows are in
2328
2329 self.assertTrue(sw.barrier(), "Barrier failed")
2330
2331 result = True
2332
Howard Persh9cab4822012-09-11 17:08:40 -07002333 sw.settle() # Allow switch to settle and generate any notifications
2334
rootf6af1672012-04-06 09:46:29 -07002335 # Check for any error messages
2336
2337 if not sw.errors_verify(0):
2338 result = False
2339
2340 # Verify flow table
2341
2342 sw.flow_tbl = ft
2343 if not sw.flow_tbl_verify():
2344 result = False
2345
2346 # Pick a random flow as a basis
Howard Persh5f3c83f2012-04-13 09:57:10 -07002347
2348 mfc = copy.deepcopy((ft.values())[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002349 mfc.rand_mod(fi, \
2350 sw.sw_features.actions, \
2351 sw.valid_ports, \
2352 sw.valid_queues \
2353 )
rootf6af1672012-04-06 09:46:29 -07002354
2355 # Repeatedly wildcard qualifiers
2356
2357 for wi in shuffle(range(len(all_wildcards_list))):
2358 w = all_wildcards_list[wi]
2359 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2360 n = wildcard_get(mfc.match.wildcards, w)
2361 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002362 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2363 w, \
2364 random.randint(n + 1, 32) \
2365 )
rootf6af1672012-04-06 09:46:29 -07002366 else:
2367 continue
2368 else:
2369 if wildcard_get(mfc.match.wildcards, w) == 0:
2370 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2371 else:
2372 continue
2373 mfc = mfc.canonical()
2374
2375 # Count the number of flows that would be modified
2376
2377 n = 0
2378 for fc in ft.values():
2379 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2380 n = n + 1
2381
2382 # If more than 1, we found our loose delete flow spec
2383 if n > 1:
2384 break
2385
Rich Lane9a003812012-10-04 17:17:59 -07002386 logging.info("Modifying %d flows" % (n))
2387 logging.info("Sending flow mod to switch:")
2388 logging.info(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002389 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2390
2391 # Do barrier, to make sure all flows are in
2392 self.assertTrue(sw.barrier(), "Barrier failed")
2393
Howard Persh9cab4822012-09-11 17:08:40 -07002394 sw.settle() # Allow switch to settle and generate any notifications
2395
rootf6af1672012-04-06 09:46:29 -07002396 # Check for error message
2397
2398 if not sw.errors_verify(0):
2399 result = False
2400
2401 # Apply flow mod to local flow table
2402
2403 for fc in ft.values():
2404 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002405 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002406
2407 # Verify flow table
2408
2409 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002410 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002411 result = False
2412
2413 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002414 logging.info("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002415
2416
Howard Persh07d99e62012-04-09 15:26:57 -07002417# FLOW MODIFY 3
2418
2419# OVERVIEW
2420# Strict modify of non-existent flow
2421#
2422# PURPOSE
2423# Verify that strict modify of a non-existent flow is equivalent to a flow add
2424#
2425# PARAMETERS
2426# None
2427#
2428# PROCESS
2429# 1. Delete all flows from switch
2430# 2. Send single flow mod, as strict modify, to switch
2431# 3. Verify flow table in switch
2432# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2433
Rich Laneb90a1c42012-10-05 09:16:05 -07002434class Flow_Mod_3(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002435 """
2436 Test FLOW_MOD_3 from draft top-half test plan
2437
2438 INPUTS
2439 None
2440 """
2441
2442 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002443 logging.info("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002444
2445 # Clear all flows from switch
2446
Rich Lane9a003812012-10-04 17:17:59 -07002447 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002448 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002449
2450 # Get switch capabilites
2451
rootf6af1672012-04-06 09:46:29 -07002452 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002453 self.assertTrue(sw.connect(self.controller), \
2454 "Failed to connect to switch" \
2455 )
rootf6af1672012-04-06 09:46:29 -07002456
2457 # Dream up some flow information, i.e. space to chose from for
2458 # random flow parameter generation
2459
2460 fi = Flow_Info()
2461 fi.rand(10)
2462
2463 # Dream up a flow config
2464
2465 fc = Flow_Cfg()
2466 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002467 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002468 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002469 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002470 sw.valid_ports, \
2471 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002472 )
2473 fc = fc.canonical()
2474
2475 # Send it to the switch
2476
Rich Lane9a003812012-10-04 17:17:59 -07002477 logging.info("Sending flow mod to switch:")
2478 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002479 ft = Flow_Tbl()
2480 fc.send_rem = False
2481 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2482 ft.insert(fc)
2483
2484 # Do barrier, to make sure all flows are in
2485
2486 self.assertTrue(sw.barrier(), "Barrier failed")
2487
2488 result = True
2489
Howard Persh9cab4822012-09-11 17:08:40 -07002490 sw.settle() # Allow switch to settle and generate any notifications
2491
rootf6af1672012-04-06 09:46:29 -07002492 # Check for any error messages
2493
2494 if not sw.errors_verify(0):
2495 result = False
2496
2497 # Verify flow table
2498
2499 sw.flow_tbl = ft
2500 if not sw.flow_tbl_verify():
2501 result = False
2502
2503 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002504 logging.info("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002505
2506
Howard Persh8d21c1f2012-04-20 15:57:29 -07002507# FLOW MODIFY 3_1
2508
2509# OVERVIEW
2510# No-op modify
2511#
2512# PURPOSE
2513# Verify that modify of a flow with new actions same as old ones operates correctly
2514#
2515# PARAMETERS
2516# None
2517#
2518# PROCESS
2519# 1. Delete all flows from switch
2520# 2. Send single flow mod, as strict modify, to switch
2521# 3. Verify flow table in switch
2522# 4. Send same flow mod, as strict modify, to switch
2523# 5. Verify flow table in switch
2524# 6. Test PASSED iff flow defined in step 2 and 4 above verified; else FAILED
2525
Rich Laneb90a1c42012-10-05 09:16:05 -07002526class Flow_Mod_3_1(base_tests.SimpleProtocol):
Howard Persh8d21c1f2012-04-20 15:57:29 -07002527 """
2528 Test FLOW_MOD_3_1 from draft top-half test plan
2529
2530 INPUTS
2531 None
2532 """
2533
2534 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002535 logging.info("Flow_Mod_3_1 TEST BEGIN")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002536
2537 # Clear all flows from switch
2538
Rich Lane9a003812012-10-04 17:17:59 -07002539 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002540 delete_all_flows(self.controller)
Howard Persh8d21c1f2012-04-20 15:57:29 -07002541
2542 # Get switch capabilites
2543
2544 sw = Switch()
2545 self.assertTrue(sw.connect(self.controller), \
2546 "Failed to connect to switch" \
2547 )
2548
2549 # Dream up some flow information, i.e. space to chose from for
2550 # random flow parameter generation
2551
2552 fi = Flow_Info()
2553 fi.rand(10)
2554
2555 # Dream up a flow config
2556
2557 fc = Flow_Cfg()
2558 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002559 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002560 sw.tbl_stats.entries[0].wildcards, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002561 sw.sw_features.actions, \
2562 sw.valid_ports, \
2563 sw.valid_queues \
2564 )
2565 fc = fc.canonical()
2566
2567 # Send it to the switch
2568
Rich Lane9a003812012-10-04 17:17:59 -07002569 logging.info("Sending flow mod to switch:")
2570 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002571 ft = Flow_Tbl()
2572 fc.send_rem = False
2573 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2574 ft.insert(fc)
2575
2576 # Do barrier, to make sure all flows are in
2577
2578 self.assertTrue(sw.barrier(), "Barrier failed")
2579
2580 result = True
2581
Howard Persh9cab4822012-09-11 17:08:40 -07002582 sw.settle() # Allow switch to settle and generate any notifications
2583
Howard Persh8d21c1f2012-04-20 15:57:29 -07002584 # Check for any error messages
2585
2586 if not sw.errors_verify(0):
2587 result = False
2588
2589 # Verify flow table
2590
2591 sw.flow_tbl = ft
2592 if not sw.flow_tbl_verify():
2593 result = False
2594
2595 # Send same flow to the switch again
2596
Rich Lane9a003812012-10-04 17:17:59 -07002597 logging.info("Sending flow mod to switch:")
2598 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002599 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2600
2601 # Do barrier, to make sure all flows are in
2602
2603 self.assertTrue(sw.barrier(), "Barrier failed")
2604
Howard Persh9cab4822012-09-11 17:08:40 -07002605 sw.settle() # Allow switch to settle and generate any notifications
2606
Howard Persh8d21c1f2012-04-20 15:57:29 -07002607 # Check for any error messages
2608
2609 if not sw.errors_verify(0):
2610 result = False
2611
2612 # Verify flow table
2613
2614 if not sw.flow_tbl_verify():
2615 result = False
2616
2617 self.assertTrue(result, "Flow_Mod_3_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002618 logging.info("Flow_Mod_3_1 TEST PASSED")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002619
2620
Howard Persh07d99e62012-04-09 15:26:57 -07002621# FLOW DELETE 1
2622#
2623# OVERVIEW
2624# Strict delete of single flow
2625#
2626# PURPOSE
2627# Verify correct operation of strict delete of single defined flow
2628#
2629# PARAMETERS
2630# None
2631#
2632# PROCESS
2633# 1. Delete all flows from switch
2634# 2. Send flow F to switch
2635# 3. Send strict flow delete for F to switch
2636# 4. Verify flow table in swtich
2637# 6. Test PASSED iff all flows sent to switch in step 2 above,
2638# less flow removed in step 3 above, are returned in step 4 above;
2639# else test FAILED
2640
Rich Laneb90a1c42012-10-05 09:16:05 -07002641class Flow_Del_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002642 """
2643 Test FLOW_DEL_1 from draft top-half test plan
2644
2645 INPUTS
2646 None
2647 """
2648
2649 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002650 logging.info("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002651
2652 # Clear all flows from switch
2653
Rich Lane9a003812012-10-04 17:17:59 -07002654 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002655 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002656
2657 # Get switch capabilites
2658
rootf6af1672012-04-06 09:46:29 -07002659 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002660 self.assertTrue(sw.connect(self.controller), \
2661 "Failed to connect to switch" \
2662 )
rootf6af1672012-04-06 09:46:29 -07002663
2664 # Dream up some flow information, i.e. space to chose from for
2665 # random flow parameter generation
2666
2667 fi = Flow_Info()
2668 fi.rand(10)
2669
2670 # Dream up a flow config
2671
2672 fc = Flow_Cfg()
2673 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002674 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002675 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002676 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002677 sw.valid_ports, \
2678 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002679 )
2680 fc = fc.canonical()
2681
2682 # Send it to the switch
2683
Rich Lane9a003812012-10-04 17:17:59 -07002684 logging.info("Sending flow add to switch:")
2685 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002686 ft = Flow_Tbl()
2687 fc.send_rem = False
2688 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2689 ft.insert(fc)
2690
2691 # Dream up some different actions, with the same flow key
2692
2693 fc2 = copy.deepcopy(fc)
2694 while True:
2695 fc2.rand_mod(fi, \
2696 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002697 sw.valid_ports, \
2698 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002699 )
2700 if fc2 != fc:
2701 break
2702
2703 # Delete strictly
2704
Rich Lane9a003812012-10-04 17:17:59 -07002705 logging.info("Sending strict flow del to switch:")
2706 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002707 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2708 ft.delete(fc)
2709
2710 # Do barrier, to make sure all flows are in
2711
2712 self.assertTrue(sw.barrier(), "Barrier failed")
2713
2714 result = True
2715
Howard Persh9cab4822012-09-11 17:08:40 -07002716 sw.settle() # Allow switch to settle and generate any notifications
2717
rootf6af1672012-04-06 09:46:29 -07002718 # Check for any error messages
2719
2720 if not sw.errors_verify(0):
2721 result = False
2722
2723 # Verify flow table
2724
2725 sw.flow_tbl = ft
2726 if not sw.flow_tbl_verify():
2727 result = False
2728
2729 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002730 logging.info("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002731
2732
Howard Persh07d99e62012-04-09 15:26:57 -07002733# FLOW DELETE 2
2734#
2735# OVERVIEW
2736# Loose delete of multiple flows
2737#
2738# PURPOSE
2739# - Verify correct operation of loose delete of multiple flows
2740#
2741# PARAMETERS
2742# Name: num_flows
2743# Type: number
2744# Description:
2745# Number of flows to define
2746# Default: 100
2747#
2748# PROCESS
2749# 1. Delete all flows from switch
2750# 2. Generate <num_flows> distinct flow configurations
2751# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2752# 4. Pick 1 defined flow F at random
2753# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2754# F' will match more than 1 existing flow key
2755# 6. Send loose flow delete for F' to switch
2756# 7. Verify flow table in switch
2757# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2758# removed in step 6 above (i.e. those that match F'), are returned
2759# in step 7 above;
2760# else test FAILED
2761
Rich Laneb90a1c42012-10-05 09:16:05 -07002762class Flow_Del_2(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002763 """
2764 Test FLOW_DEL_2 from draft top-half test plan
2765
2766 INPUTS
2767 None
2768 """
2769
2770 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002771 logging.info("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002772
Rich Lane2014f9b2012-10-05 15:29:40 -07002773 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002774
2775 # Clear all flows from switch
2776
Rich Lane9a003812012-10-04 17:17:59 -07002777 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002778 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002779
2780 # Get switch capabilites
2781
rootf6af1672012-04-06 09:46:29 -07002782 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002783 self.assertTrue(sw.connect(self.controller), \
2784 "Failed to connect to switch" \
2785 )
rootf6af1672012-04-06 09:46:29 -07002786
2787 # Dream up some flow information, i.e. space to chose from for
2788 # random flow parameter generation
2789
2790 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002791 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002792 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002793
2794 # Dream up some flows
2795
2796 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002797 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002798
2799 # Send flow table to switch
2800
Rich Lane9a003812012-10-04 17:17:59 -07002801 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002802 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002803 logging.info("Adding flow:")
2804 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002805 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2806
2807 # Do barrier, to make sure all flows are in
2808
2809 self.assertTrue(sw.barrier(), "Barrier failed")
2810
2811 result = True
2812
Howard Persh9cab4822012-09-11 17:08:40 -07002813 sw.settle() # Allow switch to settle and generate any notifications
2814
rootf6af1672012-04-06 09:46:29 -07002815 # Check for any error messages
2816
2817 if not sw.errors_verify(0):
2818 result = False
2819
2820 # Verify flow table
2821
2822 sw.flow_tbl = ft
2823 if not sw.flow_tbl_verify():
2824 result = False
2825
2826 # Pick a random flow as a basis
2827
2828 dfc = copy.deepcopy(ft.values()[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002829 dfc.rand_mod(fi, \
2830 sw.sw_features.actions, \
2831 sw.valid_ports, \
2832 sw.valid_queues \
2833 )
rootf6af1672012-04-06 09:46:29 -07002834
2835 # Repeatedly wildcard qualifiers
2836
2837 for wi in shuffle(range(len(all_wildcards_list))):
2838 w = all_wildcards_list[wi]
2839 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2840 n = wildcard_get(dfc.match.wildcards, w)
2841 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002842 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2843 w, \
2844 random.randint(n + 1, 32) \
2845 )
rootf6af1672012-04-06 09:46:29 -07002846 else:
2847 continue
2848 else:
2849 if wildcard_get(dfc.match.wildcards, w) == 0:
2850 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2851 else:
2852 continue
2853 dfc = dfc.canonical()
2854
2855 # Count the number of flows that would be deleted
2856
2857 n = 0
2858 for fc in ft.values():
2859 if dfc.overlaps(fc, True):
2860 n = n + 1
2861
2862 # If more than 1, we found our loose delete flow spec
2863 if n > 1:
2864 break
2865
Rich Lane9a003812012-10-04 17:17:59 -07002866 logging.info("Deleting %d flows" % (n))
2867 logging.info("Sending flow del to switch:")
2868 logging.info(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002869 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2870
2871 # Do barrier, to make sure all flows are in
2872 self.assertTrue(sw.barrier(), "Barrier failed")
2873
Howard Persh9cab4822012-09-11 17:08:40 -07002874 sw.settle() # Allow switch to settle and generate any notifications
2875
rootf6af1672012-04-06 09:46:29 -07002876 # Check for error message
2877
2878 if not sw.errors_verify(0):
2879 result = False
2880
2881 # Apply flow mod to local flow table
2882
2883 for fc in ft.values():
2884 if dfc.overlaps(fc, True):
2885 ft.delete(fc)
2886
2887 # Verify flow table
2888
2889 sw.flow_tbl = ft
2890 if not sw.flow_tbl_verify():
2891 result = False
2892
2893 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002894 logging.info("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002895
2896
Howard Persh07d99e62012-04-09 15:26:57 -07002897# FLOW DELETE 4
2898#
2899# OVERVIEW
2900# Flow removed messages
2901#
2902# PURPOSE
2903# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2904# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2905#
2906# PARAMETERS
2907# None
2908#
2909# PROCESS
2910# 1. Delete all flows from switch
2911# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2912# 3. Send strict flow delete of flow to switch
2913# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2914# 5. Verify flow table in switch
2915# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2916# removed in step 3 above, are returned in step 5 above, and that
2917# asynch message was received; else test FAILED
2918
2919
Rich Laneb90a1c42012-10-05 09:16:05 -07002920class Flow_Del_4(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002921 """
2922 Test FLOW_DEL_4 from draft top-half test plan
2923
2924 INPUTS
2925 None
2926 """
2927
2928 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002929 logging.info("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002930
2931 # Clear all flows from switch
2932
Rich Lane9a003812012-10-04 17:17:59 -07002933 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002934 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002935
2936 # Get switch capabilites
2937
rootf6af1672012-04-06 09:46:29 -07002938 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002939 self.assertTrue(sw.connect(self.controller), \
2940 "Failed to connect to switch" \
2941 )
rootf6af1672012-04-06 09:46:29 -07002942
2943 # Dream up some flow information, i.e. space to chose from for
2944 # random flow parameter generation
2945
2946 fi = Flow_Info()
2947 fi.rand(10)
2948
2949 # Dream up a flow config
2950
2951 fc = Flow_Cfg()
2952 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002953 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002954 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002955 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002956 sw.valid_ports, \
2957 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002958 )
2959 fc = fc.canonical()
2960
2961 # Send it to the switch. with "notify on removed"
2962
Rich Lane9a003812012-10-04 17:17:59 -07002963 logging.info("Sending flow add to switch:")
2964 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002965 ft = Flow_Tbl()
2966 fc.send_rem = True
2967 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2968 ft.insert(fc)
2969
2970 # Dream up some different actions, with the same flow key
2971
2972 fc2 = copy.deepcopy(fc)
2973 while True:
2974 fc2.rand_mod(fi, \
2975 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002976 sw.valid_ports, \
2977 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002978 )
2979 if fc2 != fc:
2980 break
2981
2982 # Delete strictly
2983
Rich Lane9a003812012-10-04 17:17:59 -07002984 logging.info("Sending strict flow del to switch:")
2985 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002986 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2987 ft.delete(fc)
2988
2989 # Do barrier, to make sure all flows are in
2990
2991 self.assertTrue(sw.barrier(), "Barrier failed")
2992
2993 result = True
2994
Howard Persh9cab4822012-09-11 17:08:40 -07002995 sw.settle() # Allow switch to settle and generate any notifications
2996
rootf6af1672012-04-06 09:46:29 -07002997 # Check for expected "removed" message
2998
Howard Persh3340d452012-04-06 16:45:21 -07002999 if not sw.errors_verify(0):
3000 result = False
3001
3002 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07003003 result = False
3004
3005 # Verify flow table
3006
3007 sw.flow_tbl = ft
3008 if not sw.flow_tbl_verify():
3009 result = False
3010
3011 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07003012 logging.info("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07003013