From c875bb948df059855c18b29bdfbfbfcb986e607a Mon Sep 17 00:00:00 2001 From: Ethan Jackson Date: Thu, 26 Mar 2015 12:52:42 -0700 Subject: [PATCH] utilities: Add new pipeline generator script. When doing OVS performance testing, it's important to have both realistic traffic traces and OpenFlow pipelines on which to evaluate prospective changes. As a first step in this direction, this patch adds a python script which generates an OpenFlow pipeline intended to simulate typical network virtualization workloads. Signed-off-by: Ethan Jackson Acked-by: Daniele Di Proietto --- utilities/automake.mk | 5 +- utilities/ovs-pipegen.py | 122 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 2 deletions(-) create mode 100755 utilities/ovs-pipegen.py diff --git a/utilities/automake.mk b/utilities/automake.mk index a06630f1f..6083b4b68 100644 --- a/utilities/automake.mk +++ b/utilities/automake.mk @@ -34,9 +34,8 @@ utilities/ovs-lib: $(top_builddir)/config.status docs += utilities/ovs-command-bashcomp.INSTALL.md EXTRA_DIST += \ - utilities/ovs-check-dead-ifs.in \ utilities/ovs-appctl-bashcomp.bash \ - utilities/ovs-vsctl-bashcomp.bash \ + utilities/ovs-check-dead-ifs.in \ utilities/ovs-command-bashcomp.INSTALL.md \ utilities/ovs-ctl.in \ utilities/ovs-dev.py \ @@ -46,11 +45,13 @@ EXTRA_DIST += \ utilities/ovs-lib.in \ utilities/ovs-parse-backtrace.in \ utilities/ovs-pcap.in \ + utilities/ovs-pipegen.py \ utilities/ovs-pki.in \ utilities/ovs-save \ utilities/ovs-tcpundump.in \ utilities/ovs-test.in \ utilities/ovs-vlan-test.in \ + utilities/ovs-vsctl-bashcomp.bash \ utilities/qemu-wrap.py MAN_ROOTS += \ utilities/ovs-appctl.8.in \ diff --git a/utilities/ovs-pipegen.py b/utilities/ovs-pipegen.py new file mode 100755 index 000000000..95647d1e2 --- /dev/null +++ b/utilities/ovs-pipegen.py @@ -0,0 +1,122 @@ +#!/usr/bin/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() -- 2.20.1