blob: 5b81460f52ad9406045f149c67933ebe79fc50f6 [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.
Rich Lane15a15062013-08-12 23:11:12 -0700953 # - The IP mask values from 32 to 63 are equivalent. Canonicalize to 32.
rootf6af1672012-04-06 09:46:29 -0700954 def canonical(self):
955 result = copy.deepcopy(self)
Howard Persh07d99e62012-04-09 15:26:57 -0700956
Rich Lane15a15062013-08-12 23:11:12 -0700957 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_SRC_MASK) > 32:
958 result.match.wildcards = wildcard_set(result.match.wildcards, \
959 ofp.OFPFW_NW_SRC_MASK, \
960 32 \
961 )
962
963 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_DST_MASK) > 32:
964 result.match.wildcards = wildcard_set(result.match.wildcards, \
965 ofp.OFPFW_NW_DST_MASK, \
966 32 \
967 )
968
Howard Persh07d99e62012-04-09 15:26:57 -0700969 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_VLAN) != 0:
970 result.match.wildcards = wildcard_set(result.match.wildcards, \
971 ofp.OFPFW_DL_VLAN_PCP, \
972 1 \
973 )
974
rootf6af1672012-04-06 09:46:29 -0700975 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700976 or result.match.eth_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700977 # dl_tyoe is wildcarded, or specified as something other
978 # than IP or ARP
Rich Laned0478ff2013-03-11 12:46:58 -0700979 # => ipv4_src, ipv4_dst, ip_proto cannot be specified,
Howard Persh07d99e62012-04-09 15:26:57 -0700980 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700981 result.match.wildcards = wildcard_set(result.match.wildcards, \
982 ofp.OFPFW_NW_SRC_MASK, \
983 32 \
984 )
985 result.match.wildcards = wildcard_set(result.match.wildcards, \
986 ofp.OFPFW_NW_DST_MASK, \
987 32 \
988 )
Howard Persh3340d452012-04-06 16:45:21 -0700989 result.match.wildcards = wildcard_set(result.match.wildcards, \
990 ofp.OFPFW_NW_PROTO, \
991 1 \
992 )
Howard Persh07d99e62012-04-09 15:26:57 -0700993
994 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700995 or result.match.eth_type != 0x0800:
996 # eth_type is wildcarded, or specified as something other than IP
997 # => ip_dscp, tcp_src and tcp_dst cannot be specified,
Howard Persh07d99e62012-04-09 15:26:57 -0700998 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700999 result.match.wildcards = wildcard_set(result.match.wildcards, \
1000 ofp.OFPFW_NW_TOS, \
1001 1 \
1002 )
1003 result.match.wildcards = wildcard_set(result.match.wildcards, \
1004 ofp.OFPFW_TP_SRC, \
1005 1 \
1006 )
1007 result.match.wildcards = wildcard_set(result.match.wildcards, \
1008 ofp.OFPFW_TP_DST, \
1009 1 \
1010 )
Howard Persh07d99e62012-04-09 15:26:57 -07001011 result.match.wildcards = wildcard_set(result.match.wildcards, \
1012 ofp.OFPFW_NW_SRC_MASK, \
1013 32 \
1014 )
1015 result.match.wildcards = wildcard_set(result.match.wildcards, \
1016 ofp.OFPFW_NW_DST_MASK, \
1017 32 \
1018 )
1019 result.match.wildcards = wildcard_set(result.match.wildcards, \
1020 ofp.OFPFW_NW_PROTO, \
1021 1 \
1022 )
1023
rootf6af1672012-04-06 09:46:29 -07001024 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
Rich Laned0478ff2013-03-11 12:46:58 -07001025 or result.match.ip_proto not in [1, 6, 17]:
1026 # ip_proto is wildcarded, or specified as something other than ICMP,
Howard Persh3340d452012-04-06 16:45:21 -07001027 # TCP or UDP
Rich Laned0478ff2013-03-11 12:46:58 -07001028 # => tcp_src and tcp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001029 result.match.wildcards = wildcard_set(result.match.wildcards, \
1030 ofp.OFPFW_TP_SRC, \
1031 1 \
1032 )
1033 result.match.wildcards = wildcard_set(result.match.wildcards, \
1034 ofp.OFPFW_TP_DST, \
1035 1 \
1036 )
rootf6af1672012-04-06 09:46:29 -07001037 return result
1038
Howard Persh680b92a2012-03-31 13:34:35 -07001039 # Overlap check
1040 # delf == True <=> Check for delete overlap, else add overlap
1041 # "Add overlap" is defined as there exists a packet that could match both the
1042 # receiver and argument flowspecs
1043 # "Delete overlap" is defined as the specificity of the argument flowspec
1044 # is greater than or equal to the specificity of the receiver flowspec
1045 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -07001046 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
1047 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001048 if self.match.in_port != x.match.in_port:
1049 return False # Both specified, and not equal
1050 elif delf:
1051 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001052 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
1053 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001054 if self.match.vlan_vid != x.match.vlan_vid:
Howard Persh680b92a2012-03-31 13:34:35 -07001055 return False # Both specified, and not equal
1056 elif delf:
1057 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001058 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
1059 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001060 if self.match.eth_src != x.match.eth_src:
Howard Persh680b92a2012-03-31 13:34:35 -07001061 return False # Both specified, and not equal
1062 elif delf:
1063 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001064 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
1065 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001066 if self.match.eth_dst != x.match.eth_dst:
Howard Persh680b92a2012-03-31 13:34:35 -07001067 return False # Both specified, and not equal
1068 elif delf:
1069 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001070 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
1071 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001072 if self.match.eth_type != x.match.eth_type:
Howard Persh680b92a2012-03-31 13:34:35 -07001073 return False # Both specified, and not equal
1074 elif delf:
1075 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -07001076 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
1077 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001078 if self.match.ip_proto != x.match.ip_proto:
Howard Persh680b92a2012-03-31 13:34:35 -07001079 return False # Both specified, and not equal
1080 elif delf:
1081 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001082 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
1083 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001084 if self.match.tcp_src != x.match.tcp_src:
Howard Persh680b92a2012-03-31 13:34:35 -07001085 return False # Both specified, and not equal
1086 elif delf:
1087 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001088 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
1089 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001090 if self.match.tcp_dst != x.match.tcp_dst:
Howard Persh680b92a2012-03-31 13:34:35 -07001091 return False # Both specified, and not equal
1092 elif delf:
1093 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001094 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
1095 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001096 if delf and na < nb:
1097 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001098 if (na < 32 and nb < 32):
1099 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
Rich Laned0478ff2013-03-11 12:46:58 -07001100 if (self.match.ipv4_src & m) != (x.match.ipv4_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -07001101 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -07001102 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
1103 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001104 if delf and na < nb:
1105 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001106 if (na < 32 and nb < 32):
1107 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
Rich Laned0478ff2013-03-11 12:46:58 -07001108 if (self.match.ipv4_dst & m) != (x.match.ipv4_dst & m):
rootf6af1672012-04-06 09:46:29 -07001109 return False # Overlapping bits not equal
1110 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
1111 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001112 if self.match.vlan_pcp != x.match.vlan_pcp:
Howard Persh680b92a2012-03-31 13:34:35 -07001113 return False # Both specified, and not equal
1114 elif delf:
1115 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001116 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
1117 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001118 if self.match.ip_dscp != x.match.ip_dscp:
Howard Persh680b92a2012-03-31 13:34:35 -07001119 return False # Both specified, and not equal
1120 elif delf:
1121 return False # Receiver more specific
1122 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -07001123
1124 def to_flow_mod_msg(self, msg):
1125 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -07001126 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001127 msg.idle_timeout = self.idle_timeout
1128 msg.hard_timeout = self.hard_timeout
1129 msg.priority = self.priority
1130 msg.actions = self.actions
1131 return msg
1132
1133 def from_flow_stat(self, msg):
1134 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -07001135 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001136 self.idle_timeout = msg.idle_timeout
1137 self.hard_timeout = msg.hard_timeout
1138 self.priority = msg.priority
1139 self.actions = msg.actions
1140
rootf6af1672012-04-06 09:46:29 -07001141 def from_flow_rem(self, msg):
1142 self.match = msg.match
1143 self.idle_timeout = msg.idle_timeout
1144 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -07001145
Howard Pershc7963582012-03-29 10:02:59 -07001146
rootf6af1672012-04-06 09:46:29 -07001147class Flow_Tbl:
1148 def clear(self):
1149 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001150
rootf6af1672012-04-06 09:46:29 -07001151 def __init__(self):
1152 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001153
rootf6af1672012-04-06 09:46:29 -07001154 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001155 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001156
1157 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001158 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001159
1160 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001161 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001162
1163 def values(self):
1164 return self.dict.values()
1165
1166 def count(self):
1167 return len(self.dict)
1168
Ed Swierk99a74de2012-08-22 06:40:54 -07001169 def rand(self, wildcards_force, sw, fi, num_flows):
rootf6af1672012-04-06 09:46:29 -07001170 self.clear()
1171 i = 0
1172 tbl = 0
1173 j = 0
1174 while i < num_flows:
1175 fc = Flow_Cfg()
1176 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001177 wildcards_force, \
Rich Lane5fd6faf2013-03-11 13:30:20 -07001178 sw.tbl_stats.entries[tbl].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001179 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001180 sw.valid_ports, \
1181 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001182 )
1183 fc = fc.canonical()
1184 if self.find(fc):
1185 continue
1186 fc.send_rem = False
1187 self.insert(fc)
1188 i = i + 1
1189 j = j + 1
Rich Lane5fd6faf2013-03-11 13:30:20 -07001190 if j >= sw.tbl_stats.entries[tbl].max_entries:
rootf6af1672012-04-06 09:46:29 -07001191 tbl = tbl + 1
1192 j = 0
1193
1194
1195class Switch:
1196 # Members:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001197 # controller - switch's test controller
1198 # sw_features - switch's OFPT_FEATURES_REPLY message
1199 # valid_ports - list of valid port numbers
1200 # valid_queues - list of valid [port, queue] pairs
1201 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1202 # queue_stats - switch's OFPT_STATS_REPLY message, for queue stats request
1203 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1204 # flow_tbl - (test's idea of) switch's flow table
rootf6af1672012-04-06 09:46:29 -07001205
1206 def __init__(self):
Howard Persh8d21c1f2012-04-20 15:57:29 -07001207 self.controller = None
1208 self.sw_features = None
1209 self.valid_ports = []
1210 self.valid_queues = []
1211 self.tbl_stats = None
1212 self.flow_stats = None
1213 self.flow_tbl = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001214 self.error_msgs = []
1215 self.removed_msgs = []
1216
1217 def error_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001218 logging.info("Got an ERROR message, type=%d, code=%d" \
Rich Laneb73808c2013-03-11 15:22:23 -07001219 % (msg.err_type, msg.code) \
Ed Swierk99a74de2012-08-22 06:40:54 -07001220 )
Ed Swierk99a74de2012-08-22 06:40:54 -07001221 self.error_msgs.append(msg)
1222
1223 def removed_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001224 logging.info("Got a REMOVED message")
Ed Swierk99a74de2012-08-22 06:40:54 -07001225 self.removed_msgs.append(msg)
rootf6af1672012-04-06 09:46:29 -07001226
Howard Persh3340d452012-04-06 16:45:21 -07001227 def controller_set(self, controller):
1228 self.controller = controller
1229 # Register error message handler
Ed Swierk99a74de2012-08-22 06:40:54 -07001230 self.error_msgs = []
1231 self.removed_msgs = []
1232 controller.register(ofp.OFPT_ERROR, self.error_handler)
1233 controller.register(ofp.OFPT_FLOW_REMOVED, self.removed_handler)
Howard Persh3340d452012-04-06 16:45:21 -07001234
rootf6af1672012-04-06 09:46:29 -07001235 def features_get(self):
1236 # Get switch features
Rich Lane28fa9272013-03-08 16:00:25 -08001237 request = ofp.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001238 (self.sw_features, pkt) = self.controller.transact(request)
rootf6af1672012-04-06 09:46:29 -07001239 if self.sw_features is None:
Rich Lane9a003812012-10-04 17:17:59 -07001240 logging.error("Get switch features failed")
rootf6af1672012-04-06 09:46:29 -07001241 return False
1242 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Rich Lane9a003812012-10-04 17:17:59 -07001243 logging.info("Ports reported by switch:")
1244 logging.info(self.valid_ports)
Rich Lane2014f9b2012-10-05 15:29:40 -07001245 ports_override = test_param_get("ports", [])
Howard Persh8d21c1f2012-04-20 15:57:29 -07001246 if ports_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001247 logging.info("Overriding ports to:")
1248 logging.info(ports_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001249 self.valid_ports = ports_override
1250
Howard Persh3340d452012-04-06 16:45:21 -07001251 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1252 # is that universal?
1253
1254 # TBD - There seems to be variability in which switches support which
1255 # ports; need to sort that out
1256 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1257# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1258# ofp.OFPP_NORMAL, \
1259# ofp.OFPP_FLOOD, \
1260# ofp.OFPP_ALL, \
1261# ofp.OFPP_CONTROLLER \
1262# ] \
1263# )
Rich Lane9a003812012-10-04 17:17:59 -07001264 logging.info("Supported actions reported by switch:")
1265 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001266 % (self.sw_features.actions, \
1267 actions_bmap_to_str(self.sw_features.actions) \
1268 ) \
1269 )
Rich Lane2014f9b2012-10-05 15:29:40 -07001270 actions_override = test_param_get("actions", -1)
Howard Persh07d99e62012-04-09 15:26:57 -07001271 if actions_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001272 logging.info("Overriding supported actions to:")
1273 logging.info(actions_bmap_to_str(actions_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001274 self.sw_features.actions = actions_override
rootf6af1672012-04-06 09:46:29 -07001275 return True
1276
1277 def tbl_stats_get(self):
1278 # Get table stats
Rich Lane28fa9272013-03-08 16:00:25 -08001279 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001280 (self.tbl_stats, pkt) = self.controller.transact(request)
Howard Persh07d99e62012-04-09 15:26:57 -07001281 if self.tbl_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001282 logging.error("Get table stats failed")
Howard Persh07d99e62012-04-09 15:26:57 -07001283 return False
Howard Persh8d21c1f2012-04-20 15:57:29 -07001284 i = 0
Rich Lane5fd6faf2013-03-11 13:30:20 -07001285 for ts in self.tbl_stats.entries:
Rich Lane9a003812012-10-04 17:17:59 -07001286 logging.info("Supported wildcards for table %d reported by switch:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001287 % (i)
1288 )
Rich Lane9a003812012-10-04 17:17:59 -07001289 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001290 % (ts.wildcards, \
1291 wildcards_to_str(ts.wildcards) \
1292 ) \
1293 )
Rich Lane2014f9b2012-10-05 15:29:40 -07001294 wildcards_override = test_param_get("wildcards", -1)
Howard Persh07d99e62012-04-09 15:26:57 -07001295 if wildcards_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001296 logging.info("Overriding supported wildcards for table %d to:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001297 % (i)
1298 )
Rich Lane9a003812012-10-04 17:17:59 -07001299 logging.info(wildcards_to_str(wildcards_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001300 ts.wildcards = wildcards_override
Howard Persh8d21c1f2012-04-20 15:57:29 -07001301 i = i + 1
Howard Persh07d99e62012-04-09 15:26:57 -07001302 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001303
Howard Persh8d21c1f2012-04-20 15:57:29 -07001304 def queue_stats_get(self):
1305 # Get queue stats
Rich Lane28fa9272013-03-08 16:00:25 -08001306 request = ofp.message.queue_stats_request()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001307 request.port_no = ofp.OFPP_ALL
1308 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001309 (self.queue_stats, pkt) = self.controller.transact(request)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001310 if self.queue_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001311 logging.error("Get queue stats failed")
Howard Persh8d21c1f2012-04-20 15:57:29 -07001312 return False
1313 self.valid_queues = map(lambda x: (x.port_no, x.queue_id), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07001314 self.queue_stats.entries \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001315 )
Rich Lane9a003812012-10-04 17:17:59 -07001316 logging.info("(Port, queue) pairs reported by switch:")
1317 logging.info(self.valid_queues)
Rich Lane2014f9b2012-10-05 15:29:40 -07001318 queues_override = test_param_get("queues", [])
Howard Persh8d21c1f2012-04-20 15:57:29 -07001319 if queues_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001320 logging.info("Overriding (port, queue) pairs to:")
1321 logging.info(queues_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001322 self.valid_queues = queues_override
1323 return True
1324
1325 def connect(self, controller):
1326 # Connect to controller, and get all switch capabilities
1327 self.controller_set(controller)
1328 return (self.features_get() \
1329 and self.tbl_stats_get() \
1330 and self.queue_stats_get() \
1331 )
1332
Howard Pershc1199d52012-04-11 14:21:32 -07001333 def flow_stats_get(self, limit = 10000):
Rich Lane28fa9272013-03-08 16:00:25 -08001334 request = ofp.message.flow_stats_request()
Rich Lane0237baf2013-03-11 22:34:59 -07001335 query_match = ofp.match()
Howard Persh680b92a2012-03-31 13:34:35 -07001336 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001337 request.match = query_match
1338 request.table_id = 0xff
1339 request.out_port = ofp.OFPP_NONE;
Rich Lane5c3151c2013-01-03 17:15:41 -08001340 self.controller.message_send(request)
Howard Persh3340d452012-04-06 16:45:21 -07001341 # <TBD>
1342 # Glue together successive reponse messages for stats reply.
1343 # Looking at the "more" flag and performing re-assembly
1344 # should be a part of the infrastructure.
1345 # </TBD>
1346 n = 0
1347 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -07001348 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY)
Howard Persh3340d452012-04-06 16:45:21 -07001349 if resp is None:
Howard Pershc1199d52012-04-11 14:21:32 -07001350 return False # Did not get expected response
Howard Persh3340d452012-04-06 16:45:21 -07001351 if n == 0:
1352 self.flow_stats = resp
1353 else:
Rich Lane5fd6faf2013-03-11 13:30:20 -07001354 self.flow_stats.entries.extend(resp.entries)
Howard Persh3340d452012-04-06 16:45:21 -07001355 n = n + 1
Rich Lane5fd6faf2013-03-11 13:30:20 -07001356 if len(self.flow_stats.entries) > limit:
Rich Lane9a003812012-10-04 17:17:59 -07001357 logging.error("Too many flows returned")
Howard Pershc1199d52012-04-11 14:21:32 -07001358 return False
1359 if (resp.flags & 1) == 0:
1360 break # No more responses expected
Howard Persh3340d452012-04-06 16:45:21 -07001361 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001362
rootf6af1672012-04-06 09:46:29 -07001363 def flow_add(self, flow_cfg, overlapf = False):
Rich Laneba3f0e22013-03-11 16:43:57 -07001364 flow_mod_msg = ofp.message.flow_add()
Howard Persh680b92a2012-03-31 13:34:35 -07001365 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001366 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001367 if overlapf:
1368 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001369 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001370 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Rich Laneb73808c2013-03-11 15:22:23 -07001371 flow_mod_msg.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001372 logging.info("Sending flow_mod(add), xid=%d"
Rich Laneb73808c2013-03-11 15:22:23 -07001373 % (flow_mod_msg.xid)
Howard Pershc1199d52012-04-11 14:21:32 -07001374 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001375 self.controller.message_send(flow_mod_msg)
1376 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001377
rootf6af1672012-04-06 09:46:29 -07001378 def flow_mod(self, flow_cfg, strictf):
Rich Laneba3f0e22013-03-11 16:43:57 -07001379 if strictf:
1380 flow_mod_msg = ofp.message.flow_modify_strict()
1381 else:
1382 flow_mod_msg = ofp.message.flow_modify()
Howard Persh680b92a2012-03-31 13:34:35 -07001383 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001384 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Rich Laneb73808c2013-03-11 15:22:23 -07001385 flow_mod_msg.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001386 logging.info("Sending flow_mod(mod), xid=%d"
Rich Laneb73808c2013-03-11 15:22:23 -07001387 % (flow_mod_msg.xid)
Howard Pershc1199d52012-04-11 14:21:32 -07001388 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001389 self.controller.message_send(flow_mod_msg)
1390 return True
rootf6af1672012-04-06 09:46:29 -07001391
1392 def flow_del(self, flow_cfg, strictf):
Rich Laneba3f0e22013-03-11 16:43:57 -07001393 if strictf:
1394 flow_mod_msg = ofp.message.flow_delete_strict()
1395 else:
1396 flow_mod_msg = ofp.message.flow_delete()
rootf6af1672012-04-06 09:46:29 -07001397 flow_mod_msg.buffer_id = 0xffffffff
1398 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001399 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001400 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Rich Laneb73808c2013-03-11 15:22:23 -07001401 flow_mod_msg.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001402 logging.info("Sending flow_mod(del), xid=%d"
Rich Laneb73808c2013-03-11 15:22:23 -07001403 % (flow_mod_msg.xid)
Howard Pershc1199d52012-04-11 14:21:32 -07001404 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001405 self.controller.message_send(flow_mod_msg)
1406 return True
rootf6af1672012-04-06 09:46:29 -07001407
1408 def barrier(self):
Rich Lane28fa9272013-03-08 16:00:25 -08001409 barrier = ofp.message.barrier_request()
Dan Talaycoc689a792012-09-28 14:22:53 -07001410 (resp, pkt) = self.controller.transact(barrier, 30)
rootf6af1672012-04-06 09:46:29 -07001411 return (resp is not None)
1412
Howard Persh3340d452012-04-06 16:45:21 -07001413 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001414 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001415 logging.info("Expecting %d error messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001416 num_got = len(self.error_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001417 logging.info("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001418 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001419 logging.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001420 result = False
1421 if num_exp == 0:
1422 return result
1423 elif num_exp == 1:
Rich Lane9a003812012-10-04 17:17:59 -07001424 logging.info("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001425 % (type, code) \
1426 )
1427 f = False
Ed Swierk99a74de2012-08-22 06:40:54 -07001428 for e in self.error_msgs:
Rich Laneb73808c2013-03-11 15:22:23 -07001429 if e.err_type == type and e.code == code:
Rich Lane9a003812012-10-04 17:17:59 -07001430 logging.info("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001431 f = True
1432 if not f:
Rich Lane9a003812012-10-04 17:17:59 -07001433 logging.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001434 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001435 else:
Rich Lane9a003812012-10-04 17:17:59 -07001436 logging.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001437 result = False
1438 return result
1439
Howard Persh3340d452012-04-06 16:45:21 -07001440 def removed_verify(self, num_exp):
1441 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001442 logging.info("Expecting %d removed messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001443 num_got = len(self.removed_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001444 logging.info("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001445 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001446 logging.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001447 result = False
1448 if num_exp < 2:
1449 return result
Rich Lane9a003812012-10-04 17:17:59 -07001450 logging.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001451 return False
1452
Howard Persh5f3c83f2012-04-13 09:57:10 -07001453 # modf == True <=> Verify for flow modify, else for add/delete
1454 def flow_tbl_verify(self, modf = False):
rootf6af1672012-04-06 09:46:29 -07001455 result = True
1456
1457 # Verify flow count in switch
Rich Lane9a003812012-10-04 17:17:59 -07001458 logging.info("Reading table stats")
1459 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001460 if not self.tbl_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001461 logging.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001462 return False
1463 n = 0
Rich Lane5fd6faf2013-03-11 13:30:20 -07001464 for ts in self.tbl_stats.entries:
rootf6af1672012-04-06 09:46:29 -07001465 n = n + ts.active_count
Rich Lane9a003812012-10-04 17:17:59 -07001466 logging.info("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001467 % (n) \
1468 )
1469 if n != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001470 logging.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001471 result = False
1472
1473 # Read flows from switch
Rich Lane9a003812012-10-04 17:17:59 -07001474 logging.info("Retrieving flows from switch")
1475 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001476 if not self.flow_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001477 logging.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001478 return False
Rich Lane5fd6faf2013-03-11 13:30:20 -07001479 logging.info("Retrieved %d flows" % (len(self.flow_stats.entries)))
rootf6af1672012-04-06 09:46:29 -07001480
1481 # Verify flows returned by switch
1482
Rich Lane5fd6faf2013-03-11 13:30:20 -07001483 if len(self.flow_stats.entries) != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001484 logging.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001485 result = False
1486
Rich Lane9a003812012-10-04 17:17:59 -07001487 logging.info("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001488 for fc in self.flow_tbl.values():
1489 fc.matched = False
Rich Lane5fd6faf2013-03-11 13:30:20 -07001490 for fs in self.flow_stats.entries:
rootf6af1672012-04-06 09:46:29 -07001491 flow_in = Flow_Cfg()
1492 flow_in.from_flow_stat(fs)
Rich Lane15a15062013-08-12 23:11:12 -07001493 flow_in = flow_in.canonical()
Rich Lane9a003812012-10-04 17:17:59 -07001494 logging.info("Received flow:")
1495 logging.info(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001496 fc = self.flow_tbl.find(flow_in)
1497 if fc is None:
Rich Lane9a003812012-10-04 17:17:59 -07001498 logging.error("Received flow:")
1499 logging.error(str(flow_in))
1500 logging.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001501 result = False
1502 elif fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001503 logging.error("Received flow:")
1504 logging.error(str(flow_in))
1505 logging.error("re-matches defined flow:")
1506 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001507 result = False
1508 else:
Rich Lane9a003812012-10-04 17:17:59 -07001509 logging.info("matched")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001510 if modf:
1511 # Check for modify
1512
1513 if flow_in.cookie != fc.cookie:
Rich Lane9a003812012-10-04 17:17:59 -07001514 logging.warning("Defined flow:")
1515 logging.warning(str(fc))
1516 logging.warning("Received flow:")
1517 logging.warning(str(flow_in))
1518 logging.warning("cookies do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001519 if not flow_in.actions_equal(fc):
Rich Lane9a003812012-10-04 17:17:59 -07001520 logging.error("Defined flow:")
1521 logging.error(str(fc))
1522 logging.error("Received flow:")
1523 logging.error(str(flow_in))
1524 logging.error("actions do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001525 else:
1526 # Check for add/delete
1527
1528 if not flow_in == fc:
Rich Lane9a003812012-10-04 17:17:59 -07001529 logging.error("Defined flow:")
1530 logging.error(str(fc))
1531 logging.error("Received flow:")
1532 logging.error(str(flow_in))
1533 logging.error("non-key portions of flow do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001534 result = False
rootf6af1672012-04-06 09:46:29 -07001535 fc.matched = True
1536 for fc in self.flow_tbl.values():
1537 if not fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001538 logging.error("Defined flow:")
1539 logging.error(str(fc))
1540 logging.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001541 result = False
1542
1543 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001544
Howard Persh9cab4822012-09-11 17:08:40 -07001545 def settle(self):
1546 time.sleep(2)
1547
Howard Persh07d99e62012-04-09 15:26:57 -07001548# FLOW ADD 5
1549#
1550# OVERVIEW
1551# Add flows to switch, read back and verify flow configurations
1552#
1553# PURPOSE
1554# - Test acceptance of flow adds
1555# - Test ability of switch to process additions to flow table in random
1556# priority order
1557# - Test correctness of flow configuration responses
1558#
1559# PARAMETERS
1560#
1561# Name: num_flows
1562# Type: number
1563# Description:
1564# Number of flows to define; 0 => maximum number of flows, as determined
1565# from switch capabilities
1566# Default: 100
1567#
1568# PROCESS
1569# 1. Delete all flows from switch
1570# 2. Generate <num_flows> distinct flow configurations
1571# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1572# 4. Verify that no OFPT_ERROR responses were generated by switch
1573# 5. Retrieve flow stats from switch
1574# 6. Compare flow configurations returned by switch
1575# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1576# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001577
Rich Laneb90a1c42012-10-05 09:16:05 -07001578class Flow_Add_5(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001579 """
1580 Test FLOW_ADD_5 from draft top-half test plan
1581
1582 INPUTS
1583 num_flows - Number of flows to generate
1584 """
Howard Persh680b92a2012-03-31 13:34:35 -07001585
rootf6af1672012-04-06 09:46:29 -07001586 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001587 logging.info("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001588
Rich Lane2014f9b2012-10-05 15:29:40 -07001589 num_flows = test_param_get("num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001590
Howard Pershc7963582012-03-29 10:02:59 -07001591 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001592
Rich Lane9a003812012-10-04 17:17:59 -07001593 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001594 delete_all_flows(self.controller)
Howard Pershc7963582012-03-29 10:02:59 -07001595
rootf6af1672012-04-06 09:46:29 -07001596 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001597
rootf6af1672012-04-06 09:46:29 -07001598 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001599 self.assertTrue(sw.connect(self.controller), \
1600 "Failed to connect to switch" \
1601 )
Howard Pershc7963582012-03-29 10:02:59 -07001602
rootf6af1672012-04-06 09:46:29 -07001603 if num_flows == 0:
1604 # Number of flows requested was 0
1605 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001606
Rich Lane5fd6faf2013-03-11 13:30:20 -07001607 for ts in sw.tbl_stats.entries:
rootf6af1672012-04-06 09:46:29 -07001608 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001609
Rich Lane9a003812012-10-04 17:17:59 -07001610 logging.info("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001611
1612 # Dream up some flow information, i.e. space to chose from for
1613 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001614
rootf6af1672012-04-06 09:46:29 -07001615 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001616 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001617
rootf6af1672012-04-06 09:46:29 -07001618 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001619
rootf6af1672012-04-06 09:46:29 -07001620 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001621 ft.rand(required_wildcards(self), sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001622
rootf6af1672012-04-06 09:46:29 -07001623 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001624
Rich Lane9a003812012-10-04 17:17:59 -07001625 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001626 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001627 logging.info("Adding flow:")
1628 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001629 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001630
rootf6af1672012-04-06 09:46:29 -07001631 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001632
rootf6af1672012-04-06 09:46:29 -07001633 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001634
rootf6af1672012-04-06 09:46:29 -07001635 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001636
Howard Persh9cab4822012-09-11 17:08:40 -07001637 sw.settle() # Allow switch to settle and generate any notifications
1638
rootf6af1672012-04-06 09:46:29 -07001639 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001640
rootf6af1672012-04-06 09:46:29 -07001641 if not sw.errors_verify(0):
1642 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001643
rootf6af1672012-04-06 09:46:29 -07001644 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001645
rootf6af1672012-04-06 09:46:29 -07001646 sw.flow_tbl = ft
1647 if not sw.flow_tbl_verify():
1648 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001649
rootf6af1672012-04-06 09:46:29 -07001650 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001651 logging.info("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001652
Howard Pershc7963582012-03-29 10:02:59 -07001653
Howard Persh07d99e62012-04-09 15:26:57 -07001654# FLOW ADD 5_1
1655#
1656# OVERVIEW
1657# Verify handling of non-canonical flows
1658#
1659# PURPOSE
1660# - Test that switch detects and correctly responds to a non-canonical flow
1661# definition. A canonical flow is one that satisfies all match qualifier
1662# dependencies; a non-canonical flow is one that does not.
1663#
1664# PARAMETERS
1665# - None
1666#
1667# PROCESS
1668# 1. Delete all flows from switch
1669# 2. Generate 1 flow definition, which is different from its canonicalization
1670# 3. Send flow to switch
1671# 4. Retrieve flow from switch
1672# 5. Compare returned flow to canonical form of defined flow
1673# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1674
1675# Disabled.
1676# Should be DUT dependent.
Howard Persh07d99e62012-04-09 15:26:57 -07001677
Rich Lane0a4f6372013-01-02 14:40:22 -08001678@nonstandard
Rich Laneb90a1c42012-10-05 09:16:05 -07001679class Flow_Add_5_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001680 """
1681 Test FLOW_ADD_5.1 from draft top-half test plan
1682
1683 INPUTS
1684 None
1685 """
Rich Laned1d9c282012-10-04 22:07:10 -07001686
rootf6af1672012-04-06 09:46:29 -07001687 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001688 logging.info("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001689
Rich Lane2014f9b2012-10-05 15:29:40 -07001690 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001691
1692 # Clear all flows from switch
1693
Rich Lane9a003812012-10-04 17:17:59 -07001694 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001695 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001696
1697 # Get switch capabilites
1698
rootf6af1672012-04-06 09:46:29 -07001699 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001700 self.assertTrue(sw.connect(self.controller), \
1701 "Failed to connect to switch" \
1702 )
rootf6af1672012-04-06 09:46:29 -07001703
1704 # Dream up some flow information, i.e. space to chose from for
1705 # random flow parameter generation
1706
1707 fi = Flow_Info()
1708 fi.rand(10)
1709
1710 # Dream up a flow config that will be canonicalized by the switch
1711
1712 while True:
1713 fc = Flow_Cfg()
1714 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001715 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07001716 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001717 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001718 sw.valid_ports, \
1719 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001720 )
1721 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001722 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001723 break
1724
1725 ft = Flow_Tbl()
1726 ft.insert(fcc)
1727
1728 # Send it to the switch
1729
Rich Lane9a003812012-10-04 17:17:59 -07001730 logging.info("Sending flow add to switch:")
1731 logging.info(str(fc))
1732 logging.info("should be canonicalized as:")
1733 logging.info(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001734 fc.send_rem = False
1735 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1736
1737 # Do barrier, to make sure all flows are in
1738
1739 self.assertTrue(sw.barrier(), "Barrier failed")
1740
1741 result = True
1742
Howard Persh9cab4822012-09-11 17:08:40 -07001743 sw.settle() # Allow switch to settle and generate any notifications
1744
rootf6af1672012-04-06 09:46:29 -07001745 # Check for any error messages
1746
1747 if not sw.errors_verify(0):
1748 result = False
1749
1750 # Verify flow table
1751
1752 sw.flow_tbl = ft
1753 if not sw.flow_tbl_verify():
1754 result = False
1755
1756 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001757 logging.info("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001758
1759
Howard Persh07d99e62012-04-09 15:26:57 -07001760# FLOW ADD 6
1761#
1762# OVERVIEW
1763# Test flow table capacity
1764#
1765# PURPOSE
1766# - Test switch can accept as many flow definitions as it claims
1767# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1768# - Test that attempting to create flows beyond capacity does not corrupt
1769# flow table
1770#
1771# PARAMETERS
1772# None
1773#
1774# PROCESS
1775# 1. Delete all flows from switch
1776# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1777# to determine flow table size, N
1778# 3. Generate (N + 1) distinct flow configurations
1779# 4. Send N flow adds to switch, for flows generated in step 3 above
1780# 5. Verify flow table in switch
1781# 6. Send one more flow add to switch
1782# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1783# response was generated by switch, for last flow mod sent
1784# 7. Retrieve flow stats from switch
1785# 8. Verify flow table in switch
1786# 9. Test PASSED iff:
1787# - error message received, for correct flow
1788# - last flow definition sent to switch is not in flow table
1789# else test FAILED
1790
Howard Persh3340d452012-04-06 16:45:21 -07001791# Disabled because of bogus capacity reported by OVS.
1792# Should be DUT dependent.
Howard Persh3340d452012-04-06 16:45:21 -07001793
Rich Lane0a4f6372013-01-02 14:40:22 -08001794@nonstandard
Rich Laneb90a1c42012-10-05 09:16:05 -07001795class Flow_Add_6(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001796 """
1797 Test FLOW_ADD_6 from draft top-half test plan
1798
1799 INPUTS
1800 num_flows - Number of flows to generate
1801 """
Howard Pershc7963582012-03-29 10:02:59 -07001802
1803 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001804 logging.info("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001805
rootf6af1672012-04-06 09:46:29 -07001806 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001807
Rich Lane9a003812012-10-04 17:17:59 -07001808 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001809 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001810
1811 # Get switch capabilites
1812
rootf6af1672012-04-06 09:46:29 -07001813 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001814 self.assertTrue(sw.connect(self.controller), \
1815 "Failed to connect to switch" \
1816 )
rootf6af1672012-04-06 09:46:29 -07001817
root2843d2b2012-04-06 10:27:46 -07001818 num_flows = 0
Rich Lane5fd6faf2013-03-11 13:30:20 -07001819 for ts in sw.tbl_stats.entries:
rootf6af1672012-04-06 09:46:29 -07001820 num_flows = num_flows + ts.max_entries
1821
Rich Lane9a003812012-10-04 17:17:59 -07001822 logging.info("Switch capacity is %d flows" % (num_flows))
1823 logging.info("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001824
1825 # Dream up some flow information, i.e. space to chose from for
1826 # random flow parameter generation
1827
1828 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001829 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001830
1831 # Create a flow table, to switch's capacity
1832
1833 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001834 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07001835
1836 # Send flow table to switch
1837
Rich Lane9a003812012-10-04 17:17:59 -07001838 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001839 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001840 logging.info("Adding flow:")
1841 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001842 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1843
1844 # Do barrier, to make sure all flows are in
1845
1846 self.assertTrue(sw.barrier(), "Barrier failed")
1847
1848 result = True
1849
Howard Persh9cab4822012-09-11 17:08:40 -07001850 sw.settle() # Allow switch to settle and generate any notifications
1851
rootf6af1672012-04-06 09:46:29 -07001852 # Check for any error messages
1853
1854 if not sw.errors_verify(0):
1855 result = False
1856
1857 # Dream up one more flow
1858
Rich Lane9a003812012-10-04 17:17:59 -07001859 logging.info("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001860 while True:
1861 fc = Flow_Cfg()
1862 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001863 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07001864 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001865 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001866 sw.valid_ports, \
1867 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001868 )
1869 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001870 if not ft.find(fc):
1871 break
rootf6af1672012-04-06 09:46:29 -07001872
1873 # Send one-more flow
1874
1875 fc.send_rem = False
Rich Lane9a003812012-10-04 17:17:59 -07001876 logging.info("Sending flow add switch")
1877 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001878 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1879
1880 # Do barrier, to make sure all flows are in
1881
1882 self.assertTrue(sw.barrier(), "Barrier failed")
1883
Howard Persh9cab4822012-09-11 17:08:40 -07001884 sw.settle() # Allow switch to settle and generate any notifications
1885
rootf6af1672012-04-06 09:46:29 -07001886 # Check for expected error message
1887
1888 if not sw.errors_verify(1, \
1889 ofp.OFPET_FLOW_MOD_FAILED, \
1890 ofp.OFPFMFC_ALL_TABLES_FULL \
1891 ):
1892 result = False
1893
1894 # Verify flow table
1895
1896 sw.flow_tbl = ft
1897 if not sw.flow_tbl_verify():
1898 result = False
1899
1900 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001901 logging.info("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001902
1903
Howard Persh07d99e62012-04-09 15:26:57 -07001904# FLOW ADD 7
1905#
1906# OVERVIEW
1907# Test flow redefinition
1908#
1909# PURPOSE
1910# Verify that successive flow adds with same priority and match criteria
1911# overwrite in flow table
1912#
1913# PARAMETERS
1914# None
1915#
1916# PROCESS
1917# 1. Delete all flows from switch
1918# 2. Generate flow definition F1
1919# 3. Generate flow definition F2, with same key (priority and match) as F1,
1920# but with different actions
1921# 4. Send flow adds for F1 and F2 to switch
1922# 5. Verify flow definitions in switch
1923# 6. Test PASSED iff 1 flow returned by switch, matching configuration of F2;
1924# else test FAILED
1925
Rich Laneb90a1c42012-10-05 09:16:05 -07001926class Flow_Add_7(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001927 """
1928 Test FLOW_ADD_7 from draft top-half test plan
1929
1930 INPUTS
1931 None
1932 """
1933
1934 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001935 logging.info("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001936
1937 # Clear all flows from switch
1938
Rich Lane9a003812012-10-04 17:17:59 -07001939 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001940 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001941
1942 # Get switch capabilites
1943
rootf6af1672012-04-06 09:46:29 -07001944 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001945 self.assertTrue(sw.connect(self.controller), \
1946 "Failed to connect to switch" \
1947 )
rootf6af1672012-04-06 09:46:29 -07001948
1949 # Dream up some flow information, i.e. space to chose from for
1950 # random flow parameter generation
1951
1952 fi = Flow_Info()
1953 fi.rand(10)
1954
1955 # Dream up a flow config
1956
1957 fc = Flow_Cfg()
1958 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001959 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07001960 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001961 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001962 sw.valid_ports, \
1963 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001964 )
1965 fc = fc.canonical()
1966
1967 # Send it to the switch
1968
Rich Lane9a003812012-10-04 17:17:59 -07001969 logging.info("Sending flow add to switch:")
1970 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001971 ft = Flow_Tbl()
1972 fc.send_rem = False
1973 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1974 ft.insert(fc)
1975
1976 # Dream up some different actions, with the same flow key
1977
1978 fc2 = copy.deepcopy(fc)
1979 while True:
1980 fc2.rand_mod(fi, \
1981 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001982 sw.valid_ports, \
1983 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001984 )
1985 if fc2 != fc:
1986 break
1987
1988 # Send that to the switch
1989
Rich Lane9a003812012-10-04 17:17:59 -07001990 logging.info("Sending flow add to switch:")
1991 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07001992 fc2.send_rem = False
1993 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
1994 ft.insert(fc2)
1995
1996 # Do barrier, to make sure all flows are in
1997
1998 self.assertTrue(sw.barrier(), "Barrier failed")
1999
2000 result = True
2001
Howard Persh9cab4822012-09-11 17:08:40 -07002002 sw.settle() # Allow switch to settle and generate any notifications
2003
rootf6af1672012-04-06 09:46:29 -07002004 # Check for any error messages
2005
2006 if not sw.errors_verify(0):
2007 result = False
2008
2009 # Verify flow table
2010
2011 sw.flow_tbl = ft
2012 if not sw.flow_tbl_verify():
2013 result = False
2014
2015 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002016 logging.info("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002017
2018
Howard Persh07d99e62012-04-09 15:26:57 -07002019# FLOW ADD 8
2020#
2021# OVERVIEW
2022# Add overlapping flows to switch, verify that overlapping flows are rejected
2023#
2024# PURPOSE
2025# - Test detection of overlapping flows by switch
2026# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
2027# - Test rejection of overlapping flows
2028# - Test defining overlapping flows does not corrupt flow table
2029#
2030# PARAMETERS
2031# None
2032#
2033# PROCESS
2034# 1. Delete all flows from switch
2035# 2. Generate flow definition F1
2036# 3. Generate flow definition F2, with key overlapping F1
2037# 4. Send flow add to switch, for F1
2038# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
2039# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
2040# was generated by switch
2041# 7. Verifiy flows configured in swtich
2042# 8. Test PASSED iff:
2043# - error message received, for overlapping flow
2044# - overlapping flow is not in flow table
2045# else test FAILED
2046
Rich Laneb90a1c42012-10-05 09:16:05 -07002047class Flow_Add_8(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002048 """
2049 Test FLOW_ADD_8 from draft top-half test plan
2050
2051 INPUTS
2052 None
2053 """
2054
2055 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002056 logging.info("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002057
2058 # Clear all flows from switch
2059
Rich Lane9a003812012-10-04 17:17:59 -07002060 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002061 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002062
2063 # Get switch capabilites
2064
rootf6af1672012-04-06 09:46:29 -07002065 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002066 self.assertTrue(sw.connect(self.controller), \
2067 "Failed to connect to switch" \
2068 )
rootf6af1672012-04-06 09:46:29 -07002069
2070 # Dream up some flow information, i.e. space to chose from for
2071 # random flow parameter generation
2072
2073 fi = Flow_Info()
2074 fi.rand(10)
2075
2076 # Dream up a flow config, with at least 1 qualifier specified
2077
2078 fc = Flow_Cfg()
2079 while True:
2080 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002081 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002082 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002083 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002084 sw.valid_ports, \
2085 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002086 )
2087 fc = fc.canonical()
2088 if fc.match.wildcards != ofp.OFPFW_ALL:
2089 break
2090
2091 # Send it to the switch
2092
Rich Lane9a003812012-10-04 17:17:59 -07002093 logging.info("Sending flow add to switch:")
2094 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002095 ft = Flow_Tbl()
2096 fc.send_rem = False
2097 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2098 ft.insert(fc)
2099
2100 # Wildcard out one qualifier that was specified, to create an
2101 # overlapping flow
2102
2103 fc2 = copy.deepcopy(fc)
2104 for wi in shuffle(range(len(all_wildcards_list))):
2105 w = all_wildcards_list[wi]
2106 if (fc2.match.wildcards & w) == 0:
2107 break
2108 if w == ofp.OFPFW_NW_SRC_MASK:
2109 w = ofp.OFPFW_NW_SRC_ALL
2110 wn = "OFPFW_NW_SRC"
2111 elif w == ofp.OFPFW_NW_DST_MASK:
2112 w = ofp.OFPFW_NW_DST_ALL
2113 wn = "OFPFW_NW_DST"
2114 else:
2115 wn = all_wildcard_names[w]
Rich Lane9a003812012-10-04 17:17:59 -07002116 logging.info("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07002117 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07002118 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07002119
2120 # Send that to the switch, with overlap checking
2121
Rich Lane9a003812012-10-04 17:17:59 -07002122 logging.info("Sending flow add to switch:")
2123 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002124 fc2.send_rem = False
2125 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
2126
2127 # Do barrier, to make sure all flows are in
2128 self.assertTrue(sw.barrier(), "Barrier failed")
2129
2130 result = True
2131
Howard Persh9cab4822012-09-11 17:08:40 -07002132 sw.settle() # Allow switch to settle and generate any notifications
2133
rootf6af1672012-04-06 09:46:29 -07002134 # Check for expected error message
2135
2136 if not sw.errors_verify(1, \
2137 ofp.OFPET_FLOW_MOD_FAILED, \
2138 ofp.OFPFMFC_OVERLAP \
2139 ):
2140 result = False
2141
2142 # Verify flow table
2143
2144 sw.flow_tbl = ft
2145 if not sw.flow_tbl_verify():
2146 result = False
2147
2148 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002149 logging.info("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002150
2151
Howard Persh07d99e62012-04-09 15:26:57 -07002152# FLOW MODIFY 1
2153#
2154# OVERVIEW
2155# Strict modify of single existing flow
2156#
2157# PURPOSE
2158# - Verify that strict flow modify operates only on specified flow
2159# - Verify that flow is correctly modified
2160#
2161# PARAMETERS
2162# None
2163#
2164# PROCESS
2165# 1. Delete all flows from switch
2166# 2. Generate 1 flow F
2167# 3. Send flow add to switch, for flow F
2168# 4. Generate new action list for flow F, yielding F'
2169# 5. Send strict flow modify to switch, for flow F'
2170# 6. Verify flow table in switch
2171# 7. Test PASSED iff flow returned by switch is F'; else FAILED
2172
Rich Laneb90a1c42012-10-05 09:16:05 -07002173class Flow_Mod_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002174 """
2175 Test FLOW_MOD_1 from draft top-half test plan
2176
2177 INPUTS
2178 None
2179 """
2180
2181 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002182 logging.info("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002183
2184 # Clear all flows from switch
2185
Rich Lane9a003812012-10-04 17:17:59 -07002186 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002187 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002188
2189 # Get switch capabilites
2190
rootf6af1672012-04-06 09:46:29 -07002191 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002192 self.assertTrue(sw.connect(self.controller), \
2193 "Failed to connect to switch" \
2194 )
rootf6af1672012-04-06 09:46:29 -07002195
2196 # Dream up some flow information, i.e. space to chose from for
2197 # random flow parameter generation
2198
2199 fi = Flow_Info()
2200 fi.rand(10)
2201
2202 # Dream up a flow config
2203
2204 fc = Flow_Cfg()
2205 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002206 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002207 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002208 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002209 sw.valid_ports, \
2210 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002211 )
2212 fc = fc.canonical()
2213
2214 # Send it to the switch
2215
Rich Lane9a003812012-10-04 17:17:59 -07002216 logging.info("Sending flow add to switch:")
2217 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002218 ft = Flow_Tbl()
2219 fc.send_rem = False
2220 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2221 ft.insert(fc)
2222
2223 # Dream up some different actions, with the same flow key
2224
2225 fc2 = copy.deepcopy(fc)
2226 while True:
2227 fc2.rand_mod(fi, \
2228 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002229 sw.valid_ports, \
2230 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002231 )
2232 if fc2 != fc:
2233 break
2234
2235 # Send that to the switch
2236
Rich Lane9a003812012-10-04 17:17:59 -07002237 logging.info("Sending strict flow mod to switch:")
2238 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002239 fc2.send_rem = False
2240 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2241 ft.insert(fc2)
2242
2243 # Do barrier, to make sure all flows are in
2244
2245 self.assertTrue(sw.barrier(), "Barrier failed")
2246
2247 result = True
2248
Howard Persh9cab4822012-09-11 17:08:40 -07002249 sw.settle() # Allow switch to settle and generate any notifications
2250
rootf6af1672012-04-06 09:46:29 -07002251 # Check for any error messages
2252
2253 if not sw.errors_verify(0):
2254 result = False
2255
2256 # Verify flow table
2257
2258 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002259 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002260 result = False
2261
2262 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002263 logging.info("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002264
Howard Persh07d99e62012-04-09 15:26:57 -07002265
2266# FLOW MODIFY 2
2267#
2268# OVERVIEW
2269# Loose modify of mutiple flows
2270#
2271# PURPOSE
2272# - Verify that loose flow modify operates only on matching flows
2273# - Verify that matching flows are correctly modified
2274#
2275# PARAMETERS
2276# Name: num_flows
2277# Type: number
2278# Description:
2279# Number of flows to define
2280# Default: 100
2281#
2282# PROCESS
2283# 1. Delete all flows from switch
2284# 2. Generate <num_flows> distinct flow configurations
2285# 3. Send <num_flows> flow adds to switch
2286# 4. Pick 1 defined flow F at random
2287# 5. Create overlapping loose flow mod match criteria by repeatedly
2288# wildcarding out qualifiers in match of F => F',
2289# and create new actions list A' for F'
2290# 6. Send loose flow modify for F' to switch
2291# 7. Verify flow table in swtich
2292# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2293# are returned in step 7 above, each with correct (original or modified)
2294# action list;
2295# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002296
Rich Laneb90a1c42012-10-05 09:16:05 -07002297class Flow_Mod_2(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002298 """
2299 Test FLOW_MOD_2 from draft top-half test plan
2300
2301 INPUTS
2302 None
2303 """
2304
2305 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002306 logging.info("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002307
Rich Lane2014f9b2012-10-05 15:29:40 -07002308 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002309
2310 # Clear all flows from switch
2311
Rich Lane9a003812012-10-04 17:17:59 -07002312 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002313 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002314
2315 # Get switch capabilites
2316
rootf6af1672012-04-06 09:46:29 -07002317 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002318 self.assertTrue(sw.connect(self.controller), \
2319 "Failed to connect to switch" \
2320 )
rootf6af1672012-04-06 09:46:29 -07002321
2322 # Dream up some flow information, i.e. space to chose from for
2323 # random flow parameter generation
2324
2325 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002326 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002327 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002328
2329 # Dream up some flows
2330
2331 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002332 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002333
2334 # Send flow table to switch
2335
Rich Lane9a003812012-10-04 17:17:59 -07002336 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002337 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002338 logging.info("Adding flow:")
2339 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002340 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2341
2342 # Do barrier, to make sure all flows are in
2343
2344 self.assertTrue(sw.barrier(), "Barrier failed")
2345
2346 result = True
2347
Howard Persh9cab4822012-09-11 17:08:40 -07002348 sw.settle() # Allow switch to settle and generate any notifications
2349
rootf6af1672012-04-06 09:46:29 -07002350 # Check for any error messages
2351
2352 if not sw.errors_verify(0):
2353 result = False
2354
2355 # Verify flow table
2356
2357 sw.flow_tbl = ft
2358 if not sw.flow_tbl_verify():
2359 result = False
2360
2361 # Pick a random flow as a basis
Howard Persh5f3c83f2012-04-13 09:57:10 -07002362
2363 mfc = copy.deepcopy((ft.values())[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002364 mfc.rand_mod(fi, \
2365 sw.sw_features.actions, \
2366 sw.valid_ports, \
2367 sw.valid_queues \
2368 )
rootf6af1672012-04-06 09:46:29 -07002369
2370 # Repeatedly wildcard qualifiers
2371
2372 for wi in shuffle(range(len(all_wildcards_list))):
2373 w = all_wildcards_list[wi]
2374 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2375 n = wildcard_get(mfc.match.wildcards, w)
2376 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002377 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2378 w, \
2379 random.randint(n + 1, 32) \
2380 )
rootf6af1672012-04-06 09:46:29 -07002381 else:
2382 continue
2383 else:
2384 if wildcard_get(mfc.match.wildcards, w) == 0:
2385 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2386 else:
2387 continue
2388 mfc = mfc.canonical()
2389
2390 # Count the number of flows that would be modified
2391
2392 n = 0
2393 for fc in ft.values():
2394 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2395 n = n + 1
2396
2397 # If more than 1, we found our loose delete flow spec
2398 if n > 1:
2399 break
2400
Rich Lane9a003812012-10-04 17:17:59 -07002401 logging.info("Modifying %d flows" % (n))
2402 logging.info("Sending flow mod to switch:")
2403 logging.info(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002404 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2405
2406 # Do barrier, to make sure all flows are in
2407 self.assertTrue(sw.barrier(), "Barrier failed")
2408
Howard Persh9cab4822012-09-11 17:08:40 -07002409 sw.settle() # Allow switch to settle and generate any notifications
2410
rootf6af1672012-04-06 09:46:29 -07002411 # Check for error message
2412
2413 if not sw.errors_verify(0):
2414 result = False
2415
2416 # Apply flow mod to local flow table
2417
2418 for fc in ft.values():
2419 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002420 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002421
2422 # Verify flow table
2423
2424 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002425 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002426 result = False
2427
2428 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002429 logging.info("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002430
2431
Howard Persh07d99e62012-04-09 15:26:57 -07002432# FLOW MODIFY 3
2433
2434# OVERVIEW
2435# Strict modify of non-existent flow
2436#
2437# PURPOSE
2438# Verify that strict modify of a non-existent flow is equivalent to a flow add
2439#
2440# PARAMETERS
2441# None
2442#
2443# PROCESS
2444# 1. Delete all flows from switch
2445# 2. Send single flow mod, as strict modify, to switch
2446# 3. Verify flow table in switch
2447# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2448
Rich Laneb90a1c42012-10-05 09:16:05 -07002449class Flow_Mod_3(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002450 """
2451 Test FLOW_MOD_3 from draft top-half test plan
2452
2453 INPUTS
2454 None
2455 """
2456
2457 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002458 logging.info("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002459
2460 # Clear all flows from switch
2461
Rich Lane9a003812012-10-04 17:17:59 -07002462 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002463 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002464
2465 # Get switch capabilites
2466
rootf6af1672012-04-06 09:46:29 -07002467 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002468 self.assertTrue(sw.connect(self.controller), \
2469 "Failed to connect to switch" \
2470 )
rootf6af1672012-04-06 09:46:29 -07002471
2472 # Dream up some flow information, i.e. space to chose from for
2473 # random flow parameter generation
2474
2475 fi = Flow_Info()
2476 fi.rand(10)
2477
2478 # Dream up a flow config
2479
2480 fc = Flow_Cfg()
2481 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002482 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002483 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002484 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002485 sw.valid_ports, \
2486 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002487 )
2488 fc = fc.canonical()
2489
2490 # Send it to the switch
2491
Rich Lane9a003812012-10-04 17:17:59 -07002492 logging.info("Sending flow mod to switch:")
2493 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002494 ft = Flow_Tbl()
2495 fc.send_rem = False
2496 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2497 ft.insert(fc)
2498
2499 # Do barrier, to make sure all flows are in
2500
2501 self.assertTrue(sw.barrier(), "Barrier failed")
2502
2503 result = True
2504
Howard Persh9cab4822012-09-11 17:08:40 -07002505 sw.settle() # Allow switch to settle and generate any notifications
2506
rootf6af1672012-04-06 09:46:29 -07002507 # Check for any error messages
2508
2509 if not sw.errors_verify(0):
2510 result = False
2511
2512 # Verify flow table
2513
2514 sw.flow_tbl = ft
2515 if not sw.flow_tbl_verify():
2516 result = False
2517
2518 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002519 logging.info("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002520
2521
Howard Persh8d21c1f2012-04-20 15:57:29 -07002522# FLOW MODIFY 3_1
2523
2524# OVERVIEW
2525# No-op modify
2526#
2527# PURPOSE
2528# Verify that modify of a flow with new actions same as old ones operates correctly
2529#
2530# PARAMETERS
2531# None
2532#
2533# PROCESS
2534# 1. Delete all flows from switch
2535# 2. Send single flow mod, as strict modify, to switch
2536# 3. Verify flow table in switch
2537# 4. Send same flow mod, as strict modify, to switch
2538# 5. Verify flow table in switch
2539# 6. Test PASSED iff flow defined in step 2 and 4 above verified; else FAILED
2540
Rich Laneb90a1c42012-10-05 09:16:05 -07002541class Flow_Mod_3_1(base_tests.SimpleProtocol):
Howard Persh8d21c1f2012-04-20 15:57:29 -07002542 """
2543 Test FLOW_MOD_3_1 from draft top-half test plan
2544
2545 INPUTS
2546 None
2547 """
2548
2549 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002550 logging.info("Flow_Mod_3_1 TEST BEGIN")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002551
2552 # Clear all flows from switch
2553
Rich Lane9a003812012-10-04 17:17:59 -07002554 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002555 delete_all_flows(self.controller)
Howard Persh8d21c1f2012-04-20 15:57:29 -07002556
2557 # Get switch capabilites
2558
2559 sw = Switch()
2560 self.assertTrue(sw.connect(self.controller), \
2561 "Failed to connect to switch" \
2562 )
2563
2564 # Dream up some flow information, i.e. space to chose from for
2565 # random flow parameter generation
2566
2567 fi = Flow_Info()
2568 fi.rand(10)
2569
2570 # Dream up a flow config
2571
2572 fc = Flow_Cfg()
2573 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002574 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002575 sw.tbl_stats.entries[0].wildcards, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002576 sw.sw_features.actions, \
2577 sw.valid_ports, \
2578 sw.valid_queues \
2579 )
2580 fc = fc.canonical()
2581
2582 # Send it to the switch
2583
Rich Lane9a003812012-10-04 17:17:59 -07002584 logging.info("Sending flow mod to switch:")
2585 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002586 ft = Flow_Tbl()
2587 fc.send_rem = False
2588 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2589 ft.insert(fc)
2590
2591 # Do barrier, to make sure all flows are in
2592
2593 self.assertTrue(sw.barrier(), "Barrier failed")
2594
2595 result = True
2596
Howard Persh9cab4822012-09-11 17:08:40 -07002597 sw.settle() # Allow switch to settle and generate any notifications
2598
Howard Persh8d21c1f2012-04-20 15:57:29 -07002599 # Check for any error messages
2600
2601 if not sw.errors_verify(0):
2602 result = False
2603
2604 # Verify flow table
2605
2606 sw.flow_tbl = ft
2607 if not sw.flow_tbl_verify():
2608 result = False
2609
2610 # Send same flow to the switch again
2611
Rich Lane9a003812012-10-04 17:17:59 -07002612 logging.info("Sending flow mod to switch:")
2613 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002614 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2615
2616 # Do barrier, to make sure all flows are in
2617
2618 self.assertTrue(sw.barrier(), "Barrier failed")
2619
Howard Persh9cab4822012-09-11 17:08:40 -07002620 sw.settle() # Allow switch to settle and generate any notifications
2621
Howard Persh8d21c1f2012-04-20 15:57:29 -07002622 # Check for any error messages
2623
2624 if not sw.errors_verify(0):
2625 result = False
2626
2627 # Verify flow table
2628
2629 if not sw.flow_tbl_verify():
2630 result = False
2631
2632 self.assertTrue(result, "Flow_Mod_3_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002633 logging.info("Flow_Mod_3_1 TEST PASSED")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002634
2635
Howard Persh07d99e62012-04-09 15:26:57 -07002636# FLOW DELETE 1
2637#
2638# OVERVIEW
2639# Strict delete of single flow
2640#
2641# PURPOSE
2642# Verify correct operation of strict delete of single defined flow
2643#
2644# PARAMETERS
2645# None
2646#
2647# PROCESS
2648# 1. Delete all flows from switch
2649# 2. Send flow F to switch
2650# 3. Send strict flow delete for F to switch
2651# 4. Verify flow table in swtich
2652# 6. Test PASSED iff all flows sent to switch in step 2 above,
2653# less flow removed in step 3 above, are returned in step 4 above;
2654# else test FAILED
2655
Rich Laneb90a1c42012-10-05 09:16:05 -07002656class Flow_Del_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002657 """
2658 Test FLOW_DEL_1 from draft top-half test plan
2659
2660 INPUTS
2661 None
2662 """
2663
2664 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002665 logging.info("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002666
2667 # Clear all flows from switch
2668
Rich Lane9a003812012-10-04 17:17:59 -07002669 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002670 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002671
2672 # Get switch capabilites
2673
rootf6af1672012-04-06 09:46:29 -07002674 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002675 self.assertTrue(sw.connect(self.controller), \
2676 "Failed to connect to switch" \
2677 )
rootf6af1672012-04-06 09:46:29 -07002678
2679 # Dream up some flow information, i.e. space to chose from for
2680 # random flow parameter generation
2681
2682 fi = Flow_Info()
2683 fi.rand(10)
2684
2685 # Dream up a flow config
2686
2687 fc = Flow_Cfg()
2688 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002689 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002690 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002691 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002692 sw.valid_ports, \
2693 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002694 )
2695 fc = fc.canonical()
2696
2697 # Send it to the switch
2698
Rich Lane9a003812012-10-04 17:17:59 -07002699 logging.info("Sending flow add to switch:")
2700 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002701 ft = Flow_Tbl()
2702 fc.send_rem = False
2703 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2704 ft.insert(fc)
2705
2706 # Dream up some different actions, with the same flow key
2707
2708 fc2 = copy.deepcopy(fc)
2709 while True:
2710 fc2.rand_mod(fi, \
2711 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002712 sw.valid_ports, \
2713 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002714 )
2715 if fc2 != fc:
2716 break
2717
2718 # Delete strictly
2719
Rich Lane9a003812012-10-04 17:17:59 -07002720 logging.info("Sending strict flow del to switch:")
2721 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002722 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2723 ft.delete(fc)
2724
2725 # Do barrier, to make sure all flows are in
2726
2727 self.assertTrue(sw.barrier(), "Barrier failed")
2728
2729 result = True
2730
Howard Persh9cab4822012-09-11 17:08:40 -07002731 sw.settle() # Allow switch to settle and generate any notifications
2732
rootf6af1672012-04-06 09:46:29 -07002733 # Check for any error messages
2734
2735 if not sw.errors_verify(0):
2736 result = False
2737
2738 # Verify flow table
2739
2740 sw.flow_tbl = ft
2741 if not sw.flow_tbl_verify():
2742 result = False
2743
2744 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002745 logging.info("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002746
2747
Howard Persh07d99e62012-04-09 15:26:57 -07002748# FLOW DELETE 2
2749#
2750# OVERVIEW
2751# Loose delete of multiple flows
2752#
2753# PURPOSE
2754# - Verify correct operation of loose delete of multiple flows
2755#
2756# PARAMETERS
2757# Name: num_flows
2758# Type: number
2759# Description:
2760# Number of flows to define
2761# Default: 100
2762#
2763# PROCESS
2764# 1. Delete all flows from switch
2765# 2. Generate <num_flows> distinct flow configurations
2766# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2767# 4. Pick 1 defined flow F at random
2768# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2769# F' will match more than 1 existing flow key
2770# 6. Send loose flow delete for F' to switch
2771# 7. Verify flow table in switch
2772# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2773# removed in step 6 above (i.e. those that match F'), are returned
2774# in step 7 above;
2775# else test FAILED
2776
Rich Laneb90a1c42012-10-05 09:16:05 -07002777class Flow_Del_2(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002778 """
2779 Test FLOW_DEL_2 from draft top-half test plan
2780
2781 INPUTS
2782 None
2783 """
2784
2785 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002786 logging.info("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002787
Rich Lane2014f9b2012-10-05 15:29:40 -07002788 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002789
2790 # Clear all flows from switch
2791
Rich Lane9a003812012-10-04 17:17:59 -07002792 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002793 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002794
2795 # Get switch capabilites
2796
rootf6af1672012-04-06 09:46:29 -07002797 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002798 self.assertTrue(sw.connect(self.controller), \
2799 "Failed to connect to switch" \
2800 )
rootf6af1672012-04-06 09:46:29 -07002801
2802 # Dream up some flow information, i.e. space to chose from for
2803 # random flow parameter generation
2804
2805 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002806 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002807 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002808
2809 # Dream up some flows
2810
2811 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002812 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002813
2814 # Send flow table to switch
2815
Rich Lane9a003812012-10-04 17:17:59 -07002816 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002817 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002818 logging.info("Adding flow:")
2819 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002820 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2821
2822 # Do barrier, to make sure all flows are in
2823
2824 self.assertTrue(sw.barrier(), "Barrier failed")
2825
2826 result = True
2827
Howard Persh9cab4822012-09-11 17:08:40 -07002828 sw.settle() # Allow switch to settle and generate any notifications
2829
rootf6af1672012-04-06 09:46:29 -07002830 # Check for any error messages
2831
2832 if not sw.errors_verify(0):
2833 result = False
2834
2835 # Verify flow table
2836
2837 sw.flow_tbl = ft
2838 if not sw.flow_tbl_verify():
2839 result = False
2840
2841 # Pick a random flow as a basis
2842
2843 dfc = copy.deepcopy(ft.values()[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002844 dfc.rand_mod(fi, \
2845 sw.sw_features.actions, \
2846 sw.valid_ports, \
2847 sw.valid_queues \
2848 )
rootf6af1672012-04-06 09:46:29 -07002849
2850 # Repeatedly wildcard qualifiers
2851
2852 for wi in shuffle(range(len(all_wildcards_list))):
2853 w = all_wildcards_list[wi]
2854 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2855 n = wildcard_get(dfc.match.wildcards, w)
2856 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002857 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2858 w, \
2859 random.randint(n + 1, 32) \
2860 )
rootf6af1672012-04-06 09:46:29 -07002861 else:
2862 continue
2863 else:
2864 if wildcard_get(dfc.match.wildcards, w) == 0:
2865 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2866 else:
2867 continue
2868 dfc = dfc.canonical()
2869
2870 # Count the number of flows that would be deleted
2871
2872 n = 0
2873 for fc in ft.values():
2874 if dfc.overlaps(fc, True):
2875 n = n + 1
2876
2877 # If more than 1, we found our loose delete flow spec
2878 if n > 1:
2879 break
2880
Rich Lane9a003812012-10-04 17:17:59 -07002881 logging.info("Deleting %d flows" % (n))
2882 logging.info("Sending flow del to switch:")
2883 logging.info(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002884 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2885
2886 # Do barrier, to make sure all flows are in
2887 self.assertTrue(sw.barrier(), "Barrier failed")
2888
Howard Persh9cab4822012-09-11 17:08:40 -07002889 sw.settle() # Allow switch to settle and generate any notifications
2890
rootf6af1672012-04-06 09:46:29 -07002891 # Check for error message
2892
2893 if not sw.errors_verify(0):
2894 result = False
2895
2896 # Apply flow mod to local flow table
2897
2898 for fc in ft.values():
2899 if dfc.overlaps(fc, True):
2900 ft.delete(fc)
2901
2902 # Verify flow table
2903
2904 sw.flow_tbl = ft
2905 if not sw.flow_tbl_verify():
2906 result = False
2907
2908 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002909 logging.info("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002910
2911
Howard Persh07d99e62012-04-09 15:26:57 -07002912# FLOW DELETE 4
2913#
2914# OVERVIEW
2915# Flow removed messages
2916#
2917# PURPOSE
2918# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2919# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2920#
2921# PARAMETERS
2922# None
2923#
2924# PROCESS
2925# 1. Delete all flows from switch
2926# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2927# 3. Send strict flow delete of flow to switch
2928# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2929# 5. Verify flow table in switch
2930# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2931# removed in step 3 above, are returned in step 5 above, and that
2932# asynch message was received; else test FAILED
2933
2934
Rich Laneb90a1c42012-10-05 09:16:05 -07002935class Flow_Del_4(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002936 """
2937 Test FLOW_DEL_4 from draft top-half test plan
2938
2939 INPUTS
2940 None
2941 """
2942
2943 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002944 logging.info("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002945
2946 # Clear all flows from switch
2947
Rich Lane9a003812012-10-04 17:17:59 -07002948 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002949 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002950
2951 # Get switch capabilites
2952
rootf6af1672012-04-06 09:46:29 -07002953 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002954 self.assertTrue(sw.connect(self.controller), \
2955 "Failed to connect to switch" \
2956 )
rootf6af1672012-04-06 09:46:29 -07002957
2958 # Dream up some flow information, i.e. space to chose from for
2959 # random flow parameter generation
2960
2961 fi = Flow_Info()
2962 fi.rand(10)
2963
2964 # Dream up a flow config
2965
2966 fc = Flow_Cfg()
2967 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002968 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002969 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002970 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002971 sw.valid_ports, \
2972 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002973 )
2974 fc = fc.canonical()
2975
2976 # Send it to the switch. with "notify on removed"
2977
Rich Lane9a003812012-10-04 17:17:59 -07002978 logging.info("Sending flow add to switch:")
2979 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002980 ft = Flow_Tbl()
2981 fc.send_rem = True
2982 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2983 ft.insert(fc)
2984
2985 # Dream up some different actions, with the same flow key
2986
2987 fc2 = copy.deepcopy(fc)
2988 while True:
2989 fc2.rand_mod(fi, \
2990 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002991 sw.valid_ports, \
2992 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002993 )
2994 if fc2 != fc:
2995 break
2996
2997 # Delete strictly
2998
Rich Lane9a003812012-10-04 17:17:59 -07002999 logging.info("Sending strict flow del to switch:")
3000 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07003001 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
3002 ft.delete(fc)
3003
3004 # Do barrier, to make sure all flows are in
3005
3006 self.assertTrue(sw.barrier(), "Barrier failed")
3007
3008 result = True
3009
Howard Persh9cab4822012-09-11 17:08:40 -07003010 sw.settle() # Allow switch to settle and generate any notifications
3011
rootf6af1672012-04-06 09:46:29 -07003012 # Check for expected "removed" message
3013
Howard Persh3340d452012-04-06 16:45:21 -07003014 if not sw.errors_verify(0):
3015 result = False
3016
3017 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07003018 result = False
3019
3020 # Verify flow table
3021
3022 sw.flow_tbl = ft
3023 if not sw.flow_tbl_verify():
3024 result = False
3025
3026 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07003027 logging.info("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07003028