2
0
mirror of https://github.com/openvswitch/ovs synced 2025-09-01 06:45:17 +00:00

ovs-vsctl: Fix bugs.

The full ovs-vsctl test suite now passes.
This commit is contained in:
Ben Pfaff
2009-12-09 13:28:48 -08:00
parent c75d15113c
commit dfbe07ba61
3 changed files with 176 additions and 129 deletions

View File

@@ -130,7 +130,9 @@ m4_define([CHECK_IFACES],
[RUN_OVS_VSCTL([list-ifaces $1])], [RUN_OVS_VSCTL([list-ifaces $1])],
[0], [0],
[m4_foreach([iface], m4_cdr($@), [iface [m4_foreach([iface], m4_cdr($@), [iface
])]) ])],
[],
[OVS_VSCTL_CLEANUP])
AT_CHECK([RUN_OVS_VSCTL([iface-to-br $1])], [1], [], AT_CHECK([RUN_OVS_VSCTL([iface-to-br $1])], [1], [],
[ovs-vsctl: no interface named $1 [ovs-vsctl: no interface named $1
], ],
@@ -192,7 +194,7 @@ AT_SETUP([add-br a, add-port a a1, add-port a a2])
AT_KEYWORDS([ovs-vsctl]) AT_KEYWORDS([ovs-vsctl])
OVS_VSCTL_SETUP OVS_VSCTL_SETUP
AT_CHECK([RUN_OVS_VSCTL( AT_CHECK([RUN_OVS_VSCTL(
[add-br a], [add-br a],
[add-port a a1], [add-port a a1],
[add-port a a2])], [0], [], [], [OVS_VSCTL_CLEANUP]) [add-port a a2])], [0], [], [], [OVS_VSCTL_CLEANUP])
CHECK_BRIDGES([a, a, 0]) CHECK_BRIDGES([a, a, 0])
@@ -269,31 +271,23 @@ CHECK_PORTS([a])
OVS_VSCTL_CLEANUP OVS_VSCTL_CLEANUP
AT_CLEANUP AT_CLEANUP
m4_define([ovs_vsctl_disabled_tests], [
dnl ---------------------------------------------------------------------- dnl ----------------------------------------------------------------------
AT_BANNER([ovs-vsctl unit tests -- fake bridges]) AT_BANNER([ovs-vsctl unit tests -- fake bridges])
m4_define([SIMPLE_FAKE_CONF], [dnl m4_define([OVS_VSCTL_SETUP_SIMPLE_FAKE_CONF],
bridge.xenbr0.port=eth0 [AT_CHECK(
bridge.xenbr0.port=eth0.9 [RUN_OVS_VSCTL(
bridge.xenbr0.port=xapi1 [add-br xenbr0],
bridge.xenbr0.port=xenbr0 [add-port xenbr0 eth0],
iface.xapi1.fake-bridge=true [add-br xapi1 xenbr0 9],
iface.xapi1.internal=true [add-port xapi1 eth0.9])],
vlan.eth0.9.tag=9 [0], [], [], [OVS_VSCTL_CLEANUP])])
vlan.xapi1.tag=9
])
AT_SETUP([simple fake bridge]) AT_SETUP([simple fake bridge])
AT_KEYWORDS([ovs-vsctl fake-bridge]) AT_KEYWORDS([ovs-vsctl fake-bridge])
OVS_VSCTL_SETUP OVS_VSCTL_SETUP
AT_CHECK([RUN_OVS_VSCTL( OVS_VSCTL_SETUP_SIMPLE_FAKE_CONF
[add-br xenbr0], CHECK_BRIDGES([xapi1, xenbr0, 9], [xenbr0, xenbr0, 0])
[add-port xenbr0 eth0],
[add-br xapi1 xenbr0 9],
[add-port xapi1 eth0.9])])
AT_CHECK([cat conf], [0], [SIMPLE_FAKE_CONF])
CHECK_BRIDGES([xenbr0, xenbr0, 0], [xapi1, xenbr0, 9])
CHECK_PORTS([xenbr0], [eth0]) CHECK_PORTS([xenbr0], [eth0])
CHECK_IFACES([xenbr0], [eth0]) CHECK_IFACES([xenbr0], [eth0])
CHECK_PORTS([xapi1], [eth0.9]) CHECK_PORTS([xapi1], [eth0.9])
@@ -304,12 +298,8 @@ AT_CLEANUP
AT_SETUP([simple fake bridge + del-br fake bridge]) AT_SETUP([simple fake bridge + del-br fake bridge])
AT_KEYWORDS([ovs-vsctl fake-bridge]) AT_KEYWORDS([ovs-vsctl fake-bridge])
OVS_VSCTL_SETUP OVS_VSCTL_SETUP
AT_DATA([conf], [SIMPLE_FAKE_CONF]) OVS_VSCTL_SETUP_SIMPLE_FAKE_CONF
AT_CHECK([RUN_OVS_VSCTL([del-br xapi1])]) AT_CHECK([RUN_OVS_VSCTL([del-br xapi1])], [0], [], [], [OVS_VSCTL_CLEANUP])
AT_CHECK([cat conf], [0], [dnl
bridge.xenbr0.port=eth0
bridge.xenbr0.port=xenbr0
])
CHECK_BRIDGES([xenbr0, xenbr0, 0]) CHECK_BRIDGES([xenbr0, xenbr0, 0])
CHECK_PORTS([xenbr0], [eth0]) CHECK_PORTS([xenbr0], [eth0])
CHECK_IFACES([xenbr0], [eth0]) CHECK_IFACES([xenbr0], [eth0])
@@ -319,35 +309,25 @@ AT_CLEANUP
AT_SETUP([simple fake bridge + del-br real bridge]) AT_SETUP([simple fake bridge + del-br real bridge])
AT_KEYWORDS([ovs-vsctl fake-bridge]) AT_KEYWORDS([ovs-vsctl fake-bridge])
OVS_VSCTL_SETUP OVS_VSCTL_SETUP
AT_DATA([conf], [SIMPLE_FAKE_CONF]) OVS_VSCTL_SETUP_SIMPLE_FAKE_CONF
AT_CHECK([RUN_OVS_VSCTL([del-br xenbr0])]) AT_CHECK([RUN_OVS_VSCTL([del-br xenbr0])], [0], [], [], [OVS_VSCTL_CLEANUP])
AT_CHECK([cat conf], [0], [])
CHECK_BRIDGES CHECK_BRIDGES
OVS_VSCTL_CLEANUP OVS_VSCTL_CLEANUP
AT_CLEANUP AT_CLEANUP
m4_define([BOND_FAKE_CONF], [dnl m4_define([OVS_VSCTL_SETUP_BOND_FAKE_CONF],
bonding.bond0.slave=eth0 [AT_CHECK(
bonding.bond0.slave=eth1 [RUN_OVS_VSCTL(
bridge.xapi1.port=bond0 [add-br xapi1],
bridge.xapi1.port=bond0.11 [add-bond xapi1 bond0 eth0 eth1],
bridge.xapi1.port=xapi1 [add-br xapi2 xapi1 11],
bridge.xapi1.port=xapi2 [add-port xapi2 bond0.11])],
iface.xapi2.fake-bridge=true [0], [], [], [OVS_VSCTL_CLEANUP])])
iface.xapi2.internal=true
vlan.bond0.11.tag=11
vlan.xapi2.tag=11
])
AT_SETUP([fake bridge on bond]) AT_SETUP([fake bridge on bond])
AT_KEYWORDS([ovs-vsctl fake-bridge]) AT_KEYWORDS([ovs-vsctl fake-bridge])
OVS_VSCTL_SETUP OVS_VSCTL_SETUP
AT_CHECK([RUN_OVS_VSCTL( OVS_VSCTL_SETUP_BOND_FAKE_CONF
[add-br xapi1],
[add-bond xapi1 bond0 eth0 eth1],
[add-br xapi2 xapi1 11],
[add-port xapi2 bond0.11])])
AT_CHECK([cat conf], [0], [BOND_FAKE_CONF])
CHECK_BRIDGES([xapi1, xapi1, 0], [xapi2, xapi1, 11]) CHECK_BRIDGES([xapi1, xapi1, 0], [xapi2, xapi1, 11])
CHECK_PORTS([xapi1], [bond0]) CHECK_PORTS([xapi1], [bond0])
CHECK_IFACES([xapi1], [eth0], [eth1]) CHECK_IFACES([xapi1], [eth0], [eth1])
@@ -359,9 +339,9 @@ AT_CLEANUP
AT_SETUP([fake bridge on bond + del-br fake bridge]) AT_SETUP([fake bridge on bond + del-br fake bridge])
AT_KEYWORDS([ovs-vsctl fake-bridge]) AT_KEYWORDS([ovs-vsctl fake-bridge])
OVS_VSCTL_SETUP OVS_VSCTL_SETUP
AT_DATA([conf], [BOND_FAKE_CONF]) OVS_VSCTL_SETUP_BOND_FAKE_CONF
AT_CHECK([RUN_OVS_VSCTL([--oneline del-br xapi2])], [0], [ AT_CHECK([RUN_OVS_VSCTL([--oneline del-br xapi2])], [0], [
]) ], [], [OVS_VSCTL_CLEANUP])
CHECK_BRIDGES([xapi1, xapi1, 0]) CHECK_BRIDGES([xapi1, xapi1, 0])
CHECK_PORTS([xapi1], [bond0]) CHECK_PORTS([xapi1], [bond0])
CHECK_IFACES([xapi1], [eth0], [eth1]) CHECK_IFACES([xapi1], [eth0], [eth1])
@@ -370,9 +350,9 @@ AT_CLEANUP
AT_SETUP([fake bridge on bond + del-br real bridge]) AT_SETUP([fake bridge on bond + del-br real bridge])
AT_KEYWORDS([ovs-vsctl fake-bridge]) AT_KEYWORDS([ovs-vsctl fake-bridge])
AT_DATA([conf], [BOND_FAKE_CONF]) OVS_VSCTL_SETUP
OVS_VSCTL_SETUP_BOND_FAKE_CONF
AT_CHECK([RUN_OVS_VSCTL([del-br xapi1])]) AT_CHECK([RUN_OVS_VSCTL([del-br xapi1])])
CHECK_BRIDGES CHECK_BRIDGES
OVS_VSCTL_CLEANUP OVS_VSCTL_CLEANUP
AT_CLEANUP AT_CLEANUP
])

View File

@@ -15,20 +15,20 @@ ovs\-vsctl \- utility for querying and configuring \fBovs\-vswitchd\fR
[\fB\-\-\fR \fIcommand \fR[\fIargs\fR\&...]] [\fB\-\-\fR \fIcommand \fR[\fIargs\fR\&...]]
. .
.SH DESCRIPTION .SH DESCRIPTION
The \fBovs\-vsctl\fR program configures \fBovs\-vswitchd\fR(8), mainly The \fBovs\-vsctl\fR program configures \fBovs\-vswitchd\fR(8) by
by providing a high\-level interface to editing its configuration file providing a high\-level interface to editing its configuration
\fBovs\-vswitchd.conf\fR(5). This program is mainly intended for use database. This program is mainly intended for use when
when \fBovs\-vswitchd\fR is running, but it can also be used when \fBovs\-vswitchd\fR is running. If it is used when
\fBovs\-vswitchd\fR is not running. In the latter case configuration \fBovs\-vswitchd\fR is not running, then \fB\-\-no\-wait\fR should be
changes will only take effect when \fBovs\-vswitchd\fR is started. specified and configuration changes will only take effect when
\fBovs\-vswitchd\fR is started.
.PP .PP
By default, each time \fBovs\-vsctl\fR runs, it examines and, By default, each time \fBovs\-vsctl\fR runs, it connects to an
depending on the requested command or commands, possibly applies \fBovsdb\-server\fR process that maintains an Open vSwitch
changes to an configuration database. Using this connection, it queries and
\fBovs\-vswitchd.conf\fR file. Then, if it applied any changes and if possibly applies changes to the database, depending on the supplied
\fBovs\-vswitchd\fR is running, it tells \fBovs\-vswitchd\fR to reload commands. Then, if it applied any changes, it waits until
the modified configuration file and waits for the reload to complete \fBovs\-vswitchd\fR has finished reconfiguring itself before it exits.
before exiting.
. .
.SS "Linux VLAN Bridging Compatibility" .SS "Linux VLAN Bridging Compatibility"
The \fBovs\-vsctl\fR program supports the model of a bridge The \fBovs\-vsctl\fR program supports the model of a bridge
@@ -54,46 +54,34 @@ they are members.
The following options affect the general outline of \fBovs\-vsctl\fR's The following options affect the general outline of \fBovs\-vsctl\fR's
activities: activities:
. .
.IP "\fB\-c \fIfile\fR" .IP "\fB\-\-db=\fIserver\fR"
.IQ "\fB\-\-config=\fIfile\fR" Sets \fIserver\fR as the database server that \fBovs\-vsctl\fR
Sets the configuration file that \fBovs\-vsctl\fR reads and possibly contacts to query or modify configuration. The default is
modifies. The default is \fB@localstatedir@/ovs\-vswitchd.conf\fR. \fBunix:@RUNDIR@/ovsdb\-server\fR. \fIserver\fR must take one of the
following forms:
.RS
.IP "\fBtcp:\fIip\fB:\fIport\fR"
Connect to the given TCP \fIport\fR on \fIip\fR.
.IP "\fBunix:\fIfile\fR"
Connect to the Unix domain server socket named \fIfile\fR.
.RE
.IP "\fB\-\-no\-wait\fR"
Prevents \fBovs\-vsctl\fR from waiting for \fBovs\-vswitchd\fR to
reconfigure itself according to the the modified database. This
option should be used if \fBovs\-vswitchd\fR is not running;
otherwise, \fBovs-vsctl\fR will not exit until \fBovs-vswitchd\fR
starts.
.IP .IP
If \fIfile\fR is specified as \fB\-\fR, then \fBovs\-vsctl\fR reads This option has no effect if the commands specified do not change the
the configuration file from standard input and, for commands that database.
modify the configuration, writes the new one to standard output. This
is useful for testing but it should not be used in production because
it bypasses the Open vSwitch configuration file locking protocol.
.
.IP "\fB\-t \fItarget\fR"
.IQ "\fB\-\-target=\fItarget\fR"
Configures how \fBovs\-vsctl\fR contacts \fBovs\-vswitchd\fR to
instruct it to reload its configuration file.
.IP
If \fItarget\fR begins with \fB/\fR it must name a Unix domain socket
on which \fBovs\-vswitchd\fR is listening for control channel
connections. By default, \fBovs\-vswitchd\fR listens on a Unix domain
socket named \fB@RUNDIR@/ovs\-vswitchd.\fIpid\fB.ctl\fR, where
\fIpid\fR is \fBovs\-vswitchd\fR's process ID.
.IP
Otherwise, \fBovs\-appctl\fR looks for a pidfile, that is, a file
whose contents are the process ID of a running process as a decimal
number, named \fB@RUNDIR@/\fItarget\fB.pid\fR. (The \fB\-\-pidfile\fR
option makes an Open vSwitch daemon create a pidfile.)
\fBovs\-appctl\fR reads the pidfile, then looks for a Unix socket
named \fB@RUNDIR@/\fItarget\fB.\fIpid\fB.ctl\fR, where \fIpid\fR is
replaced by the process ID read from \fItarget\fR, and uses that file
as if it had been specified directly as the target.
.IP
The default target is \fBovs\-vswitchd\fR.
.IP "\fB\-\-no\-reload\fR"
Prevents \fBovs\-vsctl\fR from telling \fBovs\-vswitchd\fR to reload
its configuration file.
. .
.IP "\fB\-\-no\-syslog\fR" .IP "\fB\-\-no\-syslog\fR"
By default, \fBovs\-vsctl\fR logs its arguments and the details of any By default, \fBovs\-vsctl\fR logs its arguments and the details of any
changes that it makes to the system log. This option disables this changes that it makes to the system log. This option disables this
logging. logging.
.IP
This option is equivalent to \fB\-\-verbose=vvsctl:syslog:warn\fR.
.
.IP "\fB\-\-oneline\fR" .IP "\fB\-\-oneline\fR"
Modifies the output format so that the output for each command is printed Modifies the output format so that the output for each command is printed
on a single line. New-line characters that would otherwise separate on a single line. New-line characters that would otherwise separate
@@ -101,6 +89,8 @@ lines are printed as \fB\\n\fR, and any instances of \fB\\\fR that
would otherwise appear in the output are doubled. would otherwise appear in the output are doubled.
Prints a blank line for each command that has no output. Prints a blank line for each command that has no output.
. .
.so lib/vlog.man
.
.SH COMMANDS .SH COMMANDS
The commands implemented by \fBovs\-vsctl\fR are described in the The commands implemented by \fBovs\-vsctl\fR are described in the
sections below. sections below.
@@ -203,5 +193,5 @@ The \fIbridge\fR argument to \fBbr\-exists\fR specified the name of a
bridge that does not exist. bridge that does not exist.
.SH "SEE ALSO" .SH "SEE ALSO"
. .
.BR ovs\-vswitchd.conf (5), .BR ovsdb\-server (1),
.BR ovs\-vswitchd (8). .BR ovs\-vswitchd (8).

View File

@@ -31,6 +31,7 @@
#include "dynamic-string.h" #include "dynamic-string.h"
#include "ovsdb-idl.h" #include "ovsdb-idl.h"
#include "poll-loop.h" #include "poll-loop.h"
#include "svec.h"
#include "vswitchd/vswitch-idl.h" #include "vswitchd/vswitch-idl.h"
#include "timeval.h" #include "timeval.h"
#include "util.h" #include "util.h"
@@ -48,6 +49,7 @@ static char *default_db(void);
static void usage(void) NO_RETURN; static void usage(void) NO_RETURN;
static void parse_options(int argc, char *argv[]); static void parse_options(int argc, char *argv[]);
static void check_vsctl_command(int argc, char *argv[]);
static void do_vsctl(int argc, char *argv[], struct ovsdb_idl *idl); static void do_vsctl(int argc, char *argv[], struct ovsdb_idl *idl);
int int
@@ -55,14 +57,43 @@ main(int argc, char *argv[])
{ {
struct ovsdb_idl *idl; struct ovsdb_idl *idl;
unsigned int seqno; unsigned int seqno;
struct ds args;
int start, n_commands;
int trials; int trials;
int i;
set_program_name(argv[0]); set_program_name(argv[0]);
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
time_init(); time_init();
vlog_init(); vlog_init();
vlog_set_levels(VLM_ANY_MODULE, VLF_CONSOLE, VLL_WARN);
vlog_set_levels(VLM_reconnect, VLF_ANY_FACILITY, VLL_WARN);
parse_options(argc, argv); parse_options(argc, argv);
/* Log our arguments. This is often valuable for debugging systems. */
ds_init(&args);
for (i = 1; i < argc; i++) {
ds_put_format(&args, " %s", argv[i]);
}
VLOG_INFO("Called as%s", ds_cstr(&args));
ds_destroy(&args);
/* Do basic command syntax checking. */
n_commands = 0;
for (start = i = optind; i <= argc; i++) {
if (i == argc || !strcmp(argv[i], "--")) {
if (i > start) {
check_vsctl_command(i - start, &argv[start]);
n_commands++;
}
start = i + 1;
}
}
if (!n_commands) {
ovs_fatal(0, "missing command name (use --help for help)");
}
/* Now execut the commands. */
idl = ovsdb_idl_create(db, &ovsrec_idl_class); idl = ovsdb_idl_create(db, &ovsrec_idl_class);
seqno = ovsdb_idl_get_seqno(idl); seqno = ovsdb_idl_get_seqno(idl);
trials = 0; trials = 0;
@@ -90,23 +121,22 @@ parse_options(int argc, char *argv[])
enum { enum {
OPT_DB = UCHAR_MAX + 1, OPT_DB = UCHAR_MAX + 1,
OPT_ONELINE, OPT_ONELINE,
OPT_NO_SYSLOG
}; };
static struct option long_options[] = { static struct option long_options[] = {
{"db", required_argument, 0, OPT_DB}, {"db", required_argument, 0, OPT_DB},
{"no-syslog", no_argument, 0, OPT_NO_SYSLOG},
{"oneline", no_argument, 0, OPT_ONELINE}, {"oneline", no_argument, 0, OPT_ONELINE},
{"verbose", optional_argument, 0, 'v'}, {"verbose", optional_argument, 0, 'v'},
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'}, {"version", no_argument, 0, 'V'},
{0, 0, 0, 0}, {0, 0, 0, 0},
}; };
char *short_options;
short_options = xasprintf ("+%s",
long_options_to_short_options(long_options));
for (;;) { for (;;) {
int c; int c;
c = getopt_long(argc, argv, short_options, long_options, NULL); c = getopt_long(argc, argv, "+v::hV", long_options, NULL);
if (c == -1) { if (c == -1) {
break; break;
} }
@@ -120,6 +150,10 @@ parse_options(int argc, char *argv[])
oneline = true; oneline = true;
break; break;
case OPT_NO_SYSLOG:
vlog_set_levels(VLM_vsctl, VLF_SYSLOG, VLL_WARN);
break;
case 'h': case 'h':
usage(); usage();
@@ -138,7 +172,6 @@ parse_options(int argc, char *argv[])
abort(); abort();
} }
} }
free(short_options);
if (!db) { if (!db) {
db = default_db(); db = default_db();
@@ -205,7 +238,7 @@ default_db(void)
{ {
static char *def; static char *def;
if (!def) { if (!def) {
def = xasprintf("%s/ovsdb-server", ovs_rundir); def = xasprintf("unix:%s/ovsdb-server", ovs_rundir);
} }
return def; return def;
} }
@@ -339,7 +372,7 @@ get_info(const struct ovsrec_open_vswitch *ovs, struct vsctl_info *info)
} }
if (port_is_fake_bridge(port_cfg) if (port_is_fake_bridge(port_cfg)
&& shash_add_once(&bridges, br_cfg->name, NULL)) { && shash_add_once(&bridges, port_cfg->name, NULL)) {
add_bridge(info, NULL, port_cfg->name, br, *port_cfg->tag); add_bridge(info, NULL, port_cfg->name, br, *port_cfg->tag);
} }
} }
@@ -368,7 +401,7 @@ get_info(const struct ovsrec_open_vswitch *ovs, struct vsctl_info *info)
} }
if (port_is_fake_bridge(port_cfg) if (port_is_fake_bridge(port_cfg)
&& !shash_add_once(&bridges, br_cfg->name, NULL)) { && !shash_add_once(&bridges, port_cfg->name, NULL)) {
continue; continue;
} }
@@ -398,6 +431,7 @@ get_info(const struct ovsrec_open_vswitch *ovs, struct vsctl_info *info)
iface = xmalloc(sizeof *iface); iface = xmalloc(sizeof *iface);
iface->iface_cfg = iface_cfg; iface->iface_cfg = iface_cfg;
iface->port = port; iface->port = port;
shash_add(&info->ifaces, iface_cfg->name, iface);
} }
} }
} }
@@ -455,7 +489,7 @@ static struct vsctl_iface *
find_iface(struct vsctl_info *info, const char *name) find_iface(struct vsctl_info *info, const char *name)
{ {
struct vsctl_iface *iface = shash_find_data(&info->ifaces, name); struct vsctl_iface *iface = shash_find_data(&info->ifaces, name);
if (!iface) { if (!iface || !strcmp(name, iface->port->bridge->name)) {
ovs_fatal(0, "no interface named %s", name); ovs_fatal(0, "no interface named %s", name);
} }
return iface; return iface;
@@ -471,7 +505,6 @@ bridge_insert_port(struct ovsrec_bridge *br, struct ovsrec_port *port)
for (i = 0; i < br->n_ports; i++) { for (i = 0; i < br->n_ports; i++) {
ports[i] = br->ports[i]; ports[i] = br->ports[i];
} }
printf("bridge has %zu ports, adding 1\n", br->n_ports);
ports[br->n_ports] = port; ports[br->n_ports] = port;
ovsrec_bridge_set_ports(br, ports, br->n_ports + 1); ovsrec_bridge_set_ports(br, ports, br->n_ports + 1);
free(ports); free(ports);
@@ -556,7 +589,7 @@ cmd_add_br(int argc, char *argv[], const struct ovsrec_open_vswitch *ovs,
ovs_insert_bridge(ovs, br); ovs_insert_bridge(ovs, br);
} else if (argc == 3) { } else if (argc == 3) {
ovs_fatal(0, "'%s' comamnd takes exactly 1 or 3 arguments", argv[0]); ovs_fatal(0, "'%s' comamnd takes exactly 1 or 3 arguments", argv[0]);
} else if (argc >= 4) { } else if (argc == 4) {
const char *parent_name = argv[2]; const char *parent_name = argv[2];
int vlan = atoi(argv[3]); int vlan = atoi(argv[3]);
struct ovsrec_bridge *br; struct ovsrec_bridge *br;
@@ -587,6 +620,8 @@ cmd_add_br(int argc, char *argv[], const struct ovsrec_open_vswitch *ovs,
ovsrec_port_set_interfaces(port, &iface, 1); ovsrec_port_set_interfaces(port, &iface, 1);
ovsrec_port_set_fake_bridge(port, true); ovsrec_port_set_fake_bridge(port, true);
ovsrec_port_set_tag(port, &tag, 1); ovsrec_port_set_tag(port, &tag, 1);
bridge_insert_port(br, port);
} else { } else {
NOT_REACHED(); NOT_REACHED();
} }
@@ -624,7 +659,8 @@ cmd_del_br(int argc UNUSED, char *argv[],
bridge = find_bridge(&info, argv[1]); bridge = find_bridge(&info, argv[1]);
SHASH_FOR_EACH (node, &info.ports) { SHASH_FOR_EACH (node, &info.ports) {
struct vsctl_port *port = node->data; struct vsctl_port *port = node->data;
if (port->bridge == bridge) { if (port->bridge == bridge
|| !strcmp(port->port_cfg->name, bridge->name)) {
del_port(&info, port); del_port(&info, port);
} }
} }
@@ -635,18 +671,36 @@ cmd_del_br(int argc UNUSED, char *argv[],
free_info(&info); free_info(&info);
} }
static void
output_sorted(struct svec *svec, struct ds *output)
{
const char *name;
size_t i;
svec_sort(svec);
SVEC_FOR_EACH (i, name, svec) {
ds_put_format(output, "%s\n", name);
}
}
static void static void
cmd_list_br(int argc UNUSED, char *argv[] UNUSED, cmd_list_br(int argc UNUSED, char *argv[] UNUSED,
const struct ovsrec_open_vswitch *ovs, struct ds *output) const struct ovsrec_open_vswitch *ovs, struct ds *output)
{ {
struct shash_node *node; struct shash_node *node;
struct vsctl_info info; struct vsctl_info info;
struct svec bridges;
get_info(ovs, &info); get_info(ovs, &info);
svec_init(&bridges);
SHASH_FOR_EACH (node, &info.bridges) { SHASH_FOR_EACH (node, &info.bridges) {
struct vsctl_bridge *br = node->data; struct vsctl_bridge *br = node->data;
ds_put_format(output, "%s\n", br->name); svec_add(&bridges, br->name);
} }
output_sorted(&bridges, output);
svec_destroy(&bridges);
free_info(&info); free_info(&info);
} }
@@ -670,16 +724,22 @@ cmd_list_ports(int argc UNUSED, char *argv[],
struct vsctl_bridge *br; struct vsctl_bridge *br;
struct shash_node *node; struct shash_node *node;
struct vsctl_info info; struct vsctl_info info;
struct svec ports;
get_info(ovs, &info); get_info(ovs, &info);
br = find_bridge(&info, argv[1]); br = find_bridge(&info, argv[1]);
svec_init(&ports);
SHASH_FOR_EACH (node, &info.ports) { SHASH_FOR_EACH (node, &info.ports) {
struct vsctl_port *port = node->data; struct vsctl_port *port = node->data;
if (strcmp(port->port_cfg->name, br->name) && br == port->bridge) { if (strcmp(port->port_cfg->name, br->name) && br == port->bridge) {
ds_put_format(output, "%s\n", port->port_cfg->name); svec_add(&ports, port->port_cfg->name);
} }
} }
output_sorted(&ports, output);
svec_destroy(&ports);
free_info(&info); free_info(&info);
} }
@@ -811,16 +871,23 @@ cmd_list_ifaces(int argc UNUSED, char *argv[],
struct vsctl_bridge *br; struct vsctl_bridge *br;
struct shash_node *node; struct shash_node *node;
struct vsctl_info info; struct vsctl_info info;
struct svec ifaces;
get_info(ovs, &info); get_info(ovs, &info);
br = find_bridge(&info, argv[1]); br = find_bridge(&info, argv[1]);
svec_init(&ifaces);
SHASH_FOR_EACH (node, &info.ifaces) { SHASH_FOR_EACH (node, &info.ifaces) {
struct vsctl_iface *iface = node->data; struct vsctl_iface *iface = node->data;
if (br == iface->port->bridge) { if (strcmp(iface->iface_cfg->name, br->name)
ds_put_format(output, "%s\n", iface->iface_cfg->name); && br == iface->port->bridge) {
svec_add(&ifaces, iface->iface_cfg->name);
} }
} }
output_sorted(&ifaces, output);
svec_destroy(&ifaces);
free_info(&info); free_info(&info);
} }
@@ -837,12 +904,15 @@ cmd_iface_to_br(int argc UNUSED, char *argv[],
free_info(&info); free_info(&info);
} }
typedef void vsctl_handler_func(int argc, char *argv[],
const struct ovsrec_open_vswitch *,
struct ds *output);
struct vsctl_command { struct vsctl_command {
const char *name; const char *name;
int min_args; int min_args;
int max_args; int max_args;
void (*handler)(int argc, char *argv[], vsctl_handler_func *handler;
const struct ovsrec_open_vswitch *ovs, struct ds *output);
}; };
static void run_vsctl_command(int argc, char *argv[], static void run_vsctl_command(int argc, char *argv[],
@@ -870,8 +940,8 @@ do_vsctl(int argc, char *argv[], struct ovsdb_idl *idl)
txn = ovsdb_idl_txn_create(idl); txn = ovsdb_idl_txn_create(idl);
output = xmalloc(argc * sizeof *output); output = xmalloc(argc * sizeof *output);
n_output = 0; n_output = 0;
for (start = i = 0; i < argc; i++) { for (start = i = 0; i <= argc; i++) {
if (!strcmp(argv[i], "--")) { if (i == argc || !strcmp(argv[i], "--")) {
if (i > start) { if (i > start) {
ds_init(&output[n_output]); ds_init(&output[n_output]);
run_vsctl_command(i - start, &argv[start], ovs, run_vsctl_command(i - start, &argv[start], ovs,
@@ -880,10 +950,6 @@ do_vsctl(int argc, char *argv[], struct ovsdb_idl *idl)
start = i + 1; start = i + 1;
} }
} }
if (i > start) {
ds_init(&output[n_output]);
run_vsctl_command(i - start, &argv[start], ovs, &output[n_output++]);
}
while ((status = ovsdb_idl_txn_commit(txn)) == TXN_INCOMPLETE) { while ((status = ovsdb_idl_txn_commit(txn)) == TXN_INCOMPLETE) {
ovsdb_idl_run(idl); ovsdb_idl_run(idl);
@@ -945,9 +1011,8 @@ do_vsctl(int argc, char *argv[], struct ovsdb_idl *idl)
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
static void static vsctl_handler_func *
run_vsctl_command(int argc, char *argv[], get_vsctl_handler(int argc, char *argv[])
const struct ovsrec_open_vswitch *ovs, struct ds *output)
{ {
static const struct vsctl_command all_commands[] = { static const struct vsctl_command all_commands[] = {
{"add-br", 1, 3, cmd_add_br}, {"add-br", 1, 3, cmd_add_br},
@@ -968,7 +1033,7 @@ run_vsctl_command(int argc, char *argv[],
const struct vsctl_command *p; const struct vsctl_command *p;
assert(argc > 0); assert(argc > 0);
for (p = all_commands; p->name != NULL; p++) { for (p = all_commands; p < &all_commands[ARRAY_SIZE(all_commands)]; p++) {
if (!strcmp(p->name, argv[0])) { if (!strcmp(p->name, argv[0])) {
int n_arg = argc - 1; int n_arg = argc - 1;
if (n_arg < p->min_args) { if (n_arg < p->min_args) {
@@ -978,11 +1043,23 @@ run_vsctl_command(int argc, char *argv[],
ovs_fatal(0, "'%s' command takes at most %d arguments", ovs_fatal(0, "'%s' command takes at most %d arguments",
p->name, p->max_args); p->name, p->max_args);
} else { } else {
p->handler(argc, argv, ovs, output); return p->handler;
return;
} }
} }
} }
ovs_fatal(0, "unknown command '%s'; use --help for help", argv[0]); ovs_fatal(0, "unknown command '%s'; use --help for help", argv[0]);
} }
static void
check_vsctl_command(int argc, char *argv[])
{
get_vsctl_handler(argc, argv);
}
static void
run_vsctl_command(int argc, char *argv[],
const struct ovsrec_open_vswitch *ovs, struct ds *output)
{
get_vsctl_handler(argc, argv)(argc, argv, ovs, output);
}