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