blob: 0538365230bdf43b343f9b6bd23f412bff5a6096 [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#
16# Name: actions
17# Type: number
18# Description:
19# Overrides bitmap of supported actions reported by switch
20# Default: none
21#
22# Name: conservative_ordered_actions
23# Type: boolean (True or False)
24# Description:
25# Compare flow actions lists as unordered
26# Default: True
27
28
Howard Persh680b92a2012-03-31 13:34:35 -070029import math
Howard Pershc7963582012-03-29 10:02:59 -070030
31import logging
32
33import unittest
34import random
35
36import oftest.controller as controller
37import oftest.cstruct as ofp
38import oftest.message as message
39import oftest.dataplane as dataplane
40import oftest.action as action
41import oftest.action_list as action_list
42import oftest.parse as parse
43import pktact
44import basic
45
46from testutils import *
47from time import sleep
48
49#@var port_map Local copy of the configuration map from OF port
50# numbers to OS interfaces
Dan Talayco910a8282012-04-07 00:05:20 -070051fq_port_map = None
52#@var fq_logger Local logger object
53fq_logger = None
54#@var fq_config Local copy of global configuration data
55fq_config = None
Howard Pershc7963582012-03-29 10:02:59 -070056
rootf6af1672012-04-06 09:46:29 -070057# For test priority
58test_prio = {}
59
60
Howard Pershc7963582012-03-29 10:02:59 -070061def test_set_init(config):
62 """
63 Set up function for packet action test classes
64
65 @param config The configuration dictionary; see oft
66 """
67
68 basic.test_set_init(config)
69
Dan Talayco910a8282012-04-07 00:05:20 -070070 global fq_port_map
71 global fq_logger
72 global fq_config
Howard Pershc7963582012-03-29 10:02:59 -070073
Dan Talayco910a8282012-04-07 00:05:20 -070074 fq_logger = logging.getLogger("flowq")
75 fq_logger.info("Initializing test set")
76 fq_port_map = config["port_map"]
77 fq_config = config
root2843d2b2012-04-06 10:27:46 -070078
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
148 self.vlans = []
149 i = 0
150 while i < n:
151 self.vlans.append(random.randint(1, 4094))
152 i = i + 1
153
rootf6af1672012-04-06 09:46:29 -0700154 self.ethertypes = [0x0800, 0x0806]
Howard Persh680b92a2012-03-31 13:34:35 -0700155 i = 0
156 while i < n:
157 self.ethertypes.append(random.randint(0, (1 << 16) - 1))
158 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700159 self.ethertypes = shuffle(self.ethertypes)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700160
161 self.ip_addrs = []
162 i = 0
163 while i < n:
164 self.ip_addrs.append(rand_nw_addr())
165 i = i + 1
166
167 self.ip_tos = []
168 i = 0
169 while i < n:
170 self.ip_tos.append(random.randint(0, (1 << 8) - 1) & ~3)
171 i = i + 1
172
rootf6af1672012-04-06 09:46:29 -0700173 self.ip_protos = [1, 6, 17]
Howard Persh680b92a2012-03-31 13:34:35 -0700174 i = 0
175 while i < n:
176 self.ip_protos.append(random.randint(0, (1 << 8) - 1))
177 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700178 self.ip_protos = shuffle(self.ip_protos)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700179
180 self.l4_ports = []
181 i = 0
182 while i < n:
183 self.l4_ports.append(random.randint(0, (1 << 16) - 1))
184 i = i + 1
185
186 def rand_priority(self):
187 return rand_pick(self.priorities)
188
189 def rand_dl_addr(self):
190 return rand_pick(self.dl_addrs)
191
192 def rand_vlan(self):
193 return rand_pick(self.vlans)
194
195 def rand_ethertype(self):
196 return rand_pick(self.ethertypes)
197
198 def rand_ip_addr(self):
199 return rand_pick(self.ip_addrs)
200
201 def rand_ip_tos(self):
202 return rand_pick(self.ip_tos)
203
204 def rand_ip_proto(self):
205 return rand_pick(self.ip_protos)
206
207 def rand_l4_port(self):
208 return rand_pick(self.l4_ports)
209
210
Howard Pershc7963582012-03-29 10:02:59 -0700211# TBD - These don't belong here
212
Howard Persh680b92a2012-03-31 13:34:35 -0700213all_wildcards_list = [ofp.OFPFW_IN_PORT,
Howard Persh680b92a2012-03-31 13:34:35 -0700214 ofp.OFPFW_DL_DST,
rootf6af1672012-04-06 09:46:29 -0700215 ofp.OFPFW_DL_SRC,
216 ofp.OFPFW_DL_VLAN,
217 ofp.OFPFW_DL_VLAN_PCP,
Howard Persh680b92a2012-03-31 13:34:35 -0700218 ofp.OFPFW_DL_TYPE,
rootf6af1672012-04-06 09:46:29 -0700219 ofp.OFPFW_NW_TOS,
Howard Persh680b92a2012-03-31 13:34:35 -0700220 ofp.OFPFW_NW_PROTO,
Howard Persh680b92a2012-03-31 13:34:35 -0700221 ofp.OFPFW_NW_SRC_MASK,
222 ofp.OFPFW_NW_DST_MASK,
rootf6af1672012-04-06 09:46:29 -0700223 ofp.OFPFW_TP_SRC,
224 ofp.OFPFW_TP_DST
Howard Persh680b92a2012-03-31 13:34:35 -0700225 ]
Howard Pershc7963582012-03-29 10:02:59 -0700226
Howard Persh3340d452012-04-06 16:45:21 -0700227# TBD - Need this because there are duplicates in ofp.ofp_flow_wildcards_map
228# -- FIX
rootf6af1672012-04-06 09:46:29 -0700229all_wildcard_names = {
230 1 : 'OFPFW_IN_PORT',
231 2 : 'OFPFW_DL_VLAN',
232 4 : 'OFPFW_DL_SRC',
233 8 : 'OFPFW_DL_DST',
234 16 : 'OFPFW_DL_TYPE',
235 32 : 'OFPFW_NW_PROTO',
236 64 : 'OFPFW_TP_SRC',
237 128 : 'OFPFW_TP_DST',
238 1048576 : 'OFPFW_DL_VLAN_PCP',
239 2097152 : 'OFPFW_NW_TOS'
240}
241
242
243def wildcard_set(x, w, val):
244 result = x
245 if w == ofp.OFPFW_NW_SRC_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700246 result = (result & ~ofp.OFPFW_NW_SRC_MASK) \
247 | (val << ofp.OFPFW_NW_SRC_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700248 elif w == ofp.OFPFW_NW_DST_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700249 result = (result & ~ofp.OFPFW_NW_DST_MASK) \
250 | (val << ofp.OFPFW_NW_DST_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700251 elif val == 0:
252 result = result & ~w
253 else:
254 result = result | w
255 return result
256
257def wildcard_get(x, w):
258 if w == ofp.OFPFW_NW_SRC_MASK:
259 return (x & ofp.OFPFW_NW_SRC_MASK) >> ofp.OFPFW_NW_SRC_SHIFT
260 if w == ofp.OFPFW_NW_DST_MASK:
261 return (x & ofp.OFPFW_NW_DST_MASK) >> ofp.OFPFW_NW_DST_SHIFT
262 return 1 if (x & w) != 0 else 0
263
Howard Pershc7963582012-03-29 10:02:59 -0700264
Howard Persh680b92a2012-03-31 13:34:35 -0700265all_actions_list = [ofp.OFPAT_OUTPUT,
266 ofp.OFPAT_SET_VLAN_VID,
267 ofp.OFPAT_SET_VLAN_PCP,
268 ofp.OFPAT_STRIP_VLAN,
269 ofp.OFPAT_SET_DL_SRC,
270 ofp.OFPAT_SET_DL_DST,
271 ofp.OFPAT_SET_NW_SRC,
272 ofp.OFPAT_SET_NW_DST,
273 ofp.OFPAT_SET_NW_TOS,
274 ofp.OFPAT_SET_TP_SRC,
275 ofp.OFPAT_SET_TP_DST,
276 ofp.OFPAT_ENQUEUE
277 ]
278
279def dl_addr_to_str(a):
280 return "%x:%x:%x:%x:%x:%x" % tuple(a)
281
282def ip_addr_to_str(a, n):
rootf6af1672012-04-06 09:46:29 -0700283 if n is not None:
284 a = a & ~((1 << (32 - n)) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700285 result = "%d.%d.%d.%d" % (a >> 24, \
286 (a >> 16) & 0xff, \
287 (a >> 8) & 0xff, \
288 a & 0xff \
289 )
290 if n is not None:
291 result = result + ("/%d" % (n))
292 return result
293
Howard Pershc7963582012-03-29 10:02:59 -0700294
rootf6af1672012-04-06 09:46:29 -0700295class Flow_Cfg:
Howard Pershc7963582012-03-29 10:02:59 -0700296 # Members:
297 # - match
298 # - idle_timeout
299 # - hard_timeout
300 # - priority
301 # - action_list
302
303 def __init__(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700304 self.priority = 0
Howard Pershc7963582012-03-29 10:02:59 -0700305 self.match = parse.ofp_match()
306 self.match.wildcards = ofp.OFPFW_ALL
307 self.idle_timeout = 0
308 self.hard_timeout = 0
Howard Pershc7963582012-03-29 10:02:59 -0700309 self.actions = action_list.action_list()
310
rootf6af1672012-04-06 09:46:29 -0700311 # {pri, match} is considered a flow key
312 def key_equal(self, x):
Howard Persh680b92a2012-03-31 13:34:35 -0700313 if self.priority != x.priority:
314 return False
315 # TBD - Should this logic be moved to ofp_match.__eq__()?
316 if self.match.wildcards != x.match.wildcards:
317 return False
rootf6af1672012-04-06 09:46:29 -0700318 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700319 and self.match.in_port != x.match.in_port:
320 return False
rootf6af1672012-04-06 09:46:29 -0700321 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700322 and self.match.dl_dst != x.match.dl_dst:
323 return False
rootf6af1672012-04-06 09:46:29 -0700324 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0 \
325 and self.match.dl_src != x.match.dl_src:
326 return False
327 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700328 and self.match.dl_vlan != x.match.dl_vlan:
329 return False
rootf6af1672012-04-06 09:46:29 -0700330 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700331 and self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
332 return False
rootf6af1672012-04-06 09:46:29 -0700333 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700334 and self.match.dl_type != x.match.dl_type:
335 return False
rootf6af1672012-04-06 09:46:29 -0700336 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700337 and self.match.nw_tos != x.match.nw_tos:
338 return False
rootf6af1672012-04-06 09:46:29 -0700339 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700340 and self.match.nw_proto != x.match.nw_proto:
341 return False
rootf6af1672012-04-06 09:46:29 -0700342 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
343 if n < 32:
344 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700345 if (self.match.nw_src & m) != (x.match.nw_src & m):
346 return False
rootf6af1672012-04-06 09:46:29 -0700347 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
348 if n < 32:
349 m = ~((1 << n) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700350 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
351 return False
rootf6af1672012-04-06 09:46:29 -0700352 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0 \
353 and self.match.tp_src != x.match.tp_src:
Howard Persh680b92a2012-03-31 13:34:35 -0700354 return False
rootf6af1672012-04-06 09:46:29 -0700355 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0 \
356 and self.match.tp_dst != x.match.tp_dst:
357 return False
358 return True
359
360 def non_key_equal(self, x):
361 if self.cookie != x.cookie:
Howard Pershc7963582012-03-29 10:02:59 -0700362 return False
363 if self.idle_timeout != x.idle_timeout:
364 return False
365 if self.hard_timeout != x.hard_timeout:
366 return False
Dan Talayco910a8282012-04-07 00:05:20 -0700367 if True:
368 # For now, compare actions lists as unordered
root2843d2b2012-04-06 10:27:46 -0700369 aa = copy.deepcopy(x.actions.actions)
370 for a in self.actions.actions:
371 i = 0
372 while i < len(aa):
373 if a == aa[i]:
374 break
375 i = i + 1
376 if i < len(aa):
377 aa.pop(i)
378 else:
379 return False
380 return aa == []
381 else:
382 return self.actions == x.actions
rootf6af1672012-04-06 09:46:29 -0700383
root2843d2b2012-04-06 10:27:46 -0700384 def key_str(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700385 result = "priority=%d" % self.priority
386 # TBD - Would be nice if ofp_match.show() was better behaved
387 # (no newlines), and more intuitive (things in hex where approprate), etc.
rootf6af1672012-04-06 09:46:29 -0700388 result = result + (", wildcards=0x%x={" % (self.match.wildcards))
Howard Persh680b92a2012-03-31 13:34:35 -0700389 sep = ""
rootf6af1672012-04-06 09:46:29 -0700390 for w in all_wildcards_list:
391 if (self.match.wildcards & w) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700392 continue
393 if w == ofp.OFPFW_NW_SRC_MASK:
rootf6af1672012-04-06 09:46:29 -0700394 n = wildcard_get(self.match.wildcards, w)
395 if n > 0:
396 result = result + sep + ("OFPFW_NW_SRC(%d)" % (n))
Howard Persh680b92a2012-03-31 13:34:35 -0700397 elif w == ofp.OFPFW_NW_DST_MASK:
rootf6af1672012-04-06 09:46:29 -0700398 n = wildcard_get(self.match.wildcards, w)
399 if n > 0:
400 result = result + sep + ("OFPFW_NW_DST(%d)" % (n))
Howard Persh680b92a2012-03-31 13:34:35 -0700401 else:
rootf6af1672012-04-06 09:46:29 -0700402 result = result + sep + all_wildcard_names[w]
Howard Persh680b92a2012-03-31 13:34:35 -0700403 sep = ", "
404 result = result +"}"
rootf6af1672012-04-06 09:46:29 -0700405 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700406 result = result + (", in_port=%d" % (self.match.in_port))
rootf6af1672012-04-06 09:46:29 -0700407 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700408 result = result + (", dl_dst=%s" \
409 % (dl_addr_to_str(self.match.dl_dst)) \
410 )
rootf6af1672012-04-06 09:46:29 -0700411 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh3340d452012-04-06 16:45:21 -0700412 result = result + (", dl_src=%s" \
413 % (dl_addr_to_str(self.match.dl_src)) \
414 )
rootf6af1672012-04-06 09:46:29 -0700415 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700416 result = result + (", dl_vlan=%d" % (self.match.dl_vlan))
rootf6af1672012-04-06 09:46:29 -0700417 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700418 result = result + (", dl_vlan_pcp=%d" % (self.match.dl_vlan_pcp))
rootf6af1672012-04-06 09:46:29 -0700419 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700420 result = result + (", dl_type=0x%x" % (self.match.dl_type))
rootf6af1672012-04-06 09:46:29 -0700421 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700422 result = result + (", nw_tos=0x%x" % (self.match.nw_tos))
rootf6af1672012-04-06 09:46:29 -0700423 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700424 result = result + (", nw_proto=%d" % (self.match.nw_proto))
rootf6af1672012-04-06 09:46:29 -0700425 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700426 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700427 result = result + (", nw_src=%s" % \
428 (ip_addr_to_str(self.match.nw_src, 32 - n)) \
429 )
rootf6af1672012-04-06 09:46:29 -0700430 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700431 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -0700432 result = result + (", nw_dst=%s" % \
433 (ip_addr_to_str(self.match.nw_dst, 32 - n)) \
434 )
rootf6af1672012-04-06 09:46:29 -0700435 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700436 result = result + (", tp_src=%d" % self.match.tp_src)
rootf6af1672012-04-06 09:46:29 -0700437 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700438 result = result + (", tp_dst=%d" % self.match.tp_dst)
rootf6af1672012-04-06 09:46:29 -0700439 return result
440
441 def __eq__(self, x):
442 return (self.key_equal(x) and self.non_key_equal(x))
443
444 def __str__(self):
root2843d2b2012-04-06 10:27:46 -0700445 result = self.key_str()
446 result = result + (", cookie=%d" % self.cookie)
Howard Persh680b92a2012-03-31 13:34:35 -0700447 result = result + (", idle_timeout=%d" % self.idle_timeout)
448 result = result + (", hard_timeout=%d" % self.hard_timeout)
Howard Persh680b92a2012-03-31 13:34:35 -0700449 for a in self.actions.actions:
450 result = result + (", action=%s" % ofp.ofp_action_type_map[a.type])
451 if a.type == ofp.OFPAT_OUTPUT:
452 result = result + ("(%d)" % (a.port))
453 elif a.type == ofp.OFPAT_SET_VLAN_VID:
454 result = result + ("(%d)" % (a.vlan_vid))
455 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
456 result = result + ("(%d)" % (a.vlan_pcp))
457 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
458 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
459 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
460 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
461 elif a.type == ofp.OFPAT_SET_NW_TOS:
462 result = result + ("(0x%x)" % (a.nw_tos))
463 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
464 result = result + ("(%d)" % (a.tp_port))
465 elif a.type == ofp.OFPAT_ENQUEUE:
466 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
467 return result
Howard Pershc7963582012-03-29 10:02:59 -0700468
Dan Talayco910a8282012-04-07 00:05:20 -0700469 def rand_actions_ordered(self, fi, valid_actions, valid_ports):
Howard Persh3340d452012-04-06 16:45:21 -0700470 # Action lists are ordered, so pick an ordered random subset of
471 # supported actions
Dan Talayco910a8282012-04-07 00:05:20 -0700472 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh3340d452012-04-06 16:45:21 -0700473 supported_actions = []
474 for a in all_actions_list:
475 if ((1 << a) & valid_actions) != 0:
476 supported_actions.append(a)
477
478 supported_actions = shuffle(supported_actions)
479 supported_actions \
480 = supported_actions[0 : random.randint(1, len(supported_actions))]
481
Howard Persh3340d452012-04-06 16:45:21 -0700482 self.actions = action_list.action_list()
483 for a in supported_actions:
Dan Talayco910a8282012-04-07 00:05:20 -0700484 act = None
Howard Persh3340d452012-04-06 16:45:21 -0700485 if a == ofp.OFPAT_OUTPUT:
486 pass # OUTPUT actions must come last
487 elif a == ofp.OFPAT_SET_VLAN_VID:
488 act = action.action_set_vlan_vid()
489 act.vlan_vid = fi.rand_vlan()
Howard Persh3340d452012-04-06 16:45:21 -0700490 elif a == ofp.OFPAT_SET_VLAN_PCP:
491 act = action.action_set_vlan_pcp()
492 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Persh3340d452012-04-06 16:45:21 -0700493 elif a == ofp.OFPAT_STRIP_VLAN:
494 act = action.action_strip_vlan()
Howard Persh3340d452012-04-06 16:45:21 -0700495 elif a == ofp.OFPAT_SET_DL_SRC:
496 act = action.action_set_dl_src()
497 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700498 elif a == ofp.OFPAT_SET_DL_DST:
499 act = action.action_set_dl_dst()
500 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700501 elif a == ofp.OFPAT_SET_NW_SRC:
502 act = action.action_set_nw_src()
503 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700504 elif a == ofp.OFPAT_SET_NW_DST:
505 act = action.action_set_nw_dst()
506 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700507 elif a == ofp.OFPAT_SET_NW_TOS:
508 act = action.action_set_nw_tos()
509 act.nw_tos = fi.rand_ip_tos()
Howard Persh3340d452012-04-06 16:45:21 -0700510 elif a == ofp.OFPAT_SET_TP_SRC:
511 act = action.action_set_tp_src()
512 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700513 elif a == ofp.OFPAT_SET_TP_DST:
514 act = action.action_set_tp_dst()
515 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700516 elif a == ofp.OFPAT_ENQUEUE:
517 pass # Enqueue actions must come last
Dan Talayco910a8282012-04-07 00:05:20 -0700518 if act:
519 act.max_len = ACTION_MAX_LEN
520 self.actions.add(act)
521
Howard Persh3340d452012-04-06 16:45:21 -0700522 p = random.randint(1, 100)
Howard Persh07d99e62012-04-09 15:26:57 -0700523 if p <= 33 and ofp.OFPAT_ENQUEUE in supported_actions:
Howard Persh3340d452012-04-06 16:45:21 -0700524 # One third of the time, include ENQUEUE actions at end of list
525 # At most 1 ENQUEUE action
526 act = action.action_enqueue()
527 act.port = rand_pick(valid_ports)
528 # TBD - Limits for queue number?
529 act.queue_id = random.randint(0, 7)
Dan Talayco910a8282012-04-07 00:05:20 -0700530 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700531 self.actions.add(act)
Howard Persh07d99e62012-04-09 15:26:57 -0700532 if p > 33 and p <= 66 and ofp.OFPAT_OUTPUT in supported_actions:
Howard Persh3340d452012-04-06 16:45:21 -0700533 # One third of the time, include OUTPUT actions at end of list
534 port_idxs = shuffle(range(len(valid_ports)))
535 # Only 1 output action allowed if IN_PORT wildcarded
536 n = 1 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) != 0 \
537 else random.randint(1, len(valid_ports))
538 port_idxs = port_idxs[0 : n]
539 for pi in port_idxs:
540 act = action.action_output()
541 act.port = valid_ports[pi]
Dan Talayco910a8282012-04-07 00:05:20 -0700542 act.max_len = ACTION_MAX_LEN
Howard Persh3340d452012-04-06 16:45:21 -0700543 if act.port != ofp.OFPP_IN_PORT \
544 or wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
545 # OUTPUT(IN_PORT) only valid if OFPFW_IN_PORT not wildcarded
546 self.actions.add(act)
547 else:
548 # One third of the time, include neither
549 pass
550
551
552 # Randomize flow data for flow modifies (i.e. cookie and actions)
rootf6af1672012-04-06 09:46:29 -0700553 def rand_mod(self, fi, valid_actions, valid_ports):
554 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700555
Dan Talayco910a8282012-04-07 00:05:20 -0700556 # By default, test with conservative ordering conventions
557 # This should probably be indicated in a profile
558 if test_param_get(fq_config, "conservative_ordered_actions", True):
559 self.rand_actions_ordered(fi, valid_actions, valid_ports)
Howard Persh3340d452012-04-06 16:45:21 -0700560 return self
561
Howard Persh680b92a2012-03-31 13:34:35 -0700562 # Action lists are ordered, so pick an ordered random subset of
563 # supported actions
564 supported_actions = []
565 for a in all_actions_list:
566 if ((1 << a) & valid_actions) != 0:
567 supported_actions.append(a)
568
569 supported_actions = shuffle(supported_actions)
570 supported_actions \
571 = supported_actions[0 : random.randint(1, len(supported_actions))]
Howard Pershc7963582012-03-29 10:02:59 -0700572
573 self.actions = action_list.action_list()
Howard Persh680b92a2012-03-31 13:34:35 -0700574 for a in supported_actions:
Howard Pershc7963582012-03-29 10:02:59 -0700575 if a == ofp.OFPAT_OUTPUT:
576 # TBD - Output actions are clustered in list, spread them out?
577 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700578 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700579 for pi in port_idxs:
580 act = action.action_output()
Howard Persh680b92a2012-03-31 13:34:35 -0700581 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700582 self.actions.add(act)
583 elif a == ofp.OFPAT_SET_VLAN_VID:
584 act = action.action_set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700585 act.vlan_vid = fi.rand_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700586 self.actions.add(act)
587 elif a == ofp.OFPAT_SET_VLAN_PCP:
Dan Talayco910a8282012-04-07 00:05:20 -0700588 act = action.action_set_vlan_pcp()
589 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700590 elif a == ofp.OFPAT_STRIP_VLAN:
591 act = action.action_strip_vlan()
592 self.actions.add(act)
593 elif a == ofp.OFPAT_SET_DL_SRC:
594 act = action.action_set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700595 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700596 self.actions.add(act)
597 elif a == ofp.OFPAT_SET_DL_DST:
598 act = action.action_set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700599 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700600 self.actions.add(act)
601 elif a == ofp.OFPAT_SET_NW_SRC:
602 act = action.action_set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700603 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700604 self.actions.add(act)
605 elif a == ofp.OFPAT_SET_NW_DST:
606 act = action.action_set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700607 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700608 self.actions.add(act)
609 elif a == ofp.OFPAT_SET_NW_TOS:
610 act = action.action_set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700611 act.nw_tos = fi.rand_ip_tos()
Howard Pershc7963582012-03-29 10:02:59 -0700612 self.actions.add(act)
613 elif a == ofp.OFPAT_SET_TP_SRC:
614 act = action.action_set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700615 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700616 self.actions.add(act)
617 elif a == ofp.OFPAT_SET_TP_DST:
618 act = action.action_set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700619 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700620 self.actions.add(act)
621 elif a == ofp.OFPAT_ENQUEUE:
622 # TBD - Enqueue actions are clustered in list, spread them out?
623 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700624 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700625 for pi in port_idxs:
626 act = action.action_enqueue()
Howard Persh680b92a2012-03-31 13:34:35 -0700627 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700628 # TBD - Limits for queue number?
629 act.queue_id = random.randint(0, 7)
630 self.actions.add(act)
631
632 return self
633
rootf6af1672012-04-06 09:46:29 -0700634 # Randomize flow cfg
635 def rand(self, fi, valid_wildcards, valid_actions, valid_ports):
636 # Start with no wildcards, i.e. everything specified
637 self.match.wildcards = 0
638
639 # Make approx. 5% of flows exact
640 exact = (random.randint(1, 100) <= 5)
641
642 # For each qualifier Q,
643 # if (wildcarding is not supported for Q,
644 # or an exact flow is specified
645 # or a coin toss comes up heads),
646 # specify Q
647 # else
648 # wildcard Q
649
650 if wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
651 or exact \
652 or flip_coin():
653 self.match.in_port = rand_pick(valid_ports)
654 else:
Howard Persh3340d452012-04-06 16:45:21 -0700655 self.match.wildcards = wildcard_set(self.match.wildcards, \
656 ofp.OFPFW_IN_PORT, \
657 1 \
658 )
rootf6af1672012-04-06 09:46:29 -0700659
660 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
661 or exact \
662 or flip_coin():
663 self.match.dl_dst = fi.rand_dl_addr()
664 else:
Howard Persh3340d452012-04-06 16:45:21 -0700665 self.match.wildcards = wildcard_set(self.match.wildcards, \
666 ofp.OFPFW_DL_DST, \
667 1 \
668 )
rootf6af1672012-04-06 09:46:29 -0700669
670 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
671 or exact \
672 or flip_coin():
673 self.match.dl_src = fi.rand_dl_addr()
674 else:
Howard Persh3340d452012-04-06 16:45:21 -0700675 self.match.wildcards = wildcard_set(self.match.wildcards, \
676 ofp.OFPFW_DL_SRC, \
677 1 \
678 )
rootf6af1672012-04-06 09:46:29 -0700679
680 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
681 or exact \
682 or flip_coin():
683 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
684 else:
Howard Persh3340d452012-04-06 16:45:21 -0700685 self.match.wildcards = wildcard_set(self.match.wildcards, \
686 ofp.OFPFW_DL_VLAN_PCP, \
687 1 \
688 )
rootf6af1672012-04-06 09:46:29 -0700689
690 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
691 or exact \
692 or flip_coin():
693 self.match.dl_vlan = fi.rand_vlan()
694 else:
Howard Persh3340d452012-04-06 16:45:21 -0700695 self.match.wildcards = wildcard_set(self.match.wildcards, \
696 ofp.OFPFW_DL_VLAN, \
697 1 \
698 )
rootf6af1672012-04-06 09:46:29 -0700699
700 if wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
701 or exact \
702 or flip_coin():
703 self.match.dl_type = fi.rand_ethertype()
704 else:
Howard Persh3340d452012-04-06 16:45:21 -0700705 self.match.wildcards = wildcard_set(self.match.wildcards, \
706 ofp.OFPFW_DL_TYPE, \
707 1 \
708 )
rootf6af1672012-04-06 09:46:29 -0700709
710 if exact or flip_coin():
711 n = 0
712 else:
713 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
714 if n > 32:
715 n = 32
716 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700717 self.match.wildcards = wildcard_set(self.match.wildcards, \
718 ofp.OFPFW_NW_SRC_MASK, \
719 n \
720 )
rootf6af1672012-04-06 09:46:29 -0700721 if n < 32:
722 self.match.nw_src = fi.rand_ip_addr() & ~((1 << n) - 1)
723 # Specifying any IP address match other than all bits
724 # don't care requires that Ethertype is one of {IP, ARP}
725 if flip_coin():
726 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700727 self.match.wildcards = wildcard_set(self.match.wildcards, \
728 ofp.OFPFW_DL_TYPE, \
729 0 \
730 )
rootf6af1672012-04-06 09:46:29 -0700731
732 if exact or flip_coin():
733 n = 0
734 else:
735 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
736 if n > 32:
737 n = 32
738 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700739 self.match.wildcards = wildcard_set(self.match.wildcards, \
740 ofp.OFPFW_NW_DST_MASK, \
741 n \
742 )
rootf6af1672012-04-06 09:46:29 -0700743 if n < 32:
744 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
745 # Specifying any IP address match other than all bits
746 # don't care requires that Ethertype is one of {IP, ARP}
747 if flip_coin():
748 self.match.dl_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700749 self.match.wildcards = wildcard_set(self.match.wildcards, \
750 ofp.OFPFW_DL_TYPE, \
751 0 \
752 )
rootf6af1672012-04-06 09:46:29 -0700753
754 if wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
755 or exact \
756 or flip_coin():
757 self.match.nw_tos = fi.rand_ip_tos()
758 # Specifying a TOS value requires that Ethertype is IP
759 if flip_coin():
760 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700761 self.match.wildcards = wildcard_set(self.match.wildcards, \
762 ofp.OFPFW_DL_TYPE, \
763 0 \
764 )
rootf6af1672012-04-06 09:46:29 -0700765 else:
Howard Persh3340d452012-04-06 16:45:21 -0700766 self.match.wildcards = wildcard_set(self.match.wildcards, \
767 ofp.OFPFW_NW_TOS, \
768 1 \
769 )
rootf6af1672012-04-06 09:46:29 -0700770
Dan Talayco910a8282012-04-07 00:05:20 -0700771 # Known issue on OVS with specifying nw_proto w/o dl_type as IP
772 if wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
773 or exact \
774 or flip_coin():
775 self.match.nw_proto = fi.rand_ip_proto()
776 # Specifying an IP protocol requires that Ethertype is IP
777 if flip_coin():
778 self.match.dl_type = 0x0800
779 self.match.wildcards = wildcard_set(self.match.wildcards, \
780 ofp.OFPFW_DL_TYPE, \
781 0 \
782 )
783 else:
Howard Persh3340d452012-04-06 16:45:21 -0700784 self.match.wildcards = wildcard_set(self.match.wildcards, \
785 ofp.OFPFW_NW_PROTO, \
786 1 \
787 )
Dan Talayco910a8282012-04-07 00:05:20 -0700788
rootf6af1672012-04-06 09:46:29 -0700789 if wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
790 or exact\
791 or flip_coin():
792 self.match.tp_src = fi.rand_l4_port()
793 # Specifying a L4 port requires that IP protcol is
794 # one of {ICMP, TCP, UDP}
795 if flip_coin():
796 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700797 self.match.wildcards = wildcard_set(self.match.wildcards, \
798 ofp.OFPFW_NW_PROTO, \
799 0 \
800 )
rootf6af1672012-04-06 09:46:29 -0700801 # Specifying a L4 port requirues that Ethertype is IP
802 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700803 self.match.wildcards = wildcard_set(self.match.wildcards, \
804 ofp.OFPFW_DL_TYPE, \
805 0 \
806 )
rootf6af1672012-04-06 09:46:29 -0700807 if self.match.nw_proto == 1:
808 self.match.tp_src = self.match.tp_src & 0xff
809 else:
Howard Persh3340d452012-04-06 16:45:21 -0700810 self.match.wildcards = wildcard_set(self.match.wildcards, \
811 ofp.OFPFW_TP_SRC, \
812 1 \
813 )
rootf6af1672012-04-06 09:46:29 -0700814
815 if wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
816 or exact \
817 or flip_coin():
818 self.match.tp_dst = fi.rand_l4_port()
819 # Specifying a L4 port requires that IP protcol is
820 # one of {ICMP, TCP, UDP}
821 if flip_coin():
822 self.match.nw_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700823 self.match.wildcards = wildcard_set(self.match.wildcards, \
824 ofp.OFPFW_NW_PROTO, \
825 0 \
826 )
rootf6af1672012-04-06 09:46:29 -0700827 # Specifying a L4 port requirues that Ethertype is IP
828 self.match.dl_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700829 self.match.wildcards = wildcard_set(self.match.wildcards, \
830 ofp.OFPFW_DL_TYPE, \
831 0 \
832 )
rootf6af1672012-04-06 09:46:29 -0700833 if self.match.nw_proto == 1:
834 self.match.tp_dst = self.match.tp_dst & 0xff
835 else:
Howard Persh3340d452012-04-06 16:45:21 -0700836 self.match.wildcards = wildcard_set(self.match.wildcards, \
837 ofp.OFPFW_TP_DST, \
838 1 \
839 )
rootf6af1672012-04-06 09:46:29 -0700840
841 # If nothing is wildcarded, it is an exact flow spec -- some switches
Howard Persh3340d452012-04-06 16:45:21 -0700842 # (Open vSwitch, for one) *require* that exact flow specs
843 # have priority 65535.
844 self.priority = 65535 if self.match.wildcards == 0 \
845 else fi.rand_priority()
rootf6af1672012-04-06 09:46:29 -0700846
847 # N.B. Don't make the timeout too short, else the flow might
848 # disappear before we get a chance to check for it.
849 t = random.randint(0, 65535)
850 self.idle_timeout = 0 if t < 60 else t
851 t = random.randint(0, 65535)
852 self.hard_timeout = 0 if t < 60 else t
853
854 self.rand_mod(fi, valid_actions, valid_ports)
855
856 return self
857
858 # Return flow cfg in canonical form
Howard Persh3340d452012-04-06 16:45:21 -0700859 # - There are dependencies between flow qualifiers, e.g. it only makes
860 # sense to qualify nw_proto if dl_type is qualified to be 0x0800 (IP).
861 # The canonical form of flow match criteria will "wildcard out"
862 # all such cases.
rootf6af1672012-04-06 09:46:29 -0700863 def canonical(self):
864 result = copy.deepcopy(self)
Howard Persh07d99e62012-04-09 15:26:57 -0700865
866 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_VLAN) != 0:
867 result.match.wildcards = wildcard_set(result.match.wildcards, \
868 ofp.OFPFW_DL_VLAN_PCP, \
869 1 \
870 )
871
rootf6af1672012-04-06 09:46:29 -0700872 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
873 or result.match.dl_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700874 # dl_tyoe is wildcarded, or specified as something other
875 # than IP or ARP
Howard Persh07d99e62012-04-09 15:26:57 -0700876 # => nw_src, nw_dst, nw_proto cannot be specified,
877 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700878 result.match.wildcards = wildcard_set(result.match.wildcards, \
879 ofp.OFPFW_NW_SRC_MASK, \
880 32 \
881 )
882 result.match.wildcards = wildcard_set(result.match.wildcards, \
883 ofp.OFPFW_NW_DST_MASK, \
884 32 \
885 )
Howard Persh3340d452012-04-06 16:45:21 -0700886 result.match.wildcards = wildcard_set(result.match.wildcards, \
887 ofp.OFPFW_NW_PROTO, \
888 1 \
889 )
Howard Persh07d99e62012-04-09 15:26:57 -0700890
891 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
892 or result.match.dl_type != 0x0800:
893 # dl_type is wildcarded, or specified as something other than IP
894 # => nw_tos, tp_src and tp_dst cannot be specified,
895 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700896 result.match.wildcards = wildcard_set(result.match.wildcards, \
897 ofp.OFPFW_NW_TOS, \
898 1 \
899 )
900 result.match.wildcards = wildcard_set(result.match.wildcards, \
901 ofp.OFPFW_TP_SRC, \
902 1 \
903 )
904 result.match.wildcards = wildcard_set(result.match.wildcards, \
905 ofp.OFPFW_TP_DST, \
906 1 \
907 )
Howard Persh07d99e62012-04-09 15:26:57 -0700908 result.match.wildcards = wildcard_set(result.match.wildcards, \
909 ofp.OFPFW_NW_SRC_MASK, \
910 32 \
911 )
912 result.match.wildcards = wildcard_set(result.match.wildcards, \
913 ofp.OFPFW_NW_DST_MASK, \
914 32 \
915 )
916 result.match.wildcards = wildcard_set(result.match.wildcards, \
917 ofp.OFPFW_NW_PROTO, \
918 1 \
919 )
920
rootf6af1672012-04-06 09:46:29 -0700921 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
922 or result.match.nw_proto not in [1, 6, 17]:
Howard Persh3340d452012-04-06 16:45:21 -0700923 # nw_proto is wildcarded, or specified as something other than ICMP,
924 # TCP or UDP
rootf6af1672012-04-06 09:46:29 -0700925 # => tp_src and tp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700926 result.match.wildcards = wildcard_set(result.match.wildcards, \
927 ofp.OFPFW_TP_SRC, \
928 1 \
929 )
930 result.match.wildcards = wildcard_set(result.match.wildcards, \
931 ofp.OFPFW_TP_DST, \
932 1 \
933 )
rootf6af1672012-04-06 09:46:29 -0700934 return result
935
Howard Persh680b92a2012-03-31 13:34:35 -0700936 # Overlap check
937 # delf == True <=> Check for delete overlap, else add overlap
938 # "Add overlap" is defined as there exists a packet that could match both the
939 # receiver and argument flowspecs
940 # "Delete overlap" is defined as the specificity of the argument flowspec
941 # is greater than or equal to the specificity of the receiver flowspec
942 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -0700943 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
944 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700945 if self.match.in_port != x.match.in_port:
946 return False # Both specified, and not equal
947 elif delf:
948 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700949 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
950 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700951 if self.match.dl_vlan != x.match.dl_vlan:
952 return False # Both specified, and not equal
953 elif delf:
954 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700955 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
956 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700957 if self.match.dl_src != x.match.dl_src:
958 return False # Both specified, and not equal
959 elif delf:
960 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700961 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
962 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700963 if self.match.dl_dst != x.match.dl_dst:
964 return False # Both specified, and not equal
965 elif delf:
966 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700967 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
968 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700969 if self.match.dl_type != x.match.dl_type:
970 return False # Both specified, and not equal
971 elif delf:
972 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -0700973 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
974 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700975 if self.match.nw_proto != x.match.nw_proto:
976 return False # Both specified, and not equal
977 elif delf:
978 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700979 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
980 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700981 if self.match.tp_src != x.match.tp_src:
982 return False # Both specified, and not equal
983 elif delf:
984 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700985 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
986 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700987 if self.match.tp_dst != x.match.tp_dst:
988 return False # Both specified, and not equal
989 elif delf:
990 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -0700991 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
992 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700993 if delf and na < nb:
994 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -0700995 if (na < 32 and nb < 32):
996 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
997 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -0700998 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -0700999 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
1000 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001001 if delf and na < nb:
1002 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001003 if (na < 32 and nb < 32):
1004 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
1005 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
rootf6af1672012-04-06 09:46:29 -07001006 return False # Overlapping bits not equal
1007 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
1008 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001009 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
1010 return False # Both specified, and not equal
1011 elif delf:
1012 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001013 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
1014 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001015 if self.match.nw_tos != x.match.nw_tos:
1016 return False # Both specified, and not equal
1017 elif delf:
1018 return False # Receiver more specific
1019 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -07001020
1021 def to_flow_mod_msg(self, msg):
1022 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -07001023 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001024 msg.idle_timeout = self.idle_timeout
1025 msg.hard_timeout = self.hard_timeout
1026 msg.priority = self.priority
1027 msg.actions = self.actions
1028 return msg
1029
1030 def from_flow_stat(self, msg):
1031 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -07001032 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001033 self.idle_timeout = msg.idle_timeout
1034 self.hard_timeout = msg.hard_timeout
1035 self.priority = msg.priority
1036 self.actions = msg.actions
1037
rootf6af1672012-04-06 09:46:29 -07001038 def from_flow_rem(self, msg):
1039 self.match = msg.match
1040 self.idle_timeout = msg.idle_timeout
1041 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -07001042
Howard Pershc7963582012-03-29 10:02:59 -07001043
rootf6af1672012-04-06 09:46:29 -07001044class Flow_Tbl:
1045 def clear(self):
1046 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001047
rootf6af1672012-04-06 09:46:29 -07001048 def __init__(self):
1049 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001050
rootf6af1672012-04-06 09:46:29 -07001051 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001052 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001053
1054 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001055 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001056
1057 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001058 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001059
1060 def values(self):
1061 return self.dict.values()
1062
1063 def count(self):
1064 return len(self.dict)
1065
1066 def rand(self, sw, fi, num_flows):
1067 self.clear()
1068 i = 0
1069 tbl = 0
1070 j = 0
1071 while i < num_flows:
1072 fc = Flow_Cfg()
1073 fc.rand(fi, \
1074 sw.tbl_stats.stats[tbl].wildcards, \
1075 sw.sw_features.actions, \
1076 sw.valid_ports \
1077 )
1078 fc = fc.canonical()
1079 if self.find(fc):
1080 continue
1081 fc.send_rem = False
1082 self.insert(fc)
1083 i = i + 1
1084 j = j + 1
1085 if j >= sw.tbl_stats.stats[tbl].max_entries:
1086 tbl = tbl + 1
1087 j = 0
1088
1089
Howard Persh3340d452012-04-06 16:45:21 -07001090error_msgs = []
1091removed_msgs = []
1092
1093def error_handler(self, msg, rawmsg):
Dan Talayco910a8282012-04-07 00:05:20 -07001094 fq_logger.debug("Got an ERROR message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001095 % (msg.type, msg.code) \
1096 )
Howard Persh07d99e62012-04-09 15:26:57 -07001097 fq_logger.debug("Message header:")
1098 fq_logger.debug(msg.header.show())
Howard Persh3340d452012-04-06 16:45:21 -07001099 global error_msgs
1100 error_msgs.append(msg)
1101 pass
1102
1103def removed_handler(self, msg, rawmsg):
Dan Talayco910a8282012-04-07 00:05:20 -07001104 fq_logger.debug("Got a REMOVED message")
Howard Persh07d99e62012-04-09 15:26:57 -07001105 fq_logger.debug("Message header:")
1106 fq_logger.debug(msg.header.show())
Howard Persh3340d452012-04-06 16:45:21 -07001107 global removed_msgs
1108 removed_msgs.append(msg)
1109 pass
1110
rootf6af1672012-04-06 09:46:29 -07001111class Switch:
1112 # Members:
1113 # controller - switch's test controller
1114 # sw_features - switch's OFPT_FEATURES_REPLY message
1115 # valid_ports - list of valid port numbers
1116 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1117 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1118 # flow_tbl - (test's idea of) switch's flow table
1119
1120 def __init__(self):
1121 self.controller = None
1122 self.sw_features = None
1123 self.valid_ports = []
1124 self.tbl_stats = None
1125 self.flow_stats = None
1126 self.flow_tbl = Flow_Tbl()
1127
Howard Persh3340d452012-04-06 16:45:21 -07001128 def controller_set(self, controller):
1129 self.controller = controller
1130 # Register error message handler
1131 global error_msgs
1132 error_msgs = []
1133 controller.register(ofp.OFPT_ERROR, error_handler)
1134 controller.register(ofp.OFPT_FLOW_REMOVED, removed_handler)
1135
rootf6af1672012-04-06 09:46:29 -07001136 def features_get(self):
1137 # Get switch features
1138 request = message.features_request()
1139 (self.sw_features, pkt) = self.controller.transact(request, timeout=2)
1140 if self.sw_features is None:
1141 return False
1142 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Howard Persh3340d452012-04-06 16:45:21 -07001143 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1144 # is that universal?
1145
1146 # TBD - There seems to be variability in which switches support which
1147 # ports; need to sort that out
1148 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1149# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1150# ofp.OFPP_NORMAL, \
1151# ofp.OFPP_FLOOD, \
1152# ofp.OFPP_ALL, \
1153# ofp.OFPP_CONTROLLER \
1154# ] \
1155# )
Howard Persh07d99e62012-04-09 15:26:57 -07001156 actions_override = test_param_get(fq_config, "actions", -1)
1157 if actions_override != -1:
1158 self.sw_features.actions = actions_override
1159
rootf6af1672012-04-06 09:46:29 -07001160 return True
1161
1162 def tbl_stats_get(self):
1163 # Get table stats
Howard Persh680b92a2012-03-31 13:34:35 -07001164 request = message.table_stats_request()
rootf6af1672012-04-06 09:46:29 -07001165 (self.tbl_stats, pkt) = self.controller.transact(request, timeout=2)
Howard Persh07d99e62012-04-09 15:26:57 -07001166 if self.tbl_stats is None:
1167 return False
1168 for ts in self.tbl_stats.stats:
1169 wildcards_override = test_param_get(fq_config, "wildcards", -1)
1170 if wildcards_override != -1:
1171 ts.wildcards = wildcards_override
1172 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001173
rootf6af1672012-04-06 09:46:29 -07001174 def flow_stats_get(self):
1175 request = message.flow_stats_request()
Howard Persh680b92a2012-03-31 13:34:35 -07001176 query_match = ofp.ofp_match()
1177 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001178 request.match = query_match
1179 request.table_id = 0xff
1180 request.out_port = ofp.OFPP_NONE;
Howard Persh3340d452012-04-06 16:45:21 -07001181 if self.controller.message_send(request) == -1:
1182 return False
1183 # <TBD>
1184 # Glue together successive reponse messages for stats reply.
1185 # Looking at the "more" flag and performing re-assembly
1186 # should be a part of the infrastructure.
1187 # </TBD>
1188 n = 0
1189 while True:
1190 # TBD - Check for "more" flag
Howard Persh07d99e62012-04-09 15:26:57 -07001191 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY, 4)
Howard Persh3340d452012-04-06 16:45:21 -07001192 if resp is None:
1193 break
1194 if n == 0:
1195 self.flow_stats = resp
1196 else:
1197 self.flow_stats.stats.extend(resp.stats)
1198 n = n + 1
1199 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001200
rootf6af1672012-04-06 09:46:29 -07001201 def flow_add(self, flow_cfg, overlapf = False):
Howard Persh680b92a2012-03-31 13:34:35 -07001202 flow_mod_msg = message.flow_mod()
1203 flow_mod_msg.command = ofp.OFPFC_ADD
1204 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001205 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001206 if overlapf:
1207 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001208 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001209 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Howard Persh07d99e62012-04-09 15:26:57 -07001210 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
1211 fq_logger.debug("Sending flow_mod(add), xid=%d" % (flow_mod_msg.header.xid))
rootf6af1672012-04-06 09:46:29 -07001212 return (self.controller.message_send(flow_mod_msg) != -1)
Howard Persh680b92a2012-03-31 13:34:35 -07001213
rootf6af1672012-04-06 09:46:29 -07001214 def flow_mod(self, flow_cfg, strictf):
Howard Persh680b92a2012-03-31 13:34:35 -07001215 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001216 flow_mod_msg.command = ofp.OFPFC_MODIFY_STRICT if strictf \
1217 else ofp.OFPFC_MODIFY
Howard Persh680b92a2012-03-31 13:34:35 -07001218 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001219 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001220 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
1221 fq_logger.debug("Sending flow_mod(mod), xid=%d" % (flow_mod_msg.header.xid))
rootf6af1672012-04-06 09:46:29 -07001222 return (self.controller.message_send(flow_mod_msg) != -1)
1223
1224 def flow_del(self, flow_cfg, strictf):
1225 flow_mod_msg = message.flow_mod()
Howard Persh3340d452012-04-06 16:45:21 -07001226 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT if strictf \
1227 else ofp.OFPFC_DELETE
rootf6af1672012-04-06 09:46:29 -07001228 flow_mod_msg.buffer_id = 0xffffffff
1229 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001230 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001231 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh07d99e62012-04-09 15:26:57 -07001232 flow_mod_msg.header.xid = random.randrange(1,0xffffffff)
1233 fq_logger.debug("Sending flow_mod(del), xid=%d" % (flow_mod_msg.header.xid))
rootf6af1672012-04-06 09:46:29 -07001234 return (self.controller.message_send(flow_mod_msg) != -1)
1235
1236 def barrier(self):
1237 barrier = message.barrier_request()
Howard Persh07d99e62012-04-09 15:26:57 -07001238 (resp, pkt) = self.controller.transact(barrier, 20)
rootf6af1672012-04-06 09:46:29 -07001239 return (resp is not None)
1240
Howard Persh3340d452012-04-06 16:45:21 -07001241 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001242 result = True
Howard Persh3340d452012-04-06 16:45:21 -07001243 global error_msgs
Dan Talayco910a8282012-04-07 00:05:20 -07001244 fq_logger.debug("Expecting %d error messages" % (num_exp))
Howard Persh3340d452012-04-06 16:45:21 -07001245 num_got = len(error_msgs)
Dan Talayco910a8282012-04-07 00:05:20 -07001246 fq_logger.debug("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001247 if num_got != num_exp:
Dan Talayco910a8282012-04-07 00:05:20 -07001248 fq_logger.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001249 result = False
1250 if num_exp == 0:
1251 return result
1252 elif num_exp == 1:
Dan Talayco910a8282012-04-07 00:05:20 -07001253 fq_logger.debug("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001254 % (type, code) \
1255 )
1256 f = False
1257 for e in error_msgs:
1258 if e.type == type and e.code == code:
Dan Talayco910a8282012-04-07 00:05:20 -07001259 fq_logger.debug("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001260 f = True
1261 if not f:
Dan Talayco910a8282012-04-07 00:05:20 -07001262 fq_logger.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001263 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001264 else:
Dan Talayco910a8282012-04-07 00:05:20 -07001265 fq_logger.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001266 result = False
1267 return result
1268
Howard Persh3340d452012-04-06 16:45:21 -07001269 def removed_verify(self, num_exp):
1270 result = True
1271 global removed_msgs
Dan Talayco910a8282012-04-07 00:05:20 -07001272 fq_logger.debug("Expecting %d removed messages" % (num_exp))
Howard Persh3340d452012-04-06 16:45:21 -07001273 num_got = len(removed_msgs)
Dan Talayco910a8282012-04-07 00:05:20 -07001274 fq_logger.debug("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001275 if num_got != num_exp:
Dan Talayco910a8282012-04-07 00:05:20 -07001276 fq_logger.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001277 result = False
1278 if num_exp < 2:
1279 return result
Dan Talayco910a8282012-04-07 00:05:20 -07001280 fq_logger.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001281 return False
1282
1283
Dan Talayco910a8282012-04-07 00:05:20 -07001284# fq_logger.debug("Expecting %d error messages" % (num))
Howard Persh3340d452012-04-06 16:45:21 -07001285# if num > 0:
Dan Talayco910a8282012-04-07 00:05:20 -07001286# fq_logger.debug("with type=%d code=%d" % (type, code))
Howard Persh3340d452012-04-06 16:45:21 -07001287# result = True
1288# n = 0
1289# while True:
1290# (errmsg, pkt) = self.controller.poll(ofp.OFPT_ERROR, 1)
1291# if errmsg is None:
1292# break
Dan Talayco910a8282012-04-07 00:05:20 -07001293# fq_logger.debug("Got error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001294# % (errmsg.type, errmsg.code) \
1295# )
1296# if num == 0 or errmsg.type != type or errmsg.code != code:
Dan Talayco910a8282012-04-07 00:05:20 -07001297# fq_logger.debug("Unexpected error message")
Howard Persh3340d452012-04-06 16:45:21 -07001298# result = False
1299# n = n + 1
1300# if n != num:
Dan Talayco910a8282012-04-07 00:05:20 -07001301# fq_logger.error("Received %d error messages" % (n))
Howard Persh3340d452012-04-06 16:45:21 -07001302# result = False
1303# return result
1304
rootf6af1672012-04-06 09:46:29 -07001305 def flow_tbl_verify(self):
1306 result = True
1307
1308 # Verify flow count in switch
Dan Talayco910a8282012-04-07 00:05:20 -07001309 fq_logger.debug("Reading table stats")
1310 fq_logger.debug("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001311 if not self.tbl_stats_get():
Dan Talayco910a8282012-04-07 00:05:20 -07001312 fq_logger.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001313 return False
1314 n = 0
1315 for ts in self.tbl_stats.stats:
1316 n = n + ts.active_count
Dan Talayco910a8282012-04-07 00:05:20 -07001317 fq_logger.debug("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001318 % (n) \
1319 )
1320 if n != self.flow_tbl.count():
Dan Talayco910a8282012-04-07 00:05:20 -07001321 fq_logger.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001322 result = False
1323
1324 # Read flows from switch
Dan Talayco910a8282012-04-07 00:05:20 -07001325 fq_logger.debug("Retrieving flows from switch")
1326 fq_logger.debug("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001327 if not self.flow_stats_get():
Dan Talayco910a8282012-04-07 00:05:20 -07001328 fq_logger.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001329 return False
Dan Talayco910a8282012-04-07 00:05:20 -07001330 fq_logger.debug("Retrieved %d flows" % (len(self.flow_stats.stats)))
rootf6af1672012-04-06 09:46:29 -07001331
1332 # Verify flows returned by switch
1333
1334 if len(self.flow_stats.stats) != self.flow_tbl.count():
Dan Talayco910a8282012-04-07 00:05:20 -07001335 fq_logger.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001336 result = False
1337
Dan Talayco910a8282012-04-07 00:05:20 -07001338 fq_logger.debug("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001339 for fc in self.flow_tbl.values():
1340 fc.matched = False
1341 for fs in self.flow_stats.stats:
1342 flow_in = Flow_Cfg()
1343 flow_in.from_flow_stat(fs)
Dan Talayco910a8282012-04-07 00:05:20 -07001344 fq_logger.debug("Received flow:")
1345 fq_logger.debug(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001346 fc = self.flow_tbl.find(flow_in)
1347 if fc is None:
Dan Talayco910a8282012-04-07 00:05:20 -07001348 fq_logger.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001349 result = False
1350 elif fc.matched:
Dan Talayco910a8282012-04-07 00:05:20 -07001351 fq_logger.error("re-matches defined flow:")
1352 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07001353 result = False
1354 else:
Dan Talayco910a8282012-04-07 00:05:20 -07001355 fq_logger.debug("matched")
rootf6af1672012-04-06 09:46:29 -07001356 if not flow_in == fc:
Dan Talayco910a8282012-04-07 00:05:20 -07001357 fq_logger.error("Non-key portions of flow do not match")
rootf6af1672012-04-06 09:46:29 -07001358 result = False
1359 fc.matched = True
1360 for fc in self.flow_tbl.values():
1361 if not fc.matched:
Dan Talayco910a8282012-04-07 00:05:20 -07001362 fq_logger.error("Defined flow:")
1363 fq_logger.error(str(fc))
1364 fq_logger.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001365 result = False
1366
1367 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001368
Howard Persh07d99e62012-04-09 15:26:57 -07001369# FLOW ADD 5
1370#
1371# OVERVIEW
1372# Add flows to switch, read back and verify flow configurations
1373#
1374# PURPOSE
1375# - Test acceptance of flow adds
1376# - Test ability of switch to process additions to flow table in random
1377# priority order
1378# - Test correctness of flow configuration responses
1379#
1380# PARAMETERS
1381#
1382# Name: num_flows
1383# Type: number
1384# Description:
1385# Number of flows to define; 0 => maximum number of flows, as determined
1386# from switch capabilities
1387# Default: 100
1388#
1389# PROCESS
1390# 1. Delete all flows from switch
1391# 2. Generate <num_flows> distinct flow configurations
1392# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1393# 4. Verify that no OFPT_ERROR responses were generated by switch
1394# 5. Retrieve flow stats from switch
1395# 6. Compare flow configurations returned by switch
1396# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1397# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001398
rootf6af1672012-04-06 09:46:29 -07001399class Flow_Add_5(basic.SimpleProtocol):
1400 """
1401 Test FLOW_ADD_5 from draft top-half test plan
1402
1403 INPUTS
1404 num_flows - Number of flows to generate
1405 """
Howard Persh680b92a2012-03-31 13:34:35 -07001406
rootf6af1672012-04-06 09:46:29 -07001407 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001408 fq_logger.debug("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001409
Dan Talayco910a8282012-04-07 00:05:20 -07001410 num_flows = test_param_get(fq_config, "num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001411
Howard Pershc7963582012-03-29 10:02:59 -07001412 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001413
Dan Talayco910a8282012-04-07 00:05:20 -07001414 fq_logger.debug("Deleting all flows from switch")
1415 rc = delete_all_flows(self.controller, fq_logger)
Howard Pershc7963582012-03-29 10:02:59 -07001416 self.assertEqual(rc, 0, "Failed to delete all flows")
1417
rootf6af1672012-04-06 09:46:29 -07001418 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001419
Dan Talayco910a8282012-04-07 00:05:20 -07001420 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001421 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001422 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001423 self.assertTrue(sw.features_get(), "Get switch features failed")
1424 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
Howard Pershc7963582012-03-29 10:02:59 -07001425
rootf6af1672012-04-06 09:46:29 -07001426 if num_flows == 0:
1427 # Number of flows requested was 0
1428 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001429
rootf6af1672012-04-06 09:46:29 -07001430 for ts in sw.tbl_stats.stats:
1431 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001432
Dan Talayco910a8282012-04-07 00:05:20 -07001433 fq_logger.debug("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001434
1435 # Dream up some flow information, i.e. space to chose from for
1436 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001437
rootf6af1672012-04-06 09:46:29 -07001438 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001439 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001440
rootf6af1672012-04-06 09:46:29 -07001441 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001442
rootf6af1672012-04-06 09:46:29 -07001443 ft = Flow_Tbl()
1444 ft.rand(sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001445
rootf6af1672012-04-06 09:46:29 -07001446 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001447
Dan Talayco910a8282012-04-07 00:05:20 -07001448 fq_logger.debug("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001449 for fc in ft.values(): # Randomizes order of sending
Dan Talayco910a8282012-04-07 00:05:20 -07001450 fq_logger.debug("Adding flow:")
1451 fq_logger.debug(str(fc));
rootf6af1672012-04-06 09:46:29 -07001452 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001453
rootf6af1672012-04-06 09:46:29 -07001454 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001455
rootf6af1672012-04-06 09:46:29 -07001456 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001457
rootf6af1672012-04-06 09:46:29 -07001458 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001459
rootf6af1672012-04-06 09:46:29 -07001460 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001461
rootf6af1672012-04-06 09:46:29 -07001462 if not sw.errors_verify(0):
1463 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001464
rootf6af1672012-04-06 09:46:29 -07001465 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001466
rootf6af1672012-04-06 09:46:29 -07001467 sw.flow_tbl = ft
1468 if not sw.flow_tbl_verify():
1469 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001470
rootf6af1672012-04-06 09:46:29 -07001471 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07001472 fq_logger.debug("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001473
Howard Pershc7963582012-03-29 10:02:59 -07001474
Howard Persh07d99e62012-04-09 15:26:57 -07001475# FLOW ADD 5_1
1476#
1477# OVERVIEW
1478# Verify handling of non-canonical flows
1479#
1480# PURPOSE
1481# - Test that switch detects and correctly responds to a non-canonical flow
1482# definition. A canonical flow is one that satisfies all match qualifier
1483# dependencies; a non-canonical flow is one that does not.
1484#
1485# PARAMETERS
1486# - None
1487#
1488# PROCESS
1489# 1. Delete all flows from switch
1490# 2. Generate 1 flow definition, which is different from its canonicalization
1491# 3. Send flow to switch
1492# 4. Retrieve flow from switch
1493# 5. Compare returned flow to canonical form of defined flow
1494# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1495
1496# Disabled.
1497# Should be DUT dependent.
1498test_prio["Flow_Add_5_1"] = -1
1499
rootf6af1672012-04-06 09:46:29 -07001500class Flow_Add_5_1(basic.SimpleProtocol):
1501 """
1502 Test FLOW_ADD_5.1 from draft top-half test plan
1503
1504 INPUTS
1505 None
1506 """
1507
1508 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001509 fq_logger.debug("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001510
Dan Talayco910a8282012-04-07 00:05:20 -07001511 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001512
1513 # Clear all flows from switch
1514
Dan Talayco910a8282012-04-07 00:05:20 -07001515 fq_logger.debug("Deleting all flows from switch")
1516 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001517 self.assertEqual(rc, 0, "Failed to delete all flows")
1518
1519 # Get switch capabilites
1520
Dan Talayco910a8282012-04-07 00:05:20 -07001521 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001522 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001523 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001524 self.assertTrue(sw.features_get(), "Get switch features failed")
1525 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1526
1527 # Dream up some flow information, i.e. space to chose from for
1528 # random flow parameter generation
1529
1530 fi = Flow_Info()
1531 fi.rand(10)
1532
1533 # Dream up a flow config that will be canonicalized by the switch
1534
1535 while True:
1536 fc = Flow_Cfg()
1537 fc.rand(fi, \
1538 sw.tbl_stats.stats[0].wildcards, \
1539 sw.sw_features.actions, \
1540 sw.valid_ports \
1541 )
1542 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001543 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001544 break
1545
1546 ft = Flow_Tbl()
1547 ft.insert(fcc)
1548
1549 # Send it to the switch
1550
Dan Talayco910a8282012-04-07 00:05:20 -07001551 fq_logger.debug("Sending flow add to switch:")
1552 fq_logger.debug(str(fc))
1553 fq_logger.debug("should be canonicalized as:")
1554 fq_logger.debug(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001555 fc.send_rem = False
1556 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1557
1558 # Do barrier, to make sure all flows are in
1559
1560 self.assertTrue(sw.barrier(), "Barrier failed")
1561
1562 result = True
1563
1564 # Check for any error messages
1565
1566 if not sw.errors_verify(0):
1567 result = False
1568
1569 # Verify flow table
1570
1571 sw.flow_tbl = ft
1572 if not sw.flow_tbl_verify():
1573 result = False
1574
1575 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07001576 fq_logger.debug("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001577
1578
Howard Persh07d99e62012-04-09 15:26:57 -07001579# FLOW ADD 6
1580#
1581# OVERVIEW
1582# Test flow table capacity
1583#
1584# PURPOSE
1585# - Test switch can accept as many flow definitions as it claims
1586# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1587# - Test that attempting to create flows beyond capacity does not corrupt
1588# flow table
1589#
1590# PARAMETERS
1591# None
1592#
1593# PROCESS
1594# 1. Delete all flows from switch
1595# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1596# to determine flow table size, N
1597# 3. Generate (N + 1) distinct flow configurations
1598# 4. Send N flow adds to switch, for flows generated in step 3 above
1599# 5. Verify flow table in switch
1600# 6. Send one more flow add to switch
1601# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1602# response was generated by switch, for last flow mod sent
1603# 7. Retrieve flow stats from switch
1604# 8. Verify flow table in switch
1605# 9. Test PASSED iff:
1606# - error message received, for correct flow
1607# - last flow definition sent to switch is not in flow table
1608# else test FAILED
1609
Howard Persh3340d452012-04-06 16:45:21 -07001610# Disabled because of bogus capacity reported by OVS.
1611# Should be DUT dependent.
1612test_prio["Flow_Add_6"] = -1
1613
rootf6af1672012-04-06 09:46:29 -07001614class Flow_Add_6(basic.SimpleProtocol):
1615 """
1616 Test FLOW_ADD_6 from draft top-half test plan
1617
1618 INPUTS
1619 num_flows - Number of flows to generate
1620 """
Howard Pershc7963582012-03-29 10:02:59 -07001621
1622 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001623 fq_logger.debug("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001624
rootf6af1672012-04-06 09:46:29 -07001625 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001626
Dan Talayco910a8282012-04-07 00:05:20 -07001627 fq_logger.debug("Deleting all flows from switch")
1628 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001629 self.assertEqual(rc, 0, "Failed to delete all flows")
1630
1631 # Get switch capabilites
1632
Dan Talayco910a8282012-04-07 00:05:20 -07001633 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001634 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001635 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001636 self.assertTrue(sw.features_get(), "Get switch features failed")
1637 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1638
root2843d2b2012-04-06 10:27:46 -07001639 num_flows = 0
rootf6af1672012-04-06 09:46:29 -07001640 for ts in sw.tbl_stats.stats:
1641 num_flows = num_flows + ts.max_entries
1642
Dan Talayco910a8282012-04-07 00:05:20 -07001643 fq_logger.debug("Switch capacity is %d flows" % (num_flows))
1644 fq_logger.debug("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001645
1646 # Dream up some flow information, i.e. space to chose from for
1647 # random flow parameter generation
1648
1649 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001650 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001651
1652 # Create a flow table, to switch's capacity
1653
1654 ft = Flow_Tbl()
1655 ft.rand(sw, fi, num_flows)
1656
1657 # Send flow table to switch
1658
Dan Talayco910a8282012-04-07 00:05:20 -07001659 fq_logger.debug("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001660 for fc in ft.values(): # Randomizes order of sending
Dan Talayco910a8282012-04-07 00:05:20 -07001661 fq_logger.debug("Adding flow:")
1662 fq_logger.debug(str(fc));
rootf6af1672012-04-06 09:46:29 -07001663 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1664
1665 # Do barrier, to make sure all flows are in
1666
1667 self.assertTrue(sw.barrier(), "Barrier failed")
1668
1669 result = True
1670
1671 # Check for any error messages
1672
1673 if not sw.errors_verify(0):
1674 result = False
1675
1676 # Dream up one more flow
1677
Dan Talayco910a8282012-04-07 00:05:20 -07001678 fq_logger.debug("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001679 while True:
1680 fc = Flow_Cfg()
1681 fc.rand(fi, \
Howard Persh07d99e62012-04-09 15:26:57 -07001682 sw.tbl_stats.stats[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001683 sw.sw_features.actions, \
1684 sw.valid_ports \
1685 )
1686 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001687 if not ft.find(fc):
1688 break
rootf6af1672012-04-06 09:46:29 -07001689
1690 # Send one-more flow
1691
1692 fc.send_rem = False
Dan Talayco910a8282012-04-07 00:05:20 -07001693 fq_logger.debug("Sending flow add switch")
1694 fq_logger.debug(str(fc));
rootf6af1672012-04-06 09:46:29 -07001695 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1696
1697 # Do barrier, to make sure all flows are in
1698
1699 self.assertTrue(sw.barrier(), "Barrier failed")
1700
1701 # Check for expected error message
1702
1703 if not sw.errors_verify(1, \
1704 ofp.OFPET_FLOW_MOD_FAILED, \
1705 ofp.OFPFMFC_ALL_TABLES_FULL \
1706 ):
1707 result = False
1708
1709 # Verify flow table
1710
1711 sw.flow_tbl = ft
1712 if not sw.flow_tbl_verify():
1713 result = False
1714
1715 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07001716 fq_logger.debug("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001717
1718
Howard Persh07d99e62012-04-09 15:26:57 -07001719# FLOW ADD 7
1720#
1721# OVERVIEW
1722# Test flow redefinition
1723#
1724# PURPOSE
1725# Verify that successive flow adds with same priority and match criteria
1726# overwrite in flow table
1727#
1728# PARAMETERS
1729# None
1730#
1731# PROCESS
1732# 1. Delete all flows from switch
1733# 2. Generate flow definition F1
1734# 3. Generate flow definition F2, with same key (priority and match) as F1,
1735# but with different actions
1736# 4. Send flow adds for F1 and F2 to switch
1737# 5. Verify flow definitions in switch
1738# 6. Test PASSED iff 1 flow returned by switch, matching configuration of F2;
1739# else test FAILED
1740
rootf6af1672012-04-06 09:46:29 -07001741class Flow_Add_7(basic.SimpleProtocol):
1742 """
1743 Test FLOW_ADD_7 from draft top-half test plan
1744
1745 INPUTS
1746 None
1747 """
1748
1749 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001750 fq_logger.debug("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001751
1752 # Clear all flows from switch
1753
Dan Talayco910a8282012-04-07 00:05:20 -07001754 fq_logger.debug("Deleting all flows from switch")
1755 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001756 self.assertEqual(rc, 0, "Failed to delete all flows")
1757
1758 # Get switch capabilites
1759
Dan Talayco910a8282012-04-07 00:05:20 -07001760 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001761 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001762 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001763 self.assertTrue(sw.features_get(), "Get switch features failed")
1764 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1765
1766 # Dream up some flow information, i.e. space to chose from for
1767 # random flow parameter generation
1768
1769 fi = Flow_Info()
1770 fi.rand(10)
1771
1772 # Dream up a flow config
1773
1774 fc = Flow_Cfg()
1775 fc.rand(fi, \
1776 sw.tbl_stats.stats[0].wildcards, \
1777 sw.sw_features.actions, \
1778 sw.valid_ports \
1779 )
1780 fc = fc.canonical()
1781
1782 # Send it to the switch
1783
Dan Talayco910a8282012-04-07 00:05:20 -07001784 fq_logger.debug("Sending flow add to switch:")
1785 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07001786 ft = Flow_Tbl()
1787 fc.send_rem = False
1788 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1789 ft.insert(fc)
1790
1791 # Dream up some different actions, with the same flow key
1792
1793 fc2 = copy.deepcopy(fc)
1794 while True:
1795 fc2.rand_mod(fi, \
1796 sw.sw_features.actions, \
1797 sw.valid_ports \
1798 )
1799 if fc2 != fc:
1800 break
1801
1802 # Send that to the switch
1803
Dan Talayco910a8282012-04-07 00:05:20 -07001804 fq_logger.debug("Sending flow add to switch:")
1805 fq_logger.debug(str(fc2))
rootf6af1672012-04-06 09:46:29 -07001806 fc2.send_rem = False
1807 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
1808 ft.insert(fc2)
1809
1810 # Do barrier, to make sure all flows are in
1811
1812 self.assertTrue(sw.barrier(), "Barrier failed")
1813
1814 result = True
1815
1816 # Check for any error messages
1817
1818 if not sw.errors_verify(0):
1819 result = False
1820
1821 # Verify flow table
1822
1823 sw.flow_tbl = ft
1824 if not sw.flow_tbl_verify():
1825 result = False
1826
1827 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07001828 fq_logger.debug("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001829
1830
Howard Persh07d99e62012-04-09 15:26:57 -07001831# FLOW ADD 8
1832#
1833# OVERVIEW
1834# Add overlapping flows to switch, verify that overlapping flows are rejected
1835#
1836# PURPOSE
1837# - Test detection of overlapping flows by switch
1838# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
1839# - Test rejection of overlapping flows
1840# - Test defining overlapping flows does not corrupt flow table
1841#
1842# PARAMETERS
1843# None
1844#
1845# PROCESS
1846# 1. Delete all flows from switch
1847# 2. Generate flow definition F1
1848# 3. Generate flow definition F2, with key overlapping F1
1849# 4. Send flow add to switch, for F1
1850# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
1851# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
1852# was generated by switch
1853# 7. Verifiy flows configured in swtich
1854# 8. Test PASSED iff:
1855# - error message received, for overlapping flow
1856# - overlapping flow is not in flow table
1857# else test FAILED
1858
rootf6af1672012-04-06 09:46:29 -07001859class Flow_Add_8(basic.SimpleProtocol):
1860 """
1861 Test FLOW_ADD_8 from draft top-half test plan
1862
1863 INPUTS
1864 None
1865 """
1866
1867 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001868 fq_logger.debug("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001869
1870 # Clear all flows from switch
1871
Dan Talayco910a8282012-04-07 00:05:20 -07001872 fq_logger.debug("Deleting all flows from switch")
1873 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001874 self.assertEqual(rc, 0, "Failed to delete all flows")
1875
1876 # Get switch capabilites
1877
Dan Talayco910a8282012-04-07 00:05:20 -07001878 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07001879 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07001880 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07001881 self.assertTrue(sw.features_get(), "Get switch features failed")
1882 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
1883
1884 # Dream up some flow information, i.e. space to chose from for
1885 # random flow parameter generation
1886
1887 fi = Flow_Info()
1888 fi.rand(10)
1889
1890 # Dream up a flow config, with at least 1 qualifier specified
1891
1892 fc = Flow_Cfg()
1893 while True:
1894 fc.rand(fi, \
1895 sw.tbl_stats.stats[0].wildcards, \
1896 sw.sw_features.actions, \
1897 sw.valid_ports \
1898 )
1899 fc = fc.canonical()
1900 if fc.match.wildcards != ofp.OFPFW_ALL:
1901 break
1902
1903 # Send it to the switch
1904
Dan Talayco910a8282012-04-07 00:05:20 -07001905 fq_logger.debug("Sending flow add to switch:")
1906 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07001907 ft = Flow_Tbl()
1908 fc.send_rem = False
1909 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1910 ft.insert(fc)
1911
1912 # Wildcard out one qualifier that was specified, to create an
1913 # overlapping flow
1914
1915 fc2 = copy.deepcopy(fc)
1916 for wi in shuffle(range(len(all_wildcards_list))):
1917 w = all_wildcards_list[wi]
1918 if (fc2.match.wildcards & w) == 0:
1919 break
1920 if w == ofp.OFPFW_NW_SRC_MASK:
1921 w = ofp.OFPFW_NW_SRC_ALL
1922 wn = "OFPFW_NW_SRC"
1923 elif w == ofp.OFPFW_NW_DST_MASK:
1924 w = ofp.OFPFW_NW_DST_ALL
1925 wn = "OFPFW_NW_DST"
1926 else:
1927 wn = all_wildcard_names[w]
Dan Talayco910a8282012-04-07 00:05:20 -07001928 fq_logger.debug("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07001929 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07001930 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07001931
1932 # Send that to the switch, with overlap checking
1933
Dan Talayco910a8282012-04-07 00:05:20 -07001934 fq_logger.debug("Sending flow add to switch:")
1935 fq_logger.debug(str(fc2))
rootf6af1672012-04-06 09:46:29 -07001936 fc2.send_rem = False
1937 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
1938
1939 # Do barrier, to make sure all flows are in
1940 self.assertTrue(sw.barrier(), "Barrier failed")
1941
1942 result = True
1943
1944 # Check for expected error message
1945
1946 if not sw.errors_verify(1, \
1947 ofp.OFPET_FLOW_MOD_FAILED, \
1948 ofp.OFPFMFC_OVERLAP \
1949 ):
1950 result = False
1951
1952 # Verify flow table
1953
1954 sw.flow_tbl = ft
1955 if not sw.flow_tbl_verify():
1956 result = False
1957
1958 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07001959 fq_logger.debug("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001960
1961
Howard Persh07d99e62012-04-09 15:26:57 -07001962# FLOW MODIFY 1
1963#
1964# OVERVIEW
1965# Strict modify of single existing flow
1966#
1967# PURPOSE
1968# - Verify that strict flow modify operates only on specified flow
1969# - Verify that flow is correctly modified
1970#
1971# PARAMETERS
1972# None
1973#
1974# PROCESS
1975# 1. Delete all flows from switch
1976# 2. Generate 1 flow F
1977# 3. Send flow add to switch, for flow F
1978# 4. Generate new action list for flow F, yielding F'
1979# 5. Send strict flow modify to switch, for flow F'
1980# 6. Verify flow table in switch
1981# 7. Test PASSED iff flow returned by switch is F'; else FAILED
1982
rootf6af1672012-04-06 09:46:29 -07001983class Flow_Mod_1(basic.SimpleProtocol):
1984 """
1985 Test FLOW_MOD_1 from draft top-half test plan
1986
1987 INPUTS
1988 None
1989 """
1990
1991 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07001992 fq_logger.debug("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001993
1994 # Clear all flows from switch
1995
Dan Talayco910a8282012-04-07 00:05:20 -07001996 fq_logger.debug("Deleting all flows from switch")
1997 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07001998 self.assertEqual(rc, 0, "Failed to delete all flows")
1999
2000 # Get switch capabilites
2001
Dan Talayco910a8282012-04-07 00:05:20 -07002002 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002003 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002004 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002005 self.assertTrue(sw.features_get(), "Get switch features failed")
2006 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2007
2008 # Dream up some flow information, i.e. space to chose from for
2009 # random flow parameter generation
2010
2011 fi = Flow_Info()
2012 fi.rand(10)
2013
2014 # Dream up a flow config
2015
2016 fc = Flow_Cfg()
2017 fc.rand(fi, \
2018 sw.tbl_stats.stats[0].wildcards, \
2019 sw.sw_features.actions, \
2020 sw.valid_ports \
2021 )
2022 fc = fc.canonical()
2023
2024 # Send it to the switch
2025
Dan Talayco910a8282012-04-07 00:05:20 -07002026 fq_logger.debug("Sending flow add to switch:")
2027 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07002028 ft = Flow_Tbl()
2029 fc.send_rem = False
2030 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2031 ft.insert(fc)
2032
2033 # Dream up some different actions, with the same flow key
2034
2035 fc2 = copy.deepcopy(fc)
2036 while True:
2037 fc2.rand_mod(fi, \
2038 sw.sw_features.actions, \
2039 sw.valid_ports \
2040 )
2041 if fc2 != fc:
2042 break
2043
Howard Persh07d99e62012-04-09 15:26:57 -07002044 fc2.cookie = fc.cookie
2045
rootf6af1672012-04-06 09:46:29 -07002046 # Send that to the switch
2047
Dan Talayco910a8282012-04-07 00:05:20 -07002048 fq_logger.debug("Sending strict flow mod to switch:")
2049 fq_logger.debug(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002050 fc2.send_rem = False
2051 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2052 ft.insert(fc2)
2053
2054 # Do barrier, to make sure all flows are in
2055
2056 self.assertTrue(sw.barrier(), "Barrier failed")
2057
2058 result = True
2059
2060 # Check for any error messages
2061
2062 if not sw.errors_verify(0):
2063 result = False
2064
2065 # Verify flow table
2066
2067 sw.flow_tbl = ft
2068 if not sw.flow_tbl_verify():
2069 result = False
2070
2071 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07002072 fq_logger.debug("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002073
Howard Persh07d99e62012-04-09 15:26:57 -07002074
2075# FLOW MODIFY 2
2076#
2077# OVERVIEW
2078# Loose modify of mutiple flows
2079#
2080# PURPOSE
2081# - Verify that loose flow modify operates only on matching flows
2082# - Verify that matching flows are correctly modified
2083#
2084# PARAMETERS
2085# Name: num_flows
2086# Type: number
2087# Description:
2088# Number of flows to define
2089# Default: 100
2090#
2091# PROCESS
2092# 1. Delete all flows from switch
2093# 2. Generate <num_flows> distinct flow configurations
2094# 3. Send <num_flows> flow adds to switch
2095# 4. Pick 1 defined flow F at random
2096# 5. Create overlapping loose flow mod match criteria by repeatedly
2097# wildcarding out qualifiers in match of F => F',
2098# and create new actions list A' for F'
2099# 6. Send loose flow modify for F' to switch
2100# 7. Verify flow table in swtich
2101# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2102# are returned in step 7 above, each with correct (original or modified)
2103# action list;
2104# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002105
2106class Flow_Mod_2(basic.SimpleProtocol):
2107 """
2108 Test FLOW_MOD_2 from draft top-half test plan
2109
2110 INPUTS
2111 None
2112 """
2113
2114 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07002115 fq_logger.debug("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002116
Dan Talayco910a8282012-04-07 00:05:20 -07002117 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002118
2119 # Clear all flows from switch
2120
Dan Talayco910a8282012-04-07 00:05:20 -07002121 fq_logger.debug("Deleting all flows from switch")
2122 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002123 self.assertEqual(rc, 0, "Failed to delete all flows")
2124
2125 # Get switch capabilites
2126
Dan Talayco910a8282012-04-07 00:05:20 -07002127 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002128 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002129 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002130 self.assertTrue(sw.features_get(), "Get switch features failed")
2131 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2132
2133 # Dream up some flow information, i.e. space to chose from for
2134 # random flow parameter generation
2135
2136 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002137 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002138 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002139
2140 # Dream up some flows
2141
2142 ft = Flow_Tbl()
2143 ft.rand(sw, fi, num_flows)
2144
2145 # Send flow table to switch
2146
Dan Talayco910a8282012-04-07 00:05:20 -07002147 fq_logger.debug("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002148 for fc in ft.values(): # Randomizes order of sending
Dan Talayco910a8282012-04-07 00:05:20 -07002149 fq_logger.debug("Adding flow:")
2150 fq_logger.debug(str(fc));
rootf6af1672012-04-06 09:46:29 -07002151 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2152
2153 # Do barrier, to make sure all flows are in
2154
2155 self.assertTrue(sw.barrier(), "Barrier failed")
2156
2157 result = True
2158
2159 # Check for any error messages
2160
2161 if not sw.errors_verify(0):
2162 result = False
2163
2164 # Verify flow table
2165
2166 sw.flow_tbl = ft
2167 if not sw.flow_tbl_verify():
2168 result = False
2169
2170 # Pick a random flow as a basis
2171
2172 mfc = copy.deepcopy(ft.values()[0])
2173 mfc.rand_mod(fi, sw.sw_features.actions, sw.valid_ports)
2174
2175 # Repeatedly wildcard qualifiers
2176
2177 for wi in shuffle(range(len(all_wildcards_list))):
2178 w = all_wildcards_list[wi]
2179 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2180 n = wildcard_get(mfc.match.wildcards, w)
2181 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002182 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2183 w, \
2184 random.randint(n + 1, 32) \
2185 )
rootf6af1672012-04-06 09:46:29 -07002186 else:
2187 continue
2188 else:
2189 if wildcard_get(mfc.match.wildcards, w) == 0:
2190 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2191 else:
2192 continue
2193 mfc = mfc.canonical()
2194
2195 # Count the number of flows that would be modified
2196
2197 n = 0
2198 for fc in ft.values():
2199 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2200 n = n + 1
2201
2202 # If more than 1, we found our loose delete flow spec
2203 if n > 1:
2204 break
2205
Dan Talayco910a8282012-04-07 00:05:20 -07002206 fq_logger.debug("Modifying %d flows" % (n))
2207 fq_logger.debug("Sending flow mod to switch:")
2208 fq_logger.debug(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002209 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2210
2211 # Do barrier, to make sure all flows are in
2212 self.assertTrue(sw.barrier(), "Barrier failed")
2213
2214 # Check for error message
2215
2216 if not sw.errors_verify(0):
2217 result = False
2218
2219 # Apply flow mod to local flow table
2220
2221 for fc in ft.values():
2222 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002223 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002224
2225 # Verify flow table
2226
2227 sw.flow_tbl = ft
2228 if not sw.flow_tbl_verify():
2229 result = False
2230
2231 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07002232 fq_logger.debug("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002233
2234
Howard Persh07d99e62012-04-09 15:26:57 -07002235# FLOW MODIFY 3
2236
2237# OVERVIEW
2238# Strict modify of non-existent flow
2239#
2240# PURPOSE
2241# Verify that strict modify of a non-existent flow is equivalent to a flow add
2242#
2243# PARAMETERS
2244# None
2245#
2246# PROCESS
2247# 1. Delete all flows from switch
2248# 2. Send single flow mod, as strict modify, to switch
2249# 3. Verify flow table in switch
2250# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2251
rootf6af1672012-04-06 09:46:29 -07002252class Flow_Mod_3(basic.SimpleProtocol):
2253 """
2254 Test FLOW_MOD_3 from draft top-half test plan
2255
2256 INPUTS
2257 None
2258 """
2259
2260 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07002261 fq_logger.debug("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002262
2263 # Clear all flows from switch
2264
Dan Talayco910a8282012-04-07 00:05:20 -07002265 fq_logger.debug("Deleting all flows from switch")
2266 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002267 self.assertEqual(rc, 0, "Failed to delete all flows")
2268
2269 # Get switch capabilites
2270
Dan Talayco910a8282012-04-07 00:05:20 -07002271 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002272 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002273 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002274 self.assertTrue(sw.features_get(), "Get switch features failed")
2275 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2276
2277 # Dream up some flow information, i.e. space to chose from for
2278 # random flow parameter generation
2279
2280 fi = Flow_Info()
2281 fi.rand(10)
2282
2283 # Dream up a flow config
2284
2285 fc = Flow_Cfg()
2286 fc.rand(fi, \
2287 sw.tbl_stats.stats[0].wildcards, \
2288 sw.sw_features.actions, \
2289 sw.valid_ports \
2290 )
2291 fc = fc.canonical()
2292
2293 # Send it to the switch
2294
Dan Talayco910a8282012-04-07 00:05:20 -07002295 fq_logger.debug("Sending flow mod to switch:")
2296 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07002297 ft = Flow_Tbl()
2298 fc.send_rem = False
2299 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2300 ft.insert(fc)
2301
2302 # Do barrier, to make sure all flows are in
2303
2304 self.assertTrue(sw.barrier(), "Barrier failed")
2305
2306 result = True
2307
2308 # Check for any error messages
2309
2310 if not sw.errors_verify(0):
2311 result = False
2312
2313 # Verify flow table
2314
2315 sw.flow_tbl = ft
2316 if not sw.flow_tbl_verify():
2317 result = False
2318
2319 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07002320 fq_logger.debug("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002321
2322
Howard Persh07d99e62012-04-09 15:26:57 -07002323# FLOW DELETE 1
2324#
2325# OVERVIEW
2326# Strict delete of single flow
2327#
2328# PURPOSE
2329# Verify correct operation of strict delete of single defined flow
2330#
2331# PARAMETERS
2332# None
2333#
2334# PROCESS
2335# 1. Delete all flows from switch
2336# 2. Send flow F to switch
2337# 3. Send strict flow delete for F to switch
2338# 4. Verify flow table in swtich
2339# 6. Test PASSED iff all flows sent to switch in step 2 above,
2340# less flow removed in step 3 above, are returned in step 4 above;
2341# else test FAILED
2342
rootf6af1672012-04-06 09:46:29 -07002343class Flow_Del_1(basic.SimpleProtocol):
2344 """
2345 Test FLOW_DEL_1 from draft top-half test plan
2346
2347 INPUTS
2348 None
2349 """
2350
2351 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07002352 fq_logger.debug("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002353
2354 # Clear all flows from switch
2355
Dan Talayco910a8282012-04-07 00:05:20 -07002356 fq_logger.debug("Deleting all flows from switch")
2357 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002358 self.assertEqual(rc, 0, "Failed to delete all flows")
2359
2360 # Get switch capabilites
2361
Dan Talayco910a8282012-04-07 00:05:20 -07002362 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002363 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002364 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002365 self.assertTrue(sw.features_get(), "Get switch features failed")
2366 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2367
2368 # Dream up some flow information, i.e. space to chose from for
2369 # random flow parameter generation
2370
2371 fi = Flow_Info()
2372 fi.rand(10)
2373
2374 # Dream up a flow config
2375
2376 fc = Flow_Cfg()
2377 fc.rand(fi, \
2378 sw.tbl_stats.stats[0].wildcards, \
2379 sw.sw_features.actions, \
2380 sw.valid_ports \
2381 )
2382 fc = fc.canonical()
2383
2384 # Send it to the switch
2385
Dan Talayco910a8282012-04-07 00:05:20 -07002386 fq_logger.debug("Sending flow add to switch:")
2387 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07002388 ft = Flow_Tbl()
2389 fc.send_rem = False
2390 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2391 ft.insert(fc)
2392
2393 # Dream up some different actions, with the same flow key
2394
2395 fc2 = copy.deepcopy(fc)
2396 while True:
2397 fc2.rand_mod(fi, \
2398 sw.sw_features.actions, \
2399 sw.valid_ports \
2400 )
2401 if fc2 != fc:
2402 break
2403
2404 # Delete strictly
2405
Dan Talayco910a8282012-04-07 00:05:20 -07002406 fq_logger.debug("Sending strict flow del to switch:")
2407 fq_logger.debug(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002408 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2409 ft.delete(fc)
2410
2411 # Do barrier, to make sure all flows are in
2412
2413 self.assertTrue(sw.barrier(), "Barrier failed")
2414
2415 result = True
2416
2417 # Check for any error messages
2418
2419 if not sw.errors_verify(0):
2420 result = False
2421
2422 # Verify flow table
2423
2424 sw.flow_tbl = ft
2425 if not sw.flow_tbl_verify():
2426 result = False
2427
2428 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07002429 fq_logger.debug("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002430
2431
Howard Persh07d99e62012-04-09 15:26:57 -07002432# FLOW DELETE 2
2433#
2434# OVERVIEW
2435# Loose delete of multiple flows
2436#
2437# PURPOSE
2438# - Verify correct operation of loose delete of multiple flows
2439#
2440# PARAMETERS
2441# Name: num_flows
2442# Type: number
2443# Description:
2444# Number of flows to define
2445# Default: 100
2446#
2447# PROCESS
2448# 1. Delete all flows from switch
2449# 2. Generate <num_flows> distinct flow configurations
2450# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2451# 4. Pick 1 defined flow F at random
2452# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2453# F' will match more than 1 existing flow key
2454# 6. Send loose flow delete for F' to switch
2455# 7. Verify flow table in switch
2456# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2457# removed in step 6 above (i.e. those that match F'), are returned
2458# in step 7 above;
2459# else test FAILED
2460
rootf6af1672012-04-06 09:46:29 -07002461class Flow_Del_2(basic.SimpleProtocol):
2462 """
2463 Test FLOW_DEL_2 from draft top-half test plan
2464
2465 INPUTS
2466 None
2467 """
2468
2469 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07002470 fq_logger.debug("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002471
Dan Talayco910a8282012-04-07 00:05:20 -07002472 num_flows = test_param_get(fq_config, "num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002473
2474 # Clear all flows from switch
2475
Dan Talayco910a8282012-04-07 00:05:20 -07002476 fq_logger.debug("Deleting all flows from switch")
2477 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002478 self.assertEqual(rc, 0, "Failed to delete all flows")
2479
2480 # Get switch capabilites
2481
Dan Talayco910a8282012-04-07 00:05:20 -07002482 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002483 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002484 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002485 self.assertTrue(sw.features_get(), "Get switch features failed")
2486 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2487
2488 # Dream up some flow information, i.e. space to chose from for
2489 # random flow parameter generation
2490
2491 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002492 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002493 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002494
2495 # Dream up some flows
2496
2497 ft = Flow_Tbl()
2498 ft.rand(sw, fi, num_flows)
2499
2500 # Send flow table to switch
2501
Dan Talayco910a8282012-04-07 00:05:20 -07002502 fq_logger.debug("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002503 for fc in ft.values(): # Randomizes order of sending
Dan Talayco910a8282012-04-07 00:05:20 -07002504 fq_logger.debug("Adding flow:")
2505 fq_logger.debug(str(fc));
rootf6af1672012-04-06 09:46:29 -07002506 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2507
2508 # Do barrier, to make sure all flows are in
2509
2510 self.assertTrue(sw.barrier(), "Barrier failed")
2511
2512 result = True
2513
2514 # Check for any error messages
2515
2516 if not sw.errors_verify(0):
2517 result = False
2518
2519 # Verify flow table
2520
2521 sw.flow_tbl = ft
2522 if not sw.flow_tbl_verify():
2523 result = False
2524
2525 # Pick a random flow as a basis
2526
2527 dfc = copy.deepcopy(ft.values()[0])
2528 dfc.rand_mod(fi, sw.sw_features.actions, sw.valid_ports)
2529
2530 # Repeatedly wildcard qualifiers
2531
2532 for wi in shuffle(range(len(all_wildcards_list))):
2533 w = all_wildcards_list[wi]
2534 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2535 n = wildcard_get(dfc.match.wildcards, w)
2536 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002537 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2538 w, \
2539 random.randint(n + 1, 32) \
2540 )
rootf6af1672012-04-06 09:46:29 -07002541 else:
2542 continue
2543 else:
2544 if wildcard_get(dfc.match.wildcards, w) == 0:
2545 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2546 else:
2547 continue
2548 dfc = dfc.canonical()
2549
2550 # Count the number of flows that would be deleted
2551
2552 n = 0
2553 for fc in ft.values():
2554 if dfc.overlaps(fc, True):
2555 n = n + 1
2556
2557 # If more than 1, we found our loose delete flow spec
2558 if n > 1:
2559 break
2560
Dan Talayco910a8282012-04-07 00:05:20 -07002561 fq_logger.debug("Deleting %d flows" % (n))
2562 fq_logger.debug("Sending flow del to switch:")
2563 fq_logger.debug(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002564 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2565
2566 # Do barrier, to make sure all flows are in
2567 self.assertTrue(sw.barrier(), "Barrier failed")
2568
2569 # Check for error message
2570
2571 if not sw.errors_verify(0):
2572 result = False
2573
2574 # Apply flow mod to local flow table
2575
2576 for fc in ft.values():
2577 if dfc.overlaps(fc, True):
2578 ft.delete(fc)
2579
2580 # Verify flow table
2581
2582 sw.flow_tbl = ft
2583 if not sw.flow_tbl_verify():
2584 result = False
2585
2586 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07002587 fq_logger.debug("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002588
2589
Howard Persh07d99e62012-04-09 15:26:57 -07002590# FLOW DELETE 4
2591#
2592# OVERVIEW
2593# Flow removed messages
2594#
2595# PURPOSE
2596# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2597# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2598#
2599# PARAMETERS
2600# None
2601#
2602# PROCESS
2603# 1. Delete all flows from switch
2604# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2605# 3. Send strict flow delete of flow to switch
2606# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2607# 5. Verify flow table in switch
2608# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2609# removed in step 3 above, are returned in step 5 above, and that
2610# asynch message was received; else test FAILED
2611
2612
rootf6af1672012-04-06 09:46:29 -07002613class Flow_Del_4(basic.SimpleProtocol):
2614 """
2615 Test FLOW_DEL_4 from draft top-half test plan
2616
2617 INPUTS
2618 None
2619 """
2620
2621 def runTest(self):
Dan Talayco910a8282012-04-07 00:05:20 -07002622 fq_logger.debug("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002623
2624 # Clear all flows from switch
2625
Dan Talayco910a8282012-04-07 00:05:20 -07002626 fq_logger.debug("Deleting all flows from switch")
2627 rc = delete_all_flows(self.controller, fq_logger)
rootf6af1672012-04-06 09:46:29 -07002628 self.assertEqual(rc, 0, "Failed to delete all flows")
2629
2630 # Get switch capabilites
2631
Dan Talayco910a8282012-04-07 00:05:20 -07002632 fq_logger.debug("Getting switch capabilities")
rootf6af1672012-04-06 09:46:29 -07002633 sw = Switch()
Howard Persh3340d452012-04-06 16:45:21 -07002634 sw.controller_set(self.controller)
rootf6af1672012-04-06 09:46:29 -07002635 self.assertTrue(sw.features_get(), "Get switch features failed")
2636 self.assertTrue(sw.tbl_stats_get(), "Get table stats failed")
2637
2638 # Dream up some flow information, i.e. space to chose from for
2639 # random flow parameter generation
2640
2641 fi = Flow_Info()
2642 fi.rand(10)
2643
2644 # Dream up a flow config
2645
2646 fc = Flow_Cfg()
2647 fc.rand(fi, \
2648 sw.tbl_stats.stats[0].wildcards, \
2649 sw.sw_features.actions, \
2650 sw.valid_ports \
2651 )
2652 fc = fc.canonical()
2653
2654 # Send it to the switch. with "notify on removed"
2655
Dan Talayco910a8282012-04-07 00:05:20 -07002656 fq_logger.debug("Sending flow add to switch:")
2657 fq_logger.debug(str(fc))
rootf6af1672012-04-06 09:46:29 -07002658 ft = Flow_Tbl()
2659 fc.send_rem = True
2660 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2661 ft.insert(fc)
2662
2663 # Dream up some different actions, with the same flow key
2664
2665 fc2 = copy.deepcopy(fc)
2666 while True:
2667 fc2.rand_mod(fi, \
2668 sw.sw_features.actions, \
2669 sw.valid_ports \
2670 )
2671 if fc2 != fc:
2672 break
2673
2674 # Delete strictly
2675
Dan Talayco910a8282012-04-07 00:05:20 -07002676 fq_logger.debug("Sending strict flow del to switch:")
2677 fq_logger.debug(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002678 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2679 ft.delete(fc)
2680
2681 # Do barrier, to make sure all flows are in
2682
2683 self.assertTrue(sw.barrier(), "Barrier failed")
2684
2685 result = True
2686
2687 # Check for expected "removed" message
2688
Howard Persh3340d452012-04-06 16:45:21 -07002689 if not sw.errors_verify(0):
2690 result = False
2691
2692 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07002693 result = False
2694
2695 # Verify flow table
2696
2697 sw.flow_tbl = ft
2698 if not sw.flow_tbl_verify():
2699 result = False
2700
2701 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Dan Talayco910a8282012-04-07 00:05:20 -07002702 fq_logger.debug("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002703