blob: 17533a608f412c867449cc19148d8ff28233e7d9 [file] [log] [blame]
Matteo Scandoloa229eca2017-08-08 13:05:28 -07001
2# Copyright 2017-present Open Networking Foundation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16
Howard Pershc7963582012-03-29 10:02:59 -070017"""
18Flow query test case.
19
Howard Persh3340d452012-04-06 16:45:21 -070020Attempts to fill switch to capacity with randomized flows, and ensure that
21they all are read back correctly.
Howard Pershc7963582012-03-29 10:02:59 -070022"""
Howard Persh07d99e62012-04-09 15:26:57 -070023
24# COMMON TEST PARAMETERS
25#
26# Name: wildcards
27# Type: number
28# Description:
29# Overrides bitmap of supported wildcards reported by switch
30# Default: none
31#
Howard Pershc1199d52012-04-11 14:21:32 -070032# Name: wildcards_force
33# Type: number
34# Description:
35# Bitmap of wildcards to always be set
36# Default: none
37#
Howard Persh07d99e62012-04-09 15:26:57 -070038# Name: actions
39# Type: number
40# Description:
41# Overrides bitmap of supported actions reported by switch
42# Default: none
43#
Howard Pershc1199d52012-04-11 14:21:32 -070044# Name: actions_force
45# Type: number
46# Description:
47# Bitmap of actions to always be used
48# Default: none
49#
50# Name: ports
51# Type: list of OF port numbers
52# Description:
53# Override list of OF port numbers reported by switch
54# Default: none
55#
Howard Persh8d21c1f2012-04-20 15:57:29 -070056# Name: queues
57# Type: list of OF (port-number, queue-id) pairs
58# Description:
59# Override list of OF (port-number, queue-id) pairs returned by switch
60# Default: none
61#
Howard Pershb10a47a2012-08-21 13:54:47 -070062# Name: vlans
63# Type: list of VLAN ids
64# Description:
65# Override VLAN ids used in tests to given list
66# Default: []
67#
Howard Persh07d99e62012-04-09 15:26:57 -070068# Name: conservative_ordered_actions
69# Type: boolean (True or False)
70# Description:
71# Compare flow actions lists as unordered
72# Default: True
73
74
Howard Persh680b92a2012-03-31 13:34:35 -070075import math
Howard Pershc7963582012-03-29 10:02:59 -070076
77import logging
78
79import unittest
80import random
Howard Persh9cab4822012-09-11 17:08:40 -070081import time
Rich Lane3c7cf7f2013-01-11 18:04:56 -080082import copy
Howard Pershc7963582012-03-29 10:02:59 -070083
Rich Lane477f4812012-10-04 22:49:00 -070084from oftest import config
Howard Pershc7963582012-03-29 10:02:59 -070085import oftest.controller as controller
Rich Laned7b0ffa2013-03-08 15:53:42 -080086import ofp
Howard Pershc7963582012-03-29 10:02:59 -070087import oftest.dataplane as dataplane
Howard Pershc7963582012-03-29 10:02:59 -070088import oftest.parse as parse
89import pktact
Rich Laneb90a1c42012-10-05 09:16:05 -070090import oftest.base_tests as base_tests
Howard Pershc7963582012-03-29 10:02:59 -070091
Rich Laneda3b5ad2012-10-03 09:05:32 -070092from oftest.testutils import *
Howard Pershc7963582012-03-29 10:02:59 -070093from time import sleep
94
Howard Pershc7963582012-03-29 10:02:59 -070095
rootf6af1672012-04-06 09:46:29 -070096def flip_coin():
97 return random.randint(1, 100) <= 50
98
99
Howard Pershc7963582012-03-29 10:02:59 -0700100def shuffle(list):
101 n = len(list)
102 lim = n * n
103 i = 0
104 while i < lim:
105 a = random.randint(0, n - 1)
106 b = random.randint(0, n - 1)
107 temp = list[a]
108 list[a] = list[b]
109 list[b] = temp
110 i = i + 1
111 return list
112
113
Howard Persh680b92a2012-03-31 13:34:35 -0700114def rand_pick(list):
115 return list[random.randint(0, len(list) - 1)]
Howard Pershc7963582012-03-29 10:02:59 -0700116
Howard Persh680b92a2012-03-31 13:34:35 -0700117def rand_dl_addr():
118 return [random.randint(0, 255) & ~1,
119 random.randint(0, 255),
120 random.randint(0, 255),
121 random.randint(0, 255),
122 random.randint(0, 255),
123 random.randint(0, 255)
124 ]
Howard Pershc7963582012-03-29 10:02:59 -0700125
126def rand_nw_addr():
127 return random.randint(0, (1 << 32) - 1)
128
129
rootf6af1672012-04-06 09:46:29 -0700130class Flow_Info:
Howard Persh680b92a2012-03-31 13:34:35 -0700131 # Members:
132 # priorities - list of flow priorities
133 # dl_addrs - list of MAC addresses
134 # vlans - list of VLAN ids
135 # ethertypes - list of Ethertypes
136 # ip_addrs - list of IP addresses
137 # ip_tos - list of IP TOS values
138 # ip_protos - list of IP protocols
139 # l4_ports - list of L4 ports
140
141 def __init__(self):
142 priorities = []
143 dl_addrs = []
144 vlans = []
145 ethertypes = []
146 ip_addrs = []
147 ip_tos = []
148 ip_protos = []
149 l4_ports = []
150
151 def rand(self, n):
152 self.priorities = []
153 i = 0
154 while i < n:
155 self.priorities.append(random.randint(1, 65534))
156 i = i + 1
157
158 self.dl_addrs = []
159 i = 0
160 while i < n:
161 self.dl_addrs.append(rand_dl_addr())
162 i = i + 1
163
Rich Lane2014f9b2012-10-05 15:29:40 -0700164 if test_param_get("vlans", []) != []:
165 self.vlans = test_param_get("vlans", [])
Howard Pershb10a47a2012-08-21 13:54:47 -0700166
Rich Lane9a003812012-10-04 17:17:59 -0700167 logging.info("Overriding VLAN ids to:")
168 logging.info(self.vlans)
Howard Pershb10a47a2012-08-21 13:54:47 -0700169 else:
170 self.vlans = []
171 i = 0
172 while i < n:
173 self.vlans.append(random.randint(1, 4094))
174 i = i + 1
Howard Persh680b92a2012-03-31 13:34:35 -0700175
rootf6af1672012-04-06 09:46:29 -0700176 self.ethertypes = [0x0800, 0x0806]
Howard Persh680b92a2012-03-31 13:34:35 -0700177 i = 0
178 while i < n:
179 self.ethertypes.append(random.randint(0, (1 << 16) - 1))
180 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700181 self.ethertypes = shuffle(self.ethertypes)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700182
183 self.ip_addrs = []
184 i = 0
185 while i < n:
186 self.ip_addrs.append(rand_nw_addr())
187 i = i + 1
188
189 self.ip_tos = []
190 i = 0
191 while i < n:
192 self.ip_tos.append(random.randint(0, (1 << 8) - 1) & ~3)
193 i = i + 1
194
rootf6af1672012-04-06 09:46:29 -0700195 self.ip_protos = [1, 6, 17]
Howard Persh680b92a2012-03-31 13:34:35 -0700196 i = 0
197 while i < n:
198 self.ip_protos.append(random.randint(0, (1 << 8) - 1))
199 i = i + 1
rootf6af1672012-04-06 09:46:29 -0700200 self.ip_protos = shuffle(self.ip_protos)[0 : n]
Howard Persh680b92a2012-03-31 13:34:35 -0700201
202 self.l4_ports = []
203 i = 0
204 while i < n:
205 self.l4_ports.append(random.randint(0, (1 << 16) - 1))
206 i = i + 1
207
208 def rand_priority(self):
209 return rand_pick(self.priorities)
210
211 def rand_dl_addr(self):
212 return rand_pick(self.dl_addrs)
213
214 def rand_vlan(self):
215 return rand_pick(self.vlans)
216
217 def rand_ethertype(self):
218 return rand_pick(self.ethertypes)
219
220 def rand_ip_addr(self):
221 return rand_pick(self.ip_addrs)
222
223 def rand_ip_tos(self):
224 return rand_pick(self.ip_tos)
225
226 def rand_ip_proto(self):
227 return rand_pick(self.ip_protos)
228
229 def rand_l4_port(self):
230 return rand_pick(self.l4_ports)
231
232
Howard Pershc7963582012-03-29 10:02:59 -0700233# TBD - These don't belong here
234
Howard Persh680b92a2012-03-31 13:34:35 -0700235all_wildcards_list = [ofp.OFPFW_IN_PORT,
Howard Persh680b92a2012-03-31 13:34:35 -0700236 ofp.OFPFW_DL_DST,
rootf6af1672012-04-06 09:46:29 -0700237 ofp.OFPFW_DL_SRC,
238 ofp.OFPFW_DL_VLAN,
239 ofp.OFPFW_DL_VLAN_PCP,
Howard Persh680b92a2012-03-31 13:34:35 -0700240 ofp.OFPFW_DL_TYPE,
rootf6af1672012-04-06 09:46:29 -0700241 ofp.OFPFW_NW_TOS,
Howard Persh680b92a2012-03-31 13:34:35 -0700242 ofp.OFPFW_NW_PROTO,
Howard Persh680b92a2012-03-31 13:34:35 -0700243 ofp.OFPFW_NW_SRC_MASK,
244 ofp.OFPFW_NW_DST_MASK,
rootf6af1672012-04-06 09:46:29 -0700245 ofp.OFPFW_TP_SRC,
246 ofp.OFPFW_TP_DST
Howard Persh680b92a2012-03-31 13:34:35 -0700247 ]
Howard Pershc7963582012-03-29 10:02:59 -0700248
Howard Persh3340d452012-04-06 16:45:21 -0700249# TBD - Need this because there are duplicates in ofp.ofp_flow_wildcards_map
250# -- FIX
rootf6af1672012-04-06 09:46:29 -0700251all_wildcard_names = {
252 1 : 'OFPFW_IN_PORT',
253 2 : 'OFPFW_DL_VLAN',
254 4 : 'OFPFW_DL_SRC',
255 8 : 'OFPFW_DL_DST',
256 16 : 'OFPFW_DL_TYPE',
257 32 : 'OFPFW_NW_PROTO',
258 64 : 'OFPFW_TP_SRC',
259 128 : 'OFPFW_TP_DST',
260 1048576 : 'OFPFW_DL_VLAN_PCP',
261 2097152 : 'OFPFW_NW_TOS'
262}
263
rootf6af1672012-04-06 09:46:29 -0700264def wildcard_set(x, w, val):
265 result = x
266 if w == ofp.OFPFW_NW_SRC_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700267 result = (result & ~ofp.OFPFW_NW_SRC_MASK) \
268 | (val << ofp.OFPFW_NW_SRC_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700269 elif w == ofp.OFPFW_NW_DST_MASK:
Howard Persh3340d452012-04-06 16:45:21 -0700270 result = (result & ~ofp.OFPFW_NW_DST_MASK) \
271 | (val << ofp.OFPFW_NW_DST_SHIFT)
rootf6af1672012-04-06 09:46:29 -0700272 elif val == 0:
273 result = result & ~w
274 else:
275 result = result | w
276 return result
277
278def wildcard_get(x, w):
279 if w == ofp.OFPFW_NW_SRC_MASK:
280 return (x & ofp.OFPFW_NW_SRC_MASK) >> ofp.OFPFW_NW_SRC_SHIFT
281 if w == ofp.OFPFW_NW_DST_MASK:
282 return (x & ofp.OFPFW_NW_DST_MASK) >> ofp.OFPFW_NW_DST_SHIFT
283 return 1 if (x & w) != 0 else 0
284
Howard Persh8d21c1f2012-04-20 15:57:29 -0700285def wildcards_to_str(wildcards):
286 result = "{"
287 sep = ""
288 for w in all_wildcards_list:
289 if (wildcards & w) == 0:
290 continue
291 if w == ofp.OFPFW_NW_SRC_MASK:
292 n = wildcard_get(wildcards, w)
293 if n > 0:
294 result = result + sep + ("OFPFW_NW_SRC(%d)" % (n))
295 elif w == ofp.OFPFW_NW_DST_MASK:
296 n = wildcard_get(wildcards, w)
297 if n > 0:
298 result = result + sep + ("OFPFW_NW_DST(%d)" % (n))
299 else:
300 result = result + sep + all_wildcard_names[w]
301 sep = ", "
302 result = result +"}"
303 return result
Howard Pershc7963582012-03-29 10:02:59 -0700304
Howard Persh680b92a2012-03-31 13:34:35 -0700305all_actions_list = [ofp.OFPAT_OUTPUT,
306 ofp.OFPAT_SET_VLAN_VID,
307 ofp.OFPAT_SET_VLAN_PCP,
308 ofp.OFPAT_STRIP_VLAN,
309 ofp.OFPAT_SET_DL_SRC,
310 ofp.OFPAT_SET_DL_DST,
311 ofp.OFPAT_SET_NW_SRC,
312 ofp.OFPAT_SET_NW_DST,
313 ofp.OFPAT_SET_NW_TOS,
314 ofp.OFPAT_SET_TP_SRC,
315 ofp.OFPAT_SET_TP_DST,
316 ofp.OFPAT_ENQUEUE
317 ]
318
Howard Persh8d21c1f2012-04-20 15:57:29 -0700319def actions_bmap_to_str(bm):
320 result = "{"
321 sep = ""
322 for a in all_actions_list:
Rich Lane1879dc72013-03-11 22:08:51 -0700323 if ((1 << a) & bm) != 0 and a in ofp.ofp_action_type_map:
Howard Persh8d21c1f2012-04-20 15:57:29 -0700324 result = result + sep + ofp.ofp_action_type_map[a]
325 sep = ", "
326 result = result + "}"
327 return result
328
Howard Persh680b92a2012-03-31 13:34:35 -0700329def dl_addr_to_str(a):
330 return "%x:%x:%x:%x:%x:%x" % tuple(a)
331
332def ip_addr_to_str(a, n):
rootf6af1672012-04-06 09:46:29 -0700333 if n is not None:
334 a = a & ~((1 << (32 - n)) - 1)
Howard Persh680b92a2012-03-31 13:34:35 -0700335 result = "%d.%d.%d.%d" % (a >> 24, \
336 (a >> 16) & 0xff, \
337 (a >> 8) & 0xff, \
338 a & 0xff \
339 )
340 if n is not None:
341 result = result + ("/%d" % (n))
342 return result
343
Howard Pershc7963582012-03-29 10:02:59 -0700344
rootf6af1672012-04-06 09:46:29 -0700345class Flow_Cfg:
Howard Pershc7963582012-03-29 10:02:59 -0700346 # Members:
347 # - match
348 # - idle_timeout
349 # - hard_timeout
350 # - priority
Rich Lane62e96852013-03-11 12:04:45 -0700351 # - actions
Howard Pershc7963582012-03-29 10:02:59 -0700352
353 def __init__(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700354 self.priority = 0
Rich Lane0237baf2013-03-11 22:34:59 -0700355 self.match = ofp.match()
Howard Pershc7963582012-03-29 10:02:59 -0700356 self.match.wildcards = ofp.OFPFW_ALL
357 self.idle_timeout = 0
358 self.hard_timeout = 0
Rich Lane62e96852013-03-11 12:04:45 -0700359 self.actions = []
Howard Pershc7963582012-03-29 10:02:59 -0700360
rootf6af1672012-04-06 09:46:29 -0700361 # {pri, match} is considered a flow key
362 def key_equal(self, x):
Howard Persh680b92a2012-03-31 13:34:35 -0700363 if self.priority != x.priority:
364 return False
365 # TBD - Should this logic be moved to ofp_match.__eq__()?
366 if self.match.wildcards != x.match.wildcards:
367 return False
rootf6af1672012-04-06 09:46:29 -0700368 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0 \
Howard Persh680b92a2012-03-31 13:34:35 -0700369 and self.match.in_port != x.match.in_port:
370 return False
rootf6af1672012-04-06 09:46:29 -0700371 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700372 and self.match.eth_dst != x.match.eth_dst:
Howard Persh680b92a2012-03-31 13:34:35 -0700373 return False
rootf6af1672012-04-06 09:46:29 -0700374 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700375 and self.match.eth_src != x.match.eth_src:
rootf6af1672012-04-06 09:46:29 -0700376 return False
377 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700378 and self.match.vlan_vid != x.match.vlan_vid:
Howard Persh680b92a2012-03-31 13:34:35 -0700379 return False
rootf6af1672012-04-06 09:46:29 -0700380 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700381 and self.match.vlan_pcp != x.match.vlan_pcp:
Howard Persh680b92a2012-03-31 13:34:35 -0700382 return False
rootf6af1672012-04-06 09:46:29 -0700383 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700384 and self.match.eth_type != x.match.eth_type:
Howard Persh680b92a2012-03-31 13:34:35 -0700385 return False
rootf6af1672012-04-06 09:46:29 -0700386 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700387 and self.match.ip_dscp != x.match.ip_dscp:
Howard Persh680b92a2012-03-31 13:34:35 -0700388 return False
rootf6af1672012-04-06 09:46:29 -0700389 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700390 and self.match.ip_proto != x.match.ip_proto:
Howard Persh680b92a2012-03-31 13:34:35 -0700391 return False
rootf6af1672012-04-06 09:46:29 -0700392 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
393 if n < 32:
394 m = ~((1 << n) - 1)
Rich Laned0478ff2013-03-11 12:46:58 -0700395 if (self.match.ipv4_src & m) != (x.match.ipv4_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -0700396 return False
rootf6af1672012-04-06 09:46:29 -0700397 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
398 if n < 32:
399 m = ~((1 << n) - 1)
Rich Laned0478ff2013-03-11 12:46:58 -0700400 if (self.match.ipv4_dst & m) != (x.match.ipv4_dst & m):
Howard Persh680b92a2012-03-31 13:34:35 -0700401 return False
rootf6af1672012-04-06 09:46:29 -0700402 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700403 and self.match.tcp_src != x.match.tcp_src:
Howard Persh680b92a2012-03-31 13:34:35 -0700404 return False
rootf6af1672012-04-06 09:46:29 -0700405 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700406 and self.match.tcp_dst != x.match.tcp_dst:
rootf6af1672012-04-06 09:46:29 -0700407 return False
408 return True
409
Howard Persh5f3c83f2012-04-13 09:57:10 -0700410 def actions_equal(self, x):
Rich Lane2014f9b2012-10-05 15:29:40 -0700411 if test_param_get("conservative_ordered_actions", True):
Howard Persh5f3c83f2012-04-13 09:57:10 -0700412 # Compare actions lists as unordered
413
Rich Lane62e96852013-03-11 12:04:45 -0700414 aa = copy.deepcopy(x.actions)
415 for a in self.actions:
root2843d2b2012-04-06 10:27:46 -0700416 i = 0
417 while i < len(aa):
418 if a == aa[i]:
419 break
420 i = i + 1
421 if i < len(aa):
422 aa.pop(i)
423 else:
424 return False
425 return aa == []
426 else:
427 return self.actions == x.actions
Howard Persh5f3c83f2012-04-13 09:57:10 -0700428
429 def non_key_equal(self, x):
430 if self.cookie != x.cookie:
431 return False
432 if self.idle_timeout != x.idle_timeout:
433 return False
434 if self.hard_timeout != x.hard_timeout:
435 return False
436 return self.actions_equal(x)
rootf6af1672012-04-06 09:46:29 -0700437
root2843d2b2012-04-06 10:27:46 -0700438 def key_str(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700439 result = "priority=%d" % self.priority
440 # TBD - Would be nice if ofp_match.show() was better behaved
441 # (no newlines), and more intuitive (things in hex where approprate), etc.
Howard Persh8d21c1f2012-04-20 15:57:29 -0700442 result = result + (", wildcards=0x%x=%s" \
443 % (self.match.wildcards, \
444 wildcards_to_str(self.match.wildcards) \
445 )
446 )
rootf6af1672012-04-06 09:46:29 -0700447 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -0700448 result = result + (", in_port=%d" % (self.match.in_port))
rootf6af1672012-04-06 09:46:29 -0700449 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -0700450 result = result + (", eth_dst=%s" \
451 % (dl_addr_to_str(self.match.eth_dst)) \
Howard Persh3340d452012-04-06 16:45:21 -0700452 )
rootf6af1672012-04-06 09:46:29 -0700453 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -0700454 result = result + (", eth_src=%s" \
455 % (dl_addr_to_str(self.match.eth_src)) \
Howard Persh3340d452012-04-06 16:45:21 -0700456 )
rootf6af1672012-04-06 09:46:29 -0700457 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -0700458 result = result + (", vlan_vid=%d" % (self.match.vlan_vid))
rootf6af1672012-04-06 09:46:29 -0700459 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -0700460 result = result + (", vlan_pcp=%d" % (self.match.vlan_pcp))
rootf6af1672012-04-06 09:46:29 -0700461 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -0700462 result = result + (", eth_type=0x%x" % (self.match.eth_type))
rootf6af1672012-04-06 09:46:29 -0700463 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -0700464 result = result + (", ip_dscp=0x%x" % (self.match.ip_dscp))
rootf6af1672012-04-06 09:46:29 -0700465 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -0700466 result = result + (", ip_proto=%d" % (self.match.ip_proto))
rootf6af1672012-04-06 09:46:29 -0700467 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700468 if n < 32:
Rich Laned0478ff2013-03-11 12:46:58 -0700469 result = result + (", ipv4_src=%s" % \
470 (ip_addr_to_str(self.match.ipv4_src, 32 - n)) \
Howard Persh3340d452012-04-06 16:45:21 -0700471 )
rootf6af1672012-04-06 09:46:29 -0700472 n = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -0700473 if n < 32:
Rich Laned0478ff2013-03-11 12:46:58 -0700474 result = result + (", ipv4_dst=%s" % \
475 (ip_addr_to_str(self.match.ipv4_dst, 32 - n)) \
Howard Persh3340d452012-04-06 16:45:21 -0700476 )
rootf6af1672012-04-06 09:46:29 -0700477 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -0700478 result = result + (", tcp_src=%d" % self.match.tcp_src)
rootf6af1672012-04-06 09:46:29 -0700479 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -0700480 result = result + (", tcp_dst=%d" % self.match.tcp_dst)
rootf6af1672012-04-06 09:46:29 -0700481 return result
482
483 def __eq__(self, x):
484 return (self.key_equal(x) and self.non_key_equal(x))
485
486 def __str__(self):
root2843d2b2012-04-06 10:27:46 -0700487 result = self.key_str()
488 result = result + (", cookie=%d" % self.cookie)
Howard Persh680b92a2012-03-31 13:34:35 -0700489 result = result + (", idle_timeout=%d" % self.idle_timeout)
490 result = result + (", hard_timeout=%d" % self.hard_timeout)
Rich Lane62e96852013-03-11 12:04:45 -0700491 for a in self.actions:
Rich Lane1879dc72013-03-11 22:08:51 -0700492 result = result + (", action=%s" % ofp.ofp_action_type_map.get(a.type, "unknown"))
Howard Persh680b92a2012-03-31 13:34:35 -0700493 if a.type == ofp.OFPAT_OUTPUT:
494 result = result + ("(%d)" % (a.port))
495 elif a.type == ofp.OFPAT_SET_VLAN_VID:
496 result = result + ("(%d)" % (a.vlan_vid))
497 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
498 result = result + ("(%d)" % (a.vlan_pcp))
499 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
500 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
501 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
502 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
503 elif a.type == ofp.OFPAT_SET_NW_TOS:
504 result = result + ("(0x%x)" % (a.nw_tos))
505 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
506 result = result + ("(%d)" % (a.tp_port))
507 elif a.type == ofp.OFPAT_ENQUEUE:
508 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
509 return result
Howard Pershc7963582012-03-29 10:02:59 -0700510
Howard Persh8d21c1f2012-04-20 15:57:29 -0700511 def rand_actions_ordered(self, fi, valid_actions, valid_ports, valid_queues):
Howard Persh3340d452012-04-06 16:45:21 -0700512 # Action lists are ordered, so pick an ordered random subset of
513 # supported actions
Howard Pershc1199d52012-04-11 14:21:32 -0700514
Rich Lane2014f9b2012-10-05 15:29:40 -0700515 actions_force = test_param_get("actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700516 if actions_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700517 logging.info("Forced actions:")
518 logging.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700519
Dan Talayco910a8282012-04-07 00:05:20 -0700520 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh3340d452012-04-06 16:45:21 -0700521 supported_actions = []
522 for a in all_actions_list:
523 if ((1 << a) & valid_actions) != 0:
524 supported_actions.append(a)
525
Howard Pershc1199d52012-04-11 14:21:32 -0700526 actions \
527 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
528
529 for a in all_actions_list:
530 if ((1 << a) & actions_force) != 0:
531 actions.append(a)
532
533 actions = shuffle(actions)
Howard Persh3340d452012-04-06 16:45:21 -0700534
Howard Persh6a3698d2012-08-21 14:26:39 -0700535 set_vlanf = False
536 strip_vlanf = False
Rich Lane62e96852013-03-11 12:04:45 -0700537 self.actions = []
Howard Pershc1199d52012-04-11 14:21:32 -0700538 for a in actions:
Dan Talayco910a8282012-04-07 00:05:20 -0700539 act = None
Howard Persh3340d452012-04-06 16:45:21 -0700540 if a == ofp.OFPAT_OUTPUT:
541 pass # OUTPUT actions must come last
542 elif a == ofp.OFPAT_SET_VLAN_VID:
Howard Persh6a3698d2012-08-21 14:26:39 -0700543 if not strip_vlanf:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800544 act = ofp.action.set_vlan_vid()
Howard Persh6a3698d2012-08-21 14:26:39 -0700545 act.vlan_vid = fi.rand_vlan()
546 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700547 elif a == ofp.OFPAT_SET_VLAN_PCP:
Howard Persh6a3698d2012-08-21 14:26:39 -0700548 if not strip_vlanf:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800549 act = ofp.action.set_vlan_pcp()
Howard Persh6a3698d2012-08-21 14:26:39 -0700550 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
551 set_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700552 elif a == ofp.OFPAT_STRIP_VLAN:
Howard Persh6a3698d2012-08-21 14:26:39 -0700553 if not set_vlanf:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800554 act = ofp.action.strip_vlan()
Howard Persh6a3698d2012-08-21 14:26:39 -0700555 strip_vlanf = True
Howard Persh3340d452012-04-06 16:45:21 -0700556 elif a == ofp.OFPAT_SET_DL_SRC:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800557 act = ofp.action.set_dl_src()
Howard Persh3340d452012-04-06 16:45:21 -0700558 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700559 elif a == ofp.OFPAT_SET_DL_DST:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800560 act = ofp.action.set_dl_dst()
Howard Persh3340d452012-04-06 16:45:21 -0700561 act.dl_addr = fi.rand_dl_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700562 elif a == ofp.OFPAT_SET_NW_SRC:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800563 act = ofp.action.set_nw_src()
Howard Persh3340d452012-04-06 16:45:21 -0700564 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700565 elif a == ofp.OFPAT_SET_NW_DST:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800566 act = ofp.action.set_nw_dst()
Howard Persh3340d452012-04-06 16:45:21 -0700567 act.nw_addr = fi.rand_ip_addr()
Howard Persh3340d452012-04-06 16:45:21 -0700568 elif a == ofp.OFPAT_SET_NW_TOS:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800569 act = ofp.action.set_nw_tos()
Rich Laned0478ff2013-03-11 12:46:58 -0700570 act.ip_dscp = fi.rand_ip_tos()
Howard Persh3340d452012-04-06 16:45:21 -0700571 elif a == ofp.OFPAT_SET_TP_SRC:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800572 act = ofp.action.set_tp_src()
Howard Persh3340d452012-04-06 16:45:21 -0700573 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700574 elif a == ofp.OFPAT_SET_TP_DST:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800575 act = ofp.action.set_tp_dst()
Howard Persh3340d452012-04-06 16:45:21 -0700576 act.tp_port = fi.rand_l4_port()
Howard Persh3340d452012-04-06 16:45:21 -0700577 elif a == ofp.OFPAT_ENQUEUE:
578 pass # Enqueue actions must come last
Dan Talayco910a8282012-04-07 00:05:20 -0700579 if act:
Rich Lanec495d9e2013-03-08 17:43:36 -0800580 self.actions.append(act)
Dan Talayco910a8282012-04-07 00:05:20 -0700581
Howard Persh3340d452012-04-06 16:45:21 -0700582 p = random.randint(1, 100)
Howard Pershc1199d52012-04-11 14:21:32 -0700583 if (((1 << ofp.OFPAT_ENQUEUE) & actions_force) != 0 or p <= 33) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700584 and len(valid_queues) > 0 \
585 and ofp.OFPAT_ENQUEUE in actions:
Howard Pershc1199d52012-04-11 14:21:32 -0700586 # In not forecd, one third of the time, include ENQUEUE actions
587 # at end of list
Howard Persh3340d452012-04-06 16:45:21 -0700588 # At most 1 ENQUEUE action
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800589 act = ofp.action.enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700590 (act.port, act.queue_id) = rand_pick(valid_queues)
Rich Lanec495d9e2013-03-08 17:43:36 -0800591 self.actions.append(act)
Howard Pershc1199d52012-04-11 14:21:32 -0700592 if (((1 << ofp.OFPAT_OUTPUT) & actions_force) != 0 \
593 or (p > 33 and p <= 66) \
594 ) \
Howard Persh8d21c1f2012-04-20 15:57:29 -0700595 and len(valid_ports) > 0 \
Howard Pershc1199d52012-04-11 14:21:32 -0700596 and ofp.OFPAT_OUTPUT in actions:
Howard Persh3340d452012-04-06 16:45:21 -0700597 # One third of the time, include OUTPUT actions at end of list
598 port_idxs = shuffle(range(len(valid_ports)))
599 # Only 1 output action allowed if IN_PORT wildcarded
600 n = 1 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) != 0 \
601 else random.randint(1, len(valid_ports))
602 port_idxs = port_idxs[0 : n]
603 for pi in port_idxs:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800604 act = ofp.action.output()
Howard Persh3340d452012-04-06 16:45:21 -0700605 act.port = valid_ports[pi]
Howard Persh3340d452012-04-06 16:45:21 -0700606 if act.port != ofp.OFPP_IN_PORT \
607 or wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
608 # OUTPUT(IN_PORT) only valid if OFPFW_IN_PORT not wildcarded
Rich Lanec495d9e2013-03-08 17:43:36 -0800609 self.actions.append(act)
Howard Persh3340d452012-04-06 16:45:21 -0700610 else:
611 # One third of the time, include neither
612 pass
613
614
615 # Randomize flow data for flow modifies (i.e. cookie and actions)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700616 def rand_mod(self, fi, valid_actions, valid_ports, valid_queues):
rootf6af1672012-04-06 09:46:29 -0700617 self.cookie = random.randint(0, (1 << 53) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700618
Dan Talayco910a8282012-04-07 00:05:20 -0700619 # By default, test with conservative ordering conventions
620 # This should probably be indicated in a profile
Rich Lane2014f9b2012-10-05 15:29:40 -0700621 if test_param_get("conservative_ordered_actions", True):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700622 self.rand_actions_ordered(fi, valid_actions, valid_ports, valid_queues)
Howard Persh3340d452012-04-06 16:45:21 -0700623 return self
624
Rich Lane2014f9b2012-10-05 15:29:40 -0700625 actions_force = test_param_get("actions_force", 0)
Howard Persh8d21c1f2012-04-20 15:57:29 -0700626 if actions_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700627 logging.info("Forced actions:")
628 logging.info(actions_bmap_to_str(actions_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700629
630 ACTION_MAX_LEN = 65535 # @fixme Should be test param?
Howard Persh680b92a2012-03-31 13:34:35 -0700631 supported_actions = []
632 for a in all_actions_list:
633 if ((1 << a) & valid_actions) != 0:
634 supported_actions.append(a)
635
Howard Pershc1199d52012-04-11 14:21:32 -0700636 actions \
637 = shuffle(supported_actions)[0 : random.randint(1, len(supported_actions))]
638
639 for a in all_actions_list:
640 if ((1 << a) & actions_force) != 0:
641 actions.append(a)
642
643 actions = shuffle(actions)
Howard Pershc7963582012-03-29 10:02:59 -0700644
Rich Lane62e96852013-03-11 12:04:45 -0700645 self.actions = []
Howard Pershc1199d52012-04-11 14:21:32 -0700646 for a in actions:
Howard Pershc7963582012-03-29 10:02:59 -0700647 if a == ofp.OFPAT_OUTPUT:
648 # TBD - Output actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700649 if len(valid_ports) == 0:
650 continue
Howard Pershc7963582012-03-29 10:02:59 -0700651 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700652 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700653 for pi in port_idxs:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800654 act = ofp.action.output()
Howard Persh680b92a2012-03-31 13:34:35 -0700655 act.port = valid_ports[pi]
Rich Lanec495d9e2013-03-08 17:43:36 -0800656 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700657 elif a == ofp.OFPAT_SET_VLAN_VID:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800658 act = ofp.action.set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700659 act.vlan_vid = fi.rand_vlan()
Rich Lanec495d9e2013-03-08 17:43:36 -0800660 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700661 elif a == ofp.OFPAT_SET_VLAN_PCP:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800662 act = ofp.action.set_vlan_pcp()
Dan Talayco910a8282012-04-07 00:05:20 -0700663 act.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc7963582012-03-29 10:02:59 -0700664 elif a == ofp.OFPAT_STRIP_VLAN:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800665 act = ofp.action.strip_vlan()
Rich Lanec495d9e2013-03-08 17:43:36 -0800666 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700667 elif a == ofp.OFPAT_SET_DL_SRC:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800668 act = ofp.action.set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700669 act.dl_addr = fi.rand_dl_addr()
Rich Lanec495d9e2013-03-08 17:43:36 -0800670 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700671 elif a == ofp.OFPAT_SET_DL_DST:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800672 act = ofp.action.set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700673 act.dl_addr = fi.rand_dl_addr()
Rich Lanec495d9e2013-03-08 17:43:36 -0800674 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700675 elif a == ofp.OFPAT_SET_NW_SRC:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800676 act = ofp.action.set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700677 act.nw_addr = fi.rand_ip_addr()
Rich Lanec495d9e2013-03-08 17:43:36 -0800678 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700679 elif a == ofp.OFPAT_SET_NW_DST:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800680 act = ofp.action.set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700681 act.nw_addr = fi.rand_ip_addr()
Rich Lanec495d9e2013-03-08 17:43:36 -0800682 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700683 elif a == ofp.OFPAT_SET_NW_TOS:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800684 act = ofp.action.set_nw_tos()
Rich Laned0478ff2013-03-11 12:46:58 -0700685 act.ip_dscp = fi.rand_ip_tos()
Rich Lanec495d9e2013-03-08 17:43:36 -0800686 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700687 elif a == ofp.OFPAT_SET_TP_SRC:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800688 act = ofp.action.set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700689 act.tp_port = fi.rand_l4_port()
Rich Lanec495d9e2013-03-08 17:43:36 -0800690 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700691 elif a == ofp.OFPAT_SET_TP_DST:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800692 act = ofp.action.set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700693 act.tp_port = fi.rand_l4_port()
Rich Lanec495d9e2013-03-08 17:43:36 -0800694 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700695 elif a == ofp.OFPAT_ENQUEUE:
696 # TBD - Enqueue actions are clustered in list, spread them out?
Howard Persh8d21c1f2012-04-20 15:57:29 -0700697 if len(valid_queues) == 0:
698 continue
699 qidxs = shuffle(range(len(valid_queues)))
700 qidxs = qidxs[0 : random.randint(1, len(valid_queues))]
701 for qi in qidxs:
Rich Lane9d3cc6b2013-03-08 16:33:08 -0800702 act = ofp.action.enqueue()
Howard Persh8d21c1f2012-04-20 15:57:29 -0700703 (act.port, act.queue_id) = valid_queues[qi]
Rich Lanec495d9e2013-03-08 17:43:36 -0800704 self.actions.append(act)
Howard Pershc7963582012-03-29 10:02:59 -0700705
706 return self
707
rootf6af1672012-04-06 09:46:29 -0700708 # Randomize flow cfg
Ed Swierk99a74de2012-08-22 06:40:54 -0700709 def rand(self, fi, wildcards_force, valid_wildcards, valid_actions, valid_ports,
710 valid_queues):
Howard Persh8d21c1f2012-04-20 15:57:29 -0700711 if wildcards_force != 0:
Rich Lane9a003812012-10-04 17:17:59 -0700712 logging.info("Wildcards forced:")
713 logging.info(wildcards_to_str(wildcards_force))
Howard Pershc1199d52012-04-11 14:21:32 -0700714
rootf6af1672012-04-06 09:46:29 -0700715 # Start with no wildcards, i.e. everything specified
716 self.match.wildcards = 0
Howard Pershc1199d52012-04-11 14:21:32 -0700717
718 if wildcards_force != 0:
719 exact = False
720 else:
721 # Make approx. 5% of flows exact
722 exact = (random.randint(1, 100) <= 5)
rootf6af1672012-04-06 09:46:29 -0700723
724 # For each qualifier Q,
725 # if (wildcarding is not supported for Q,
726 # or an exact flow is specified
727 # or a coin toss comes up heads),
728 # specify Q
729 # else
730 # wildcard Q
731
Howard Pershc1199d52012-04-11 14:21:32 -0700732 if wildcard_get(wildcards_force, ofp.OFPFW_IN_PORT) == 0 \
733 and (wildcard_get(valid_wildcards, ofp.OFPFW_IN_PORT) == 0 \
734 or exact \
735 or flip_coin() \
736 ):
rootf6af1672012-04-06 09:46:29 -0700737 self.match.in_port = rand_pick(valid_ports)
738 else:
Howard Persh3340d452012-04-06 16:45:21 -0700739 self.match.wildcards = wildcard_set(self.match.wildcards, \
740 ofp.OFPFW_IN_PORT, \
741 1 \
742 )
rootf6af1672012-04-06 09:46:29 -0700743
Howard Pershc1199d52012-04-11 14:21:32 -0700744 if wildcard_get(wildcards_force, ofp.OFPFW_DL_DST) == 0 \
745 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_DST) == 0 \
746 or exact \
747 or flip_coin() \
748 ):
Rich Laned0478ff2013-03-11 12:46:58 -0700749 self.match.eth_dst = fi.rand_dl_addr()
rootf6af1672012-04-06 09:46:29 -0700750 else:
Howard Persh3340d452012-04-06 16:45:21 -0700751 self.match.wildcards = wildcard_set(self.match.wildcards, \
752 ofp.OFPFW_DL_DST, \
753 1 \
754 )
rootf6af1672012-04-06 09:46:29 -0700755
Howard Pershc1199d52012-04-11 14:21:32 -0700756 if wildcard_get(wildcards_force, ofp.OFPFW_DL_SRC) == 0 \
757 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_SRC) == 0 \
758 or exact \
759 or flip_coin() \
760 ):
Rich Laned0478ff2013-03-11 12:46:58 -0700761 self.match.eth_src = fi.rand_dl_addr()
rootf6af1672012-04-06 09:46:29 -0700762 else:
Howard Persh3340d452012-04-06 16:45:21 -0700763 self.match.wildcards = wildcard_set(self.match.wildcards, \
764 ofp.OFPFW_DL_SRC, \
765 1 \
766 )
rootf6af1672012-04-06 09:46:29 -0700767
Howard Pershc1199d52012-04-11 14:21:32 -0700768 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN) == 0 \
769 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN) == 0 \
770 or exact \
771 or flip_coin() \
772 ):
Rich Laned0478ff2013-03-11 12:46:58 -0700773 self.match.vlan_vid = fi.rand_vlan()
rootf6af1672012-04-06 09:46:29 -0700774 else:
Howard Persh3340d452012-04-06 16:45:21 -0700775 self.match.wildcards = wildcard_set(self.match.wildcards, \
776 ofp.OFPFW_DL_VLAN, \
777 1 \
778 )
rootf6af1672012-04-06 09:46:29 -0700779
Howard Pershc1199d52012-04-11 14:21:32 -0700780 if wildcard_get(wildcards_force, ofp.OFPFW_DL_VLAN_PCP) == 0 \
781 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0 \
782 or exact \
783 or flip_coin() \
784 ):
Rich Laned0478ff2013-03-11 12:46:58 -0700785 self.match.vlan_pcp = random.randint(0, (1 << 3) - 1)
Howard Pershc1199d52012-04-11 14:21:32 -0700786 else:
787 self.match.wildcards = wildcard_set(self.match.wildcards, \
788 ofp.OFPFW_DL_VLAN_PCP, \
789 1 \
790 )
791
792 if wildcard_get(wildcards_force, ofp.OFPFW_DL_TYPE) == 0 \
793 and (wildcard_get(valid_wildcards, ofp.OFPFW_DL_TYPE) == 0 \
794 or exact \
795 or flip_coin() \
796 ):
Rich Laned0478ff2013-03-11 12:46:58 -0700797 self.match.eth_type = fi.rand_ethertype()
rootf6af1672012-04-06 09:46:29 -0700798 else:
Howard Persh3340d452012-04-06 16:45:21 -0700799 self.match.wildcards = wildcard_set(self.match.wildcards, \
800 ofp.OFPFW_DL_TYPE, \
801 1 \
802 )
rootf6af1672012-04-06 09:46:29 -0700803
Howard Pershc1199d52012-04-11 14:21:32 -0700804 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_SRC_MASK)
805 if n == 0:
806 if exact or flip_coin():
807 n = 0
808 else:
809 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_SRC_MASK)
810 if n > 32:
811 n = 32
812 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700813 self.match.wildcards = wildcard_set(self.match.wildcards, \
814 ofp.OFPFW_NW_SRC_MASK, \
815 n \
816 )
rootf6af1672012-04-06 09:46:29 -0700817 if n < 32:
Rich Laned0478ff2013-03-11 12:46:58 -0700818 self.match.ipv4_src = fi.rand_ip_addr() & ~((1 << n) - 1)
rootf6af1672012-04-06 09:46:29 -0700819 # Specifying any IP address match other than all bits
820 # don't care requires that Ethertype is one of {IP, ARP}
821 if flip_coin():
Rich Laned0478ff2013-03-11 12:46:58 -0700822 self.match.eth_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700823 self.match.wildcards = wildcard_set(self.match.wildcards, \
824 ofp.OFPFW_DL_TYPE, \
825 0 \
826 )
rootf6af1672012-04-06 09:46:29 -0700827
Howard Pershc1199d52012-04-11 14:21:32 -0700828 n = wildcard_get(wildcards_force, ofp.OFPFW_NW_DST_MASK)
829 if n == 0:
830 if exact or flip_coin():
831 n = 0
832 else:
833 n = wildcard_get(valid_wildcards, ofp.OFPFW_NW_DST_MASK)
834 if n > 32:
835 n = 32
836 n = random.randint(0, n)
Howard Persh3340d452012-04-06 16:45:21 -0700837 self.match.wildcards = wildcard_set(self.match.wildcards, \
838 ofp.OFPFW_NW_DST_MASK, \
839 n \
840 )
rootf6af1672012-04-06 09:46:29 -0700841 if n < 32:
Rich Laned0478ff2013-03-11 12:46:58 -0700842 self.match.ipv4_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
rootf6af1672012-04-06 09:46:29 -0700843 # Specifying any IP address match other than all bits
844 # don't care requires that Ethertype is one of {IP, ARP}
845 if flip_coin():
Rich Laned0478ff2013-03-11 12:46:58 -0700846 self.match.eth_type = rand_pick([0x0800, 0x0806])
Howard Persh3340d452012-04-06 16:45:21 -0700847 self.match.wildcards = wildcard_set(self.match.wildcards, \
848 ofp.OFPFW_DL_TYPE, \
849 0 \
850 )
rootf6af1672012-04-06 09:46:29 -0700851
Howard Pershc1199d52012-04-11 14:21:32 -0700852 if wildcard_get(wildcards_force, ofp.OFPFW_NW_TOS) == 0 \
853 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_TOS) == 0 \
854 or exact \
855 or flip_coin() \
856 ):
Rich Laned0478ff2013-03-11 12:46:58 -0700857 self.match.ip_dscp = fi.rand_ip_tos()
rootf6af1672012-04-06 09:46:29 -0700858 # Specifying a TOS value requires that Ethertype is IP
859 if flip_coin():
Rich Laned0478ff2013-03-11 12:46:58 -0700860 self.match.eth_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700861 self.match.wildcards = wildcard_set(self.match.wildcards, \
862 ofp.OFPFW_DL_TYPE, \
863 0 \
864 )
rootf6af1672012-04-06 09:46:29 -0700865 else:
Howard Persh3340d452012-04-06 16:45:21 -0700866 self.match.wildcards = wildcard_set(self.match.wildcards, \
867 ofp.OFPFW_NW_TOS, \
868 1 \
869 )
rootf6af1672012-04-06 09:46:29 -0700870
Rich Laned0478ff2013-03-11 12:46:58 -0700871 # Known issue on OVS with specifying ip_proto w/o eth_type as IP
Howard Pershc1199d52012-04-11 14:21:32 -0700872 if wildcard_get(wildcards_force, ofp.OFPFW_NW_PROTO) == 0 \
873 and (wildcard_get(valid_wildcards, ofp.OFPFW_NW_PROTO) == 0 \
874 or exact \
875 or flip_coin() \
876 ):
Rich Laned0478ff2013-03-11 12:46:58 -0700877 self.match.ip_proto = fi.rand_ip_proto()
Dan Talayco910a8282012-04-07 00:05:20 -0700878 # Specifying an IP protocol requires that Ethertype is IP
879 if flip_coin():
Rich Laned0478ff2013-03-11 12:46:58 -0700880 self.match.eth_type = 0x0800
Dan Talayco910a8282012-04-07 00:05:20 -0700881 self.match.wildcards = wildcard_set(self.match.wildcards, \
882 ofp.OFPFW_DL_TYPE, \
883 0 \
884 )
885 else:
Howard Persh3340d452012-04-06 16:45:21 -0700886 self.match.wildcards = wildcard_set(self.match.wildcards, \
887 ofp.OFPFW_NW_PROTO, \
888 1 \
889 )
Dan Talayco910a8282012-04-07 00:05:20 -0700890
Howard Pershc1199d52012-04-11 14:21:32 -0700891 if wildcard_get(wildcards_force, ofp.OFPFW_TP_SRC) == 0 \
892 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_SRC) == 0 \
893 or exact\
894 or flip_coin() \
895 ):
Rich Laned0478ff2013-03-11 12:46:58 -0700896 self.match.tcp_src = fi.rand_l4_port()
rootf6af1672012-04-06 09:46:29 -0700897 # Specifying a L4 port requires that IP protcol is
898 # one of {ICMP, TCP, UDP}
899 if flip_coin():
Rich Laned0478ff2013-03-11 12:46:58 -0700900 self.match.ip_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700901 self.match.wildcards = wildcard_set(self.match.wildcards, \
902 ofp.OFPFW_NW_PROTO, \
903 0 \
904 )
rootf6af1672012-04-06 09:46:29 -0700905 # Specifying a L4 port requirues that Ethertype is IP
Rich Laned0478ff2013-03-11 12:46:58 -0700906 self.match.eth_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700907 self.match.wildcards = wildcard_set(self.match.wildcards, \
908 ofp.OFPFW_DL_TYPE, \
909 0 \
910 )
Rich Laned0478ff2013-03-11 12:46:58 -0700911 if self.match.ip_proto == 1:
912 self.match.tcp_src = self.match.tcp_src & 0xff
rootf6af1672012-04-06 09:46:29 -0700913 else:
Howard Persh3340d452012-04-06 16:45:21 -0700914 self.match.wildcards = wildcard_set(self.match.wildcards, \
915 ofp.OFPFW_TP_SRC, \
916 1 \
917 )
rootf6af1672012-04-06 09:46:29 -0700918
Howard Pershc1199d52012-04-11 14:21:32 -0700919 if wildcard_get(wildcards_force, ofp.OFPFW_TP_DST) == 0 \
920 and (wildcard_get(valid_wildcards, ofp.OFPFW_TP_DST) == 0 \
921 or exact \
922 or flip_coin() \
923 ):
Rich Laned0478ff2013-03-11 12:46:58 -0700924 self.match.tcp_dst = fi.rand_l4_port()
rootf6af1672012-04-06 09:46:29 -0700925 # Specifying a L4 port requires that IP protcol is
926 # one of {ICMP, TCP, UDP}
927 if flip_coin():
Rich Laned0478ff2013-03-11 12:46:58 -0700928 self.match.ip_proto = rand_pick([1, 6, 17])
Howard Persh3340d452012-04-06 16:45:21 -0700929 self.match.wildcards = wildcard_set(self.match.wildcards, \
930 ofp.OFPFW_NW_PROTO, \
931 0 \
932 )
rootf6af1672012-04-06 09:46:29 -0700933 # Specifying a L4 port requirues that Ethertype is IP
Rich Laned0478ff2013-03-11 12:46:58 -0700934 self.match.eth_type = 0x0800
Howard Persh3340d452012-04-06 16:45:21 -0700935 self.match.wildcards = wildcard_set(self.match.wildcards, \
936 ofp.OFPFW_DL_TYPE, \
937 0 \
938 )
Rich Laned0478ff2013-03-11 12:46:58 -0700939 if self.match.ip_proto == 1:
940 self.match.tcp_dst = self.match.tcp_dst & 0xff
rootf6af1672012-04-06 09:46:29 -0700941 else:
Howard Persh3340d452012-04-06 16:45:21 -0700942 self.match.wildcards = wildcard_set(self.match.wildcards, \
943 ofp.OFPFW_TP_DST, \
944 1 \
945 )
rootf6af1672012-04-06 09:46:29 -0700946
947 # If nothing is wildcarded, it is an exact flow spec -- some switches
Howard Persh3340d452012-04-06 16:45:21 -0700948 # (Open vSwitch, for one) *require* that exact flow specs
949 # have priority 65535.
950 self.priority = 65535 if self.match.wildcards == 0 \
951 else fi.rand_priority()
rootf6af1672012-04-06 09:46:29 -0700952
953 # N.B. Don't make the timeout too short, else the flow might
954 # disappear before we get a chance to check for it.
955 t = random.randint(0, 65535)
956 self.idle_timeout = 0 if t < 60 else t
957 t = random.randint(0, 65535)
958 self.hard_timeout = 0 if t < 60 else t
959
Howard Persh8d21c1f2012-04-20 15:57:29 -0700960 self.rand_mod(fi, valid_actions, valid_ports, valid_queues)
rootf6af1672012-04-06 09:46:29 -0700961
962 return self
963
964 # Return flow cfg in canonical form
Howard Persh3340d452012-04-06 16:45:21 -0700965 # - There are dependencies between flow qualifiers, e.g. it only makes
Rich Laned0478ff2013-03-11 12:46:58 -0700966 # sense to qualify ip_proto if eth_type is qualified to be 0x0800 (IP).
Howard Persh3340d452012-04-06 16:45:21 -0700967 # The canonical form of flow match criteria will "wildcard out"
968 # all such cases.
Rich Lane15a15062013-08-12 23:11:12 -0700969 # - The IP mask values from 32 to 63 are equivalent. Canonicalize to 32.
rootf6af1672012-04-06 09:46:29 -0700970 def canonical(self):
971 result = copy.deepcopy(self)
Howard Persh07d99e62012-04-09 15:26:57 -0700972
Rich Lane15a15062013-08-12 23:11:12 -0700973 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_SRC_MASK) > 32:
974 result.match.wildcards = wildcard_set(result.match.wildcards, \
975 ofp.OFPFW_NW_SRC_MASK, \
976 32 \
977 )
978
979 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_DST_MASK) > 32:
980 result.match.wildcards = wildcard_set(result.match.wildcards, \
981 ofp.OFPFW_NW_DST_MASK, \
982 32 \
983 )
984
Howard Persh07d99e62012-04-09 15:26:57 -0700985 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_VLAN) != 0:
986 result.match.wildcards = wildcard_set(result.match.wildcards, \
987 ofp.OFPFW_DL_VLAN_PCP, \
988 1 \
989 )
990
rootf6af1672012-04-06 09:46:29 -0700991 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
Rich Laned0478ff2013-03-11 12:46:58 -0700992 or result.match.eth_type not in [0x0800, 0x0806]:
Howard Persh3340d452012-04-06 16:45:21 -0700993 # dl_tyoe is wildcarded, or specified as something other
994 # than IP or ARP
Rich Laned0478ff2013-03-11 12:46:58 -0700995 # => ipv4_src, ipv4_dst, ip_proto cannot be specified,
Howard Persh07d99e62012-04-09 15:26:57 -0700996 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -0700997 result.match.wildcards = wildcard_set(result.match.wildcards, \
998 ofp.OFPFW_NW_SRC_MASK, \
999 32 \
1000 )
1001 result.match.wildcards = wildcard_set(result.match.wildcards, \
1002 ofp.OFPFW_NW_DST_MASK, \
1003 32 \
1004 )
Howard Persh3340d452012-04-06 16:45:21 -07001005 result.match.wildcards = wildcard_set(result.match.wildcards, \
1006 ofp.OFPFW_NW_PROTO, \
1007 1 \
1008 )
Howard Persh07d99e62012-04-09 15:26:57 -07001009
1010 if wildcard_get(result.match.wildcards, ofp.OFPFW_DL_TYPE) != 0 \
Rich Laned0478ff2013-03-11 12:46:58 -07001011 or result.match.eth_type != 0x0800:
1012 # eth_type is wildcarded, or specified as something other than IP
1013 # => ip_dscp, tcp_src and tcp_dst cannot be specified,
Howard Persh07d99e62012-04-09 15:26:57 -07001014 # must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001015 result.match.wildcards = wildcard_set(result.match.wildcards, \
1016 ofp.OFPFW_NW_TOS, \
1017 1 \
1018 )
1019 result.match.wildcards = wildcard_set(result.match.wildcards, \
1020 ofp.OFPFW_TP_SRC, \
1021 1 \
1022 )
1023 result.match.wildcards = wildcard_set(result.match.wildcards, \
1024 ofp.OFPFW_TP_DST, \
1025 1 \
1026 )
Howard Persh07d99e62012-04-09 15:26:57 -07001027 result.match.wildcards = wildcard_set(result.match.wildcards, \
1028 ofp.OFPFW_NW_SRC_MASK, \
1029 32 \
1030 )
1031 result.match.wildcards = wildcard_set(result.match.wildcards, \
1032 ofp.OFPFW_NW_DST_MASK, \
1033 32 \
1034 )
1035 result.match.wildcards = wildcard_set(result.match.wildcards, \
1036 ofp.OFPFW_NW_PROTO, \
1037 1 \
1038 )
1039
rootf6af1672012-04-06 09:46:29 -07001040 if wildcard_get(result.match.wildcards, ofp.OFPFW_NW_PROTO) != 0 \
Rich Laned0478ff2013-03-11 12:46:58 -07001041 or result.match.ip_proto not in [1, 6, 17]:
1042 # ip_proto is wildcarded, or specified as something other than ICMP,
Howard Persh3340d452012-04-06 16:45:21 -07001043 # TCP or UDP
Rich Laned0478ff2013-03-11 12:46:58 -07001044 # => tcp_src and tcp_dst cannot be specified, must be wildcarded
Howard Persh3340d452012-04-06 16:45:21 -07001045 result.match.wildcards = wildcard_set(result.match.wildcards, \
1046 ofp.OFPFW_TP_SRC, \
1047 1 \
1048 )
1049 result.match.wildcards = wildcard_set(result.match.wildcards, \
1050 ofp.OFPFW_TP_DST, \
1051 1 \
1052 )
rootf6af1672012-04-06 09:46:29 -07001053 return result
1054
Howard Persh680b92a2012-03-31 13:34:35 -07001055 # Overlap check
1056 # delf == True <=> Check for delete overlap, else add overlap
1057 # "Add overlap" is defined as there exists a packet that could match both the
1058 # receiver and argument flowspecs
1059 # "Delete overlap" is defined as the specificity of the argument flowspec
1060 # is greater than or equal to the specificity of the receiver flowspec
1061 def overlaps(self, x, delf):
rootf6af1672012-04-06 09:46:29 -07001062 if wildcard_get(self.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
1063 if wildcard_get(x.match.wildcards, ofp.OFPFW_IN_PORT) == 0:
Howard Persh680b92a2012-03-31 13:34:35 -07001064 if self.match.in_port != x.match.in_port:
1065 return False # Both specified, and not equal
1066 elif delf:
1067 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001068 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
1069 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001070 if self.match.vlan_vid != x.match.vlan_vid:
Howard Persh680b92a2012-03-31 13:34:35 -07001071 return False # Both specified, and not equal
1072 elif delf:
1073 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001074 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
1075 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_SRC) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001076 if self.match.eth_src != x.match.eth_src:
Howard Persh680b92a2012-03-31 13:34:35 -07001077 return False # Both specified, and not equal
1078 elif delf:
1079 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001080 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_DST) == 0:
1081 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_DST) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001082 if self.match.eth_dst != x.match.eth_dst:
Howard Persh680b92a2012-03-31 13:34:35 -07001083 return False # Both specified, and not equal
1084 elif delf:
1085 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001086 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
1087 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_TYPE) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001088 if self.match.eth_type != x.match.eth_type:
Howard Persh680b92a2012-03-31 13:34:35 -07001089 return False # Both specified, and not equal
1090 elif delf:
1091 return False # Recevier more specific
rootf6af1672012-04-06 09:46:29 -07001092 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
1093 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_PROTO) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001094 if self.match.ip_proto != x.match.ip_proto:
Howard Persh680b92a2012-03-31 13:34:35 -07001095 return False # Both specified, and not equal
1096 elif delf:
1097 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001098 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
1099 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_SRC) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001100 if self.match.tcp_src != x.match.tcp_src:
Howard Persh680b92a2012-03-31 13:34:35 -07001101 return False # Both specified, and not equal
1102 elif delf:
1103 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001104 if wildcard_get(self.match.wildcards, ofp.OFPFW_TP_DST) == 0:
1105 if wildcard_get(x.match.wildcards, ofp.OFPFW_TP_DST) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001106 if self.match.tcp_dst != x.match.tcp_dst:
Howard Persh680b92a2012-03-31 13:34:35 -07001107 return False # Both specified, and not equal
1108 elif delf:
1109 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001110 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
1111 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_SRC_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001112 if delf and na < nb:
1113 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001114 if (na < 32 and nb < 32):
1115 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
Rich Laned0478ff2013-03-11 12:46:58 -07001116 if (self.match.ipv4_src & m) != (x.match.ipv4_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -07001117 return False # Overlapping bits not equal
rootf6af1672012-04-06 09:46:29 -07001118 na = wildcard_get(self.match.wildcards, ofp.OFPFW_NW_DST_MASK)
1119 nb = wildcard_get(x.match.wildcards, ofp.OFPFW_NW_DST_MASK)
Howard Persh680b92a2012-03-31 13:34:35 -07001120 if delf and na < nb:
1121 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -07001122 if (na < 32 and nb < 32):
1123 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
Rich Laned0478ff2013-03-11 12:46:58 -07001124 if (self.match.ipv4_dst & m) != (x.match.ipv4_dst & m):
rootf6af1672012-04-06 09:46:29 -07001125 return False # Overlapping bits not equal
1126 if wildcard_get(self.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
1127 if wildcard_get(x.match.wildcards, ofp.OFPFW_DL_VLAN_PCP) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001128 if self.match.vlan_pcp != x.match.vlan_pcp:
Howard Persh680b92a2012-03-31 13:34:35 -07001129 return False # Both specified, and not equal
1130 elif delf:
1131 return False # Receiver more specific
rootf6af1672012-04-06 09:46:29 -07001132 if wildcard_get(self.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
1133 if wildcard_get(x.match.wildcards, ofp.OFPFW_NW_TOS) == 0:
Rich Laned0478ff2013-03-11 12:46:58 -07001134 if self.match.ip_dscp != x.match.ip_dscp:
Howard Persh680b92a2012-03-31 13:34:35 -07001135 return False # Both specified, and not equal
1136 elif delf:
1137 return False # Receiver more specific
1138 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -07001139
1140 def to_flow_mod_msg(self, msg):
1141 msg.match = self.match
rootf6af1672012-04-06 09:46:29 -07001142 msg.cookie = self.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001143 msg.idle_timeout = self.idle_timeout
1144 msg.hard_timeout = self.hard_timeout
1145 msg.priority = self.priority
1146 msg.actions = self.actions
1147 return msg
1148
1149 def from_flow_stat(self, msg):
1150 self.match = msg.match
rootf6af1672012-04-06 09:46:29 -07001151 self.cookie = msg.cookie
Howard Pershc7963582012-03-29 10:02:59 -07001152 self.idle_timeout = msg.idle_timeout
1153 self.hard_timeout = msg.hard_timeout
1154 self.priority = msg.priority
1155 self.actions = msg.actions
1156
rootf6af1672012-04-06 09:46:29 -07001157 def from_flow_rem(self, msg):
1158 self.match = msg.match
1159 self.idle_timeout = msg.idle_timeout
1160 self.priority = msg.priority
Howard Pershc7963582012-03-29 10:02:59 -07001161
Howard Pershc7963582012-03-29 10:02:59 -07001162
rootf6af1672012-04-06 09:46:29 -07001163class Flow_Tbl:
1164 def clear(self):
1165 self.dict = {}
Howard Persh680b92a2012-03-31 13:34:35 -07001166
rootf6af1672012-04-06 09:46:29 -07001167 def __init__(self):
1168 self.clear()
Howard Persh680b92a2012-03-31 13:34:35 -07001169
rootf6af1672012-04-06 09:46:29 -07001170 def find(self, f):
root2843d2b2012-04-06 10:27:46 -07001171 return self.dict.get(f.key_str(), None)
rootf6af1672012-04-06 09:46:29 -07001172
1173 def insert(self, f):
root2843d2b2012-04-06 10:27:46 -07001174 self.dict[f.key_str()] = f
rootf6af1672012-04-06 09:46:29 -07001175
1176 def delete(self, f):
root2843d2b2012-04-06 10:27:46 -07001177 del self.dict[f.key_str()]
rootf6af1672012-04-06 09:46:29 -07001178
1179 def values(self):
1180 return self.dict.values()
1181
1182 def count(self):
1183 return len(self.dict)
1184
Ed Swierk99a74de2012-08-22 06:40:54 -07001185 def rand(self, wildcards_force, sw, fi, num_flows):
rootf6af1672012-04-06 09:46:29 -07001186 self.clear()
1187 i = 0
1188 tbl = 0
1189 j = 0
1190 while i < num_flows:
1191 fc = Flow_Cfg()
1192 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001193 wildcards_force, \
Rich Lane5fd6faf2013-03-11 13:30:20 -07001194 sw.tbl_stats.entries[tbl].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001195 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001196 sw.valid_ports, \
1197 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001198 )
1199 fc = fc.canonical()
1200 if self.find(fc):
1201 continue
1202 fc.send_rem = False
1203 self.insert(fc)
1204 i = i + 1
1205 j = j + 1
Rich Lane5fd6faf2013-03-11 13:30:20 -07001206 if j >= sw.tbl_stats.entries[tbl].max_entries:
rootf6af1672012-04-06 09:46:29 -07001207 tbl = tbl + 1
1208 j = 0
1209
1210
1211class Switch:
1212 # Members:
Howard Persh8d21c1f2012-04-20 15:57:29 -07001213 # controller - switch's test controller
1214 # sw_features - switch's OFPT_FEATURES_REPLY message
1215 # valid_ports - list of valid port numbers
1216 # valid_queues - list of valid [port, queue] pairs
1217 # tbl_stats - switch's OFPT_STATS_REPLY message, for table stats request
1218 # queue_stats - switch's OFPT_STATS_REPLY message, for queue stats request
1219 # flow_stats - switch's OFPT_STATS_REPLY message, for flow stats request
1220 # flow_tbl - (test's idea of) switch's flow table
rootf6af1672012-04-06 09:46:29 -07001221
1222 def __init__(self):
Howard Persh8d21c1f2012-04-20 15:57:29 -07001223 self.controller = None
1224 self.sw_features = None
1225 self.valid_ports = []
1226 self.valid_queues = []
1227 self.tbl_stats = None
1228 self.flow_stats = None
1229 self.flow_tbl = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001230 self.error_msgs = []
1231 self.removed_msgs = []
1232
1233 def error_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001234 logging.info("Got an ERROR message, type=%d, code=%d" \
Rich Laneb73808c2013-03-11 15:22:23 -07001235 % (msg.err_type, msg.code) \
Ed Swierk99a74de2012-08-22 06:40:54 -07001236 )
Ed Swierk99a74de2012-08-22 06:40:54 -07001237 self.error_msgs.append(msg)
1238
1239 def removed_handler(self, controller, msg, rawmsg):
Rich Lane9a003812012-10-04 17:17:59 -07001240 logging.info("Got a REMOVED message")
Ed Swierk99a74de2012-08-22 06:40:54 -07001241 self.removed_msgs.append(msg)
rootf6af1672012-04-06 09:46:29 -07001242
Howard Persh3340d452012-04-06 16:45:21 -07001243 def controller_set(self, controller):
1244 self.controller = controller
1245 # Register error message handler
Ed Swierk99a74de2012-08-22 06:40:54 -07001246 self.error_msgs = []
1247 self.removed_msgs = []
1248 controller.register(ofp.OFPT_ERROR, self.error_handler)
1249 controller.register(ofp.OFPT_FLOW_REMOVED, self.removed_handler)
Howard Persh3340d452012-04-06 16:45:21 -07001250
rootf6af1672012-04-06 09:46:29 -07001251 def features_get(self):
1252 # Get switch features
Rich Lane28fa9272013-03-08 16:00:25 -08001253 request = ofp.message.features_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001254 (self.sw_features, pkt) = self.controller.transact(request)
rootf6af1672012-04-06 09:46:29 -07001255 if self.sw_features is None:
Rich Lane9a003812012-10-04 17:17:59 -07001256 logging.error("Get switch features failed")
rootf6af1672012-04-06 09:46:29 -07001257 return False
1258 self.valid_ports = map(lambda x: x.port_no, self.sw_features.ports)
Rich Lane9a003812012-10-04 17:17:59 -07001259 logging.info("Ports reported by switch:")
1260 logging.info(self.valid_ports)
Rich Lane2014f9b2012-10-05 15:29:40 -07001261 ports_override = test_param_get("ports", [])
Howard Persh8d21c1f2012-04-20 15:57:29 -07001262 if ports_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001263 logging.info("Overriding ports to:")
1264 logging.info(ports_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001265 self.valid_ports = ports_override
1266
Howard Persh3340d452012-04-06 16:45:21 -07001267 # TBD - OFPP_LOCAL is returned by OVS is switch features --
1268 # is that universal?
1269
1270 # TBD - There seems to be variability in which switches support which
1271 # ports; need to sort that out
1272 # TBD - Is it legal to enqueue to a special port? Depends on switch?
1273# self.valid_ports.extend([ofp.OFPP_IN_PORT, \
1274# ofp.OFPP_NORMAL, \
1275# ofp.OFPP_FLOOD, \
1276# ofp.OFPP_ALL, \
1277# ofp.OFPP_CONTROLLER \
1278# ] \
1279# )
Rich Lane9a003812012-10-04 17:17:59 -07001280 logging.info("Supported actions reported by switch:")
1281 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001282 % (self.sw_features.actions, \
1283 actions_bmap_to_str(self.sw_features.actions) \
1284 ) \
1285 )
Rich Lane2014f9b2012-10-05 15:29:40 -07001286 actions_override = test_param_get("actions", -1)
Howard Persh07d99e62012-04-09 15:26:57 -07001287 if actions_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001288 logging.info("Overriding supported actions to:")
1289 logging.info(actions_bmap_to_str(actions_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001290 self.sw_features.actions = actions_override
rootf6af1672012-04-06 09:46:29 -07001291 return True
1292
1293 def tbl_stats_get(self):
1294 # Get table stats
Rich Lane28fa9272013-03-08 16:00:25 -08001295 request = ofp.message.table_stats_request()
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001296 (self.tbl_stats, pkt) = self.controller.transact(request)
Howard Persh07d99e62012-04-09 15:26:57 -07001297 if self.tbl_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001298 logging.error("Get table stats failed")
Howard Persh07d99e62012-04-09 15:26:57 -07001299 return False
Howard Persh8d21c1f2012-04-20 15:57:29 -07001300 i = 0
Rich Lane5fd6faf2013-03-11 13:30:20 -07001301 for ts in self.tbl_stats.entries:
Rich Lane9a003812012-10-04 17:17:59 -07001302 logging.info("Supported wildcards for table %d reported by switch:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001303 % (i)
1304 )
Rich Lane9a003812012-10-04 17:17:59 -07001305 logging.info("0x%x=%s" \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001306 % (ts.wildcards, \
1307 wildcards_to_str(ts.wildcards) \
1308 ) \
1309 )
Rich Lane2014f9b2012-10-05 15:29:40 -07001310 wildcards_override = test_param_get("wildcards", -1)
Howard Persh07d99e62012-04-09 15:26:57 -07001311 if wildcards_override != -1:
Rich Lane9a003812012-10-04 17:17:59 -07001312 logging.info("Overriding supported wildcards for table %d to:"
Howard Persh8d21c1f2012-04-20 15:57:29 -07001313 % (i)
1314 )
Rich Lane9a003812012-10-04 17:17:59 -07001315 logging.info(wildcards_to_str(wildcards_override))
Howard Persh07d99e62012-04-09 15:26:57 -07001316 ts.wildcards = wildcards_override
Howard Persh8d21c1f2012-04-20 15:57:29 -07001317 i = i + 1
Howard Persh07d99e62012-04-09 15:26:57 -07001318 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001319
Howard Persh8d21c1f2012-04-20 15:57:29 -07001320 def queue_stats_get(self):
1321 # Get queue stats
Rich Lane28fa9272013-03-08 16:00:25 -08001322 request = ofp.message.queue_stats_request()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001323 request.port_no = ofp.OFPP_ALL
1324 request.queue_id = ofp.OFPQ_ALL
Rich Lanec8aaa3e2012-07-26 19:28:02 -07001325 (self.queue_stats, pkt) = self.controller.transact(request)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001326 if self.queue_stats is None:
Rich Lane9a003812012-10-04 17:17:59 -07001327 logging.error("Get queue stats failed")
Howard Persh8d21c1f2012-04-20 15:57:29 -07001328 return False
1329 self.valid_queues = map(lambda x: (x.port_no, x.queue_id), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07001330 self.queue_stats.entries \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001331 )
Rich Lane9a003812012-10-04 17:17:59 -07001332 logging.info("(Port, queue) pairs reported by switch:")
1333 logging.info(self.valid_queues)
Rich Lane2014f9b2012-10-05 15:29:40 -07001334 queues_override = test_param_get("queues", [])
Howard Persh8d21c1f2012-04-20 15:57:29 -07001335 if queues_override != []:
Rich Lane9a003812012-10-04 17:17:59 -07001336 logging.info("Overriding (port, queue) pairs to:")
1337 logging.info(queues_override)
Howard Persh8d21c1f2012-04-20 15:57:29 -07001338 self.valid_queues = queues_override
1339 return True
1340
1341 def connect(self, controller):
1342 # Connect to controller, and get all switch capabilities
1343 self.controller_set(controller)
1344 return (self.features_get() \
1345 and self.tbl_stats_get() \
1346 and self.queue_stats_get() \
1347 )
1348
Howard Pershc1199d52012-04-11 14:21:32 -07001349 def flow_stats_get(self, limit = 10000):
Rich Lane28fa9272013-03-08 16:00:25 -08001350 request = ofp.message.flow_stats_request()
Rich Lane0237baf2013-03-11 22:34:59 -07001351 query_match = ofp.match()
Howard Persh680b92a2012-03-31 13:34:35 -07001352 query_match.wildcards = ofp.OFPFW_ALL
rootf6af1672012-04-06 09:46:29 -07001353 request.match = query_match
1354 request.table_id = 0xff
1355 request.out_port = ofp.OFPP_NONE;
Rich Lane5c3151c2013-01-03 17:15:41 -08001356 self.controller.message_send(request)
Howard Persh3340d452012-04-06 16:45:21 -07001357 # <TBD>
1358 # Glue together successive reponse messages for stats reply.
1359 # Looking at the "more" flag and performing re-assembly
1360 # should be a part of the infrastructure.
1361 # </TBD>
1362 n = 0
1363 while True:
Dan Talaycoc689a792012-09-28 14:22:53 -07001364 (resp, pkt) = self.controller.poll(ofp.OFPT_STATS_REPLY)
Howard Persh3340d452012-04-06 16:45:21 -07001365 if resp is None:
Howard Pershc1199d52012-04-11 14:21:32 -07001366 return False # Did not get expected response
Howard Persh3340d452012-04-06 16:45:21 -07001367 if n == 0:
1368 self.flow_stats = resp
1369 else:
Rich Lane5fd6faf2013-03-11 13:30:20 -07001370 self.flow_stats.entries.extend(resp.entries)
Howard Persh3340d452012-04-06 16:45:21 -07001371 n = n + 1
Rich Lane5fd6faf2013-03-11 13:30:20 -07001372 if len(self.flow_stats.entries) > limit:
Rich Lane9a003812012-10-04 17:17:59 -07001373 logging.error("Too many flows returned")
Howard Pershc1199d52012-04-11 14:21:32 -07001374 return False
1375 if (resp.flags & 1) == 0:
1376 break # No more responses expected
Howard Persh3340d452012-04-06 16:45:21 -07001377 return (n > 0)
Howard Persh680b92a2012-03-31 13:34:35 -07001378
rootf6af1672012-04-06 09:46:29 -07001379 def flow_add(self, flow_cfg, overlapf = False):
Rich Laneba3f0e22013-03-11 16:43:57 -07001380 flow_mod_msg = ofp.message.flow_add()
Howard Persh680b92a2012-03-31 13:34:35 -07001381 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001382 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Howard Persh680b92a2012-03-31 13:34:35 -07001383 if overlapf:
1384 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
rootf6af1672012-04-06 09:46:29 -07001385 if flow_cfg.send_rem:
Howard Persh3340d452012-04-06 16:45:21 -07001386 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_SEND_FLOW_REM
Rich Laneb73808c2013-03-11 15:22:23 -07001387 flow_mod_msg.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001388 logging.info("Sending flow_mod(add), xid=%d"
Rich Laneb73808c2013-03-11 15:22:23 -07001389 % (flow_mod_msg.xid)
Howard Pershc1199d52012-04-11 14:21:32 -07001390 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001391 self.controller.message_send(flow_mod_msg)
1392 return True
Howard Persh680b92a2012-03-31 13:34:35 -07001393
rootf6af1672012-04-06 09:46:29 -07001394 def flow_mod(self, flow_cfg, strictf):
Rich Laneba3f0e22013-03-11 16:43:57 -07001395 if strictf:
1396 flow_mod_msg = ofp.message.flow_modify_strict()
1397 else:
1398 flow_mod_msg = ofp.message.flow_modify()
Howard Persh680b92a2012-03-31 13:34:35 -07001399 flow_mod_msg.buffer_id = 0xffffffff
rootf6af1672012-04-06 09:46:29 -07001400 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Rich Laneb73808c2013-03-11 15:22:23 -07001401 flow_mod_msg.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001402 logging.info("Sending flow_mod(mod), xid=%d"
Rich Laneb73808c2013-03-11 15:22:23 -07001403 % (flow_mod_msg.xid)
Howard Pershc1199d52012-04-11 14:21:32 -07001404 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001405 self.controller.message_send(flow_mod_msg)
1406 return True
rootf6af1672012-04-06 09:46:29 -07001407
1408 def flow_del(self, flow_cfg, strictf):
Rich Laneba3f0e22013-03-11 16:43:57 -07001409 if strictf:
1410 flow_mod_msg = ofp.message.flow_delete_strict()
1411 else:
1412 flow_mod_msg = ofp.message.flow_delete()
rootf6af1672012-04-06 09:46:29 -07001413 flow_mod_msg.buffer_id = 0xffffffff
1414 # TBD - "out_port" filtering of deletes needs to be tested
Howard Persh680b92a2012-03-31 13:34:35 -07001415 flow_mod_msg.out_port = ofp.OFPP_NONE
rootf6af1672012-04-06 09:46:29 -07001416 flow_cfg.to_flow_mod_msg(flow_mod_msg)
Rich Laneb73808c2013-03-11 15:22:23 -07001417 flow_mod_msg.xid = random.randrange(1,0xffffffff)
Rich Lane9a003812012-10-04 17:17:59 -07001418 logging.info("Sending flow_mod(del), xid=%d"
Rich Laneb73808c2013-03-11 15:22:23 -07001419 % (flow_mod_msg.xid)
Howard Pershc1199d52012-04-11 14:21:32 -07001420 )
Rich Lane5c3151c2013-01-03 17:15:41 -08001421 self.controller.message_send(flow_mod_msg)
1422 return True
rootf6af1672012-04-06 09:46:29 -07001423
1424 def barrier(self):
Rich Lane28fa9272013-03-08 16:00:25 -08001425 barrier = ofp.message.barrier_request()
Dan Talaycoc689a792012-09-28 14:22:53 -07001426 (resp, pkt) = self.controller.transact(barrier, 30)
rootf6af1672012-04-06 09:46:29 -07001427 return (resp is not None)
1428
Howard Persh3340d452012-04-06 16:45:21 -07001429 def errors_verify(self, num_exp, type = 0, code = 0):
rootf6af1672012-04-06 09:46:29 -07001430 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001431 logging.info("Expecting %d error messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001432 num_got = len(self.error_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001433 logging.info("Got %d error messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001434 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001435 logging.error("Incorrect number of error messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001436 result = False
1437 if num_exp == 0:
1438 return result
1439 elif num_exp == 1:
Rich Lane9a003812012-10-04 17:17:59 -07001440 logging.info("Expecting error message, type=%d, code=%d" \
Howard Persh3340d452012-04-06 16:45:21 -07001441 % (type, code) \
1442 )
1443 f = False
Ed Swierk99a74de2012-08-22 06:40:54 -07001444 for e in self.error_msgs:
Rich Laneb73808c2013-03-11 15:22:23 -07001445 if e.err_type == type and e.code == code:
Rich Lane9a003812012-10-04 17:17:59 -07001446 logging.info("Got it")
Howard Persh3340d452012-04-06 16:45:21 -07001447 f = True
1448 if not f:
Rich Lane9a003812012-10-04 17:17:59 -07001449 logging.error("Did not get it")
rootf6af1672012-04-06 09:46:29 -07001450 result = False
Howard Persh3340d452012-04-06 16:45:21 -07001451 else:
Rich Lane9a003812012-10-04 17:17:59 -07001452 logging.error("Can't expect more than 1 error message type")
rootf6af1672012-04-06 09:46:29 -07001453 result = False
1454 return result
1455
Howard Persh3340d452012-04-06 16:45:21 -07001456 def removed_verify(self, num_exp):
1457 result = True
Rich Lane9a003812012-10-04 17:17:59 -07001458 logging.info("Expecting %d removed messages" % (num_exp))
Ed Swierk99a74de2012-08-22 06:40:54 -07001459 num_got = len(self.removed_msgs)
Rich Lane9a003812012-10-04 17:17:59 -07001460 logging.info("Got %d removed messages" % (num_got))
Howard Persh3340d452012-04-06 16:45:21 -07001461 if num_got != num_exp:
Rich Lane9a003812012-10-04 17:17:59 -07001462 logging.error("Incorrect number of removed messages received")
Howard Persh3340d452012-04-06 16:45:21 -07001463 result = False
1464 if num_exp < 2:
1465 return result
Rich Lane9a003812012-10-04 17:17:59 -07001466 logging.error("Can't expect more than 1 error message type")
Howard Persh3340d452012-04-06 16:45:21 -07001467 return False
1468
Howard Persh5f3c83f2012-04-13 09:57:10 -07001469 # modf == True <=> Verify for flow modify, else for add/delete
1470 def flow_tbl_verify(self, modf = False):
rootf6af1672012-04-06 09:46:29 -07001471 result = True
1472
1473 # Verify flow count in switch
Rich Lane9a003812012-10-04 17:17:59 -07001474 logging.info("Reading table stats")
1475 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001476 if not self.tbl_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001477 logging.error("Get table stats failed")
rootf6af1672012-04-06 09:46:29 -07001478 return False
1479 n = 0
Rich Lane5fd6faf2013-03-11 13:30:20 -07001480 for ts in self.tbl_stats.entries:
rootf6af1672012-04-06 09:46:29 -07001481 n = n + ts.active_count
Rich Lane9a003812012-10-04 17:17:59 -07001482 logging.info("Table stats reported %d active flows" \
rootf6af1672012-04-06 09:46:29 -07001483 % (n) \
1484 )
1485 if n != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001486 logging.error("Incorrect number of active flows reported")
rootf6af1672012-04-06 09:46:29 -07001487 result = False
1488
1489 # Read flows from switch
Rich Lane9a003812012-10-04 17:17:59 -07001490 logging.info("Retrieving flows from switch")
1491 logging.info("Expecting %d flows" % (self.flow_tbl.count()))
rootf6af1672012-04-06 09:46:29 -07001492 if not self.flow_stats_get():
Rich Lane9a003812012-10-04 17:17:59 -07001493 logging.error("Get flow stats failed")
rootf6af1672012-04-06 09:46:29 -07001494 return False
Rich Lane5fd6faf2013-03-11 13:30:20 -07001495 logging.info("Retrieved %d flows" % (len(self.flow_stats.entries)))
rootf6af1672012-04-06 09:46:29 -07001496
1497 # Verify flows returned by switch
1498
Rich Lane5fd6faf2013-03-11 13:30:20 -07001499 if len(self.flow_stats.entries) != self.flow_tbl.count():
Rich Lane9a003812012-10-04 17:17:59 -07001500 logging.error("Switch reported incorrect number of flows")
rootf6af1672012-04-06 09:46:29 -07001501 result = False
1502
Rich Lane9a003812012-10-04 17:17:59 -07001503 logging.info("Verifying received flows")
rootf6af1672012-04-06 09:46:29 -07001504 for fc in self.flow_tbl.values():
1505 fc.matched = False
Rich Lane5fd6faf2013-03-11 13:30:20 -07001506 for fs in self.flow_stats.entries:
rootf6af1672012-04-06 09:46:29 -07001507 flow_in = Flow_Cfg()
1508 flow_in.from_flow_stat(fs)
Rich Lane15a15062013-08-12 23:11:12 -07001509 flow_in = flow_in.canonical()
Rich Lane9a003812012-10-04 17:17:59 -07001510 logging.info("Received flow:")
1511 logging.info(str(flow_in))
rootf6af1672012-04-06 09:46:29 -07001512 fc = self.flow_tbl.find(flow_in)
1513 if fc is None:
Rich Lane9a003812012-10-04 17:17:59 -07001514 logging.error("Received flow:")
1515 logging.error(str(flow_in))
1516 logging.error("does not match any defined flow")
rootf6af1672012-04-06 09:46:29 -07001517 result = False
1518 elif fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001519 logging.error("Received flow:")
1520 logging.error(str(flow_in))
1521 logging.error("re-matches defined flow:")
1522 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001523 result = False
1524 else:
Rich Lane9a003812012-10-04 17:17:59 -07001525 logging.info("matched")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001526 if modf:
1527 # Check for modify
1528
1529 if flow_in.cookie != fc.cookie:
Rich Lane9a003812012-10-04 17:17:59 -07001530 logging.warning("Defined flow:")
1531 logging.warning(str(fc))
1532 logging.warning("Received flow:")
1533 logging.warning(str(flow_in))
1534 logging.warning("cookies do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001535 if not flow_in.actions_equal(fc):
Rich Lane9a003812012-10-04 17:17:59 -07001536 logging.error("Defined flow:")
1537 logging.error(str(fc))
1538 logging.error("Received flow:")
1539 logging.error(str(flow_in))
1540 logging.error("actions do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001541 else:
1542 # Check for add/delete
1543
1544 if not flow_in == fc:
Rich Lane9a003812012-10-04 17:17:59 -07001545 logging.error("Defined flow:")
1546 logging.error(str(fc))
1547 logging.error("Received flow:")
1548 logging.error(str(flow_in))
1549 logging.error("non-key portions of flow do not match")
Howard Persh5f3c83f2012-04-13 09:57:10 -07001550 result = False
rootf6af1672012-04-06 09:46:29 -07001551 fc.matched = True
1552 for fc in self.flow_tbl.values():
1553 if not fc.matched:
Rich Lane9a003812012-10-04 17:17:59 -07001554 logging.error("Defined flow:")
1555 logging.error(str(fc))
1556 logging.error("was not returned by switch")
rootf6af1672012-04-06 09:46:29 -07001557 result = False
1558
1559 return result
Howard Persh680b92a2012-03-31 13:34:35 -07001560
Howard Persh9cab4822012-09-11 17:08:40 -07001561 def settle(self):
1562 time.sleep(2)
1563
Howard Persh07d99e62012-04-09 15:26:57 -07001564# FLOW ADD 5
1565#
1566# OVERVIEW
1567# Add flows to switch, read back and verify flow configurations
1568#
1569# PURPOSE
1570# - Test acceptance of flow adds
1571# - Test ability of switch to process additions to flow table in random
1572# priority order
1573# - Test correctness of flow configuration responses
1574#
1575# PARAMETERS
1576#
1577# Name: num_flows
1578# Type: number
1579# Description:
1580# Number of flows to define; 0 => maximum number of flows, as determined
1581# from switch capabilities
1582# Default: 100
1583#
1584# PROCESS
1585# 1. Delete all flows from switch
1586# 2. Generate <num_flows> distinct flow configurations
1587# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
1588# 4. Verify that no OFPT_ERROR responses were generated by switch
1589# 5. Retrieve flow stats from switch
1590# 6. Compare flow configurations returned by switch
1591# 7. Test PASSED iff all flows sent to switch in step 3 above are returned
1592# in step 5 above; else test FAILED
Howard Persh680b92a2012-03-31 13:34:35 -07001593
Rich Laneb90a1c42012-10-05 09:16:05 -07001594class Flow_Add_5(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001595 """
1596 Test FLOW_ADD_5 from draft top-half test plan
1597
1598 INPUTS
1599 num_flows - Number of flows to generate
1600 """
Howard Persh680b92a2012-03-31 13:34:35 -07001601
rootf6af1672012-04-06 09:46:29 -07001602 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001603 logging.info("Flow_Add_5 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001604
Rich Lane2014f9b2012-10-05 15:29:40 -07001605 num_flows = test_param_get("num_flows", 100)
Howard Persh3340d452012-04-06 16:45:21 -07001606
Howard Pershc7963582012-03-29 10:02:59 -07001607 # Clear all flows from switch
rootf6af1672012-04-06 09:46:29 -07001608
Rich Lane9a003812012-10-04 17:17:59 -07001609 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001610 delete_all_flows(self.controller)
Howard Pershc7963582012-03-29 10:02:59 -07001611
rootf6af1672012-04-06 09:46:29 -07001612 # Get switch capabilites
Howard Pershc7963582012-03-29 10:02:59 -07001613
rootf6af1672012-04-06 09:46:29 -07001614 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001615 self.assertTrue(sw.connect(self.controller), \
1616 "Failed to connect to switch" \
1617 )
Howard Pershc7963582012-03-29 10:02:59 -07001618
rootf6af1672012-04-06 09:46:29 -07001619 if num_flows == 0:
1620 # Number of flows requested was 0
1621 # => Generate max number of flows
Howard Pershc7963582012-03-29 10:02:59 -07001622
Rich Lane5fd6faf2013-03-11 13:30:20 -07001623 for ts in sw.tbl_stats.entries:
rootf6af1672012-04-06 09:46:29 -07001624 num_flows = num_flows + ts.max_entries
Howard Pershc7963582012-03-29 10:02:59 -07001625
Rich Lane9a003812012-10-04 17:17:59 -07001626 logging.info("Generating %d flows" % (num_flows))
Howard Persh680b92a2012-03-31 13:34:35 -07001627
1628 # Dream up some flow information, i.e. space to chose from for
1629 # random flow parameter generation
Howard Pershc7963582012-03-29 10:02:59 -07001630
rootf6af1672012-04-06 09:46:29 -07001631 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001632 fi.rand(max(2 * int(math.log(num_flows)), 1))
Howard Pershc7963582012-03-29 10:02:59 -07001633
rootf6af1672012-04-06 09:46:29 -07001634 # Create a flow table
Howard Persh680b92a2012-03-31 13:34:35 -07001635
rootf6af1672012-04-06 09:46:29 -07001636 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001637 ft.rand(required_wildcards(self), sw, fi, num_flows)
Howard Persh680b92a2012-03-31 13:34:35 -07001638
rootf6af1672012-04-06 09:46:29 -07001639 # Send flow table to switch
Howard Persh680b92a2012-03-31 13:34:35 -07001640
Rich Lane9a003812012-10-04 17:17:59 -07001641 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001642 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001643 logging.info("Adding flow:")
1644 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001645 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
Howard Persh680b92a2012-03-31 13:34:35 -07001646
rootf6af1672012-04-06 09:46:29 -07001647 # Do barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001648
rootf6af1672012-04-06 09:46:29 -07001649 self.assertTrue(sw.barrier(), "Barrier failed")
Howard Pershc7963582012-03-29 10:02:59 -07001650
rootf6af1672012-04-06 09:46:29 -07001651 result = True
Howard Pershc7963582012-03-29 10:02:59 -07001652
Howard Persh9cab4822012-09-11 17:08:40 -07001653 sw.settle() # Allow switch to settle and generate any notifications
1654
rootf6af1672012-04-06 09:46:29 -07001655 # Check for any error messages
Howard Pershc7963582012-03-29 10:02:59 -07001656
rootf6af1672012-04-06 09:46:29 -07001657 if not sw.errors_verify(0):
1658 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001659
rootf6af1672012-04-06 09:46:29 -07001660 # Verify flow table
Howard Pershc7963582012-03-29 10:02:59 -07001661
rootf6af1672012-04-06 09:46:29 -07001662 sw.flow_tbl = ft
1663 if not sw.flow_tbl_verify():
1664 result = False
Howard Pershc7963582012-03-29 10:02:59 -07001665
rootf6af1672012-04-06 09:46:29 -07001666 self.assertTrue(result, "Flow_Add_5 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001667 logging.info("Flow_Add_5 TEST PASSED")
Howard Pershc7963582012-03-29 10:02:59 -07001668
Howard Pershc7963582012-03-29 10:02:59 -07001669
Howard Persh07d99e62012-04-09 15:26:57 -07001670# FLOW ADD 5_1
1671#
1672# OVERVIEW
1673# Verify handling of non-canonical flows
1674#
1675# PURPOSE
1676# - Test that switch detects and correctly responds to a non-canonical flow
1677# definition. A canonical flow is one that satisfies all match qualifier
1678# dependencies; a non-canonical flow is one that does not.
1679#
1680# PARAMETERS
1681# - None
1682#
1683# PROCESS
1684# 1. Delete all flows from switch
1685# 2. Generate 1 flow definition, which is different from its canonicalization
1686# 3. Send flow to switch
1687# 4. Retrieve flow from switch
1688# 5. Compare returned flow to canonical form of defined flow
1689# 7. Test PASSED iff flow received in step 4 above is identical to canonical form of flow defined in step 3 above
1690
1691# Disabled.
1692# Should be DUT dependent.
Howard Persh07d99e62012-04-09 15:26:57 -07001693
Rich Lane0a4f6372013-01-02 14:40:22 -08001694@nonstandard
Rich Laneb90a1c42012-10-05 09:16:05 -07001695class Flow_Add_5_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001696 """
1697 Test FLOW_ADD_5.1 from draft top-half test plan
1698
1699 INPUTS
1700 None
1701 """
Rich Laned1d9c282012-10-04 22:07:10 -07001702
rootf6af1672012-04-06 09:46:29 -07001703 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001704 logging.info("Flow_Add_5_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001705
Rich Lane2014f9b2012-10-05 15:29:40 -07001706 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07001707
1708 # Clear all flows from switch
1709
Rich Lane9a003812012-10-04 17:17:59 -07001710 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001711 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001712
1713 # Get switch capabilites
1714
rootf6af1672012-04-06 09:46:29 -07001715 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001716 self.assertTrue(sw.connect(self.controller), \
1717 "Failed to connect to switch" \
1718 )
rootf6af1672012-04-06 09:46:29 -07001719
1720 # Dream up some flow information, i.e. space to chose from for
1721 # random flow parameter generation
1722
1723 fi = Flow_Info()
1724 fi.rand(10)
1725
1726 # Dream up a flow config that will be canonicalized by the switch
1727
1728 while True:
1729 fc = Flow_Cfg()
1730 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001731 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07001732 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001733 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001734 sw.valid_ports, \
1735 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001736 )
1737 fcc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001738 if fcc.match != fc.match:
rootf6af1672012-04-06 09:46:29 -07001739 break
1740
1741 ft = Flow_Tbl()
1742 ft.insert(fcc)
1743
1744 # Send it to the switch
1745
Rich Lane9a003812012-10-04 17:17:59 -07001746 logging.info("Sending flow add to switch:")
1747 logging.info(str(fc))
1748 logging.info("should be canonicalized as:")
1749 logging.info(str(fcc))
rootf6af1672012-04-06 09:46:29 -07001750 fc.send_rem = False
1751 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1752
1753 # Do barrier, to make sure all flows are in
1754
1755 self.assertTrue(sw.barrier(), "Barrier failed")
1756
1757 result = True
1758
Howard Persh9cab4822012-09-11 17:08:40 -07001759 sw.settle() # Allow switch to settle and generate any notifications
1760
rootf6af1672012-04-06 09:46:29 -07001761 # Check for any error messages
1762
1763 if not sw.errors_verify(0):
1764 result = False
1765
1766 # Verify flow table
1767
1768 sw.flow_tbl = ft
1769 if not sw.flow_tbl_verify():
1770 result = False
1771
1772 self.assertTrue(result, "Flow_Add_5_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001773 logging.info("Flow_Add_5_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001774
1775
Howard Persh07d99e62012-04-09 15:26:57 -07001776# FLOW ADD 6
1777#
1778# OVERVIEW
1779# Test flow table capacity
1780#
1781# PURPOSE
1782# - Test switch can accept as many flow definitions as it claims
1783# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL
1784# - Test that attempting to create flows beyond capacity does not corrupt
1785# flow table
1786#
1787# PARAMETERS
1788# None
1789#
1790# PROCESS
1791# 1. Delete all flows from switch
1792# 2. Send OFPT_FEATURES_REQUEST and OFPT_STATS_REQUEST/OFPST_TABLE enquiries
1793# to determine flow table size, N
1794# 3. Generate (N + 1) distinct flow configurations
1795# 4. Send N flow adds to switch, for flows generated in step 3 above
1796# 5. Verify flow table in switch
1797# 6. Send one more flow add to switch
1798# 7. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_ALL_TABLES_FULL error
1799# response was generated by switch, for last flow mod sent
1800# 7. Retrieve flow stats from switch
1801# 8. Verify flow table in switch
1802# 9. Test PASSED iff:
1803# - error message received, for correct flow
1804# - last flow definition sent to switch is not in flow table
1805# else test FAILED
1806
Howard Persh3340d452012-04-06 16:45:21 -07001807# Disabled because of bogus capacity reported by OVS.
1808# Should be DUT dependent.
Howard Persh3340d452012-04-06 16:45:21 -07001809
Rich Lane0a4f6372013-01-02 14:40:22 -08001810@nonstandard
Rich Laneb90a1c42012-10-05 09:16:05 -07001811class Flow_Add_6(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001812 """
1813 Test FLOW_ADD_6 from draft top-half test plan
1814
1815 INPUTS
1816 num_flows - Number of flows to generate
1817 """
Howard Pershc7963582012-03-29 10:02:59 -07001818
1819 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001820 logging.info("Flow_Add_6 TEST BEGIN")
Howard Pershc7963582012-03-29 10:02:59 -07001821
rootf6af1672012-04-06 09:46:29 -07001822 # Clear all flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001823
Rich Lane9a003812012-10-04 17:17:59 -07001824 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001825 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001826
1827 # Get switch capabilites
1828
rootf6af1672012-04-06 09:46:29 -07001829 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001830 self.assertTrue(sw.connect(self.controller), \
1831 "Failed to connect to switch" \
1832 )
rootf6af1672012-04-06 09:46:29 -07001833
root2843d2b2012-04-06 10:27:46 -07001834 num_flows = 0
Rich Lane5fd6faf2013-03-11 13:30:20 -07001835 for ts in sw.tbl_stats.entries:
rootf6af1672012-04-06 09:46:29 -07001836 num_flows = num_flows + ts.max_entries
1837
Rich Lane9a003812012-10-04 17:17:59 -07001838 logging.info("Switch capacity is %d flows" % (num_flows))
1839 logging.info("Generating %d flows" % (num_flows))
rootf6af1672012-04-06 09:46:29 -07001840
1841 # Dream up some flow information, i.e. space to chose from for
1842 # random flow parameter generation
1843
1844 fi = Flow_Info()
Howard Persh07d99e62012-04-09 15:26:57 -07001845 fi.rand(max(2 * int(math.log(num_flows)), 1))
rootf6af1672012-04-06 09:46:29 -07001846
1847 # Create a flow table, to switch's capacity
1848
1849 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07001850 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07001851
1852 # Send flow table to switch
1853
Rich Lane9a003812012-10-04 17:17:59 -07001854 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07001855 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07001856 logging.info("Adding flow:")
1857 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001858 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1859
1860 # Do barrier, to make sure all flows are in
1861
1862 self.assertTrue(sw.barrier(), "Barrier failed")
1863
1864 result = True
1865
Howard Persh9cab4822012-09-11 17:08:40 -07001866 sw.settle() # Allow switch to settle and generate any notifications
1867
rootf6af1672012-04-06 09:46:29 -07001868 # Check for any error messages
1869
1870 if not sw.errors_verify(0):
1871 result = False
1872
1873 # Dream up one more flow
1874
Rich Lane9a003812012-10-04 17:17:59 -07001875 logging.info("Creating one more flow")
rootf6af1672012-04-06 09:46:29 -07001876 while True:
1877 fc = Flow_Cfg()
1878 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001879 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07001880 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001881 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001882 sw.valid_ports, \
1883 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001884 )
1885 fc = fc.canonical()
Howard Persh07d99e62012-04-09 15:26:57 -07001886 if not ft.find(fc):
1887 break
rootf6af1672012-04-06 09:46:29 -07001888
1889 # Send one-more flow
1890
1891 fc.send_rem = False
Rich Lane9a003812012-10-04 17:17:59 -07001892 logging.info("Sending flow add switch")
1893 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07001894 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1895
1896 # Do barrier, to make sure all flows are in
1897
1898 self.assertTrue(sw.barrier(), "Barrier failed")
1899
Howard Persh9cab4822012-09-11 17:08:40 -07001900 sw.settle() # Allow switch to settle and generate any notifications
1901
rootf6af1672012-04-06 09:46:29 -07001902 # Check for expected error message
1903
1904 if not sw.errors_verify(1, \
1905 ofp.OFPET_FLOW_MOD_FAILED, \
1906 ofp.OFPFMFC_ALL_TABLES_FULL \
1907 ):
1908 result = False
1909
1910 # Verify flow table
1911
1912 sw.flow_tbl = ft
1913 if not sw.flow_tbl_verify():
1914 result = False
1915
1916 self.assertTrue(result, "Flow_add_6 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07001917 logging.info("Flow_add_6 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07001918
1919
Howard Persh07d99e62012-04-09 15:26:57 -07001920# FLOW ADD 7
1921#
1922# OVERVIEW
1923# Test flow redefinition
1924#
1925# PURPOSE
1926# Verify that successive flow adds with same priority and match criteria
1927# overwrite in flow table
1928#
1929# PARAMETERS
1930# None
1931#
1932# PROCESS
1933# 1. Delete all flows from switch
1934# 2. Generate flow definition F1
1935# 3. Generate flow definition F2, with same key (priority and match) as F1,
1936# but with different actions
1937# 4. Send flow adds for F1 and F2 to switch
1938# 5. Verify flow definitions in switch
1939# 6. Test PASSED iff 1 flow returned by switch, matching configuration of F2;
1940# else test FAILED
1941
Rich Laneb90a1c42012-10-05 09:16:05 -07001942class Flow_Add_7(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07001943 """
1944 Test FLOW_ADD_7 from draft top-half test plan
1945
1946 INPUTS
1947 None
1948 """
1949
1950 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07001951 logging.info("Flow_Add_7 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07001952
1953 # Clear all flows from switch
1954
Rich Lane9a003812012-10-04 17:17:59 -07001955 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08001956 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07001957
1958 # Get switch capabilites
1959
rootf6af1672012-04-06 09:46:29 -07001960 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07001961 self.assertTrue(sw.connect(self.controller), \
1962 "Failed to connect to switch" \
1963 )
rootf6af1672012-04-06 09:46:29 -07001964
1965 # Dream up some flow information, i.e. space to chose from for
1966 # random flow parameter generation
1967
1968 fi = Flow_Info()
1969 fi.rand(10)
1970
1971 # Dream up a flow config
1972
1973 fc = Flow_Cfg()
1974 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07001975 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07001976 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07001977 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001978 sw.valid_ports, \
1979 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07001980 )
1981 fc = fc.canonical()
1982
1983 # Send it to the switch
1984
Rich Lane9a003812012-10-04 17:17:59 -07001985 logging.info("Sending flow add to switch:")
1986 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07001987 ft = Flow_Tbl()
1988 fc.send_rem = False
1989 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
1990 ft.insert(fc)
1991
1992 # Dream up some different actions, with the same flow key
1993
1994 fc2 = copy.deepcopy(fc)
1995 while True:
1996 fc2.rand_mod(fi, \
1997 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07001998 sw.valid_ports, \
1999 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002000 )
2001 if fc2 != fc:
2002 break
2003
2004 # Send that to the switch
2005
Rich Lane9a003812012-10-04 17:17:59 -07002006 logging.info("Sending flow add to switch:")
2007 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002008 fc2.send_rem = False
2009 self.assertTrue(sw.flow_add(fc2), "Failed to add flow")
2010 ft.insert(fc2)
2011
2012 # Do barrier, to make sure all flows are in
2013
2014 self.assertTrue(sw.barrier(), "Barrier failed")
2015
2016 result = True
2017
Howard Persh9cab4822012-09-11 17:08:40 -07002018 sw.settle() # Allow switch to settle and generate any notifications
2019
rootf6af1672012-04-06 09:46:29 -07002020 # Check for any error messages
2021
2022 if not sw.errors_verify(0):
2023 result = False
2024
2025 # Verify flow table
2026
2027 sw.flow_tbl = ft
2028 if not sw.flow_tbl_verify():
2029 result = False
2030
2031 self.assertTrue(result, "Flow_Add_7 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002032 logging.info("Flow_Add_7 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002033
2034
Howard Persh07d99e62012-04-09 15:26:57 -07002035# FLOW ADD 8
2036#
2037# OVERVIEW
2038# Add overlapping flows to switch, verify that overlapping flows are rejected
2039#
2040# PURPOSE
2041# - Test detection of overlapping flows by switch
2042# - Test generation of OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP messages
2043# - Test rejection of overlapping flows
2044# - Test defining overlapping flows does not corrupt flow table
2045#
2046# PARAMETERS
2047# None
2048#
2049# PROCESS
2050# 1. Delete all flows from switch
2051# 2. Generate flow definition F1
2052# 3. Generate flow definition F2, with key overlapping F1
2053# 4. Send flow add to switch, for F1
2054# 5. Send flow add to switch, for F2, with OFPFF_CHECK_OVERLAP set
2055# 6. Verify that OFPET_FLOW_MOD_FAILED/OFPFMFC_OVERLAP error response
2056# was generated by switch
2057# 7. Verifiy flows configured in swtich
2058# 8. Test PASSED iff:
2059# - error message received, for overlapping flow
2060# - overlapping flow is not in flow table
2061# else test FAILED
2062
Rich Laneb90a1c42012-10-05 09:16:05 -07002063class Flow_Add_8(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002064 """
2065 Test FLOW_ADD_8 from draft top-half test plan
2066
2067 INPUTS
2068 None
2069 """
2070
2071 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002072 logging.info("Flow_Add_8 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002073
2074 # Clear all flows from switch
2075
Rich Lane9a003812012-10-04 17:17:59 -07002076 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002077 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002078
2079 # Get switch capabilites
2080
rootf6af1672012-04-06 09:46:29 -07002081 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002082 self.assertTrue(sw.connect(self.controller), \
2083 "Failed to connect to switch" \
2084 )
rootf6af1672012-04-06 09:46:29 -07002085
2086 # Dream up some flow information, i.e. space to chose from for
2087 # random flow parameter generation
2088
2089 fi = Flow_Info()
2090 fi.rand(10)
2091
2092 # Dream up a flow config, with at least 1 qualifier specified
2093
2094 fc = Flow_Cfg()
2095 while True:
2096 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002097 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002098 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002099 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002100 sw.valid_ports, \
2101 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002102 )
2103 fc = fc.canonical()
2104 if fc.match.wildcards != ofp.OFPFW_ALL:
2105 break
2106
2107 # Send it to the switch
2108
Rich Lane9a003812012-10-04 17:17:59 -07002109 logging.info("Sending flow add to switch:")
2110 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002111 ft = Flow_Tbl()
2112 fc.send_rem = False
2113 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2114 ft.insert(fc)
2115
2116 # Wildcard out one qualifier that was specified, to create an
2117 # overlapping flow
2118
2119 fc2 = copy.deepcopy(fc)
2120 for wi in shuffle(range(len(all_wildcards_list))):
2121 w = all_wildcards_list[wi]
2122 if (fc2.match.wildcards & w) == 0:
2123 break
2124 if w == ofp.OFPFW_NW_SRC_MASK:
2125 w = ofp.OFPFW_NW_SRC_ALL
2126 wn = "OFPFW_NW_SRC"
2127 elif w == ofp.OFPFW_NW_DST_MASK:
2128 w = ofp.OFPFW_NW_DST_ALL
2129 wn = "OFPFW_NW_DST"
2130 else:
2131 wn = all_wildcard_names[w]
Rich Lane9a003812012-10-04 17:17:59 -07002132 logging.info("Wildcarding out %s" % (wn))
rootf6af1672012-04-06 09:46:29 -07002133 fc2.match.wildcards = fc2.match.wildcards | w
Howard Persh07d99e62012-04-09 15:26:57 -07002134 fc2 = fc2.canonical()
rootf6af1672012-04-06 09:46:29 -07002135
2136 # Send that to the switch, with overlap checking
2137
Rich Lane9a003812012-10-04 17:17:59 -07002138 logging.info("Sending flow add to switch:")
2139 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002140 fc2.send_rem = False
2141 self.assertTrue(sw.flow_add(fc2, True), "Failed to add flow")
2142
2143 # Do barrier, to make sure all flows are in
2144 self.assertTrue(sw.barrier(), "Barrier failed")
2145
2146 result = True
2147
Howard Persh9cab4822012-09-11 17:08:40 -07002148 sw.settle() # Allow switch to settle and generate any notifications
2149
rootf6af1672012-04-06 09:46:29 -07002150 # Check for expected error message
2151
2152 if not sw.errors_verify(1, \
2153 ofp.OFPET_FLOW_MOD_FAILED, \
2154 ofp.OFPFMFC_OVERLAP \
2155 ):
2156 result = False
2157
2158 # Verify flow table
2159
2160 sw.flow_tbl = ft
2161 if not sw.flow_tbl_verify():
2162 result = False
2163
2164 self.assertTrue(result, "Flow_Add_8 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002165 logging.info("Flow_Add_8 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002166
2167
Howard Persh07d99e62012-04-09 15:26:57 -07002168# FLOW MODIFY 1
2169#
2170# OVERVIEW
2171# Strict modify of single existing flow
2172#
2173# PURPOSE
2174# - Verify that strict flow modify operates only on specified flow
2175# - Verify that flow is correctly modified
2176#
2177# PARAMETERS
2178# None
2179#
2180# PROCESS
2181# 1. Delete all flows from switch
2182# 2. Generate 1 flow F
2183# 3. Send flow add to switch, for flow F
2184# 4. Generate new action list for flow F, yielding F'
2185# 5. Send strict flow modify to switch, for flow F'
2186# 6. Verify flow table in switch
2187# 7. Test PASSED iff flow returned by switch is F'; else FAILED
2188
Rich Laneb90a1c42012-10-05 09:16:05 -07002189class Flow_Mod_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002190 """
2191 Test FLOW_MOD_1 from draft top-half test plan
2192
2193 INPUTS
2194 None
2195 """
2196
2197 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002198 logging.info("Flow_Mod_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002199
2200 # Clear all flows from switch
2201
Rich Lane9a003812012-10-04 17:17:59 -07002202 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002203 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002204
2205 # Get switch capabilites
2206
rootf6af1672012-04-06 09:46:29 -07002207 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002208 self.assertTrue(sw.connect(self.controller), \
2209 "Failed to connect to switch" \
2210 )
rootf6af1672012-04-06 09:46:29 -07002211
2212 # Dream up some flow information, i.e. space to chose from for
2213 # random flow parameter generation
2214
2215 fi = Flow_Info()
2216 fi.rand(10)
2217
2218 # Dream up a flow config
2219
2220 fc = Flow_Cfg()
2221 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002222 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002223 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002224 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002225 sw.valid_ports, \
2226 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002227 )
2228 fc = fc.canonical()
2229
2230 # Send it to the switch
2231
Rich Lane9a003812012-10-04 17:17:59 -07002232 logging.info("Sending flow add to switch:")
2233 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002234 ft = Flow_Tbl()
2235 fc.send_rem = False
2236 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2237 ft.insert(fc)
2238
2239 # Dream up some different actions, with the same flow key
2240
2241 fc2 = copy.deepcopy(fc)
2242 while True:
2243 fc2.rand_mod(fi, \
2244 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002245 sw.valid_ports, \
2246 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002247 )
2248 if fc2 != fc:
2249 break
2250
2251 # Send that to the switch
2252
Rich Lane9a003812012-10-04 17:17:59 -07002253 logging.info("Sending strict flow mod to switch:")
2254 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002255 fc2.send_rem = False
2256 self.assertTrue(sw.flow_mod(fc2, True), "Failed to modify flow")
2257 ft.insert(fc2)
2258
2259 # Do barrier, to make sure all flows are in
2260
2261 self.assertTrue(sw.barrier(), "Barrier failed")
2262
2263 result = True
2264
Howard Persh9cab4822012-09-11 17:08:40 -07002265 sw.settle() # Allow switch to settle and generate any notifications
2266
rootf6af1672012-04-06 09:46:29 -07002267 # Check for any error messages
2268
2269 if not sw.errors_verify(0):
2270 result = False
2271
2272 # Verify flow table
2273
2274 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002275 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002276 result = False
2277
2278 self.assertTrue(result, "Flow_Mod_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002279 logging.info("Flow_Mod_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002280
Howard Persh07d99e62012-04-09 15:26:57 -07002281
2282# FLOW MODIFY 2
2283#
2284# OVERVIEW
2285# Loose modify of mutiple flows
2286#
2287# PURPOSE
2288# - Verify that loose flow modify operates only on matching flows
2289# - Verify that matching flows are correctly modified
2290#
2291# PARAMETERS
2292# Name: num_flows
2293# Type: number
2294# Description:
2295# Number of flows to define
2296# Default: 100
2297#
2298# PROCESS
2299# 1. Delete all flows from switch
2300# 2. Generate <num_flows> distinct flow configurations
2301# 3. Send <num_flows> flow adds to switch
2302# 4. Pick 1 defined flow F at random
2303# 5. Create overlapping loose flow mod match criteria by repeatedly
2304# wildcarding out qualifiers in match of F => F',
2305# and create new actions list A' for F'
2306# 6. Send loose flow modify for F' to switch
2307# 7. Verify flow table in swtich
2308# 8. Test PASSED iff all flows sent to switch in steps 3 and 6 above,
2309# are returned in step 7 above, each with correct (original or modified)
2310# action list;
2311# else test FAILED
rootf6af1672012-04-06 09:46:29 -07002312
Rich Laneb90a1c42012-10-05 09:16:05 -07002313class Flow_Mod_2(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002314 """
2315 Test FLOW_MOD_2 from draft top-half test plan
2316
2317 INPUTS
2318 None
2319 """
2320
2321 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002322 logging.info("Flow_Mod_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002323
Rich Lane2014f9b2012-10-05 15:29:40 -07002324 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002325
2326 # Clear all flows from switch
2327
Rich Lane9a003812012-10-04 17:17:59 -07002328 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002329 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002330
2331 # Get switch capabilites
2332
rootf6af1672012-04-06 09:46:29 -07002333 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002334 self.assertTrue(sw.connect(self.controller), \
2335 "Failed to connect to switch" \
2336 )
rootf6af1672012-04-06 09:46:29 -07002337
2338 # Dream up some flow information, i.e. space to chose from for
2339 # random flow parameter generation
2340
2341 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002342 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002343 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002344
2345 # Dream up some flows
2346
2347 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002348 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002349
2350 # Send flow table to switch
2351
Rich Lane9a003812012-10-04 17:17:59 -07002352 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002353 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002354 logging.info("Adding flow:")
2355 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002356 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2357
2358 # Do barrier, to make sure all flows are in
2359
2360 self.assertTrue(sw.barrier(), "Barrier failed")
2361
2362 result = True
2363
Howard Persh9cab4822012-09-11 17:08:40 -07002364 sw.settle() # Allow switch to settle and generate any notifications
2365
rootf6af1672012-04-06 09:46:29 -07002366 # Check for any error messages
2367
2368 if not sw.errors_verify(0):
2369 result = False
2370
2371 # Verify flow table
2372
2373 sw.flow_tbl = ft
2374 if not sw.flow_tbl_verify():
2375 result = False
2376
2377 # Pick a random flow as a basis
Howard Persh5f3c83f2012-04-13 09:57:10 -07002378
2379 mfc = copy.deepcopy((ft.values())[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002380 mfc.rand_mod(fi, \
2381 sw.sw_features.actions, \
2382 sw.valid_ports, \
2383 sw.valid_queues \
2384 )
rootf6af1672012-04-06 09:46:29 -07002385
2386 # Repeatedly wildcard qualifiers
2387
2388 for wi in shuffle(range(len(all_wildcards_list))):
2389 w = all_wildcards_list[wi]
2390 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2391 n = wildcard_get(mfc.match.wildcards, w)
2392 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002393 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, \
2394 w, \
2395 random.randint(n + 1, 32) \
2396 )
rootf6af1672012-04-06 09:46:29 -07002397 else:
2398 continue
2399 else:
2400 if wildcard_get(mfc.match.wildcards, w) == 0:
2401 mfc.match.wildcards = wildcard_set(mfc.match.wildcards, w, 1)
2402 else:
2403 continue
2404 mfc = mfc.canonical()
2405
2406 # Count the number of flows that would be modified
2407
2408 n = 0
2409 for fc in ft.values():
2410 if mfc.overlaps(fc, True) and not mfc.non_key_equal(fc):
2411 n = n + 1
2412
2413 # If more than 1, we found our loose delete flow spec
2414 if n > 1:
2415 break
2416
Rich Lane9a003812012-10-04 17:17:59 -07002417 logging.info("Modifying %d flows" % (n))
2418 logging.info("Sending flow mod to switch:")
2419 logging.info(str(mfc))
rootf6af1672012-04-06 09:46:29 -07002420 self.assertTrue(sw.flow_mod(mfc, False), "Failed to modify flow")
2421
2422 # Do barrier, to make sure all flows are in
2423 self.assertTrue(sw.barrier(), "Barrier failed")
2424
Howard Persh9cab4822012-09-11 17:08:40 -07002425 sw.settle() # Allow switch to settle and generate any notifications
2426
rootf6af1672012-04-06 09:46:29 -07002427 # Check for error message
2428
2429 if not sw.errors_verify(0):
2430 result = False
2431
2432 # Apply flow mod to local flow table
2433
2434 for fc in ft.values():
2435 if mfc.overlaps(fc, True):
root2843d2b2012-04-06 10:27:46 -07002436 fc.actions = mfc.actions
rootf6af1672012-04-06 09:46:29 -07002437
2438 # Verify flow table
2439
2440 sw.flow_tbl = ft
Howard Persh5f3c83f2012-04-13 09:57:10 -07002441 if not sw.flow_tbl_verify(True):
rootf6af1672012-04-06 09:46:29 -07002442 result = False
2443
2444 self.assertTrue(result, "Flow_Mod_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002445 logging.info("Flow_Mod_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002446
2447
Howard Persh07d99e62012-04-09 15:26:57 -07002448# FLOW MODIFY 3
2449
2450# OVERVIEW
2451# Strict modify of non-existent flow
2452#
2453# PURPOSE
2454# Verify that strict modify of a non-existent flow is equivalent to a flow add
2455#
2456# PARAMETERS
2457# None
2458#
2459# PROCESS
2460# 1. Delete all flows from switch
2461# 2. Send single flow mod, as strict modify, to switch
2462# 3. Verify flow table in switch
2463# 4. Test PASSED iff flow defined in step 2 above verified; else FAILED
2464
Rich Laneb90a1c42012-10-05 09:16:05 -07002465class Flow_Mod_3(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002466 """
2467 Test FLOW_MOD_3 from draft top-half test plan
2468
2469 INPUTS
2470 None
2471 """
2472
2473 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002474 logging.info("Flow_Mod_3 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002475
2476 # Clear all flows from switch
2477
Rich Lane9a003812012-10-04 17:17:59 -07002478 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002479 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002480
2481 # Get switch capabilites
2482
rootf6af1672012-04-06 09:46:29 -07002483 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002484 self.assertTrue(sw.connect(self.controller), \
2485 "Failed to connect to switch" \
2486 )
rootf6af1672012-04-06 09:46:29 -07002487
2488 # Dream up some flow information, i.e. space to chose from for
2489 # random flow parameter generation
2490
2491 fi = Flow_Info()
2492 fi.rand(10)
2493
2494 # Dream up a flow config
2495
2496 fc = Flow_Cfg()
2497 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002498 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002499 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002500 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002501 sw.valid_ports, \
2502 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002503 )
2504 fc = fc.canonical()
2505
2506 # Send it to the switch
2507
Rich Lane9a003812012-10-04 17:17:59 -07002508 logging.info("Sending flow mod to switch:")
2509 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002510 ft = Flow_Tbl()
2511 fc.send_rem = False
2512 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2513 ft.insert(fc)
2514
2515 # Do barrier, to make sure all flows are in
2516
2517 self.assertTrue(sw.barrier(), "Barrier failed")
2518
2519 result = True
2520
Howard Persh9cab4822012-09-11 17:08:40 -07002521 sw.settle() # Allow switch to settle and generate any notifications
2522
rootf6af1672012-04-06 09:46:29 -07002523 # Check for any error messages
2524
2525 if not sw.errors_verify(0):
2526 result = False
2527
2528 # Verify flow table
2529
2530 sw.flow_tbl = ft
2531 if not sw.flow_tbl_verify():
2532 result = False
2533
2534 self.assertTrue(result, "Flow_Mod_3 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002535 logging.info("Flow_Mod_3 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002536
2537
Howard Persh8d21c1f2012-04-20 15:57:29 -07002538# FLOW MODIFY 3_1
2539
2540# OVERVIEW
2541# No-op modify
2542#
2543# PURPOSE
2544# Verify that modify of a flow with new actions same as old ones operates correctly
2545#
2546# PARAMETERS
2547# None
2548#
2549# PROCESS
2550# 1. Delete all flows from switch
2551# 2. Send single flow mod, as strict modify, to switch
2552# 3. Verify flow table in switch
2553# 4. Send same flow mod, as strict modify, to switch
2554# 5. Verify flow table in switch
2555# 6. Test PASSED iff flow defined in step 2 and 4 above verified; else FAILED
2556
Rich Laneb90a1c42012-10-05 09:16:05 -07002557class Flow_Mod_3_1(base_tests.SimpleProtocol):
Howard Persh8d21c1f2012-04-20 15:57:29 -07002558 """
2559 Test FLOW_MOD_3_1 from draft top-half test plan
2560
2561 INPUTS
2562 None
2563 """
2564
2565 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002566 logging.info("Flow_Mod_3_1 TEST BEGIN")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002567
2568 # Clear all flows from switch
2569
Rich Lane9a003812012-10-04 17:17:59 -07002570 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002571 delete_all_flows(self.controller)
Howard Persh8d21c1f2012-04-20 15:57:29 -07002572
2573 # Get switch capabilites
2574
2575 sw = Switch()
2576 self.assertTrue(sw.connect(self.controller), \
2577 "Failed to connect to switch" \
2578 )
2579
2580 # Dream up some flow information, i.e. space to chose from for
2581 # random flow parameter generation
2582
2583 fi = Flow_Info()
2584 fi.rand(10)
2585
2586 # Dream up a flow config
2587
2588 fc = Flow_Cfg()
2589 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002590 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002591 sw.tbl_stats.entries[0].wildcards, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002592 sw.sw_features.actions, \
2593 sw.valid_ports, \
2594 sw.valid_queues \
2595 )
2596 fc = fc.canonical()
2597
2598 # Send it to the switch
2599
Rich Lane9a003812012-10-04 17:17:59 -07002600 logging.info("Sending flow mod to switch:")
2601 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002602 ft = Flow_Tbl()
2603 fc.send_rem = False
2604 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2605 ft.insert(fc)
2606
2607 # Do barrier, to make sure all flows are in
2608
2609 self.assertTrue(sw.barrier(), "Barrier failed")
2610
2611 result = True
2612
Howard Persh9cab4822012-09-11 17:08:40 -07002613 sw.settle() # Allow switch to settle and generate any notifications
2614
Howard Persh8d21c1f2012-04-20 15:57:29 -07002615 # Check for any error messages
2616
2617 if not sw.errors_verify(0):
2618 result = False
2619
2620 # Verify flow table
2621
2622 sw.flow_tbl = ft
2623 if not sw.flow_tbl_verify():
2624 result = False
2625
2626 # Send same flow to the switch again
2627
Rich Lane9a003812012-10-04 17:17:59 -07002628 logging.info("Sending flow mod to switch:")
2629 logging.info(str(fc))
Howard Persh8d21c1f2012-04-20 15:57:29 -07002630 self.assertTrue(sw.flow_mod(fc, True), "Failed to modify flows")
2631
2632 # Do barrier, to make sure all flows are in
2633
2634 self.assertTrue(sw.barrier(), "Barrier failed")
2635
Howard Persh9cab4822012-09-11 17:08:40 -07002636 sw.settle() # Allow switch to settle and generate any notifications
2637
Howard Persh8d21c1f2012-04-20 15:57:29 -07002638 # Check for any error messages
2639
2640 if not sw.errors_verify(0):
2641 result = False
2642
2643 # Verify flow table
2644
2645 if not sw.flow_tbl_verify():
2646 result = False
2647
2648 self.assertTrue(result, "Flow_Mod_3_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002649 logging.info("Flow_Mod_3_1 TEST PASSED")
Howard Persh8d21c1f2012-04-20 15:57:29 -07002650
2651
Howard Persh07d99e62012-04-09 15:26:57 -07002652# FLOW DELETE 1
2653#
2654# OVERVIEW
2655# Strict delete of single flow
2656#
2657# PURPOSE
2658# Verify correct operation of strict delete of single defined flow
2659#
2660# PARAMETERS
2661# None
2662#
2663# PROCESS
2664# 1. Delete all flows from switch
2665# 2. Send flow F to switch
2666# 3. Send strict flow delete for F to switch
2667# 4. Verify flow table in swtich
2668# 6. Test PASSED iff all flows sent to switch in step 2 above,
2669# less flow removed in step 3 above, are returned in step 4 above;
2670# else test FAILED
2671
Rich Laneb90a1c42012-10-05 09:16:05 -07002672class Flow_Del_1(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002673 """
2674 Test FLOW_DEL_1 from draft top-half test plan
2675
2676 INPUTS
2677 None
2678 """
2679
2680 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002681 logging.info("Flow_Del_1 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002682
2683 # Clear all flows from switch
2684
Rich Lane9a003812012-10-04 17:17:59 -07002685 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002686 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002687
2688 # Get switch capabilites
2689
rootf6af1672012-04-06 09:46:29 -07002690 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002691 self.assertTrue(sw.connect(self.controller), \
2692 "Failed to connect to switch" \
2693 )
rootf6af1672012-04-06 09:46:29 -07002694
2695 # Dream up some flow information, i.e. space to chose from for
2696 # random flow parameter generation
2697
2698 fi = Flow_Info()
2699 fi.rand(10)
2700
2701 # Dream up a flow config
2702
2703 fc = Flow_Cfg()
2704 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002705 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002706 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002707 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002708 sw.valid_ports, \
2709 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002710 )
2711 fc = fc.canonical()
2712
2713 # Send it to the switch
2714
Rich Lane9a003812012-10-04 17:17:59 -07002715 logging.info("Sending flow add to switch:")
2716 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002717 ft = Flow_Tbl()
2718 fc.send_rem = False
2719 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2720 ft.insert(fc)
2721
2722 # Dream up some different actions, with the same flow key
2723
2724 fc2 = copy.deepcopy(fc)
2725 while True:
2726 fc2.rand_mod(fi, \
2727 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002728 sw.valid_ports, \
2729 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002730 )
2731 if fc2 != fc:
2732 break
2733
2734 # Delete strictly
2735
Rich Lane9a003812012-10-04 17:17:59 -07002736 logging.info("Sending strict flow del to switch:")
2737 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07002738 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
2739 ft.delete(fc)
2740
2741 # Do barrier, to make sure all flows are in
2742
2743 self.assertTrue(sw.barrier(), "Barrier failed")
2744
2745 result = True
2746
Howard Persh9cab4822012-09-11 17:08:40 -07002747 sw.settle() # Allow switch to settle and generate any notifications
2748
rootf6af1672012-04-06 09:46:29 -07002749 # Check for any error messages
2750
2751 if not sw.errors_verify(0):
2752 result = False
2753
2754 # Verify flow table
2755
2756 sw.flow_tbl = ft
2757 if not sw.flow_tbl_verify():
2758 result = False
2759
2760 self.assertTrue(result, "Flow_Del_1 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002761 logging.info("Flow_Del_1 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002762
2763
Howard Persh07d99e62012-04-09 15:26:57 -07002764# FLOW DELETE 2
2765#
2766# OVERVIEW
2767# Loose delete of multiple flows
2768#
2769# PURPOSE
2770# - Verify correct operation of loose delete of multiple flows
2771#
2772# PARAMETERS
2773# Name: num_flows
2774# Type: number
2775# Description:
2776# Number of flows to define
2777# Default: 100
2778#
2779# PROCESS
2780# 1. Delete all flows from switch
2781# 2. Generate <num_flows> distinct flow configurations
2782# 3. Send <num_flows> flow adds to switch, for flows generated in step 2 above
2783# 4. Pick 1 defined flow F at random
2784# 5. Repeatedly wildcard out qualifiers in match of F, creating F', such that
2785# F' will match more than 1 existing flow key
2786# 6. Send loose flow delete for F' to switch
2787# 7. Verify flow table in switch
2788# 8. Test PASSED iff all flows sent to switch in step 3 above, less flows
2789# removed in step 6 above (i.e. those that match F'), are returned
2790# in step 7 above;
2791# else test FAILED
2792
Rich Laneb90a1c42012-10-05 09:16:05 -07002793class Flow_Del_2(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002794 """
2795 Test FLOW_DEL_2 from draft top-half test plan
2796
2797 INPUTS
2798 None
2799 """
2800
2801 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002802 logging.info("Flow_Del_2 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002803
Rich Lane2014f9b2012-10-05 15:29:40 -07002804 num_flows = test_param_get("num_flows", 100)
rootf6af1672012-04-06 09:46:29 -07002805
2806 # Clear all flows from switch
2807
Rich Lane9a003812012-10-04 17:17:59 -07002808 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002809 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002810
2811 # Get switch capabilites
2812
rootf6af1672012-04-06 09:46:29 -07002813 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002814 self.assertTrue(sw.connect(self.controller), \
2815 "Failed to connect to switch" \
2816 )
rootf6af1672012-04-06 09:46:29 -07002817
2818 # Dream up some flow information, i.e. space to chose from for
2819 # random flow parameter generation
2820
2821 fi = Flow_Info()
Howard Persh3340d452012-04-06 16:45:21 -07002822 # Shrunk, to increase chance of meta-matches
Howard Persh07d99e62012-04-09 15:26:57 -07002823 fi.rand(max(int(math.log(num_flows)) / 2, 1))
rootf6af1672012-04-06 09:46:29 -07002824
2825 # Dream up some flows
2826
2827 ft = Flow_Tbl()
Ed Swierk99a74de2012-08-22 06:40:54 -07002828 ft.rand(required_wildcards(self), sw, fi, num_flows)
rootf6af1672012-04-06 09:46:29 -07002829
2830 # Send flow table to switch
2831
Rich Lane9a003812012-10-04 17:17:59 -07002832 logging.info("Sending flow adds to switch")
rootf6af1672012-04-06 09:46:29 -07002833 for fc in ft.values(): # Randomizes order of sending
Rich Lane9a003812012-10-04 17:17:59 -07002834 logging.info("Adding flow:")
2835 logging.info(str(fc));
rootf6af1672012-04-06 09:46:29 -07002836 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2837
2838 # Do barrier, to make sure all flows are in
2839
2840 self.assertTrue(sw.barrier(), "Barrier failed")
2841
2842 result = True
2843
Howard Persh9cab4822012-09-11 17:08:40 -07002844 sw.settle() # Allow switch to settle and generate any notifications
2845
rootf6af1672012-04-06 09:46:29 -07002846 # Check for any error messages
2847
2848 if not sw.errors_verify(0):
2849 result = False
2850
2851 # Verify flow table
2852
2853 sw.flow_tbl = ft
2854 if not sw.flow_tbl_verify():
2855 result = False
2856
2857 # Pick a random flow as a basis
2858
2859 dfc = copy.deepcopy(ft.values()[0])
Howard Persh8d21c1f2012-04-20 15:57:29 -07002860 dfc.rand_mod(fi, \
2861 sw.sw_features.actions, \
2862 sw.valid_ports, \
2863 sw.valid_queues \
2864 )
rootf6af1672012-04-06 09:46:29 -07002865
2866 # Repeatedly wildcard qualifiers
2867
2868 for wi in shuffle(range(len(all_wildcards_list))):
2869 w = all_wildcards_list[wi]
2870 if w == ofp.OFPFW_NW_SRC_MASK or w == ofp.OFPFW_NW_DST_MASK:
2871 n = wildcard_get(dfc.match.wildcards, w)
2872 if n < 32:
Howard Persh3340d452012-04-06 16:45:21 -07002873 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, \
2874 w, \
2875 random.randint(n + 1, 32) \
2876 )
rootf6af1672012-04-06 09:46:29 -07002877 else:
2878 continue
2879 else:
2880 if wildcard_get(dfc.match.wildcards, w) == 0:
2881 dfc.match.wildcards = wildcard_set(dfc.match.wildcards, w, 1)
2882 else:
2883 continue
2884 dfc = dfc.canonical()
2885
2886 # Count the number of flows that would be deleted
2887
2888 n = 0
2889 for fc in ft.values():
2890 if dfc.overlaps(fc, True):
2891 n = n + 1
2892
2893 # If more than 1, we found our loose delete flow spec
2894 if n > 1:
2895 break
2896
Rich Lane9a003812012-10-04 17:17:59 -07002897 logging.info("Deleting %d flows" % (n))
2898 logging.info("Sending flow del to switch:")
2899 logging.info(str(dfc))
rootf6af1672012-04-06 09:46:29 -07002900 self.assertTrue(sw.flow_del(dfc, False), "Failed to delete flows")
2901
2902 # Do barrier, to make sure all flows are in
2903 self.assertTrue(sw.barrier(), "Barrier failed")
2904
Howard Persh9cab4822012-09-11 17:08:40 -07002905 sw.settle() # Allow switch to settle and generate any notifications
2906
rootf6af1672012-04-06 09:46:29 -07002907 # Check for error message
2908
2909 if not sw.errors_verify(0):
2910 result = False
2911
2912 # Apply flow mod to local flow table
2913
2914 for fc in ft.values():
2915 if dfc.overlaps(fc, True):
2916 ft.delete(fc)
2917
2918 # Verify flow table
2919
2920 sw.flow_tbl = ft
2921 if not sw.flow_tbl_verify():
2922 result = False
2923
2924 self.assertTrue(result, "Flow_Del_2 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07002925 logging.info("Flow_Del_2 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07002926
2927
Howard Persh07d99e62012-04-09 15:26:57 -07002928# FLOW DELETE 4
2929#
2930# OVERVIEW
2931# Flow removed messages
2932#
2933# PURPOSE
2934# Verify that switch generates OFPT_FLOW_REMOVED/OFPRR_DELETE response
2935# messages when deleting flows that were added with OFPFF_SEND_FLOW_REM flag
2936#
2937# PARAMETERS
2938# None
2939#
2940# PROCESS
2941# 1. Delete all flows from switch
2942# 2. Send flow add to switch, with OFPFF_SEND_FLOW_REM set
2943# 3. Send strict flow delete of flow to switch
2944# 4. Verify that OFPT_FLOW_REMOVED/OFPRR_DELETE message is received from switch
2945# 5. Verify flow table in switch
2946# 6. Test PASSED iff all flows sent to switch in step 2 above, less flow
2947# removed in step 3 above, are returned in step 5 above, and that
2948# asynch message was received; else test FAILED
2949
2950
Rich Laneb90a1c42012-10-05 09:16:05 -07002951class Flow_Del_4(base_tests.SimpleProtocol):
rootf6af1672012-04-06 09:46:29 -07002952 """
2953 Test FLOW_DEL_4 from draft top-half test plan
2954
2955 INPUTS
2956 None
2957 """
2958
2959 def runTest(self):
Rich Lane9a003812012-10-04 17:17:59 -07002960 logging.info("Flow_Del_4 TEST BEGIN")
rootf6af1672012-04-06 09:46:29 -07002961
2962 # Clear all flows from switch
2963
Rich Lane9a003812012-10-04 17:17:59 -07002964 logging.info("Deleting all flows from switch")
Rich Lane32bf9482013-01-03 17:26:30 -08002965 delete_all_flows(self.controller)
rootf6af1672012-04-06 09:46:29 -07002966
2967 # Get switch capabilites
2968
rootf6af1672012-04-06 09:46:29 -07002969 sw = Switch()
Howard Persh8d21c1f2012-04-20 15:57:29 -07002970 self.assertTrue(sw.connect(self.controller), \
2971 "Failed to connect to switch" \
2972 )
rootf6af1672012-04-06 09:46:29 -07002973
2974 # Dream up some flow information, i.e. space to chose from for
2975 # random flow parameter generation
2976
2977 fi = Flow_Info()
2978 fi.rand(10)
2979
2980 # Dream up a flow config
2981
2982 fc = Flow_Cfg()
2983 fc.rand(fi, \
Ed Swierk99a74de2012-08-22 06:40:54 -07002984 required_wildcards(self), \
Rich Lane5fd6faf2013-03-11 13:30:20 -07002985 sw.tbl_stats.entries[0].wildcards, \
rootf6af1672012-04-06 09:46:29 -07002986 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07002987 sw.valid_ports, \
2988 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07002989 )
2990 fc = fc.canonical()
2991
2992 # Send it to the switch. with "notify on removed"
2993
Rich Lane9a003812012-10-04 17:17:59 -07002994 logging.info("Sending flow add to switch:")
2995 logging.info(str(fc))
rootf6af1672012-04-06 09:46:29 -07002996 ft = Flow_Tbl()
2997 fc.send_rem = True
2998 self.assertTrue(sw.flow_add(fc), "Failed to add flow")
2999 ft.insert(fc)
3000
3001 # Dream up some different actions, with the same flow key
3002
3003 fc2 = copy.deepcopy(fc)
3004 while True:
3005 fc2.rand_mod(fi, \
3006 sw.sw_features.actions, \
Howard Persh8d21c1f2012-04-20 15:57:29 -07003007 sw.valid_ports, \
3008 sw.valid_queues \
rootf6af1672012-04-06 09:46:29 -07003009 )
3010 if fc2 != fc:
3011 break
3012
3013 # Delete strictly
3014
Rich Lane9a003812012-10-04 17:17:59 -07003015 logging.info("Sending strict flow del to switch:")
3016 logging.info(str(fc2))
rootf6af1672012-04-06 09:46:29 -07003017 self.assertTrue(sw.flow_del(fc2, True), "Failed to delete flow")
3018 ft.delete(fc)
3019
3020 # Do barrier, to make sure all flows are in
3021
3022 self.assertTrue(sw.barrier(), "Barrier failed")
3023
3024 result = True
3025
Howard Persh9cab4822012-09-11 17:08:40 -07003026 sw.settle() # Allow switch to settle and generate any notifications
3027
rootf6af1672012-04-06 09:46:29 -07003028 # Check for expected "removed" message
3029
Howard Persh3340d452012-04-06 16:45:21 -07003030 if not sw.errors_verify(0):
3031 result = False
3032
3033 if not sw.removed_verify(1):
rootf6af1672012-04-06 09:46:29 -07003034 result = False
3035
3036 # Verify flow table
3037
3038 sw.flow_tbl = ft
3039 if not sw.flow_tbl_verify():
3040 result = False
3041
3042 self.assertTrue(result, "Flow_Del_4 TEST FAILED")
Rich Lane9a003812012-10-04 17:17:59 -07003043 logging.info("Flow_Del_4 TEST PASSED")
rootf6af1672012-04-06 09:46:29 -07003044