]> git.proxmox.com Git - mirror_ovs.git/blob - utilities/ovs-pipegen.py
Require Python 3 and remove support for Python 2.
[mirror_ovs.git] / utilities / ovs-pipegen.py
1 #! /usr/bin/env python
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
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"
67 match += ",%s=%d" % (src_dst, random.randint(1024, 2 ** 16 - 1))
68 return flow_str(stage, match, action)
69
70
71 def pipeline(size):
72 pipeline = [l2, l3, l4, l2]
73
74 flows = []
75 for stage in range(len(pipeline)):
76 action = resubmit(stage + 1)
77 flows += [pipeline[stage](stage, action) for _ in range(size)]
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:
83 print(f)
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,
113 formatter_class=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()