123 lines
3.8 KiB
Python
Executable File
123 lines
3.8 KiB
Python
Executable File
#! /usr/bin/env python
|
|
# Copyright (c) 2013, 2014, 2015 Nicira, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at:
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import argparse
|
|
import random
|
|
import sys
|
|
import textwrap
|
|
|
|
def flow_str(stage, match, action, priority=32768):
|
|
mtd_match = "metadata=%d" % stage
|
|
if match:
|
|
mtd_match += "," + match
|
|
|
|
return "priority=%d %s,actions=%s" % (priority, mtd_match, action)
|
|
|
|
|
|
def resubmit(nxt):
|
|
return "load:%d->OXM_OF_METADATA[],resubmit(,0)" % nxt
|
|
|
|
|
|
def rand_ip_mask():
|
|
return ("%d.%d.%d.%d" % (random.randint(0, 255), random.randint(0, 255),
|
|
random.randint(0, 255), random.randint(0, 255)),
|
|
random.choice([8, 16, 24, 32]))
|
|
|
|
|
|
def rand_bool():
|
|
return bool(random.randint(0, 1))
|
|
|
|
|
|
def l2(stage, action):
|
|
mac = ["%x" % random.randint(0, 2 ** 8 - 1) for x in range(6)]
|
|
mac = [x.zfill(2) for x in mac]
|
|
mac = ":".join(mac)
|
|
return flow_str(stage, "dl_dst=%s" % mac, action)
|
|
|
|
|
|
def l3(stage, action):
|
|
ip, mask = rand_ip_mask()
|
|
return flow_str(stage, "ip,ip_dst=%s/%d" % (ip, mask), action,
|
|
priority=mask)
|
|
|
|
|
|
def l4(stage, action):
|
|
match = "tcp"
|
|
|
|
if rand_bool():
|
|
match += ",ip_src=%s/%d" % rand_ip_mask()
|
|
|
|
if rand_bool():
|
|
match += ",ip_dst=%s/%d" % rand_ip_mask()
|
|
|
|
src_dst = "tp_src" if rand_bool() else "tp_dst"
|
|
match += ",%s=%d" % (src_dst, random.randint(1024, 2**16 - 1))
|
|
return flow_str(stage, match, action)
|
|
|
|
|
|
def pipeline(size):
|
|
pipeline = [l2, l3, l4, l2]
|
|
|
|
flows = []
|
|
for stage in xrange(len(pipeline)):
|
|
action = resubmit(stage + 1)
|
|
flows += [pipeline[stage](stage, action) for _ in xrange(size)]
|
|
flows.append(flow_str(stage, "", action, priority=1))
|
|
|
|
flows.append(flow_str(len(pipeline), "", "in_port"))
|
|
|
|
for f in flows:
|
|
print f
|
|
|
|
|
|
def main():
|
|
description = textwrap.dedent(
|
|
"""
|
|
Generate a test OpenFlow pipeline.
|
|
|
|
Open vSwitch relies heavily on flow caching to get good performance for
|
|
packet processing. While on average, this produces good results,
|
|
performance is heavily depedent on the slow path OpenFlow tables, and
|
|
how they're translated into datapath megaflows. For this reason, when
|
|
doing performance testing it's important to run with "realistic"
|
|
OpenFlow tables to ensure results will stand up in the real world.
|
|
|
|
This script generates a simple OpenFlow pipeline intended to simulate
|
|
realistic network virtualization workloads. All traffic received is
|
|
run through a series of OpenFlow tables designed to simulate a logical
|
|
switch, router, and firewall, before forwarded back on the in_port.
|
|
""")
|
|
|
|
epilog = textwrap.dedent(
|
|
"""
|
|
typical usage:
|
|
ovs-ofctl del-flows bridge \\
|
|
&& %s | ovs-ofctl add-flows bridge - \\
|
|
&& ovs-ofctl dump-flows bridge
|
|
""" % sys.argv[0])
|
|
|
|
parser = argparse.ArgumentParser(description=description, epilog=epilog,
|
|
formatter_class=\
|
|
argparse.RawDescriptionHelpFormatter)
|
|
parser.add_argument("--size", dest="size", default=1000,
|
|
help="Size (rules) of each OpenFlow table.")
|
|
args=parser.parse_args()
|
|
|
|
pipeline(int(args.size))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|