From: Ben Pfaff Date: Fri, 15 Aug 2014 17:32:50 +0000 (-0700) Subject: test-controller: Rename to ovs-testcontroller, again install. X-Git-Tag: v2.4.0~1581 X-Git-Url: http://git.cascardo.eti.br/?p=cascardo%2Fovs.git;a=commitdiff_plain;h=0bc1b46a38cca06023fdfa5d500c738ccdfa94e7 test-controller: Rename to ovs-testcontroller, again install. 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 Requested-by: Dariusz Dwornikowski Signed-off-by: Ben Pfaff Acked-by: Justin Pettit --- diff --git a/INSTALL.SSL b/INSTALL.SSL index 061af97ab..a6931d20c 100644 --- a/INSTALL.SSL +++ b/INSTALL.SSL @@ -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 diff --git a/INSTALL.XenServer b/INSTALL.XenServer index 1e2363418..8c07d24f9 100644 --- a/INSTALL.XenServer +++ b/INSTALL.XenServer @@ -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 fb39811e7..505935892 100644 --- 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 fa41c1679..c87357dfd 100644 --- 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? diff --git a/debian/.gitignore b/debian/.gitignore index bec99864e..e8d9d316f 100644 --- a/debian/.gitignore +++ b/debian/.gitignore @@ -16,6 +16,7 @@ /openvswitch-switch /openvswitch-switch.copyright /openvswitch-test +/openvswitch-testcontroller /openvswitch-vtep /python-openvswitch /tmp diff --git a/debian/automake.mk b/debian/automake.mk index 948a619e7..86c1310bf 100644 --- a/debian/automake.mk +++ b/debian/automake.mk @@ -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 \ diff --git a/debian/changelog b/debian/changelog index 8dd53312d..ff2e0bcd0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -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... diff --git a/debian/control b/debian/control index af4af4e23..0fe701898 100644 --- a/debian/control +++ b/debian/control @@ -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 index 000000000..0548826ef --- /dev/null +++ b/debian/openvswitch-testcontroller.README.Debian @@ -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 , Thu, 14 Aug 2014 10:49:34 -0700 diff --git a/debian/openvswitch-testcontroller.default b/debian/openvswitch-testcontroller.default new file mode 100644 index 000000000..48b53f124 --- /dev/null +++ b/debian/openvswitch-testcontroller.default @@ -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 index 000000000..d8d4f775f --- /dev/null +++ b/debian/openvswitch-testcontroller.dirs @@ -0,0 +1 @@ +etc/openvswitch-testcontroller diff --git a/debian/openvswitch-testcontroller.init b/debian/openvswitch-testcontroller.init new file mode 100755 index 000000000..67b7a994f --- /dev/null +++ b/debian/openvswitch-testcontroller.init @@ -0,0 +1,278 @@ +#!/bin/sh +# +# Copyright (c) 2011, 2014 Nicira, Inc. +# Copyright (c) 2007, 2009 Javier Fernandez-Sanguino +# +# 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 index 000000000..d368f2a01 --- /dev/null +++ b/debian/openvswitch-testcontroller.install @@ -0,0 +1 @@ +usr/bin/ovs-testcontroller diff --git a/debian/openvswitch-testcontroller.manpages b/debian/openvswitch-testcontroller.manpages new file mode 100644 index 000000000..4ea178163 --- /dev/null +++ b/debian/openvswitch-testcontroller.manpages @@ -0,0 +1 @@ +_debian/utilities/ovs-testcontroller.8 diff --git a/debian/openvswitch-testcontroller.postinst b/debian/openvswitch-testcontroller.postinst new file mode 100755 index 000000000..7242b4a3b --- /dev/null +++ b/debian/openvswitch-testcontroller.postinst @@ -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: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# 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 index 000000000..afca1bbf0 --- /dev/null +++ b/debian/openvswitch-testcontroller.postrm @@ -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: +# * `remove' +# * `purge' +# * `upgrade' +# * `failed-upgrade' +# * `abort-install' +# * `abort-install' +# * `abort-upgrade' +# * `disappear' +# +# 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 diff --git a/manpages.mk b/manpages.mk index 446b30a4d..b21ec41d2 100644 --- a/manpages.mk +++ b/manpages.mk @@ -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 \ diff --git a/rhel/openvswitch-fedora.spec.in b/rhel/openvswitch-fedora.spec.in index 9f66f4134..0efebd4c3 100644 --- a/rhel/openvswitch-fedora.spec.in +++ b/rhel/openvswitch-fedora.spec.in @@ -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 diff --git a/rhel/openvswitch.spec.in b/rhel/openvswitch.spec.in index 251cfe503..88bc67331 100644 --- a/rhel/openvswitch.spec.in +++ b/rhel/openvswitch.spec.in @@ -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 \ diff --git a/tests/.gitignore b/tests/.gitignore index 5b55a7d35..7c980619f 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -14,8 +14,6 @@ /test-bundle /test-byte-order /test-classifier -/test-controller.8 -/test-controller /test-csum /test-flows /test-hash diff --git a/tests/automake.mk b/tests/automake.mk index 2b88ad29a..470c1b989 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -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 index 62bfa0f57..000000000 --- a/tests/test-controller.8.in +++ /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 index a615ab49c..000000000 --- a/tests/test-controller.c +++ /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 - -#include -#include -#include -#include -#include -#include -#include - -#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 " - "\":\""); - } - - if (!simap_put(&port_queues, port_name, atoi(queue_id))) { - ovs_fatal(0, " 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); -} diff --git a/utilities/.gitignore b/utilities/.gitignore index d2baa6602..dda889b4b 100644 --- a/utilities/.gitignore +++ b/utilities/.gitignore @@ -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 diff --git a/utilities/automake.mk b/utilities/automake.mk index 3e38e3742..87ccb98c7 100644 --- a/utilities/automake.mk +++ b/utilities/automake.mk @@ -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 index 000000000..18e089809 --- /dev/null +++ b/utilities/ovs-testcontroller.8.in @@ -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 index 000000000..a615ab49c --- /dev/null +++ b/utilities/ovs-testcontroller.c @@ -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 + +#include +#include +#include +#include +#include +#include +#include + +#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 " + "\":\""); + } + + if (!simap_put(&port_queues, port_name, atoi(queue_id))) { + ovs_fatal(0, " 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); +} diff --git a/xenserver/openvswitch-xen.spec.in b/xenserver/openvswitch-xen.spec.in index 73ac9e337..bd826813d 100644 --- a/xenserver/openvswitch-xen.spec.in +++ b/xenserver/openvswitch-xen.spec.in @@ -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