- Bridge compatibility daemon: vswitchd/brcompatd
- - Datapath administration utility: utilities/dpctl.
+ - Datapath administration utility: utilities/ovs-dpctl.
Some less important binaries will be built also:
program such as "su" to become root temporarily.
1. Create a datapath instance. The command below creates a datapath
- identified as dp0 (see dpctl(8) for more detailed usage
+ identified as dp0 (see ovs-dpctl(8) for more detailed usage
information).
- # dpctl adddp dp0
+ # ovs-dpctl adddp dp0
(dp0 is the first datapath within a host. openvswitch_mod supports
multiple datapaths within the same host, which would be identified
bridged to the physical switch ports by the secchan, for use in
in-band control.
-2. Use dpctl to attach the datapath to physical interfaces on the
+2. Use ovs-dpctl to attach the datapath to physical interfaces on the
machine. Say, for example, you want to create a trivial 2-port
- switch using interfaces eth1 and eth2, you would issue the following
- commands:
+ switch using interfaces eth1 and eth2, you would issue the
+ following commands:
- # dpctl addif dp0 eth1
- # dpctl addif dp0 eth2
+ # ovs-dpctl addif dp0 eth1
+ # ovs-dpctl addif dp0 eth2
You can verify that the interfaces were successfully added by asking
- dpctl to print the current status of datapath dp0:
+ ovs-dpctl to print the current status of datapath dp0:
- # dpctl show dp0
+ # ovs-dpctl show dp0
3. Arrange so that the switch can reach the controller over the
network.
- vswitchd, a daemon that implements the virtual switch.
- - dpctl, a tool for configuring the kernel module and
+ - ovs-dpctl, a tool for configuring the kernel module and
controlling OpenFlow switches.
This distribution includes some additional software as well:
- ovs-controller, a simple OpenFlow switch
+ - ovs-ofctl, a utility for querying and controlling OpenFlow
+ switches and controllers.
+
- vlog-appctl, a utility that can control OpenVSwitch daemons,
adjusting their logging levels among other uses.
check_op "Removing IP address from $netdev" ifconfig $netdev 0.0.0.0
done
- must_succeed "Creating datapath" dpctl adddp of0 $NETDEVS
+ must_succeed "Creating datapath" ovs-dpctl adddp of0 $NETDEVS
xx='[0-9abcdefABCDEF][0-9abcdefABCDEF]'
case $DATAPATH_ID in
--exec $DAEMON
echo "$NAME."
- check_op "Deleting datapath" dpctl deldp of0
+ check_op "Deleting datapath" ovs-dpctl deldp of0
check_op "Unloading kernel module" modprobe -r openvswitch_mod
;;
force-stop)
_debian/secchan/secchan usr/sbin
-_debian/utilities/dpctl usr/sbin
+_debian/utilities/ovs-dpctl usr/sbin
_debian/utilities/ovs-discover usr/sbin
_debian/utilities/ovs-kill usr/sbin
+_debian/utilities/ovs-ofctl usr/sbin
debian/openvswitch/usr/share/openvswitch/commands/* usr/share/openvswitch/commands
debian/commands/* usr/share/openvswitch/commands
_debian/secchan/secchan.8
_debian/utilities/ovs-discover.8
+_debian/utilities/ovs-dpctl.8
_debian/utilities/ovs-kill.8
-_debian/utilities/dpctl.8
+_debian/utilities/ovs-ofctl.8
#CACERT_MODE=secure
# MGMT_VCONNS: List of vconns (space-separated) on which secchan
-# should listen for management connections from dpctl, etc.
+# should listen for management connections from ovs-ofctl, etc.
# openvswitch-switchui by default connects to
# unix:/var/run/secchan.mgmt, so do not disable this if you want to
# use openvswitch-switchui.
.SH "SEE ALSO"
+.BR ovs\-dpctl (8),
.BR ovs-pki (8),
-.BR dpctl (8),
.BR secchan (8)
VLOG_MODULE(netdev)
VLOG_MODULE(netflow)
VLOG_MODULE(netlink)
+VLOG_MODULE(ofctl)
VLOG_MODULE(ovs_discover)
VLOG_MODULE(ofproto)
VLOG_MODULE(pktbuf)
.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 \fBdpctl
+any of the network devices added to the datapath with \fBovs\-dpctl
addif\fR in its communication with the controller.
To use \fBsecchan\fR in a network with out-of-band control, specify
.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 \fBdpctl
+over one of the network devices added to the datapath with \fBovs\-dpctl
addif\fR. This configuration is often more convenient than
out-of-band control, because it is not necessary to maintain two
independent networks.
In this mode, \fBsecchan\fR will broadcast a DHCP request with vendor
class identifier \fBOpenFlow\fR across the network devices added to
-the datapath with \fBdpctl addif\fR. It will accept any valid DHCP
+the datapath with \fBovs\-dpctl addif\fR. It will accept any valid DHCP
reply that has the same vendor class identifier and includes a
vendor-specific option with code 1 whose contents are a string
specifying the location of the controller in the same format used on
``local port'' to allow \fBsecchan\fR to connect to that controller.
The OpenFlow local port is a virtual network port that \fBsecchan\fR
bridges to the physical switch ports. The name of the local port for
-a given \fIdatapath\fR may be seen by running \fBdpctl dp-show
+a given \fIdatapath\fR may be seen by running \fBovs\-dpctl dp-show
\fIdatapath\fR; the local port is listed as port 0 in \fBdp-show\fR's
output.
.TP
\fB-l\fR, \fB--listen=\fImethod\fR
Configures the switch to additionally listen for incoming OpenFlow
-connections for switch management with \fBdpctl\fR. The \fImethod\fR
+connections for switch management with \fBovs\-ofctl\fR. 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.
under the \fB--listen\fR option above. This option may be specified
multiple times to listen to multiple connection methods.
-If \fBdpctl monitor\fR is used to connect to \fImethod\fR specified on
+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
.TP
\fB--command-acl=\fR[\fB!\fR]\fIglob\fR[\fB,\fR[\fB!\fR]\fIglob\fR...]
Configures the commands that remote OpenFlow connections are allowed
-to invoke using (e.g.) \fBdpctl execute\fR. The argument is a
+to invoke using (e.g.) \fBovs\-ofctl execute\fR. The argument is a
comma-separated sequence of shell glob patterns. A glob pattern
specified without a leading \fB!\fR is a ``whitelist'' that specifies
a set of commands that are that may be invoked, whereas a pattern that
.SH "SEE ALSO"
-.BR dpctl (8),
.BR ovs\-appctl (8),
-.BR ovs-discover (8),
.BR ovs\-controller (8),
-.BR ovs-pki (8),
+.BR ovs\-discover (8),
+.BR ovs\-dpctl (8),
+.BR ovs\-ofctl (8),
+.BR ovs\-pki (8),
.BR vswitchd.conf (5)
/Makefile
/Makefile.in
-/dpctl
-/dpctl.8
/nlmon
/ovs-appctl
/ovs-appctl.8
/ovs-controller.8
/ovs-discover
/ovs-discover.8
+/ovs-dpctl
+/ovs-dpctl.8
/ovs-kill
/ovs-kill.8
+/ovs-ofctl
+/ovs-ofctl.8
/ovs-parse-leaks
/ovs-pki
/ovs-pki-cgi
bin_PROGRAMS += \
- utilities/dpctl \
utilities/ovs-appctl \
utilities/ovs-cfg-mod \
utilities/ovs-controller \
utilities/ovs-discover \
+ utilities/ovs-dpctl \
utilities/ovs-kill \
+ utilities/ovs-ofctl \
utilities/ovs-wdt
noinst_PROGRAMS += utilities/nlmon
bin_SCRIPTS += utilities/ovs-pki
dist_sbin_SCRIPTS += utilities/ovs-monitor
EXTRA_DIST += \
- utilities/dpctl.8.in \
utilities/ovs-appctl.8.in \
utilities/ovs-cfg-mod.8.in \
utilities/ovs-controller.8.in \
utilities/ovs-discover.8.in \
+ utilities/ovs-dpctl.8.in \
utilities/ovs-kill.8.in \
+ utilities/ovs-ofctl.8.in \
utilities/ovs-parse-leaks.in \
utilities/ovs-pki-cgi.in \
utilities/ovs-pki.8.in \
utilities/ovs-pki.in
DISTCLEANFILES += \
- utilities/dpctl.8 \
utilities/ovs-appctl.8 \
utilities/ovs-cfg-mod.8 \
utilities/ovs-controller.8 \
utilities/ovs-discover.8 \
+ utilities/ovs-dpctl.8 \
utilities/ovs-kill.8 \
+ utilities/ovs-ofctl.8 \
utilities/ovs-parse-leaks \
utilities/ovs-pki \
utilities/ovs-pki.8 \
utilities/ovs-pki-cgi
man_MANS += \
- utilities/dpctl.8 \
utilities/ovs-appctl.8 \
utilities/ovs-cfg-mod.8 \
utilities/ovs-controller.8 \
utilities/ovs-discover.8 \
+ utilities/ovs-dpctl.8 \
utilities/ovs-kill.8 \
+ utilities/ovs-ofctl.8 \
utilities/ovs-pki.8
-utilities_dpctl_SOURCES = utilities/dpctl.c
-utilities_dpctl_LDADD = lib/libopenvswitch.a $(FAULT_LIBS) $(SSL_LIBS)
-
utilities_ovs_appctl_SOURCES = utilities/ovs-appctl.c
utilities_ovs_appctl_LDADD = lib/libopenvswitch.a
utilities_ovs_discover_SOURCES = utilities/ovs-discover.c
utilities_ovs_discover_LDADD = lib/libopenvswitch.a
+utilities_ovs_dpctl_SOURCES = utilities/ovs-dpctl.c
+utilities_ovs_dpctl_LDADD = lib/libopenvswitch.a $(FAULT_LIBS)
+
utilities_ovs_kill_SOURCES = utilities/ovs-kill.c
utilities_ovs_kill_LDADD = lib/libopenvswitch.a
+utilities_ovs_ofctl_SOURCES = utilities/ovs-ofctl.c
+utilities_ovs_ofctl_LDADD = lib/libopenvswitch.a $(FAULT_LIBS) $(SSL_LIBS)
+
utilities_ovs_wdt_SOURCES = utilities/ovs-wdt.c
utilities_nlmon_SOURCES = utilities/nlmon.c
+++ /dev/null
-.TH dpctl 8 "March 2009" "OpenVSwitch" "OpenVSwitch Manual"
-.ds PN dpctl
-
-.SH NAME
-dpctl \- administer OpenVSwitch datapaths and OpenFlow switches
-
-.SH SYNOPSIS
-.B dpctl
-[\fIoptions\fR] \fIcommand \fR[\fIswitch\fR] [\fIargs\fR\&...]
-
-.SH DESCRIPTION
-The
-.B dpctl
-program is a command line tool for monitoring and administering
-OpenVSwitch datapaths and OpenFlow switches.
-.B dpctl
-can add, delete, and modify OpenVSwitch datapaths. It can also show
-the current state of an OpenFlow switch, including features,
-configuration, and table entries.
-
-.SS "OpenVSwitch Datapath Commands"
-
-The \fBdpctl\fR program can create, modify, and delete OpenVSwitch
-datapaths. A single machine may host up to 256 datapaths (numbered 0
-to 255).
-
-A newly created datapath is associated with only one network device, a
-virtual network device sometimes called the datapath's ``local port''.
-A newly created datapath is not, however, associated with any of the
-host's other network devices. To intercept and process traffic on a
-given network device, use the \fBaddif\fR command to explicitly add
-that network device to the datapath.
-
-Do not use \fBdpctl\fR commands to modify datapaths in conjunction
-with \fBvswitchd\fR(8). Instead, modify the \fBvswitchd\fR
-configuration file and send \fBSIGHUP\fR to the \fBvswitchd\fR
-process.
-
-.PP
-Most \fBdpctl\fR commands that work with datapaths take an argument
-that specifies the name of the datapath, in one of the following
-forms:
-
-.so lib/dpif.man
-
-.PP
-The following commands manage datapaths.
-
-.TP
-\fBadddp \fIdp\fR [\fInetdev\fR...]
-
-Creates datapath \fIdp\fR. The name of the new datapath's local port
-depends on how \fIdp\fR is specified: if it takes the form
-\fBdp\fIN\fR, the local port will be named \fBdp\fIN\fR; if \fIdp\fR
-is \fBnl:\fI, the local port will be named \fBof\fIN\fR; otherwise,
-the local port's name will be \fIdp\fR.
-
-This will fail if the host already has 256 datapaths, if a network
-device with the same name as the new datapath's local port already
-exists, or if \fIdp\fR is given in the form \fBdp\fIN\fR or
-\fBnl:\fIN\fR and a datapath numbered \fIN\fR already exists.
-
-If \fInetdev\fRs are specified, \fBdpctl\fR adds them to the datapath.
-
-.TP
-\fBdeldp \fIdp\fR
-Deletes datapath \fIdp\fR. If \fIdp\fR is associated with any network
-devices, they are automatically removed.
-
-.TP
-\fBaddif \fIdp netdev\fR[\fIoption\fR...]...
-Adds each \fInetdev\fR to the set of network devices datapath
-\fIdp\fR monitors, where \fIdp\fR is the name of an existing
-datapath, and \fInetdev\fR is the name of one of the host's
-network devices, e.g. \fBeth0\fR. Once a network device has been added
-to a datapath, the datapath has complete ownership of the network device's
-traffic and the network device appears silent to the rest of the
-system.
-
-A \fInetdev\fR may be followed by a comma-separated list of options.
-The following options are currently supported:
-
-.RS
-.IP "\fBport=\fIportno\fR"
-Specifies \fIportno\fR (a number between 1 and 255) as the port number
-at which \fInetdev\fR will be attached. By default, \fBaddif\fR
-automatically selects the lowest available port number.
-
-.IP "\fBinternal\fR"
-Instead of attaching an existing \fInetdev\fR, creates an internal
-port (analogous to the local port) with that name.
-.RE
-
-.TP
-\fBdelif \fIdp netdev\fR...
-Removes each \fInetdev\fR from the list of network devices datapath
-\fIdp\fR monitors.
-
-.TP
-\fBget-idx \fIdp\fR
-Prints the datapath number of datapath \fIdp\fR.
-
-.TP
-\fBget-name \fIdp\fR
-Prints the name of datapath \fIdp\fR, that is, the name of the network
-device acting as its local port.
-
-.TP
-\fBdp-show \fR[\fIdp\fR...]
-Prints a summary of configured datapaths, including their datapath
-numbers and a list of ports connected to each datapath. (The local
-port is identified as port 0.)
-
-If one or more datapaths are specified, information on only those
-datapaths are displayed. Otherwise, \fBdpctl\fR displays information
-about all configured datapaths.
-
-.IP "\fBdp-dump-flows \fIdp\fR"
-Prints to the console all flow entries in datapath \fIdp\fR's
-flow table.
-
-This command is primarily useful for debugging OpenVSwitch. The flow
-table entries that it displays are not
-OpenFlow flow entries. Instead, they are different and considerably
-simpler flows maintained by the OpenVSwitch kernel module.
-
-.IP "\fBdp-del-flows \fIdp\fR"
-Deletes all flow entries from datapath \fIdp\fR's flow table.
-
-This command is primarily useful for debugging OpenVSwitch. As
-discussed in \fBdp-dump-flows\fR, these entries are
-not OpenFlow flow entries. By deleting them, the process that set them
-up may be confused about their disappearance.
-
-.IP "\fBdp-dump-groups \fIdp\fR"
-Prints to the console the sets of port groups maintained by datapath
-\fIdp\fR. Ordinarily there are at least 2 port groups in a datapath
-that \fBsecchan\fR or \fBvswitch\fR is controlling: group 0 contains
-all ports except those disabled by STP, and group 1 contains all
-ports. Additional groups might be used in the future.
-
-This command is primarily useful for debugging OpenVSwitch. OpenFlow
-does not have a concept of port groups.
-
-.SS "OpenFlow Switch Management Commands"
-
-These commands allow \fBdpctl\fR to monitor and administer an OpenFlow
-switch. It is able to show the current state of a switch, including
-features, configuration, and table entries.
-
-Most of these commands take an argument that specifies the method for
-connecting to an OpenFlow switch. The following connection methods
-are supported:
-
-.RS
-.TP
-\fBssl:\fIhost\fR[\fB:\fIport\fR]
-The specified SSL \fIport\fR (default: 6633) on the given remote
-\fIhost\fR. The \fB--private-key\fR, \fB--certificate\fR, and
-\fB--ca-cert\fR options are mandatory when this form is used.
-
-.TP
-\fBtcp:\fIhost\fR[\fB:\fIport\fR]
-The specified TCP \fIport\fR (default: 6633) on the given remote
-\fIhost\fR.
-
-.TP
-\fBunix:\fIfile\fR
-The Unix domain server socket named \fIfile\fR.
-
-.IP "\fIfile\fR"
-This is short for \fBunix:\fIfile\fR, as long as \fIfile\fR does not
-contain a colon.
-
-.IP \fIdp\fR
-This is short for \fBunix:@RUNDIR@/\fIdp\fB.mgmt\fR, as long as
-\fIdp\fR does not contain a colon.
-.RE
-
-.TP
-\fBshow \fIswitch\fR
-Prints to the console information on \fIswitch\fR, including
-information on its flow tables and ports.
-
-.TP
-\fBstatus \fIswitch\fR [\fIkey\fR]
-Prints to the console a series of key-value pairs that report the
-status of \fIswitch\fR. If \fIkey\fR is specified, only the key-value
-pairs whose key names begin with \fIkey\fR are printed. If \fIkey\fR is
-omitted, all key-value pairs are printed.
-
-.TP
-\fBdump-tables \fIswitch\fR
-Prints to the console statistics for each of the flow tables used by
-\fIswitch\fR.
-
-.TP
-\fBdump-ports \fIswitch\fR
-Prints to the console statistics for each of the network devices
-associated with \fIswitch\fR.
-
-.TP
-\fBmod-port \fIswitch\fR \fInetdev\fR \fIaction\fR
-Modify characteristics of an interface monitored by \fIswitch\fR.
-\fInetdev\fR can be referred to by its OpenFlow assigned port number or
-the device name, e.g. \fBeth0\fR. The \fIaction\fR may be any one of the
-following:
-
-.RS
-.IP \fBup\fR
-Enables the interface. This is equivalent to ``ifconfig up'' on a Unix
-system.
-
-.IP \fBdown\fR
-Disables the interface. This is equivalent to ``ifconfig down'' on a Unix
-system.
-
-.IP \fBflood\fR
-When a \fIflood\fR action is specified, traffic will be sent out this
-interface. This is the default posture for monitored ports.
-
-.IP \fBnoflood\fR
-When a \fIflood\fR action is specified, traffic will not be sent out
-this interface. This is primarily useful to prevent loops when a
-spanning tree protocol is not in use.
-
-.RE
-
-.TP
-\fBdump-flows \fIswitch \fR[\fIflows\fR]
-Prints to the console all flow entries in \fIswitch\fR's
-tables that match \fIflows\fR. If \fIflows\fR is omitted, all flows
-in the switch are retrieved. See \fBFlow Syntax\fR, below, for the
-syntax of \fIflows\fR. The output format is described in
-\fBTable Entry Output\fR.
-
-.TP
-\fBdump-aggregate \fIswitch \fR[\fIflows\fR]
-Prints to the console aggregate statistics for flows in
-\fIswitch\fR's tables that match \fIflows\fR. If \fIflows\fR is omitted,
-the statistics are aggregated across all flows in the switch's flow
-tables. See \fBFlow Syntax\fR, below, for the syntax of \fIflows\fR.
-The output format is descrbed in \fBTable Entry Output\fR.
-
-.TP
-\fBadd-flow \fIswitch flow\fR
-Add the flow entry as described by \fIflow\fR to the \fIswitch\fR's
-tables. The flow entry is in the format described in \fBFlow Syntax\fR,
-below.
-
-.TP
-\fBadd-flows \fIswitch file\fR
-Add flow entries as described in \fIfile\fR to \fIswitch\fR's
-tables. Each line in \fIfile\fR is a flow entry in the format
-described in \fBFlow Syntax\fR, below.
-
-.TP
-\fBmod-flows \fIswitch flow\fR
-Modify the actions in entries from the \fIswitch\fR's tables
-that match \fIflow\fR. When invoked with the \fB--strict\fR option,
-wildcards are not treated as active for matching purposes. See
-\fBFlow Syntax\fR, below, for the syntax of \fIflows\fR.
-
-.TP
-\fBdel-flows \fIswitch \fR[\fIflow\fR]
-Deletes entries from the \fIswitch\fR's tables that match
-\fIflow\fR. When invoked with the \fB--strict\fR option, wildcards are
-not treated as active for matching purposes. If \fIflow\fR is
-omitted and the \fB--strict\fR option is not used, all flows in the
-switch's tables are removed. See \fBFlow Syntax\fR, below, for the
-syntax of \fIflows\fR.
-
-.TP
-\fBmonitor \fIswitch\fR [\fImiss-len\fR [\fIsend-exp]]
-Connects to \fIswitch\fR and prints to the console all OpenFlow
-messages received. Usually, \fIswitch\fR should specify a connection
-named on \fBsecchan\fR(8)'s \fB-l\fR or \fB--listen\fR command line
-option.
-
-If \fImiss-len\fR is provided, \fBdpctl\fR sends an OpenFlow ``set
-configuration'' message at connection setup time that requests
-\fImiss-len\fR bytes of each packet that misses the flow table. The
-OpenFlow reference implementation not send these messages to the
-\fBdpctl monitor\fR client connection unless a nonzero value is
-specified on this argument.
-
-If \fIsend-exp\fR is specified as \fB1\fR, \fBdpctl\fR will also
-request to be sent flow expiration messages. If this argument is
-omitted, or \fB0\fR is specified, then \fRdpctl\fR will not request
-flow expirations.
-
-This command may be useful for debugging switch or controller
-implementations.
-
-.TP
-\fBexecute \fIswitch command \fR[\fIarg\fR...]
-Sends a request to \fIswitch\fR to execute \fIcommand\fR along with
-each \fIarg\fR, if any, then waits for the command to complete and
-reports its completion status on \fBstderr\fR and its output, if any,
-on \fBstdout\fR. The set of available commands and their argument is
-switch-dependent. (This command uses a Nicira extension to OpenFlow
-that may not be available on all switches.)
-
-.SS "OpenFlow Switch and Controller Commands"
-
-The following commands, like those in the previous section, may be
-applied to OpenFlow switches, using any of the connection methods
-described in that section. Unlike those commands, these may also be
-applied to OpenFlow controllers.
-
-.TP
-\fBprobe \fItarget\fR
-Sends a single OpenFlow echo-request message to \fItarget\fR and waits
-for the response. With the \fB-t\fR or \fB--timeout\fR option, this
-command can test whether an OpenFlow switch or controller is up and
-running.
-
-.TP
-\fBping \fItarget \fR[\fIn\fR]
-Sends a series of 10 echo request packets to \fItarget\fR and times
-each reply. The echo request packets consist of an OpenFlow header
-plus \fIn\fR bytes (default: 64) of randomly generated payload. This
-measures the latency of individual requests.
-
-.TP
-\fBbenchmark \fItarget n count\fR
-Sends \fIcount\fR echo request packets that each consist of an
-OpenFlow header plus \fIn\fR bytes of payload and waits for each
-response. Reports the total time required. This is a measure of the
-maximum bandwidth to \fItarget\fR for round-trips of \fIn\fR-byte
-messages.
-
-.SS "Flow Syntax"
-
-Some \fBdpctl\fR commands accept an argument that describes a flow or
-flows. Such flow descriptions comprise a series
-\fIfield\fB=\fIvalue\fR assignments, separated by commas or white
-space. (Embedding spaces into a flow description normally requires
-quoting to prevent the shell from breaking the description into
-multiple arguments.)
-
-The following field assignments describe how a flow matches a packet.
-If any of these assignments is omitted from the flow syntax, the field
-is treated as a wildcard; thus, if all of them are omitted, the
-resulting flow matches all packets. The string \fB*\fR or \fBANY\fR
-may be specified to explicitly mark any of these fields as a wildcard.
-(\fB*\fR should be quoted to protect it from shell expansion.)
-
-.IP \fBin_port=\fIport_no\fR
-Matches physical port \fIport_no\fR. Switch ports are numbered as
-displayed by \fBdpctl show\fR.
-
-.IP \fBdl_vlan=\fIvlan\fR
-Matches IEEE 802.1q virtual LAN tag \fIvlan\fR. Specify \fB0xffff\fR
-as \fIvlan\fR to match packets that are not tagged with a virtual LAN;
-otherwise, specify a number between 0 and 4095, inclusive, as the
-12-bit VLAN ID to match.
-
-.IP \fBdl_src=\fImac\fR
-Matches Ethernet source address \fImac\fR, which is specified as 6 pairs
-of hexadecimal digits delimited by colons (e.g. \fB00:0A:E4:25:6B:B0\fR).
-
-.IP \fBdl_dst=\fImac\fR
-Matches Ethernet destination address \fImac\fR.
-
-.IP \fBdl_type=\fIethertype\fR
-Matches Ethernet protocol type \fIethertype\fR, which is specified as an
-integer between 0 and 65535, inclusive, either in decimal or as a
-hexadecimal number prefixed by \fB0x\fR (e.g. \fB0x0806\fR to match ARP
-packets).
-
-.IP \fBnw_src=\fIip\fR[\fB/\fInetmask\fR]
-Matches IPv4 source address \fIip\fR, which may be specified as an
-IP address or host name (e.g. \fB192.168.1.1\fR or
-\fBwww.example.com\fR). The optional \fInetmask\fR allows restricting a
-match to an IPv4 address prefix. The netmask may be specified as a dotted
-quad (e.g. \fB192.168.1.0/255.255.255.0\fR) or as a CIDR block
-(e.g. \fB192.168.1.0/24\fR).
-
-.IP \fBnw_dst=\fIip\fR[\fB/\fInetmask\fR]
-Matches IPv4 destination address \fIip\fR.
-
-.IP \fBnw_proto=\fIproto\fR
-Matches IP protocol type \fIproto\fR, which is specified as a decimal
-number between 0 and 255, inclusive (e.g. 6 to match TCP packets).
-
-.IP \fBtp_src=\fIport\fR
-Matches UDP or TCP source port \fIport\fR, which is specified as a decimal
-number between 0 and 65535, inclusive (e.g. 80 to match packets originating
-from a HTTP server).
-
-.IP \fBtp_dst=\fIport\fR
-Matches UDP or TCP destination port \fIport\fR.
-
-.IP \fBicmp_type=\fItype\fR
-Matches ICMP message with \fItype\fR, which is specified as a decimal
-number between 0 and 255, inclusive.
-
-.IP \fBicmp_code=\fIcode\fR
-Matches ICMP messages with \fIcode\fR.
-
-.PP
-The following shorthand notations are also available:
-
-.IP \fBip\fR
-Same as \fBdl_type=0x0800\fR.
-
-.IP \fBicmp\fR
-Same as \fBdl_type=0x0800,nw_proto=1\fR.
-
-.IP \fBtcp\fR
-Same as \fBdl_type=0x0800,nw_proto=6\fR.
-
-.IP \fBudp\fR
-Same as \fBdl_type=0x0800,nw_proto=17\fR.
-
-.IP \fBarp\fR
-Same as \fBdl_type=0x0806\fR.
-
-.PP
-The \fBadd-flow\fR and \fBadd-flows\fR commands require an additional field:
-
-.IP \fBactions=\fR[\fItarget\fR][\fB,\fItarget\fR...]\fR
-Specifies a comma-separated list of actions to take on a packet when the
-flow entry matches. If no \fItarget\fR is specified, then packets
-matching the flow are dropped. The \fItarget\fR may be a decimal port
-number designating the physical port on which to output the packet, or one
-of the following keywords:
-
-.RS
-.IP \fBoutput\fR:\fIport\fR
-Outputs the packet on the port specified by \fIport\fR.
-
-.IP \fBnormal\fR
-Subjects the packet to the device's normal L2/L3 processing. (This
-action is not implemented by all OpenFlow switches.)
-
-.IP \fBflood\fR
-Outputs the packet on all switch physical ports other than the port on
-which it was received and any ports on which flooding is disabled
-(typically, these would be ports disabled by the IEEE 802.1D spanning
-tree protocol).
-
-.IP \fBall\fR
-Outputs the packet on all switch physical ports other than the port on
-which it was received.
-
-.IP \fBcontroller\fR:\fImax_len\fR
-Sends the packet to the OpenFlow controller as a ``packet in''
-message. If \fImax_len\fR is a number, then it specifies the maximum
-number of bytes that should be sent. If \fImax_len\fR is \fBALL\fR or
-omitted, then the entire packet is sent.
-
-.IP \fBlocal\fR
-Outputs the packet on the ``local port,'' which corresponds to the
-\fBof\fIn\fR network device (see \fBCONTACTING THE CONTROLLER\fR in
-\fBsecchan\fR(8) for information on the \fBof\fIn\fR network device).
-
-.IP \fBdrop\fR
-Discards the packet, so no further processing or forwarding takes place.
-If a drop action is used, no other actions may be specified.
-
-.IP \fBmod_vlan_vid\fR:\fIvlan_vid\fR
-Modifies the VLAN id on a packet. The VLAN tag is added or modified
-as necessary to match the value specified. If the VLAN tag is added,
-a priority of zero is used (see the \fBmod_vlan_pcp\fR action to set
-this).
-
-.IP \fBmod_vlan_pcp\fR:\fIvlan_pcp\fR
-Modifies the VLAN priority on a packet. The VLAN tag is added or modified
-as necessary to match the value specified. Valid values are between 0
-(lowest) and 7 (highest). If the VLAN tag is added, a vid of zero is used
-(see the \fBmod_vlan_vid\fR action to set this).
-
-.IP \fBstrip_vlan\fR
-Strips the VLAN tag from a packet if it is present.
-
-.IP \fBmod_dl_src\fB:\fImac\fR
-Sets the source Ethernet address to \fImac\fR.
-
-.IP \fBmod_dl_dst\fB:\fImac\fR
-Sets the destination Ethernet address to \fImac\fR.
-.RE
-
-.IP
-(The OpenFlow protocol supports other actions that \fBdpctl\fR does
-not yet expose to the user.)
-
-.PP
-The \fBadd-flow\fR, \fBadd-flows\fR, and \fBdel-flows\fR commands
-support an additional optional field:
-
-.IP \fBpriority=\fIvalue\fR
-The priority at which a wildcarded entry will match in comparison to
-others. \fIvalue\fR is a number between 0 and 65535, inclusive. A higher
-\fIvalue\fR will match before a lower one. An exact-match entry will always
-have priority over an entry containing wildcards, so it has an implicit
-priority value of 65535. When adding a flow, if the field is not specified,
-the flow's priority will default to 32768.
-
-.PP
-The \fBadd-flow\fR and \fBadd-flows\fR commands support additional
-optional fields:
-
-.TP
-\fBidle_timeout=\fIseconds\fR
-Causes the flow to expire after the given number of seconds of
-inactivity. A value of 0 prevents a flow from expiring due to
-inactivity. The default is 60 seconds.
-
-.IP \fBhard_timeout=\fIseconds\fR
-Causes the flow to expire after the given number of seconds,
-regardless of activity. A value of 0 (the default) gives the flow no
-hard expiration deadline.
-
-.PP
-The \fBdump-flows\fR, \fBdump-aggregate\fR, \fBdel-flow\fR
-and \fBdel-flows\fR commands support one additional optional field:
-
-.TP
-\fBout_port=\fIport\fR
-If set, a matching flow must include an output action to \fIport\fR.
-
-.PP
-The \fBdump-flows\fR and \fBdump-aggregate\fR commands support an
-additional optional field:
-
-.IP \fBtable=\fInumber\fR
-If specified, limits the flows about which statistics are gathered to
-those in the table with the given \fInumber\fR. Tables are numbered
-as shown by the \fBdump-tables\fR command.
-
-If this field is not specified, or if \fInumber\fR is given as
-\fB255\fR, statistics are gathered about flows from all tables.
-
-.SS "Table Entry Output"
-
-The \fBdump-tables\fR and \fBdump-aggregate\fR commands print information
-about the entries in a datapath's tables. Each line of output is a
-unique flow entry, which begins with some common information:
-
-.IP \fBduration\fR
-The number of seconds the entry has been in the table.
-
-.IP \fBtable_id\fR
-The table that contains the flow. When a packet arrives, the switch
-begins searching for an entry at the lowest numbered table. Tables are
-numbered as shown by the \fBdump-tables\fR command.
-
-.IP \fBpriority\fR
-The priority of the entry in relation to other entries within the same
-table. A higher value will match before a lower one.
-
-.IP \fBn_packets\fR
-The number of packets that have matched the entry.
-
-.IP \fBn_bytes\fR
-The total number of bytes from packets that have matched the entry.
-
-.PP
-The rest of the line consists of a description of the flow entry as
-described in \fBFlow Syntax\fR, above.
-
-
-.SH OPTIONS
-.TP
-\fB--strict\fR
-Uses strict matching when running flow modification commands.
-
-.TP
-\fB-t\fR, \fB--timeout=\fIsecs\fR
-Limits \fBdpctl\fR runtime to approximately \fIsecs\fR seconds. If
-the timeout expires, \fBdpctl\fR will exit with a \fBSIGALRM\fR
-signal.
-
-.TP
-\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR
-Specifies a PEM file containing the private key used as the
-identity for SSL connections to a switch.
-
-.TP
-\fB-c\fR, \fB--certificate=\fIcert.pem\fR
-Specifies a PEM file containing a certificate, signed by the
-controller's certificate authority (CA), that certifies the
-private key to identify a trustworthy controller.
-
-.TP
-\fB-C\fR, \fB--ca-cert=\fIcacert.pem\fR
-Specifies a PEM file containing the CA certificate used to verify that
-a switch is trustworthy.
-
-.so lib/vlog.man
-.so lib/common.man
-
-.SH EXAMPLES
-
-.SS "Datapath Examples"
-
-A typical \fBdpctl\fR command sequence for controlling an OpenFlow
-kernel module:
-
-.TP
-\fBdpctl adddp dp0\fR
-Creates datapath numbered 0.
-
-.TP
-\fBdpctl addif dp0 eth0 eth1\fR
-Adds two network devices to the new datapath.
-
-.PP
-At this point one would ordinarily start \fBsecchan\fR(8) on
-\fBdp0\fR, transforming \fBdp0\fR into an OpenFlow switch. Then, when
-the switch and the datapath is no longer needed:
-
-.TP
-\fBdpctl delif dp0 eth0 eth1\fR
-Removes network devices from the datapath.
-
-.TP
-\fBdpctl deldp dp0\fR
-Deletes the datapath.
-
-.SS "OpenFlow Switch Examples"
-
-The following examples assume that an OpenFlow switch on the local
-host has been configured to listen for management connections on a
-Unix domain socket named \fB@RUNDIR@/openflow.sock\fR, e.g. by
-specifying \fB--listen=punix:@RUNDIR@/openflow.sock\fR on the
-\fBsecchan\fR(8) command line.
-
-.TP
-\fBdpctl dump-tables unix:@RUNDIR@/openflow.sock\fR
-Prints out the switch's table stats. (This is more interesting after
-some traffic has passed through.)
-
-.TP
-\fBdpctl dump-flows unix:@RUNDIR@/openflow.sock\fR
-Prints the flow entries in the switch.
-
-.SH "SEE ALSO"
-
-.BR vswitchd (8),
-.BR secchan (8),
-.BR ovs\-appctl (8),
-.BR ovs\-controller (8)
+++ /dev/null
-/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford
- * Junior University
- *
- * We are making the OpenFlow specification and associated documentation
- * (Software) available for public use and benefit with the expectation
- * that others will use, modify and enhance the Software and contribute
- * those enhancements back to the community. However, since we would
- * like to make the Software available for broadest use, with as few
- * restrictions as possible permission is hereby granted, free of
- * charge, to any person obtaining a copy of this Software to deal in
- * the Software under the copyrights without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * The name and trademarks of copyright holder(s) may NOT be used in
- * advertising or publicity pertaining to the Software or any
- * derivatives without specific, written prior permission.
- */
-
-#include <config.h>
-#include <arpa/inet.h>
-#include <errno.h>
-#include <getopt.h>
-#include <inttypes.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-
-#include "command-line.h"
-#include "compiler.h"
-#include "dirs.h"
-#include "dpif.h"
-#include "dynamic-string.h"
-#include "netdev.h"
-#include "netlink.h"
-#include "odp-util.h"
-#include "ofp-print.h"
-#include "ofpbuf.h"
-#include "openflow/nicira-ext.h"
-#include "openflow/openflow.h"
-#include "packets.h"
-#include "random.h"
-#include "socket-util.h"
-#include "timeval.h"
-#include "util.h"
-#include "vconn-ssl.h"
-#include "vconn.h"
-
-#include "vlog.h"
-#define THIS_MODULE VLM_dpctl
-
-#define DEFAULT_IDLE_TIMEOUT 60
-
-#define MOD_PORT_CMD_UP "up"
-#define MOD_PORT_CMD_DOWN "down"
-#define MOD_PORT_CMD_FLOOD "flood"
-#define MOD_PORT_CMD_NOFLOOD "noflood"
-
-
-/* Settings that may be configured by the user. */
-struct settings {
- bool strict; /* Use strict matching for flow mod commands */
-};
-
-struct command {
- const char *name;
- int min_args;
- int max_args;
- void (*handler)(const struct settings *, int argc, char *argv[]);
-};
-
-static struct command all_commands[];
-
-static void usage(void) NO_RETURN;
-static void parse_options(int argc, char *argv[], struct settings *);
-
-int main(int argc, char *argv[])
-{
- struct settings s;
- struct command *p;
-
- set_program_name(argv[0]);
- time_init();
- vlog_init();
- parse_options(argc, argv, &s);
- signal(SIGPIPE, SIG_IGN);
-
- argc -= optind;
- argv += optind;
- if (argc < 1)
- ovs_fatal(0, "missing command name; use --help for help");
-
- for (p = all_commands; p->name != NULL; p++) {
- if (!strcmp(p->name, argv[0])) {
- int n_arg = argc - 1;
- if (n_arg < p->min_args)
- ovs_fatal(0, "'%s' command requires at least %d arguments",
- p->name, p->min_args);
- else if (n_arg > p->max_args)
- ovs_fatal(0, "'%s' command takes at most %d arguments",
- p->name, p->max_args);
- else {
- p->handler(&s, argc, argv);
- if (ferror(stdout)) {
- ovs_fatal(0, "write to stdout failed");
- }
- if (ferror(stderr)) {
- ovs_fatal(0, "write to stderr failed");
- }
- exit(0);
- }
- }
- }
- ovs_fatal(0, "unknown command '%s'; use --help for help", argv[0]);
-
- return 0;
-}
-
-static void
-parse_options(int argc, char *argv[], struct settings *s)
-{
- enum {
- OPT_STRICT = UCHAR_MAX + 1
- };
- static struct option long_options[] = {
- {"timeout", required_argument, 0, 't'},
- {"verbose", optional_argument, 0, 'v'},
- {"strict", no_argument, 0, OPT_STRICT},
- {"help", no_argument, 0, 'h'},
- {"version", no_argument, 0, 'V'},
- VCONN_SSL_LONG_OPTIONS
- {0, 0, 0, 0},
- };
- char *short_options = long_options_to_short_options(long_options);
-
- /* Set defaults that we can figure out before parsing options. */
- s->strict = false;
-
- for (;;) {
- unsigned long int timeout;
- int c;
-
- c = getopt_long(argc, argv, short_options, long_options, NULL);
- if (c == -1) {
- break;
- }
-
- switch (c) {
- case 't':
- timeout = strtoul(optarg, NULL, 10);
- if (timeout <= 0) {
- ovs_fatal(0, "value %s on -t or --timeout is not at least 1",
- optarg);
- } else {
- time_alarm(timeout);
- }
- break;
-
- case 'h':
- usage();
-
- case 'V':
- printf("%s %s compiled "__DATE__" "__TIME__"\n",
- program_name, VERSION BUILDNR);
- exit(EXIT_SUCCESS);
-
- case 'v':
- vlog_set_verbosity(optarg);
- break;
-
- case OPT_STRICT:
- s->strict = true;
- break;
-
- VCONN_SSL_OPTION_HANDLERS
-
- case '?':
- exit(EXIT_FAILURE);
-
- default:
- abort();
- }
- }
- free(short_options);
-}
-
-static void
-usage(void)
-{
- printf("%s: OpenVSwitch datapath and OpenFlow switch management utility\n"
- "usage: %s [OPTIONS] COMMAND [ARG...]\n"
- "\nFor OpenVSwitch datapaths:\n"
- " adddp DP [IFACE...] add new datapath DP (with IFACES)\n"
- " deldp DP delete local datapath DP\n"
- " addif DP IFACE... add each IFACE as a port on DP\n"
- " delif DP IFACE... delete each IFACE from DP\n"
- " dp-show show basic info on all datapaths\n"
- " dp-show DP... show basic info on each DP\n"
- " dp-dump-flows DP display flows in DP\n"
- " dp-del-flows DP delete all flows from DP\n"
- " dp-dump-groups DP display port groups in DP\n"
- "\nFor OpenFlow switches:\n"
- " show SWITCH show OpenFlow information\n"
- " status SWITCH [KEY] report statistics (about KEY)\n"
- " dump-desc SWITCH print switch description\n"
- " dump-tables SWITCH print table stats\n"
- " mod-port SWITCH IFACE ACT modify port behavior\n"
- " dump-ports SWITCH print port statistics\n"
- " dump-flows SWITCH print all flow entries\n"
- " dump-flows SWITCH FLOW print matching FLOWs\n"
- " dump-aggregate SWITCH print aggregate flow statistics\n"
- " dump-aggregate SWITCH FLOW print aggregate stats for FLOWs\n"
-#ifdef SUPPORT_SNAT
- " add-snat SWITCH IFACE IP add SNAT config to IFACE\n"
- " del-snat SWITCH IFACE delete SNAT config on IFACE\n"
-#endif
- " add-flow SWITCH FLOW add flow described by FLOW\n"
- " add-flows SWITCH FILE add flows from FILE\n"
- " mod-flows SWITCH FLOW modify actions of matching FLOWs\n"
- " del-flows SWITCH [FLOW] delete matching FLOWs\n"
- " monitor SWITCH MISSLEN EXP print packets received from SWITCH\n"
- " execute SWITCH CMD [ARG...] execute CMD with ARGS on SWITCH\n"
- "\nFor OpenFlow switches and controllers:\n"
- " probe VCONN probe whether VCONN is up\n"
- " ping VCONN [N] latency of N-byte echos\n"
- " benchmark VCONN N COUNT bandwidth of COUNT N-byte echos\n"
- "where each SWITCH is an active OpenFlow connection method.\n",
- program_name, program_name);
- vconn_usage(true, false, false);
- vlog_usage();
- printf("\nOther options:\n"
- " --strict use strict match for flow commands\n"
- " -t, --timeout=SECS give up after SECS seconds\n"
- " -h, --help display this help message\n"
- " -V, --version display version information\n");
- exit(EXIT_SUCCESS);
-}
-
-static void run(int retval, const char *message, ...)
- PRINTF_FORMAT(2, 3);
-
-static void run(int retval, const char *message, ...)
-{
- if (retval) {
- va_list args;
-
- fprintf(stderr, "%s: ", program_name);
- va_start(args, message);
- vfprintf(stderr, message, args);
- va_end(args);
- if (retval == EOF) {
- fputs(": unexpected end of file\n", stderr);
- } else {
- fprintf(stderr, ": %s\n", strerror(retval));
- }
-
- exit(EXIT_FAILURE);
- }
-}
-\f
-static void do_add_port(const struct settings *, int argc, char *argv[]);
-
-static int if_up(const char *netdev_name)
-{
- struct netdev *netdev;
- int retval;
-
- retval = netdev_open(netdev_name, NETDEV_ETH_TYPE_NONE, &netdev);
- if (!retval) {
- retval = netdev_turn_flags_on(netdev, NETDEV_UP, true);
- netdev_close(netdev);
- }
- return retval;
-}
-
-static void
-do_get_idx(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- struct dpif dpif;
- run(dpif_open(argv[1], &dpif), "opening datapath");
- printf("%u\n", dpif_id(&dpif));
- dpif_close(&dpif);
-}
-
-static void
-do_get_name(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- struct dpif dpif;
- char name[IF_NAMESIZE + 1];
-
- run(dpif_open(argv[1], &dpif), "opening datapath");
- run(dpif_get_name(&dpif, name, sizeof name), "getting datapath name");
- puts(name);
- dpif_close(&dpif);
-}
-
-static void
-do_add_dp(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- struct dpif dpif;
- run(dpif_create(argv[1], &dpif), "add_dp");
- dpif_close(&dpif);
- if (argc > 2) {
- do_add_port(s, argc, argv);
- }
-}
-
-static void
-do_del_dp(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- struct dpif dpif;
- run(dpif_open(argv[1], &dpif), "opening datapath");
- run(dpif_delete(&dpif), "del_dp");
- dpif_close(&dpif);
-}
-
-static int
-compare_ports(const void *a_, const void *b_)
-{
- const struct odp_port *a = a_;
- const struct odp_port *b = b_;
- return a->port < b->port ? -1 : a->port > b->port;
-}
-
-static void
-query_ports(struct dpif *dpif, struct odp_port **ports, size_t *n_ports)
-{
- run(dpif_port_list(dpif, ports, n_ports), "listing ports");
- qsort(*ports, *n_ports, sizeof **ports, compare_ports);
-}
-
-static uint16_t
-get_free_port(struct dpif *dpif)
-{
- struct odp_port *ports;
- size_t n_ports;
- int port_no;
-
- query_ports(dpif, &ports, &n_ports);
- for (port_no = 0; port_no <= UINT16_MAX; port_no++) {
- size_t i;
- for (i = 0; i < n_ports; i++) {
- if (ports[i].port == port_no) {
- goto next_portno;
- }
- }
- free(ports);
- return port_no;
-
- next_portno: ;
- }
- ovs_fatal(0, "no free datapath ports");
-}
-
-static void
-do_add_port(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- bool failure = false;
- struct dpif dpif;
- int i;
-
- run(dpif_open(argv[1], &dpif), "opening datapath");
- for (i = 2; i < argc; i++) {
- char *save_ptr = NULL;
- char *devname, *suboptions;
- int port = -1;
- int flags = 0;
- int error;
-
- devname = strtok_r(argv[i], ",,", &save_ptr);
- if (!devname) {
- ovs_error(0, "%s is not a valid network device name", argv[i]);
- continue;
- }
-
- suboptions = strtok_r(NULL, "", &save_ptr);
- if (suboptions) {
- enum {
- AP_PORT,
- AP_INTERNAL
- };
- static char *options[] = {
- "port",
- "internal"
- };
-
- while (*suboptions != '\0') {
- char *value;
-
- switch (getsubopt(&suboptions, options, &value)) {
- case AP_PORT:
- if (!value) {
- ovs_error(0, "'port' suboption requires a value");
- }
- port = atoi(value);
- break;
-
- case AP_INTERNAL:
- flags |= ODP_PORT_INTERNAL;
- break;
-
- default:
- ovs_error(0, "unknown suboption '%s'", value);
- break;
- }
- }
- }
- if (port < 0) {
- port = get_free_port(&dpif);
- }
-
- error = dpif_port_add(&dpif, devname, port, flags);
- if (error) {
- ovs_error(error, "adding %s as port %"PRIu16" of %s failed",
- devname, port, argv[1]);
- failure = true;
- } else if (if_up(devname)) {
- failure = true;
- }
- }
- dpif_close(&dpif);
- if (failure) {
- exit(EXIT_FAILURE);
- }
-}
-
-static bool
-get_port_number(struct dpif *dpif, const char *name, uint16_t *port)
-{
- struct odp_port *ports;
- size_t n_ports;
- size_t i;
-
- query_ports(dpif, &ports, &n_ports);
- for (i = 0; i < n_ports; i++) {
- if (!strcmp(name, ports[i].devname)) {
- *port = ports[i].port;
- free(ports);
- return true;
- }
- }
- free(ports);
- ovs_error(0, "no port named %s", name);
- return false;
-}
-
-static void
-do_del_port(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- bool failure = false;
- struct dpif dpif;
- int i;
-
- run(dpif_open(argv[1], &dpif), "opening datapath");
- for (i = 2; i < argc; i++) {
- const char *name = argv[i];
- uint16_t port;
- int error;
-
- if (!name[strspn(name, "0123456789")]) {
- port = atoi(name);
- } else if (!get_port_number(&dpif, name, &port)) {
- failure = true;
- continue;
- }
-
- error = dpif_port_del(&dpif, port);
- if (error) {
- ovs_error(error, "deleting port %s from %s failed", name, argv[1]);
- failure = true;
- }
- }
- dpif_close(&dpif);
- if (failure) {
- exit(EXIT_FAILURE);
- }
-}
-
-static void
-show_dpif(struct dpif *dpif)
-{
- struct odp_port *ports;
- struct odp_stats stats;
- size_t n_ports;
- size_t i;
-
- printf("dp%u:\n", dpif_id(dpif));
- if (!dpif_get_dp_stats(dpif, &stats)) {
- printf("\tflows: cur:%"PRIu32", soft-max:%"PRIu32", "
- "hard-max:%"PRIu32"\n",
- stats.n_flows, stats.cur_capacity, stats.max_capacity);
- printf("\tports: cur:%"PRIu32", max:%"PRIu32"\n",
- stats.n_ports, stats.max_ports);
- printf("\tgroups: max:%"PRIu16"\n", stats.max_groups);
- printf("\tlookups: frags:%"PRIu64", hit:%"PRIu64", missed:%"PRIu64", "
- "lost:%"PRIu64"\n",
- stats.n_frags, stats.n_hit, stats.n_missed, stats.n_lost);
- printf("\tqueues: max-miss:%"PRIu16", max-action:%"PRIu16"\n",
- stats.max_miss_queue, stats.max_action_queue);
- }
- query_ports(dpif, &ports, &n_ports);
- for (i = 0; i < n_ports; i++) {
- printf("\tport %u: %s", ports[i].port, ports[i].devname);
- if (ports[i].flags & ODP_PORT_INTERNAL) {
- printf(" (internal)");
- }
- printf("\n");
- }
- free(ports);
- dpif_close(dpif);
-}
-
-static void
-do_dp_show(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- bool failure = false;
- if (argc > 1) {
- int i;
- for (i = 1; i < argc; i++) {
- const char *name = argv[i];
- struct dpif dpif;
- int error;
-
- error = dpif_open(name, &dpif);
- if (!error) {
- show_dpif(&dpif);
- } else {
- ovs_error(error, "opening datapath %s failed", name);
- failure = true;
- }
- }
- } else {
- unsigned int i;
- for (i = 0; i < ODP_MAX; i++) {
- char name[128];
- struct dpif dpif;
- int error;
-
- sprintf(name, "dp%u", i);
- error = dpif_open(name, &dpif);
- if (!error) {
- show_dpif(&dpif);
- } else if (error != ENODEV) {
- ovs_error(error, "opening datapath %s failed", name);
- failure = true;
- }
- }
- }
- if (failure) {
- exit(EXIT_FAILURE);
- }
-}
-
-static void
-do_dp_dump_flows(const struct settings *s UNUSED,
- int argc UNUSED, char *argv[])
-{
- struct odp_flow *flows;
- struct dpif dpif;
- size_t n_flows;
- struct ds ds;
- size_t i;
-
- run(dpif_open(argv[1], &dpif), "opening datapath");
- run(dpif_flow_list_all(&dpif, &flows, &n_flows), "listing all flows");
-
- ds_init(&ds);
- for (i = 0; i < n_flows; i++) {
- struct odp_flow *f = &flows[i];
- enum { MAX_ACTIONS = 4096 / sizeof(union odp_action) };
- union odp_action actions[MAX_ACTIONS];
-
- f->actions = actions;
- f->n_actions = MAX_ACTIONS;
- dpif_flow_get(&dpif, f);
-
- ds_clear(&ds);
- format_odp_flow(&ds, f);
- printf("%s\n", ds_cstr(&ds));
- }
- ds_destroy(&ds);
- dpif_close(&dpif);
-}
-
-static void
-do_dp_del_flows(const struct settings *s UNUSED,
- int argc UNUSED, char *argv[])
-{
- struct dpif dpif;
-
- run(dpif_open(argv[1], &dpif), "opening datapath");
- run(dpif_flow_flush(&dpif), "deleting all flows");
- dpif_close(&dpif);
-}
-
-static void
-do_dp_dump_groups(const struct settings *s UNUSED,
- int argc UNUSED, char *argv[])
-{
- struct odp_stats stats;
- struct dpif dpif;
- unsigned int i;
-
- run(dpif_open(argv[1], &dpif), "opening datapath");
- run(dpif_get_dp_stats(&dpif, &stats), "get datapath stats");
- for (i = 0; i < stats.max_groups; i++) {
- uint16_t ports[UINT16_MAX];
- size_t n_ports;
-
- if (!dpif_port_group_get(&dpif, i, ports,
- ARRAY_SIZE(ports), &n_ports) && n_ports) {
- size_t j;
-
- printf("group %u:", i);
- for (j = 0; j < n_ports; j++) {
- printf(" %"PRIu16, ports[j]);
- }
- printf("\n");
- }
- }
- dpif_close(&dpif);
-}
-\f
-/* Generic commands. */
-
-static void
-open_vconn(const char *name, struct vconn **vconnp)
-{
- struct dpif dpif;
- struct stat s;
-
- if (strstr(name, ":")) {
- run(vconn_open_block(name, OFP_VERSION, vconnp),
- "connecting to %s", name);
- } else if (!stat(name, &s) && S_ISSOCK(s.st_mode)) {
- char *vconn_name = xasprintf("unix:%s", name);
- VLOG_INFO("connecting to %s", vconn_name);
- run(vconn_open_block(vconn_name, OFP_VERSION, vconnp),
- "connecting to %s", vconn_name);
- free(vconn_name);
- } else if (!dpif_open(name, &dpif)) {
- char dpif_name[IF_NAMESIZE + 1];
- char *socket_name;
- char *vconn_name;
-
- run(dpif_get_name(&dpif, dpif_name, sizeof dpif_name),
- "obtaining name of %s", dpif_name);
- dpif_close(&dpif);
- if (strcmp(dpif_name, name)) {
- VLOG_INFO("datapath %s is named %s", name, dpif_name);
- }
-
- socket_name = xasprintf("%s/%s.mgmt", ovs_rundir, dpif_name);
- if (stat(socket_name, &s)) {
- ovs_fatal(errno, "cannot connect to %s: stat failed on %s",
- name, socket_name);
- } else if (!S_ISSOCK(s.st_mode)) {
- ovs_fatal(0, "cannot connect to %s: %s is not a socket",
- name, socket_name);
- }
-
- vconn_name = xasprintf("unix:%s", socket_name);
- VLOG_INFO("connecting to %s", vconn_name);
- run(vconn_open_block(vconn_name, OFP_VERSION, vconnp),
- "connecting to %s", vconn_name);
- free(socket_name);
- free(vconn_name);
- } else {
- ovs_fatal(0, "%s is not a valid connection method", name);
- }
-}
-
-static void *
-alloc_stats_request(size_t body_len, uint16_t type, struct ofpbuf **bufferp)
-{
- struct ofp_stats_request *rq;
- rq = make_openflow((offsetof(struct ofp_stats_request, body)
- + body_len), OFPT_STATS_REQUEST, bufferp);
- rq->type = htons(type);
- rq->flags = htons(0);
- return rq->body;
-}
-
-static void
-send_openflow_buffer(struct vconn *vconn, struct ofpbuf *buffer)
-{
- update_openflow_length(buffer);
- run(vconn_send_block(vconn, buffer), "failed to send packet to switch");
-}
-
-static void
-dump_transaction(const char *vconn_name, struct ofpbuf *request)
-{
- struct vconn *vconn;
- struct ofpbuf *reply;
-
- update_openflow_length(request);
- open_vconn(vconn_name, &vconn);
- run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
- ofp_print(stdout, reply->data, reply->size, 1);
- vconn_close(vconn);
-}
-
-static void
-dump_trivial_transaction(const char *vconn_name, uint8_t request_type)
-{
- struct ofpbuf *request;
- make_openflow(sizeof(struct ofp_header), request_type, &request);
- dump_transaction(vconn_name, request);
-}
-
-static void
-dump_stats_transaction(const char *vconn_name, struct ofpbuf *request)
-{
- uint32_t send_xid = ((struct ofp_header *) request->data)->xid;
- struct vconn *vconn;
- bool done = false;
-
- open_vconn(vconn_name, &vconn);
- send_openflow_buffer(vconn, request);
- while (!done) {
- uint32_t recv_xid;
- struct ofpbuf *reply;
-
- run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
- recv_xid = ((struct ofp_header *) reply->data)->xid;
- if (send_xid == recv_xid) {
- struct ofp_stats_reply *osr;
-
- ofp_print(stdout, reply->data, reply->size, 1);
-
- osr = ofpbuf_at(reply, 0, sizeof *osr);
- done = !osr || !(ntohs(osr->flags) & OFPSF_REPLY_MORE);
- } else {
- VLOG_DBG("received reply with xid %08"PRIx32" "
- "!= expected %08"PRIx32, recv_xid, send_xid);
- }
- ofpbuf_delete(reply);
- }
- vconn_close(vconn);
-}
-
-static void
-dump_trivial_stats_transaction(const char *vconn_name, uint8_t stats_type)
-{
- struct ofpbuf *request;
- alloc_stats_request(0, stats_type, &request);
- dump_stats_transaction(vconn_name, request);
-}
-
-static void
-do_show(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- dump_trivial_transaction(argv[1], OFPT_FEATURES_REQUEST);
- dump_trivial_transaction(argv[1], OFPT_GET_CONFIG_REQUEST);
-}
-
-static void
-do_status(const struct settings *s UNUSED, int argc, char *argv[])
-{
- struct nicira_header *request, *reply;
- struct vconn *vconn;
- struct ofpbuf *b;
-
- request = make_openflow(sizeof *request, OFPT_VENDOR, &b);
- request->vendor = htonl(NX_VENDOR_ID);
- request->subtype = htonl(NXT_STATUS_REQUEST);
- if (argc > 2) {
- ofpbuf_put(b, argv[2], strlen(argv[2]));
- update_openflow_length(b);
- }
- open_vconn(argv[1], &vconn);
- run(vconn_transact(vconn, b, &b), "talking to %s", argv[1]);
- vconn_close(vconn);
-
- if (b->size < sizeof *reply) {
- ovs_fatal(0, "short reply (%zu bytes)", b->size);
- }
- reply = b->data;
- if (reply->header.type != OFPT_VENDOR
- || reply->vendor != ntohl(NX_VENDOR_ID)
- || reply->subtype != ntohl(NXT_STATUS_REPLY)) {
- ofp_print(stderr, b->data, b->size, 2);
- ovs_fatal(0, "bad reply");
- }
-
- fwrite(reply + 1, b->size - sizeof *reply, 1, stdout);
-}
-
-static void
-do_dump_desc(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- dump_trivial_stats_transaction(argv[1], OFPST_DESC);
-}
-
-static void
-do_dump_tables(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
-}
-
-
-static uint32_t
-str_to_u32(const char *str)
-{
- char *tail;
- uint32_t value;
-
- errno = 0;
- value = strtoul(str, &tail, 0);
- if (errno == EINVAL || errno == ERANGE || *tail) {
- ovs_fatal(0, "invalid numeric format %s", str);
- }
- return value;
-}
-
-static void
-str_to_mac(const char *str, uint8_t mac[6])
-{
- if (sscanf(str, "%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8,
- &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) != 6) {
- ovs_fatal(0, "invalid mac address %s", str);
- }
-}
-
-static uint32_t
-str_to_ip(const char *str_, uint32_t *ip)
-{
- char *str = xstrdup(str_);
- char *save_ptr = NULL;
- const char *name, *netmask;
- struct in_addr in_addr;
- int n_wild, retval;
-
- name = strtok_r(str, "//", &save_ptr);
- retval = name ? lookup_ip(name, &in_addr) : EINVAL;
- if (retval) {
- ovs_fatal(0, "%s: could not convert to IP address", str);
- }
- *ip = in_addr.s_addr;
-
- netmask = strtok_r(NULL, "//", &save_ptr);
- if (netmask) {
- uint8_t o[4];
- if (sscanf(netmask, "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8,
- &o[0], &o[1], &o[2], &o[3]) == 4) {
- uint32_t nm = (o[0] << 24) | (o[1] << 16) | (o[2] << 8) | o[3];
- int i;
-
- /* Find first 1-bit. */
- for (i = 0; i < 32; i++) {
- if (nm & (1u << i)) {
- break;
- }
- }
- n_wild = i;
-
- /* Verify that the rest of the bits are 1-bits. */
- for (; i < 32; i++) {
- if (!(nm & (1u << i))) {
- ovs_fatal(0, "%s: %s is not a valid netmask",
- str, netmask);
- }
- }
- } else {
- int prefix = atoi(netmask);
- if (prefix <= 0 || prefix > 32) {
- ovs_fatal(0, "%s: network prefix bits not between 1 and 32",
- str);
- }
- n_wild = 32 - prefix;
- }
- } else {
- n_wild = 0;
- }
-
- free(str);
- return n_wild;
-}
-
-static void *
-put_action(struct ofpbuf *b, size_t size, uint16_t type)
-{
- struct ofp_action_header *ah = ofpbuf_put_zeros(b, size);
- ah->type = htons(type);
- ah->len = htons(size);
- return ah;
-}
-
-static struct ofp_action_output *
-put_output_action(struct ofpbuf *b, uint16_t port)
-{
- struct ofp_action_output *oao = put_action(b, sizeof *oao, OFPAT_OUTPUT);
- oao->port = htons(port);
- return oao;
-}
-
-static void
-put_dl_addr_action(struct ofpbuf *b, uint16_t type, const char *addr)
-{
- struct ofp_action_dl_addr *oada = put_action(b, sizeof *oada, type);
- str_to_mac(addr, oada->dl_addr);
-}
-
-
-static bool
-parse_port_name(const char *name, uint16_t *port)
-{
- struct pair {
- const char *name;
- uint16_t value;
- };
- static const struct pair pairs[] = {
-#define DEF_PAIR(NAME) {#NAME, OFPP_##NAME}
- DEF_PAIR(IN_PORT),
- DEF_PAIR(TABLE),
- DEF_PAIR(NORMAL),
- DEF_PAIR(FLOOD),
- DEF_PAIR(ALL),
- DEF_PAIR(CONTROLLER),
- DEF_PAIR(LOCAL),
- DEF_PAIR(NONE),
-#undef DEF_PAIR
- };
- static const int n_pairs = ARRAY_SIZE(pairs);
- size_t i;
-
- for (i = 0; i < n_pairs; i++) {
- if (!strcasecmp(name, pairs[i].name)) {
- *port = pairs[i].value;
- return true;
- }
- }
- return false;
-}
-
-static void
-str_to_action(char *str, struct ofpbuf *b)
-{
- char *act, *arg;
- char *saveptr = NULL;
- bool drop = false;
- int n_actions;
-
- for (act = strtok_r(str, ", \t\r\n", &saveptr), n_actions = 0; act;
- act = strtok_r(NULL, ", \t\r\n", &saveptr), n_actions++)
- {
- uint16_t port;
-
- if (drop) {
- ovs_fatal(0, "Drop actions must not be followed by other actions");
- }
-
- /* Arguments are separated by colons */
- arg = strchr(act, ':');
- if (arg) {
- *arg = '\0';
- arg++;
- }
-
- if (!strcasecmp(act, "mod_vlan_vid")) {
- struct ofp_action_vlan_vid *va;
- va = put_action(b, sizeof *va, OFPAT_SET_VLAN_VID);
- va->vlan_vid = htons(str_to_u32(arg));
- } else if (!strcasecmp(act, "mod_vlan_pcp")) {
- struct ofp_action_vlan_pcp *va;
- va = put_action(b, sizeof *va, OFPAT_SET_VLAN_PCP);
- va->vlan_pcp = str_to_u32(arg);
- } else if (!strcasecmp(act, "strip_vlan")) {
- struct ofp_action_header *ah;
- ah = put_action(b, sizeof *ah, OFPAT_STRIP_VLAN);
- ah->type = htons(OFPAT_STRIP_VLAN);
- } else if (!strcasecmp(act, "mod_dl_src")) {
- put_dl_addr_action(b, OFPAT_SET_DL_SRC, arg);
- } else if (!strcasecmp(act, "mod_dl_dst")) {
- put_dl_addr_action(b, OFPAT_SET_DL_DST, arg);
- } else if (!strcasecmp(act, "output")) {
- put_output_action(b, str_to_u32(arg));
- } else if (!strcasecmp(act, "drop")) {
- /* A drop action in OpenFlow occurs by just not setting
- * an action. */
- drop = true;
- if (n_actions) {
- ovs_fatal(0, "Drop actions must not be preceded by other "
- "actions");
- }
-#ifdef SUPPORT_SNAT
- } else if (!strcasecmp(act, "nat")) {
- struct nx_action_snat *sa;
-
- if (str_to_u32(arg) > OFPP_MAX) {
- ovs_fatal(0, "Invalid nat port: %s\n", arg);
- }
-
- sa = put_action(b, sizeof *sa, OFPAT_VENDOR);
- sa->vendor = htonl(NX_VENDOR_ID);
- sa->subtype = htons(NXAST_SNAT);
- sa->port = htons(str_to_u32(arg));
-#endif
- } else if (!strcasecmp(act, "CONTROLLER")) {
- struct ofp_action_output *oao;
- oao = put_output_action(b, OFPP_CONTROLLER);
-
- /* Unless a numeric argument is specified, we send the whole
- * packet to the controller. */
- if (arg && (strspn(act, "0123456789") == strlen(act))) {
- oao->max_len = htons(str_to_u32(arg));
- }
- } else if (parse_port_name(act, &port)) {
- put_output_action(b, port);
- } else if (strspn(act, "0123456789") == strlen(act)) {
- put_output_action(b, str_to_u32(act));
- } else {
- ovs_fatal(0, "Unknown action: %s", act);
- }
- }
-}
-
-struct protocol {
- const char *name;
- uint16_t dl_type;
- uint8_t nw_proto;
-};
-
-static bool
-parse_protocol(const char *name, const struct protocol **p_out)
-{
- static const struct protocol protocols[] = {
- { "ip", ETH_TYPE_IP, 0 },
- { "arp", ETH_TYPE_ARP, 0 },
- { "icmp", ETH_TYPE_IP, IP_TYPE_ICMP },
- { "tcp", ETH_TYPE_IP, IP_TYPE_TCP },
- { "udp", ETH_TYPE_IP, IP_TYPE_UDP },
- };
- const struct protocol *p;
-
- for (p = protocols; p < &protocols[ARRAY_SIZE(protocols)]; p++) {
- if (!strcmp(p->name, name)) {
- *p_out = p;
- return true;
- }
- }
- *p_out = NULL;
- return false;
-}
-
-struct field {
- const char *name;
- uint32_t wildcard;
- enum { F_U8, F_U16, F_MAC, F_IP } type;
- size_t offset, shift;
-};
-
-static bool
-parse_field(const char *name, const struct field **f_out)
-{
-#define F_OFS(MEMBER) offsetof(struct ofp_match, MEMBER)
- static const struct field fields[] = {
- { "in_port", OFPFW_IN_PORT, F_U16, F_OFS(in_port), 0 },
- { "dl_vlan", OFPFW_DL_VLAN, F_U16, F_OFS(dl_vlan), 0 },
- { "dl_src", OFPFW_DL_SRC, F_MAC, F_OFS(dl_src), 0 },
- { "dl_dst", OFPFW_DL_DST, F_MAC, F_OFS(dl_dst), 0 },
- { "dl_type", OFPFW_DL_TYPE, F_U16, F_OFS(dl_type), 0 },
- { "nw_src", OFPFW_NW_SRC_MASK, F_IP,
- F_OFS(nw_src), OFPFW_NW_SRC_SHIFT },
- { "nw_dst", OFPFW_NW_DST_MASK, F_IP,
- F_OFS(nw_dst), OFPFW_NW_DST_SHIFT },
- { "nw_proto", OFPFW_NW_PROTO, F_U8, F_OFS(nw_proto), 0 },
- { "tp_src", OFPFW_TP_SRC, F_U16, F_OFS(tp_src), 0 },
- { "tp_dst", OFPFW_TP_DST, F_U16, F_OFS(tp_dst), 0 },
- { "icmp_type", OFPFW_ICMP_TYPE, F_U16, F_OFS(icmp_type), 0 },
- { "icmp_code", OFPFW_ICMP_CODE, F_U16, F_OFS(icmp_code), 0 }
- };
- const struct field *f;
-
- for (f = fields; f < &fields[ARRAY_SIZE(fields)]; f++) {
- if (!strcmp(f->name, name)) {
- *f_out = f;
- return true;
- }
- }
- *f_out = NULL;
- return false;
-}
-
-static void
-str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions,
- uint8_t *table_idx, uint16_t *out_port, uint16_t *priority,
- uint16_t *idle_timeout, uint16_t *hard_timeout)
-{
- char *save_ptr = NULL;
- char *name;
- uint32_t wildcards;
-
- if (table_idx) {
- *table_idx = 0xff;
- }
- if (out_port) {
- *out_port = OFPP_NONE;
- }
- if (priority) {
- *priority = OFP_DEFAULT_PRIORITY;
- }
- if (idle_timeout) {
- *idle_timeout = DEFAULT_IDLE_TIMEOUT;
- }
- if (hard_timeout) {
- *hard_timeout = OFP_FLOW_PERMANENT;
- }
- if (actions) {
- char *act_str = strstr(string, "action");
- if (!act_str) {
- ovs_fatal(0, "must specify an action");
- }
- *(act_str-1) = '\0';
-
- act_str = strchr(act_str, '=');
- if (!act_str) {
- ovs_fatal(0, "must specify an action");
- }
-
- act_str++;
-
- str_to_action(act_str, actions);
- }
- memset(match, 0, sizeof *match);
- wildcards = OFPFW_ALL;
- for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name;
- name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) {
- const struct protocol *p;
-
- if (parse_protocol(name, &p)) {
- wildcards &= ~OFPFW_DL_TYPE;
- match->dl_type = htons(p->dl_type);
- if (p->nw_proto) {
- wildcards &= ~OFPFW_NW_PROTO;
- match->nw_proto = p->nw_proto;
- }
- } else {
- const struct field *f;
- char *value;
-
- value = strtok_r(NULL, ", \t\r\n", &save_ptr);
- if (!value) {
- ovs_fatal(0, "field %s missing value", name);
- }
-
- if (table_idx && !strcmp(name, "table")) {
- *table_idx = atoi(value);
- } else if (out_port && !strcmp(name, "out_port")) {
- *out_port = atoi(value);
- } else if (priority && !strcmp(name, "priority")) {
- *priority = atoi(value);
- } else if (idle_timeout && !strcmp(name, "idle_timeout")) {
- *idle_timeout = atoi(value);
- } else if (hard_timeout && !strcmp(name, "hard_timeout")) {
- *hard_timeout = atoi(value);
- } else if (parse_field(name, &f)) {
- void *data = (char *) match + f->offset;
- if (!strcmp(value, "*") || !strcmp(value, "ANY")) {
- wildcards |= f->wildcard;
- } else {
- wildcards &= ~f->wildcard;
- if (f->wildcard == OFPFW_IN_PORT
- && parse_port_name(value, (uint16_t *) data)) {
- /* Nothing to do. */
- } else if (f->type == F_U8) {
- *(uint8_t *) data = str_to_u32(value);
- } else if (f->type == F_U16) {
- *(uint16_t *) data = htons(str_to_u32(value));
- } else if (f->type == F_MAC) {
- str_to_mac(value, data);
- } else if (f->type == F_IP) {
- wildcards |= str_to_ip(value, data) << f->shift;
- } else {
- NOT_REACHED();
- }
- }
- } else {
- ovs_fatal(0, "unknown keyword %s", name);
- }
- }
- }
- match->wildcards = htonl(wildcards);
-}
-
-static void
-do_dump_flows(const struct settings *s UNUSED, int argc, char *argv[])
-{
- struct ofp_flow_stats_request *req;
- uint16_t out_port;
- struct ofpbuf *request;
-
- req = alloc_stats_request(sizeof *req, OFPST_FLOW, &request);
- str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL,
- &req->table_id, &out_port, NULL, NULL, NULL);
- memset(&req->pad, 0, sizeof req->pad);
- req->out_port = htons(out_port);
-
- dump_stats_transaction(argv[1], request);
-}
-
-static void
-do_dump_aggregate(const struct settings *s UNUSED, int argc, char *argv[])
-{
- struct ofp_aggregate_stats_request *req;
- struct ofpbuf *request;
- uint16_t out_port;
-
- req = alloc_stats_request(sizeof *req, OFPST_AGGREGATE, &request);
- str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL,
- &req->table_id, &out_port, NULL, NULL, NULL);
- memset(&req->pad, 0, sizeof req->pad);
- req->out_port = htons(out_port);
-
- dump_stats_transaction(argv[1], request);
-}
-
-#ifdef SUPPORT_SNAT
-static void
-do_add_snat(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- struct vconn *vconn;
- struct ofpbuf *buffer;
- struct nx_act_config *nac;
- size_t size;
-
- /* Parse and send. */
- size = sizeof *nac + sizeof nac->snat[0];
- nac = make_openflow(size, OFPT_VENDOR, &buffer);
-
- nac->header.vendor = htonl(NX_VENDOR_ID);
- nac->header.subtype = htonl(NXT_ACT_SET_CONFIG);
-
- nac->type = htons(NXAST_SNAT);
- nac->snat[0].command = NXSC_ADD;
- nac->snat[0].port = htons(str_to_u32(argv[2]));
- nac->snat[0].mac_timeout = htons(0);
- str_to_ip(argv[3], &nac->snat[0].ip_addr_start);
- str_to_ip(argv[3], &nac->snat[0].ip_addr_end);
-
- open_vconn(argv[1], &vconn);
- send_openflow_buffer(vconn, buffer);
- vconn_close(vconn);
-}
-
-static void
-do_del_snat(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- struct vconn *vconn;
- struct ofpbuf *buffer;
- struct nx_act_config *nac;
- size_t size;
-
- /* Parse and send. */
- size = sizeof *nac + sizeof nac->snat[0];
- nac = make_openflow(size, OFPT_VENDOR, &buffer);
-
- nac->header.vendor = htonl(NX_VENDOR_ID);
- nac->header.subtype = htonl(NXT_ACT_SET_CONFIG);
-
- nac->type = htons(NXAST_SNAT);
- nac->snat[0].command = NXSC_DELETE;
- nac->snat[0].port = htons(str_to_u32(argv[2]));
- nac->snat[0].mac_timeout = htons(0);
-
- open_vconn(argv[1], &vconn);
- send_openflow_buffer(vconn, buffer);
- vconn_close(vconn);
-}
-#endif /* SUPPORT_SNAT */
-
-static void
-do_add_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- struct vconn *vconn;
- struct ofpbuf *buffer;
- struct ofp_flow_mod *ofm;
- uint16_t priority, idle_timeout, hard_timeout;
- struct ofp_match match;
-
- /* Parse and send. str_to_flow() will expand and reallocate the data in
- * 'buffer', so we can't keep pointers to across the str_to_flow() call. */
- make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
- str_to_flow(argv[2], &match, buffer,
- NULL, NULL, &priority, &idle_timeout, &hard_timeout);
- ofm = buffer->data;
- ofm->match = match;
- ofm->command = htons(OFPFC_ADD);
- ofm->idle_timeout = htons(idle_timeout);
- ofm->hard_timeout = htons(hard_timeout);
- ofm->buffer_id = htonl(UINT32_MAX);
- ofm->priority = htons(priority);
- ofm->reserved = htonl(0);
-
- open_vconn(argv[1], &vconn);
- send_openflow_buffer(vconn, buffer);
- vconn_close(vconn);
-}
-
-static void
-do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- struct vconn *vconn;
- FILE *file;
- char line[1024];
-
- file = fopen(argv[2], "r");
- if (file == NULL) {
- ovs_fatal(errno, "%s: open", argv[2]);
- }
-
- open_vconn(argv[1], &vconn);
- while (fgets(line, sizeof line, file)) {
- struct ofpbuf *buffer;
- struct ofp_flow_mod *ofm;
- uint16_t priority, idle_timeout, hard_timeout;
- struct ofp_match match;
-
- char *comment;
-
- /* Delete comments. */
- comment = strchr(line, '#');
- if (comment) {
- *comment = '\0';
- }
-
- /* Drop empty lines. */
- if (line[strspn(line, " \t\n")] == '\0') {
- continue;
- }
-
- /* Parse and send. str_to_flow() will expand and reallocate the data
- * in 'buffer', so we can't keep pointers to across the str_to_flow()
- * call. */
- ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
- str_to_flow(line, &match, buffer,
- NULL, NULL, &priority, &idle_timeout, &hard_timeout);
- ofm = buffer->data;
- ofm->match = match;
- ofm->command = htons(OFPFC_ADD);
- ofm->idle_timeout = htons(idle_timeout);
- ofm->hard_timeout = htons(hard_timeout);
- ofm->buffer_id = htonl(UINT32_MAX);
- ofm->priority = htons(priority);
- ofm->reserved = htonl(0);
-
- send_openflow_buffer(vconn, buffer);
- }
- vconn_close(vconn);
- fclose(file);
-}
-
-static void
-do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[])
-{
- uint16_t priority, idle_timeout, hard_timeout;
- struct vconn *vconn;
- struct ofpbuf *buffer;
- struct ofp_flow_mod *ofm;
-
- /* Parse and send. */
- ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
- str_to_flow(argv[2], &ofm->match, buffer,
- NULL, NULL, &priority, &idle_timeout, &hard_timeout);
- if (s->strict) {
- ofm->command = htons(OFPFC_MODIFY_STRICT);
- } else {
- ofm->command = htons(OFPFC_MODIFY);
- }
- ofm->idle_timeout = htons(idle_timeout);
- ofm->hard_timeout = htons(hard_timeout);
- ofm->buffer_id = htonl(UINT32_MAX);
- ofm->priority = htons(priority);
- ofm->reserved = htonl(0);
-
- open_vconn(argv[1], &vconn);
- send_openflow_buffer(vconn, buffer);
- vconn_close(vconn);
-}
-
-static void do_del_flows(const struct settings *s, int argc, char *argv[])
-{
- struct vconn *vconn;
- uint16_t priority;
- uint16_t out_port;
- struct ofpbuf *buffer;
- struct ofp_flow_mod *ofm;
-
- /* Parse and send. */
- ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
- str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, NULL,
- &out_port, &priority, NULL, NULL);
- if (s->strict) {
- ofm->command = htons(OFPFC_DELETE_STRICT);
- } else {
- ofm->command = htons(OFPFC_DELETE);
- }
- ofm->idle_timeout = htons(0);
- ofm->hard_timeout = htons(0);
- ofm->buffer_id = htonl(UINT32_MAX);
- ofm->out_port = htons(out_port);
- ofm->priority = htons(priority);
- ofm->reserved = htonl(0);
-
- open_vconn(argv[1], &vconn);
- send_openflow_buffer(vconn, buffer);
- vconn_close(vconn);
-}
-
-static void
-do_monitor(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- struct vconn *vconn;
-
- open_vconn(argv[1], &vconn);
- if (argc > 2) {
- int miss_send_len = atoi(argv[2]);
- int send_flow_exp = argc > 3 ? atoi(argv[3]) : 0;
- struct ofp_switch_config *osc;
- struct ofpbuf *buf;
-
- osc = make_openflow(sizeof *osc, OFPT_SET_CONFIG, &buf);
- osc->flags = htons(send_flow_exp ? OFPC_SEND_FLOW_EXP : 0);
- osc->miss_send_len = htons(miss_send_len);
- send_openflow_buffer(vconn, buf);
- }
- for (;;) {
- struct ofpbuf *b;
- run(vconn_recv_block(vconn, &b), "vconn_recv");
- ofp_print(stderr, b->data, b->size, 2);
- ofpbuf_delete(b);
- }
-}
-
-static void
-do_dump_ports(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- dump_trivial_stats_transaction(argv[1], OFPST_PORT);
-}
-
-static void
-do_probe(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- struct ofpbuf *request;
- struct vconn *vconn;
- struct ofpbuf *reply;
-
- make_openflow(sizeof(struct ofp_header), OFPT_ECHO_REQUEST, &request);
- open_vconn(argv[1], &vconn);
- run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]);
- if (reply->size != sizeof(struct ofp_header)) {
- ovs_fatal(0, "reply does not match request");
- }
- ofpbuf_delete(reply);
- vconn_close(vconn);
-}
-
-static void
-do_mod_port(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- struct ofpbuf *request, *reply;
- struct ofp_switch_features *osf;
- struct ofp_port_mod *opm;
- struct vconn *vconn;
- char *endptr;
- int n_ports;
- int port_idx;
- int port_no;
-
-
- /* Check if the argument is a port index. Otherwise, treat it as
- * the port name. */
- port_no = strtol(argv[2], &endptr, 10);
- if (port_no == 0 && endptr == argv[2]) {
- port_no = -1;
- }
-
- /* Send a "Features Request" to get the information we need in order
- * to modify the port. */
- make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request);
- open_vconn(argv[1], &vconn);
- run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]);
-
- osf = reply->data;
- n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports;
-
- for (port_idx = 0; port_idx < n_ports; port_idx++) {
- if (port_no != -1) {
- /* Check argument as a port index */
- if (osf->ports[port_idx].port_no == htons(port_no)) {
- break;
- }
- } else {
- /* Check argument as an interface name */
- if (!strncmp((char *)osf->ports[port_idx].name, argv[2],
- sizeof osf->ports[0].name)) {
- break;
- }
-
- }
- }
- if (port_idx == n_ports) {
- ovs_fatal(0, "couldn't find monitored port: %s", argv[2]);
- }
-
- opm = make_openflow(sizeof(struct ofp_port_mod), OFPT_PORT_MOD, &request);
- opm->port_no = osf->ports[port_idx].port_no;
- memcpy(opm->hw_addr, osf->ports[port_idx].hw_addr, sizeof opm->hw_addr);
- opm->config = htonl(0);
- opm->mask = htonl(0);
- opm->advertise = htonl(0);
-
- printf("modifying port: %s\n", osf->ports[port_idx].name);
-
- if (!strncasecmp(argv[3], MOD_PORT_CMD_UP, sizeof MOD_PORT_CMD_UP)) {
- opm->mask |= htonl(OFPPC_PORT_DOWN);
- } else if (!strncasecmp(argv[3], MOD_PORT_CMD_DOWN,
- sizeof MOD_PORT_CMD_DOWN)) {
- opm->mask |= htonl(OFPPC_PORT_DOWN);
- opm->config |= htonl(OFPPC_PORT_DOWN);
- } else if (!strncasecmp(argv[3], MOD_PORT_CMD_FLOOD,
- sizeof MOD_PORT_CMD_FLOOD)) {
- opm->mask |= htonl(OFPPC_NO_FLOOD);
- } else if (!strncasecmp(argv[3], MOD_PORT_CMD_NOFLOOD,
- sizeof MOD_PORT_CMD_NOFLOOD)) {
- opm->mask |= htonl(OFPPC_NO_FLOOD);
- opm->config |= htonl(OFPPC_NO_FLOOD);
- } else {
- ovs_fatal(0, "unknown mod-port command '%s'", argv[3]);
- }
-
- send_openflow_buffer(vconn, request);
-
- ofpbuf_delete(reply);
- vconn_close(vconn);
-}
-
-static void
-do_ping(const struct settings *s UNUSED, int argc, char *argv[])
-{
- size_t max_payload = 65535 - sizeof(struct ofp_header);
- unsigned int payload;
- struct vconn *vconn;
- int i;
-
- payload = argc > 2 ? atoi(argv[2]) : 64;
- if (payload > max_payload) {
- ovs_fatal(0, "payload must be between 0 and %zu bytes", max_payload);
- }
-
- open_vconn(argv[1], &vconn);
- for (i = 0; i < 10; i++) {
- struct timeval start, end;
- struct ofpbuf *request, *reply;
- struct ofp_header *rq_hdr, *rpy_hdr;
-
- rq_hdr = make_openflow(sizeof(struct ofp_header) + payload,
- OFPT_ECHO_REQUEST, &request);
- random_bytes(rq_hdr + 1, payload);
-
- gettimeofday(&start, NULL);
- run(vconn_transact(vconn, ofpbuf_clone(request), &reply), "transact");
- gettimeofday(&end, NULL);
-
- rpy_hdr = reply->data;
- if (reply->size != request->size
- || memcmp(rpy_hdr + 1, rq_hdr + 1, payload)
- || rpy_hdr->xid != rq_hdr->xid
- || rpy_hdr->type != OFPT_ECHO_REPLY) {
- printf("Reply does not match request. Request:\n");
- ofp_print(stdout, request, request->size, 2);
- printf("Reply:\n");
- ofp_print(stdout, reply, reply->size, 2);
- }
- printf("%d bytes from %s: xid=%08"PRIx32" time=%.1f ms\n",
- reply->size - sizeof *rpy_hdr, argv[1], rpy_hdr->xid,
- (1000*(double)(end.tv_sec - start.tv_sec))
- + (.001*(end.tv_usec - start.tv_usec)));
- ofpbuf_delete(request);
- ofpbuf_delete(reply);
- }
- vconn_close(vconn);
-}
-
-static void
-do_benchmark(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- size_t max_payload = 65535 - sizeof(struct ofp_header);
- struct timeval start, end;
- unsigned int payload_size, message_size;
- struct vconn *vconn;
- double duration;
- int count;
- int i;
-
- payload_size = atoi(argv[2]);
- if (payload_size > max_payload) {
- ovs_fatal(0, "payload must be between 0 and %zu bytes", max_payload);
- }
- message_size = sizeof(struct ofp_header) + payload_size;
-
- count = atoi(argv[3]);
-
- printf("Sending %d packets * %u bytes (with header) = %u bytes total\n",
- count, message_size, count * message_size);
-
- open_vconn(argv[1], &vconn);
- gettimeofday(&start, NULL);
- for (i = 0; i < count; i++) {
- struct ofpbuf *request, *reply;
- struct ofp_header *rq_hdr;
-
- rq_hdr = make_openflow(message_size, OFPT_ECHO_REQUEST, &request);
- memset(rq_hdr + 1, 0, payload_size);
- run(vconn_transact(vconn, request, &reply), "transact");
- ofpbuf_delete(reply);
- }
- gettimeofday(&end, NULL);
- vconn_close(vconn);
-
- duration = ((1000*(double)(end.tv_sec - start.tv_sec))
- + (.001*(end.tv_usec - start.tv_usec)));
- printf("Finished in %.1f ms (%.0f packets/s) (%.0f bytes/s)\n",
- duration, count / (duration / 1000.0),
- count * message_size / (duration / 1000.0));
-}
-
-static void
-do_execute(const struct settings *s UNUSED, int argc, char *argv[])
-{
- struct vconn *vconn;
- struct ofpbuf *request;
- struct nicira_header *nicira;
- struct nx_command_reply *ncr;
- uint32_t xid;
- int i;
-
- nicira = make_openflow(sizeof *nicira, OFPT_VENDOR, &request);
- xid = nicira->header.xid;
- nicira->vendor = htonl(NX_VENDOR_ID);
- nicira->subtype = htonl(NXT_COMMAND_REQUEST);
- ofpbuf_put(request, argv[2], strlen(argv[2]));
- for (i = 3; i < argc; i++) {
- ofpbuf_put_zeros(request, 1);
- ofpbuf_put(request, argv[i], strlen(argv[i]));
- }
- update_openflow_length(request);
-
- open_vconn(argv[1], &vconn);
- run(vconn_send_block(vconn, request), "send");
-
- for (;;) {
- struct ofpbuf *reply;
- uint32_t status;
-
- run(vconn_recv_xid(vconn, xid, &reply), "recv_xid");
- if (reply->size < sizeof *ncr) {
- ovs_fatal(0, "reply is too short (%zu bytes < %zu bytes)",
- reply->size, sizeof *ncr);
- }
- ncr = reply->data;
- if (ncr->nxh.header.type != OFPT_VENDOR
- || ncr->nxh.vendor != htonl(NX_VENDOR_ID)
- || ncr->nxh.subtype != htonl(NXT_COMMAND_REPLY)) {
- ovs_fatal(0, "reply is invalid");
- }
-
- status = ntohl(ncr->status);
- if (status & NXT_STATUS_STARTED) {
- /* Wait for a second reply. */
- continue;
- } else if (status & NXT_STATUS_EXITED) {
- fprintf(stderr, "process terminated normally with exit code %d",
- status & NXT_STATUS_EXITSTATUS);
- } else if (status & NXT_STATUS_SIGNALED) {
- fprintf(stderr, "process terminated by signal %d",
- status & NXT_STATUS_TERMSIG);
- } else if (status & NXT_STATUS_ERROR) {
- fprintf(stderr, "error executing command");
- } else {
- fprintf(stderr, "process terminated for unknown reason");
- }
- if (status & NXT_STATUS_COREDUMP) {
- fprintf(stderr, " (core dumped)");
- }
- putc('\n', stderr);
-
- fwrite(ncr + 1, reply->size - sizeof *ncr, 1, stdout);
- break;
- }
-}
-
-static void
-do_help(const struct settings *s UNUSED, int argc UNUSED, char *argv[] UNUSED)
-{
- usage();
-}
-
-static struct command all_commands[] = {
-#ifdef HAVE_NETLINK
- { "adddp", 1, INT_MAX, do_add_dp },
- { "deldp", 1, 1, do_del_dp },
- { "addif", 2, INT_MAX, do_add_port },
- { "delif", 2, INT_MAX, do_del_port },
- { "get-idx", 1, 1, do_get_idx },
- { "get-name", 1, 1, do_get_name },
- { "dp-show", 0, INT_MAX, do_dp_show },
- { "dp-dump-flows", 1, 1, do_dp_dump_flows },
- { "dp-del-flows", 1, 1, do_dp_del_flows },
- { "dp-dump-groups", 1, 1, do_dp_dump_groups },
-#endif
-
- { "show", 1, 1, do_show },
- { "status", 1, 2, do_status },
-
- { "help", 0, INT_MAX, do_help },
- { "monitor", 1, 3, do_monitor },
- { "dump-desc", 1, 1, do_dump_desc },
- { "dump-tables", 1, 1, do_dump_tables },
- { "dump-flows", 1, 2, do_dump_flows },
- { "dump-aggregate", 1, 2, do_dump_aggregate },
-#ifdef SUPPORT_SNAT
- { "add-snat", 3, 3, do_add_snat },
- { "del-snat", 2, 2, do_del_snat },
-#endif
- { "add-flow", 2, 2, do_add_flow },
- { "add-flows", 2, 2, do_add_flows },
- { "mod-flows", 2, 2, do_mod_flows },
- { "del-flows", 1, 2, do_del_flows },
- { "dump-ports", 1, 1, do_dump_ports },
- { "mod-port", 3, 3, do_mod_port },
- { "probe", 1, 1, do_probe },
- { "ping", 1, 2, do_ping },
- { "benchmark", 3, 3, do_benchmark },
- { "execute", 2, INT_MAX, do_execute },
- { NULL, 0, 0, NULL },
-};
.SH "SEE ALSO"
-.BR dpctl (8),
-.BR secchan (8),
-.BR ovs\-controller (8)
+.BR ovs\-controller (8),
+.BR ovs\-dpctl (8),
+.BR secchan (8)
.SH "SEE ALSO"
-.BR dpctl (8),
.BR secchan (8),
-.BR ovs\-appctl (8)
+.BR ovs\-appctl (8),
+.BR ovs\-dpctl (8)
.SH BUGS
If the network devices specified on the command line have been added
-to an OpenVSwitch datapath with \fBdpctl addif\fR, then controller
+to an OpenVSwitch datapath with \fBovs\-dpctl addif\fR, then controller
discovery will fail because \fBovs\-discover\fR will not be able to
see DHCP responses, even though tools such as \fBtcpdump\fR(8) and
\fBwireshark\fR(1) can see them on the wire. This is because of the
--- /dev/null
+.TH ovs\-dpctl 8 "March 2009" "OpenVSwitch" "OpenVSwitch Manual"
+.ds PN ovs\-dpctl
+
+.SH NAME
+ovs\-dpctl \- administer OpenVSwitch datapaths
+
+.SH SYNOPSIS
+.B ovs\-dpctl
+[\fIoptions\fR] \fIcommand \fR[\fIswitch\fR] [\fIargs\fR\&...]
+
+.SH DESCRIPTION
+
+The \fBovs\-dpctl\fR program can create, modify, and delete OpenVSwitch
+datapaths. A single machine may host up to 256 datapaths (numbered 0
+to 255).
+
+A newly created datapath is associated with only one network device, a
+virtual network device sometimes called the datapath's ``local port''.
+A newly created datapath is not, however, associated with any of the
+host's other network devices. To intercept and process traffic on a
+given network device, use the \fBaddif\fR command to explicitly add
+that network device to the datapath.
+
+Do not use \fBovs\-dpctl\fR commands to modify datapaths if
+\fBvswitchd\fR(8) is in use. Instead, modify the \fBvswitchd\fR
+configuration file and send \fBSIGHUP\fR to the \fBvswitchd\fR
+process.
+
+.PP
+Most \fBovs\-dpctl\fR commands that work with datapaths take an argument
+that specifies the name of the datapath, in one of the following
+forms:
+
+.so lib/dpif.man
+
+.PP
+The following commands manage datapaths.
+
+.TP
+\fBadddp \fIdp\fR [\fInetdev\fR...]
+
+Creates datapath \fIdp\fR. The name of the new datapath's local port
+depends on how \fIdp\fR is specified: if it takes the form
+\fBdp\fIN\fR, the local port will be named \fBdp\fIN\fR; if \fIdp\fR
+is \fBnl:\fI, the local port will be named \fBof\fIN\fR; otherwise,
+the local port's name will be \fIdp\fR.
+
+This will fail if the host already has 256 datapaths, if a network
+device with the same name as the new datapath's local port already
+exists, or if \fIdp\fR is given in the form \fBdp\fIN\fR or
+\fBnl:\fIN\fR and a datapath numbered \fIN\fR already exists.
+
+If \fInetdev\fRs are specified, \fBovs\-dpctl\fR adds them to the datapath.
+
+.TP
+\fBdeldp \fIdp\fR
+Deletes datapath \fIdp\fR. If \fIdp\fR is associated with any network
+devices, they are automatically removed.
+
+.TP
+\fBaddif \fIdp netdev\fR[\fIoption\fR...]...
+Adds each \fInetdev\fR to the set of network devices datapath
+\fIdp\fR monitors, where \fIdp\fR is the name of an existing
+datapath, and \fInetdev\fR is the name of one of the host's
+network devices, e.g. \fBeth0\fR. Once a network device has been added
+to a datapath, the datapath has complete ownership of the network device's
+traffic and the network device appears silent to the rest of the
+system.
+
+A \fInetdev\fR may be followed by a comma-separated list of options.
+The following options are currently supported:
+
+.RS
+.IP "\fBport=\fIportno\fR"
+Specifies \fIportno\fR (a number between 1 and 255) as the port number
+at which \fInetdev\fR will be attached. By default, \fBaddif\fR
+automatically selects the lowest available port number.
+
+.IP "\fBinternal\fR"
+Instead of attaching an existing \fInetdev\fR, creates an internal
+port (analogous to the local port) with that name.
+.RE
+
+.TP
+\fBdelif \fIdp netdev\fR...
+Removes each \fInetdev\fR from the list of network devices datapath
+\fIdp\fR monitors.
+
+.TP
+\fBget-idx \fIdp\fR
+Prints the datapath number of datapath \fIdp\fR.
+
+.TP
+\fBget-name \fIdp\fR
+Prints the name of datapath \fIdp\fR, that is, the name of the network
+device acting as its local port.
+
+.TP
+\fBdp-show \fR[\fIdp\fR...]
+Prints a summary of configured datapaths, including their datapath
+numbers and a list of ports connected to each datapath. (The local
+port is identified as port 0.)
+
+If one or more datapaths are specified, information on only those
+datapaths are displayed. Otherwise, \fBovs\-dpctl\fR displays information
+about all configured datapaths.
+
+.IP "\fBdp-dump-flows \fIdp\fR"
+Prints to the console all flow entries in datapath \fIdp\fR's
+flow table.
+
+This command is primarily useful for debugging OpenVSwitch. The flow
+table entries that it displays are not
+OpenFlow flow entries. Instead, they are different and considerably
+simpler flows maintained by the OpenVSwitch kernel module.
+
+.IP "\fBdp-del-flows \fIdp\fR"
+Deletes all flow entries from datapath \fIdp\fR's flow table.
+
+This command is primarily useful for debugging OpenVSwitch. As
+discussed in \fBdp-dump-flows\fR, these entries are
+not OpenFlow flow entries. By deleting them, the process that set them
+up may be confused about their disappearance.
+
+.IP "\fBdp-dump-groups \fIdp\fR"
+Prints to the console the sets of port groups maintained by datapath
+\fIdp\fR. Ordinarily there are at least 2 port groups in a datapath
+that \fBsecchan\fR or \fBvswitch\fR is controlling: group 0 contains
+all ports except those disabled by STP, and group 1 contains all
+ports. Additional groups might be used in the future.
+
+This command is primarily useful for debugging OpenVSwitch. OpenFlow
+does not have a concept of port groups.
+
+.SH OPTIONS
+.TP
+\fB-t\fR, \fB--timeout=\fIsecs\fR
+Limits \fBovs\-dpctl\fR runtime to approximately \fIsecs\fR seconds. If
+the timeout expires, \fBovs\-dpctl\fR will exit with a \fBSIGALRM\fR
+signal.
+
+.so lib/vlog.man
+.so lib/common.man
+
+.SH EXAMPLES
+
+A typical \fBovs\-dpctl\fR command sequence for controlling an
+OpenVSwitch kernel module:
+
+.TP
+\fBovs\-dpctl adddp dp0\fR
+Creates datapath number 0.
+
+.TP
+\fBovs\-dpctl addif dp0 eth0 eth1\fR
+Adds two network devices to the new datapath.
+
+.PP
+At this point one would ordinarily start \fBsecchan\fR(8) on
+\fBdp0\fR, transforming \fBdp0\fR into an OpenFlow switch. Then, when
+the switch and the datapath is no longer needed:
+
+.TP
+\fBovs\-dpctl delif dp0 eth0 eth1\fR
+Removes network devices from the datapath.
+
+.TP
+\fBovs\-dpctl deldp dp0\fR
+Deletes the datapath.
+
+.SH "SEE ALSO"
+
+.BR vswitchd (8),
+.BR secchan (8),
+.BR ovs\-appctl (8)
--- /dev/null
+/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford
+ * Junior University
+ *
+ * We are making the OpenFlow specification and associated documentation
+ * (Software) available for public use and benefit with the expectation
+ * that others will use, modify and enhance the Software and contribute
+ * those enhancements back to the community. However, since we would
+ * like to make the Software available for broadest use, with as few
+ * restrictions as possible permission is hereby granted, free of
+ * charge, to any person obtaining a copy of this Software to deal in
+ * the Software under the copyrights without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The name and trademarks of copyright holder(s) may NOT be used in
+ * advertising or publicity pertaining to the Software or any
+ * derivatives without specific, written prior permission.
+ */
+
+#include <config.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include "command-line.h"
+#include "compiler.h"
+#include "dirs.h"
+#include "dpif.h"
+#include "dynamic-string.h"
+#include "netdev.h"
+#include "odp-util.h"
+#include "timeval.h"
+#include "util.h"
+
+#include "vlog.h"
+#define THIS_MODULE VLM_dpctl
+
+struct command {
+ const char *name;
+ int min_args;
+ int max_args;
+ void (*handler)(int argc, char *argv[]);
+};
+
+static struct command all_commands[];
+
+static void usage(void) NO_RETURN;
+static void parse_options(int argc, char *argv[]);
+
+int main(int argc, char *argv[])
+{
+ struct command *p;
+
+ set_program_name(argv[0]);
+ time_init();
+ vlog_init();
+ parse_options(argc, argv);
+ signal(SIGPIPE, SIG_IGN);
+
+ argc -= optind;
+ argv += optind;
+ if (argc < 1)
+ ovs_fatal(0, "missing command name; use --help for help");
+
+ for (p = all_commands; p->name != NULL; p++) {
+ if (!strcmp(p->name, argv[0])) {
+ int n_arg = argc - 1;
+ if (n_arg < p->min_args)
+ ovs_fatal(0, "'%s' command requires at least %d arguments",
+ p->name, p->min_args);
+ else if (n_arg > p->max_args)
+ ovs_fatal(0, "'%s' command takes at most %d arguments",
+ p->name, p->max_args);
+ else {
+ p->handler(argc, argv);
+ if (ferror(stdout)) {
+ ovs_fatal(0, "write to stdout failed");
+ }
+ if (ferror(stderr)) {
+ ovs_fatal(0, "write to stderr failed");
+ }
+ exit(0);
+ }
+ }
+ }
+ ovs_fatal(0, "unknown command '%s'; use --help for help", argv[0]);
+
+ return 0;
+}
+
+static void
+parse_options(int argc, char *argv[])
+{
+ static struct option long_options[] = {
+ {"timeout", required_argument, 0, 't'},
+ {"verbose", optional_argument, 0, 'v'},
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {0, 0, 0, 0},
+ };
+ char *short_options = long_options_to_short_options(long_options);
+
+ for (;;) {
+ unsigned long int timeout;
+ int c;
+
+ c = getopt_long(argc, argv, short_options, long_options, NULL);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 't':
+ timeout = strtoul(optarg, NULL, 10);
+ if (timeout <= 0) {
+ ovs_fatal(0, "value %s on -t or --timeout is not at least 1",
+ optarg);
+ } else {
+ time_alarm(timeout);
+ }
+ break;
+
+ case 'h':
+ usage();
+
+ case 'V':
+ printf("%s %s compiled "__DATE__" "__TIME__"\n",
+ program_name, VERSION BUILDNR);
+ exit(EXIT_SUCCESS);
+
+ case 'v':
+ vlog_set_verbosity(optarg);
+ break;
+
+ case '?':
+ exit(EXIT_FAILURE);
+
+ default:
+ abort();
+ }
+ }
+ free(short_options);
+}
+
+static void
+usage(void)
+{
+ printf("%s: OpenVSwitch datapath management utility\n"
+ "usage: %s [OPTIONS] COMMAND [ARG...]\n"
+ " adddp DP [IFACE...] add new datapath DP (with IFACES)\n"
+ " deldp DP delete local datapath DP\n"
+ " addif DP IFACE... add each IFACE as a port on DP\n"
+ " delif DP IFACE... delete each IFACE from DP\n"
+ " dp-show show basic info on all datapaths\n"
+ " dp-show DP... show basic info on each DP\n"
+ " dp-dump-flows DP display flows in DP\n"
+ " dp-del-flows DP delete all flows from DP\n"
+ " dp-dump-groups DP display port groups in DP\n",
+ program_name, program_name);
+ vlog_usage();
+ printf("\nOther options:\n"
+ " -t, --timeout=SECS give up after SECS seconds\n"
+ " -h, --help display this help message\n"
+ " -V, --version display version information\n");
+ exit(EXIT_SUCCESS);
+}
+
+static void run(int retval, const char *message, ...)
+ PRINTF_FORMAT(2, 3);
+
+static void run(int retval, const char *message, ...)
+{
+ if (retval) {
+ va_list args;
+
+ fprintf(stderr, "%s: ", program_name);
+ va_start(args, message);
+ vfprintf(stderr, message, args);
+ va_end(args);
+ if (retval == EOF) {
+ fputs(": unexpected end of file\n", stderr);
+ } else {
+ fprintf(stderr, ": %s\n", strerror(retval));
+ }
+
+ exit(EXIT_FAILURE);
+ }
+}
+\f
+static void do_add_port(int argc, char *argv[]);
+
+static int if_up(const char *netdev_name)
+{
+ struct netdev *netdev;
+ int retval;
+
+ retval = netdev_open(netdev_name, NETDEV_ETH_TYPE_NONE, &netdev);
+ if (!retval) {
+ retval = netdev_turn_flags_on(netdev, NETDEV_UP, true);
+ netdev_close(netdev);
+ }
+ return retval;
+}
+
+static void
+do_get_idx(int argc UNUSED, char *argv[])
+{
+ struct dpif dpif;
+ run(dpif_open(argv[1], &dpif), "opening datapath");
+ printf("%u\n", dpif_id(&dpif));
+ dpif_close(&dpif);
+}
+
+static void
+do_get_name(int argc UNUSED, char *argv[])
+{
+ struct dpif dpif;
+ char name[IF_NAMESIZE + 1];
+
+ run(dpif_open(argv[1], &dpif), "opening datapath");
+ run(dpif_get_name(&dpif, name, sizeof name), "getting datapath name");
+ puts(name);
+ dpif_close(&dpif);
+}
+
+static void
+do_add_dp(int argc UNUSED, char *argv[])
+{
+ struct dpif dpif;
+ run(dpif_create(argv[1], &dpif), "add_dp");
+ dpif_close(&dpif);
+ if (argc > 2) {
+ do_add_port(argc, argv);
+ }
+}
+
+static void
+do_del_dp(int argc UNUSED, char *argv[])
+{
+ struct dpif dpif;
+ run(dpif_open(argv[1], &dpif), "opening datapath");
+ run(dpif_delete(&dpif), "del_dp");
+ dpif_close(&dpif);
+}
+
+static int
+compare_ports(const void *a_, const void *b_)
+{
+ const struct odp_port *a = a_;
+ const struct odp_port *b = b_;
+ return a->port < b->port ? -1 : a->port > b->port;
+}
+
+static void
+query_ports(struct dpif *dpif, struct odp_port **ports, size_t *n_ports)
+{
+ run(dpif_port_list(dpif, ports, n_ports), "listing ports");
+ qsort(*ports, *n_ports, sizeof **ports, compare_ports);
+}
+
+static uint16_t
+get_free_port(struct dpif *dpif)
+{
+ struct odp_port *ports;
+ size_t n_ports;
+ int port_no;
+
+ query_ports(dpif, &ports, &n_ports);
+ for (port_no = 0; port_no <= UINT16_MAX; port_no++) {
+ size_t i;
+ for (i = 0; i < n_ports; i++) {
+ if (ports[i].port == port_no) {
+ goto next_portno;
+ }
+ }
+ free(ports);
+ return port_no;
+
+ next_portno: ;
+ }
+ ovs_fatal(0, "no free datapath ports");
+}
+
+static void
+do_add_port(int argc UNUSED, char *argv[])
+{
+ bool failure = false;
+ struct dpif dpif;
+ int i;
+
+ run(dpif_open(argv[1], &dpif), "opening datapath");
+ for (i = 2; i < argc; i++) {
+ char *save_ptr = NULL;
+ char *devname, *suboptions;
+ int port = -1;
+ int flags = 0;
+ int error;
+
+ devname = strtok_r(argv[i], ",,", &save_ptr);
+ if (!devname) {
+ ovs_error(0, "%s is not a valid network device name", argv[i]);
+ continue;
+ }
+
+ suboptions = strtok_r(NULL, "", &save_ptr);
+ if (suboptions) {
+ enum {
+ AP_PORT,
+ AP_INTERNAL
+ };
+ static char *options[] = {
+ "port",
+ "internal"
+ };
+
+ while (*suboptions != '\0') {
+ char *value;
+
+ switch (getsubopt(&suboptions, options, &value)) {
+ case AP_PORT:
+ if (!value) {
+ ovs_error(0, "'port' suboption requires a value");
+ }
+ port = atoi(value);
+ break;
+
+ case AP_INTERNAL:
+ flags |= ODP_PORT_INTERNAL;
+ break;
+
+ default:
+ ovs_error(0, "unknown suboption '%s'", value);
+ break;
+ }
+ }
+ }
+ if (port < 0) {
+ port = get_free_port(&dpif);
+ }
+
+ error = dpif_port_add(&dpif, devname, port, flags);
+ if (error) {
+ ovs_error(error, "adding %s as port %"PRIu16" of %s failed",
+ devname, port, argv[1]);
+ failure = true;
+ } else if (if_up(devname)) {
+ failure = true;
+ }
+ }
+ dpif_close(&dpif);
+ if (failure) {
+ exit(EXIT_FAILURE);
+ }
+}
+
+static bool
+get_port_number(struct dpif *dpif, const char *name, uint16_t *port)
+{
+ struct odp_port *ports;
+ size_t n_ports;
+ size_t i;
+
+ query_ports(dpif, &ports, &n_ports);
+ for (i = 0; i < n_ports; i++) {
+ if (!strcmp(name, ports[i].devname)) {
+ *port = ports[i].port;
+ free(ports);
+ return true;
+ }
+ }
+ free(ports);
+ ovs_error(0, "no port named %s", name);
+ return false;
+}
+
+static void
+do_del_port(int argc UNUSED, char *argv[])
+{
+ bool failure = false;
+ struct dpif dpif;
+ int i;
+
+ run(dpif_open(argv[1], &dpif), "opening datapath");
+ for (i = 2; i < argc; i++) {
+ const char *name = argv[i];
+ uint16_t port;
+ int error;
+
+ if (!name[strspn(name, "0123456789")]) {
+ port = atoi(name);
+ } else if (!get_port_number(&dpif, name, &port)) {
+ failure = true;
+ continue;
+ }
+
+ error = dpif_port_del(&dpif, port);
+ if (error) {
+ ovs_error(error, "deleting port %s from %s failed", name, argv[1]);
+ failure = true;
+ }
+ }
+ dpif_close(&dpif);
+ if (failure) {
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void
+show_dpif(struct dpif *dpif)
+{
+ struct odp_port *ports;
+ struct odp_stats stats;
+ size_t n_ports;
+ size_t i;
+
+ printf("dp%u:\n", dpif_id(dpif));
+ if (!dpif_get_dp_stats(dpif, &stats)) {
+ printf("\tflows: cur:%"PRIu32", soft-max:%"PRIu32", "
+ "hard-max:%"PRIu32"\n",
+ stats.n_flows, stats.cur_capacity, stats.max_capacity);
+ printf("\tports: cur:%"PRIu32", max:%"PRIu32"\n",
+ stats.n_ports, stats.max_ports);
+ printf("\tgroups: max:%"PRIu16"\n", stats.max_groups);
+ printf("\tlookups: frags:%"PRIu64", hit:%"PRIu64", missed:%"PRIu64", "
+ "lost:%"PRIu64"\n",
+ stats.n_frags, stats.n_hit, stats.n_missed, stats.n_lost);
+ printf("\tqueues: max-miss:%"PRIu16", max-action:%"PRIu16"\n",
+ stats.max_miss_queue, stats.max_action_queue);
+ }
+ query_ports(dpif, &ports, &n_ports);
+ for (i = 0; i < n_ports; i++) {
+ printf("\tport %u: %s", ports[i].port, ports[i].devname);
+ if (ports[i].flags & ODP_PORT_INTERNAL) {
+ printf(" (internal)");
+ }
+ printf("\n");
+ }
+ free(ports);
+ dpif_close(dpif);
+}
+
+static void
+do_dp_show(int argc UNUSED, char *argv[])
+{
+ bool failure = false;
+ if (argc > 1) {
+ int i;
+ for (i = 1; i < argc; i++) {
+ const char *name = argv[i];
+ struct dpif dpif;
+ int error;
+
+ error = dpif_open(name, &dpif);
+ if (!error) {
+ show_dpif(&dpif);
+ } else {
+ ovs_error(error, "opening datapath %s failed", name);
+ failure = true;
+ }
+ }
+ } else {
+ unsigned int i;
+ for (i = 0; i < ODP_MAX; i++) {
+ char name[128];
+ struct dpif dpif;
+ int error;
+
+ sprintf(name, "dp%u", i);
+ error = dpif_open(name, &dpif);
+ if (!error) {
+ show_dpif(&dpif);
+ } else if (error != ENODEV) {
+ ovs_error(error, "opening datapath %s failed", name);
+ failure = true;
+ }
+ }
+ }
+ if (failure) {
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void
+do_dp_dump_flows(int argc UNUSED, char *argv[])
+{
+ struct odp_flow *flows;
+ struct dpif dpif;
+ size_t n_flows;
+ struct ds ds;
+ size_t i;
+
+ run(dpif_open(argv[1], &dpif), "opening datapath");
+ run(dpif_flow_list_all(&dpif, &flows, &n_flows), "listing all flows");
+
+ ds_init(&ds);
+ for (i = 0; i < n_flows; i++) {
+ struct odp_flow *f = &flows[i];
+ enum { MAX_ACTIONS = 4096 / sizeof(union odp_action) };
+ union odp_action actions[MAX_ACTIONS];
+
+ f->actions = actions;
+ f->n_actions = MAX_ACTIONS;
+ dpif_flow_get(&dpif, f);
+
+ ds_clear(&ds);
+ format_odp_flow(&ds, f);
+ printf("%s\n", ds_cstr(&ds));
+ }
+ ds_destroy(&ds);
+ dpif_close(&dpif);
+}
+
+static void
+do_dp_del_flows(int argc UNUSED, char *argv[])
+{
+ struct dpif dpif;
+
+ run(dpif_open(argv[1], &dpif), "opening datapath");
+ run(dpif_flow_flush(&dpif), "deleting all flows");
+ dpif_close(&dpif);
+}
+
+static void
+do_dp_dump_groups(int argc UNUSED, char *argv[])
+{
+ struct odp_stats stats;
+ struct dpif dpif;
+ unsigned int i;
+
+ run(dpif_open(argv[1], &dpif), "opening datapath");
+ run(dpif_get_dp_stats(&dpif, &stats), "get datapath stats");
+ for (i = 0; i < stats.max_groups; i++) {
+ uint16_t ports[UINT16_MAX];
+ size_t n_ports;
+
+ if (!dpif_port_group_get(&dpif, i, ports,
+ ARRAY_SIZE(ports), &n_ports) && n_ports) {
+ size_t j;
+
+ printf("group %u:", i);
+ for (j = 0; j < n_ports; j++) {
+ printf(" %"PRIu16, ports[j]);
+ }
+ printf("\n");
+ }
+ }
+ dpif_close(&dpif);
+}
+
+static void
+do_help(int argc UNUSED, char *argv[] UNUSED)
+{
+ usage();
+}
+
+static struct command all_commands[] = {
+ { "adddp", 1, INT_MAX, do_add_dp },
+ { "deldp", 1, 1, do_del_dp },
+ { "addif", 2, INT_MAX, do_add_port },
+ { "delif", 2, INT_MAX, do_del_port },
+ { "get-idx", 1, 1, do_get_idx },
+ { "get-name", 1, 1, do_get_name },
+ { "dp-show", 0, INT_MAX, do_dp_show },
+ { "dp-dump-flows", 1, 1, do_dp_dump_flows },
+ { "dp-del-flows", 1, 1, do_dp_del_flows },
+ { "dp-dump-groups", 1, 1, do_dp_dump_groups },
+ { "help", 0, INT_MAX, do_help },
+ { NULL, 0, 0, NULL },
+};
if [ -d /proc/$pid ]; then
# Check if the secchan and datapath still can communicate
if [ -S $SECCHAN_SOCK ]; then
- dpctl probe -t 2 unix:$SECCHAN_SOCK
+ ovs-ofctl probe -t 2 unix:$SECCHAN_SOCK
if [ $? -ne 0 ]; then
log "datapath probe failed"
let DP_DOWN++
--- /dev/null
+.TH ovs\-ofctl 8 "March 2009" "OpenVSwitch" "OpenVSwitch Manual"
+.ds PN ovs\-ofctl
+
+.SH NAME
+ovs\-ofctl \- administer OpenFlow switches
+
+.SH SYNOPSIS
+.B ovs\-ofctl
+[\fIoptions\fR] \fIcommand \fR[\fIswitch\fR] [\fIargs\fR\&...]
+
+.SH DESCRIPTION
+The
+.B ovs\-ofctl
+program is a command line tool for monitoring and administering
+OpenFlow switches. It can also show the current state of an OpenFlow
+switch, including features, configuration, and table entries.
+
+.SS "OpenFlow Switch Management Commands"
+
+These commands allow \fBovs\-ofctl\fR to monitor and administer an OpenFlow
+switch. It is able to show the current state of a switch, including
+features, configuration, and table entries.
+
+Most of these commands take an argument that specifies the method for
+connecting to an OpenFlow switch. The following connection methods
+are supported:
+
+.RS
+.TP
+\fBssl:\fIhost\fR[\fB:\fIport\fR]
+The specified SSL \fIport\fR (default: 6633) on the given remote
+\fIhost\fR. The \fB--private-key\fR, \fB--certificate\fR, and
+\fB--ca-cert\fR options are mandatory when this form is used.
+
+.TP
+\fBtcp:\fIhost\fR[\fB:\fIport\fR]
+The specified TCP \fIport\fR (default: 6633) on the given remote
+\fIhost\fR.
+
+.TP
+\fBunix:\fIfile\fR
+The Unix domain server socket named \fIfile\fR.
+
+.IP "\fIfile\fR"
+This is short for \fBunix:\fIfile\fR, as long as \fIfile\fR does not
+contain a colon.
+
+.IP \fIdp\fR
+This is short for \fBunix:@RUNDIR@/\fIdp\fB.mgmt\fR, as long as
+\fIdp\fR does not contain a colon.
+.RE
+
+.TP
+\fBshow \fIswitch\fR
+Prints to the console information on \fIswitch\fR, including
+information on its flow tables and ports.
+
+.TP
+\fBstatus \fIswitch\fR [\fIkey\fR]
+Prints to the console a series of key-value pairs that report the
+status of \fIswitch\fR. If \fIkey\fR is specified, only the key-value
+pairs whose key names begin with \fIkey\fR are printed. If \fIkey\fR is
+omitted, all key-value pairs are printed.
+
+.TP
+\fBdump-tables \fIswitch\fR
+Prints to the console statistics for each of the flow tables used by
+\fIswitch\fR.
+
+.TP
+\fBdump-ports \fIswitch\fR
+Prints to the console statistics for each of the network devices
+associated with \fIswitch\fR.
+
+.TP
+\fBmod-port \fIswitch\fR \fInetdev\fR \fIaction\fR
+Modify characteristics of an interface monitored by \fIswitch\fR.
+\fInetdev\fR can be referred to by its OpenFlow assigned port number or
+the device name, e.g. \fBeth0\fR. The \fIaction\fR may be any one of the
+following:
+
+.RS
+.IP \fBup\fR
+Enables the interface. This is equivalent to ``ifconfig up'' on a Unix
+system.
+
+.IP \fBdown\fR
+Disables the interface. This is equivalent to ``ifconfig down'' on a Unix
+system.
+
+.IP \fBflood\fR
+When a \fIflood\fR action is specified, traffic will be sent out this
+interface. This is the default posture for monitored ports.
+
+.IP \fBnoflood\fR
+When a \fIflood\fR action is specified, traffic will not be sent out
+this interface. This is primarily useful to prevent loops when a
+spanning tree protocol is not in use.
+
+.RE
+
+.TP
+\fBdump-flows \fIswitch \fR[\fIflows\fR]
+Prints to the console all flow entries in \fIswitch\fR's
+tables that match \fIflows\fR. If \fIflows\fR is omitted, all flows
+in the switch are retrieved. See \fBFlow Syntax\fR, below, for the
+syntax of \fIflows\fR. The output format is described in
+\fBTable Entry Output\fR.
+
+.TP
+\fBdump-aggregate \fIswitch \fR[\fIflows\fR]
+Prints to the console aggregate statistics for flows in
+\fIswitch\fR's tables that match \fIflows\fR. If \fIflows\fR is omitted,
+the statistics are aggregated across all flows in the switch's flow
+tables. See \fBFlow Syntax\fR, below, for the syntax of \fIflows\fR.
+The output format is descrbed in \fBTable Entry Output\fR.
+
+.TP
+\fBadd-flow \fIswitch flow\fR
+Add the flow entry as described by \fIflow\fR to the \fIswitch\fR's
+tables. The flow entry is in the format described in \fBFlow Syntax\fR,
+below.
+
+.TP
+\fBadd-flows \fIswitch file\fR
+Add flow entries as described in \fIfile\fR to \fIswitch\fR's
+tables. Each line in \fIfile\fR is a flow entry in the format
+described in \fBFlow Syntax\fR, below.
+
+.TP
+\fBmod-flows \fIswitch flow\fR
+Modify the actions in entries from the \fIswitch\fR's tables
+that match \fIflow\fR. When invoked with the \fB--strict\fR option,
+wildcards are not treated as active for matching purposes. See
+\fBFlow Syntax\fR, below, for the syntax of \fIflows\fR.
+
+.TP
+\fBdel-flows \fIswitch \fR[\fIflow\fR]
+Deletes entries from the \fIswitch\fR's tables that match
+\fIflow\fR. When invoked with the \fB--strict\fR option, wildcards are
+not treated as active for matching purposes. If \fIflow\fR is
+omitted and the \fB--strict\fR option is not used, all flows in the
+switch's tables are removed. See \fBFlow Syntax\fR, below, for the
+syntax of \fIflows\fR.
+
+.TP
+\fBmonitor \fIswitch\fR [\fImiss-len\fR [\fIsend-exp]]
+Connects to \fIswitch\fR and prints to the console all OpenFlow
+messages received. Usually, \fIswitch\fR should specify a connection
+named on \fBsecchan\fR(8)'s \fB-l\fR or \fB--listen\fR command line
+option.
+
+If \fImiss-len\fR is provided, \fBovs\-ofctl\fR sends an OpenFlow ``set
+configuration'' message at connection setup time that requests
+\fImiss-len\fR bytes of each packet that misses the flow table. The
+OpenFlow reference implementation not send these messages to the
+\fBovs\-ofctl monitor\fR client connection unless a nonzero value is
+specified on this argument.
+
+If \fIsend-exp\fR is specified as \fB1\fR, \fBovs\-ofctl\fR will also
+request to be sent flow expiration messages. If this argument is
+omitted, or \fB0\fR is specified, then \fRovs\-ofctl\fR will not request
+flow expirations.
+
+This command may be useful for debugging switch or controller
+implementations.
+
+.TP
+\fBexecute \fIswitch command \fR[\fIarg\fR...]
+Sends a request to \fIswitch\fR to execute \fIcommand\fR along with
+each \fIarg\fR, if any, then waits for the command to complete and
+reports its completion status on \fBstderr\fR and its output, if any,
+on \fBstdout\fR. The set of available commands and their argument is
+switch-dependent. (This command uses a Nicira extension to OpenFlow
+that may not be available on all switches.)
+
+.SS "OpenFlow Switch and Controller Commands"
+
+The following commands, like those in the previous section, may be
+applied to OpenFlow switches, using any of the connection methods
+described in that section. Unlike those commands, these may also be
+applied to OpenFlow controllers.
+
+.TP
+\fBprobe \fItarget\fR
+Sends a single OpenFlow echo-request message to \fItarget\fR and waits
+for the response. With the \fB-t\fR or \fB--timeout\fR option, this
+command can test whether an OpenFlow switch or controller is up and
+running.
+
+.TP
+\fBping \fItarget \fR[\fIn\fR]
+Sends a series of 10 echo request packets to \fItarget\fR and times
+each reply. The echo request packets consist of an OpenFlow header
+plus \fIn\fR bytes (default: 64) of randomly generated payload. This
+measures the latency of individual requests.
+
+.TP
+\fBbenchmark \fItarget n count\fR
+Sends \fIcount\fR echo request packets that each consist of an
+OpenFlow header plus \fIn\fR bytes of payload and waits for each
+response. Reports the total time required. This is a measure of the
+maximum bandwidth to \fItarget\fR for round-trips of \fIn\fR-byte
+messages.
+
+.SS "Flow Syntax"
+
+Some \fBovs\-ofctl\fR commands accept an argument that describes a flow or
+flows. Such flow descriptions comprise a series
+\fIfield\fB=\fIvalue\fR assignments, separated by commas or white
+space. (Embedding spaces into a flow description normally requires
+quoting to prevent the shell from breaking the description into
+multiple arguments.)
+
+The following field assignments describe how a flow matches a packet.
+If any of these assignments is omitted from the flow syntax, the field
+is treated as a wildcard; thus, if all of them are omitted, the
+resulting flow matches all packets. The string \fB*\fR or \fBANY\fR
+may be specified to explicitly mark any of these fields as a wildcard.
+(\fB*\fR should be quoted to protect it from shell expansion.)
+
+.IP \fBin_port=\fIport_no\fR
+Matches physical port \fIport_no\fR. Switch ports are numbered as
+displayed by \fBovs\-ofctl show\fR.
+
+.IP \fBdl_vlan=\fIvlan\fR
+Matches IEEE 802.1q virtual LAN tag \fIvlan\fR. Specify \fB0xffff\fR
+as \fIvlan\fR to match packets that are not tagged with a virtual LAN;
+otherwise, specify a number between 0 and 4095, inclusive, as the
+12-bit VLAN ID to match.
+
+.IP \fBdl_src=\fImac\fR
+Matches Ethernet source address \fImac\fR, which is specified as 6 pairs
+of hexadecimal digits delimited by colons (e.g. \fB00:0A:E4:25:6B:B0\fR).
+
+.IP \fBdl_dst=\fImac\fR
+Matches Ethernet destination address \fImac\fR.
+
+.IP \fBdl_type=\fIethertype\fR
+Matches Ethernet protocol type \fIethertype\fR, which is specified as an
+integer between 0 and 65535, inclusive, either in decimal or as a
+hexadecimal number prefixed by \fB0x\fR (e.g. \fB0x0806\fR to match ARP
+packets).
+
+.IP \fBnw_src=\fIip\fR[\fB/\fInetmask\fR]
+Matches IPv4 source address \fIip\fR, which may be specified as an
+IP address or host name (e.g. \fB192.168.1.1\fR or
+\fBwww.example.com\fR). The optional \fInetmask\fR allows restricting a
+match to an IPv4 address prefix. The netmask may be specified as a dotted
+quad (e.g. \fB192.168.1.0/255.255.255.0\fR) or as a CIDR block
+(e.g. \fB192.168.1.0/24\fR).
+
+.IP \fBnw_dst=\fIip\fR[\fB/\fInetmask\fR]
+Matches IPv4 destination address \fIip\fR.
+
+.IP \fBnw_proto=\fIproto\fR
+Matches IP protocol type \fIproto\fR, which is specified as a decimal
+number between 0 and 255, inclusive (e.g. 6 to match TCP packets).
+
+.IP \fBtp_src=\fIport\fR
+Matches UDP or TCP source port \fIport\fR, which is specified as a decimal
+number between 0 and 65535, inclusive (e.g. 80 to match packets originating
+from a HTTP server).
+
+.IP \fBtp_dst=\fIport\fR
+Matches UDP or TCP destination port \fIport\fR.
+
+.IP \fBicmp_type=\fItype\fR
+Matches ICMP message with \fItype\fR, which is specified as a decimal
+number between 0 and 255, inclusive.
+
+.IP \fBicmp_code=\fIcode\fR
+Matches ICMP messages with \fIcode\fR.
+
+.PP
+The following shorthand notations are also available:
+
+.IP \fBip\fR
+Same as \fBdl_type=0x0800\fR.
+
+.IP \fBicmp\fR
+Same as \fBdl_type=0x0800,nw_proto=1\fR.
+
+.IP \fBtcp\fR
+Same as \fBdl_type=0x0800,nw_proto=6\fR.
+
+.IP \fBudp\fR
+Same as \fBdl_type=0x0800,nw_proto=17\fR.
+
+.IP \fBarp\fR
+Same as \fBdl_type=0x0806\fR.
+
+.PP
+The \fBadd-flow\fR and \fBadd-flows\fR commands require an additional field:
+
+.IP \fBactions=\fR[\fItarget\fR][\fB,\fItarget\fR...]\fR
+Specifies a comma-separated list of actions to take on a packet when the
+flow entry matches. If no \fItarget\fR is specified, then packets
+matching the flow are dropped. The \fItarget\fR may be a decimal port
+number designating the physical port on which to output the packet, or one
+of the following keywords:
+
+.RS
+.IP \fBoutput\fR:\fIport\fR
+Outputs the packet on the port specified by \fIport\fR.
+
+.IP \fBnormal\fR
+Subjects the packet to the device's normal L2/L3 processing. (This
+action is not implemented by all OpenFlow switches.)
+
+.IP \fBflood\fR
+Outputs the packet on all switch physical ports other than the port on
+which it was received and any ports on which flooding is disabled
+(typically, these would be ports disabled by the IEEE 802.1D spanning
+tree protocol).
+
+.IP \fBall\fR
+Outputs the packet on all switch physical ports other than the port on
+which it was received.
+
+.IP \fBcontroller\fR:\fImax_len\fR
+Sends the packet to the OpenFlow controller as a ``packet in''
+message. If \fImax_len\fR is a number, then it specifies the maximum
+number of bytes that should be sent. If \fImax_len\fR is \fBALL\fR or
+omitted, then the entire packet is sent.
+
+.IP \fBlocal\fR
+Outputs the packet on the ``local port,'' which corresponds to the
+\fBof\fIn\fR network device (see \fBCONTACTING THE CONTROLLER\fR in
+\fBsecchan\fR(8) for information on the \fBof\fIn\fR network device).
+
+.IP \fBdrop\fR
+Discards the packet, so no further processing or forwarding takes place.
+If a drop action is used, no other actions may be specified.
+
+.IP \fBmod_vlan_vid\fR:\fIvlan_vid\fR
+Modifies the VLAN id on a packet. The VLAN tag is added or modified
+as necessary to match the value specified. If the VLAN tag is added,
+a priority of zero is used (see the \fBmod_vlan_pcp\fR action to set
+this).
+
+.IP \fBmod_vlan_pcp\fR:\fIvlan_pcp\fR
+Modifies the VLAN priority on a packet. The VLAN tag is added or modified
+as necessary to match the value specified. Valid values are between 0
+(lowest) and 7 (highest). If the VLAN tag is added, a vid of zero is used
+(see the \fBmod_vlan_vid\fR action to set this).
+
+.IP \fBstrip_vlan\fR
+Strips the VLAN tag from a packet if it is present.
+
+.IP \fBmod_dl_src\fB:\fImac\fR
+Sets the source Ethernet address to \fImac\fR.
+
+.IP \fBmod_dl_dst\fB:\fImac\fR
+Sets the destination Ethernet address to \fImac\fR.
+.RE
+
+.IP
+(The OpenFlow protocol supports other actions that \fBovs\-ofctl\fR does
+not yet expose to the user.)
+
+.PP
+The \fBadd-flow\fR, \fBadd-flows\fR, and \fBdel-flows\fR commands
+support an additional optional field:
+
+.IP \fBpriority=\fIvalue\fR
+The priority at which a wildcarded entry will match in comparison to
+others. \fIvalue\fR is a number between 0 and 65535, inclusive. A higher
+\fIvalue\fR will match before a lower one. An exact-match entry will always
+have priority over an entry containing wildcards, so it has an implicit
+priority value of 65535. When adding a flow, if the field is not specified,
+the flow's priority will default to 32768.
+
+.PP
+The \fBadd-flow\fR and \fBadd-flows\fR commands support additional
+optional fields:
+
+.TP
+\fBidle_timeout=\fIseconds\fR
+Causes the flow to expire after the given number of seconds of
+inactivity. A value of 0 prevents a flow from expiring due to
+inactivity. The default is 60 seconds.
+
+.IP \fBhard_timeout=\fIseconds\fR
+Causes the flow to expire after the given number of seconds,
+regardless of activity. A value of 0 (the default) gives the flow no
+hard expiration deadline.
+
+.PP
+The \fBdump-flows\fR, \fBdump-aggregate\fR, \fBdel-flow\fR
+and \fBdel-flows\fR commands support one additional optional field:
+
+.TP
+\fBout_port=\fIport\fR
+If set, a matching flow must include an output action to \fIport\fR.
+
+.PP
+The \fBdump-flows\fR and \fBdump-aggregate\fR commands support an
+additional optional field:
+
+.IP \fBtable=\fInumber\fR
+If specified, limits the flows about which statistics are gathered to
+those in the table with the given \fInumber\fR. Tables are numbered
+as shown by the \fBdump-tables\fR command.
+
+If this field is not specified, or if \fInumber\fR is given as
+\fB255\fR, statistics are gathered about flows from all tables.
+
+.SS "Table Entry Output"
+
+The \fBdump-tables\fR and \fBdump-aggregate\fR commands print information
+about the entries in a datapath's tables. Each line of output is a
+unique flow entry, which begins with some common information:
+
+.IP \fBduration\fR
+The number of seconds the entry has been in the table.
+
+.IP \fBtable_id\fR
+The table that contains the flow. When a packet arrives, the switch
+begins searching for an entry at the lowest numbered table. Tables are
+numbered as shown by the \fBdump-tables\fR command.
+
+.IP \fBpriority\fR
+The priority of the entry in relation to other entries within the same
+table. A higher value will match before a lower one.
+
+.IP \fBn_packets\fR
+The number of packets that have matched the entry.
+
+.IP \fBn_bytes\fR
+The total number of bytes from packets that have matched the entry.
+
+.PP
+The rest of the line consists of a description of the flow entry as
+described in \fBFlow Syntax\fR, above.
+
+
+.SH OPTIONS
+.TP
+\fB--strict\fR
+Uses strict matching when running flow modification commands.
+
+.TP
+\fB-t\fR, \fB--timeout=\fIsecs\fR
+Limits \fBovs\-ofctl\fR runtime to approximately \fIsecs\fR seconds. If
+the timeout expires, \fBovs\-ofctl\fR will exit with a \fBSIGALRM\fR
+signal.
+
+.TP
+\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR
+Specifies a PEM file containing the private key used as the
+identity for SSL connections to a switch.
+
+.TP
+\fB-c\fR, \fB--certificate=\fIcert.pem\fR
+Specifies a PEM file containing a certificate, signed by the
+controller's certificate authority (CA), that certifies the
+private key to identify a trustworthy controller.
+
+.TP
+\fB-C\fR, \fB--ca-cert=\fIcacert.pem\fR
+Specifies a PEM file containing the CA certificate used to verify that
+a switch is trustworthy.
+
+.so lib/vlog.man
+.so lib/common.man
+
+.SH EXAMPLES
+
+The following examples assume that an OpenFlow switch on the local
+host has been configured to listen for management connections on a
+Unix domain socket named \fB@RUNDIR@/openflow.sock\fR, e.g. by
+specifying \fB--listen=punix:@RUNDIR@/openflow.sock\fR on the
+\fBsecchan\fR(8) command line.
+
+.TP
+\fBovs\-ofctl dump-tables unix:@RUNDIR@/openflow.sock\fR
+Prints out the switch's table stats. (This is more interesting after
+some traffic has passed through.)
+
+.TP
+\fBovs\-ofctl dump-flows unix:@RUNDIR@/openflow.sock\fR
+Prints the flow entries in the switch.
+
+.SH "SEE ALSO"
+
+.BR vswitchd (8),
+.BR ovs\-appctl (8),
+.BR ovs\-controller (8)
--- /dev/null
+/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford
+ * Junior University
+ *
+ * We are making the OpenFlow specification and associated documentation
+ * (Software) available for public use and benefit with the expectation
+ * that others will use, modify and enhance the Software and contribute
+ * those enhancements back to the community. However, since we would
+ * like to make the Software available for broadest use, with as few
+ * restrictions as possible permission is hereby granted, free of
+ * charge, to any person obtaining a copy of this Software to deal in
+ * the Software under the copyrights without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The name and trademarks of copyright holder(s) may NOT be used in
+ * advertising or publicity pertaining to the Software or any
+ * derivatives without specific, written prior permission.
+ */
+
+#include <config.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include "command-line.h"
+#include "compiler.h"
+#include "dirs.h"
+#include "dpif.h"
+#include "dynamic-string.h"
+#include "netdev.h"
+#include "netlink.h"
+#include "odp-util.h"
+#include "ofp-print.h"
+#include "ofpbuf.h"
+#include "openflow/nicira-ext.h"
+#include "openflow/openflow.h"
+#include "packets.h"
+#include "random.h"
+#include "socket-util.h"
+#include "timeval.h"
+#include "util.h"
+#include "vconn-ssl.h"
+#include "vconn.h"
+
+#include "vlog.h"
+#define THIS_MODULE VLM_ofctl
+
+#define DEFAULT_IDLE_TIMEOUT 60
+
+#define MOD_PORT_CMD_UP "up"
+#define MOD_PORT_CMD_DOWN "down"
+#define MOD_PORT_CMD_FLOOD "flood"
+#define MOD_PORT_CMD_NOFLOOD "noflood"
+
+
+/* Settings that may be configured by the user. */
+struct settings {
+ bool strict; /* Use strict matching for flow mod commands */
+};
+
+struct command {
+ const char *name;
+ int min_args;
+ int max_args;
+ void (*handler)(const struct settings *, int argc, char *argv[]);
+};
+
+static struct command all_commands[];
+
+static void usage(void) NO_RETURN;
+static void parse_options(int argc, char *argv[], struct settings *);
+
+int main(int argc, char *argv[])
+{
+ struct settings s;
+ struct command *p;
+
+ set_program_name(argv[0]);
+ time_init();
+ vlog_init();
+ parse_options(argc, argv, &s);
+ signal(SIGPIPE, SIG_IGN);
+
+ argc -= optind;
+ argv += optind;
+ if (argc < 1)
+ ovs_fatal(0, "missing command name; use --help for help");
+
+ for (p = all_commands; p->name != NULL; p++) {
+ if (!strcmp(p->name, argv[0])) {
+ int n_arg = argc - 1;
+ if (n_arg < p->min_args)
+ ovs_fatal(0, "'%s' command requires at least %d arguments",
+ p->name, p->min_args);
+ else if (n_arg > p->max_args)
+ ovs_fatal(0, "'%s' command takes at most %d arguments",
+ p->name, p->max_args);
+ else {
+ p->handler(&s, argc, argv);
+ if (ferror(stdout)) {
+ ovs_fatal(0, "write to stdout failed");
+ }
+ if (ferror(stderr)) {
+ ovs_fatal(0, "write to stderr failed");
+ }
+ exit(0);
+ }
+ }
+ }
+ ovs_fatal(0, "unknown command '%s'; use --help for help", argv[0]);
+
+ return 0;
+}
+
+static void
+parse_options(int argc, char *argv[], struct settings *s)
+{
+ enum {
+ OPT_STRICT = UCHAR_MAX + 1
+ };
+ static struct option long_options[] = {
+ {"timeout", required_argument, 0, 't'},
+ {"verbose", optional_argument, 0, 'v'},
+ {"strict", no_argument, 0, OPT_STRICT},
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ VCONN_SSL_LONG_OPTIONS
+ {0, 0, 0, 0},
+ };
+ char *short_options = long_options_to_short_options(long_options);
+
+ /* Set defaults that we can figure out before parsing options. */
+ s->strict = false;
+
+ for (;;) {
+ unsigned long int timeout;
+ int c;
+
+ c = getopt_long(argc, argv, short_options, long_options, NULL);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 't':
+ timeout = strtoul(optarg, NULL, 10);
+ if (timeout <= 0) {
+ ovs_fatal(0, "value %s on -t or --timeout is not at least 1",
+ optarg);
+ } else {
+ time_alarm(timeout);
+ }
+ break;
+
+ case 'h':
+ usage();
+
+ case 'V':
+ printf("%s %s compiled "__DATE__" "__TIME__"\n",
+ program_name, VERSION BUILDNR);
+ exit(EXIT_SUCCESS);
+
+ case 'v':
+ vlog_set_verbosity(optarg);
+ break;
+
+ case OPT_STRICT:
+ s->strict = true;
+ break;
+
+ VCONN_SSL_OPTION_HANDLERS
+
+ case '?':
+ exit(EXIT_FAILURE);
+
+ default:
+ abort();
+ }
+ }
+ free(short_options);
+}
+
+static void
+usage(void)
+{
+ printf("%s: OpenFlow switch management utility\n"
+ "usage: %s [OPTIONS] COMMAND [ARG...]\n"
+ "\nFor OpenFlow switches:\n"
+ " show SWITCH show OpenFlow information\n"
+ " status SWITCH [KEY] report statistics (about KEY)\n"
+ " dump-desc SWITCH print switch description\n"
+ " dump-tables SWITCH print table stats\n"
+ " mod-port SWITCH IFACE ACT modify port behavior\n"
+ " dump-ports SWITCH print port statistics\n"
+ " dump-flows SWITCH print all flow entries\n"
+ " dump-flows SWITCH FLOW print matching FLOWs\n"
+ " dump-aggregate SWITCH print aggregate flow statistics\n"
+ " dump-aggregate SWITCH FLOW print aggregate stats for FLOWs\n"
+#ifdef SUPPORT_SNAT
+ " add-snat SWITCH IFACE IP add SNAT config to IFACE\n"
+ " del-snat SWITCH IFACE delete SNAT config on IFACE\n"
+#endif
+ " add-flow SWITCH FLOW add flow described by FLOW\n"
+ " add-flows SWITCH FILE add flows from FILE\n"
+ " mod-flows SWITCH FLOW modify actions of matching FLOWs\n"
+ " del-flows SWITCH [FLOW] delete matching FLOWs\n"
+ " monitor SWITCH MISSLEN EXP print packets received from SWITCH\n"
+ " execute SWITCH CMD [ARG...] execute CMD with ARGS on SWITCH\n"
+ "\nFor OpenFlow switches and controllers:\n"
+ " probe VCONN probe whether VCONN is up\n"
+ " ping VCONN [N] latency of N-byte echos\n"
+ " benchmark VCONN N COUNT bandwidth of COUNT N-byte echos\n"
+ "where each SWITCH is an active OpenFlow connection method.\n",
+ program_name, program_name);
+ vconn_usage(true, false, false);
+ vlog_usage();
+ printf("\nOther options:\n"
+ " --strict use strict match for flow commands\n"
+ " -t, --timeout=SECS give up after SECS seconds\n"
+ " -h, --help display this help message\n"
+ " -V, --version display version information\n");
+ exit(EXIT_SUCCESS);
+}
+
+static void run(int retval, const char *message, ...)
+ PRINTF_FORMAT(2, 3);
+
+static void run(int retval, const char *message, ...)
+{
+ if (retval) {
+ va_list args;
+
+ fprintf(stderr, "%s: ", program_name);
+ va_start(args, message);
+ vfprintf(stderr, message, args);
+ va_end(args);
+ if (retval == EOF) {
+ fputs(": unexpected end of file\n", stderr);
+ } else {
+ fprintf(stderr, ": %s\n", strerror(retval));
+ }
+
+ exit(EXIT_FAILURE);
+ }
+}
+\f
+/* Generic commands. */
+
+static void
+open_vconn(const char *name, struct vconn **vconnp)
+{
+ struct dpif dpif;
+ struct stat s;
+
+ if (strstr(name, ":")) {
+ run(vconn_open_block(name, OFP_VERSION, vconnp),
+ "connecting to %s", name);
+ } else if (!stat(name, &s) && S_ISSOCK(s.st_mode)) {
+ char *vconn_name = xasprintf("unix:%s", name);
+ VLOG_INFO("connecting to %s", vconn_name);
+ run(vconn_open_block(vconn_name, OFP_VERSION, vconnp),
+ "connecting to %s", vconn_name);
+ free(vconn_name);
+ } else if (!dpif_open(name, &dpif)) {
+ char dpif_name[IF_NAMESIZE + 1];
+ char *socket_name;
+ char *vconn_name;
+
+ run(dpif_get_name(&dpif, dpif_name, sizeof dpif_name),
+ "obtaining name of %s", dpif_name);
+ dpif_close(&dpif);
+ if (strcmp(dpif_name, name)) {
+ VLOG_INFO("datapath %s is named %s", name, dpif_name);
+ }
+
+ socket_name = xasprintf("%s/%s.mgmt", ovs_rundir, dpif_name);
+ if (stat(socket_name, &s)) {
+ ovs_fatal(errno, "cannot connect to %s: stat failed on %s",
+ name, socket_name);
+ } else if (!S_ISSOCK(s.st_mode)) {
+ ovs_fatal(0, "cannot connect to %s: %s is not a socket",
+ name, socket_name);
+ }
+
+ vconn_name = xasprintf("unix:%s", socket_name);
+ VLOG_INFO("connecting to %s", vconn_name);
+ run(vconn_open_block(vconn_name, OFP_VERSION, vconnp),
+ "connecting to %s", vconn_name);
+ free(socket_name);
+ free(vconn_name);
+ } else {
+ ovs_fatal(0, "%s is not a valid connection method", name);
+ }
+}
+
+static void *
+alloc_stats_request(size_t body_len, uint16_t type, struct ofpbuf **bufferp)
+{
+ struct ofp_stats_request *rq;
+ rq = make_openflow((offsetof(struct ofp_stats_request, body)
+ + body_len), OFPT_STATS_REQUEST, bufferp);
+ rq->type = htons(type);
+ rq->flags = htons(0);
+ return rq->body;
+}
+
+static void
+send_openflow_buffer(struct vconn *vconn, struct ofpbuf *buffer)
+{
+ update_openflow_length(buffer);
+ run(vconn_send_block(vconn, buffer), "failed to send packet to switch");
+}
+
+static void
+dump_transaction(const char *vconn_name, struct ofpbuf *request)
+{
+ struct vconn *vconn;
+ struct ofpbuf *reply;
+
+ update_openflow_length(request);
+ open_vconn(vconn_name, &vconn);
+ run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
+ ofp_print(stdout, reply->data, reply->size, 1);
+ vconn_close(vconn);
+}
+
+static void
+dump_trivial_transaction(const char *vconn_name, uint8_t request_type)
+{
+ struct ofpbuf *request;
+ make_openflow(sizeof(struct ofp_header), request_type, &request);
+ dump_transaction(vconn_name, request);
+}
+
+static void
+dump_stats_transaction(const char *vconn_name, struct ofpbuf *request)
+{
+ uint32_t send_xid = ((struct ofp_header *) request->data)->xid;
+ struct vconn *vconn;
+ bool done = false;
+
+ open_vconn(vconn_name, &vconn);
+ send_openflow_buffer(vconn, request);
+ while (!done) {
+ uint32_t recv_xid;
+ struct ofpbuf *reply;
+
+ run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
+ recv_xid = ((struct ofp_header *) reply->data)->xid;
+ if (send_xid == recv_xid) {
+ struct ofp_stats_reply *osr;
+
+ ofp_print(stdout, reply->data, reply->size, 1);
+
+ osr = ofpbuf_at(reply, 0, sizeof *osr);
+ done = !osr || !(ntohs(osr->flags) & OFPSF_REPLY_MORE);
+ } else {
+ VLOG_DBG("received reply with xid %08"PRIx32" "
+ "!= expected %08"PRIx32, recv_xid, send_xid);
+ }
+ ofpbuf_delete(reply);
+ }
+ vconn_close(vconn);
+}
+
+static void
+dump_trivial_stats_transaction(const char *vconn_name, uint8_t stats_type)
+{
+ struct ofpbuf *request;
+ alloc_stats_request(0, stats_type, &request);
+ dump_stats_transaction(vconn_name, request);
+}
+
+static void
+do_show(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+{
+ dump_trivial_transaction(argv[1], OFPT_FEATURES_REQUEST);
+ dump_trivial_transaction(argv[1], OFPT_GET_CONFIG_REQUEST);
+}
+
+static void
+do_status(const struct settings *s UNUSED, int argc, char *argv[])
+{
+ struct nicira_header *request, *reply;
+ struct vconn *vconn;
+ struct ofpbuf *b;
+
+ request = make_openflow(sizeof *request, OFPT_VENDOR, &b);
+ request->vendor = htonl(NX_VENDOR_ID);
+ request->subtype = htonl(NXT_STATUS_REQUEST);
+ if (argc > 2) {
+ ofpbuf_put(b, argv[2], strlen(argv[2]));
+ update_openflow_length(b);
+ }
+ open_vconn(argv[1], &vconn);
+ run(vconn_transact(vconn, b, &b), "talking to %s", argv[1]);
+ vconn_close(vconn);
+
+ if (b->size < sizeof *reply) {
+ ovs_fatal(0, "short reply (%zu bytes)", b->size);
+ }
+ reply = b->data;
+ if (reply->header.type != OFPT_VENDOR
+ || reply->vendor != ntohl(NX_VENDOR_ID)
+ || reply->subtype != ntohl(NXT_STATUS_REPLY)) {
+ ofp_print(stderr, b->data, b->size, 2);
+ ovs_fatal(0, "bad reply");
+ }
+
+ fwrite(reply + 1, b->size - sizeof *reply, 1, stdout);
+}
+
+static void
+do_dump_desc(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+{
+ dump_trivial_stats_transaction(argv[1], OFPST_DESC);
+}
+
+static void
+do_dump_tables(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+{
+ dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
+}
+
+
+static uint32_t
+str_to_u32(const char *str)
+{
+ char *tail;
+ uint32_t value;
+
+ errno = 0;
+ value = strtoul(str, &tail, 0);
+ if (errno == EINVAL || errno == ERANGE || *tail) {
+ ovs_fatal(0, "invalid numeric format %s", str);
+ }
+ return value;
+}
+
+static void
+str_to_mac(const char *str, uint8_t mac[6])
+{
+ if (sscanf(str, "%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8,
+ &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) != 6) {
+ ovs_fatal(0, "invalid mac address %s", str);
+ }
+}
+
+static uint32_t
+str_to_ip(const char *str_, uint32_t *ip)
+{
+ char *str = xstrdup(str_);
+ char *save_ptr = NULL;
+ const char *name, *netmask;
+ struct in_addr in_addr;
+ int n_wild, retval;
+
+ name = strtok_r(str, "//", &save_ptr);
+ retval = name ? lookup_ip(name, &in_addr) : EINVAL;
+ if (retval) {
+ ovs_fatal(0, "%s: could not convert to IP address", str);
+ }
+ *ip = in_addr.s_addr;
+
+ netmask = strtok_r(NULL, "//", &save_ptr);
+ if (netmask) {
+ uint8_t o[4];
+ if (sscanf(netmask, "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8,
+ &o[0], &o[1], &o[2], &o[3]) == 4) {
+ uint32_t nm = (o[0] << 24) | (o[1] << 16) | (o[2] << 8) | o[3];
+ int i;
+
+ /* Find first 1-bit. */
+ for (i = 0; i < 32; i++) {
+ if (nm & (1u << i)) {
+ break;
+ }
+ }
+ n_wild = i;
+
+ /* Verify that the rest of the bits are 1-bits. */
+ for (; i < 32; i++) {
+ if (!(nm & (1u << i))) {
+ ovs_fatal(0, "%s: %s is not a valid netmask",
+ str, netmask);
+ }
+ }
+ } else {
+ int prefix = atoi(netmask);
+ if (prefix <= 0 || prefix > 32) {
+ ovs_fatal(0, "%s: network prefix bits not between 1 and 32",
+ str);
+ }
+ n_wild = 32 - prefix;
+ }
+ } else {
+ n_wild = 0;
+ }
+
+ free(str);
+ return n_wild;
+}
+
+static void *
+put_action(struct ofpbuf *b, size_t size, uint16_t type)
+{
+ struct ofp_action_header *ah = ofpbuf_put_zeros(b, size);
+ ah->type = htons(type);
+ ah->len = htons(size);
+ return ah;
+}
+
+static struct ofp_action_output *
+put_output_action(struct ofpbuf *b, uint16_t port)
+{
+ struct ofp_action_output *oao = put_action(b, sizeof *oao, OFPAT_OUTPUT);
+ oao->port = htons(port);
+ return oao;
+}
+
+static void
+put_dl_addr_action(struct ofpbuf *b, uint16_t type, const char *addr)
+{
+ struct ofp_action_dl_addr *oada = put_action(b, sizeof *oada, type);
+ str_to_mac(addr, oada->dl_addr);
+}
+
+
+static bool
+parse_port_name(const char *name, uint16_t *port)
+{
+ struct pair {
+ const char *name;
+ uint16_t value;
+ };
+ static const struct pair pairs[] = {
+#define DEF_PAIR(NAME) {#NAME, OFPP_##NAME}
+ DEF_PAIR(IN_PORT),
+ DEF_PAIR(TABLE),
+ DEF_PAIR(NORMAL),
+ DEF_PAIR(FLOOD),
+ DEF_PAIR(ALL),
+ DEF_PAIR(CONTROLLER),
+ DEF_PAIR(LOCAL),
+ DEF_PAIR(NONE),
+#undef DEF_PAIR
+ };
+ static const int n_pairs = ARRAY_SIZE(pairs);
+ size_t i;
+
+ for (i = 0; i < n_pairs; i++) {
+ if (!strcasecmp(name, pairs[i].name)) {
+ *port = pairs[i].value;
+ return true;
+ }
+ }
+ return false;
+}
+
+static void
+str_to_action(char *str, struct ofpbuf *b)
+{
+ char *act, *arg;
+ char *saveptr = NULL;
+ bool drop = false;
+ int n_actions;
+
+ for (act = strtok_r(str, ", \t\r\n", &saveptr), n_actions = 0; act;
+ act = strtok_r(NULL, ", \t\r\n", &saveptr), n_actions++)
+ {
+ uint16_t port;
+
+ if (drop) {
+ ovs_fatal(0, "Drop actions must not be followed by other actions");
+ }
+
+ /* Arguments are separated by colons */
+ arg = strchr(act, ':');
+ if (arg) {
+ *arg = '\0';
+ arg++;
+ }
+
+ if (!strcasecmp(act, "mod_vlan_vid")) {
+ struct ofp_action_vlan_vid *va;
+ va = put_action(b, sizeof *va, OFPAT_SET_VLAN_VID);
+ va->vlan_vid = htons(str_to_u32(arg));
+ } else if (!strcasecmp(act, "mod_vlan_pcp")) {
+ struct ofp_action_vlan_pcp *va;
+ va = put_action(b, sizeof *va, OFPAT_SET_VLAN_PCP);
+ va->vlan_pcp = str_to_u32(arg);
+ } else if (!strcasecmp(act, "strip_vlan")) {
+ struct ofp_action_header *ah;
+ ah = put_action(b, sizeof *ah, OFPAT_STRIP_VLAN);
+ ah->type = htons(OFPAT_STRIP_VLAN);
+ } else if (!strcasecmp(act, "mod_dl_src")) {
+ put_dl_addr_action(b, OFPAT_SET_DL_SRC, arg);
+ } else if (!strcasecmp(act, "mod_dl_dst")) {
+ put_dl_addr_action(b, OFPAT_SET_DL_DST, arg);
+ } else if (!strcasecmp(act, "output")) {
+ put_output_action(b, str_to_u32(arg));
+ } else if (!strcasecmp(act, "drop")) {
+ /* A drop action in OpenFlow occurs by just not setting
+ * an action. */
+ drop = true;
+ if (n_actions) {
+ ovs_fatal(0, "Drop actions must not be preceded by other "
+ "actions");
+ }
+#ifdef SUPPORT_SNAT
+ } else if (!strcasecmp(act, "nat")) {
+ struct nx_action_snat *sa;
+
+ if (str_to_u32(arg) > OFPP_MAX) {
+ ovs_fatal(0, "Invalid nat port: %s\n", arg);
+ }
+
+ sa = put_action(b, sizeof *sa, OFPAT_VENDOR);
+ sa->vendor = htonl(NX_VENDOR_ID);
+ sa->subtype = htons(NXAST_SNAT);
+ sa->port = htons(str_to_u32(arg));
+#endif
+ } else if (!strcasecmp(act, "CONTROLLER")) {
+ struct ofp_action_output *oao;
+ oao = put_output_action(b, OFPP_CONTROLLER);
+
+ /* Unless a numeric argument is specified, we send the whole
+ * packet to the controller. */
+ if (arg && (strspn(act, "0123456789") == strlen(act))) {
+ oao->max_len = htons(str_to_u32(arg));
+ }
+ } else if (parse_port_name(act, &port)) {
+ put_output_action(b, port);
+ } else if (strspn(act, "0123456789") == strlen(act)) {
+ put_output_action(b, str_to_u32(act));
+ } else {
+ ovs_fatal(0, "Unknown action: %s", act);
+ }
+ }
+}
+
+struct protocol {
+ const char *name;
+ uint16_t dl_type;
+ uint8_t nw_proto;
+};
+
+static bool
+parse_protocol(const char *name, const struct protocol **p_out)
+{
+ static const struct protocol protocols[] = {
+ { "ip", ETH_TYPE_IP, 0 },
+ { "arp", ETH_TYPE_ARP, 0 },
+ { "icmp", ETH_TYPE_IP, IP_TYPE_ICMP },
+ { "tcp", ETH_TYPE_IP, IP_TYPE_TCP },
+ { "udp", ETH_TYPE_IP, IP_TYPE_UDP },
+ };
+ const struct protocol *p;
+
+ for (p = protocols; p < &protocols[ARRAY_SIZE(protocols)]; p++) {
+ if (!strcmp(p->name, name)) {
+ *p_out = p;
+ return true;
+ }
+ }
+ *p_out = NULL;
+ return false;
+}
+
+struct field {
+ const char *name;
+ uint32_t wildcard;
+ enum { F_U8, F_U16, F_MAC, F_IP } type;
+ size_t offset, shift;
+};
+
+static bool
+parse_field(const char *name, const struct field **f_out)
+{
+#define F_OFS(MEMBER) offsetof(struct ofp_match, MEMBER)
+ static const struct field fields[] = {
+ { "in_port", OFPFW_IN_PORT, F_U16, F_OFS(in_port), 0 },
+ { "dl_vlan", OFPFW_DL_VLAN, F_U16, F_OFS(dl_vlan), 0 },
+ { "dl_src", OFPFW_DL_SRC, F_MAC, F_OFS(dl_src), 0 },
+ { "dl_dst", OFPFW_DL_DST, F_MAC, F_OFS(dl_dst), 0 },
+ { "dl_type", OFPFW_DL_TYPE, F_U16, F_OFS(dl_type), 0 },
+ { "nw_src", OFPFW_NW_SRC_MASK, F_IP,
+ F_OFS(nw_src), OFPFW_NW_SRC_SHIFT },
+ { "nw_dst", OFPFW_NW_DST_MASK, F_IP,
+ F_OFS(nw_dst), OFPFW_NW_DST_SHIFT },
+ { "nw_proto", OFPFW_NW_PROTO, F_U8, F_OFS(nw_proto), 0 },
+ { "tp_src", OFPFW_TP_SRC, F_U16, F_OFS(tp_src), 0 },
+ { "tp_dst", OFPFW_TP_DST, F_U16, F_OFS(tp_dst), 0 },
+ { "icmp_type", OFPFW_ICMP_TYPE, F_U16, F_OFS(icmp_type), 0 },
+ { "icmp_code", OFPFW_ICMP_CODE, F_U16, F_OFS(icmp_code), 0 }
+ };
+ const struct field *f;
+
+ for (f = fields; f < &fields[ARRAY_SIZE(fields)]; f++) {
+ if (!strcmp(f->name, name)) {
+ *f_out = f;
+ return true;
+ }
+ }
+ *f_out = NULL;
+ return false;
+}
+
+static void
+str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions,
+ uint8_t *table_idx, uint16_t *out_port, uint16_t *priority,
+ uint16_t *idle_timeout, uint16_t *hard_timeout)
+{
+ char *save_ptr = NULL;
+ char *name;
+ uint32_t wildcards;
+
+ if (table_idx) {
+ *table_idx = 0xff;
+ }
+ if (out_port) {
+ *out_port = OFPP_NONE;
+ }
+ if (priority) {
+ *priority = OFP_DEFAULT_PRIORITY;
+ }
+ if (idle_timeout) {
+ *idle_timeout = DEFAULT_IDLE_TIMEOUT;
+ }
+ if (hard_timeout) {
+ *hard_timeout = OFP_FLOW_PERMANENT;
+ }
+ if (actions) {
+ char *act_str = strstr(string, "action");
+ if (!act_str) {
+ ovs_fatal(0, "must specify an action");
+ }
+ *(act_str-1) = '\0';
+
+ act_str = strchr(act_str, '=');
+ if (!act_str) {
+ ovs_fatal(0, "must specify an action");
+ }
+
+ act_str++;
+
+ str_to_action(act_str, actions);
+ }
+ memset(match, 0, sizeof *match);
+ wildcards = OFPFW_ALL;
+ for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name;
+ name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) {
+ const struct protocol *p;
+
+ if (parse_protocol(name, &p)) {
+ wildcards &= ~OFPFW_DL_TYPE;
+ match->dl_type = htons(p->dl_type);
+ if (p->nw_proto) {
+ wildcards &= ~OFPFW_NW_PROTO;
+ match->nw_proto = p->nw_proto;
+ }
+ } else {
+ const struct field *f;
+ char *value;
+
+ value = strtok_r(NULL, ", \t\r\n", &save_ptr);
+ if (!value) {
+ ovs_fatal(0, "field %s missing value", name);
+ }
+
+ if (table_idx && !strcmp(name, "table")) {
+ *table_idx = atoi(value);
+ } else if (out_port && !strcmp(name, "out_port")) {
+ *out_port = atoi(value);
+ } else if (priority && !strcmp(name, "priority")) {
+ *priority = atoi(value);
+ } else if (idle_timeout && !strcmp(name, "idle_timeout")) {
+ *idle_timeout = atoi(value);
+ } else if (hard_timeout && !strcmp(name, "hard_timeout")) {
+ *hard_timeout = atoi(value);
+ } else if (parse_field(name, &f)) {
+ void *data = (char *) match + f->offset;
+ if (!strcmp(value, "*") || !strcmp(value, "ANY")) {
+ wildcards |= f->wildcard;
+ } else {
+ wildcards &= ~f->wildcard;
+ if (f->wildcard == OFPFW_IN_PORT
+ && parse_port_name(value, (uint16_t *) data)) {
+ /* Nothing to do. */
+ } else if (f->type == F_U8) {
+ *(uint8_t *) data = str_to_u32(value);
+ } else if (f->type == F_U16) {
+ *(uint16_t *) data = htons(str_to_u32(value));
+ } else if (f->type == F_MAC) {
+ str_to_mac(value, data);
+ } else if (f->type == F_IP) {
+ wildcards |= str_to_ip(value, data) << f->shift;
+ } else {
+ NOT_REACHED();
+ }
+ }
+ } else {
+ ovs_fatal(0, "unknown keyword %s", name);
+ }
+ }
+ }
+ match->wildcards = htonl(wildcards);
+}
+
+static void
+do_dump_flows(const struct settings *s UNUSED, int argc, char *argv[])
+{
+ struct ofp_flow_stats_request *req;
+ uint16_t out_port;
+ struct ofpbuf *request;
+
+ req = alloc_stats_request(sizeof *req, OFPST_FLOW, &request);
+ str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL,
+ &req->table_id, &out_port, NULL, NULL, NULL);
+ memset(&req->pad, 0, sizeof req->pad);
+ req->out_port = htons(out_port);
+
+ dump_stats_transaction(argv[1], request);
+}
+
+static void
+do_dump_aggregate(const struct settings *s UNUSED, int argc, char *argv[])
+{
+ struct ofp_aggregate_stats_request *req;
+ struct ofpbuf *request;
+ uint16_t out_port;
+
+ req = alloc_stats_request(sizeof *req, OFPST_AGGREGATE, &request);
+ str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL,
+ &req->table_id, &out_port, NULL, NULL, NULL);
+ memset(&req->pad, 0, sizeof req->pad);
+ req->out_port = htons(out_port);
+
+ dump_stats_transaction(argv[1], request);
+}
+
+#ifdef SUPPORT_SNAT
+static void
+do_add_snat(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+{
+ struct vconn *vconn;
+ struct ofpbuf *buffer;
+ struct nx_act_config *nac;
+ size_t size;
+
+ /* Parse and send. */
+ size = sizeof *nac + sizeof nac->snat[0];
+ nac = make_openflow(size, OFPT_VENDOR, &buffer);
+
+ nac->header.vendor = htonl(NX_VENDOR_ID);
+ nac->header.subtype = htonl(NXT_ACT_SET_CONFIG);
+
+ nac->type = htons(NXAST_SNAT);
+ nac->snat[0].command = NXSC_ADD;
+ nac->snat[0].port = htons(str_to_u32(argv[2]));
+ nac->snat[0].mac_timeout = htons(0);
+ str_to_ip(argv[3], &nac->snat[0].ip_addr_start);
+ str_to_ip(argv[3], &nac->snat[0].ip_addr_end);
+
+ open_vconn(argv[1], &vconn);
+ send_openflow_buffer(vconn, buffer);
+ vconn_close(vconn);
+}
+
+static void
+do_del_snat(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+{
+ struct vconn *vconn;
+ struct ofpbuf *buffer;
+ struct nx_act_config *nac;
+ size_t size;
+
+ /* Parse and send. */
+ size = sizeof *nac + sizeof nac->snat[0];
+ nac = make_openflow(size, OFPT_VENDOR, &buffer);
+
+ nac->header.vendor = htonl(NX_VENDOR_ID);
+ nac->header.subtype = htonl(NXT_ACT_SET_CONFIG);
+
+ nac->type = htons(NXAST_SNAT);
+ nac->snat[0].command = NXSC_DELETE;
+ nac->snat[0].port = htons(str_to_u32(argv[2]));
+ nac->snat[0].mac_timeout = htons(0);
+
+ open_vconn(argv[1], &vconn);
+ send_openflow_buffer(vconn, buffer);
+ vconn_close(vconn);
+}
+#endif /* SUPPORT_SNAT */
+
+static void
+do_add_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+{
+ struct vconn *vconn;
+ struct ofpbuf *buffer;
+ struct ofp_flow_mod *ofm;
+ uint16_t priority, idle_timeout, hard_timeout;
+ struct ofp_match match;
+
+ /* Parse and send. str_to_flow() will expand and reallocate the data in
+ * 'buffer', so we can't keep pointers to across the str_to_flow() call. */
+ make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
+ str_to_flow(argv[2], &match, buffer,
+ NULL, NULL, &priority, &idle_timeout, &hard_timeout);
+ ofm = buffer->data;
+ ofm->match = match;
+ ofm->command = htons(OFPFC_ADD);
+ ofm->idle_timeout = htons(idle_timeout);
+ ofm->hard_timeout = htons(hard_timeout);
+ ofm->buffer_id = htonl(UINT32_MAX);
+ ofm->priority = htons(priority);
+ ofm->reserved = htonl(0);
+
+ open_vconn(argv[1], &vconn);
+ send_openflow_buffer(vconn, buffer);
+ vconn_close(vconn);
+}
+
+static void
+do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+{
+ struct vconn *vconn;
+ FILE *file;
+ char line[1024];
+
+ file = fopen(argv[2], "r");
+ if (file == NULL) {
+ ovs_fatal(errno, "%s: open", argv[2]);
+ }
+
+ open_vconn(argv[1], &vconn);
+ while (fgets(line, sizeof line, file)) {
+ struct ofpbuf *buffer;
+ struct ofp_flow_mod *ofm;
+ uint16_t priority, idle_timeout, hard_timeout;
+ struct ofp_match match;
+
+ char *comment;
+
+ /* Delete comments. */
+ comment = strchr(line, '#');
+ if (comment) {
+ *comment = '\0';
+ }
+
+ /* Drop empty lines. */
+ if (line[strspn(line, " \t\n")] == '\0') {
+ continue;
+ }
+
+ /* Parse and send. str_to_flow() will expand and reallocate the data
+ * in 'buffer', so we can't keep pointers to across the str_to_flow()
+ * call. */
+ ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
+ str_to_flow(line, &match, buffer,
+ NULL, NULL, &priority, &idle_timeout, &hard_timeout);
+ ofm = buffer->data;
+ ofm->match = match;
+ ofm->command = htons(OFPFC_ADD);
+ ofm->idle_timeout = htons(idle_timeout);
+ ofm->hard_timeout = htons(hard_timeout);
+ ofm->buffer_id = htonl(UINT32_MAX);
+ ofm->priority = htons(priority);
+ ofm->reserved = htonl(0);
+
+ send_openflow_buffer(vconn, buffer);
+ }
+ vconn_close(vconn);
+ fclose(file);
+}
+
+static void
+do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[])
+{
+ uint16_t priority, idle_timeout, hard_timeout;
+ struct vconn *vconn;
+ struct ofpbuf *buffer;
+ struct ofp_flow_mod *ofm;
+
+ /* Parse and send. */
+ ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
+ str_to_flow(argv[2], &ofm->match, buffer,
+ NULL, NULL, &priority, &idle_timeout, &hard_timeout);
+ if (s->strict) {
+ ofm->command = htons(OFPFC_MODIFY_STRICT);
+ } else {
+ ofm->command = htons(OFPFC_MODIFY);
+ }
+ ofm->idle_timeout = htons(idle_timeout);
+ ofm->hard_timeout = htons(hard_timeout);
+ ofm->buffer_id = htonl(UINT32_MAX);
+ ofm->priority = htons(priority);
+ ofm->reserved = htonl(0);
+
+ open_vconn(argv[1], &vconn);
+ send_openflow_buffer(vconn, buffer);
+ vconn_close(vconn);
+}
+
+static void do_del_flows(const struct settings *s, int argc, char *argv[])
+{
+ struct vconn *vconn;
+ uint16_t priority;
+ uint16_t out_port;
+ struct ofpbuf *buffer;
+ struct ofp_flow_mod *ofm;
+
+ /* Parse and send. */
+ ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
+ str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, NULL,
+ &out_port, &priority, NULL, NULL);
+ if (s->strict) {
+ ofm->command = htons(OFPFC_DELETE_STRICT);
+ } else {
+ ofm->command = htons(OFPFC_DELETE);
+ }
+ ofm->idle_timeout = htons(0);
+ ofm->hard_timeout = htons(0);
+ ofm->buffer_id = htonl(UINT32_MAX);
+ ofm->out_port = htons(out_port);
+ ofm->priority = htons(priority);
+ ofm->reserved = htonl(0);
+
+ open_vconn(argv[1], &vconn);
+ send_openflow_buffer(vconn, buffer);
+ vconn_close(vconn);
+}
+
+static void
+do_monitor(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+{
+ struct vconn *vconn;
+
+ open_vconn(argv[1], &vconn);
+ if (argc > 2) {
+ int miss_send_len = atoi(argv[2]);
+ int send_flow_exp = argc > 3 ? atoi(argv[3]) : 0;
+ struct ofp_switch_config *osc;
+ struct ofpbuf *buf;
+
+ osc = make_openflow(sizeof *osc, OFPT_SET_CONFIG, &buf);
+ osc->flags = htons(send_flow_exp ? OFPC_SEND_FLOW_EXP : 0);
+ osc->miss_send_len = htons(miss_send_len);
+ send_openflow_buffer(vconn, buf);
+ }
+ for (;;) {
+ struct ofpbuf *b;
+ run(vconn_recv_block(vconn, &b), "vconn_recv");
+ ofp_print(stderr, b->data, b->size, 2);
+ ofpbuf_delete(b);
+ }
+}
+
+static void
+do_dump_ports(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+{
+ dump_trivial_stats_transaction(argv[1], OFPST_PORT);
+}
+
+static void
+do_probe(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+{
+ struct ofpbuf *request;
+ struct vconn *vconn;
+ struct ofpbuf *reply;
+
+ make_openflow(sizeof(struct ofp_header), OFPT_ECHO_REQUEST, &request);
+ open_vconn(argv[1], &vconn);
+ run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]);
+ if (reply->size != sizeof(struct ofp_header)) {
+ ovs_fatal(0, "reply does not match request");
+ }
+ ofpbuf_delete(reply);
+ vconn_close(vconn);
+}
+
+static void
+do_mod_port(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+{
+ struct ofpbuf *request, *reply;
+ struct ofp_switch_features *osf;
+ struct ofp_port_mod *opm;
+ struct vconn *vconn;
+ char *endptr;
+ int n_ports;
+ int port_idx;
+ int port_no;
+
+
+ /* Check if the argument is a port index. Otherwise, treat it as
+ * the port name. */
+ port_no = strtol(argv[2], &endptr, 10);
+ if (port_no == 0 && endptr == argv[2]) {
+ port_no = -1;
+ }
+
+ /* Send a "Features Request" to get the information we need in order
+ * to modify the port. */
+ make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request);
+ open_vconn(argv[1], &vconn);
+ run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]);
+
+ osf = reply->data;
+ n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports;
+
+ for (port_idx = 0; port_idx < n_ports; port_idx++) {
+ if (port_no != -1) {
+ /* Check argument as a port index */
+ if (osf->ports[port_idx].port_no == htons(port_no)) {
+ break;
+ }
+ } else {
+ /* Check argument as an interface name */
+ if (!strncmp((char *)osf->ports[port_idx].name, argv[2],
+ sizeof osf->ports[0].name)) {
+ break;
+ }
+
+ }
+ }
+ if (port_idx == n_ports) {
+ ovs_fatal(0, "couldn't find monitored port: %s", argv[2]);
+ }
+
+ opm = make_openflow(sizeof(struct ofp_port_mod), OFPT_PORT_MOD, &request);
+ opm->port_no = osf->ports[port_idx].port_no;
+ memcpy(opm->hw_addr, osf->ports[port_idx].hw_addr, sizeof opm->hw_addr);
+ opm->config = htonl(0);
+ opm->mask = htonl(0);
+ opm->advertise = htonl(0);
+
+ printf("modifying port: %s\n", osf->ports[port_idx].name);
+
+ if (!strncasecmp(argv[3], MOD_PORT_CMD_UP, sizeof MOD_PORT_CMD_UP)) {
+ opm->mask |= htonl(OFPPC_PORT_DOWN);
+ } else if (!strncasecmp(argv[3], MOD_PORT_CMD_DOWN,
+ sizeof MOD_PORT_CMD_DOWN)) {
+ opm->mask |= htonl(OFPPC_PORT_DOWN);
+ opm->config |= htonl(OFPPC_PORT_DOWN);
+ } else if (!strncasecmp(argv[3], MOD_PORT_CMD_FLOOD,
+ sizeof MOD_PORT_CMD_FLOOD)) {
+ opm->mask |= htonl(OFPPC_NO_FLOOD);
+ } else if (!strncasecmp(argv[3], MOD_PORT_CMD_NOFLOOD,
+ sizeof MOD_PORT_CMD_NOFLOOD)) {
+ opm->mask |= htonl(OFPPC_NO_FLOOD);
+ opm->config |= htonl(OFPPC_NO_FLOOD);
+ } else {
+ ovs_fatal(0, "unknown mod-port command '%s'", argv[3]);
+ }
+
+ send_openflow_buffer(vconn, request);
+
+ ofpbuf_delete(reply);
+ vconn_close(vconn);
+}
+
+static void
+do_ping(const struct settings *s UNUSED, int argc, char *argv[])
+{
+ size_t max_payload = 65535 - sizeof(struct ofp_header);
+ unsigned int payload;
+ struct vconn *vconn;
+ int i;
+
+ payload = argc > 2 ? atoi(argv[2]) : 64;
+ if (payload > max_payload) {
+ ovs_fatal(0, "payload must be between 0 and %zu bytes", max_payload);
+ }
+
+ open_vconn(argv[1], &vconn);
+ for (i = 0; i < 10; i++) {
+ struct timeval start, end;
+ struct ofpbuf *request, *reply;
+ struct ofp_header *rq_hdr, *rpy_hdr;
+
+ rq_hdr = make_openflow(sizeof(struct ofp_header) + payload,
+ OFPT_ECHO_REQUEST, &request);
+ random_bytes(rq_hdr + 1, payload);
+
+ gettimeofday(&start, NULL);
+ run(vconn_transact(vconn, ofpbuf_clone(request), &reply), "transact");
+ gettimeofday(&end, NULL);
+
+ rpy_hdr = reply->data;
+ if (reply->size != request->size
+ || memcmp(rpy_hdr + 1, rq_hdr + 1, payload)
+ || rpy_hdr->xid != rq_hdr->xid
+ || rpy_hdr->type != OFPT_ECHO_REPLY) {
+ printf("Reply does not match request. Request:\n");
+ ofp_print(stdout, request, request->size, 2);
+ printf("Reply:\n");
+ ofp_print(stdout, reply, reply->size, 2);
+ }
+ printf("%d bytes from %s: xid=%08"PRIx32" time=%.1f ms\n",
+ reply->size - sizeof *rpy_hdr, argv[1], rpy_hdr->xid,
+ (1000*(double)(end.tv_sec - start.tv_sec))
+ + (.001*(end.tv_usec - start.tv_usec)));
+ ofpbuf_delete(request);
+ ofpbuf_delete(reply);
+ }
+ vconn_close(vconn);
+}
+
+static void
+do_benchmark(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+{
+ size_t max_payload = 65535 - sizeof(struct ofp_header);
+ struct timeval start, end;
+ unsigned int payload_size, message_size;
+ struct vconn *vconn;
+ double duration;
+ int count;
+ int i;
+
+ payload_size = atoi(argv[2]);
+ if (payload_size > max_payload) {
+ ovs_fatal(0, "payload must be between 0 and %zu bytes", max_payload);
+ }
+ message_size = sizeof(struct ofp_header) + payload_size;
+
+ count = atoi(argv[3]);
+
+ printf("Sending %d packets * %u bytes (with header) = %u bytes total\n",
+ count, message_size, count * message_size);
+
+ open_vconn(argv[1], &vconn);
+ gettimeofday(&start, NULL);
+ for (i = 0; i < count; i++) {
+ struct ofpbuf *request, *reply;
+ struct ofp_header *rq_hdr;
+
+ rq_hdr = make_openflow(message_size, OFPT_ECHO_REQUEST, &request);
+ memset(rq_hdr + 1, 0, payload_size);
+ run(vconn_transact(vconn, request, &reply), "transact");
+ ofpbuf_delete(reply);
+ }
+ gettimeofday(&end, NULL);
+ vconn_close(vconn);
+
+ duration = ((1000*(double)(end.tv_sec - start.tv_sec))
+ + (.001*(end.tv_usec - start.tv_usec)));
+ printf("Finished in %.1f ms (%.0f packets/s) (%.0f bytes/s)\n",
+ duration, count / (duration / 1000.0),
+ count * message_size / (duration / 1000.0));
+}
+
+static void
+do_execute(const struct settings *s UNUSED, int argc, char *argv[])
+{
+ struct vconn *vconn;
+ struct ofpbuf *request;
+ struct nicira_header *nicira;
+ struct nx_command_reply *ncr;
+ uint32_t xid;
+ int i;
+
+ nicira = make_openflow(sizeof *nicira, OFPT_VENDOR, &request);
+ xid = nicira->header.xid;
+ nicira->vendor = htonl(NX_VENDOR_ID);
+ nicira->subtype = htonl(NXT_COMMAND_REQUEST);
+ ofpbuf_put(request, argv[2], strlen(argv[2]));
+ for (i = 3; i < argc; i++) {
+ ofpbuf_put_zeros(request, 1);
+ ofpbuf_put(request, argv[i], strlen(argv[i]));
+ }
+ update_openflow_length(request);
+
+ open_vconn(argv[1], &vconn);
+ run(vconn_send_block(vconn, request), "send");
+
+ for (;;) {
+ struct ofpbuf *reply;
+ uint32_t status;
+
+ run(vconn_recv_xid(vconn, xid, &reply), "recv_xid");
+ if (reply->size < sizeof *ncr) {
+ ovs_fatal(0, "reply is too short (%zu bytes < %zu bytes)",
+ reply->size, sizeof *ncr);
+ }
+ ncr = reply->data;
+ if (ncr->nxh.header.type != OFPT_VENDOR
+ || ncr->nxh.vendor != htonl(NX_VENDOR_ID)
+ || ncr->nxh.subtype != htonl(NXT_COMMAND_REPLY)) {
+ ovs_fatal(0, "reply is invalid");
+ }
+
+ status = ntohl(ncr->status);
+ if (status & NXT_STATUS_STARTED) {
+ /* Wait for a second reply. */
+ continue;
+ } else if (status & NXT_STATUS_EXITED) {
+ fprintf(stderr, "process terminated normally with exit code %d",
+ status & NXT_STATUS_EXITSTATUS);
+ } else if (status & NXT_STATUS_SIGNALED) {
+ fprintf(stderr, "process terminated by signal %d",
+ status & NXT_STATUS_TERMSIG);
+ } else if (status & NXT_STATUS_ERROR) {
+ fprintf(stderr, "error executing command");
+ } else {
+ fprintf(stderr, "process terminated for unknown reason");
+ }
+ if (status & NXT_STATUS_COREDUMP) {
+ fprintf(stderr, " (core dumped)");
+ }
+ putc('\n', stderr);
+
+ fwrite(ncr + 1, reply->size - sizeof *ncr, 1, stdout);
+ break;
+ }
+}
+
+static void
+do_help(const struct settings *s UNUSED, int argc UNUSED, char *argv[] UNUSED)
+{
+ usage();
+}
+
+static struct command all_commands[] = {
+ { "show", 1, 1, do_show },
+ { "status", 1, 2, do_status },
+ { "monitor", 1, 3, do_monitor },
+ { "dump-desc", 1, 1, do_dump_desc },
+ { "dump-tables", 1, 1, do_dump_tables },
+ { "dump-flows", 1, 2, do_dump_flows },
+ { "dump-aggregate", 1, 2, do_dump_aggregate },
+#ifdef SUPPORT_SNAT
+ { "add-snat", 3, 3, do_add_snat },
+ { "del-snat", 2, 2, do_del_snat },
+#endif
+ { "add-flow", 2, 2, do_add_flow },
+ { "add-flows", 2, 2, do_add_flows },
+ { "mod-flows", 2, 2, do_mod_flows },
+ { "del-flows", 1, 2, do_del_flows },
+ { "dump-ports", 1, 1, do_dump_ports },
+ { "mod-port", 3, 3, do_mod_port },
+ { "probe", 1, 1, do_probe },
+ { "ping", 1, 2, do_ping },
+ { "benchmark", 3, 3, do_benchmark },
+ { "execute", 2, INT_MAX, do_execute },
+ { "help", 0, INT_MAX, do_help },
+ { NULL, 0, 0, NULL },
+};
.SH "SEE ALSO"
.BR controller (8),
-.BR dpctl (8),
.BR ovs\-pki\-cgi (8),
.BR secchan (8)
* - We deleted an interface but there are still a few packets
* queued up from it.
*
- * - Someone externally added an interface (e.g. with "dpctl
+ * - Someone externally added an interface (e.g. with "ovs-dpctl
* addif") that we don't know about.
*
* - Packet arrived on the local port but the local port is not
to the maximum number of supported OpenVSwitch datapaths.
.PP
\fBvswitchd\fR does all the necessary management of OpenVSwitch datapaths
-itself. Thus, external tools, such \fBdpctl\fR(8), are not needed for
+itself. Thus, external tools, such \fBovs\-dpctl\fR(8), are not needed for
managing datapaths in conjunction with \fBvswitchd\fR, and their use
to modify datapaths when \fBvswitchd\fR is running can interfere with
-its operation. (\fBdpctl\fR may still be useful for diagnostics.)
+its operation. (\fBovs\-dpctl\fR may still be useful for diagnostics.)
.PP
An OpenVSwitch datapath kernel module must be loaded for \fBvswitchd\fR
to be useful. Please refer to the \fBINSTALL\fR file included in the
when a rate-limit is specified.
.ST "Remote Command Execution Settings"
These settings configure the commands that remote OpenFlow connections
-are allowed to invoke using (e.g.) \fBdpctl execute\fR. To be
+are allowed to invoke using (e.g.) \fBovs\-ofctl execute\fR. To be
permitted, a command name must be whitelisted and must not be
blacklisted. When the whitelist and blacklist permit a command name,
\fBvswitchd\fR looks for a program with the same name as the command
By default, each bridge \fIname\fR listens for OpenFlow management
connections on a Unix domain socket named
\fB@RUNDIR@/\fIname\fB.mgmt\fR. This socket can be used to perform
-local OpenFlow monitoring and administration, e.g., \fBdpctl dump-flows
+local OpenFlow monitoring and administration, e.g., \fBovs\-ofctl dump-flows
unix:@RUNDIR@/\fIname\fB.mgmt\fR to display the flows currently set up
in bridge \fIname\fR.
.PP
By default, each bridge \fIname\fR listens for OpenFlow controller
connection snooping connections on a Unix domain socket named
\fB@RUNDIR@/\fIname\fB.snoop\fR. A client that connects to this
-socket, e.g., \fBdpctl monitor unix:@RUNDIR@/\fIname\fB.snoop\fR, will
+socket, e.g., \fBovs\-ofctl monitor unix:@RUNDIR@/\fIname\fB.snoop\fR, will
receive a copy of every OpenFlow message sent by the switch to the
controller, or vice versa, on the primary OpenFlow controller
connection.
# Full paths to executables & modules
vswitchd="$VSWITCH_BASE/sbin/vswitchd"
brcompatd="$VSWITCH_BASE/sbin/brcompatd"
-dpctl="$VSWITCH_BASE/bin/dpctl"
+dpctl="$VSWITCH_BASE/bin/ovs-dpctl"
appctl="$VSWITCH_BASE/bin/ovs-appctl"
+ofctl="$VSWITCH_BASE/bin/ovs-ofctl"
if [ "$ENABLE_FAKE_PROC_NET" == "y" ]; then
local mgmt_hwaddr=$(xen_pifdev_hwaddr "$mgmt_pifdev")
test -n "$mgmt_hwaddr" || return
action "Inserting dl_addr $mgmt_hwaddr flows for mgmt intf" true
- "$dpctl" add-flow "$mgmt_intf" dl_src="$mgmt_hwaddr",idle_timeout=0,priority=0,action=normal
- "$dpctl" add-flow "$mgmt_intf" dl_dst="$mgmt_hwaddr",idle_timeout=0,priority=0,action=normal
+ "$ofctl" add-flow "$mgmt_intf" dl_src="$mgmt_hwaddr",idle_timeout=0,priority=0,action=normal
+ "$ofctl" add-flow "$mgmt_intf" dl_dst="$mgmt_hwaddr",idle_timeout=0,priority=0,action=normal
}
function ifup_dp_intf {
}
function watchdp {
- watch dpctl dp-show "$@"
+ watch ovs-dpctl dp-show "$@"
}
function watchdpflows {
if [ $# -gt 0 ]; then
grep="| grep $@"
fi
- watch "dpctl dp-dump-flows $dp $grep"
+ watch "ovs-dpctl dp-dump-flows $dp $grep"
}
function watchflows {
local grep=""
local dp=$1
shift
- bridge=$(dpctl dp-show $dp | grep 'port 0:' | cut -d' ' -f 3)
+ bridge=$(ovs-dpctl dp-show $dp | grep 'port 0:' | cut -d' ' -f 3)
if [ $# -gt 0 ]; then
grep="| grep $@"
fi
- watch "dpctl dump-flows unix:/var/run/$bridge.mgmt $grep"
+ watch "ovs-ofctl dump-flows unix:/var/run/$bridge.mgmt $grep"
}
function monitorlogs {
/root/vswitch/scripts/XSFeatureNiciraVSwitch.pyo
/root/vswitch/sbin/brcompatd
/root/vswitch/sbin/vswitchd
-/root/vswitch/bin/dpctl
/root/vswitch/bin/ovs-appctl
/root/vswitch/bin/ovs-cfg-mod
+/root/vswitch/bin/ovs-dpctl
+/root/vswitch/bin/ovs-ofctl
/root/vswitch/share/man/man5/vswitchd.conf.5
/root/vswitch/share/man/man8/brcompatd.8
/root/vswitch/share/man/man8/ovs-appctl.8
/root/vswitch/share/man/man8/ovs-cfg-mod.8
-/root/vswitch/share/man/man8/dpctl.8
+/root/vswitch/share/man/man8/ovs-dpctl.8
+/root/vswitch/share/man/man8/ovs-ofctl.8
/root/vswitch/share/man/man8/vswitchd.8