blob: a09b88682aa062240e846068fa19631aa4930ed7 [file] [log] [blame]
Howard Pershc7963582012-03-29 10:02:59 -07001"""
2Flow query test case.
3
4Attempts to fill switch to capacity with randomized flows, and ensure that they all are read back correctly.
5"""
Howard Persh680b92a2012-03-31 13:34:35 -07006import math
Howard Pershc7963582012-03-29 10:02:59 -07007
8import logging
9
10import unittest
11import random
12
13import oftest.controller as controller
14import oftest.cstruct as ofp
15import oftest.message as message
16import oftest.dataplane as dataplane
17import oftest.action as action
18import oftest.action_list as action_list
19import oftest.parse as parse
20import pktact
21import basic
22
23from testutils import *
24from time import sleep
25
26#@var port_map Local copy of the configuration map from OF port
27# numbers to OS interfaces
28pa_port_map = None
29#@var pa_logger Local logger object
30pa_logger = None
31#@var pa_config Local copy of global configuration data
32pa_config = None
33
34def test_set_init(config):
35 """
36 Set up function for packet action test classes
37
38 @param config The configuration dictionary; see oft
39 """
40
41 basic.test_set_init(config)
42
43 global pa_port_map
44 global pa_logger
45 global pa_config
46
47 pa_logger = logging.getLogger("pkt_act")
48 pa_logger.info("Initializing test set")
49 pa_port_map = config["port_map"]
50 pa_config = config
51
52
53def shuffle(list):
54 n = len(list)
55 lim = n * n
56 i = 0
57 while i < lim:
58 a = random.randint(0, n - 1)
59 b = random.randint(0, n - 1)
60 temp = list[a]
61 list[a] = list[b]
62 list[b] = temp
63 i = i + 1
64 return list
65
66
Howard Persh680b92a2012-03-31 13:34:35 -070067def rand_pick(list):
68 return list[random.randint(0, len(list) - 1)]
Howard Pershc7963582012-03-29 10:02:59 -070069
Howard Persh680b92a2012-03-31 13:34:35 -070070def rand_dl_addr():
71 return [random.randint(0, 255) & ~1,
72 random.randint(0, 255),
73 random.randint(0, 255),
74 random.randint(0, 255),
75 random.randint(0, 255),
76 random.randint(0, 255)
77 ]
Howard Pershc7963582012-03-29 10:02:59 -070078
79def rand_nw_addr():
80 return random.randint(0, (1 << 32) - 1)
81
82
Howard Persh680b92a2012-03-31 13:34:35 -070083class flow_info:
84 # Members:
85 # priorities - list of flow priorities
86 # dl_addrs - list of MAC addresses
87 # vlans - list of VLAN ids
88 # ethertypes - list of Ethertypes
89 # ip_addrs - list of IP addresses
90 # ip_tos - list of IP TOS values
91 # ip_protos - list of IP protocols
92 # l4_ports - list of L4 ports
93
94 def __init__(self):
95 priorities = []
96 dl_addrs = []
97 vlans = []
98 ethertypes = []
99 ip_addrs = []
100 ip_tos = []
101 ip_protos = []
102 l4_ports = []
103
104 def rand(self, n):
105 self.priorities = []
106 i = 0
107 while i < n:
108 self.priorities.append(random.randint(1, 65534))
109 i = i + 1
110
111 self.dl_addrs = []
112 i = 0
113 while i < n:
114 self.dl_addrs.append(rand_dl_addr())
115 i = i + 1
116
117 self.vlans = []
118 i = 0
119 while i < n:
120 self.vlans.append(random.randint(1, 4094))
121 i = i + 1
122
123 self.ethertypes = []
124 i = 0
125 while i < n:
126 self.ethertypes.append(random.randint(0, (1 << 16) - 1))
127 i = i + 1
128
129 self.ip_addrs = []
130 i = 0
131 while i < n:
132 self.ip_addrs.append(rand_nw_addr())
133 i = i + 1
134
135 self.ip_tos = []
136 i = 0
137 while i < n:
138 self.ip_tos.append(random.randint(0, (1 << 8) - 1) & ~3)
139 i = i + 1
140
141 self.ip_protos = []
142 i = 0
143 while i < n:
144 self.ip_protos.append(random.randint(0, (1 << 8) - 1))
145 i = i + 1
146
147 self.l4_ports = []
148 i = 0
149 while i < n:
150 self.l4_ports.append(random.randint(0, (1 << 16) - 1))
151 i = i + 1
152
153 def rand_priority(self):
154 return rand_pick(self.priorities)
155
156 def rand_dl_addr(self):
157 return rand_pick(self.dl_addrs)
158
159 def rand_vlan(self):
160 return rand_pick(self.vlans)
161
162 def rand_ethertype(self):
163 return rand_pick(self.ethertypes)
164
165 def rand_ip_addr(self):
166 return rand_pick(self.ip_addrs)
167
168 def rand_ip_tos(self):
169 return rand_pick(self.ip_tos)
170
171 def rand_ip_proto(self):
172 return rand_pick(self.ip_protos)
173
174 def rand_l4_port(self):
175 return rand_pick(self.l4_ports)
176
177
Howard Pershc7963582012-03-29 10:02:59 -0700178# TBD - These don't belong here
179
Howard Persh680b92a2012-03-31 13:34:35 -0700180all_wildcards_list = [ofp.OFPFW_IN_PORT,
181 ofp.OFPFW_DL_VLAN,
182 ofp.OFPFW_DL_SRC,
183 ofp.OFPFW_DL_DST,
184 ofp.OFPFW_DL_TYPE,
185 ofp.OFPFW_NW_PROTO,
186 ofp.OFPFW_TP_SRC,
187 ofp.OFPFW_TP_DST,
188 ofp.OFPFW_NW_SRC_MASK,
189 ofp.OFPFW_NW_DST_MASK,
190 ofp.OFPFW_DL_VLAN_PCP,
191 ofp.OFPFW_NW_TOS
192 ]
Howard Pershc7963582012-03-29 10:02:59 -0700193
Howard Pershc7963582012-03-29 10:02:59 -0700194
Howard Persh680b92a2012-03-31 13:34:35 -0700195all_actions_list = [ofp.OFPAT_OUTPUT,
196 ofp.OFPAT_SET_VLAN_VID,
197 ofp.OFPAT_SET_VLAN_PCP,
198 ofp.OFPAT_STRIP_VLAN,
199 ofp.OFPAT_SET_DL_SRC,
200 ofp.OFPAT_SET_DL_DST,
201 ofp.OFPAT_SET_NW_SRC,
202 ofp.OFPAT_SET_NW_DST,
203 ofp.OFPAT_SET_NW_TOS,
204 ofp.OFPAT_SET_TP_SRC,
205 ofp.OFPAT_SET_TP_DST,
206 ofp.OFPAT_ENQUEUE
207 ]
208
209def dl_addr_to_str(a):
210 return "%x:%x:%x:%x:%x:%x" % tuple(a)
211
212def ip_addr_to_str(a, n):
213 result = "%d.%d.%d.%d" % (a >> 24, \
214 (a >> 16) & 0xff, \
215 (a >> 8) & 0xff, \
216 a & 0xff \
217 )
218 if n is not None:
219 result = result + ("/%d" % (n))
220 return result
221
Howard Pershc7963582012-03-29 10:02:59 -0700222
223class flow_cfg:
224 # Members:
225 # - match
226 # - idle_timeout
227 # - hard_timeout
228 # - priority
229 # - action_list
230
231 def __init__(self):
Howard Persh680b92a2012-03-31 13:34:35 -0700232 self.priority = 0
Howard Pershc7963582012-03-29 10:02:59 -0700233 self.match = parse.ofp_match()
234 self.match.wildcards = ofp.OFPFW_ALL
235 self.idle_timeout = 0
236 self.hard_timeout = 0
Howard Pershc7963582012-03-29 10:02:59 -0700237 self.actions = action_list.action_list()
238
239 def __eq__(self, x):
Howard Persh680b92a2012-03-31 13:34:35 -0700240 if self.priority != x.priority:
241 return False
242 # TBD - Should this logic be moved to ofp_match.__eq__()?
243 if self.match.wildcards != x.match.wildcards:
244 return False
245 if (self.match.wildcards & ofp.OFPFW_IN_PORT) == 0 \
246 and self.match.in_port != x.match.in_port:
247 return False
248 if (self.match.wildcards & ofp.OFPFW_DL_SRC) == 0 \
249 and self.match.dl_src != x.match.dl_src:
250 return False
251 if (self.match.wildcards & ofp.OFPFW_DL_DST) == 0 \
252 and self.match.dl_dst != x.match.dl_dst:
253 return False
254 if (self.match.wildcards & ofp.OFPFW_DL_VLAN) == 0 \
255 and self.match.dl_vlan != x.match.dl_vlan:
256 return False
257 if (self.match.wildcards & ofp.OFPFW_DL_VLAN_PCP) == 0 \
258 and self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
259 return False
260 if (self.match.wildcards & ofp.OFPFW_DL_TYPE) == 0 \
261 and self.match.dl_type != x.match.dl_type:
262 return False
263 if (self.match.wildcards & ofp.OFPFW_NW_TOS) == 0 \
264 and self.match.nw_tos != x.match.nw_tos:
265 return False
266 if (self.match.wildcards & ofp.OFPFW_NW_PROTO) == 0 \
267 and self.match.nw_proto != x.match.nw_proto:
268 return False
269 if (self.match.wildcards & ofp.OFPFW_NW_SRC_MASK) \
270 < ofp.OFPFW_NW_SRC_ALL:
271 m = ~((1 << ((self.match.wildcards & ofp.OFPFW_NW_SRC_MASK) \
272 >> ofp.OFPFW_NW_SRC_SHIFT)) - 1)
273 if (self.match.nw_src & m) != (x.match.nw_src & m):
274 return False
275 if (self.match.wildcards & ofp.OFPFW_NW_DST_MASK) \
276 < ofp.OFPFW_NW_DST_ALL:
277 m = ~((1 << ((self.match.wildcards & ofp.OFPFW_NW_DST_MASK) \
278 >> ofp.OFPFW_NW_DST_SHIFT)) - 1)
279 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
280 return False
281 if (self.match.wildcards & ofp.OFPFW_TP_SRC) == 0 \
282 and self.match.tp_src != x.match.tp_src:
283 return False
284 if (self.match.wildcards & ofp.OFPFW_TP_DST) == 0 \
285 and self.match.tp_dst != x.match.tp_dst:
Howard Pershc7963582012-03-29 10:02:59 -0700286 return False
287 if self.idle_timeout != x.idle_timeout:
288 return False
289 if self.hard_timeout != x.hard_timeout:
290 return False
Howard Pershc7963582012-03-29 10:02:59 -0700291 return self.actions == x.actions # N.B. Action lists are ordered
292
Howard Persh680b92a2012-03-31 13:34:35 -0700293 def __str__(self):
294 result = "priority=%d" % self.priority
295 # TBD - Would be nice if ofp_match.show() was better behaved
296 # (no newlines), and more intuitive (things in hex where approprate), etc.
297 result = result + ", wildcards={"
298 sep = ""
299 for w in ofp.ofp_flow_wildcards_map:
300 if w == ofp.OFPFW_NW_SRC_SHIFT \
301 or w == ofp.OFPFW_NW_SRC_BITS \
302 or w == ofp.OFPFW_NW_SRC_ALL \
303 or w == ofp.OFPFW_NW_DST_SHIFT \
304 or w == ofp.OFPFW_NW_DST_BITS \
305 or w == ofp.OFPFW_NW_DST_ALL \
306 or w == ofp.OFPFW_ALL \
307 or self.match.wildcards & w == 0:
308 continue
309 if w == ofp.OFPFW_NW_SRC_MASK:
310 result = result + sep + "OFPFW_NW_SRC"
311 elif w == ofp.OFPFW_NW_DST_MASK:
312 result = result + sep + "OFPFW_NW_DST"
313 else:
314 result = result + sep + ofp.ofp_flow_wildcards_map[w]
315 sep = ", "
316 result = result +"}"
317 if (self.match.wildcards & ofp.OFPFW_IN_PORT) == 0:
318 result = result + (", in_port=%d" % (self.match.in_port))
319 if (self.match.wildcards & ofp.OFPFW_DL_SRC) == 0:
320 result = result + (", dl_src=%s" % (dl_addr_to_str(self.match.dl_src)))
321 if (self.match.wildcards & ofp.OFPFW_DL_DST) == 0:
322 result = result + (", dl_dst=%s" % (dl_addr_to_str(self.match.dl_dst)))
323 if (self.match.wildcards & ofp.OFPFW_DL_VLAN) == 0:
324 result = result + (", dl_vlan=%d" % (self.match.dl_vlan))
325 if (self.match.wildcards & ofp.OFPFW_DL_VLAN_PCP) == 0:
326 result = result + (", dl_vlan_pcp=%d" % (self.match.dl_vlan_pcp))
327 if (self.match.wildcards & ofp.OFPFW_DL_TYPE) == 0:
328 result = result + (", dl_type=0x%x" % (self.match.dl_type))
329 if (self.match.wildcards & ofp.OFPFW_NW_TOS) == 0:
330 result = result + (", nw_tos=0x%x" % (self.match.nw_tos))
331 if (self.match.wildcards & ofp.OFPFW_NW_PROTO) == 0:
332 result = result + (", nw_proto=%d" % (self.match.nw_proto))
333 n = (self.match.wildcards & ofp.OFPFW_NW_SRC_MASK) >> ofp.OFPFW_NW_SRC_SHIFT
334 if n < 32:
335 result = result + (", nw_src=%s" % (ip_addr_to_str(self.match.nw_src, n)))
336 n = (self.match.wildcards & ofp.OFPFW_NW_DST_MASK) >> ofp.OFPFW_NW_DST_SHIFT
337 if n < 32:
338 result = result + (", nw_dst=%s" % (ip_addr_to_str(self.match.nw_dst, n)))
339 if (self.match.wildcards & ofp.OFPFW_TP_SRC) == 0:
340 result = result + (", tp_src=%d" % self.match.tp_src)
341 if (self.match.wildcards & ofp.OFPFW_TP_DST) == 0:
342 result = result + (", tp_dst=%d" % self.match.tp_dst)
343 result = result + (", idle_timeout=%d" % self.idle_timeout)
344 result = result + (", hard_timeout=%d" % self.hard_timeout)
345 result = result + (", hard_timeout=%d" % self.hard_timeout)
346 for a in self.actions.actions:
347 result = result + (", action=%s" % ofp.ofp_action_type_map[a.type])
348 if a.type == ofp.OFPAT_OUTPUT:
349 result = result + ("(%d)" % (a.port))
350 elif a.type == ofp.OFPAT_SET_VLAN_VID:
351 result = result + ("(%d)" % (a.vlan_vid))
352 elif a.type == ofp.OFPAT_SET_VLAN_PCP:
353 result = result + ("(%d)" % (a.vlan_pcp))
354 elif a.type == ofp.OFPAT_SET_DL_SRC or a.type == ofp.OFPAT_SET_DL_DST:
355 result = result + ("(%s)" % (dl_addr_to_str(a.dl_addr)))
356 elif a.type == ofp.OFPAT_SET_NW_SRC or a.type == ofp.OFPAT_SET_NW_DST:
357 result = result + ("(%s)" % (ip_addr_to_str(a.nw_addr, None)))
358 elif a.type == ofp.OFPAT_SET_NW_TOS:
359 result = result + ("(0x%x)" % (a.nw_tos))
360 elif a.type == ofp.OFPAT_SET_TP_SRC or a.type == ofp.OFPAT_SET_TP_DST:
361 result = result + ("(%d)" % (a.tp_port))
362 elif a.type == ofp.OFPAT_ENQUEUE:
363 result = result + ("(port=%d,queue=%d)" % (a.port, a.queue_id))
364 return result
Howard Pershc7963582012-03-29 10:02:59 -0700365
Howard Persh680b92a2012-03-31 13:34:35 -0700366 def rand(self, fi, valid_wildcards, valid_actions, valid_ports):
367 # Start with no wildcards, i.e. everything specified
368 self.match.wildcards = 0
369
370 # Make approx. 1% of flows exact
Howard Pershc7963582012-03-29 10:02:59 -0700371 exact = True if random.randint(1, 100) == 1 else False
372
Howard Persh680b92a2012-03-31 13:34:35 -0700373 # For each qualifier Q,
374 # if (wildcarding is not supported for Q,
375 # or an exact flow is specified
376 # or a coin toss comes up heads),
377 # specify Q
378 # else
379 # wildcard Q
Howard Pershc7963582012-03-29 10:02:59 -0700380
Howard Persh680b92a2012-03-31 13:34:35 -0700381 if (ofp.OFPFW_IN_PORT & valid_wildcards) == 0 \
382 or exact \
383 or random.randint(1, 100) <= 50:
384 self.match.in_port = rand_pick(valid_ports)
385 else:
386 self.match.wildcards = self.match.wildcards | ofp.OFPFW_IN_PORT
387
388 if (ofp.OFPFW_DL_DST & valid_wildcards) == 0 \
389 or exact \
390 or random.randint(1, 100) <= 50:
391 self.match.dl_dst = fi.rand_dl_addr()
392 else:
393 self.match.wildcards = self.match.wildcards | ofp.OFPFW_DL_DST
Howard Pershc7963582012-03-29 10:02:59 -0700394
Howard Persh680b92a2012-03-31 13:34:35 -0700395 if (ofp.OFPFW_DL_SRC & valid_wildcards) == 0 \
396 or exact \
397 or random.randint(1, 100) <= 50:
398 self.match.dl_src = fi.rand_dl_addr()
399 else:
400 self.match.wildcards = self.match.wildcards | ofp.OFPFW_DL_SRC
401
402 if (ofp.OFPFW_DL_VLAN_PCP & valid_wildcards) == 0 \
403 or exact \
404 or random.randint(1, 100) <= 50:
405 self.match.dl_vlan_pcp = random.randint(0, (1 << 3) - 1)
406 else:
407 self.match.wildcards = self.match.wildcards | ofp.OFPFW_DL_VLAN_PCP
408
409 if (ofp.OFPFW_DL_VLAN & valid_wildcards) == 0 \
410 or exact \
411 or random.randint(1, 100) <= 50:
412 self.match.dl_vlan = fi.rand_vlan()
413 else:
414 self.match.wildcards = self.match.wildcards | ofp.OFPFW_DL_VLAN
415
416 if (ofp.OFPFW_DL_TYPE & valid_wildcards) == 0 \
417 or exact \
418 or random.randint(1, 100) <= 50:
419 self.match.dl_type = fi.rand_ethertype()
420 else:
421 self.match.wildcards = self.match.wildcards | ofp.OFPFW_DL_TYPE
422
423 if exact:
424 n = 0
425 else:
426 n = (valid_wildcards & ofp.OFPFW_NW_SRC_MASK) \
427 >> ofp.OFPFW_NW_SRC_SHIFT
428 if n > 32:
429 n = 32
430 n = random.randint(0, n)
431 self.match.wildcards = self.match.wildcards \
432 | (n << ofp.OFPFW_NW_SRC_SHIFT)
433 if n < 32:
434 self.match.nw_src = fi.rand_ip_addr() & ~((1 << n) - 1)
435 # Specifying any IP address match other than all bits
436 # don't care requires that Ethertype is one of {IP, ARP}
437 self.match.dl_type = rand_pick([0x0800, 0x0806])
438 self.match.wildcards = self.match.wildcards & ~ofp.OFPFW_DL_TYPE
439
440 if exact:
441 n = 0
442 else:
443 n = (valid_wildcards & ofp.OFPFW_NW_DST_MASK) \
444 >> ofp.OFPFW_NW_DST_SHIFT
445 if n > 32:
446 n = 32
447 n = random.randint(0, n)
448 self.match.wildcards = self.match.wildcards \
449 | (n << ofp.OFPFW_NW_DST_SHIFT)
450 if n < 32:
451 self.match.nw_dst = fi.rand_ip_addr() & ~((1 << n) - 1)
452 # Specifying any IP address match other than all bits
453 # don't care requires that Ethertype is one of {IP, ARP}
454 self.match.dl_type = rand_pick([0x0800, 0x0806])
455 self.match.wildcards = self.match.wildcards & ~ofp.OFPFW_DL_TYPE
456
457 if (ofp.OFPFW_NW_TOS & valid_wildcards) == 0 \
458 or exact \
459 or random.randint(1, 100) <= 50:
460 self.match.nw_tos = fi.rand_ip_tos()
461 # Specifying a TOS value requires that Ethertype is IP
462 self.match.dl_type = 0x0800
463 self.match.wildcards = self.match.wildcards & ~ofp.OFPFW_DL_TYPE
464 else:
465 self.match.wildcards = self.match.wildcards | ofp.OFPFW_NW_TOS
466
467 if (ofp.OFPFW_NW_PROTO & valid_wildcards) == 0 \
468 or exact \
469 or random.randint(1, 100) <= 50:
470 self.match.nw_proto = fi.rand_ip_proto()
471 # Specifying an IP protocol requires that Ethertype is IP
472 self.match.dl_type = 0x0800
473 self.match.wildcards = self.match.wildcards & ~ofp.OFPFW_DL_TYPE
474 else:
475 self.match.wildcards = self.match.wildcards | ofp.OFPFW_NW_PROTO
476
477 if (ofp.OFPFW_TP_SRC & valid_wildcards) == 0 \
478 or exact\
479 or random.randint(1, 100) <= 50:
480 self.match.tp_src = fi.rand_l4_port()
481 # Specifying a L4 port requires that IP protcol is
482 # one of {ICMP, TCP, UDP}
483 self.match.nw_proto = rand_pick([1, 6, 17])
484 self.match.wildcards = self.match.wildcards & ~ofp.OFPFW_NW_PROTO
485 # Specifying a L4 port requirues that Ethertype is IP
486 self.match.dl_type = 0x0800
487 self.match.wildcards = self.match.wildcards & ~ofp.OFPFW_DL_TYPE
488 else:
489 self.match.wildcards = self.match.wildcards | ofp.OFPFW_TP_SRC
490
491 if (ofp.OFPFW_TP_DST & valid_wildcards) == 0 \
492 or exact \
493 or random.randint(1, 100) <= 50:
494 self.match.tp_dst = fi.rand_l4_port()
495 # Specifying a L4 port requires that IP protcol is
496 # one of {ICMP, TCP, UDP}
497 self.match.nw_proto = rand_pick([1, 6, 17])
498 self.match.wildcards = self.match.wildcards & ~ofp.OFPFW_NW_PROTO
499 # Specifying a L4 port requirues that Ethertype is IP
500 self.match.dl_type = 0x0800
501 self.match.wildcards = self.match.wildcards & ~ofp.OFPFW_DL_TYPE
502 else:
503 self.match.wildcards = self.match.wildcards | ofp.OFPFW_TP_DST
504
505 # N.B. Don't make the timeout too short, else the flow might
506 # disappear before we get a chance to check for it.
Howard Pershc7963582012-03-29 10:02:59 -0700507 t = random.randint(0, 65535)
508 self.idle_timeout = 0 if t < 60 else t
509 t = random.randint(0, 65535)
510 self.hard_timeout = 0 if t < 60 else t
Howard Pershc7963582012-03-29 10:02:59 -0700511
Howard Persh680b92a2012-03-31 13:34:35 -0700512 # If nothing is wildcarded, it is an exact flow spec -- some switches
513 # (Open vSwitch, for one) *require* that exact flow specs have priority 65535.
514 self.priority = 65535 if self.match.wildcards == 0 else fi.rand_priority()
Howard Pershc7963582012-03-29 10:02:59 -0700515
Howard Persh680b92a2012-03-31 13:34:35 -0700516 # Action lists are ordered, so pick an ordered random subset of
517 # supported actions
518 supported_actions = []
519 for a in all_actions_list:
520 if ((1 << a) & valid_actions) != 0:
521 supported_actions.append(a)
522
523 supported_actions = shuffle(supported_actions)
524 supported_actions \
525 = supported_actions[0 : random.randint(1, len(supported_actions))]
Howard Pershc7963582012-03-29 10:02:59 -0700526
527 self.actions = action_list.action_list()
Howard Persh680b92a2012-03-31 13:34:35 -0700528 for a in supported_actions:
Howard Pershc7963582012-03-29 10:02:59 -0700529 if a == ofp.OFPAT_OUTPUT:
530 # TBD - Output actions are clustered in list, spread them out?
531 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700532 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700533 for pi in port_idxs:
534 act = action.action_output()
Howard Persh680b92a2012-03-31 13:34:35 -0700535 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700536 self.actions.add(act)
537 elif a == ofp.OFPAT_SET_VLAN_VID:
538 act = action.action_set_vlan_vid()
Howard Persh680b92a2012-03-31 13:34:35 -0700539 act.vlan_vid = fi.rand_vlan()
Howard Pershc7963582012-03-29 10:02:59 -0700540 self.actions.add(act)
541 elif a == ofp.OFPAT_SET_VLAN_PCP:
542 # TBD - Temporaily removed, broken in Indigo
543 #act = action.action_set_vlan_pcp()
544 #act.vlan_pcp = random.randint(0, (1 << 3) - 1)
545 pass
546 elif a == ofp.OFPAT_STRIP_VLAN:
547 act = action.action_strip_vlan()
548 self.actions.add(act)
549 elif a == ofp.OFPAT_SET_DL_SRC:
550 act = action.action_set_dl_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700551 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700552 self.actions.add(act)
553 elif a == ofp.OFPAT_SET_DL_DST:
554 act = action.action_set_dl_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700555 act.dl_addr = fi.rand_dl_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700556 self.actions.add(act)
557 elif a == ofp.OFPAT_SET_NW_SRC:
558 act = action.action_set_nw_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700559 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700560 self.actions.add(act)
561 elif a == ofp.OFPAT_SET_NW_DST:
562 act = action.action_set_nw_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700563 act.nw_addr = fi.rand_ip_addr()
Howard Pershc7963582012-03-29 10:02:59 -0700564 self.actions.add(act)
565 elif a == ofp.OFPAT_SET_NW_TOS:
566 act = action.action_set_nw_tos()
Howard Persh680b92a2012-03-31 13:34:35 -0700567 act.nw_tos = fi.rand_ip_tos()
Howard Pershc7963582012-03-29 10:02:59 -0700568 self.actions.add(act)
569 elif a == ofp.OFPAT_SET_TP_SRC:
570 act = action.action_set_tp_src()
Howard Persh680b92a2012-03-31 13:34:35 -0700571 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700572 self.actions.add(act)
573 elif a == ofp.OFPAT_SET_TP_DST:
574 act = action.action_set_tp_dst()
Howard Persh680b92a2012-03-31 13:34:35 -0700575 act.tp_port = fi.rand_l4_port()
Howard Pershc7963582012-03-29 10:02:59 -0700576 self.actions.add(act)
577 elif a == ofp.OFPAT_ENQUEUE:
578 # TBD - Enqueue actions are clustered in list, spread them out?
579 port_idxs = shuffle(range(len(valid_ports)))
Howard Persh680b92a2012-03-31 13:34:35 -0700580 port_idxs = port_idxs[0 : random.randint(1, len(valid_ports))]
Howard Pershc7963582012-03-29 10:02:59 -0700581 for pi in port_idxs:
582 act = action.action_enqueue()
Howard Persh680b92a2012-03-31 13:34:35 -0700583 act.port = valid_ports[pi]
Howard Pershc7963582012-03-29 10:02:59 -0700584 # TBD - Limits for queue number?
585 act.queue_id = random.randint(0, 7)
586 self.actions.add(act)
587
588 return self
589
Howard Persh680b92a2012-03-31 13:34:35 -0700590 # Overlap check
591 # delf == True <=> Check for delete overlap, else add overlap
592 # "Add overlap" is defined as there exists a packet that could match both the
593 # receiver and argument flowspecs
594 # "Delete overlap" is defined as the specificity of the argument flowspec
595 # is greater than or equal to the specificity of the receiver flowspec
596 def overlaps(self, x, delf):
Howard Pershc7963582012-03-29 10:02:59 -0700597 if self.priority != x.priority:
598 return False
Howard Persh680b92a2012-03-31 13:34:35 -0700599 if (self.match.wildcards & ofp.OFPFW_IN_PORT) == 0:
600 if (x.match.wildcards & ofp.OFPFW_IN_PORT) == 0:
601 if self.match.in_port != x.match.in_port:
602 return False # Both specified, and not equal
603 elif delf:
604 return False # Receiver more specific
605 if (self.match.wildcards & ofp.OFPFW_DL_VLAN) == 0:
606 if (x.match.wildcards & ofp.OFPFW_DL_VLAN) == 0:
607 if self.match.dl_vlan != x.match.dl_vlan:
608 return False # Both specified, and not equal
609 elif delf:
610 return False # Receiver more specific
611 if (self.match.wildcards & ofp.OFPFW_DL_SRC) == 0:
612 if (x.match.wildcards & ofp.OFPFW_DL_SRC) == 0:
613 if self.match.dl_src != x.match.dl_src:
614 return False # Both specified, and not equal
615 elif delf:
616 return False # Receiver more specific
617 if (self.match.wildcards & ofp.OFPFW_DL_DST) == 0:
618 if (x.match.wildcards & ofp.OFPFW_DL_DST) == 0:
619 if self.match.dl_dst != x.match.dl_dst:
620 return False # Both specified, and not equal
621 elif delf:
622 return False # Receiver more specific
623 if (self.match.wildcards & ofp.OFPFW_DL_TYPE) == 0:
624 if (x.match.wildcards & ofp.OFPFW_DL_TYPE) == 0:
625 if self.match.dl_type != x.match.dl_type:
626 return False # Both specified, and not equal
627 elif delf:
628 return False # Recevier more specific
629 if (self.match.wildcards & ofp.OFPFW_NW_PROTO) == 0:
630 if (x.match.wildcards & ofp.OFPFW_NW_PROTO) == 0:
631 if self.match.nw_proto != x.match.nw_proto:
632 return False # Both specified, and not equal
633 elif delf:
634 return False # Receiver more specific
635 if (self.match.wildcards & ofp.OFPFW_TP_SRC) == 0:
636 if (x.match.wildcards & ofp.OFPFW_TP_SRC) == 0:
637 if self.match.tp_src != x.match.tp_src:
638 return False # Both specified, and not equal
639 elif delf:
640 return False # Receiver more specific
641 if (self.match.wildcards & ofp.OFPFW_TP_DST) == 0:
642 if (x.match.wildcards & ofp.OFPFW_TP_DST) == 0:
643 if self.match.tp_dst != x.match.tp_dst:
644 return False # Both specified, and not equal
645 elif delf:
646 return False # Receiver more specific
647 na = (self.match.wildcards & ofp.OFPFW_NW_SRC_MASK) \
648 >> ofp.OFPFW_NW_SRC_SHIFT
649 nb = (x.match.wildcards & ofp.OFPFW_NW_SRC_MASK) \
650 >> ofp.OFPFW_NW_SRC_SHIFT
651 if delf and na < nb:
652 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -0700653 if (na < 32 and nb < 32):
654 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
655 if (self.match.nw_src & m) != (x.match.nw_src & m):
Howard Persh680b92a2012-03-31 13:34:35 -0700656 return False # Overlapping bits not equal
657 na = (self.match.wildcards & ofp.OFPFW_NW_DST_MASK) \
658 >> ofp.OFPFW_NW_DST_SHIFT
659 nb = (x.match.wildcards & ofp.OFPFW_NW_DST_MASK) \
660 >> ofp.OFPFW_NW_DST_SHIFT
661 if delf and na < nb:
662 return False # Receiver more specific
Howard Pershc7963582012-03-29 10:02:59 -0700663 if (na < 32 and nb < 32):
664 m = ~((1 << na) - 1) & ~((1 << nb) - 1)
665 if (self.match.nw_dst & m) != (x.match.nw_dst & m):
Howard Persh680b92a2012-03-31 13:34:35 -0700666 return False # Overlapping bit not equal
667 if (self.match.wildcards & ofp.OFPFW_DL_VLAN_PCP) == 0:
668 if (x.match.wildcards & ofp.OFPFW_DL_VLAN_PCP) == 0:
669 if self.match.dl_vlan_pcp != x.match.dl_vlan_pcp:
670 return False # Both specified, and not equal
671 elif delf:
672 return False # Receiver more specific
673 if (self.match.wildcards & ofp.OFPFW_NW_TOS) == 0:
674 if (x.match.wildcards & ofp.OFPFW_NW_TOS) == 0:
675 if self.match.nw_tos != x.match.nw_tos:
676 return False # Both specified, and not equal
677 elif delf:
678 return False # Receiver more specific
679 return True # Flows overlap
Howard Pershc7963582012-03-29 10:02:59 -0700680
681 def to_flow_mod_msg(self, msg):
682 msg.match = self.match
683 msg.idle_timeout = self.idle_timeout
684 msg.hard_timeout = self.hard_timeout
685 msg.priority = self.priority
686 msg.actions = self.actions
687 return msg
688
689 def from_flow_stat(self, msg):
690 self.match = msg.match
691 self.idle_timeout = msg.idle_timeout
692 self.hard_timeout = msg.hard_timeout
693 self.priority = msg.priority
694 self.actions = msg.actions
695
696
697class FlowQuery(basic.SimpleProtocol):
698 """
699 """
700
Howard Persh680b92a2012-03-31 13:34:35 -0700701 def do_barrier(self):
702 barrier = message.barrier_request()
703 (resp, pkt) = self.controller.transact(barrier, 5)
704 self.assertTrue(resp is not None,
705 "Did not receive response to barrier request"
706 )
707
708
709 def verify_flows(self,
710 sw_features,
711 tbl_flows,
712 num_flows,
713 overlapf,
714 num_overlaps
715 ):
716 result = True
717
718 # Check number of flows reported in table stats
719
720 self.logger.debug("Verifying table stats reports correct number of")
721 self.logger.debug(" active flows")
722 request = message.table_stats_request()
723 (tbl_stats_after, pkt) = self.controller.transact(request, timeout=2)
724 self.assertTrue(tbl_stats_after is not None,
725 "No reply to table_stats_request"
726 )
727
728 num_flows_reported = 0
729 for ts in tbl_stats_after.stats:
730 num_flows_reported = num_flows_reported + ts.active_count
731
732 num_flows_expected = num_flows
733 if overlapf:
734 num_flows_expected = num_flows_expected - num_overlaps
735
736 self.logger.debug("Number of flows reported = "
737 + str(num_flows_reported)
738 )
739 self.logger.debug("Numer of flows expected = "
740 + str(num_flows_expected)
741 )
742 if num_flows_reported != num_flows_expected:
743 self.logger.error("Incorrect number of flows returned by table stats")
744 result = False
745
746 # Retrieve all flows from switch
747
748 self.logger.debug("Retrieving all flows from switch")
749 stat_req = message.flow_stats_request()
750 query_match = ofp.ofp_match()
751 query_match.wildcards = ofp.OFPFW_ALL
752 stat_req.match = query_match
753 stat_req.table_id = 0xff
754 stat_req.out_port = ofp.OFPP_NONE;
755 flow_stats, pkt = self.controller.transact(stat_req, timeout=2)
756 self.assertTrue(flow_stats is not None, "Get all flow stats failed")
757
758 # Verify retrieved flows
759
760 self.logger.debug("Verifying retrieved flows")
761
762 self.assertEqual(flow_stats.type,
763 ofp.OFPST_FLOW,
764 "Unexpected type of response message"
765 )
766
767 num_flows_reported = len(flow_stats.stats)
768
769 self.logger.debug("Number of flows reported = "
770 + str(num_flows_reported)
771 )
772 self.logger.debug("Numer of flows expected = "
773 + str(num_flows_expected)
774 )
775 if num_flows_reported != num_flows_expected:
776 self.logger.error("Incorrect number of flows returned by table stats")
777 result = False
778
779 for f in tbl_flows:
780 f.resp_matched = False
781
782 num_resp_flows_matched = 0
783 for flow_stat in flow_stats.stats:
784 flow_in = flow_cfg()
785 flow_in.from_flow_stat(flow_stat)
786
787 matched = False
788 for f in tbl_flows:
789 if f.deleted:
790 continue
791 if not f.resp_matched \
792 and (not overlapf or not f.overlap) \
793 and f == flow_in:
794 f.resp_matched = True
795 num_resp_flows_matched = num_resp_flows_matched + 1
796 matched = True
797 break
798 if not matched:
799 self.logger.error("Response flow")
800 self.logger.error(str(flow_in))
801 self.logger.error("does not match any configured flow")
802 result = False
803
804 self.logger.debug("Number of flows matched in response = "
805 + str(num_resp_flows_matched)
806 )
807 self.logger.debug("Number of flows expected = "
808 + str(num_flows_expected)
809 )
810 if num_resp_flows_matched != num_flows_expected:
811 for f in tbl_flows:
812 if not f.resp_matched:
813 self.logger.error("Configured flow")
814 self.logger.error("tbl_idx=%d, flow_idx=%d, %s" % (f.tbl_idx, f.flow_idx, str(f)))
815 self.logger.error("missing in flow response")
816 result = False
817
818 self.assertTrue(result, "Flow verification failed")
819
820 def flow_add(self, flow, overlapf):
821 flow_mod_msg = message.flow_mod()
822 flow_mod_msg.command = ofp.OFPFC_ADD
823 flow_mod_msg.buffer_id = 0xffffffff
824 flow_mod_msg.cookie = random.randint(0, (1 << 53) - 1)
825 flow.to_flow_mod_msg(flow_mod_msg)
826 if overlapf:
827 flow_mod_msg.flags = flow_mod_msg.flags | ofp.OFPFF_CHECK_OVERLAP
828 self.logger.debug("Sending flow_mod(add) request to switch")
829 rv = self.controller.message_send(flow_mod_msg)
830 self.assertTrue(rv != -1, "Error installing flow mod")
831
832 # TBD - Don't poll for each error message
833 if flow.overlap:
834 self.logger.debug("Flow overlaps with tbl_idx=%d flow_idx=%d"
835 % (flow.overlaps_with[0], flow.overlaps_with[1])
836 )
837 else:
838 self.logger.debug("Flow does not overlap")
839 self.logger.debug("Checking for error response from switch")
840 (errmsg, pkt) = self.controller.poll(ofp.OFPT_ERROR, 1)
841 if errmsg is not None:
842 # Got ERROR message
843 self.logger.debug("Got ERROR message, type = "
844 + str(errmsg.type)
845 + ", code = "
846 + str(errmsg.code)
847 )
848
849 if errmsg.type == ofp.OFPET_FLOW_MOD_FAILED \
850 and errmsg.code == ofp.OFPFMFC_OVERLAP:
851 # Got "overlap" ERROR message
852 self.logger.debug("ERROR is overlap")
853
854 self.assertTrue(overlapf and flow.overlap,
855 "Overlap not expected"
856 )
857 else:
858 self.logger.debug("ERROR is not overlap")
859 self.assertTrue(False,
860 "Unexpected error message")
861
862 else:
863 # Did not get ERROR message
864 self.logger.debug("No ERROR message received")
865 self.assertTrue(not (overlapf and flow.overlap),
866 "Did not get expected OVERLAP"
867 )
868
869
870 def flow_del(self, flow, strictf):
871 flow_mod_msg = message.flow_mod()
872 flow_mod_msg.command = ofp.OFPFC_DELETE_STRICT \
873 if strictf else ofp.OFPFC_DELETE
874 flow_mod_msg.buffer_id = 0xffffffff
875 flow_mod_msg.cookie = random.randint(0, (1 << 53) - 1)
876 # TBD - Needs to be a test variable
877 flow_mod_msg.out_port = ofp.OFPP_NONE
878 flow.to_flow_mod_msg(flow_mod_msg)
879 rv = self.controller.message_send(flow_mod_msg)
880 self.assertTrue(rv != -1, "Error installing flow mod")
881 # TBD - Don't poll for each error message
882 (errmsg, pkt) = self.controller.poll(ofp.OFPT_ERROR, 1)
883 if errmsg is not None:
884 # Got ERROR message
885 self.logger.debug("Got ERROR message, type = "
886 + str(errmsg.type)
887 + ", code = "
888 + str(errmsg.code)
889 )
890 self.assertTrue(False,
891 "Unexpected error message"
892 )
893
894
895 # Add flows to capacity, make sure they can be read back, and delete them
896
897 def test1(self,
898 overlapf, # True <=> When sending flow adds to
899 # switch, include the "check for
900 # overlap" flag, and verify that an
901 # error message is received
902 # if an overlapping flow is defined
903 strictf # True <=> When deleting flows, delete
904 # them strictly
905 ):
Howard Pershc7963582012-03-29 10:02:59 -0700906 """
907 """
908
909 # Clear all flows from switch
910 self.logger.debug("Deleting all flows from switch")
911 rc = delete_all_flows(self.controller, pa_logger)
912 self.assertEqual(rc, 0, "Failed to delete all flows")
913
914 # Get valid port numbers
915 # Get number of tables supported
916 # Get actions supported by switch
917
918 self.logger.debug("Retrieving features from switch")
919 request = message.features_request()
920 (sw_features, pkt) = self.controller.transact(request, timeout=2)
921 self.assertTrue(sw_features is not None, "No reply to features_request")
922 self.logger.debug("Switch features -")
923 self.logger.debug("Number of tables: " + str(sw_features.n_tables))
924 self.logger.debug("Supported actions: " + hex(sw_features.actions))
Howard Persh680b92a2012-03-31 13:34:35 -0700925 self.logger.debug("Ports: "
926 + str(map(lambda x: x.port_no, sw_features.ports))
927 )
Howard Pershc7963582012-03-29 10:02:59 -0700928
929 # For each table, get wildcards supported maximum number of flows
930
931 self.logger.debug("Retrieving table stats from switch")
932 request = message.table_stats_request()
933 (tbl_stats, pkt) = self.controller.transact(request, timeout=2)
Howard Persh680b92a2012-03-31 13:34:35 -0700934 self.assertTrue(tbl_stats is not None,
935 "No reply to table_stats_request"
936 )
Howard Pershc7963582012-03-29 10:02:59 -0700937 active_count = 0
Howard Persh680b92a2012-03-31 13:34:35 -0700938 max_entries = 0
Howard Pershc7963582012-03-29 10:02:59 -0700939 tbl_idx = 0
940 while tbl_idx < sw_features.n_tables:
941 self.logger.debug("Table " + str(tbl_idx) + " - ")
Howard Persh680b92a2012-03-31 13:34:35 -0700942 self.logger.debug("Supported wildcards: "
943 + hex(tbl_stats.stats[tbl_idx].wildcards)
944 )
945 self.logger.debug("Max entries: "
946 + str(tbl_stats.stats[tbl_idx].max_entries)
947 )
948 self.logger.debug("Active count: "
949 + str(tbl_stats.stats[tbl_idx].active_count)
950 )
951 max_entries = max_entries + tbl_stats.stats[tbl_idx].max_entries
Howard Pershc7963582012-03-29 10:02:59 -0700952 active_count = active_count + tbl_stats.stats[tbl_idx].active_count
953 tbl_idx = tbl_idx + 1
954
Howard Persh680b92a2012-03-31 13:34:35 -0700955 self.logger.debug("Total active entries = "
956 + str(active_count)
957 )
958 self.assertEqual(active_count,
959 0,
960 "Delete all flows failed"
961 )
Howard Pershc7963582012-03-29 10:02:59 -0700962
Howard Persh680b92a2012-03-31 13:34:35 -0700963 # TBD - For testing only, since Open vSWitch reports
964 # ridiculously large capacity; remove
965 sw_features.n_tables = 1
966 tbl_stats.stats[0].max_entries = 10
967 max_entries = tbl_stats.stats[0].max_entries
968
969 # Dream up some flow information, i.e. space to chose from for
970 # random flow parameter generation
971 fi = flow_info()
972 n = int(math.log(max_entries))
973 if not overlapf:
974 # Generated space smaller when testing overlaps,
975 # to increase likelihood of some
976 n = 2 * n
977 fi.rand(n)
Howard Pershc7963582012-03-29 10:02:59 -0700978
979 # For each table, think up flows to fill it
980
981 self.logger.debug("Creating flows")
982 num_flows = 0
983 num_overlaps = 0
984 tbl_flows = []
985 tbl_idx = 0
Howard Persh680b92a2012-03-31 13:34:35 -0700986
Howard Pershc7963582012-03-29 10:02:59 -0700987 while tbl_idx < sw_features.n_tables:
Howard Pershc7963582012-03-29 10:02:59 -0700988 flow_idx = 0
989 while flow_idx < tbl_stats.stats[tbl_idx].max_entries:
Howard Persh680b92a2012-03-31 13:34:35 -0700990 flow_out = flow_cfg()
991 if overlapf and num_flows == 1:
992 # Make 2nd flow a copy of the first,
993 # to guarantee at least 1 overlap
994 flow_out = copy.deepcopy(tbl_flows[0])
Howard Pershc7963582012-03-29 10:02:59 -0700995 flow_out.overlap = True
Howard Persh680b92a2012-03-31 13:34:35 -0700996 flow_out.overlaps_with = [0, 0]
997 num_overlaps = num_overlaps + 1
Howard Pershc7963582012-03-29 10:02:59 -0700998 else:
Howard Persh680b92a2012-03-31 13:34:35 -0700999 flow_out.rand(fi,
1000 tbl_stats.stats[tbl_idx].wildcards,
1001 sw_features.actions,
1002 map(lambda x: x.port_no, sw_features.ports)
1003 )
1004 flow_out.overlap = False
1005
1006 for f in tbl_flows:
1007 if (not overlapf or not f.overlap) \
1008 and flow_out.overlaps(f, False):
1009 flow_out.overlap = True
1010 flow_out.overlaps_with = [f.tbl_idx, f.flow_idx]
1011 num_overlaps = num_overlaps + 1
1012
1013 flow_out.tbl_idx = tbl_idx
1014 flow_out.flow_idx = flow_idx
1015
1016 self.logger.debug("tbl_idx=%d, flow_idx=%d, %s" % (tbl_idx, flow_idx, str(flow_out)))
1017
1018 tbl_flows.append(flow_out)
1019
Howard Pershc7963582012-03-29 10:02:59 -07001020 num_flows = num_flows + 1
1021 flow_idx = flow_idx + 1
Howard Pershc7963582012-03-29 10:02:59 -07001022 tbl_idx = tbl_idx + 1
1023
Howard Persh680b92a2012-03-31 13:34:35 -07001024 self.logger.debug("Created " + str(num_flows)
1025 + " flows, with " + str(num_overlaps)
1026 + " overlaps"
1027 )
Howard Pershc7963582012-03-29 10:02:59 -07001028
1029 # Send all flows to switch
1030
1031 self.logger.debug("Sending flows to switch")
Howard Persh680b92a2012-03-31 13:34:35 -07001032 for f in tbl_flows:
1033 self.flow_add(f, overlapf)
1034 f.deleted = False
Howard Pershc7963582012-03-29 10:02:59 -07001035
1036 # Send barrier, to make sure all flows are in
Howard Persh680b92a2012-03-31 13:34:35 -07001037 self.do_barrier()
Howard Pershc7963582012-03-29 10:02:59 -07001038
Howard Persh680b92a2012-03-31 13:34:35 -07001039 # Red back all flows from switch, and verify
Howard Pershc7963582012-03-29 10:02:59 -07001040
Howard Persh680b92a2012-03-31 13:34:35 -07001041 self.verify_flows(sw_features,
1042 tbl_flows,
1043 num_flows,
1044 overlapf,
1045 num_overlaps
1046 )
Howard Pershc7963582012-03-29 10:02:59 -07001047
Howard Persh680b92a2012-03-31 13:34:35 -07001048 # Delete a flows from switch
Howard Pershc7963582012-03-29 10:02:59 -07001049
Howard Persh680b92a2012-03-31 13:34:35 -07001050 if strictf:
1051 # Strict delete
1052
1053 # Delete a few flows, in random order, individually (i.e. strictly)
1054
1055 del_flow_idxs = shuffle(range(len(tbl_flows)))
1056 # TBD - Limited, for testing only; remove
1057 del_flow_idxs = del_flow_idxs[0 : random.randint(3, 3)]
1058 for di in del_flow_idxs:
1059 f = tbl_flows[di]
1060 tbl_idx = f.tbl_idx
1061 flow_idx = f.flow_idx
1062 if (overlapf and f.overlap):
1063 self.logger.debug("Flow tbl_idx = " + str(tbl_idx)
1064 + ", flow_idx = " + str(flow_idx)
1065 + " was an overlap, skipping delete"
1066 )
1067 else:
1068 self.logger.debug("Deleting flow, tbl_idx = "
1069 + str(tbl_idx) + ", flow_idx = "
1070 + str(flow_idx)
1071 )
1072 self.flow_del(f, True)
1073 f.deleted = True
1074 num_flows = num_flows - 1
Howard Pershc7963582012-03-29 10:02:59 -07001075
Howard Persh680b92a2012-03-31 13:34:35 -07001076 # Send barrier, to make sure all flows are deleted
1077 self.do_barrier();
Howard Pershc7963582012-03-29 10:02:59 -07001078
Howard Persh680b92a2012-03-31 13:34:35 -07001079 # Red back all flows from switch, and verify
Howard Pershc7963582012-03-29 10:02:59 -07001080
Howard Persh680b92a2012-03-31 13:34:35 -07001081 self.verify_flows(sw_features,
1082 tbl_flows,
1083 num_flows,
1084 overlapf,
1085 num_overlaps
1086 )
Howard Pershc7963582012-03-29 10:02:59 -07001087
Howard Persh680b92a2012-03-31 13:34:35 -07001088 # Delete all remaining flows, in random order,
1089 # individually (i.e. strictly)
1090
1091 del_flow_idxs = shuffle(range(len(tbl_flows)))
1092 for di in del_flow_idxs:
1093 f = tbl_flows[di]
1094 if f.deleted:
1095 continue
1096 tbl_idx = f.tbl_idx
1097 flow_idx = f.flow_idx
1098 if (overlapf and f.overlap):
1099 self.logger.debug("Flow tbl_idx = "
1100 + str(tbl_idx)
1101 + ", flow_idx = "
1102 + str(flow_idx)
1103 + " was an overlap, skipping delete"
1104 )
1105 else:
1106 self.logger.debug("Deleting flow, tbl_idx = "
1107 + str(tbl_idx)
1108 + ", flow_idx = "
1109 + str(flow_idx)
1110 )
1111 self.flow_del(f, True)
1112 f.deleted = True
1113 num_flows = num_flows - 1
Howard Pershc7963582012-03-29 10:02:59 -07001114
Howard Persh680b92a2012-03-31 13:34:35 -07001115 # Send barrier, to make sure all flows are deleted
1116 self.do_barrier()
1117
1118 # Red back all flows from switch (i.e. none), and verify
1119
1120 self.verify_flows(sw_features,
1121 tbl_flows,
1122 num_flows,
1123 overlapf,
1124 num_overlaps
1125 )
Howard Pershc7963582012-03-29 10:02:59 -07001126
Howard Persh680b92a2012-03-31 13:34:35 -07001127 else:
1128 # Non-strict delete
Howard Pershc7963582012-03-29 10:02:59 -07001129
Howard Persh680b92a2012-03-31 13:34:35 -07001130 # Pick a flow at random that had at least 1 qualifier specified,
1131 # wildcard a qualifier that was specified,
1132 # and do a non-strict delete
1133 # Keep wildcarding specified qualifiers, one by one, and deleteing,
1134 # until everything is wildcarded,
1135 # and hence all flows should be deleted
Howard Pershc7963582012-03-29 10:02:59 -07001136
Howard Persh680b92a2012-03-31 13:34:35 -07001137 while True:
1138 f = tbl_flows[random.randint(0, len(tbl_flows) - 1)]
1139 if f.match.wildcards != tbl_stats.stats[f.tbl_idx].wildcards:
1140 self.logger.debug("Choosing flow for basis of non-strict delete")
1141 self.logger.debug(" tbl_idx=%d flow_idx=%d" % (f.tbl_idx, f.flow_idx))
1142 self.logger.debug(" " + str(f))
1143 break
Howard Pershc7963582012-03-29 10:02:59 -07001144
Howard Persh680b92a2012-03-31 13:34:35 -07001145 # For each qualifier, in random order, if it was specified,
1146 # wildcard it, do a delete, and check the results
1147
1148 wildcard_idxs = shuffle(range(len(all_wildcards_list)))
1149 for wi in wildcard_idxs:
1150 w = all_wildcards_list[wi]
1151 if (f.match.wildcards & w) != 0:
1152 continue
Howard Pershc7963582012-03-29 10:02:59 -07001153
Howard Persh680b92a2012-03-31 13:34:35 -07001154 if w == ofp.OFPFW_NW_SRC_MASK:
1155 f.match.wildcards = (f.match.wildcards
1156 & ~ofp.OFPFW_NW_SRC_MASK
1157 ) \
1158 | ofp.OFPFW_NW_SRC_ALL
1159 wn = "OFPFW_NW_SRC"
1160 elif w == ofp.OFPFW_NW_DST_MASK:
1161 f.match.wildcards = (f.match.wildcards
1162 & ~ofp.OFPFW_NW_DST_MASK
1163 ) \
1164 | ofp.OFPFW_NW_DST_ALL
1165 wn = "OFPFW_NW_DST"
1166 else:
1167 f.match.wildcards = f.match.wildcards | w
1168 wn = ofp.ofp_flow_wildcards_map[w]
Howard Pershc7963582012-03-29 10:02:59 -07001169
Howard Persh680b92a2012-03-31 13:34:35 -07001170 self.logger.debug("Adding wildcard %s" % (wn))
1171 self.logger.debug(str(f))
Howard Pershc7963582012-03-29 10:02:59 -07001172
Howard Persh680b92a2012-03-31 13:34:35 -07001173 # Mark all flows which would be deleted by this
1174 # non-strict delete
1175
1176 for ff in tbl_flows:
1177 if not ff.deleted and f.overlaps(ff, True):
1178 self.logger.debug("Deleting flow, tbl_idx = "
1179 + str(ff.tbl_idx) + ", flow_idx = "
1180 + str(ff.flow_idx)
1181 )
1182 ff.deleted = True
1183 num_flows = num_flows - 1
1184
1185 self.flow_del(f, False)
1186
1187 # Send barrier, to make sure all flows are deleted
1188 self.do_barrier()
1189
1190 # Red back all flows from switch, and verify
1191
1192 self.verify_flows(sw_features,
1193 tbl_flows,
1194 num_flows,
1195 overlapf,
1196 num_overlaps
1197 )
Howard Pershc7963582012-03-29 10:02:59 -07001198
Howard Pershc7963582012-03-29 10:02:59 -07001199
1200
1201 def runTest(self):
1202 """
1203 Run all tests
1204 """
1205
Howard Persh680b92a2012-03-31 13:34:35 -07001206 self.test1(False, True) # Test with no overlaps, strict delete
1207 self.test1(True, True) # Test with overlaps, strict delete
1208# self.test1(False, False) # Test with no overlaps, non-strict delete
1209# self.test1(True, False) # Test with overlaps, non-strict delete
Howard Pershc7963582012-03-29 10:02:59 -07001210