test-controller: Rename to ovs-testcontroller, again install.
authorBen Pfaff <blp@nicira.com>
Fri, 15 Aug 2014 17:32:50 +0000 (10:32 -0700)
committerBen Pfaff <blp@nicira.com>
Tue, 26 Aug 2014 18:03:43 +0000 (11:03 -0700)
mininet uses the Open vSwitch controller by default, for testing.

CC: 757761@bugs.debian.org
Reported-at: https://bugs.debian.org/757761
Requested-by: Tomasz Buchert <tomasz.buchert@inria.fr>
Requested-by: Dariusz Dwornikowski <dariusz.dwornikowski@cs.put.poznan.pl>
Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Justin Pettit <jpettit@nicira.com>
28 files changed:
INSTALL.SSL
INSTALL.XenServer
NEWS
README
debian/.gitignore
debian/automake.mk
debian/changelog
debian/control
debian/openvswitch-testcontroller.README.Debian [new file with mode: 0644]
debian/openvswitch-testcontroller.default [new file with mode: 0644]
debian/openvswitch-testcontroller.dirs [new file with mode: 0644]
debian/openvswitch-testcontroller.init [new file with mode: 0755]
debian/openvswitch-testcontroller.install [new file with mode: 0644]
debian/openvswitch-testcontroller.manpages [new file with mode: 0644]
debian/openvswitch-testcontroller.postinst [new file with mode: 0755]
debian/openvswitch-testcontroller.postrm [new file with mode: 0755]
manpages.mk
rhel/openvswitch-fedora.spec.in
rhel/openvswitch.spec.in
tests/.gitignore
tests/automake.mk
tests/test-controller.8.in [deleted file]
tests/test-controller.c [deleted file]
utilities/.gitignore
utilities/automake.mk
utilities/ovs-testcontroller.8.in [new file with mode: 0644]
utilities/ovs-testcontroller.c [new file with mode: 0644]
xenserver/openvswitch-xen.spec.in

index 061af97..a6931d2 100644 (file)
@@ -115,10 +115,10 @@ that contains the PKI structure:
       % ovs-pki req+sign ctl controller
 
 ctl-privkey.pem and ctl-cert.pem would need to be copied to the
-controller for its use at runtime.  If you were to use test-controller,
-the simple OpenFlow controller included with Open vSwitch, then the
---private-key and --certificate options, respectively, would point to
-these files.
+controller for its use at runtime.  If, for testing purposes, you were
+to use ovs-testcontroller, the simple OpenFlow controller included
+with Open vSwitch, then the --private-key and --certificate options,
+respectively, would point to these files.
 
 It is very important to make sure that no stray copies of
 ctl-privkey.pem are created, because they could be used to impersonate
index 1e23634..8c07d24 100644 (file)
@@ -172,7 +172,7 @@ controller on XenServer and, as a consequence of the step above that
 deletes all of the bridges at boot time, controller configuration only
 persists until XenServer reboot.  The configuration database manager
 can, however, configure controllers for bridges.  See the BUGS section
-of test-controller(8) for more information on this topic.
+of ovs-testcontroller(8) for more information on this topic.
 
 * The Open vSwitch startup script automatically adds a firewall rule
 to allow GRE traffic. This rule is needed for the XenServer feature
diff --git a/NEWS b/NEWS
index fb39811..5059358 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -19,6 +19,9 @@ Post-v2.3.0
      * Nicira extension "move" actions may now be included in action sets.
    - ovsdb-server: New OVSDB protocol extension allows inequality tests on
      "optional scalar" columns.  See ovsdb-server(1) for details.
+   - test-controller has been renamed ovs-testcontroller at request of users
+     who find it useful for testing basic OpenFlow setups.  It is still not
+     a necessary or desirable part of most Open vSwitch deployments.
 
 
 v2.3.0 - 14 Aug 2014
diff --git a/README b/README
index fa41c16..c87357d 100644 (file)
--- a/README
+++ b/README
@@ -72,6 +72,9 @@ Open vSwitch also provides some tools:
     * ovs-pki, a utility for creating and managing the public-key
       infrastructure for OpenFlow switches.
 
+    * ovs-testcontroller, a simple OpenFlow controller that may be useful
+      for testing (though not for production).
+
     * A patch to tcpdump that enables it to parse OpenFlow messages.
 
 What other documentation is available?
index bec9986..e8d9d31 100644 (file)
@@ -16,6 +16,7 @@
 /openvswitch-switch
 /openvswitch-switch.copyright
 /openvswitch-test
+/openvswitch-testcontroller
 /openvswitch-vtep
 /python-openvswitch
 /tmp
index 948a619..86c1310 100644 (file)
@@ -37,6 +37,14 @@ EXTRA_DIST += \
        debian/openvswitch-test.dirs \
        debian/openvswitch-test.install \
        debian/openvswitch-test.manpages \
+       debian/openvswitch-testcontroller.README.Debian \
+       debian/openvswitch-testcontroller.default \
+       debian/openvswitch-testcontroller.dirs \
+       debian/openvswitch-testcontroller.init \
+       debian/openvswitch-testcontroller.install \
+       debian/openvswitch-testcontroller.manpages \
+       debian/openvswitch-testcontroller.postinst \
+       debian/openvswitch-testcontroller.postrm \
        debian/openvswitch-vtep.default \
        debian/openvswitch-vtep.dirs \
        debian/openvswitch-vtep.init \
index 8dd5331..ff2e0bc 100644 (file)
@@ -1,5 +1,10 @@
 openvswitch (2.3.90-1) unstable; urgency=low
    [ Open vSwitch team ]
+   * The openvswitch-testcontroller package is new.  It reintroduces the
+     simple OpenFlow controller that was packaged with Open vSwitch prior to
+     version 2.1, at request of users who find it useful for testing basic
+     OpenFlow setups.  It is still not a necessary or desirable part of most
+     Open vSwitch deployments.
    * New upstream version
     - Nothing yet!  Try NEWS...
 
index af4af4e..0fe7018 100644 (file)
@@ -60,7 +60,8 @@ Description: Open vSwitch common components
  to support distribution across multiple physical servers similar to
  VMware's vNetwork distributed vswitch or Cisco's Nexus 1000V.
  .
- openvswitch-common provides components required by both openvswitch-switch.
+ openvswitch-common provides components required by both openvswitch-switch
+ and openvswitch-testcontroller.
 
 Package: openvswitch-switch
 Architecture: linux-any
@@ -117,6 +118,17 @@ Description: Open vSwitch public key infrastructure dependency package
  Open vSwitch switches and controllers, reducing the risk of
  man-in-the-middle attacks on the Open vSwitch network infrastructure.
 
+Package: openvswitch-testcontroller
+Architecture: linux-any
+Depends:
+ ${shlibs:Depends}, openvswitch-common (= ${binary:Version}),
+ openvswitch-pki (= ${source:Version}), ${misc:Depends}
+Description: Simple controller for testing OpenFlow setups
+ This controller enables OpenFlow switches that connect to it to act
+ as MAC-learning Ethernet switches.  It can be used for initial
+ testing of OpenFlow networks.  It is not a necessary or desirable
+ part of a production OpenFlow deployment.
+
 Package: openvswitch-dbg
 Section: debug
 Architecture: linux-any
@@ -124,6 +136,9 @@ Depends:
  ${shlibs:Depends}, ${misc:Depends},
  openvswitch-common (= ${binary:Version}),
  openvswitch-switch (= ${binary:Version})
+Conflicts:
+ openvswitch-testcontroller (<< ${binary:Version}),
+ openvswitch-testcontroller (>> ${binary:Version})
 Description: Debug symbols for Open vSwitch packages
  Open vSwitch is a production quality, multilayer, software-based,
  Ethernet virtual switch. It is designed to enable massive network
diff --git a/debian/openvswitch-testcontroller.README.Debian b/debian/openvswitch-testcontroller.README.Debian
new file mode 100644 (file)
index 0000000..0548826
--- /dev/null
@@ -0,0 +1,12 @@
+README.Debian for openvswitch-testcontroller
+--------------------------------------------
+
+The controller in this package enables OpenFlow switches that connect
+to it to act as MAC-learning Ethernet switches.  It can be used for
+initial testing of OpenFlow networks.  It is not a necessary or
+desirable part of a production OpenFlow deployment.
+
+To (re)configure the controller, edit /etc/default/openvswitch-testcontroller
+and run "/etc/init.d/openvswitch-testcontroller restart".
+
+ -- Ben Pfaff <pfaffben@debian.org>, Thu, 14 Aug 2014 10:49:34 -0700
diff --git a/debian/openvswitch-testcontroller.default b/debian/openvswitch-testcontroller.default
new file mode 100644 (file)
index 0000000..48b53f1
--- /dev/null
@@ -0,0 +1,29 @@
+# This is a POSIX shell fragment                -*- sh -*-
+
+# LISTEN: What OpenFlow connection methods should the controller listen on?
+#
+# This is a space-delimited list of connection methods:
+#
+# * "pssl:[PORT]": Listen for SSL connections on the specified PORT
+#   (default: 6633).  The private key, certificate, and CA certificate
+#   must be specified below.
+#
+# * "ptcp:[PORT]": Listen for TCP connections on the specified PORT
+#   (default: 6633).  Not recommended for security reasons.
+#
+LISTEN="pssl:"
+
+# PRIVKEY: Name of file containing controller's private key.
+# Required if SSL enabled.
+PRIVKEY=/etc/openvswitch-testcontroller/privkey.pem
+
+# CERT: Name of file containing certificate for private key.
+# Required if SSL enabled.
+CERT=/etc/openvswitch-testcontroller/cert.pem
+
+# CACERT: Name of file containing switch CA certificate.
+# Required if SSL enabled.
+CACERT=/etc/openvswitch-testcontroller/cacert.pem
+
+# Additional options to pass to ovs-testcontroller, e.g. "--hub"
+DAEMON_OPTS=""
diff --git a/debian/openvswitch-testcontroller.dirs b/debian/openvswitch-testcontroller.dirs
new file mode 100644 (file)
index 0000000..d8d4f77
--- /dev/null
@@ -0,0 +1 @@
+etc/openvswitch-testcontroller
diff --git a/debian/openvswitch-testcontroller.init b/debian/openvswitch-testcontroller.init
new file mode 100755 (executable)
index 0000000..67b7a99
--- /dev/null
@@ -0,0 +1,278 @@
+#!/bin/sh
+#
+# Copyright (c) 2011, 2014 Nicira, Inc.
+# Copyright (c) 2007, 2009 Javier Fernandez-Sanguino <jfs@debian.org>
+#
+# This is free software; you may redistribute it and/or modify
+# it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2,
+# or (at your option) any later version.
+#
+# This is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License with
+# the Debian operating system, in /usr/share/common-licenses/GPL;  if
+# not, write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307 USA
+#
+### BEGIN INIT INFO
+# Provides:          openvswitch-testcontroller
+# Required-Start:    $network $local_fs $remote_fs
+# Required-Stop:     $remote_fs
+# Should-Start:      $named
+# Should-Stop:
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Simple OpenFlow controller for testing
+# Description:       This controller enables OpenFlow switches that connect to
+#                    it to act as MAC-learning Ethernet switches.
+### END INIT INFO
+
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+
+DAEMON=/usr/bin/ovs-testcontroller # Introduce the server's location here
+NAME=ovs-testcontroller         # Introduce the short server's name here
+DESC=ovs-testcontroller         # Introduce a short description here
+LOGDIR=/var/log/openvswitch    # Log directory to use
+
+PIDFILE=/var/run/openvswitch/$NAME.pid
+
+test -x $DAEMON || exit 0
+
+. /lib/lsb/init-functions
+
+# Default options, these can be overriden by the information
+# at /etc/default/openvswitch-testcontroller
+DAEMON_OPTS=""          # Additional options given to the server
+
+DODTIME=10              # Time to wait for the server to die, in seconds
+                        # If this value is set too low you might not
+                        # let some servers to die gracefully and
+                        # 'restart' will not work
+
+LOGFILE=$LOGDIR/$NAME.log  # Server logfile
+#DAEMONUSER=            # User to run the daemons as. If this value
+                        # is set start-stop-daemon will chuid the server
+
+# Include defaults if available
+default=/etc/default/openvswitch-testcontroller
+if [ -f $default ] ; then
+    . $default
+fi
+
+# Check that the user exists (if we set a user)
+# Does the user exist?
+if [ -n "$DAEMONUSER" ] ; then
+    if getent passwd | grep -q "^$DAEMONUSER:"; then
+        # Obtain the uid and gid
+        DAEMONUID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $3}'`
+        DAEMONGID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $4}'`
+    else
+        log_failure_msg "The user $DAEMONUSER, required to run $NAME does not exist."
+        exit 1
+    fi
+fi
+
+
+set -e
+
+running_pid() {
+# Check if a given process pid's cmdline matches a given name
+    pid=$1
+    name=$2
+    [ -z "$pid" ] && return 1
+    [ ! -d /proc/$pid ] &&  return 1
+    cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1`
+    # Is this the expected server
+    [ "$cmd" != "$name" ] &&  return 1
+    return 0
+}
+
+running() {
+# Check if the process is running looking at /proc
+# (works for all users)
+
+    # No pidfile, probably no daemon present
+    [ ! -f "$PIDFILE" ] && return 1
+    pid=`cat $PIDFILE`
+    running_pid $pid $DAEMON || return 1
+    return 0
+}
+
+start_server() {
+    if [ -z "$LISTEN" ]; then
+        echo "$default: No connection methods configured, controller disabled" >&2
+        exit 0
+    fi
+
+    if [ ! -d /var/run/openvswitch ]; then
+        install -d -m 755 -o root -g root /var/run/openvswitch
+    fi
+
+    SSL_OPTS=
+    case $LISTEN in
+        *ssl*)
+            : ${PRIVKEY:=/etc/openvswitch-testcontroller/privkey.pem}
+            : ${CERT:=/etc/openvswitch-testcontroller/cert.pem}
+            : ${CACERT:=/etc/openvswitch-testcontroller/cacert.pem}
+            if test ! -e "$PRIVKEY" || test ! -e "$CERT" ||
+                test ! -e "$CACERT"; then
+                if test ! -e "$PRIVKEY"; then
+                    echo "$PRIVKEY: private key missing" >&2
+                fi
+                if test ! -e "$CERT"; then
+                    echo "$CERT: certificate for private key missing" >&2
+                fi
+                if test ! -e "$CACERT"; then
+                    echo "$CACERT: CA certificate missing" >&2
+                fi
+                exit 1
+            fi
+            SSL_OPTS="--private-key=$PRIVKEY --certificate=$CERT --ca-cert=$CACERT"
+            ;;
+    esac
+
+# Start the process using the wrapper
+        if [ -z "$DAEMONUSER" ] ; then
+            start-stop-daemon --start --pidfile $PIDFILE \
+                        --exec $DAEMON -- --detach --pidfile=$PIDFILE \
+                        $LISTEN $DAEMON_OPTS $SSL_OPTS
+            errcode=$?
+        else
+# if we are using a daemonuser then change the user id
+            start-stop-daemon --start --quiet --pidfile $PIDFILE \
+                        --chuid $DAEMONUSER --exec $DAEMON -- \
+                        --detach --pidfile=$PIDFILE $LISTEN $DAEMON_OPTS \
+                        $SSL_OPTS
+            errcode=$?
+        fi
+        return $errcode
+}
+
+stop_server() {
+# Stop the process using the wrapper
+        if [ -z "$DAEMONUSER" ] ; then
+            start-stop-daemon --stop --quiet --pidfile $PIDFILE \
+                        --exec $DAEMON
+            errcode=$?
+        else
+# if we are using a daemonuser then look for process that match
+            start-stop-daemon --stop --quiet --pidfile $PIDFILE \
+                        --user $DAEMONUSER --exec $DAEMON
+            errcode=$?
+        fi
+
+        return $errcode
+}
+
+reload_server() {
+    [ ! -f "$PIDFILE" ] && return 1
+    pid=`cat $PIDFILE` # This is the daemon's pid
+    # Send a SIGHUP
+    kill -1 $pid
+    return $?
+}
+
+force_stop() {
+# Force the process to die killing it manually
+    [ ! -e "$PIDFILE" ] && return
+    if running ; then
+        kill -15 $pid
+        # Is it really dead?
+        sleep "$DODTIME"
+        if running ; then
+            kill -9 $pid
+            sleep "$DODTIME"
+            if running ; then
+                echo "Cannot kill $NAME (pid=$pid)!"
+                exit 1
+            fi
+        fi
+    fi
+    rm -f $PIDFILE
+}
+
+
+case "$1" in
+  start)
+        log_daemon_msg "Starting $DESC " "$NAME"
+        # Check if it's running first
+        if running ;  then
+            log_progress_msg "apparently already running"
+            log_end_msg 0
+            exit 0
+        fi
+        if start_server && running ;  then
+            # It's ok, the server started and is running
+            log_end_msg 0
+        else
+            # Either we could not start it or it is not running
+            # after we did
+            # NOTE: Some servers might die some time after they start,
+            # this code does not try to detect this and might give
+            # a false positive (use 'status' for that)
+            log_end_msg 1
+        fi
+        ;;
+  stop)
+        log_daemon_msg "Stopping $DESC" "$NAME"
+        if running ; then
+            # Only stop the server if we see it running
+            stop_server
+            log_end_msg $?
+        else
+            # If it's not running don't do anything
+            log_progress_msg "apparently not running"
+            log_end_msg 0
+            exit 0
+        fi
+        ;;
+  force-stop)
+        # First try to stop gracefully the program
+        $0 stop
+        if running; then
+            # If it's still running try to kill it more forcefully
+            log_daemon_msg "Stopping (force) $DESC" "$NAME"
+            force_stop
+            log_end_msg $?
+        fi
+        ;;
+  restart|force-reload)
+        log_daemon_msg "Restarting $DESC" "$NAME"
+        if running; then
+            stop_server
+            # Wait some sensible amount, some server need this.
+            [ -n "$DODTIME" ] && sleep $DODTIME
+        fi
+        start_server
+        running
+        log_end_msg $?
+        ;;
+  status)
+
+        log_daemon_msg "Checking status of $DESC" "$NAME"
+        if running ;  then
+            log_progress_msg "running"
+            log_end_msg 0
+        else
+            log_progress_msg "apparently not running"
+            log_end_msg 1
+            exit 1
+        fi
+        ;;
+  # Use this if the daemon cannot reload
+  reload)
+        log_warning_msg "Reloading $NAME daemon: not implemented, as the daemon"
+        log_warning_msg "cannot re-read the config file (use restart)."
+        ;;
+  *)
+        N=/etc/init.d/openvswitch-testcontroller
+        echo "Usage: $N {start|stop|force-stop|restart|force-reload|status}" >&2
+        exit 1
+        ;;
+esac
+
+exit 0
diff --git a/debian/openvswitch-testcontroller.install b/debian/openvswitch-testcontroller.install
new file mode 100644 (file)
index 0000000..d368f2a
--- /dev/null
@@ -0,0 +1 @@
+usr/bin/ovs-testcontroller
diff --git a/debian/openvswitch-testcontroller.manpages b/debian/openvswitch-testcontroller.manpages
new file mode 100644 (file)
index 0000000..4ea1781
--- /dev/null
@@ -0,0 +1 @@
+_debian/utilities/ovs-testcontroller.8
diff --git a/debian/openvswitch-testcontroller.postinst b/debian/openvswitch-testcontroller.postinst
new file mode 100755 (executable)
index 0000000..7242b4a
--- /dev/null
@@ -0,0 +1,60 @@
+#!/bin/sh
+# postinst script for openvswitch-testcontroller
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <postinst> `configure' <most-recently-configured-version>
+#        * <old-postinst> `abort-upgrade' <new version>
+#        * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+#          <new-version>
+#        * <postinst> `abort-remove'
+#        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+#          <failed-install-package> <version> `removing'
+#          <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+    configure)
+        cd /etc/openvswitch-testcontroller
+
+        # If cacert.pem is a symlink to the old location for cacert.pem,
+        # remove it so that we can symlink it to the new location.
+        if test -h cacert.pem && \
+           test X"`readlink cacert.pem`" = X/usr/share/openvswitch/pki/switchca/cacert.pem; then
+            rm -f cacert.pem
+        fi
+
+        if ! test -e cacert.pem; then
+            ln -s /var/lib/openvswitch/pki/switchca/cacert.pem cacert.pem
+        fi
+        if ! test -e privkey.pem || ! test -e cert.pem; then
+            oldumask=$(umask)
+            umask 077
+            ovs-pki req+sign tmp controller >/dev/null
+            mv tmp-privkey.pem privkey.pem
+            mv tmp-cert.pem cert.pem
+            mv tmp-req.pem req.pem
+            chmod go+r cert.pem req.pem
+            umask $oldumask
+        fi
+        ;;
+
+    abort-upgrade|abort-remove|abort-deconfigure)
+        ;;
+
+    *)
+        echo "postinst called with unknown argument \`$1'" >&2
+        exit 1
+        ;;
+esac
+
+#DEBHELPER#
+
+exit 0
+
+
diff --git a/debian/openvswitch-testcontroller.postrm b/debian/openvswitch-testcontroller.postrm
new file mode 100755 (executable)
index 0000000..afca1bb
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/sh
+# postrm script for openvswitch-testcontroller
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+#        * <postrm> `remove'
+#        * <postrm> `purge'
+#        * <old-postrm> `upgrade' <new-version>
+#        * <new-postrm> `failed-upgrade' <old-version>
+#        * <new-postrm> `abort-install'
+#        * <new-postrm> `abort-install' <old-version>
+#        * <new-postrm> `abort-upgrade' <old-version>
+#        * <disappearer's-postrm> `disappear' <overwriter>
+#          <overwriter-version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+
+case "$1" in
+    purge)
+        if cd /etc/openvswitch-testcontroller; then
+            rm -f cacert.pem cert.pem privkey.pem req.pem
+            rm -f tmp-privkey.pem tmp-cert.pem tmp-req.pem
+        fi
+        ;;
+
+    remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
+        ;;
+
+    *)
+        echo "postrm called with unknown argument \`$1'" >&2
+        exit 1
+        ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
index 446b30a..b21ec41 100644 (file)
@@ -84,26 +84,6 @@ lib/common.man:
 lib/vlog-syn.man:
 lib/vlog.man:
 
-tests/test-controller.8: \
-       tests/test-controller.8.in \
-       lib/common.man \
-       lib/daemon.man \
-       lib/ssl-peer-ca-cert.man \
-       lib/ssl.man \
-       lib/unixctl.man \
-       lib/vconn-active.man \
-       lib/vconn-passive.man \
-       lib/vlog.man
-tests/test-controller.8.in:
-lib/common.man:
-lib/daemon.man:
-lib/ssl-peer-ca-cert.man:
-lib/ssl.man:
-lib/unixctl.man:
-lib/vconn-active.man:
-lib/vconn-passive.man:
-lib/vlog.man:
-
 utilities/bugtool/ovs-bugtool.8: \
        utilities/bugtool/ovs-bugtool.8.in
 utilities/bugtool/ovs-bugtool.8.in:
@@ -190,6 +170,26 @@ lib/common-syn.man:
 lib/common.man:
 utilities/ovs-vlan-bugs.man:
 
+utilities/ovs-testcontroller.8: \
+       utilities/ovs-testcontroller.8.in \
+       lib/common.man \
+       lib/daemon.man \
+       lib/ssl-peer-ca-cert.man \
+       lib/ssl.man \
+       lib/unixctl.man \
+       lib/vconn-active.man \
+       lib/vconn-passive.man \
+       lib/vlog.man
+utilities/ovs-testcontroller.8.in:
+lib/common.man:
+lib/daemon.man:
+lib/ssl-peer-ca-cert.man:
+lib/ssl.man:
+lib/unixctl.man:
+lib/vconn-active.man:
+lib/vconn-passive.man:
+lib/vlog.man:
+
 utilities/ovs-vlan-bug-workaround.8: \
        utilities/ovs-vlan-bug-workaround.8.in \
        lib/common.man \
index 9f66f41..0efebd4 100644 (file)
@@ -179,10 +179,12 @@ systemctl start openvswitch.service
 /usr/bin/ovs-vsctl
 /usr/bin/ovsdb-client
 /usr/bin/ovsdb-tool
+/usr/bin/ovs-testcontroller
 /usr/bin/ovs-pki
 /usr/bin/ovs-test
 /usr/bin/ovs-l3ping
 /usr/bin/vtep-ctl
+%doc /usr/share/man/man8/ovs-testcontroller.8.gz
 %doc /usr/share/man/man8/ovs-pki.8.gz
 %doc /usr/share/man/man1/ovsdb-client.1.gz
 %doc /usr/share/man/man1/ovsdb-server.1.gz
index 251cfe5..88bc673 100644 (file)
@@ -1,6 +1,6 @@
 # Spec file for Open vSwitch on Red Hat Enterprise Linux.
 
-# Copyright (C) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
 #
 # Copying and distribution of this file, with or without modification,
 # are permitted in any medium without royalty provided the copyright
@@ -60,6 +60,8 @@ install python/compat/argparse.py $RPM_BUILD_ROOT/usr/share/openvswitch/python
 
 # Get rid of stuff we don't want to make RPM happy.
 rm \
+    $RPM_BUILD_ROOT/usr/bin/ovs-testcontroller \
+    $RPM_BUILD_ROOT/usr/share/man/man8/ovs-testcontroller.8 \
     $RPM_BUILD_ROOT/usr/bin/ovs-test \
     $RPM_BUILD_ROOT/usr/bin/ovs-l3ping \
     $RPM_BUILD_ROOT/usr/share/man/man8/ovs-test.8 \
index 5b55a7d..7c98061 100644 (file)
@@ -14,8 +14,6 @@
 /test-bundle
 /test-byte-order
 /test-classifier
-/test-controller.8
-/test-controller
 /test-csum
 /test-flows
 /test-hash
index 2b88ad2..470c1b9 100644 (file)
@@ -181,13 +181,6 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
          echo 'm4_define([AT_PACKAGE_BUGREPORT], [$(PACKAGE_BUGREPORT)])'; \
        } >'$(srcdir)/package.m4'
 
-noinst_PROGRAMS += tests/test-controller
-MAN_ROOTS += tests/test-controller.8.in
-DISTCLEANFILES += tests/test-controller.8
-noinst_man_MANS += tests/test-controller.8
-tests_test_controller_SOURCES = tests/test-controller.c
-tests_test_controller_LDADD = lib/libopenvswitch.la
-
 noinst_PROGRAMS += tests/test-ovsdb
 tests_test_ovsdb_SOURCES = \
        tests/test-ovsdb.c \
diff --git a/tests/test-controller.8.in b/tests/test-controller.8.in
deleted file mode 100644 (file)
index 62bfa0f..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-                         .\" -*- nroff -*-
-.de IQ
-.  br
-.  ns
-.  IP "\\$1"
-..
-.TH test\-controller 8 "@VERSION@" "Open vSwitch" "Open vSwitch Manual"
-.ds PN test\-controller
-.
-.SH NAME
-test\-controller \- simple OpenFlow controller for testing
-.
-.SH SYNOPSIS
-.B test\-controller
-[\fIoptions\fR] \fImethod\fR \fB[\fImethod\fR]\&...
-.
-.SH DESCRIPTION
-.PP
-\fBtest\-controller\fR is a simple OpenFlow controller.  It is very
-easy to set up, so it may be suitable for initial testing of
-connectivity between an OpenFlow switch and a controller.  It may also
-be useful for developer testing and debugging of some Open vSwitch
-features.
-.PP
-\fBtest\-controller\fR is not a general-purpose OpenFlow controller.
-It does not make sense to deploy it routinely or in production.
-\fBtest\-controller\fR does not provide any features that are not
-built into Open vSwitch, and lacks many that are built in to Open
-vSwitch, so adding it to an Open vSwitch deployment actually reduces
-functionality and performance while increasing latency.
-.PP
-\fBtest\-controller\fR manages any number of remote switches over
-OpenFlow protocol, causing them to function as L2 MAC-learning
-switches or hub.  The switches it controls are specified as one or
-more of the following OpenFlow connection methods:
-.
-.RS
-.so lib/vconn-passive.man
-.so lib/vconn-active.man
-.RE
-.
-.SH OPTIONS
-.IP "\fB\-n\fR"
-.IQ "\fB\-\-noflow\fR"
-By default, \fBtest\-controller\fR sets up a flow in each OpenFlow switch
-whenever it receives a packet whose destination is known due through
-MAC learning.  This option disables flow setup, so that every packet
-in the network passes through the controller.
-.IP
-This option is most useful for debugging.  It reduces switching
-performance, so it should not be used in production.
-.
-.TP
-\fB\-\-max\-idle=\fIsecs\fR|\fBpermanent\fR
-Sets \fIsecs\fR as the number of seconds that a flow set up by the
-controller will remain in the switch's flow table without any matching
-packets being seen.  If \fBpermanent\fR is specified, which is not
-recommended, flows will never expire.  The default is 60 seconds.
-.IP
-This option has no effect when \fB\-n\fR (or \fB\-\-noflow\fR) is in use
-(because the controller does not set up flows in that case).
-.
-.IP "\fB\-H\fR"
-.IQ "\fB\-\-hub\fR"
-By default, the controller acts as an L2 MAC-learning switch.  This
-option changes its behavior to that of a hub that floods packets on
-all but the incoming port.
-.IP
-If \fB\-H\fR (or \fB\-\-hub\fR) and \fB\-n\fR (or \fB\-\-noflow\fR) are used
-together, then the cumulative effect is that every packet passes
-through the controller and every packet is flooded.
-.IP
-This option is most useful for debugging.  It reduces switching
-performance, so it should not be used in production.
-.
-.IP "\fB\-w\fR[\fIwildcard_mask\fR]"
-.IQ "\fB\-\-wildcards\fR[\fB=\fIwildcard_mask\fR]\fR"
-By default, \fBtest\-controller\fR sets up exact-match flows.  This
-option allows it to set up wildcarded flows, which may reduce
-flow setup latency by causing less traffic to be sent up to the
-controller.
-.IP
-The optional \fIwildcard_mask\fR is an OpenFlow wildcard bitmask in
-hexadecimal that specifies the fields to wildcard.  If no
-\fIwildcard_mask\fR is specified, the default value 0x2820F0 is used
-which specifies L2-only switching and wildcards L3 and L4 fields.
-Another interesting value is 0x2000EC, which specifies L3-only
-switching and wildcards L2 and L4 fields.
-.IP
-This option has no effect when \fB\-n\fR (or \fB\-\-noflow\fR) is in use
-(because the controller does not set up flows in that case).
-.
-.IP "\fB\-N\fR"
-.IQ "\fB\-\-normal\fR"
-By default, \fBtest\-controller\fR directs packets to a particular port
-or floods them.  This option causes it to direct non-flooded packets
-to the OpenFlow \fBOFPP_NORMAL\fR port.  This allows the switch itself
-to make decisions about packet destinations.  Support for
-\fBOFPP_NORMAL\fR is optional in OpenFlow, so this option may not well
-with some non-Open vSwitch switches.
-.
-.IP "\fB\-\-mute\fR"
-Prevents test\-controller from replying to any OpenFlow messages sent
-to it by switches.
-.IP
-This option is only for debugging the Open vSwitch implementation of
-``fail open'' mode.  It must not be used in production.
-.
-.IP "\fB\-q \fIid\fR"
-.IQ "\fB\-\-queue=\fIid\fR"
-By default, \fBtest\-controller\fR uses the default OpenFlow queue for
-sending packets and setting up flows.  Use one of these options,
-supplying \fIid\fR as an OpenFlow queue ID as a decimal number, to
-instead use that specific queue.
-.IP
-This option is incompatible with \fB\-N\fR or \fB\-\-normal\fR and
-with \fB\-H\fR or \fB\-\-hub\fR.  If more than one is specified then
-this option takes precedence.
-.IP
-This option may be useful for testing or debugging quality of service
-setups.
-.
-.IP "\fB\-Q \fIport-name\fB:\fIqueue-id\fR"
-.IP "\fB\-\-port\-queue \fIport-name\fB:\fIqueue-id\fR"
-Configures packets received on the port named \fIport-name\fR
-(e.g. \fBeth0\fR) to be output on OpenFlow queue ID \fIqueue-id\fR
-(specified as a decimal number).  For the specified port, this option
-overrides the default specified on \fB\-q\fR or \fB\-\-queue\fR.
-.IP
-This option may be specified any number of times with different
-\fIport-name\fR arguments.
-.IP
-This option is incompatible with \fB\-N\fR or \fB\-\-normal\fR and
-with \fB\-H\fR or \fB\-\-hub\fR.  If more than one is specified then
-this option takes precedence.
-.IP
-This option may be useful for testing or debugging quality of service
-setups.
-.
-.IP "\fB\-\-with\-flows \fIfile\fR"
-When a switch connects, push the flow entries as described in
-\fIfile\fR.  Each line in \fIfile\fR is a flow entry in the format
-described for the \fBadd\-flows\fR command in the \fBFlow Syntax\fR
-section of the \fBovs\-ofctl\fR(8) man page.
-.IP
-Use this option more than once to add flows from multiple files.
-.
-.SS "Public Key Infrastructure Options"
-.so lib/ssl.man
-.so lib/ssl-peer-ca-cert.man
-.ds DD
-.so lib/daemon.man
-.so lib/vlog.man
-.so lib/unixctl.man
-.so lib/common.man
-.so so lib/ofp-version.man
-.
-.SH EXAMPLES
-.PP
-To bind locally to port 6633 (the default) and wait for incoming
-connections from OpenFlow switches:
-.IP
-\fB% test\-controller ptcp:\fR
-.PP
-In the future, the default port number will change to 6653, which is the
-IANA-defined value.
-.SH "BUGS"
-.PP
-Configuring a Citrix XenServer to connect to a particular controller
-only points the remote OVSDB management connection to that controller.
-It does not also configure OpenFlow connections, because the manager
-is expected to do that over the management protocol.
-\fBtest\-controller\fR is not an Open vSwitch manager and does not know
-how to do that.
-.PP
-As a stopgap workaround, \fBovs\-vsctl\fR can wait for an OVSDB
-connection and set the controller, e.g.:
-.IP
-\fB% ovs\-vsctl \-t0 \-\-db=pssl: \-\-certificate=cert.pem
-\-\-ca\-cert=none \-\-private\-key=privkey.pem
-\-\-peer\-ca\-cert=cacert.pem set\-controller ssl:\fIip\fR
-.SH "SEE ALSO"
-.
-.BR ovs\-appctl (8),
-.BR ovs\-ofctl (8),
-.BR ovs\-dpctl (8)
diff --git a/tests/test-controller.c b/tests/test-controller.c
deleted file mode 100644 (file)
index a615ab4..0000000
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 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.
- */
-
-#include <config.h>
-
-#include <errno.h>
-#include <getopt.h>
-#include <limits.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "command-line.h"
-#include "compiler.h"
-#include "daemon.h"
-#include "fatal-signal.h"
-#include "learning-switch.h"
-#include "ofp-parse.h"
-#include "ofp-version-opt.h"
-#include "ofpbuf.h"
-#include "openflow/openflow.h"
-#include "poll-loop.h"
-#include "rconn.h"
-#include "simap.h"
-#include "stream-ssl.h"
-#include "timeval.h"
-#include "unixctl.h"
-#include "util.h"
-#include "vconn.h"
-#include "vlog.h"
-#include "socket-util.h"
-#include "ofp-util.h"
-
-VLOG_DEFINE_THIS_MODULE(controller);
-
-#define MAX_SWITCHES 16
-#define MAX_LISTENERS 16
-
-struct switch_ {
-    struct lswitch *lswitch;
-};
-
-/* -H, --hub: Learn the ports on which MAC addresses appear? */
-static bool learn_macs = true;
-
-/* -n, --noflow: Set up flows?  (If not, every packet is processed at the
- * controller.) */
-static bool set_up_flows = true;
-
-/* -N, --normal: Use "NORMAL" action instead of explicit port? */
-static bool action_normal = false;
-
-/* -w, --wildcard: 0 to disable wildcard flow entries, an OFPFW10_* bitmask to
- * enable specific wildcards, or UINT32_MAX to use the default wildcards. */
-static uint32_t wildcards = 0;
-
-/* --max-idle: Maximum idle time, in seconds, before flows expire. */
-static int max_idle = 60;
-
-/* --mute: If true, accept connections from switches but do not reply to any
- * of their messages (for debugging fail-open mode). */
-static bool mute = false;
-
-/* -q, --queue: default OpenFlow queue, none if UINT32_MAX. */
-static uint32_t default_queue = UINT32_MAX;
-
-/* -Q, --port-queue: map from port name to port number. */
-static struct simap port_queues = SIMAP_INITIALIZER(&port_queues);
-
-/* --with-flows: Flows to send to switch. */
-static struct ofputil_flow_mod *default_flows;
-static size_t n_default_flows;
-static enum ofputil_protocol usable_protocols;
-
-/* --unixctl: Name of unixctl socket, or null to use the default. */
-static char *unixctl_path = NULL;
-
-static void new_switch(struct switch_ *, struct vconn *);
-static void parse_options(int argc, char *argv[]);
-static void usage(void) NO_RETURN;
-
-int
-main(int argc, char *argv[])
-{
-    struct unixctl_server *unixctl;
-    struct switch_ switches[MAX_SWITCHES];
-    struct pvconn *listeners[MAX_LISTENERS];
-    int n_switches, n_listeners;
-    int retval;
-    int i;
-
-    proctitle_init(argc, argv);
-    set_program_name(argv[0]);
-    parse_options(argc, argv);
-    fatal_ignore_sigpipe();
-
-    if (argc - optind < 1) {
-        ovs_fatal(0, "at least one vconn argument required; "
-                  "use --help for usage");
-    }
-
-    n_switches = n_listeners = 0;
-    for (i = optind; i < argc; i++) {
-        const char *name = argv[i];
-        struct vconn *vconn;
-
-        retval = vconn_open(name, get_allowed_ofp_versions(), DSCP_DEFAULT,
-                            &vconn);
-        if (!retval) {
-            if (n_switches >= MAX_SWITCHES) {
-                ovs_fatal(0, "max %d switch connections", n_switches);
-            }
-            new_switch(&switches[n_switches++], vconn);
-            continue;
-        } else if (retval == EAFNOSUPPORT) {
-            struct pvconn *pvconn;
-            retval = pvconn_open(name, get_allowed_ofp_versions(),
-                                 DSCP_DEFAULT, &pvconn);
-            if (!retval) {
-                if (n_listeners >= MAX_LISTENERS) {
-                    ovs_fatal(0, "max %d passive connections", n_listeners);
-                }
-                listeners[n_listeners++] = pvconn;
-            }
-        }
-        if (retval) {
-            VLOG_ERR("%s: connect: %s", name, ovs_strerror(retval));
-        }
-    }
-    if (n_switches == 0 && n_listeners == 0) {
-        ovs_fatal(0, "no active or passive switch connections");
-    }
-
-    daemonize_start();
-
-    retval = unixctl_server_create(unixctl_path, &unixctl);
-    if (retval) {
-        exit(EXIT_FAILURE);
-    }
-
-    daemonize_complete();
-
-    while (n_switches > 0 || n_listeners > 0) {
-        /* Accept connections on listening vconns. */
-        for (i = 0; i < n_listeners && n_switches < MAX_SWITCHES; ) {
-            struct vconn *new_vconn;
-
-            retval = pvconn_accept(listeners[i], &new_vconn);
-            if (!retval || retval == EAGAIN) {
-                if (!retval) {
-                    new_switch(&switches[n_switches++], new_vconn);
-                }
-                i++;
-            } else {
-                pvconn_close(listeners[i]);
-                listeners[i] = listeners[--n_listeners];
-            }
-        }
-
-        /* Do some switching work.  . */
-        for (i = 0; i < n_switches; ) {
-            struct switch_ *this = &switches[i];
-            lswitch_run(this->lswitch);
-            if (lswitch_is_alive(this->lswitch)) {
-                i++;
-            } else {
-                lswitch_destroy(this->lswitch);
-                switches[i] = switches[--n_switches];
-            }
-        }
-
-        unixctl_server_run(unixctl);
-
-        /* Wait for something to happen. */
-        if (n_switches < MAX_SWITCHES) {
-            for (i = 0; i < n_listeners; i++) {
-                pvconn_wait(listeners[i]);
-            }
-        }
-        for (i = 0; i < n_switches; i++) {
-            struct switch_ *sw = &switches[i];
-            lswitch_wait(sw->lswitch);
-        }
-        unixctl_server_wait(unixctl);
-        poll_block();
-    }
-
-    return 0;
-}
-
-static void
-new_switch(struct switch_ *sw, struct vconn *vconn)
-{
-    struct lswitch_config cfg;
-    struct rconn *rconn;
-
-    rconn = rconn_create(60, 0, DSCP_DEFAULT, get_allowed_ofp_versions());
-    rconn_connect_unreliably(rconn, vconn, NULL);
-
-    cfg.mode = (action_normal ? LSW_NORMAL
-                : learn_macs ? LSW_LEARN
-                : LSW_FLOOD);
-    cfg.wildcards = wildcards;
-    cfg.max_idle = set_up_flows ? max_idle : -1;
-    cfg.default_flows = default_flows;
-    cfg.n_default_flows = n_default_flows;
-    cfg.usable_protocols = usable_protocols;
-    cfg.default_queue = default_queue;
-    cfg.port_queues = &port_queues;
-    cfg.mute = mute;
-    sw->lswitch = lswitch_create(rconn, &cfg);
-}
-
-static void
-add_port_queue(char *s)
-{
-    char *save_ptr = NULL;
-    char *port_name;
-    char *queue_id;
-
-    port_name = strtok_r(s, ":", &save_ptr);
-    queue_id = strtok_r(NULL, "", &save_ptr);
-    if (!queue_id) {
-        ovs_fatal(0, "argument to -Q or --port-queue should take the form "
-                  "\"<port-name>:<queue-id>\"");
-    }
-
-    if (!simap_put(&port_queues, port_name, atoi(queue_id))) {
-        ovs_fatal(0, "<port-name> arguments for -Q or --port-queue must "
-                  "be unique");
-    }
-}
-
-static void
-parse_options(int argc, char *argv[])
-{
-    enum {
-        OPT_MAX_IDLE = UCHAR_MAX + 1,
-        OPT_PEER_CA_CERT,
-        OPT_MUTE,
-        OPT_WITH_FLOWS,
-        OPT_UNIXCTL,
-        VLOG_OPTION_ENUMS,
-        DAEMON_OPTION_ENUMS,
-        OFP_VERSION_OPTION_ENUMS
-    };
-    static const struct option long_options[] = {
-        {"hub",         no_argument, NULL, 'H'},
-        {"noflow",      no_argument, NULL, 'n'},
-        {"normal",      no_argument, NULL, 'N'},
-        {"wildcards",   optional_argument, NULL, 'w'},
-        {"max-idle",    required_argument, NULL, OPT_MAX_IDLE},
-        {"mute",        no_argument, NULL, OPT_MUTE},
-        {"queue",       required_argument, NULL, 'q'},
-        {"port-queue",  required_argument, NULL, 'Q'},
-        {"with-flows",  required_argument, NULL, OPT_WITH_FLOWS},
-        {"unixctl",     required_argument, NULL, OPT_UNIXCTL},
-        {"help",        no_argument, NULL, 'h'},
-        DAEMON_LONG_OPTIONS,
-        OFP_VERSION_LONG_OPTIONS,
-        VLOG_LONG_OPTIONS,
-        STREAM_SSL_LONG_OPTIONS,
-        {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
-        {NULL, 0, NULL, 0},
-    };
-    char *short_options = long_options_to_short_options(long_options);
-
-    for (;;) {
-        int indexptr;
-        char *error;
-        int c;
-
-        c = getopt_long(argc, argv, short_options, long_options, &indexptr);
-        if (c == -1) {
-            break;
-        }
-
-        switch (c) {
-        case 'H':
-            learn_macs = false;
-            break;
-
-        case 'n':
-            set_up_flows = false;
-            break;
-
-        case OPT_MUTE:
-            mute = true;
-            break;
-
-        case 'N':
-            action_normal = true;
-            break;
-
-        case 'w':
-            wildcards = optarg ? strtol(optarg, NULL, 16) : UINT32_MAX;
-            break;
-
-        case OPT_MAX_IDLE:
-            if (!strcmp(optarg, "permanent")) {
-                max_idle = OFP_FLOW_PERMANENT;
-            } else {
-                max_idle = atoi(optarg);
-                if (max_idle < 1 || max_idle > 65535) {
-                    ovs_fatal(0, "--max-idle argument must be between 1 and "
-                              "65535 or the word 'permanent'");
-                }
-            }
-            break;
-
-        case 'q':
-            default_queue = atoi(optarg);
-            break;
-
-        case 'Q':
-            add_port_queue(optarg);
-            break;
-
-        case OPT_WITH_FLOWS:
-            error = parse_ofp_flow_mod_file(optarg, OFPFC_ADD, &default_flows,
-                                            &n_default_flows,
-                                            &usable_protocols);
-            if (error) {
-                ovs_fatal(0, "%s", error);
-            }
-            break;
-
-        case OPT_UNIXCTL:
-            unixctl_path = optarg;
-            break;
-
-        case 'h':
-            usage();
-
-        VLOG_OPTION_HANDLERS
-        OFP_VERSION_OPTION_HANDLERS
-        DAEMON_OPTION_HANDLERS
-
-        STREAM_SSL_OPTION_HANDLERS
-
-        case OPT_PEER_CA_CERT:
-            stream_ssl_set_peer_ca_cert_file(optarg);
-            break;
-
-        case '?':
-            exit(EXIT_FAILURE);
-
-        default:
-            abort();
-        }
-    }
-    free(short_options);
-
-    if (!simap_is_empty(&port_queues) || default_queue != UINT32_MAX) {
-        if (action_normal) {
-            ovs_error(0, "queue IDs are incompatible with -N or --normal; "
-                      "not using OFPP_NORMAL");
-            action_normal = false;
-        }
-
-        if (!learn_macs) {
-            ovs_error(0, "queue IDs are incompatible with -H or --hub; "
-                      "not acting as hub");
-            learn_macs = true;
-        }
-    }
-}
-
-static void
-usage(void)
-{
-    printf("%s: OpenFlow controller\n"
-           "usage: %s [OPTIONS] METHOD\n"
-           "where METHOD is any OpenFlow connection method.\n",
-           program_name, program_name);
-    vconn_usage(true, true, false);
-    daemon_usage();
-    ofp_version_usage();
-    vlog_usage();
-    printf("\nOther options:\n"
-           "  -H, --hub               act as hub instead of learning switch\n"
-           "  -n, --noflow            pass traffic, but don't add flows\n"
-           "  --max-idle=SECS         max idle time for new flows\n"
-           "  -N, --normal            use OFPP_NORMAL action\n"
-           "  -w, --wildcards[=MASK]  wildcard (specified) bits in flows\n"
-           "  -q, --queue=QUEUE-ID    OpenFlow queue ID to use for output\n"
-           "  -Q PORT-NAME:QUEUE-ID   use QUEUE-ID for frames from PORT-NAME\n"
-           "  --with-flows FILE       use the flows from FILE\n"
-           "  --unixctl=SOCKET        override default control socket name\n"
-           "  -h, --help              display this help message\n"
-           "  -V, --version           display version information\n");
-    exit(EXIT_SUCCESS);
-}
index d2baa66..dda889b 100644 (file)
@@ -8,6 +8,8 @@
 /ovs-cfg-mod
 /ovs-cfg-mod.8
 /ovs-check-dead-ifs
+/ovs-testcontroller
+/ovs-testcontroller.8
 /ovs-ctl
 /ovs-dpctl
 /ovs-dpctl.8
index 3e38e37..87ccb98 100644 (file)
@@ -1,5 +1,6 @@
 bin_PROGRAMS += \
        utilities/ovs-appctl \
+       utilities/ovs-testcontroller \
        utilities/ovs-dpctl \
        utilities/ovs-ofctl \
        utilities/ovs-vsctl
@@ -39,6 +40,7 @@ EXTRA_DIST += \
 MAN_ROOTS += \
        utilities/ovs-appctl.8.in \
        utilities/ovs-benchmark.1.in \
+       utilities/ovs-testcontroller.8.in \
        utilities/ovs-ctl.8 \
        utilities/ovs-dpctl.8.in \
        utilities/ovs-dpctl-top.8.in \
@@ -58,6 +60,7 @@ DISTCLEANFILES += \
        utilities/ovs-ctl \
        utilities/ovs-benchmark.1 \
        utilities/ovs-check-dead-ifs \
+       utilities/ovs-testcontroller.8 \
        utilities/ovs-dpctl.8 \
        utilities/ovs-dpctl-top \
        utilities/ovs-dpctl-top.8 \
@@ -83,6 +86,7 @@ man_MANS += \
        utilities/ovs-appctl.8 \
        utilities/ovs-benchmark.1 \
        utilities/ovs-ctl.8 \
+       utilities/ovs-testcontroller.8 \
        utilities/ovs-dpctl.8 \
        utilities/ovs-dpctl-top.8 \
        utilities/ovs-l3ping.8 \
@@ -99,6 +103,9 @@ man_MANS += \
 utilities_ovs_appctl_SOURCES = utilities/ovs-appctl.c
 utilities_ovs_appctl_LDADD = lib/libopenvswitch.la
 
+utilities_ovs_testcontroller_SOURCES = utilities/ovs-testcontroller.c
+utilities_ovs_testcontroller_LDADD = lib/libopenvswitch.la $(SSL_LIBS)
+
 utilities_ovs_dpctl_SOURCES = utilities/ovs-dpctl.c
 utilities_ovs_dpctl_LDADD = lib/libopenvswitch.la
 
diff --git a/utilities/ovs-testcontroller.8.in b/utilities/ovs-testcontroller.8.in
new file mode 100644 (file)
index 0000000..18e0898
--- /dev/null
@@ -0,0 +1,176 @@
+.\" -*- nroff -*-
+.de IQ
+.  br
+.  ns
+.  IP "\\$1"
+..
+.TH ovs\-testcontroller 8 "@VERSION@" "Open vSwitch" "Open vSwitch Manual"
+.ds PN ovs\-testcontroller
+.
+.SH NAME
+ovs\-testcontroller \- simple OpenFlow controller for testing
+.
+.SH SYNOPSIS
+.B ovs\-testcontroller
+[\fIoptions\fR] \fImethod\fR \fB[\fImethod\fR]\&...
+.
+.SH DESCRIPTION
+\fBovs\-testcontroller\fR is a simple OpenFlow controller that manages
+any number of switches over the OpenFlow protocol, causing them to
+function as L2 MAC-learning switches or hubs.  It is suitable for
+initial testing of OpenFlow networks.  It is not a necessary or
+desirable part of a production OpenFlow deployment.
+.PP
+\fBovs\-testcontroller\fR controls one or more OpenFlow switches, specified as
+one or more of the following OpenFlow connection methods:
+.
+.RS
+.so lib/vconn-passive.man
+.so lib/vconn-active.man
+.RE
+.
+.SH OPTIONS
+.IP "\fB\-n\fR"
+.IQ "\fB\-\-noflow\fR"
+By default, \fBovs\-testcontroller\fR sets up a flow in each OpenFlow switch
+whenever it receives a packet whose destination is known due through
+MAC learning.  This option disables flow setup, so that every packet
+in the network passes through the controller.
+.IP
+This option is most useful for debugging.  It reduces switching
+performance, so it should not be used in production.
+.
+.TP
+\fB\-\-max\-idle=\fIsecs\fR|\fBpermanent\fR
+Sets \fIsecs\fR as the number of seconds that a flow set up by the
+controller will remain in the switch's flow table without any matching
+packets being seen.  If \fBpermanent\fR is specified, which is not
+recommended, flows will never expire.  The default is 60 seconds.
+.IP
+This option has no effect when \fB\-n\fR (or \fB\-\-noflow\fR) is in use
+(because the controller does not set up flows in that case).
+.
+.IP "\fB\-H\fR"
+.IQ "\fB\-\-hub\fR"
+By default, the controller acts as an L2 MAC-learning switch.  This
+option changes its behavior to that of a hub that floods packets on
+all but the incoming port.
+.IP
+If \fB\-H\fR (or \fB\-\-hub\fR) and \fB\-n\fR (or \fB\-\-noflow\fR) are used
+together, then the cumulative effect is that every packet passes
+through the controller and every packet is flooded.
+.IP
+This option is most useful for debugging.  It reduces switching
+performance, so it should not be used in production.
+.
+.IP "\fB\-w\fR[\fIwildcard_mask\fR]"
+.IQ "\fB\-\-wildcards\fR[\fB=\fIwildcard_mask\fR]\fR"
+By default, \fBovs\-testcontroller\fR sets up exact-match flows.  This
+option allows it to set up wildcarded flows, which may reduce
+flow setup latency by causing less traffic to be sent up to the
+controller.
+.IP
+The optional \fIwildcard_mask\fR is an OpenFlow wildcard bitmask in
+hexadecimal that specifies the fields to wildcard.  If no
+\fIwildcard_mask\fR is specified, the default value 0x2820F0 is used
+which specifies L2-only switching and wildcards L3 and L4 fields.
+Another interesting value is 0x2000EC, which specifies L3-only
+switching and wildcards L2 and L4 fields.
+.IP
+This option has no effect when \fB\-n\fR (or \fB\-\-noflow\fR) is in use
+(because the controller does not set up flows in that case).
+.
+.IP "\fB\-N\fR"
+.IQ "\fB\-\-normal\fR"
+By default, \fBovs\-testcontroller\fR directs packets to a particular port
+or floods them.  This option causes it to direct non-flooded packets
+to the OpenFlow \fBOFPP_NORMAL\fR port.  This allows the switch itself
+to make decisions about packet destinations.  Support for
+\fBOFPP_NORMAL\fR is optional in OpenFlow, so this option may not well
+with some non-Open vSwitch switches.
+.
+.IP "\fB\-\-mute\fR"
+Prevents ovs\-testcontroller from replying to any OpenFlow messages sent
+to it by switches.
+.IP
+This option is only for debugging the Open vSwitch implementation of
+``fail open'' mode.  It must not be used in production.
+.
+.IP "\fB\-q \fIid\fR"
+.IQ "\fB\-\-queue=\fIid\fR"
+By default, \fBovs\-testcontroller\fR uses the default OpenFlow queue for
+sending packets and setting up flows.  Use one of these options,
+supplying \fIid\fR as an OpenFlow queue ID as a decimal number, to
+instead use that specific queue.
+.IP
+This option is incompatible with \fB\-N\fR or \fB\-\-normal\fR and
+with \fB\-H\fR or \fB\-\-hub\fR.  If more than one is specified then
+this option takes precedence.
+.IP
+This option may be useful for testing or debugging quality of service
+setups.
+.
+.IP "\fB\-Q \fIport-name\fB:\fIqueue-id\fR"
+.IP "\fB\-\-port\-queue \fIport-name\fB:\fIqueue-id\fR"
+Configures packets received on the port named \fIport-name\fR
+(e.g. \fBeth0\fR) to be output on OpenFlow queue ID \fIqueue-id\fR
+(specified as a decimal number).  For the specified port, this option
+overrides the default specified on \fB\-q\fR or \fB\-\-queue\fR.
+.IP
+This option may be specified any number of times with different
+\fIport-name\fR arguments.
+.IP
+This option is incompatible with \fB\-N\fR or \fB\-\-normal\fR and
+with \fB\-H\fR or \fB\-\-hub\fR.  If more than one is specified then
+this option takes precedence.
+.IP
+This option may be useful for testing or debugging quality of service
+setups.
+.
+.IP "\fB\-\-with\-flows \fIfile\fR"
+When a switch connects, push the flow entries as described in
+\fIfile\fR.  Each line in \fIfile\fR is a flow entry in the format
+described for the \fBadd\-flows\fR command in the \fBFlow Syntax\fR
+section of the \fBovs\-ofctl\fR(8) man page.
+.IP
+Use this option more than once to add flows from multiple files.
+.
+.SS "Public Key Infrastructure Options"
+.so lib/ssl.man
+.so lib/ssl-peer-ca-cert.man
+.ds DD
+.so lib/daemon.man
+.so lib/vlog.man
+.so lib/unixctl.man
+.so lib/common.man
+.so so lib/ofp-version.man
+.
+.SH EXAMPLES
+.PP
+To bind locally to port 6633 (the default) and wait for incoming
+connections from OpenFlow switches:
+.IP
+\fB% ovs\-testcontroller ptcp:\fR
+.PP
+In the future, the default port number will change to 6653, which is the
+IANA-defined value.
+.SH "BUGS"
+.PP
+Configuring a Citrix XenServer to connect to a particular controller
+only points the remote OVSDB management connection to that controller.
+It does not also configure OpenFlow connections, because the manager
+is expected to do that over the management protocol.
+\fBovs\-testcontroller\fR is not an Open vSwitch manager and does not know
+how to do that.
+.PP
+As a stopgap workaround, \fBovs\-vsctl\fR can wait for an OVSDB
+connection and set the controller, e.g.:
+.IP
+\fB% ovs\-vsctl \-t0 \-\-db=pssl: \-\-certificate=cert.pem
+\-\-ca\-cert=none \-\-private\-key=privkey.pem
+\-\-peer\-ca\-cert=cacert.pem set\-controller ssl:\fIip\fR
+.SH "SEE ALSO"
+.
+.BR ovs\-appctl (8),
+.BR ovs\-ofctl (8),
+.BR ovs\-dpctl (8)
diff --git a/utilities/ovs-testcontroller.c b/utilities/ovs-testcontroller.c
new file mode 100644 (file)
index 0000000..a615ab4
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 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.
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "command-line.h"
+#include "compiler.h"
+#include "daemon.h"
+#include "fatal-signal.h"
+#include "learning-switch.h"
+#include "ofp-parse.h"
+#include "ofp-version-opt.h"
+#include "ofpbuf.h"
+#include "openflow/openflow.h"
+#include "poll-loop.h"
+#include "rconn.h"
+#include "simap.h"
+#include "stream-ssl.h"
+#include "timeval.h"
+#include "unixctl.h"
+#include "util.h"
+#include "vconn.h"
+#include "vlog.h"
+#include "socket-util.h"
+#include "ofp-util.h"
+
+VLOG_DEFINE_THIS_MODULE(controller);
+
+#define MAX_SWITCHES 16
+#define MAX_LISTENERS 16
+
+struct switch_ {
+    struct lswitch *lswitch;
+};
+
+/* -H, --hub: Learn the ports on which MAC addresses appear? */
+static bool learn_macs = true;
+
+/* -n, --noflow: Set up flows?  (If not, every packet is processed at the
+ * controller.) */
+static bool set_up_flows = true;
+
+/* -N, --normal: Use "NORMAL" action instead of explicit port? */
+static bool action_normal = false;
+
+/* -w, --wildcard: 0 to disable wildcard flow entries, an OFPFW10_* bitmask to
+ * enable specific wildcards, or UINT32_MAX to use the default wildcards. */
+static uint32_t wildcards = 0;
+
+/* --max-idle: Maximum idle time, in seconds, before flows expire. */
+static int max_idle = 60;
+
+/* --mute: If true, accept connections from switches but do not reply to any
+ * of their messages (for debugging fail-open mode). */
+static bool mute = false;
+
+/* -q, --queue: default OpenFlow queue, none if UINT32_MAX. */
+static uint32_t default_queue = UINT32_MAX;
+
+/* -Q, --port-queue: map from port name to port number. */
+static struct simap port_queues = SIMAP_INITIALIZER(&port_queues);
+
+/* --with-flows: Flows to send to switch. */
+static struct ofputil_flow_mod *default_flows;
+static size_t n_default_flows;
+static enum ofputil_protocol usable_protocols;
+
+/* --unixctl: Name of unixctl socket, or null to use the default. */
+static char *unixctl_path = NULL;
+
+static void new_switch(struct switch_ *, struct vconn *);
+static void parse_options(int argc, char *argv[]);
+static void usage(void) NO_RETURN;
+
+int
+main(int argc, char *argv[])
+{
+    struct unixctl_server *unixctl;
+    struct switch_ switches[MAX_SWITCHES];
+    struct pvconn *listeners[MAX_LISTENERS];
+    int n_switches, n_listeners;
+    int retval;
+    int i;
+
+    proctitle_init(argc, argv);
+    set_program_name(argv[0]);
+    parse_options(argc, argv);
+    fatal_ignore_sigpipe();
+
+    if (argc - optind < 1) {
+        ovs_fatal(0, "at least one vconn argument required; "
+                  "use --help for usage");
+    }
+
+    n_switches = n_listeners = 0;
+    for (i = optind; i < argc; i++) {
+        const char *name = argv[i];
+        struct vconn *vconn;
+
+        retval = vconn_open(name, get_allowed_ofp_versions(), DSCP_DEFAULT,
+                            &vconn);
+        if (!retval) {
+            if (n_switches >= MAX_SWITCHES) {
+                ovs_fatal(0, "max %d switch connections", n_switches);
+            }
+            new_switch(&switches[n_switches++], vconn);
+            continue;
+        } else if (retval == EAFNOSUPPORT) {
+            struct pvconn *pvconn;
+            retval = pvconn_open(name, get_allowed_ofp_versions(),
+                                 DSCP_DEFAULT, &pvconn);
+            if (!retval) {
+                if (n_listeners >= MAX_LISTENERS) {
+                    ovs_fatal(0, "max %d passive connections", n_listeners);
+                }
+                listeners[n_listeners++] = pvconn;
+            }
+        }
+        if (retval) {
+            VLOG_ERR("%s: connect: %s", name, ovs_strerror(retval));
+        }
+    }
+    if (n_switches == 0 && n_listeners == 0) {
+        ovs_fatal(0, "no active or passive switch connections");
+    }
+
+    daemonize_start();
+
+    retval = unixctl_server_create(unixctl_path, &unixctl);
+    if (retval) {
+        exit(EXIT_FAILURE);
+    }
+
+    daemonize_complete();
+
+    while (n_switches > 0 || n_listeners > 0) {
+        /* Accept connections on listening vconns. */
+        for (i = 0; i < n_listeners && n_switches < MAX_SWITCHES; ) {
+            struct vconn *new_vconn;
+
+            retval = pvconn_accept(listeners[i], &new_vconn);
+            if (!retval || retval == EAGAIN) {
+                if (!retval) {
+                    new_switch(&switches[n_switches++], new_vconn);
+                }
+                i++;
+            } else {
+                pvconn_close(listeners[i]);
+                listeners[i] = listeners[--n_listeners];
+            }
+        }
+
+        /* Do some switching work.  . */
+        for (i = 0; i < n_switches; ) {
+            struct switch_ *this = &switches[i];
+            lswitch_run(this->lswitch);
+            if (lswitch_is_alive(this->lswitch)) {
+                i++;
+            } else {
+                lswitch_destroy(this->lswitch);
+                switches[i] = switches[--n_switches];
+            }
+        }
+
+        unixctl_server_run(unixctl);
+
+        /* Wait for something to happen. */
+        if (n_switches < MAX_SWITCHES) {
+            for (i = 0; i < n_listeners; i++) {
+                pvconn_wait(listeners[i]);
+            }
+        }
+        for (i = 0; i < n_switches; i++) {
+            struct switch_ *sw = &switches[i];
+            lswitch_wait(sw->lswitch);
+        }
+        unixctl_server_wait(unixctl);
+        poll_block();
+    }
+
+    return 0;
+}
+
+static void
+new_switch(struct switch_ *sw, struct vconn *vconn)
+{
+    struct lswitch_config cfg;
+    struct rconn *rconn;
+
+    rconn = rconn_create(60, 0, DSCP_DEFAULT, get_allowed_ofp_versions());
+    rconn_connect_unreliably(rconn, vconn, NULL);
+
+    cfg.mode = (action_normal ? LSW_NORMAL
+                : learn_macs ? LSW_LEARN
+                : LSW_FLOOD);
+    cfg.wildcards = wildcards;
+    cfg.max_idle = set_up_flows ? max_idle : -1;
+    cfg.default_flows = default_flows;
+    cfg.n_default_flows = n_default_flows;
+    cfg.usable_protocols = usable_protocols;
+    cfg.default_queue = default_queue;
+    cfg.port_queues = &port_queues;
+    cfg.mute = mute;
+    sw->lswitch = lswitch_create(rconn, &cfg);
+}
+
+static void
+add_port_queue(char *s)
+{
+    char *save_ptr = NULL;
+    char *port_name;
+    char *queue_id;
+
+    port_name = strtok_r(s, ":", &save_ptr);
+    queue_id = strtok_r(NULL, "", &save_ptr);
+    if (!queue_id) {
+        ovs_fatal(0, "argument to -Q or --port-queue should take the form "
+                  "\"<port-name>:<queue-id>\"");
+    }
+
+    if (!simap_put(&port_queues, port_name, atoi(queue_id))) {
+        ovs_fatal(0, "<port-name> arguments for -Q or --port-queue must "
+                  "be unique");
+    }
+}
+
+static void
+parse_options(int argc, char *argv[])
+{
+    enum {
+        OPT_MAX_IDLE = UCHAR_MAX + 1,
+        OPT_PEER_CA_CERT,
+        OPT_MUTE,
+        OPT_WITH_FLOWS,
+        OPT_UNIXCTL,
+        VLOG_OPTION_ENUMS,
+        DAEMON_OPTION_ENUMS,
+        OFP_VERSION_OPTION_ENUMS
+    };
+    static const struct option long_options[] = {
+        {"hub",         no_argument, NULL, 'H'},
+        {"noflow",      no_argument, NULL, 'n'},
+        {"normal",      no_argument, NULL, 'N'},
+        {"wildcards",   optional_argument, NULL, 'w'},
+        {"max-idle",    required_argument, NULL, OPT_MAX_IDLE},
+        {"mute",        no_argument, NULL, OPT_MUTE},
+        {"queue",       required_argument, NULL, 'q'},
+        {"port-queue",  required_argument, NULL, 'Q'},
+        {"with-flows",  required_argument, NULL, OPT_WITH_FLOWS},
+        {"unixctl",     required_argument, NULL, OPT_UNIXCTL},
+        {"help",        no_argument, NULL, 'h'},
+        DAEMON_LONG_OPTIONS,
+        OFP_VERSION_LONG_OPTIONS,
+        VLOG_LONG_OPTIONS,
+        STREAM_SSL_LONG_OPTIONS,
+        {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
+        {NULL, 0, NULL, 0},
+    };
+    char *short_options = long_options_to_short_options(long_options);
+
+    for (;;) {
+        int indexptr;
+        char *error;
+        int c;
+
+        c = getopt_long(argc, argv, short_options, long_options, &indexptr);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+        case 'H':
+            learn_macs = false;
+            break;
+
+        case 'n':
+            set_up_flows = false;
+            break;
+
+        case OPT_MUTE:
+            mute = true;
+            break;
+
+        case 'N':
+            action_normal = true;
+            break;
+
+        case 'w':
+            wildcards = optarg ? strtol(optarg, NULL, 16) : UINT32_MAX;
+            break;
+
+        case OPT_MAX_IDLE:
+            if (!strcmp(optarg, "permanent")) {
+                max_idle = OFP_FLOW_PERMANENT;
+            } else {
+                max_idle = atoi(optarg);
+                if (max_idle < 1 || max_idle > 65535) {
+                    ovs_fatal(0, "--max-idle argument must be between 1 and "
+                              "65535 or the word 'permanent'");
+                }
+            }
+            break;
+
+        case 'q':
+            default_queue = atoi(optarg);
+            break;
+
+        case 'Q':
+            add_port_queue(optarg);
+            break;
+
+        case OPT_WITH_FLOWS:
+            error = parse_ofp_flow_mod_file(optarg, OFPFC_ADD, &default_flows,
+                                            &n_default_flows,
+                                            &usable_protocols);
+            if (error) {
+                ovs_fatal(0, "%s", error);
+            }
+            break;
+
+        case OPT_UNIXCTL:
+            unixctl_path = optarg;
+            break;
+
+        case 'h':
+            usage();
+
+        VLOG_OPTION_HANDLERS
+        OFP_VERSION_OPTION_HANDLERS
+        DAEMON_OPTION_HANDLERS
+
+        STREAM_SSL_OPTION_HANDLERS
+
+        case OPT_PEER_CA_CERT:
+            stream_ssl_set_peer_ca_cert_file(optarg);
+            break;
+
+        case '?':
+            exit(EXIT_FAILURE);
+
+        default:
+            abort();
+        }
+    }
+    free(short_options);
+
+    if (!simap_is_empty(&port_queues) || default_queue != UINT32_MAX) {
+        if (action_normal) {
+            ovs_error(0, "queue IDs are incompatible with -N or --normal; "
+                      "not using OFPP_NORMAL");
+            action_normal = false;
+        }
+
+        if (!learn_macs) {
+            ovs_error(0, "queue IDs are incompatible with -H or --hub; "
+                      "not acting as hub");
+            learn_macs = true;
+        }
+    }
+}
+
+static void
+usage(void)
+{
+    printf("%s: OpenFlow controller\n"
+           "usage: %s [OPTIONS] METHOD\n"
+           "where METHOD is any OpenFlow connection method.\n",
+           program_name, program_name);
+    vconn_usage(true, true, false);
+    daemon_usage();
+    ofp_version_usage();
+    vlog_usage();
+    printf("\nOther options:\n"
+           "  -H, --hub               act as hub instead of learning switch\n"
+           "  -n, --noflow            pass traffic, but don't add flows\n"
+           "  --max-idle=SECS         max idle time for new flows\n"
+           "  -N, --normal            use OFPP_NORMAL action\n"
+           "  -w, --wildcards[=MASK]  wildcard (specified) bits in flows\n"
+           "  -q, --queue=QUEUE-ID    OpenFlow queue ID to use for output\n"
+           "  -Q PORT-NAME:QUEUE-ID   use QUEUE-ID for frames from PORT-NAME\n"
+           "  --with-flows FILE       use the flows from FILE\n"
+           "  --unixctl=SOCKET        override default control socket name\n"
+           "  -h, --help              display this help message\n"
+           "  -V, --version           display version information\n");
+    exit(EXIT_SUCCESS);
+}
index 73ac9e3..bd82681 100644 (file)
@@ -1,6 +1,6 @@
 # Spec file for Open vSwitch.
 
-# Copyright (C) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
 #
 # Copying and distribution of this file, with or without modification,
 # are permitted in any medium without royalty provided the copyright
@@ -129,10 +129,12 @@ cp -rf $RPM_BUILD_ROOT/usr/share/openvswitch/bugtool-plugins/* $RPM_BUILD_ROOT/e
 # Get rid of stuff we don't want to make RPM happy.
 rm \
     $RPM_BUILD_ROOT/usr/bin/ovs-benchmark \
+    $RPM_BUILD_ROOT/usr/bin/ovs-testcontroller \
     $RPM_BUILD_ROOT/usr/bin/ovs-l3ping \
     $RPM_BUILD_ROOT/usr/bin/ovs-pki \
     $RPM_BUILD_ROOT/usr/bin/ovs-test \
     $RPM_BUILD_ROOT/usr/share/man/man1/ovs-benchmark.1 \
+    $RPM_BUILD_ROOT/usr/share/man/man8/ovs-testcontroller.8 \
     $RPM_BUILD_ROOT/usr/share/man/man8/ovs-l3ping.8 \
     $RPM_BUILD_ROOT/usr/share/man/man8/ovs-pki.8 \
     $RPM_BUILD_ROOT/usr/share/man/man8/ovs-test.8