blob: e7f1718106d1ef23d17286b5a0c91ddbb065ee94 [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:
Rich Lane1879dc72013-03-11 22:08:51 -0700307 if ((1 << a) & bm) != 0 and a in ofp.ofp_action_type_map:
Howard Persh8d21c1f2012-04-20 15:57:29 -0700308 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 Lane0237baf2013-03-11 22:34:59 -0700339 self.match = 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:
Rich Lane1879dc72013-03-11 22:08:51 -0700476 result = result + (", action=%s" % ofp.ofp_action_type_map.get(a.type, "unknown"))
Howard Persh680b92a2012-03-31 13:34:35 -0700477 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()
Rich Lane0237baf2013-03-11 22:34:59 -07001322 query_match = ofp.match()
Howard Persh680b92a2012-03-31 13:34:35 -07001323 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 Laneba3f0e22013-03-11 16:43:57 -07001351 flow_mod_msg = ofp.message.flow_add()
Howard Persh680b92a2012-03-31 13:34:35 -07001352 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001353 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001354 if overlapf:
1355 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001356 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001357 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Rich Laneb73808c2013-03-11 15:22:23 -07001358 flow_mod_msg.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001359 logging.info("Sending flow_mod(add), xid=%d"
Rich Laneb73808c2013-03-11 15:22:23 -07001360 % (flow_mod_msg.xid)
Howard Pershc1199d52012-04-11 14:21:32 -07001361 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001362 self.controller.message_send(flow_mod_msg)
1363 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001364
rootf6af1672012-04-06 09:46:29 -07001365 def flow_mod(self, flow_cfg, strictf):
Rich Laneba3f0e22013-03-11 16:43:57 -07001366 if strictf:
1367 flow_mod_msg = ofp.message.flow_modify_strict()
1368 else:
1369 flow_mod_msg = ofp.message.flow_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 Laneba3f0e22013-03-11 16:43:57 -07001380 if strictf:
1381 flow_mod_msg = ofp.message.flow_delete_strict()
1382 else:
1383 flow_mod_msg = ofp.message.flow_delete()
rootf6af1672012-04-06 09:46:29 -07001384 flow_mod_msg.buffer_id = 0xffffffff
1385 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001386 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001387 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Rich Laneb73808c2013-03-11 15:22:23 -07001388 flow_mod_msg.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001389 logging.info("Sending flow_mod(del), xid=%d"
Rich Laneb73808c2013-03-11 15:22:23 -07001390 % (flow_mod_msg.xid)
Howard Pershc1199d52012-04-11 14:21:32 -07001391 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001392 self.controller.message_send(flow_mod_msg)
1393 return True
rootf6af1672012-04-06 09:46:29 -07001394
1395 def barrier(self):
Rich Lane28fa9272013-03-08 16:00:25 -08001396 barrier = ofp.message.barrier_request()
Dan Talaycoc689a792012-09-28 14:22:53 -07001397 (resp, pkt) = self.controller.transact(barrier, 30)
rootf6af1672012-04-06 09:46:29 -07001398 return (resp is not None)
1399
Howard Persh3340d452012-04-06 16:45:21 -07001400 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001401 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001402 logging.info("Expecting %d error messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001403 num_got = len(self.error_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001404 logging.info("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001405 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001406 logging.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001407 result = False
1408 if num_exp == 0:
1409 return result
1410 elif num_exp == 1:
Rich Lane9a003812012-10-04 17:17:59 -07001411 logging.info("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001412 % (type, code) \
1413 )
1414 f = False
Ed Swierk99a74de2012-08-22 06:40:54 -07001415 for e in self.error_msgs:
Rich Laneb73808c2013-03-11 15:22:23 -07001416 if e.err_type == type and e.code == code:
Rich Lane9a003812012-10-04 17:17:59 -07001417 logging.info("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001418 f = True
1419 if not f:
Rich Lane9a003812012-10-04 17:17:59 -07001420 logging.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001421 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001422 else:
Rich Lane9a003812012-10-04 17:17:59 -07001423 logging.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001424 result = False
1425 return result
1426
Howard Persh3340d452012-04-06 16:45:21 -07001427 def removed_verify(self, num_exp):
1428 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001429 logging.info("Expecting %d removed messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001430 num_got = len(self.removed_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001431 logging.info("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001432 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001433 logging.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001434 result = False
1435 if num_exp < 2:
1436 return result
Rich Lane9a003812012-10-04 17:17:59 -07001437 logging.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001438 return False
1439
Howard Persh5f3c83f2012-04-13 09:57:10 -07001440 # modf == True <=> Verify for flow modify, else for add/delete
1441 def flow_tbl_verify(self, modf = False):
rootf6af1672012-04-06 09:46:29 -07001442 result = True
1443
1444 # Verify flow count in switch
Rich Lane9a003812012-10-04 17:17:59 -07001445 logging.info("Reading table stats")
1446 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001447 if not self.tbl_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001448 logging.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001449 return False
1450 n = 0
Rich Lane5fd6faf2013-03-11 13:30:20 -07001451 for ts in self.tbl_stats.entries:
rootf6af1672012-04-06 09:46:29 -07001452 n = n + ts.active_count
Rich Lane9a003812012-10-04 17:17:59 -07001453 logging.info("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001454 % (n) \
1455 )
1456 if n != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001457 logging.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001458 result = False
1459
1460 # Read flows from switch
Rich Lane9a003812012-10-04 17:17:59 -07001461 logging.info("Retrieving flows from switch")
1462 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001463 if not self.flow_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001464 logging.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001465 return False
Rich Lane5fd6faf2013-03-11 13:30:20 -07001466 logging.info("Retrieved %d flows" % (len(self.flow_stats.entries)))
rootf6af1672012-04-06 09:46:29 -07001467
1468 # Verify flows returned by switch
1469
Rich Lane5fd6faf2013-03-11 13:30:20 -07001470 if len(self.flow_stats.entries) != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001471 logging.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001472 result = False
1473
Rich Lane9a003812012-10-04 17:17:59 -07001474 logging.info("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001475 for fc in self.flow_tbl.values():
1476 fc.matched = False
Rich Lane5fd6faf2013-03-11 13:30:20 -07001477 for fs in self.flow_stats.entries:
rootf6af1672012-04-06 09:46:29 -07001478 flow_in = Flow_Cfg()
1479 flow_in.from_flow_stat(fs)
Rich Lane9a003812012-10-04 17:17:59 -07001480 logging.info("Received flow:")
1481 logging.info(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001482 fc = self.flow_tbl.find(flow_in)
1483 if fc is None:
Rich Lane9a003812012-10-04 17:17:59 -07001484 logging.error("Received flow:")
1485 logging.error(str(flow_in))
1486 logging.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001487 result = False
1488 elif fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001489 logging.error("Received flow:")
1490 logging.error(str(flow_in))
1491 logging.error("re-matches defined flow:")
1492 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001493 result = False
1494 else:
Rich Lane9a003812012-10-04 17:17:59 -07001495 logging.info("matched")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001496 if modf:
1497 # Check for modify
1498
1499 if flow_in.cookie != fc.cookie:
Rich Lane9a003812012-10-04 17:17:59 -07001500 logging.warning("Defined flow:")
1501 logging.warning(str(fc))
1502 logging.warning("Received flow:")
1503 logging.warning(str(flow_in))
1504 logging.warning("cookies do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001505 if not flow_in.actions_equal(fc):
Rich Lane9a003812012-10-04 17:17:59 -07001506 logging.error("Defined flow:")
1507 logging.error(str(fc))
1508 logging.error("Received flow:")
1509 logging.error(str(flow_in))
1510 logging.error("actions do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001511 else:
1512 # Check for add/delete
1513
1514 if not flow_in == fc:
Rich Lane9a003812012-10-04 17:17:59 -07001515 logging.error("Defined flow:")
1516 logging.error(str(fc))
1517 logging.error("Received flow:")
1518 logging.error(str(flow_in))
1519 logging.error("non-key portions of flow do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001520 result = False
rootf6af1672012-04-06 09:46:29 -07001521 fc.matched = True
1522 for fc in self.flow_tbl.values():
1523 if not fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001524 logging.error("Defined flow:")
1525 logging.error(str(fc))
1526 logging.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001527 result = False
1528
1529 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001530
Howard Persh9cab4822012-09-11 17:08:40 -07001531 def settle(self):
1532 time.sleep(2)
1533
Howard Persh07d99e62012-04-09 15:26:57 -07001534# FLOW ADD 5
1535#
1536# OVERVIEW
1537# Add flows to switch, read back and verify flow configurations
1538#
1539# PURPOSE
1540# - Test acceptance of flow adds
1541# - Test ability of switch to process additions to flow table in random
1542# priority order
1543# - Test correctness of flow configuration responses
1544#
1545# PARAMETERS
1546#
1547# Name: num_flows
1548# Type: number
1549# Description:
1550# Number of flows to define; 0 => maximum number of flows, as determined
1551# from switch capabilities
1552# Default: 100
1553#
1554# PROCESS
1555# 1. Delete all flows from switch
1556# 2. Generate <num_flows> distinct flow configurations
1557# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1558# 4. Verify that no OFPT_ERROR responses were generated by switch
1559# 5. Retrieve flow stats from switch
1560# 6. Compare flow configurations returned by switch
1561# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1562# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001563
Rich Laneb90a1c42012-10-05 09:16:05 -07001564class Flow_Add_5(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001565 """
1566 Test FLOW_ADD_5 from draft top-half test plan
1567
1568 INPUTS
1569 num_flows - Number of flows to generate
1570 """
Howard Persh680b92a2012-03-31 13:34:35 -07001571
rootf6af1672012-04-06 09:46:29 -07001572 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001573 logging.info("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001574
Rich Lane2014f9b2012-10-05 15:29:40 -07001575 num_flows = test_param_get("num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001576
Howard Pershc7963582012-03-29 10:02:59 -07001577 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001578
Rich Lane9a003812012-10-04 17:17:59 -07001579 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001580 delete_all_flows(self.controller)
Howard Pershc7963582012-03-29 10:02:59 -07001581
rootf6af1672012-04-06 09:46:29 -07001582 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001583
rootf6af1672012-04-06 09:46:29 -07001584 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001585 self.assertTrue(sw.connect(self.controller), \
1586 "Failed to connect to switch" \
1587 )
Howard Pershc7963582012-03-29 10:02:59 -07001588
rootf6af1672012-04-06 09:46:29 -07001589 if num_flows == 0:
1590 # Number of flows requested was 0
1591 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001592
Rich Lane5fd6faf2013-03-11 13:30:20 -07001593 for ts in sw.tbl_stats.entries:
rootf6af1672012-04-06 09:46:29 -07001594 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001595
Rich Lane9a003812012-10-04 17:17:59 -07001596 logging.info("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001597
1598 # Dream up some flow information, i.e. space to chose from for
1599 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001600
rootf6af1672012-04-06 09:46:29 -07001601 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001602 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001603
rootf6af1672012-04-06 09:46:29 -07001604 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001605
rootf6af1672012-04-06 09:46:29 -07001606 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001607 ft.rand(required_wildcards(self), sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001608
rootf6af1672012-04-06 09:46:29 -07001609 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001610
Rich Lane9a003812012-10-04 17:17:59 -07001611 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001612 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001613 logging.info("Adding flow:")
1614 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001615 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001616
rootf6af1672012-04-06 09:46:29 -07001617 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001618
rootf6af1672012-04-06 09:46:29 -07001619 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001620
rootf6af1672012-04-06 09:46:29 -07001621 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001622
Howard Persh9cab4822012-09-11 17:08:40 -07001623 sw.settle() # Allow switch to settle and generate any notifications
1624
rootf6af1672012-04-06 09:46:29 -07001625 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001626
rootf6af1672012-04-06 09:46:29 -07001627 if not sw.errors_verify(0):
1628 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001629
rootf6af1672012-04-06 09:46:29 -07001630 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001631
rootf6af1672012-04-06 09:46:29 -07001632 sw.flow_tbl = ft
1633 if not sw.flow_tbl_verify():
1634 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001635
rootf6af1672012-04-06 09:46:29 -07001636 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001637 logging.info("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001638
Howard Pershc7963582012-03-29 10:02:59 -07001639
Howard Persh07d99e62012-04-09 15:26:57 -07001640# FLOW ADD 5_1
1641#
1642# OVERVIEW
1643# Verify handling of non-canonical flows
1644#
1645# PURPOSE
1646# - Test that switch detects and correctly responds to a non-canonical flow
1647# definition. A canonical flow is one that satisfies all match qualifier
1648# dependencies; a non-canonical flow is one that does not.
1649#
1650# PARAMETERS
1651# - None
1652#
1653# PROCESS
1654# 1. Delete all flows from switch
1655# 2. Generate 1 flow definition, which is different from its canonicalization
1656# 3. Send flow to switch
1657# 4. Retrieve flow from switch
1658# 5. Compare returned flow to canonical form of defined flow
1659# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1660
1661# Disabled.
1662# Should be DUT dependent.
Howard Persh07d99e62012-04-09 15:26:57 -07001663
Rich Lane0a4f6372013-01-02 14:40:22 -08001664@nonstandard
Rich Laneb90a1c42012-10-05 09:16:05 -07001665class Flow_Add_5_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001666 """
1667 Test FLOW_ADD_5.1 from draft top-half test plan
1668
1669 INPUTS
1670 None
1671 """
Rich Laned1d9c282012-10-04 22:07:10 -07001672
rootf6af1672012-04-06 09:46:29 -07001673 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001674 logging.info("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001675
Rich Lane2014f9b2012-10-05 15:29:40 -07001676 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001677
1678 # Clear all flows from switch
1679
Rich Lane9a003812012-10-04 17:17:59 -07001680 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001681 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001682
1683 # Get switch capabilites
1684
rootf6af1672012-04-06 09:46:29 -07001685 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001686 self.assertTrue(sw.connect(self.controller), \
1687 "Failed to connect to switch" \
1688 )
rootf6af1672012-04-06 09:46:29 -07001689
1690 # Dream up some flow information, i.e. space to chose from for
1691 # random flow parameter generation
1692
1693 fi = Flow_Info()
1694 fi.rand(10)
1695
1696 # Dream up a flow config that will be canonicalized by the switch
1697
1698 while True:
1699 fc = Flow_Cfg()
1700 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001701 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07001702 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001703 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001704 sw.valid_ports, \
1705 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001706 )
1707 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001708 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001709 break
1710
1711 ft = Flow_Tbl()
1712 ft.insert(fcc)
1713
1714 # Send it to the switch
1715
Rich Lane9a003812012-10-04 17:17:59 -07001716 logging.info("Sending flow add to switch:")
1717 logging.info(str(fc))
1718 logging.info("should be canonicalized as:")
1719 logging.info(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001720 fc.send_rem = False
1721 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1722
1723 # Do barrier, to make sure all flows are in
1724
1725 self.assertTrue(sw.barrier(), "Barrier failed")
1726
1727 result = True
1728
Howard Persh9cab4822012-09-11 17:08:40 -07001729 sw.settle() # Allow switch to settle and generate any notifications
1730
rootf6af1672012-04-06 09:46:29 -07001731 # Check for any error messages
1732
1733 if not sw.errors_verify(0):
1734 result = False
1735
1736 # Verify flow table
1737
1738 sw.flow_tbl = ft
1739 if not sw.flow_tbl_verify():
1740 result = False
1741
1742 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001743 logging.info("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001744
1745
Howard Persh07d99e62012-04-09 15:26:57 -07001746# FLOW ADD 6
1747#
1748# OVERVIEW
1749# Test flow table capacity
1750#
1751# PURPOSE
1752# - Test switch can accept as many flow definitions as it claims
1753# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1754# - Test that attempting to create flows beyond capacity does not corrupt
1755# flow table
1756#
1757# PARAMETERS
1758# None
1759#
1760# PROCESS
1761# 1. Delete all flows from switch
1762# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1763# to determine flow table size, N
1764# 3. Generate (N + 1) distinct flow configurations
1765# 4. Send N flow adds to switch, for flows generated in step 3 above
1766# 5. Verify flow table in switch
1767# 6. Send one more flow add to switch
1768# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1769# response was generated by switch, for last flow mod sent
1770# 7. Retrieve flow stats from switch
1771# 8. Verify flow table in switch
1772# 9. Test PASSED iff:
1773# - error message received, for correct flow
1774# - last flow definition sent to switch is not in flow table
1775# else test FAILED
1776
Howard Persh3340d452012-04-06 16:45:21 -07001777# Disabled because of bogus capacity reported by OVS.
1778# Should be DUT dependent.
Howard Persh3340d452012-04-06 16:45:21 -07001779
Rich Lane0a4f6372013-01-02 14:40:22 -08001780@nonstandard
Rich Laneb90a1c42012-10-05 09:16:05 -07001781class Flow_Add_6(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001782 """
1783 Test FLOW_ADD_6 from draft top-half test plan
1784
1785 INPUTS
1786 num_flows - Number of flows to generate
1787 """
Howard Pershc7963582012-03-29 10:02:59 -07001788
1789 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001790 logging.info("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001791
rootf6af1672012-04-06 09:46:29 -07001792 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001793
Rich Lane9a003812012-10-04 17:17:59 -07001794 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001795 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001796
1797 # Get switch capabilites
1798
rootf6af1672012-04-06 09:46:29 -07001799 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001800 self.assertTrue(sw.connect(self.controller), \
1801 "Failed to connect to switch" \
1802 )
rootf6af1672012-04-06 09:46:29 -07001803
root2843d2b2012-04-06 10:27:46 -07001804 num_flows = 0
Rich Lane5fd6faf2013-03-11 13:30:20 -07001805 for ts in sw.tbl_stats.entries:
rootf6af1672012-04-06 09:46:29 -07001806 num_flows = num_flows + ts.max_entries
1807
Rich Lane9a003812012-10-04 17:17:59 -07001808 logging.info("Switch capacity is %d flows" % (num_flows))
1809 logging.info("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001810
1811 # Dream up some flow information, i.e. space to chose from for
1812 # random flow parameter generation
1813
1814 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001815 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001816
1817 # Create a flow table, to switch's capacity
1818
1819 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001820 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07001821
1822 # Send flow table to switch
1823
Rich Lane9a003812012-10-04 17:17:59 -07001824 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001825 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001826 logging.info("Adding flow:")
1827 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001828 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1829
1830 # Do barrier, to make sure all flows are in
1831
1832 self.assertTrue(sw.barrier(), "Barrier failed")
1833
1834 result = True
1835
Howard Persh9cab4822012-09-11 17:08:40 -07001836 sw.settle() # Allow switch to settle and generate any notifications
1837
rootf6af1672012-04-06 09:46:29 -07001838 # Check for any error messages
1839
1840 if not sw.errors_verify(0):
1841 result = False
1842
1843 # Dream up one more flow
1844
Rich Lane9a003812012-10-04 17:17:59 -07001845 logging.info("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001846 while True:
1847 fc = Flow_Cfg()
1848 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001849 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07001850 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001851 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001852 sw.valid_ports, \
1853 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001854 )
1855 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001856 if not ft.find(fc):
1857 break
rootf6af1672012-04-06 09:46:29 -07001858
1859 # Send one-more flow
1860
1861 fc.send_rem = False
Rich Lane9a003812012-10-04 17:17:59 -07001862 logging.info("Sending flow add switch")
1863 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001864 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1865
1866 # Do barrier, to make sure all flows are in
1867
1868 self.assertTrue(sw.barrier(), "Barrier failed")
1869
Howard Persh9cab4822012-09-11 17:08:40 -07001870 sw.settle() # Allow switch to settle and generate any notifications
1871
rootf6af1672012-04-06 09:46:29 -07001872 # Check for expected error message
1873
1874 if not sw.errors_verify(1, \
1875 ofp.OFPET_FLOW_MOD_FAILED, \
1876 ofp.OFPFMFC_ALL_TABLES_FULL \
1877 ):
1878 result = False
1879
1880 # Verify flow table
1881
1882 sw.flow_tbl = ft
1883 if not sw.flow_tbl_verify():
1884 result = False
1885
1886 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001887 logging.info("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001888
1889
Howard Persh07d99e62012-04-09 15:26:57 -07001890# FLOW ADD 7
1891#
1892# OVERVIEW
1893# Test flow redefinition
1894#
1895# PURPOSE
1896# Verify that successive flow adds with same priority and match criteria
1897# overwrite in flow table
1898#
1899# PARAMETERS
1900# None
1901#
1902# PROCESS
1903# 1. Delete all flows from switch
1904# 2. Generate flow definition F1
1905# 3. Generate flow definition F2, with same key (priority and match) as F1,
1906# but with different actions
1907# 4. Send flow adds for F1 and F2 to switch
1908# 5. Verify flow definitions in switch
1909# 6. Test PASSED iff 1 flow returned by switch, matching configuration of F2;
1910# else test FAILED
1911
Rich Laneb90a1c42012-10-05 09:16:05 -07001912class Flow_Add_7(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001913 """
1914 Test FLOW_ADD_7 from draft top-half test plan
1915
1916 INPUTS
1917 None
1918 """
1919
1920 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001921 logging.info("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001922
1923 # Clear all flows from switch
1924
Rich Lane9a003812012-10-04 17:17:59 -07001925 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001926 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001927
1928 # Get switch capabilites
1929
rootf6af1672012-04-06 09:46:29 -07001930 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001931 self.assertTrue(sw.connect(self.controller), \
1932 "Failed to connect to switch" \
1933 )
rootf6af1672012-04-06 09:46:29 -07001934
1935 # Dream up some flow information, i.e. space to chose from for
1936 # random flow parameter generation
1937
1938 fi = Flow_Info()
1939 fi.rand(10)
1940
1941 # Dream up a flow config
1942
1943 fc = Flow_Cfg()
1944 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001945 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07001946 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001947 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001948 sw.valid_ports, \
1949 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001950 )
1951 fc = fc.canonical()
1952
1953 # Send it to the switch
1954
Rich Lane9a003812012-10-04 17:17:59 -07001955 logging.info("Sending flow add to switch:")
1956 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001957 ft = Flow_Tbl()
1958 fc.send_rem = False
1959 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1960 ft.insert(fc)
1961
1962 # Dream up some different actions, with the same flow key
1963
1964 fc2 = copy.deepcopy(fc)
1965 while True:
1966 fc2.rand_mod(fi, \
1967 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001968 sw.valid_ports, \
1969 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001970 )
1971 if fc2 != fc:
1972 break
1973
1974 # Send that to the switch
1975
Rich Lane9a003812012-10-04 17:17:59 -07001976 logging.info("Sending flow add to switch:")
1977 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07001978 fc2.send_rem = False
1979 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
1980 ft.insert(fc2)
1981
1982 # Do barrier, to make sure all flows are in
1983
1984 self.assertTrue(sw.barrier(), "Barrier failed")
1985
1986 result = True
1987
Howard Persh9cab4822012-09-11 17:08:40 -07001988 sw.settle() # Allow switch to settle and generate any notifications
1989
rootf6af1672012-04-06 09:46:29 -07001990 # Check for any error messages
1991
1992 if not sw.errors_verify(0):
1993 result = False
1994
1995 # Verify flow table
1996
1997 sw.flow_tbl = ft
1998 if not sw.flow_tbl_verify():
1999 result = False
2000
2001 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002002 logging.info("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002003
2004
Howard Persh07d99e62012-04-09 15:26:57 -07002005# FLOW ADD 8
2006#
2007# OVERVIEW
2008# Add overlapping flows to switch, verify that overlapping flows are rejected
2009#
2010# PURPOSE
2011# - Test detection of overlapping flows by switch
2012# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
2013# - Test rejection of overlapping flows
2014# - Test defining overlapping flows does not corrupt flow table
2015#
2016# PARAMETERS
2017# None
2018#
2019# PROCESS
2020# 1. Delete all flows from switch
2021# 2. Generate flow definition F1
2022# 3. Generate flow definition F2, with key overlapping F1
2023# 4. Send flow add to switch, for F1
2024# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
2025# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
2026# was generated by switch
2027# 7. Verifiy flows configured in swtich
2028# 8. Test PASSED iff:
2029# - error message received, for overlapping flow
2030# - overlapping flow is not in flow table
2031# else test FAILED
2032
Rich Laneb90a1c42012-10-05 09:16:05 -07002033class Flow_Add_8(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002034 """
2035 Test FLOW_ADD_8 from draft top-half test plan
2036
2037 INPUTS
2038 None
2039 """
2040
2041 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002042 logging.info("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002043
2044 # Clear all flows from switch
2045
Rich Lane9a003812012-10-04 17:17:59 -07002046 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002047 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002048
2049 # Get switch capabilites
2050
rootf6af1672012-04-06 09:46:29 -07002051 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002052 self.assertTrue(sw.connect(self.controller), \
2053 "Failed to connect to switch" \
2054 )
rootf6af1672012-04-06 09:46:29 -07002055
2056 # Dream up some flow information, i.e. space to chose from for
2057 # random flow parameter generation
2058
2059 fi = Flow_Info()
2060 fi.rand(10)
2061
2062 # Dream up a flow config, with at least 1 qualifier specified
2063
2064 fc = Flow_Cfg()
2065 while True:
2066 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002067 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002068 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002069 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002070 sw.valid_ports, \
2071 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002072 )
2073 fc = fc.canonical()
2074 if fc.match.wildcards != ofp.OFPFW_ALL:
2075 break
2076
2077 # Send it to the switch
2078
Rich Lane9a003812012-10-04 17:17:59 -07002079 logging.info("Sending flow add to switch:")
2080 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002081 ft = Flow_Tbl()
2082 fc.send_rem = False
2083 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2084 ft.insert(fc)
2085
2086 # Wildcard out one qualifier that was specified, to create an
2087 # overlapping flow
2088
2089 fc2 = copy.deepcopy(fc)
2090 for wi in shuffle(range(len(all_wildcards_list))):
2091 w = all_wildcards_list[wi]
2092 if (fc2.match.wildcards & w) == 0:
2093 break
2094 if w == ofp.OFPFW_NW_SRC_MASK:
2095 w = ofp.OFPFW_NW_SRC_ALL
2096 wn = "OFPFW_NW_SRC"
2097 elif w == ofp.OFPFW_NW_DST_MASK:
2098 w = ofp.OFPFW_NW_DST_ALL
2099 wn = "OFPFW_NW_DST"
2100 else:
2101 wn = all_wildcard_names[w]
Rich Lane9a003812012-10-04 17:17:59 -07002102 logging.info("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07002103 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07002104 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07002105
2106 # Send that to the switch, with overlap checking
2107
Rich Lane9a003812012-10-04 17:17:59 -07002108 logging.info("Sending flow add to switch:")
2109 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002110 fc2.send_rem = False
2111 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
2112
2113 # Do barrier, to make sure all flows are in
2114 self.assertTrue(sw.barrier(), "Barrier failed")
2115
2116 result = True
2117
Howard Persh9cab4822012-09-11 17:08:40 -07002118 sw.settle() # Allow switch to settle and generate any notifications
2119
rootf6af1672012-04-06 09:46:29 -07002120 # Check for expected error message
2121
2122 if not sw.errors_verify(1, \
2123 ofp.OFPET_FLOW_MOD_FAILED, \
2124 ofp.OFPFMFC_OVERLAP \
2125 ):
2126 result = False
2127
2128 # Verify flow table
2129
2130 sw.flow_tbl = ft
2131 if not sw.flow_tbl_verify():
2132 result = False
2133
2134 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002135 logging.info("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002136
2137
Howard Persh07d99e62012-04-09 15:26:57 -07002138# FLOW MODIFY 1
2139#
2140# OVERVIEW
2141# Strict modify of single existing flow
2142#
2143# PURPOSE
2144# - Verify that strict flow modify operates only on specified flow
2145# - Verify that flow is correctly modified
2146#
2147# PARAMETERS
2148# None
2149#
2150# PROCESS
2151# 1. Delete all flows from switch
2152# 2. Generate 1 flow F
2153# 3. Send flow add to switch, for flow F
2154# 4. Generate new action list for flow F, yielding F'
2155# 5. Send strict flow modify to switch, for flow F'
2156# 6. Verify flow table in switch
2157# 7. Test PASSED iff flow returned by switch is F'; else FAILED
2158
Rich Laneb90a1c42012-10-05 09:16:05 -07002159class Flow_Mod_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002160 """
2161 Test FLOW_MOD_1 from draft top-half test plan
2162
2163 INPUTS
2164 None
2165 """
2166
2167 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002168 logging.info("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002169
2170 # Clear all flows from switch
2171
Rich Lane9a003812012-10-04 17:17:59 -07002172 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002173 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002174
2175 # Get switch capabilites
2176
rootf6af1672012-04-06 09:46:29 -07002177 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002178 self.assertTrue(sw.connect(self.controller), \
2179 "Failed to connect to switch" \
2180 )
rootf6af1672012-04-06 09:46:29 -07002181
2182 # Dream up some flow information, i.e. space to chose from for
2183 # random flow parameter generation
2184
2185 fi = Flow_Info()
2186 fi.rand(10)
2187
2188 # Dream up a flow config
2189
2190 fc = Flow_Cfg()
2191 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002192 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002193 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002194 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002195 sw.valid_ports, \
2196 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002197 )
2198 fc = fc.canonical()
2199
2200 # Send it to the switch
2201
Rich Lane9a003812012-10-04 17:17:59 -07002202 logging.info("Sending flow add to switch:")
2203 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002204 ft = Flow_Tbl()
2205 fc.send_rem = False
2206 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2207 ft.insert(fc)
2208
2209 # Dream up some different actions, with the same flow key
2210
2211 fc2 = copy.deepcopy(fc)
2212 while True:
2213 fc2.rand_mod(fi, \
2214 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002215 sw.valid_ports, \
2216 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002217 )
2218 if fc2 != fc:
2219 break
2220
2221 # Send that to the switch
2222
Rich Lane9a003812012-10-04 17:17:59 -07002223 logging.info("Sending strict flow mod to switch:")
2224 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002225 fc2.send_rem = False
2226 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2227 ft.insert(fc2)
2228
2229 # Do barrier, to make sure all flows are in
2230
2231 self.assertTrue(sw.barrier(), "Barrier failed")
2232
2233 result = True
2234
Howard Persh9cab4822012-09-11 17:08:40 -07002235 sw.settle() # Allow switch to settle and generate any notifications
2236
rootf6af1672012-04-06 09:46:29 -07002237 # Check for any error messages
2238
2239 if not sw.errors_verify(0):
2240 result = False
2241
2242 # Verify flow table
2243
2244 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002245 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002246 result = False
2247
2248 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002249 logging.info("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002250
Howard Persh07d99e62012-04-09 15:26:57 -07002251
2252# FLOW MODIFY 2
2253#
2254# OVERVIEW
2255# Loose modify of mutiple flows
2256#
2257# PURPOSE
2258# - Verify that loose flow modify operates only on matching flows
2259# - Verify that matching flows are correctly modified
2260#
2261# PARAMETERS
2262# Name: num_flows
2263# Type: number
2264# Description:
2265# Number of flows to define
2266# Default: 100
2267#
2268# PROCESS
2269# 1. Delete all flows from switch
2270# 2. Generate <num_flows> distinct flow configurations
2271# 3. Send <num_flows> flow adds to switch
2272# 4. Pick 1 defined flow F at random
2273# 5. Create overlapping loose flow mod match criteria by repeatedly
2274# wildcarding out qualifiers in match of F => F',
2275# and create new actions list A' for F'
2276# 6. Send loose flow modify for F' to switch
2277# 7. Verify flow table in swtich
2278# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2279# are returned in step 7 above, each with correct (original or modified)
2280# action list;
2281# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002282
Rich Laneb90a1c42012-10-05 09:16:05 -07002283class Flow_Mod_2(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002284 """
2285 Test FLOW_MOD_2 from draft top-half test plan
2286
2287 INPUTS
2288 None
2289 """
2290
2291 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002292 logging.info("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002293
Rich Lane2014f9b2012-10-05 15:29:40 -07002294 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002295
2296 # Clear all flows from switch
2297
Rich Lane9a003812012-10-04 17:17:59 -07002298 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002299 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002300
2301 # Get switch capabilites
2302
rootf6af1672012-04-06 09:46:29 -07002303 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002304 self.assertTrue(sw.connect(self.controller), \
2305 "Failed to connect to switch" \
2306 )
rootf6af1672012-04-06 09:46:29 -07002307
2308 # Dream up some flow information, i.e. space to chose from for
2309 # random flow parameter generation
2310
2311 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002312 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002313 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002314
2315 # Dream up some flows
2316
2317 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002318 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002319
2320 # Send flow table to switch
2321
Rich Lane9a003812012-10-04 17:17:59 -07002322 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002323 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002324 logging.info("Adding flow:")
2325 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002326 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2327
2328 # Do barrier, to make sure all flows are in
2329
2330 self.assertTrue(sw.barrier(), "Barrier failed")
2331
2332 result = True
2333
Howard Persh9cab4822012-09-11 17:08:40 -07002334 sw.settle() # Allow switch to settle and generate any notifications
2335
rootf6af1672012-04-06 09:46:29 -07002336 # Check for any error messages
2337
2338 if not sw.errors_verify(0):
2339 result = False
2340
2341 # Verify flow table
2342
2343 sw.flow_tbl = ft
2344 if not sw.flow_tbl_verify():
2345 result = False
2346
2347 # Pick a random flow as a basis
Howard Persh5f3c83f2012-04-13 09:57:10 -07002348
2349 mfc = copy.deepcopy((ft.values())[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002350 mfc.rand_mod(fi, \
2351 sw.sw_features.actions, \
2352 sw.valid_ports, \
2353 sw.valid_queues \
2354 )
rootf6af1672012-04-06 09:46:29 -07002355
2356 # Repeatedly wildcard qualifiers
2357
2358 for wi in shuffle(range(len(all_wildcards_list))):
2359 w = all_wildcards_list[wi]
2360 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2361 n = wildcard_get(mfc.match.wildcards, w)
2362 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002363 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2364 w, \
2365 random.randint(n + 1, 32) \
2366 )
rootf6af1672012-04-06 09:46:29 -07002367 else:
2368 continue
2369 else:
2370 if wildcard_get(mfc.match.wildcards, w) == 0:
2371 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2372 else:
2373 continue
2374 mfc = mfc.canonical()
2375
2376 # Count the number of flows that would be modified
2377
2378 n = 0
2379 for fc in ft.values():
2380 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2381 n = n + 1
2382
2383 # If more than 1, we found our loose delete flow spec
2384 if n > 1:
2385 break
2386
Rich Lane9a003812012-10-04 17:17:59 -07002387 logging.info("Modifying %d flows" % (n))
2388 logging.info("Sending flow mod to switch:")
2389 logging.info(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002390 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2391
2392 # Do barrier, to make sure all flows are in
2393 self.assertTrue(sw.barrier(), "Barrier failed")
2394
Howard Persh9cab4822012-09-11 17:08:40 -07002395 sw.settle() # Allow switch to settle and generate any notifications
2396
rootf6af1672012-04-06 09:46:29 -07002397 # Check for error message
2398
2399 if not sw.errors_verify(0):
2400 result = False
2401
2402 # Apply flow mod to local flow table
2403
2404 for fc in ft.values():
2405 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002406 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002407
2408 # Verify flow table
2409
2410 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002411 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002412 result = False
2413
2414 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002415 logging.info("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002416
2417
Howard Persh07d99e62012-04-09 15:26:57 -07002418# FLOW MODIFY 3
2419
2420# OVERVIEW
2421# Strict modify of non-existent flow
2422#
2423# PURPOSE
2424# Verify that strict modify of a non-existent flow is equivalent to a flow add
2425#
2426# PARAMETERS
2427# None
2428#
2429# PROCESS
2430# 1. Delete all flows from switch
2431# 2. Send single flow mod, as strict modify, to switch
2432# 3. Verify flow table in switch
2433# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2434
Rich Laneb90a1c42012-10-05 09:16:05 -07002435class Flow_Mod_3(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002436 """
2437 Test FLOW_MOD_3 from draft top-half test plan
2438
2439 INPUTS
2440 None
2441 """
2442
2443 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002444 logging.info("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002445
2446 # Clear all flows from switch
2447
Rich Lane9a003812012-10-04 17:17:59 -07002448 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002449 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002450
2451 # Get switch capabilites
2452
rootf6af1672012-04-06 09:46:29 -07002453 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002454 self.assertTrue(sw.connect(self.controller), \
2455 "Failed to connect to switch" \
2456 )
rootf6af1672012-04-06 09:46:29 -07002457
2458 # Dream up some flow information, i.e. space to chose from for
2459 # random flow parameter generation
2460
2461 fi = Flow_Info()
2462 fi.rand(10)
2463
2464 # Dream up a flow config
2465
2466 fc = Flow_Cfg()
2467 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002468 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002469 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002470 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002471 sw.valid_ports, \
2472 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002473 )
2474 fc = fc.canonical()
2475
2476 # Send it to the switch
2477
Rich Lane9a003812012-10-04 17:17:59 -07002478 logging.info("Sending flow mod to switch:")
2479 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002480 ft = Flow_Tbl()
2481 fc.send_rem = False
2482 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2483 ft.insert(fc)
2484
2485 # Do barrier, to make sure all flows are in
2486
2487 self.assertTrue(sw.barrier(), "Barrier failed")
2488
2489 result = True
2490
Howard Persh9cab4822012-09-11 17:08:40 -07002491 sw.settle() # Allow switch to settle and generate any notifications
2492
rootf6af1672012-04-06 09:46:29 -07002493 # Check for any error messages
2494
2495 if not sw.errors_verify(0):
2496 result = False
2497
2498 # Verify flow table
2499
2500 sw.flow_tbl = ft
2501 if not sw.flow_tbl_verify():
2502 result = False
2503
2504 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002505 logging.info("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002506
2507
Howard Persh8d21c1f2012-04-20 15:57:29 -07002508# FLOW MODIFY 3_1
2509
2510# OVERVIEW
2511# No-op modify
2512#
2513# PURPOSE
2514# Verify that modify of a flow with new actions same as old ones operates correctly
2515#
2516# PARAMETERS
2517# None
2518#
2519# PROCESS
2520# 1. Delete all flows from switch
2521# 2. Send single flow mod, as strict modify, to switch
2522# 3. Verify flow table in switch
2523# 4. Send same flow mod, as strict modify, to switch
2524# 5. Verify flow table in switch
2525# 6. Test PASSED iff flow defined in step 2 and 4 above verified; else FAILED
2526
Rich Laneb90a1c42012-10-05 09:16:05 -07002527class Flow_Mod_3_1(base_tests.SimpleProtocol):
Howard Persh8d21c1f2012-04-20 15:57:29 -07002528 """
2529 Test FLOW_MOD_3_1 from draft top-half test plan
2530
2531 INPUTS
2532 None
2533 """
2534
2535 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002536 logging.info("Flow_Mod_3_1 TEST BEGIN")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002537
2538 # Clear all flows from switch
2539
Rich Lane9a003812012-10-04 17:17:59 -07002540 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002541 delete_all_flows(self.controller)
Howard Persh8d21c1f2012-04-20 15:57:29 -07002542
2543 # Get switch capabilites
2544
2545 sw = Switch()
2546 self.assertTrue(sw.connect(self.controller), \
2547 "Failed to connect to switch" \
2548 )
2549
2550 # Dream up some flow information, i.e. space to chose from for
2551 # random flow parameter generation
2552
2553 fi = Flow_Info()
2554 fi.rand(10)
2555
2556 # Dream up a flow config
2557
2558 fc = Flow_Cfg()
2559 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002560 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002561 sw.tbl_stats.entries[0].wildcards, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002562 sw.sw_features.actions, \
2563 sw.valid_ports, \
2564 sw.valid_queues \
2565 )
2566 fc = fc.canonical()
2567
2568 # Send it to the switch
2569
Rich Lane9a003812012-10-04 17:17:59 -07002570 logging.info("Sending flow mod to switch:")
2571 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002572 ft = Flow_Tbl()
2573 fc.send_rem = False
2574 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2575 ft.insert(fc)
2576
2577 # Do barrier, to make sure all flows are in
2578
2579 self.assertTrue(sw.barrier(), "Barrier failed")
2580
2581 result = True
2582
Howard Persh9cab4822012-09-11 17:08:40 -07002583 sw.settle() # Allow switch to settle and generate any notifications
2584
Howard Persh8d21c1f2012-04-20 15:57:29 -07002585 # Check for any error messages
2586
2587 if not sw.errors_verify(0):
2588 result = False
2589
2590 # Verify flow table
2591
2592 sw.flow_tbl = ft
2593 if not sw.flow_tbl_verify():
2594 result = False
2595
2596 # Send same flow to the switch again
2597
Rich Lane9a003812012-10-04 17:17:59 -07002598 logging.info("Sending flow mod to switch:")
2599 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002600 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2601
2602 # Do barrier, to make sure all flows are in
2603
2604 self.assertTrue(sw.barrier(), "Barrier failed")
2605
Howard Persh9cab4822012-09-11 17:08:40 -07002606 sw.settle() # Allow switch to settle and generate any notifications
2607
Howard Persh8d21c1f2012-04-20 15:57:29 -07002608 # Check for any error messages
2609
2610 if not sw.errors_verify(0):
2611 result = False
2612
2613 # Verify flow table
2614
2615 if not sw.flow_tbl_verify():
2616 result = False
2617
2618 self.assertTrue(result, "Flow_Mod_3_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002619 logging.info("Flow_Mod_3_1 TEST PASSED")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002620
2621
Howard Persh07d99e62012-04-09 15:26:57 -07002622# FLOW DELETE 1
2623#
2624# OVERVIEW
2625# Strict delete of single flow
2626#
2627# PURPOSE
2628# Verify correct operation of strict delete of single defined flow
2629#
2630# PARAMETERS
2631# None
2632#
2633# PROCESS
2634# 1. Delete all flows from switch
2635# 2. Send flow F to switch
2636# 3. Send strict flow delete for F to switch
2637# 4. Verify flow table in swtich
2638# 6. Test PASSED iff all flows sent to switch in step 2 above,
2639# less flow removed in step 3 above, are returned in step 4 above;
2640# else test FAILED
2641
Rich Laneb90a1c42012-10-05 09:16:05 -07002642class Flow_Del_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002643 """
2644 Test FLOW_DEL_1 from draft top-half test plan
2645
2646 INPUTS
2647 None
2648 """
2649
2650 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002651 logging.info("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002652
2653 # Clear all flows from switch
2654
Rich Lane9a003812012-10-04 17:17:59 -07002655 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002656 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002657
2658 # Get switch capabilites
2659
rootf6af1672012-04-06 09:46:29 -07002660 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002661 self.assertTrue(sw.connect(self.controller), \
2662 "Failed to connect to switch" \
2663 )
rootf6af1672012-04-06 09:46:29 -07002664
2665 # Dream up some flow information, i.e. space to chose from for
2666 # random flow parameter generation
2667
2668 fi = Flow_Info()
2669 fi.rand(10)
2670
2671 # Dream up a flow config
2672
2673 fc = Flow_Cfg()
2674 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002675 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002676 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002677 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002678 sw.valid_ports, \
2679 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002680 )
2681 fc = fc.canonical()
2682
2683 # Send it to the switch
2684
Rich Lane9a003812012-10-04 17:17:59 -07002685 logging.info("Sending flow add to switch:")
2686 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002687 ft = Flow_Tbl()
2688 fc.send_rem = False
2689 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2690 ft.insert(fc)
2691
2692 # Dream up some different actions, with the same flow key
2693
2694 fc2 = copy.deepcopy(fc)
2695 while True:
2696 fc2.rand_mod(fi, \
2697 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002698 sw.valid_ports, \
2699 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002700 )
2701 if fc2 != fc:
2702 break
2703
2704 # Delete strictly
2705
Rich Lane9a003812012-10-04 17:17:59 -07002706 logging.info("Sending strict flow del to switch:")
2707 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002708 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2709 ft.delete(fc)
2710
2711 # Do barrier, to make sure all flows are in
2712
2713 self.assertTrue(sw.barrier(), "Barrier failed")
2714
2715 result = True
2716
Howard Persh9cab4822012-09-11 17:08:40 -07002717 sw.settle() # Allow switch to settle and generate any notifications
2718
rootf6af1672012-04-06 09:46:29 -07002719 # Check for any error messages
2720
2721 if not sw.errors_verify(0):
2722 result = False
2723
2724 # Verify flow table
2725
2726 sw.flow_tbl = ft
2727 if not sw.flow_tbl_verify():
2728 result = False
2729
2730 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002731 logging.info("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002732
2733
Howard Persh07d99e62012-04-09 15:26:57 -07002734# FLOW DELETE 2
2735#
2736# OVERVIEW
2737# Loose delete of multiple flows
2738#
2739# PURPOSE
2740# - Verify correct operation of loose delete of multiple flows
2741#
2742# PARAMETERS
2743# Name: num_flows
2744# Type: number
2745# Description:
2746# Number of flows to define
2747# Default: 100
2748#
2749# PROCESS
2750# 1. Delete all flows from switch
2751# 2. Generate <num_flows> distinct flow configurations
2752# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2753# 4. Pick 1 defined flow F at random
2754# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2755# F' will match more than 1 existing flow key
2756# 6. Send loose flow delete for F' to switch
2757# 7. Verify flow table in switch
2758# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2759# removed in step 6 above (i.e. those that match F'), are returned
2760# in step 7 above;
2761# else test FAILED
2762
Rich Laneb90a1c42012-10-05 09:16:05 -07002763class Flow_Del_2(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002764 """
2765 Test FLOW_DEL_2 from draft top-half test plan
2766
2767 INPUTS
2768 None
2769 """
2770
2771 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002772 logging.info("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002773
Rich Lane2014f9b2012-10-05 15:29:40 -07002774 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002775
2776 # Clear all flows from switch
2777
Rich Lane9a003812012-10-04 17:17:59 -07002778 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002779 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002780
2781 # Get switch capabilites
2782
rootf6af1672012-04-06 09:46:29 -07002783 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002784 self.assertTrue(sw.connect(self.controller), \
2785 "Failed to connect to switch" \
2786 )
rootf6af1672012-04-06 09:46:29 -07002787
2788 # Dream up some flow information, i.e. space to chose from for
2789 # random flow parameter generation
2790
2791 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002792 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002793 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002794
2795 # Dream up some flows
2796
2797 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002798 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002799
2800 # Send flow table to switch
2801
Rich Lane9a003812012-10-04 17:17:59 -07002802 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002803 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002804 logging.info("Adding flow:")
2805 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002806 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2807
2808 # Do barrier, to make sure all flows are in
2809
2810 self.assertTrue(sw.barrier(), "Barrier failed")
2811
2812 result = True
2813
Howard Persh9cab4822012-09-11 17:08:40 -07002814 sw.settle() # Allow switch to settle and generate any notifications
2815
rootf6af1672012-04-06 09:46:29 -07002816 # Check for any error messages
2817
2818 if not sw.errors_verify(0):
2819 result = False
2820
2821 # Verify flow table
2822
2823 sw.flow_tbl = ft
2824 if not sw.flow_tbl_verify():
2825 result = False
2826
2827 # Pick a random flow as a basis
2828
2829 dfc = copy.deepcopy(ft.values()[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002830 dfc.rand_mod(fi, \
2831 sw.sw_features.actions, \
2832 sw.valid_ports, \
2833 sw.valid_queues \
2834 )
rootf6af1672012-04-06 09:46:29 -07002835
2836 # Repeatedly wildcard qualifiers
2837
2838 for wi in shuffle(range(len(all_wildcards_list))):
2839 w = all_wildcards_list[wi]
2840 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2841 n = wildcard_get(dfc.match.wildcards, w)
2842 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002843 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2844 w, \
2845 random.randint(n + 1, 32) \
2846 )
rootf6af1672012-04-06 09:46:29 -07002847 else:
2848 continue
2849 else:
2850 if wildcard_get(dfc.match.wildcards, w) == 0:
2851 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2852 else:
2853 continue
2854 dfc = dfc.canonical()
2855
2856 # Count the number of flows that would be deleted
2857
2858 n = 0
2859 for fc in ft.values():
2860 if dfc.overlaps(fc, True):
2861 n = n + 1
2862
2863 # If more than 1, we found our loose delete flow spec
2864 if n > 1:
2865 break
2866
Rich Lane9a003812012-10-04 17:17:59 -07002867 logging.info("Deleting %d flows" % (n))
2868 logging.info("Sending flow del to switch:")
2869 logging.info(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002870 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2871
2872 # Do barrier, to make sure all flows are in
2873 self.assertTrue(sw.barrier(), "Barrier failed")
2874
Howard Persh9cab4822012-09-11 17:08:40 -07002875 sw.settle() # Allow switch to settle and generate any notifications
2876
rootf6af1672012-04-06 09:46:29 -07002877 # Check for error message
2878
2879 if not sw.errors_verify(0):
2880 result = False
2881
2882 # Apply flow mod to local flow table
2883
2884 for fc in ft.values():
2885 if dfc.overlaps(fc, True):
2886 ft.delete(fc)
2887
2888 # Verify flow table
2889
2890 sw.flow_tbl = ft
2891 if not sw.flow_tbl_verify():
2892 result = False
2893
2894 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002895 logging.info("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002896
2897
Howard Persh07d99e62012-04-09 15:26:57 -07002898# FLOW DELETE 4
2899#
2900# OVERVIEW
2901# Flow removed messages
2902#
2903# PURPOSE
2904# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2905# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2906#
2907# PARAMETERS
2908# None
2909#
2910# PROCESS
2911# 1. Delete all flows from switch
2912# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2913# 3. Send strict flow delete of flow to switch
2914# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2915# 5. Verify flow table in switch
2916# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2917# removed in step 3 above, are returned in step 5 above, and that
2918# asynch message was received; else test FAILED
2919
2920
Rich Laneb90a1c42012-10-05 09:16:05 -07002921class Flow_Del_4(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002922 """
2923 Test FLOW_DEL_4 from draft top-half test plan
2924
2925 INPUTS
2926 None
2927 """
2928
2929 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002930 logging.info("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002931
2932 # Clear all flows from switch
2933
Rich Lane9a003812012-10-04 17:17:59 -07002934 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002935 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002936
2937 # Get switch capabilites
2938
rootf6af1672012-04-06 09:46:29 -07002939 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002940 self.assertTrue(sw.connect(self.controller), \
2941 "Failed to connect to switch" \
2942 )
rootf6af1672012-04-06 09:46:29 -07002943
2944 # Dream up some flow information, i.e. space to chose from for
2945 # random flow parameter generation
2946
2947 fi = Flow_Info()
2948 fi.rand(10)
2949
2950 # Dream up a flow config
2951
2952 fc = Flow_Cfg()
2953 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002954 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002955 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002956 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002957 sw.valid_ports, \
2958 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002959 )
2960 fc = fc.canonical()
2961
2962 # Send it to the switch. with "notify on removed"
2963
Rich Lane9a003812012-10-04 17:17:59 -07002964 logging.info("Sending flow add to switch:")
2965 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002966 ft = Flow_Tbl()
2967 fc.send_rem = True
2968 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2969 ft.insert(fc)
2970
2971 # Dream up some different actions, with the same flow key
2972
2973 fc2 = copy.deepcopy(fc)
2974 while True:
2975 fc2.rand_mod(fi, \
2976 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002977 sw.valid_ports, \
2978 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002979 )
2980 if fc2 != fc:
2981 break
2982
2983 # Delete strictly
2984
Rich Lane9a003812012-10-04 17:17:59 -07002985 logging.info("Sending strict flow del to switch:")
2986 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002987 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2988 ft.delete(fc)
2989
2990 # Do barrier, to make sure all flows are in
2991
2992 self.assertTrue(sw.barrier(), "Barrier failed")
2993
2994 result = True
2995
Howard Persh9cab4822012-09-11 17:08:40 -07002996 sw.settle() # Allow switch to settle and generate any notifications
2997
rootf6af1672012-04-06 09:46:29 -07002998 # Check for expected "removed" message
2999
Howard Persh3340d452012-04-06 16:45:21 -07003000 if not sw.errors_verify(0):
3001 result = False
3002
3003 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07003004 result = False
3005
3006 # Verify flow table
3007
3008 sw.flow_tbl = ft
3009 if not sw.flow_tbl_verify():
3010 result = False
3011
3012 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07003013 logging.info("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07003014