]>
Commit | Line | Data |
---|---|---|
f6783a7a | 1 | #! /usr/bin/env python |
c875bb94 EJ |
2 | # Copyright (c) 2013, 2014, 2015 Nicira, Inc. |
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 | import argparse | |
17 | import random | |
18 | import sys | |
19 | import textwrap | |
20 | ||
21 | def flow_str(stage, match, action, priority=32768): | |
22 | mtd_match = "metadata=%d" % stage | |
23 | if match: | |
24 | mtd_match += "," + match | |
25 | ||
26 | return "priority=%d %s,actions=%s" % (priority, mtd_match, action) | |
27 | ||
28 | ||
29 | def resubmit(nxt): | |
30 | return "load:%d->OXM_OF_METADATA[],resubmit(,0)" % nxt | |
31 | ||
32 | ||
33 | def rand_ip_mask(): | |
34 | return ("%d.%d.%d.%d" % (random.randint(0, 255), random.randint(0, 255), | |
35 | random.randint(0, 255), random.randint(0, 255)), | |
36 | random.choice([8, 16, 24, 32])) | |
37 | ||
38 | ||
39 | def rand_bool(): | |
40 | return bool(random.randint(0, 1)) | |
41 | ||
42 | ||
43 | def l2(stage, action): | |
44 | mac = ["%x" % random.randint(0, 2 ** 8 - 1) for x in range(6)] | |
45 | mac = [x.zfill(2) for x in mac] | |
46 | mac = ":".join(mac) | |
47 | return flow_str(stage, "dl_dst=%s" % mac, action) | |
48 | ||
49 | ||
50 | def l3(stage, action): | |
51 | ip, mask = rand_ip_mask() | |
52 | return flow_str(stage, "ip,ip_dst=%s/%d" % (ip, mask), action, | |
53 | priority=mask) | |
54 | ||
55 | ||
56 | def l4(stage, action): | |
57 | match = "tcp" | |
58 | ||
59 | if rand_bool(): | |
60 | match += ",ip_src=%s/%d" % rand_ip_mask() | |
61 | ||
62 | if rand_bool(): | |
63 | match += ",ip_dst=%s/%d" % rand_ip_mask() | |
64 | ||
65 | src_dst = "tp_src" if rand_bool() else "tp_dst" | |
66 | match += ",%s=%d" % (src_dst, random.randint(1024, 2**16 - 1)) | |
67 | return flow_str(stage, match, action) | |
68 | ||
69 | ||
70 | def pipeline(size): | |
71 | pipeline = [l2, l3, l4, l2] | |
72 | ||
73 | flows = [] | |
74 | for stage in xrange(len(pipeline)): | |
75 | action = resubmit(stage + 1) | |
76 | flows += [pipeline[stage](stage, action) for _ in xrange(size)] | |
77 | flows.append(flow_str(stage, "", action, priority=1)) | |
78 | ||
79 | flows.append(flow_str(len(pipeline), "", "in_port")) | |
80 | ||
81 | for f in flows: | |
82 | print f | |
83 | ||
84 | ||
85 | def main(): | |
86 | description = textwrap.dedent( | |
87 | """ | |
88 | Generate a test OpenFlow pipeline. | |
89 | ||
90 | Open vSwitch relies heavily on flow caching to get good performance for | |
91 | packet processing. While on average, this produces good results, | |
92 | performance is heavily depedent on the slow path OpenFlow tables, and | |
93 | how they're translated into datapath megaflows. For this reason, when | |
94 | doing performance testing it's important to run with "realistic" | |
95 | OpenFlow tables to ensure results will stand up in the real world. | |
96 | ||
97 | This script generates a simple OpenFlow pipeline intended to simulate | |
98 | realistic network virtualization workloads. All traffic received is | |
99 | run through a series of OpenFlow tables designed to simulate a logical | |
100 | switch, router, and firewall, before forwarded back on the in_port. | |
101 | """) | |
102 | ||
103 | epilog = textwrap.dedent( | |
104 | """ | |
105 | typical usage: | |
106 | ovs-ofctl del-flows bridge \\ | |
107 | && %s | ovs-ofctl add-flows bridge - \\ | |
108 | && ovs-ofctl dump-flows bridge | |
109 | """ % sys.argv[0]) | |
110 | ||
111 | parser = argparse.ArgumentParser(description=description, epilog=epilog, | |
112 | formatter_class=\ | |
113 | argparse.RawDescriptionHelpFormatter) | |
114 | parser.add_argument("--size", dest="size", default=1000, | |
115 | help="Size (rules) of each OpenFlow table.") | |
116 | args=parser.parse_args() | |
117 | ||
118 | pipeline(int(args.size)) | |
119 | ||
120 | ||
121 | if __name__ == "__main__": | |
122 | main() |