- Initial version
diff --git a/tools/ovs-ctl/ovs-ctl.py b/tools/ovs-ctl/ovs-ctl.py
new file mode 100755
index 0000000..5df57d9
--- /dev/null
+++ b/tools/ovs-ctl/ovs-ctl.py
@@ -0,0 +1,465 @@
+#!/usr/bin/python
+
+import os
+import subprocess
+import argparse
+import sys
+import signal
+import time
+import ConfigParser
+import pprint
+
+###############################################################################
+#
+# Arguments
+#
+# Arguments can be specified directly, or via config file. 
+# TODO -- Make this a separate reusable class
+#
+################################################################################
+gBasename = "ovs-ctl"
+
+gConfigParser = argparse.ArgumentParser(description=gBasename, add_help=False)
+
+gConfigParser.add_argument('-cf', '--config-file', 
+                     help="Load settings from the given config file", 
+                     nargs='+', metavar="FILE", 
+                     default=os.path.expanduser("~/."+gBasename))
+
+gConfigParser.add_argument('-c', '--config', 
+                     help="Use the specified configuration section", 
+                     default=None)
+
+gConfigParser.add_argument('-d', '--default-config-file', 
+                     help="Location of the local default config file", 
+                     metavar="FILE", 
+                     default="/opt/ovs/%s-default.conf" % (gBasename))
+
+gConfigParser.add_argument('-nd', '--no-default', 
+                     help="Do not load the default config file", 
+                     action='store_true', default=False)
+gConfigParser.add_argument('--dump-config',
+                     help="Dump the loaded configuration settings", 
+                     action='store_true', default=False)
+
+#
+# Parse the config files first, then parse remaining command line arguments
+#
+gConfig = ConfigParser.SafeConfigParser()
+configArgs, remainingArgs = gConfigParser.parse_known_args()
+
+if not configArgs.no_default:
+    gConfig.read([configArgs.default_config_file])
+
+if isinstance(configArgs.config_file, str):
+    configFiles = [ configArgs.config_file]
+else:
+    configFiles = configArgs.config_file
+
+configFiles = [ os.path.expanduser(x) if x.startswith('~') else x 
+                for x in configFiles ]
+
+gConfig.read(configFiles)
+
+# Dump loaded config if requested
+if configArgs.dump_config:
+    for section in gConfig.sections():
+        print section
+        for option in gConfig.options(section):
+            print " ", option, "=", gConfig.get(section, option)
+    sys.exit()
+
+
+
+#
+# Functional arguments go here
+#
+
+#
+# OVS target binaries -- these can all be specified individually. 
+# If not specified, they are determined by the base directory settings
+#
+gParser = argparse.ArgumentParser(parents=[gConfigParser])
+
+gParser.add_argument('--ovs-vswitchd-schema', 
+                     help="""Path to the vswitchd.ovsschema file""")
+gParser.add_argument('--ovs-vswitchd-log', 
+                     help="""Path to the vswitchd log file""")
+gParser.add_argument('--ovs-vswitchd', 
+                     help="""Path to the target ovs-vswitchd binary""")
+gParser.add_argument('--ovs-vsctl', 
+                     help="""Path to the target ovs-vsctl binary""")
+gParser.add_argument('--ovs-ofctl', 
+                     help="""Path to the target ovs-ofctl binary""")
+gParser.add_argument('--ovsdb-tool', 
+                     help="""Path to the target ovsdb-tool binary""")
+gParser.add_argument('--ovsdb-server', 
+                     help="""Path to the target ovsdb-server binary""")
+gParser.add_argument('--ovs-kmod', 
+                     help="""Path to the OVS kernel module""")
+gParser.add_argument('--ovs-src-dir',
+                     help="""Directory for the OVS Source Files""")
+
+gParser.add_argument('--ovs-log-dir',
+                     help="""Directory for the OVS Runtime Log Files""")
+
+gParser.add_argument('--ovs-version')
+
+gParser.add_argument("--ovs-base-dir", help="OVS Base Installation Directory")
+
+gParser.add_argument("--ovs-runtime-dir", 
+                     help="OVS Runtime Directory", 
+                     default="/var/run/ovs")
+
+gParser.add_argument('--ovs-db-sock', 
+                     help="Domain Socket Location")
+                     
+gParser.add_argument('--ovs-db-file', 
+                     help="Location for the OVS database file")
+
+
+#
+# Logging/Debugging/Testing options
+#
+gParser.add_argument('--dry', 
+                     help="""Dry run only. Don't actually do anything""", 
+                     action='store_true',  default=False)
+
+gParser.add_argument('--log', 
+                     help='Enable logging', 
+                     action='store_true', default=False)
+
+gParser.add_argument('--verbose', 
+                     help='Enable verbose output information', 
+                     action='store_true', default=False)
+
+gParser.add_argument("--kill", help="Kill running OVS", 
+                     default=False, action='store_true')
+
+gParser.add_argument("--keep-veths", 
+                     help="""By default, all existing veths will be destroyed and
+the veth module removed before initializing. If you don't want the veth module
+removed, specify this argument. Your mileage may vary if you use this.""", 
+                     default=False, action='store_true')
+
+gParser.add_argument("--no-kmod", 
+                     help="""Do not attempt to insert or remove the OVS kernel module. 
+Your mileage may vary.""", 
+                     default=False, action='store_true')
+
+gParser.add_argument("--vlog", 
+                     help="""Tail the running vswitch.log file in a new xterm""", 
+                     default=False, action='store_true')
+
+#
+# Runtime and setup arguments
+#
+gParser.add_argument('-p', '--port-count', type=int, 
+                     help="Number of veth ports to connect.", 
+                     default='4')
+
+
+gParser.add_argument("--bridge", help="Name of OF OVS Bridge", 
+                     default="ofbr0")
+
+gParser.add_argument("--cip", help="Controller Connection", 
+                     default="127.0.0.1")
+
+gParser.add_argument("--cport", type=int, help="Controller Port", 
+                     default=6633)
+
+gParser.add_argument("--max_backoff", help="VSwitchD max backoff value", 
+                     default=1000, type=int)
+
+
+gParser.add_argument("--keep-db", 
+                     help="""By default, a new database is initialized at each
+execution. If you want to keep and use the old database (if it exists), 
+use this option""", 
+                     action='store_true', default=False)
+
+
+
+#
+# Reset defaults based on config files and override
+#
+# Anything in the "Defaults" section gets slurped first:
+defaults = {}
+if gConfig.has_section('Defaults'):
+    defaults = dict(gConfig.items('Defaults'))
+    gParser.set_defaults(**defaults)
+
+#
+# The configuration to execute might be specified in on the command line, or in the Defaults section(s)
+# of the config files. 
+#
+# If its specified on the command line, it will be present in configArgs.config
+# If its specified in the section, it will only be present in the defaults dict. 
+# Need to check both. Command line takes precedence. 
+#
+gConfigSection = None
+if configArgs.config != None:
+    gConfigSection = configArgs.config
+elif defaults.has_key('config'):
+    gConfigSection = defaults['config']
+
+
+if gConfigSection != None:
+    if gConfig.has_section(gConfigSection):
+        section = dict(gConfig.items(gConfigSection))
+        gParser.set_defaults(**section)
+    else:
+        print >>sys.stderr, "Requestion configuration '%s' does not exist" % (configArgs.config)
+        sys.exit()
+
+
+###############################################################################
+# 
+# Done with argument setup. Parser remaining arguments
+#
+###############################################################################
+gArgs = gParser.parse_args(remainingArgs)
+
+
+#
+# At the end of all of this, we need the following things to be defined
+# or derived:
+#
+gRequiredOptions = [
+    [ 'ovs_vswitchd_schema', 'ovs_src_dir',     '/vswitchd/vswitch.ovsschema', True,  True  ], 
+    [ 'ovs_vswitchd',        'ovs_base_dir',    '/sbin/ovs-vswitchd',          True,  True  ], 
+    [ 'ovs_vsctl',           'ovs_base_dir',    '/bin/ovs-vsctl',              True,  True  ], 
+    [ 'ovs_ofctl',           'ovs_base_dir',    '/bin/ovs-ofctl',              True,  True  ], 
+    [ 'ovsdb_tool',          'ovs_base_dir',    '/bin/ovsdb-tool',             True,  True, ], 
+    [ 'ovsdb_server',        'ovs_base_dir',    '/sbin/ovsdb-server',          True,  True, ], 
+    [ 'ovs_db_file',          'ovs_base_dir',    '/ovs.db',                    False, True, ], 
+    [ 'ovs_db_sock',         'ovs_runtime_dir', '/db.sock',                    False, True, ], 
+    [ 'ovs_kmod',            'ovs_base_dir',    '/sbin/openvswitch_mod.ko',    True,  not gArgs.no_kmod ], 
+]
+
+def __require_option(key, basedir, path, exists=True):
+    value = getattr(gArgs, key)
+    if value is None:
+        # Unspecified -- try to default based on given path
+        value = getattr(gArgs, basedir)
+
+        if value is None:
+            return False
+
+        value += path
+
+    if exists and not os.path.exists(value):
+        return False
+
+    if gArgs.verbose:
+        print '--v-- option: %s @ %s' % (key, value)
+
+    setattr(gArgs, key, value)
+
+
+Validated = True
+# Try to validate as many things as we can
+for option in gRequiredOptions:
+    if option[4]:
+        if __require_option(option[0], option[1], option[2], option[3]) == False:
+            Validated = False
+
+# If any of them failed, try to be as helpful as possible
+if Validated == False:
+    print >>sys.stdout, "\nConfiguration problem. One or more required settings are missing or could not be derived:\n"
+    for option in gRequiredOptions:
+        if option[4] is False:
+            continue
+
+        value = getattr(gArgs, option[0])
+        if value:
+            print >>sys.stdout, " %s: %s" % (option[0], value), 
+            if option[3] and not os.path.exists(value):
+                print >>sys.stdout, "-- does not exist"
+            else:
+                print "(OK)"
+        else:
+            print >>sys.stdout, " %s: Unknown. " % (option[0]), 
+            base = getattr(gArgs, option[1])
+            if base:
+                print >>sys.stdout, "Search path was '%s'." % (base + option[2])
+            else:
+                print >>sys.stdout, "Could not derive path because '%s' was also unspecified." % (option[1])
+    print >>sys.stdout
+    sys.exit()
+
+
+
+
+#
+# If we aren't in a dry run, you must execute as root to accompish anything
+#
+if not os.geteuid() == 0 and gArgs.dry == False:
+    print >>sys.stderr, "Must run as root to accomplish any of this."
+    sys.exit()
+
+
+###############################################################################
+#
+# Helpers 
+#
+###############################################################################
+
+def createVeths(count):
+    for idx in range(0, count):
+        lcall(["/sbin/ip", "link", "add", "type", "veth"])
+
+def vethsUp(count):
+    for idx in range(0, count*2):
+        lcall(["/sbin/ifconfig", 'veth%s' % (idx), "up"])
+
+def lcall(cmd, log=gArgs.log, dry=gArgs.dry, popen=False, 
+          pidFile=None):
+    
+    if log or gArgs.verbose:
+        print "%s: %s" % ('popen' if popen else 'call', cmd)
+    
+    if not dry:
+        if not popen:
+            subprocess.call(cmd)
+        else:
+            p = subprocess.Popen(cmd)
+            if pidFile != None:
+                pidf = open(pidFile, "w"); 
+                print >>pidf, p.pid
+                pidf.close()
+
+    
+
+def vsctl(argsList):
+    argsList.insert(0, "--db=unix:%s" % (gArgs.ovs_db_sock))
+    argsList.insert(0, gArgs.ovs_vsctl)
+    lcall(argsList)
+
+def ofctl(argsList):
+    argsList.insert(0, gArgs.ovs_ofctl)
+    lcall(argsList)
+
+def killpid(pid):
+    try:
+        os.kill(pid, signal.SIGTERM)
+        return False
+    except OSError, e:
+        return True
+
+
+def killp(pidfile):
+    if os.path.exists(pidfile):
+        pid=int(open(pidfile).read())
+        print "Killing %s, pid=%s..." % (pidfile, pid),
+        if not gArgs.dry:
+            while not killpid(pid):
+                time.sleep(1)
+                pass
+        print "dead"
+
+
+###############################################################################
+#
+# main
+#
+###############################################################################
+
+gServerPid = gArgs.ovs_runtime_dir + "/ovsdb-server.pid"
+gSwitchPid = gArgs.ovs_runtime_dir + "/ovs-vswitchd.pid"
+gLogPid=     gArgs.ovs_runtime_dir + "/ovs-vswitchd-tail.pid"
+
+# Kill previous execution based on contents of the runtime dir
+if os.path.exists(gServerPid):
+    print gServerPid
+    vsctl(["del-br", gArgs.bridge])
+
+# Kill existing DB/vswitchd
+killp(gSwitchPid)
+killp(gServerPid)
+killp(gLogPid)
+
+# Remove old logpid file, since this does not happen automagically
+if os.path.exists(gLogPid):
+    os.remove(gLogPid)
+
+if gArgs.keep_veths == False:
+    lcall(['/sbin/rmmod', 'veth'])
+    lcall(['/sbin/modprobe', 'veth'])
+
+# Remove kmod
+lcall(['/sbin/rmmod', gArgs.ovs_kmod])
+
+if gArgs.kill == True:
+    # Don't do anything else
+    sys.exit()
+
+
+# Remove bridge module
+lcall(['/sbin/rmmod', 'bridge'])
+# Insert openvswitch module
+lcall(['/sbin/insmod', gArgs.ovs_kmod])
+
+createVeths(gArgs.port_count)
+vethsUp(gArgs.port_count)
+
+if not os.path.exists(gArgs.ovs_db_file) or gArgs.keep_db == False:
+    print "Initializing DB @ %s" % (gArgs.ovs_db_file)
+    if os.path.exists(gArgs.ovs_db_file) and not gArgs.dry:
+        os.remove(gArgs.ovs_db_file)
+
+    lcall([gArgs.ovsdb_tool, "create", gArgs.ovs_db_file, 
+           gArgs.ovs_vswitchd_schema])
+else:
+    print "Keeping existing DB @ %s" % (gArgs.ovs_db_file)
+
+
+if not os.path.exists(gArgs.ovs_runtime_dir):
+    os.makedirs(gArgs.ovs_runtime_dir)
+
+# Start dbserver
+lcall([gArgs.ovsdb_server, gArgs.ovs_db_file, 
+       "--remote=punix:%s" % (gArgs.ovs_db_sock), 
+       "--detach", "--pidfile=%s" % (gServerPid)])
+
+# Init db
+vsctl(["--no-wait", "init"])
+
+# Start vswitchd
+startV = [ gArgs.ovs_vswitchd, 
+          "unix:%s" % (gArgs.ovs_db_sock), 
+          "--verbose", "--detach",
+          "--pidfile=%s" % (gSwitchPid) ]
+
+if gArgs.ovs_vswitchd_log:
+    startV.append("--log-file=%s" % (gArgs.ovs_vswitchd_log))
+
+lcall(startV)
+
+if gArgs.vlog:
+    lcall(["xterm", "-T", "vswitchd-log", "-e", "tail", "-f", 
+           gArgs.ovs_vswitchd_log], 
+          popen=True, pidFile=gLogPid)
+
+
+# Add a bridge
+vsctl(["add-br", gArgs.bridge])
+ofctl(["show", gArgs.bridge])
+
+# Add Veths to bridge
+for idx in range(0, gArgs.port_count):
+    vsctl(["add-port", gArgs.bridge, "veth%s" % (idx*2)])
+
+
+# Set controller
+vsctl(["set-controller", gArgs.bridge, "tcp:%s:%s" % (
+        gArgs.cip, gArgs.cport)])
+
+# Minimize default backoff for controller connections
+vsctl(["set", "Controller", gArgs.bridge, 
+       "max_backoff=%s" % (gArgs.max_backoff)])
+
+
+ofctl(["show", gArgs.bridge])
+
+