diff options
| author | Ben Pfaff <blp@nicira.com> | 2011-06-07 09:40:53 -0700 |
|---|---|---|
| committer | Ben Pfaff <blp@nicira.com> | 2011-06-07 09:40:53 -0700 |
| commit | 045b2e5c77d02cd0d7bba046e2dbed72ec4828c8 (patch) | |
| tree | 8110e620c0dbe59cd6375a9a32d0b3612ac90843 /tests | |
| parent | d3db2ef1f501cdbbf136de35e77a72e9b4970ece (diff) | |
| download | openvswitch-045b2e5c77d02cd0d7bba046e2dbed72ec4828c8.tar.gz | |
ovs-openflowd: Rename test-openflowd and move to "tests" directory.
Too many users thought that they needed to run ovs-openflowd at the same
time as ovs-vswitchd. I hope that this change discourages them.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/.gitignore | 2 | ||||
| -rw-r--r-- | tests/automake.mk | 14 | ||||
| -rw-r--r-- | tests/ofproto-macros.at | 8 | ||||
| -rw-r--r-- | tests/test-openflowd.8.in | 345 | ||||
| -rw-r--r-- | tests/test-openflowd.c | 541 |
5 files changed, 905 insertions, 5 deletions
diff --git a/tests/.gitignore b/tests/.gitignore index a1bde03e4..e2b293c4f 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -21,6 +21,8 @@ /test-list /test-lockfile /test-multipath +/test-openflowd +/test-openflowd.8 /test-ovsdb /test-packets /test-random diff --git a/tests/automake.mk b/tests/automake.mk index eda69f7b3..750f420de 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -113,7 +113,6 @@ check-lcov: all tests/atconfig tests/atlocal $(TESTSUITE) $(lcov_wrappers) valgrind_wrappers = \ tests/valgrind/ovs-appctl \ - tests/valgrind/ovs-openflowd \ tests/valgrind/ovs-vsctl \ tests/valgrind/ovsdb-client \ tests/valgrind/ovsdb-server \ @@ -131,6 +130,7 @@ valgrind_wrappers = \ tests/valgrind/test-list \ tests/valgrind/test-lockfile \ tests/valgrind/test-multipath \ + tests/valgrind/test-openflowd \ tests/valgrind/test-ovsdb \ tests/valgrind/test-packets \ tests/valgrind/test-random \ @@ -230,6 +230,18 @@ noinst_PROGRAMS += tests/test-multipath tests_test_multipath_SOURCES = tests/test-multipath.c tests_test_multipath_LDADD = lib/libopenvswitch.a +noinst_PROGRAMS += tests/test-openflowd +EXTRA_DIST += tests/test-openflowd.8.in +DISTCLEANFILES += tests/test-openflowd.8 +noinst_man_MANS += tests/ovs-openflowd.8 +tests_test_openflowd_SOURCES = tests/test-openflowd.c +tests_test_openflowd_LDADD = \ + ofproto/libofproto.a \ + lib/libsflow.a \ + lib/libopenvswitch.a \ + $(SSL_LIBS) + + noinst_PROGRAMS += tests/test-packets tests_test_packets_SOURCES = tests/test-packets.c tests_test_packets_LDADD = lib/libopenvswitch.a diff --git a/tests/ofproto-macros.at b/tests/ofproto-macros.at index dc863e73f..24cb45a7d 100644 --- a/tests/ofproto-macros.at +++ b/tests/ofproto-macros.at @@ -5,10 +5,10 @@ m4_define([TESTABLE_LOG], [-vPATTERN:ANY:'%c|%p|%m']) m4_define([OFPROTO_START], [OVS_RUNDIR=$PWD; export OVS_RUNDIR OVS_LOGDIR=$PWD; export OVS_LOGDIR - trap 'kill `cat ovs-openflowd.pid`' 0 - AT_CAPTURE_FILE([ovs-openflowd.log]) + trap 'kill `cat test-openflowd.pid`' 0 + AT_CAPTURE_FILE([test-openflowd.log]) AT_CHECK( - [ovs-openflowd --detach --pidfile --enable-dummy --log-file --fail=closed dummy@br0 none --datapath-id=fedcba9876543210 $1], + [test-openflowd --detach --pidfile --enable-dummy --log-file --fail=closed dummy@br0 none --datapath-id=fedcba9876543210 $1], [0], [], [stderr]) AT_CHECK([[sed < stderr ' /vlog|INFO|opened log file/d @@ -19,5 +19,5 @@ m4_define([OFPROTO_START], ]) m4_define([OFPROTO_STOP], - [AT_CHECK([ovs-appctl -t ovs-openflowd exit]) + [AT_CHECK([ovs-appctl -t test-openflowd exit]) trap '' 0]) diff --git a/tests/test-openflowd.8.in b/tests/test-openflowd.8.in new file mode 100644 index 000000000..135ba846e --- /dev/null +++ b/tests/test-openflowd.8.in @@ -0,0 +1,345 @@ +.TH test\-openflowd 8 "March 2009" "Open vSwitch" "Open vSwitch Manual" +.\" This program's name: +.ds PN test\-openflowd +.\" SSL peer program's name: +.ds SN ovs\-controller +. +.SH NAME +test\-openflowd \- OpenFlow switch implementation +. +.SH SYNOPSIS +.B test\-openflowd +[\fIoptions\fR] \fIdatapath\fR \fIcontroller\fR\&... +. +.SH DESCRIPTION +The \fBtest\-openflowd\fR program implements an OpenFlow switch using a +flow-based datapath. \fBtest\-openflowd\fR connects to one or more +OpenFlow controllers over TCP or SSL. +.PP +For a more powerful alternative to \fBtest\-openflowd\fR, see +\fBovs\-vswitchd\fR(8). Do not run both daemons at the same time. +.PP +The mandatory \fIdatapath\fR argument argument specifies the local +datapath to relay. It takes the form [\fItype\fB@\fR]\fIname\fR, +where \fIname\fR is the network device associated with the datapath's +local port. If \fItype\fR is given, it specifies the datapath +provider of \fIname\fR, otherwise the default provider \fBsystem\fR is +assumed. +. +.PP +The optional \fIcontroller\fR arguments specify how to connect to the +OpenFlow controller or controllers. Each takes one of the following +forms: +. +.so lib/vconn-active.man +.IP "\fBnone\fR" +Run without actively maintaining a connection to a remote OpenFlow +controller. (See the \fB\-\-listen\fR option, under \fBNetworking +Options\fR below, for another way to make OpenFlow connections to the +switch.) +. +.PP +When multiple controllers are configured, \fBtest\-openflowd\fR +connects to all of them simultaneously. OpenFlow 1.0 does not specify +how multiple controllers coordinate in interacting with a single +switch, so more than one controller should be specified only if the +controllers are themselves designed to coordinate with each other. +(The Nicira-defined \fBNXT_ROLE\fR OpenFlow vendor extension may be +useful for this.) +. +.SS "Contacting Controllers" +The OpenFlow switch must be able to contact the OpenFlow controllers +over the network. It can do so in one of two ways: +. +.IP out-of-band +In this configuration, OpenFlow traffic uses a network separate from +the data traffic that it controls, that is, the switch does not use +any of the network devices added to the datapath with \fBovs\-dpctl +add\-if\fR in its communication with the controller. +.IP +To use \fBtest\-openflowd\fR in a network with out-of-band control, specify +\fB\-\-out\-of\-band\fR on the \fBtest\-openflowd\fR command line. The control +network must be configured separately, before or after \fBtest\-openflowd\fR +is started. +. +.IP in-band +In this configuration, a single network is used for OpenFlow traffic +and other data traffic, that is, the switch contacts the controller +over one of the network devices added to the datapath with \fBovs\-dpctl +add\-if\fR. This configuration is often more convenient than +out-of-band control, because it is not necessary to maintain two +independent networks. +.IP +In-band control is the default for \fBtest\-openflowd\fR, so no special +command-line option is required. + +Specify the location of the +controller on the \fBtest\-openflowd\fR command line as the \fIcontroller\fR +argument. You must also configure the network device for the OpenFlow +``local port'' to allow \fBtest\-openflowd\fR to connect to that controller. +The OpenFlow local port is a virtual network port that \fBtest\-openflowd\fR +bridges to the physical switch ports. The name of the local port for +a given \fIdatapath\fR may be seen by running \fBovs\-dpctl show +\fIdatapath\fR; the local port is listed as port 0 in \fBshow\fR's +output. +. +.IP +Before \fBtest\-openflowd\fR starts, the local port network device is not +bridged to any physical network, so the next step depends on whether +connectivity is required to configure the device's IP address. If the +switch has a static IP address, you may configure its IP address now +with a command such as +.B ifconfig of0 192.168.1.1 +and then invoke \fBtest\-openflowd\fR. +.IP +On the other hand, if the switch does not have a static IP address, +e.g. it obtains its IP address dynamically via DHCP, the DHCP client +will not be able to contact the DHCP server until the OpenFlow switch +has started up. Thus, start \fBtest\-openflowd\fR without configuring +the local port network device, and start the DHCP client afterward. +.RE +. +.SH OPTIONS +.SS "OpenFlow Options" +.TP +\fB\-\-datapath\-id=\fIdpid\fR +Sets \fIdpid\fR, which must consist of exactly 16 hexadecimal digits +and may not be all-zero, +as the datapath ID that the switch will use to identify itself to +OpenFlow controllers. +.IP +If this option is omitted, the default datapath ID is taken from the +Ethernet address of the datapath's local port (which is typically +randomly generated) in the lower 48 bits and zeros in the upper 16. +. +.TP +\fB\-\-mfr\-desc=\fIdesc\fR +Set the description of the switch's manufacturer to \fIdesc\fR, which +may contain up to 255 ASCII characters. +. +.TP +\fB\-\-hw\-desc=\fIdesc\fR +Set the description of the switch's hardware revision to \fIdesc\fR, which +may contain up to 255 ASCII characters. +. +.TP +\fB\-\-sw\-desc=\fIdesc\fR +Set the description of the switch's software revision to \fIdesc\fR, which +may contain up to 255 ASCII characters. +. +.TP +\fB\-\-serial\-desc=\fIdesc\fR +Set the description of the switch's serial number to \fIdesc\fR, which +may contain up to 31 ASCII characters. +. +.TP +\fB\-\-dp\-desc=\fIdesc\fR +Set the description of the datapath to \fIdesc\fR, which may contain up to +255 ASCII characters. Note that this field is intended for debugging +purposes and is not guaranteed to be unique and should not be used as +the primary identifier of the datapath. +. +.SS "Networking Options" +.TP +\fB\-\-datapath\-id=\fIdpid\fR +Sets \fIdpid\fR, which must consist of exactly 16 hexadecimal digits, +as the datapath ID that the switch will use to identify itself to the +OpenFlow controller. +.IP +If this option is omitted, the default datapath ID is taken from the +Ethernet address of the datapath's local port (which is typically +randomly generated) in the lower 48 bits and zeros in the upper 16. +. +.TP +\fB\-\-fail=\fR[\fBstandalone\fR|\fBsecure\fR] +The controller is, ordinarily, responsible for setting up all flows on +the OpenFlow switch. Thus, if the connection to the controller fails, +no new network connections can be set up. If the connection to the +controller stays down long enough, no packets can pass through the +switch at all. +.IP +If this option is set to \fBstandalone\fR (the default), +\fBtest\-openflowd\fR will +take over responsibility for setting up flows in the local datapath +when no message has been received from the controller for three times +the inactivity probe interval (see below), or 45 seconds by default. +In this ``fail open'' mode, \fBtest\-openflowd\fR causes the datapath to act +like an ordinary MAC-learning switch. \fBtest\-openflowd\fR will continue to +retry connection to the controller in the background and, when the +connection succeeds, it discontinues its standalone switching behavior. +.IP +If this option is set to \fBsecure\fR, then \fBtest\-openflowd\fR will not +set up flows on its own when the controller connection fails. +. +.TP +\fB\-\-inactivity\-probe=\fIsecs\fR +When the OpenFlow switch is connected to the controller, the +switch waits for a message to be received from the controller for +\fIsecs\fR seconds before it sends a inactivity probe to the +controller. After sending the inactivity probe, if no response is +received for an additional \fIsecs\fR seconds, the switch +assumes that the connection has been broken and attempts to reconnect. +The default and the minimum value are both 5 seconds. +.IP +When fail-open mode is configured, changing the inactivity probe +interval also changes the interval before entering fail-open mode (see +above). +. +.TP +\fB\-\-max\-idle=\fIsecs\fR|\fBpermanent\fR +Sets \fIsecs\fR as the number of seconds that a flow set up by the +OpenFlow switch will remain in the switch's flow table without any +matching packets being seen. If \fBpermanent\fR is specified, which +is not recommended, flows set up by the switch will never +expire. The default is 15 seconds. +.IP +Most flows are set up by the OpenFlow controller, not by the +switch. This option affects only the following flows, which the +OpenFlow switch sets up itself: +. +.RS +.IP \(bu +When \fB\-\-fail=open\fR is specified, flows set up when the +switch has not been able to contact the controller for the configured +fail-open delay. +. +.IP \(bu +When in-band control is in use, flows set up to bootstrap contacting +the controller (see \fBContacting the Controller\fR, above, for +more information about in-band control). +.RE +. +.IP +As a result, when both \fB\-\-fail=secure\fR and \fB\-\-out\-of\-band\fR are +specified, this option has no effect. +. +.TP +\fB\-\-max\-backoff=\fIsecs\fR +Sets the maximum time between attempts to connect to the controller to +\fIsecs\fR, which must be at least 1. The actual interval between +connection attempts starts at 1 second and doubles on each failing +attempt until it reaches the maximum. The default maximum backoff +time is 8 seconds. +. +.TP +\fB\-l\fR, \fB\-\-listen=\fImethod\fR +By default, the switch listens for OpenFlow management connections on a +Unix domain socket named \fB@RUNDIR@/\fIdatapath\fB.mgmt\fR. This socket +can be used to perform local OpenFlow monitoring and administration with +tools such as \fBovs\-ofctl\fR. +.IP +This option may be used to override the default listener. The \fImethod\fR +must be given as one of the passive OpenFlow connection methods listed +below. This option may be specified multiple times to listen to +multiple connection methods. If a single \fImethod\fR of \fBnone\fR is +used, no listeners will be created. +. +.RS +.so lib/vconn-passive.man +.RE +. +.TP +\fB\-\-snoop=\fImethod\fR +Configures the switch to additionally listen for incoming OpenFlow +connections for controller connection snooping. The \fImethod\fR must +be given as one of the passive OpenFlow connection methods listed +under the \fB\-\-listen\fR option above. This option may be specified +multiple times to listen to multiple connection methods. +.IP +If \fBovs\-ofctl monitor\fR is used to connect to \fImethod\fR specified on +\fB\-\-snoop\fR, it will display all the OpenFlow messages traveling +between the switch and its controller on the primary OpenFlow +connection. This can be useful for debugging switch and controller +problems. +. +.TP +\fB\-\-in\-band\fR, \fB\-\-out\-of\-band\fR +Configures \fBtest\-openflowd\fR to operate in in-band or out-of-band control +mode (see \fBContacting the Controller\fR above). When neither option +is given, the default is in-band control. +. +.TP +\fB\-\-netflow=\fIip\fB:\fIport\fR +Configures the given UDP \fIport\fR on the specified IP \fIip\fR as +a recipient of NetFlow messages for expired flows. The \fIip\fR must +be specified numerically, not as a DNS name. +.IP +This option may be specified multiple times to configure additional +NetFlow collectors. +. +.SS "Rate-Limiting Options" +. +These options configure how the switch applies a ``token bucket'' to +limit the rate at which packets in unknown flows are forwarded to an +OpenFlow controller for flow-setup processing. This feature prevents +a single OpenFlow switch from overwhelming a controller. +. +.TP +\fB\-\-rate\-limit\fR[\fB=\fIrate\fR] +. +Limits the maximum rate at which packets will be forwarded to the +OpenFlow controller to \fIrate\fR packets per second. If \fIrate\fR +is not specified then the default of 1,000 packets per second is used. +.IP +If \fB\-\-rate\-limit\fR is not used, then the switch does not limit the +rate at which packets are forwarded to the controller. +. +.TP +\fB\-\-burst\-limit=\fIburst\fR +. +Sets the maximum number of unused packet credits that the switch will +allow to accumulate during time in which no packets are being +forwarded to the OpenFlow controller to \fIburst\fR (measured in +packets). The default \fIburst\fR is one-quarter of the \fIrate\fR +specified on \fB\-\-rate\-limit\fR. +. +This option takes effect only when \fB\-\-rate\-limit\fR is also specified. +. +.SS "Datapath Options" +. +.IP "\fB\-\-ports=\fIport\fR[\fB,\fIport\fR...]" +Ordinarily, \fBtest\-openflowd\fR expects the administrator to create +the specified \fIdatapath\fR and add ports to it externally with a +utility such as \fBovs\-dpctl\fR. However, the userspace switch +datapath is implemented inside \fBtest\-openflowd\fR itself and does +not (currently) have any external interface for \fBovs\-dpctl\fR to +access. As a stopgap measure, this option specifies one or more ports +to add to the datapath at \fBtest\-openflowd\fR startup time. Multiple +ports may be specified as a comma-separated list or by specifying +\fB\-\-ports\fR multiple times. +.IP +See \fBINSTALL.userspace\fR for more information about userspace +switching. +. +.SS "Daemon Options" +.so lib/daemon.man +. +.SS "Public Key Infrastructure Options" +.so lib/ssl.man +.so lib/ssl-bootstrap.man +. +.SS "Logging Options" +.so lib/vlog.man +.SS "Other Options" +.so lib/unixctl.man +.so lib/common.man +.so lib/leak-checker.man +. +.SH "RUNTIME MANAGEMENT COMMANDS" +\fBovs\-appctl\fR(8) can send commands to a running +\fBtest\-openflowd\fR process. The currently supported commands are +described below. +.SS "TEST\-OPENFLOWD COMMANDS" +These commands are specific to \fBtest\-openflowd\fR. +.IP "\fBexit\fR" +Causes \fBtest\-openflowd\fR to gracefully terminate. +.so ofproto/ofproto-unixctl.man +.so lib/vlog-unixctl.man +. +.SH "SEE ALSO" +. +.BR ovs\-appctl (8), +.BR ovs\-controller (8), +.BR ovs\-dpctl (8), +.BR ovs\-ofctl (8), +.BR ovs\-pki (8) diff --git a/tests/test-openflowd.c b/tests/test-openflowd.c new file mode 100644 index 000000000..b22b2aad8 --- /dev/null +++ b/tests/test-openflowd.c @@ -0,0 +1,541 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks. + * + * 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 <assert.h> +#include <errno.h> +#include <getopt.h> +#include <inttypes.h> +#include <netinet/in.h> +#include <stdlib.h> +#include <signal.h> +#include <string.h> + +#include "command-line.h" +#include "compiler.h" +#include "daemon.h" +#include "dirs.h" +#include "dummy.h" +#include "leak-checker.h" +#include "list.h" +#include "netdev.h" +#include "ofpbuf.h" +#include "ofproto/ofproto.h" +#include "openflow/openflow.h" +#include "packets.h" +#include "poll-loop.h" +#include "rconn.h" +#include "stream-ssl.h" +#include "timeval.h" +#include "unixctl.h" +#include "util.h" +#include "vconn.h" +#include "vlog.h" + +VLOG_DEFINE_THIS_MODULE(openflowd); + +/* Settings that may be configured by the user. */ +struct ofsettings { + const char *unixctl_path; /* File name for unixctl socket. */ + + /* Controller configuration. */ + struct ofproto_controller *controllers; + size_t n_controllers; + enum ofproto_fail_mode fail_mode; + bool run_forever; /* Continue running even with no controller? */ + + /* Datapath. */ + uint64_t datapath_id; /* Datapath ID. */ + char *dp_name; /* Name of local datapath. */ + char *dp_type; /* Type of local datapath. */ + struct sset ports; /* Set of ports to add to datapath (if any). */ + + /* Description strings. */ + const char *mfr_desc; /* Manufacturer. */ + const char *hw_desc; /* Hardware. */ + const char *sw_desc; /* Software version. */ + const char *serial_desc; /* Serial number. */ + const char *dp_desc; /* Datapath description. */ + + /* Related vconns and network devices. */ + struct sset snoops; /* Listen for controller snooping conns. */ + + /* Failure behavior. */ + int max_idle; /* Idle time for flows in fail-open mode. */ + + /* NetFlow. */ + struct sset netflow; /* NetFlow targets. */ +}; + +static unixctl_cb_func test_openflowd_exit; + +static void parse_options(int argc, char *argv[], struct ofsettings *); +static void usage(void) NO_RETURN; + +int +main(int argc, char *argv[]) +{ + struct unixctl_server *unixctl; + struct ofproto *ofproto; + struct ofsettings s; + int error; + struct netflow_options nf_options; + const char *port; + bool exiting; + + proctitle_init(argc, argv); + set_program_name(argv[0]); + parse_options(argc, argv, &s); + signal(SIGPIPE, SIG_IGN); + + daemonize_start(); + + /* Start listening for ovs-appctl requests. */ + error = unixctl_server_create(s.unixctl_path, &unixctl); + if (error) { + exit(EXIT_FAILURE); + } + + unixctl_command_register("exit", test_openflowd_exit, &exiting); + + VLOG_INFO("Open vSwitch version %s", VERSION BUILDNR); + VLOG_INFO("OpenFlow protocol version 0x%02x", OFP_VERSION); + + error = ofproto_create(s.dp_name, s.dp_type, &ofproto); + if (error) { + VLOG_FATAL("could not initialize OpenFlow switch (%s)", + strerror(error)); + } + + /* Add ports to the datapath if requested by the user. */ + SSET_FOR_EACH (port, &s.ports) { + struct netdev *netdev; + + error = netdev_open_default(port, &netdev); + if (error) { + VLOG_FATAL("%s: failed to open network device (%s)", + port, strerror(error)); + } + + error = ofproto_port_add(ofproto, netdev, NULL); + if (error) { + VLOG_FATAL("failed to add %s as a port (%s)", + port, strerror(error)); + } + + netdev_close(netdev); + } + + /* Configure OpenFlow switch. */ + if (s.datapath_id) { + ofproto_set_datapath_id(ofproto, s.datapath_id); + } + ofproto_set_desc(ofproto, s.mfr_desc, s.hw_desc, s.sw_desc, + s.serial_desc, s.dp_desc); + error = ofproto_set_snoops(ofproto, &s.snoops); + if (error) { + VLOG_FATAL("failed to configure controller snooping connections (%s)", + strerror(error)); + } + memset(&nf_options, 0, sizeof nf_options); + nf_options.collectors = s.netflow; + error = ofproto_set_netflow(ofproto, &nf_options); + if (error) { + VLOG_FATAL("failed to configure NetFlow collectors (%s)", + strerror(error)); + } + ofproto_set_controllers(ofproto, s.controllers, s.n_controllers); + ofproto_set_fail_mode(ofproto, s.fail_mode); + + daemonize_complete(); + + exiting = false; + while (!exiting && (s.run_forever || ofproto_is_alive(ofproto))) { + error = ofproto_run(ofproto); + if (error) { + VLOG_FATAL("unrecoverable datapath error (%s)", strerror(error)); + } + unixctl_server_run(unixctl); + netdev_run(); + + ofproto_wait(ofproto); + unixctl_server_wait(unixctl); + netdev_wait(); + if (exiting) { + poll_immediate_wake(); + } + poll_block(); + } + + ofproto_destroy(ofproto); + + return 0; +} + +static void +test_openflowd_exit(struct unixctl_conn *conn, const char *args OVS_UNUSED, + void *exiting_) +{ + bool *exiting = exiting_; + *exiting = true; + unixctl_command_reply(conn, 200, NULL); +} + +/* User interface. */ + +/* Breaks 'ports' apart at commas and adds each resulting word to 'ports'. */ +static void +parse_ports(const char *s_, struct sset *ports) +{ + char *s = xstrdup(s_); + char *save_ptr = NULL; + char *token; + + for (token = strtok_r(s, ",", &save_ptr); token != NULL; + token = strtok_r(NULL, ",", &save_ptr)) { + sset_add(ports, token); + } + free(s); +} + +static void +parse_options(int argc, char *argv[], struct ofsettings *s) +{ + enum { + OPT_DATAPATH_ID = UCHAR_MAX + 1, + OPT_MFR_DESC, + OPT_HW_DESC, + OPT_SW_DESC, + OPT_SERIAL_DESC, + OPT_DP_DESC, + OPT_BR_NAME, + OPT_FAIL_MODE, + OPT_INACTIVITY_PROBE, + OPT_MAX_IDLE, + OPT_MAX_BACKOFF, + OPT_SNOOP, + OPT_RATE_LIMIT, + OPT_BURST_LIMIT, + OPT_BOOTSTRAP_CA_CERT, + OPT_OUT_OF_BAND, + OPT_IN_BAND, + OPT_NETFLOW, + OPT_PORTS, + OPT_UNIXCTL, + OPT_ENABLE_DUMMY, + VLOG_OPTION_ENUMS, + LEAK_CHECKER_OPTION_ENUMS, + DAEMON_OPTION_ENUMS + }; + static struct option long_options[] = { + {"datapath-id", required_argument, NULL, OPT_DATAPATH_ID}, + {"mfr-desc", required_argument, NULL, OPT_MFR_DESC}, + {"hw-desc", required_argument, NULL, OPT_HW_DESC}, + {"sw-desc", required_argument, NULL, OPT_SW_DESC}, + {"serial-desc", required_argument, NULL, OPT_SERIAL_DESC}, + {"dp-desc", required_argument, NULL, OPT_DP_DESC}, + {"config", required_argument, NULL, 'F'}, + {"br-name", required_argument, NULL, OPT_BR_NAME}, + {"fail", required_argument, NULL, OPT_FAIL_MODE}, + {"inactivity-probe", required_argument, NULL, OPT_INACTIVITY_PROBE}, + {"max-idle", required_argument, NULL, OPT_MAX_IDLE}, + {"max-backoff", required_argument, NULL, OPT_MAX_BACKOFF}, + {"listen", required_argument, NULL, 'l'}, + {"snoop", required_argument, NULL, OPT_SNOOP}, + {"rate-limit", optional_argument, NULL, OPT_RATE_LIMIT}, + {"burst-limit", required_argument, NULL, OPT_BURST_LIMIT}, + {"out-of-band", no_argument, NULL, OPT_OUT_OF_BAND}, + {"in-band", no_argument, NULL, OPT_IN_BAND}, + {"netflow", required_argument, NULL, OPT_NETFLOW}, + {"ports", required_argument, NULL, OPT_PORTS}, + {"unixctl", required_argument, NULL, OPT_UNIXCTL}, + {"enable-dummy", no_argument, NULL, OPT_ENABLE_DUMMY}, + {"verbose", optional_argument, NULL, 'v'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'V'}, + DAEMON_LONG_OPTIONS, + VLOG_LONG_OPTIONS, + LEAK_CHECKER_LONG_OPTIONS, + STREAM_SSL_LONG_OPTIONS, + {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT}, + {NULL, 0, NULL, 0}, + }; + char *short_options = long_options_to_short_options(long_options); + struct ofproto_controller controller_opts; + struct sset controllers; + const char *name; + int i; + + /* Set defaults that we can figure out before parsing options. */ + controller_opts.target = NULL; + controller_opts.max_backoff = 8; + controller_opts.probe_interval = 5; + controller_opts.band = OFPROTO_IN_BAND; + controller_opts.rate_limit = 0; + controller_opts.burst_limit = 0; + s->unixctl_path = NULL; + s->fail_mode = OFPROTO_FAIL_STANDALONE; + s->datapath_id = 0; + s->mfr_desc = NULL; + s->hw_desc = NULL; + s->sw_desc = NULL; + s->serial_desc = NULL; + s->dp_desc = NULL; + sset_init(&controllers); + sset_init(&s->snoops); + s->max_idle = 0; + sset_init(&s->netflow); + sset_init(&s->ports); + for (;;) { + int c; + + c = getopt_long(argc, argv, short_options, long_options, NULL); + if (c == -1) { + break; + } + + switch (c) { + case OPT_DATAPATH_ID: + if (!dpid_from_string(optarg, &s->datapath_id)) { + VLOG_FATAL("argument to --datapath-id must be exactly 16 hex " + "digits and may not be all-zero"); + } + break; + + case OPT_MFR_DESC: + s->mfr_desc = optarg; + break; + + case OPT_HW_DESC: + s->hw_desc = optarg; + break; + + case OPT_SW_DESC: + s->sw_desc = optarg; + break; + + case OPT_SERIAL_DESC: + s->serial_desc = optarg; + break; + + case OPT_DP_DESC: + s->dp_desc = optarg; + break; + + case OPT_FAIL_MODE: + if (!strcmp(optarg, "open") || !strcmp(optarg, "standalone")) { + s->fail_mode = OFPROTO_FAIL_STANDALONE; + } else if (!strcmp(optarg, "closed") + || !strcmp(optarg, "secure")) { + s->fail_mode = OFPROTO_FAIL_SECURE; + } else { + VLOG_FATAL("--fail argument must be \"standalone\" " + "or \"secure\""); + } + break; + + case OPT_INACTIVITY_PROBE: + controller_opts.probe_interval = atoi(optarg); + if (controller_opts.probe_interval < 5) { + VLOG_FATAL("--inactivity-probe argument must be at least 5"); + } + break; + + case OPT_MAX_IDLE: + if (!strcmp(optarg, "permanent")) { + s->max_idle = OFP_FLOW_PERMANENT; + } else { + s->max_idle = atoi(optarg); + if (s->max_idle < 1 || s->max_idle > 65535) { + VLOG_FATAL("--max-idle argument must be between 1 and " + "65535 or the word 'permanent'"); + } + } + break; + + case OPT_MAX_BACKOFF: + controller_opts.max_backoff = atoi(optarg); + if (controller_opts.max_backoff < 1) { + VLOG_FATAL("--max-backoff argument must be at least 1"); + } else if (controller_opts.max_backoff > 3600) { + controller_opts.max_backoff = 3600; + } + break; + + case OPT_RATE_LIMIT: + if (optarg) { + controller_opts.rate_limit = atoi(optarg); + if (controller_opts.rate_limit < 1) { + VLOG_FATAL("--rate-limit argument must be at least 1"); + } + } else { + controller_opts.rate_limit = 1000; + } + break; + + case OPT_BURST_LIMIT: + controller_opts.burst_limit = atoi(optarg); + if (controller_opts.burst_limit < 1) { + VLOG_FATAL("--burst-limit argument must be at least 1"); + } + break; + + case OPT_OUT_OF_BAND: + controller_opts.band = OFPROTO_OUT_OF_BAND; + break; + + case OPT_IN_BAND: + controller_opts.band = OFPROTO_IN_BAND; + break; + + case OPT_NETFLOW: + sset_add(&s->netflow, optarg); + break; + + case 'l': + sset_add(&controllers, optarg); + break; + + case OPT_SNOOP: + sset_add(&s->snoops, optarg); + break; + + case OPT_PORTS: + parse_ports(optarg, &s->ports); + break; + + case OPT_UNIXCTL: + s->unixctl_path = optarg; + break; + + case OPT_ENABLE_DUMMY: + dummy_enable(); + break; + + case 'h': + usage(); + + case 'V': + OVS_PRINT_VERSION(OFP_VERSION, OFP_VERSION); + exit(EXIT_SUCCESS); + + DAEMON_OPTION_HANDLERS + + VLOG_OPTION_HANDLERS + + LEAK_CHECKER_OPTION_HANDLERS + + STREAM_SSL_OPTION_HANDLERS + + case OPT_BOOTSTRAP_CA_CERT: + stream_ssl_set_ca_cert_file(optarg, true); + break; + + case '?': + exit(EXIT_FAILURE); + + default: + abort(); + } + } + free(short_options); + + argc -= optind; + argv += optind; + if (argc < 2) { + VLOG_FATAL("need at least two non-option arguments; " + "use --help for usage"); + } + + /* Rate limiting. */ + if (controller_opts.rate_limit && controller_opts.rate_limit < 100) { + VLOG_WARN("Rate limit set to unusually low value %d", + controller_opts.rate_limit); + } + + /* Local vconns. */ + ofproto_parse_name(argv[0], &s->dp_name, &s->dp_type); + + /* Figure out controller names. */ + s->run_forever = false; + if (sset_is_empty(&controllers)) { + sset_add_and_free(&controllers, xasprintf("punix:%s/%s.mgmt", + ovs_rundir(), s->dp_name)); + } + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "none")) { + s->run_forever = true; + } else { + sset_add(&controllers, argv[i]); + } + } + + /* Set up controllers. */ + s->n_controllers = sset_count(&controllers); + s->controllers = xmalloc(s->n_controllers * sizeof *s->controllers); + i = 0; + SSET_FOR_EACH (name, &controllers) { + s->controllers[i] = controller_opts; + s->controllers[i].target = xstrdup(name); + i++; + } + sset_destroy(&controllers); +} + +static void +usage(void) +{ + printf("%s: an OpenFlow switch implementation.\n" + "usage: %s [OPTIONS] [TYPE@]DATAPATH CONTROLLER...\n" + "where DATAPATH is a local datapath (e.g. \"dp0\")\n" + "optionally with an explicit TYPE (default: \"system\").\n" + "Each CONTROLLER is an active OpenFlow connection method.\n", + program_name, program_name); + vconn_usage(true, true, true); + printf("\nOpenFlow options:\n" + " -d, --datapath-id=ID Use ID as the OpenFlow switch ID\n" + " (ID must consist of 16 hex digits)\n" + " --mfr-desc=MFR Identify manufacturer as MFR\n" + " --hw-desc=HW Identify hardware as HW\n" + " --sw-desc=SW Identify software as SW\n" + " --serial-desc=SERIAL Identify serial number as SERIAL\n" + " --dp-desc=DP_DESC Identify dp description as DP_DESC\n" + "\nNetworking options:\n" + " --fail=open|closed when controller connection fails:\n" + " closed: drop all packets\n" + " open (default): act as learning switch\n" + " --inactivity-probe=SECS time between inactivity probes\n" + " --max-idle=SECS max idle for flows set up by switch\n" + " --max-backoff=SECS max time between controller connection\n" + " attempts (default: 8 seconds)\n" + " -l, --listen=METHOD allow management connections on METHOD\n" + " (a passive OpenFlow connection method)\n" + " --snoop=METHOD allow controller snooping on METHOD\n" + " (a passive OpenFlow connection method)\n" + " --out-of-band controller connection is out-of-band\n" + " --netflow=HOST:PORT configure NetFlow output target\n" + "\nRate-limiting of \"packet-in\" messages to the controller:\n" + " --rate-limit[=PACKETS] max rate, in packets/s (default: 1000)\n" + " --burst-limit=BURST limit on packet credit for idle time\n"); + daemon_usage(); + vlog_usage(); + printf("\nOther options:\n" + " --unixctl=SOCKET override default control socket name\n" + " -h, --help display this help message\n" + " -V, --version display version information\n"); + leak_checker_usage(); + exit(EXIT_SUCCESS); +} |
