[ovs-dev] [brcompatd 8/8] ovs-brcompatd: Run ovs-vsctl instead of accessing database directly.

Ethan Jackson ethan at nicira.com
Wed Jun 8 01:22:03 UTC 2011


The patch seems fine.  I had one thought which may or may not be valuable.

In reading send_ifindex_reply() and get_bridge_intefaces() I thought
that it might be valuable to implement a function which converts a "
\t\r\n" delimited string to a sset.  Then send_ifindex_reply() could
take a sset and would be a bit cleaner.  Seems like it would be useful
in several places.

Ethan

On Mon, Jun 6, 2011 at 12:41, Ben Pfaff <blp at nicira.com> wrote:
> ovs-vsctl is carefully written to avoid races in database access.  It is
> much simpler to just call it than to reimplement its capabilities.
>
> This eliminates the requirement that bridges managed by ovs-brcompatd have
> no ports at ovs-brcompatd startup time.  It also eliminates races between
> competing brctl and ovs-vsctl processes.
> ---
>  vswitchd/ovs-brcompatd.8.in |   46 +--
>  vswitchd/ovs-brcompatd.c    |  916 +++++++++++--------------------------------
>  2 files changed, 250 insertions(+), 712 deletions(-)
>
> diff --git a/vswitchd/ovs-brcompatd.8.in b/vswitchd/ovs-brcompatd.8.in
> index 692ac67..fb3548e 100644
> --- a/vswitchd/ovs-brcompatd.8.in
> +++ b/vswitchd/ovs-brcompatd.8.in
> @@ -6,7 +6,7 @@ ovs\-brcompatd \- Bridge compatibility front-end for ovs\-vswitchd
>  .
>  .SH SYNOPSIS
>  .B ovs\-brcompatd
> -[\fIoptions\fR] \fIdatabase\fR
> +[\fIoptions\fR]
>  .
>  .SH DESCRIPTION
>  A daemon that provides a legacy bridge front-end for \fBovs\-vswitchd\fR.  It
> @@ -14,48 +14,32 @@ does this by listening for bridge ioctl commands (e.g., those generated by
>  the \fBbrctl\fR program) to add or remove datapaths and the interfaces
>  that attach to them.
>  .PP
> -The mandatory \fIdatabase\fR argument specifies the
> -\fBovsdb\-server\fR from which \fBovs\-vswitchd\fR's configuration is
> -retrieved.  It should take the form \fBunix:\fIfile\fR, to connect to
> -the Unix domain server socket named \fIfile\fR.
> -.PP
>  .SH OPTIONS
> -.IP "\fB\-\-appctl\-command=\fIcommand\fR"
> -Sets the command that \fBovs\-brcompatd\fR runs to communicate with
> -\fBovs\-vswitchd\fR.  The command is run in \fB/bin/sh\fR as a shell
> -command, so \fIcommand\fR may contain arbitrary shell metacharacters,
> -etc.  The \fB\-\-help\fR option displays the default command.
> -.IP
> -\fIcommand\fR must contain exactly one instance of \fB%s\fR, which
> -\fBovs\-brcompatd\fR replaces by a command from the set understood by
> -\fBovs\-vswitchd\fR.  Any instances of \fB%%\fR in \fIcommand\fR are
> -replaced by a single \fB%\fR.  The \fB%\fR character may not otherwise
> -appear in \fIcommand\fR.
> -.IP
> -The commands that are substituted into \fIcommand\fR are those that
> -can be listed by passing \fBhelp\fR to \fBovs\-appctl\fR with
> -\fBovs\-vswitchd\fR as target.
> -.IP
> -\fIcommand\fR must not redirect \fBovs\-appctl\fR's standard output or
> -standard error streams, because \fBovs\-brcompatd\fR expects to read
> -both of these streams separately.
> +.IP "\fB\-\-appctl=\fIprogram\fR"
> +Sets the name to the program that \fBovs\-brcompatd\fR runs to
> +communicate with \fBovs\-vswitchd\fR.  The default is
> +\fBovs\-appctl\fR.  Unless \fIprogram\fR contains \fB/\fR,
> +\fBovs\-brcompatd\fR will search the \fBPATH\fR environment variable
> +to find it.
> +.
> +.IP "\fB\-\-vsctl=\fIprogram\fR"
> +Sets the name to the program that \fBovs\-brcompatd\fR runs to
> +communicate with \fBovsdb\-server\fR.  The default is
> +\fBovs\-vsctl\fR.  Unless \fIprogram\fR contains \fB/\fR,
> +\fBovs\-brcompatd\fR will search the \fBPATH\fR environment variable
> +to find it.
>  .
>  .so lib/daemon.man
>  .so lib/vlog.man
>  .so lib/common.man
>  .so lib/leak-checker.man
>  .
> -.SH BUGS
> -.
> -\fBovs\-brcompatd\fR requires the bridges that it manages to initially
> -have no ports listed in their database records when it starts up.
> -Otherwise, it may add duplicate ports to bridges.
> -.
>  .SH NOTES
>  \fBovs\-brcompatd\fR requires the \fBbrcompat_mod.ko\fR kernel module to be
>  loaded.
>  .SH "SEE ALSO"
>  .BR ovs\-appctl (8),
> +.BR ovs\-vsctl (8),
>  .BR ovs\-vswitchd (8),
>  .BR ovsdb\-server (1),
>  \fBINSTALL.bridge\fR in the Open vSwitch distribution.
> diff --git a/vswitchd/ovs-brcompatd.c b/vswitchd/ovs-brcompatd.c
> index 458aead..4f35452 100644
> --- a/vswitchd/ovs-brcompatd.c
> +++ b/vswitchd/ovs-brcompatd.c
> @@ -46,7 +46,6 @@
>  #include "netlink-socket.h"
>  #include "ofpbuf.h"
>  #include "openvswitch/brcompat-netlink.h"
> -#include "ovsdb-idl.h"
>  #include "packets.h"
>  #include "poll-loop.h"
>  #include "process.h"
> @@ -54,34 +53,29 @@
>  #include "rtnetlink-link.h"
>  #include "signals.h"
>  #include "sset.h"
> +#include "svec.h"
>  #include "timeval.h"
>  #include "unixctl.h"
>  #include "util.h"
>  #include "vlog.h"
> -#include "vswitchd/vswitch-idl.h"
>
>  VLOG_DEFINE_THIS_MODULE(brcompatd);
>
> -
>  /* xxx Just hangs if datapath is rmmod/insmod.  Learn to reconnect? */
>
> -/* Actions to modify bridge compatibility configuration. */
> -enum bmc_action {
> -    BMC_ADD_DP,
> -    BMC_DEL_DP,
> -    BMC_ADD_PORT,
> -    BMC_DEL_PORT
> -};
> -
> -static const char *parse_options(int argc, char *argv[]);
> +static void parse_options(int argc, char *argv[]);
>  static void usage(void) NO_RETURN;
>
>  static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 60);
>
> -/* Shell command to execute (via popen()) to send a control command to the
> - * running ovs-vswitchd process.  The string must contain one instance of %s,
> - * which is replaced by the control command. */
> -static char *appctl_command;
> +/* --appctl: Absolute path to ovs-appctl. */
> +static char *appctl_program;
> +
> +/* --vsctl: Absolute path to ovs-vsctl. */
> +static char *vsctl_program;
> +
> +/* Options that we should generally pass to ovs-vsctl. */
> +#define VSCTL_OPTIONS "--timeout=5", "-vANY:console:WARN"
>
>  /* Netlink socket to bridge compatibility kernel module. */
>  static struct nl_sock *brc_sock;
> @@ -93,6 +87,91 @@ static const struct nl_policy brc_multicast_policy[] = {
>     [BRC_GENL_A_MC_GROUP] = {.type = NL_A_U32 }
>  };
>
> +static char *
> +capture_vsctl_valist(const char *arg0, va_list args)
> +{
> +    char *stdout_log, *stderr_log;
> +    enum vlog_level log_level;
> +    struct svec argv;
> +    int status;
> +    char *msg;
> +
> +    /* Compose arguments. */
> +    svec_init(&argv);
> +    svec_add(&argv, arg0);
> +    for (;;) {
> +        const char *arg = va_arg(args, const char *);
> +        if (!arg) {
> +            break;
> +        }
> +        svec_add(&argv, arg);
> +    }
> +    svec_terminate(&argv);
> +
> +    /* Run process. */
> +    if (process_run_capture(argv.names, &stdout_log, &stderr_log, SIZE_MAX,
> +                            &status)) {
> +        svec_destroy(&argv);
> +        return NULL;
> +    }
> +
> +    /* Log results. */
> +    if (WIFEXITED(status)) {
> +        int code = WEXITSTATUS(status);
> +        log_level = code == 0 ? VLL_DBG : code == 1 ? VLL_WARN : VLL_ERR;
> +    } else {
> +        log_level = VLL_ERR;
> +    }
> +    msg = process_status_msg(status);
> +    VLOG(log_level, "ovs-vsctl exited (%s)", msg);
> +    if (stdout_log && *stdout_log) {
> +        VLOG(log_level, "ovs-vsctl wrote to stdout:\n%s\n", stdout_log);
> +    }
> +    if (stderr_log && *stderr_log) {
> +        VLOG(log_level, "ovs-vsctl wrote to stderr:\n%s\n", stderr_log);
> +    }
> +    free(msg);
> +
> +    svec_destroy(&argv);
> +
> +    free(stderr_log);
> +    if (WIFEXITED(status) && !WEXITSTATUS(status)) {
> +        return stdout_log;
> +    } else {
> +        free(stdout_log);
> +        return NULL;
> +    }
> +}
> +
> +static char * SENTINEL(0)
> +capture_vsctl(const char *arg0, ...)
> +{
> +    char *stdout_log;
> +    va_list args;
> +
> +    va_start(args, arg0);
> +    stdout_log = capture_vsctl_valist(arg0, args);
> +    va_end(args);
> +
> +    return stdout_log;
> +}
> +
> +static bool SENTINEL(0)
> +run_vsctl(const char *arg0, ...)
> +{
> +    char *stdout_log;
> +    va_list args;
> +    bool ok;
> +
> +    va_start(args, arg0);
> +    stdout_log = capture_vsctl_valist(arg0, args);
> +    va_end(args);
> +
> +    ok = stdout_log != NULL;
> +    free(stdout_log);
> +    return ok;
> +}
> +
>  static int
>  lookup_brc_multicast_group(int *multicast_group)
>  {
> @@ -163,425 +242,6 @@ static const struct nl_policy brc_dp_policy[] = {
>     [BRC_GENL_A_DP_NAME] = { .type = NL_A_STRING },
>  };
>
> -static struct ovsrec_bridge *
> -find_bridge(const struct ovsrec_open_vswitch *ovs, const char *br_name)
> -{
> -    size_t i;
> -
> -    for (i = 0; i < ovs->n_bridges; i++) {
> -        if (!strcmp(br_name, ovs->bridges[i]->name)) {
> -            return ovs->bridges[i];
> -        }
> -    }
> -
> -    return NULL;
> -}
> -
> -static int
> -execute_appctl_command(const char *unixctl_command, char **output)
> -{
> -    char *stdout_log, *stderr_log;
> -    int error, status;
> -    char *argv[5];
> -
> -    argv[0] = "/bin/sh";
> -    argv[1] = "-c";
> -    argv[2] = xasprintf(appctl_command, unixctl_command);
> -    argv[3] = NULL;
> -
> -    /* Run process and log status. */
> -    error = process_run_capture(argv, &stdout_log, &stderr_log, 65536,
> -                                &status);
> -    if (error) {
> -        VLOG_ERR("failed to execute %s command via ovs-appctl: %s",
> -                 unixctl_command, strerror(error));
> -    } else if (status) {
> -        char *msg = process_status_msg(status);
> -        VLOG_ERR("ovs-appctl exited with error (%s)", msg);
> -        free(msg);
> -        error = ECHILD;
> -    }
> -
> -    /* Deal with stdout_log. */
> -    if (output) {
> -        *output = stdout_log;
> -    } else {
> -        free(stdout_log);
> -    }
> -
> -    /* Deal with stderr_log */
> -    if (stderr_log && *stderr_log) {
> -        VLOG_INFO("ovs-appctl wrote to stderr:\n%s", stderr_log);
> -    }
> -    free(stderr_log);
> -
> -    free(argv[2]);
> -
> -    return error;
> -}
> -
> -static void
> -do_get_bridge_parts(const struct ovsrec_bridge *br, struct sset *parts,
> -                    int vlan, bool break_down_bonds)
> -{
> -    size_t i, j;
> -
> -    for (i = 0; i < br->n_ports; i++) {
> -        const struct ovsrec_port *port = br->ports[i];
> -
> -        if (vlan >= 0) {
> -            int port_vlan = port->n_tag ? *port->tag : 0;
> -            if (vlan != port_vlan) {
> -                continue;
> -            }
> -        }
> -        if (break_down_bonds) {
> -            for (j = 0; j < port->n_interfaces; j++) {
> -                const struct ovsrec_interface *iface = port->interfaces[j];
> -                sset_add(parts, iface->name);
> -            }
> -        } else {
> -            sset_add(parts, port->name);
> -        }
> -    }
> -}
> -
> -/* Add all the interfaces for 'bridge' to 'ifaces', breaking bonded interfaces
> - * down into their constituent parts.
> - *
> - * If 'vlan' < 0, all interfaces on 'bridge' are reported.  If 'vlan' == 0,
> - * then only interfaces for trunk ports or ports with implicit VLAN 0 are
> - * reported.  If 'vlan' > 0, only interfaces with implicit VLAN 'vlan' are
> - * reported.  */
> -static void
> -get_bridge_ifaces(const struct ovsrec_bridge *br, struct sset *ifaces,
> -                  int vlan)
> -{
> -    do_get_bridge_parts(br, ifaces, vlan, true);
> -}
> -
> -/* Add all the ports for 'bridge' to 'ports'.  Bonded ports are reported under
> - * the bond name, not broken down into their constituent interfaces.
> - *
> - * If 'vlan' < 0, all ports on 'bridge' are reported.  If 'vlan' == 0, then
> - * only trunk ports or ports with implicit VLAN 0 are reported.  If 'vlan' > 0,
> - * only port with implicit VLAN 'vlan' are reported.  */
> -static void
> -get_bridge_ports(const struct ovsrec_bridge *br, struct sset *ports,
> -                 int vlan)
> -{
> -    do_get_bridge_parts(br, ports, vlan, false);
> -}
> -
> -static struct ovsdb_idl_txn *
> -txn_from_openvswitch(const struct ovsrec_open_vswitch *ovs)
> -{
> -    return ovsdb_idl_txn_get(&ovs->header_);
> -}
> -
> -static bool
> -port_is_fake_bridge(const struct ovsrec_port *port)
> -{
> -    return (port->fake_bridge
> -            && port->tag
> -            && *port->tag >= 1 && *port->tag <= 4095);
> -}
> -
> -static void
> -ovs_insert_bridge(const struct ovsrec_open_vswitch *ovs,
> -                  struct ovsrec_bridge *bridge)
> -{
> -    struct ovsrec_bridge **bridges;
> -    size_t i;
> -
> -    bridges = xmalloc(sizeof *ovs->bridges * (ovs->n_bridges + 1));
> -    for (i = 0; i < ovs->n_bridges; i++) {
> -        bridges[i] = ovs->bridges[i];
> -    }
> -    bridges[ovs->n_bridges] = bridge;
> -    ovsrec_open_vswitch_set_bridges(ovs, bridges, ovs->n_bridges + 1);
> -    free(bridges);
> -}
> -
> -static struct json *
> -where_uuid_equals(const struct uuid *uuid)
> -{
> -    return
> -        json_array_create_1(
> -            json_array_create_3(
> -                json_string_create("_uuid"),
> -                json_string_create("=="),
> -                json_array_create_2(
> -                    json_string_create("uuid"),
> -                    json_string_create_nocopy(
> -                        xasprintf(UUID_FMT, UUID_ARGS(uuid))))));
> -}
> -
> -/* Commits 'txn'.  If 'wait_for_reload' is true, also waits for Open vSwitch to
> -   reload the configuration before returning.
> -
> -   Returns EAGAIN if the caller should try the operation again, 0 on success,
> -   otherwise a positive errno value. */
> -static int
> -commit_txn(struct ovsdb_idl_txn *txn, bool wait_for_reload)
> -{
> -    struct ovsdb_idl *idl = ovsdb_idl_txn_get_idl (txn);
> -    enum ovsdb_idl_txn_status status;
> -    int64_t next_cfg = 0;
> -
> -    if (wait_for_reload) {
> -        const struct ovsrec_open_vswitch *ovs = ovsrec_open_vswitch_first(idl);
> -        struct json *where = where_uuid_equals(&ovs->header_.uuid);
> -        ovsdb_idl_txn_increment(txn, "Open_vSwitch", "next_cfg", where);
> -        json_destroy(where);
> -    }
> -    status = ovsdb_idl_txn_commit_block(txn);
> -    if (wait_for_reload && status == TXN_SUCCESS) {
> -        next_cfg = ovsdb_idl_txn_get_increment_new_value(txn);
> -    }
> -    ovsdb_idl_txn_destroy(txn);
> -
> -    switch (status) {
> -    case TXN_INCOMPLETE:
> -        NOT_REACHED();
> -
> -    case TXN_ABORTED:
> -        VLOG_ERR_RL(&rl, "OVSDB transaction unexpectedly aborted");
> -        return ECONNABORTED;
> -
> -    case TXN_UNCHANGED:
> -        return 0;
> -
> -    case TXN_SUCCESS:
> -        if (wait_for_reload) {
> -            for (;;) {
> -                /* We can't use 'ovs' any longer because ovsdb_idl_run() can
> -                 * destroy it. */
> -                const struct ovsrec_open_vswitch *ovs2;
> -
> -                ovsdb_idl_run(idl);
> -                OVSREC_OPEN_VSWITCH_FOR_EACH (ovs2, idl) {
> -                    if (ovs2->cur_cfg >= next_cfg) {
> -                        goto done;
> -                    }
> -                }
> -                ovsdb_idl_wait(idl);
> -                poll_block();
> -            }
> -        done: ;
> -        }
> -        return 0;
> -
> -    case TXN_TRY_AGAIN:
> -        VLOG_ERR_RL(&rl, "OVSDB transaction needs retry");
> -        return EAGAIN;
> -
> -    case TXN_ERROR:
> -        VLOG_ERR_RL(&rl, "OVSDB transaction failed: %s",
> -                    ovsdb_idl_txn_get_error(txn));
> -        return EBUSY;
> -
> -    default:
> -        NOT_REACHED();
> -    }
> -}
> -
> -static int
> -add_bridge(struct ovsdb_idl *idl, const struct ovsrec_open_vswitch *ovs,
> -           const char *br_name)
> -{
> -    struct ovsrec_bridge *br;
> -    struct ovsrec_port *port;
> -    struct ovsrec_interface *iface;
> -    struct ovsdb_idl_txn *txn;
> -
> -    if (find_bridge(ovs, br_name)) {
> -        VLOG_WARN("addbr %s: bridge %s exists", br_name, br_name);
> -        return EEXIST;
> -    } else if (netdev_exists(br_name)) {
> -        size_t i;
> -
> -        for (i = 0; i < ovs->n_bridges; i++) {
> -            size_t j;
> -            struct ovsrec_bridge *br_cfg = ovs->bridges[i];
> -
> -            for (j = 0; j < br_cfg->n_ports; j++) {
> -                if (port_is_fake_bridge(br_cfg->ports[j])) {
> -                    VLOG_WARN("addbr %s: %s exists as a fake bridge",
> -                              br_name, br_name);
> -                    return 0;
> -                }
> -            }
> -        }
> -
> -        VLOG_WARN("addbr %s: cannot create bridge %s because a network "
> -                  "device named %s already exists",
> -                  br_name, br_name, br_name);
> -        return EEXIST;
> -    }
> -
> -    txn = ovsdb_idl_txn_create(idl);
> -
> -    ovsdb_idl_txn_add_comment(txn, "ovs-brcompatd: addbr %s", br_name);
> -
> -    iface = ovsrec_interface_insert(txn_from_openvswitch(ovs));
> -    ovsrec_interface_set_name(iface, br_name);
> -
> -    port = ovsrec_port_insert(txn_from_openvswitch(ovs));
> -    ovsrec_port_set_name(port, br_name);
> -    ovsrec_port_set_interfaces(port, &iface, 1);
> -
> -    br = ovsrec_bridge_insert(txn_from_openvswitch(ovs));
> -    ovsrec_bridge_set_name(br, br_name);
> -    ovsrec_bridge_set_ports(br, &port, 1);
> -
> -    ovs_insert_bridge(ovs, br);
> -
> -    return commit_txn(txn, true);
> -}
> -
> -static void
> -add_port(const struct ovsrec_open_vswitch *ovs,
> -         const struct ovsrec_bridge *br, const char *port_name)
> -{
> -    struct ovsrec_interface *iface;
> -    struct ovsrec_port *port;
> -    struct ovsrec_port **ports;
> -    size_t i;
> -
> -    /* xxx Check conflicts? */
> -    iface = ovsrec_interface_insert(txn_from_openvswitch(ovs));
> -    ovsrec_interface_set_name(iface, port_name);
> -
> -    port = ovsrec_port_insert(txn_from_openvswitch(ovs));
> -    ovsrec_port_set_name(port, port_name);
> -    ovsrec_port_set_interfaces(port, &iface, 1);
> -
> -    ports = xmalloc(sizeof *br->ports * (br->n_ports + 1));
> -    for (i = 0; i < br->n_ports; i++) {
> -        ports[i] = br->ports[i];
> -    }
> -    ports[br->n_ports] = port;
> -    ovsrec_bridge_set_ports(br, ports, br->n_ports + 1);
> -    free(ports);
> -}
> -
> -/* Deletes 'port' from 'br'.
> - *
> - * After calling this function, 'port' must not be referenced again. */
> -static void
> -del_port(const struct ovsrec_bridge *br, const struct ovsrec_port *port)
> -{
> -    struct ovsrec_port **ports;
> -    size_t i, n;
> -
> -    /* Remove 'port' from the bridge's list of ports. */
> -    ports = xmalloc(sizeof *br->ports * br->n_ports);
> -    for (i = n = 0; i < br->n_ports; i++) {
> -        if (br->ports[i] != port) {
> -            ports[n++] = br->ports[i];
> -        }
> -    }
> -    ovsrec_bridge_set_ports(br, ports, n);
> -    free(ports);
> -}
> -
> -/* Delete 'iface' from 'port' (which must be within 'br').  If 'iface' was
> - * 'port''s only interface, delete 'port' from 'br' also.
> - *
> - * After calling this function, 'iface' must not be referenced again. */
> -static void
> -del_interface(const struct ovsrec_bridge *br,
> -              const struct ovsrec_port *port,
> -              const struct ovsrec_interface *iface)
> -{
> -    if (port->n_interfaces == 1) {
> -        del_port(br, port);
> -    } else {
> -        struct ovsrec_interface **ifaces;
> -        size_t i, n;
> -
> -        ifaces = xmalloc(sizeof *port->interfaces * port->n_interfaces);
> -        for (i = n = 0; i < port->n_interfaces; i++) {
> -            if (port->interfaces[i] != iface) {
> -                ifaces[n++] = port->interfaces[i];
> -            }
> -        }
> -        ovsrec_port_set_interfaces(port, ifaces, n);
> -        free(ifaces);
> -    }
> -}
> -
> -/* Find and return a port within 'br' named 'port_name'. */
> -static const struct ovsrec_port *
> -find_port(const struct ovsrec_bridge *br, const char *port_name)
> -{
> -    size_t i;
> -
> -    for (i = 0; i < br->n_ports; i++) {
> -        struct ovsrec_port *port = br->ports[i];
> -        if (!strcmp(port_name, port->name)) {
> -            return port;
> -        }
> -    }
> -    return NULL;
> -}
> -
> -/* Find and return an interface within 'br' named 'iface_name'. */
> -static const struct ovsrec_interface *
> -find_interface(const struct ovsrec_bridge *br, const char *iface_name,
> -               struct ovsrec_port **portp)
> -{
> -    size_t i;
> -
> -    for (i = 0; i < br->n_ports; i++) {
> -        struct ovsrec_port *port = br->ports[i];
> -        size_t j;
> -
> -        for (j = 0; j < port->n_interfaces; j++) {
> -            struct ovsrec_interface *iface = port->interfaces[j];
> -            if (!strcmp(iface->name, iface_name)) {
> -                *portp = port;
> -                return iface;
> -            }
> -        }
> -    }
> -
> -    *portp = NULL;
> -    return NULL;
> -}
> -
> -static int
> -del_bridge(struct ovsdb_idl *idl,
> -           const struct ovsrec_open_vswitch *ovs, const char *br_name)
> -{
> -    struct ovsrec_bridge *br = find_bridge(ovs, br_name);
> -    struct ovsrec_bridge **bridges;
> -    struct ovsdb_idl_txn *txn;
> -    size_t i, n;
> -
> -    if (!br) {
> -        VLOG_WARN("delbr %s: no bridge named %s", br_name, br_name);
> -        return ENXIO;
> -    }
> -
> -    txn = ovsdb_idl_txn_create(idl);
> -
> -    ovsdb_idl_txn_add_comment(txn, "ovs-brcompatd: delbr %s", br_name);
> -
> -    /* Remove 'br' from the vswitch's list of bridges. */
> -    bridges = xmalloc(sizeof *ovs->bridges * ovs->n_bridges);
> -    for (i = n = 0; i < ovs->n_bridges; i++) {
> -        if (ovs->bridges[i] != br) {
> -            bridges[n++] = ovs->bridges[i];
> -        }
> -    }
> -    ovsrec_open_vswitch_set_bridges(ovs, bridges, n);
> -    free(bridges);
> -
> -    return commit_txn(txn, true);
> -}
> -
>  static int
>  parse_command(struct ofpbuf *buffer, uint32_t *seq, const char **br_name,
>               const char **port_name, uint64_t *count, uint64_t *skip)
> @@ -654,9 +314,7 @@ send_simple_reply(uint32_t seq, int error)
>  }
>
>  static int
> -handle_bridge_cmd(struct ovsdb_idl *idl,
> -                  const struct ovsrec_open_vswitch *ovs,
> -                  struct ofpbuf *buffer, bool add)
> +handle_bridge_cmd(struct ofpbuf *buffer, bool add)
>  {
>     const char *br_name;
>     uint32_t seq;
> @@ -664,14 +322,14 @@ handle_bridge_cmd(struct ovsdb_idl *idl,
>
>     error = parse_command(buffer, &seq, &br_name, NULL, NULL, NULL);
>     if (!error) {
> -        int retval;
> -
> -        do {
> -            retval = (add ? add_bridge : del_bridge)(idl, ovs, br_name);
> -            VLOG_INFO_RL(&rl, "%sbr %s: %s",
> -                         add ? "add" : "del", br_name, strerror(retval));
> -        } while (retval == EAGAIN);
> -
> +        const char *vsctl_cmd = add ? "add-br" : "del-br";
> +        const char *brctl_cmd = add ? "addbr" : "delbr";
> +        if (!run_vsctl(vsctl_program, VSCTL_OPTIONS,
> +                       "--", vsctl_cmd, br_name,
> +                       "--", "comment", "ovs-brcompatd:", brctl_cmd, br_name,
> +                       (char *) NULL)) {
> +            error = add ? EEXIST : ENXIO;
> +        }
>         send_simple_reply(seq, error);
>     }
>     return error;
> @@ -683,97 +341,75 @@ static const struct nl_policy brc_port_policy[] = {
>  };
>
>  static int
> -handle_port_cmd(struct ovsdb_idl *idl,
> -                const struct ovsrec_open_vswitch *ovs,
> -                struct ofpbuf *buffer, bool add)
> +handle_port_cmd(struct ofpbuf *buffer, bool add)
>  {
> -    const char *cmd_name = add ? "add-if" : "del-if";
>     const char *br_name, *port_name;
>     uint32_t seq;
>     int error;
>
>     error = parse_command(buffer, &seq, &br_name, &port_name, NULL, NULL);
>     if (!error) {
> -        struct ovsrec_bridge *br = find_bridge(ovs, br_name);
> -
> -        if (!br) {
> -            VLOG_WARN("%s %s %s: no bridge named %s",
> -                      cmd_name, br_name, port_name, br_name);
> -            error = EINVAL;
> -        } else if (!netdev_exists(port_name)) {
> -            VLOG_WARN("%s %s %s: no network device named %s",
> -                      cmd_name, br_name, port_name, port_name);
> +        const char *vsctl_cmd = add ? "add-port" : "del-port";
> +        const char *brctl_cmd = add ? "addif" : "delif";
> +        if (!run_vsctl(vsctl_program, VSCTL_OPTIONS,
> +                       "--", vsctl_cmd, br_name, port_name,
> +                       "--", "comment", "ovs-brcompatd:", brctl_cmd,
> +                       br_name, port_name, (char *) NULL)) {
>             error = EINVAL;
> -        } else {
> -            do {
> -                struct ovsdb_idl_txn *txn = ovsdb_idl_txn_create(idl);
> -
> -                if (add) {
> -                    ovsdb_idl_txn_add_comment(txn, "ovs-brcompatd: add-if %s",
> -                                              port_name);
> -                    add_port(ovs, br, port_name);
> -                } else {
> -                    const struct ovsrec_port *port = find_port(br, port_name);
> -                    if (port) {
> -                        ovsdb_idl_txn_add_comment(txn,
> -                                                  "ovs-brcompatd: del-if %s",
> -                                                  port_name);
> -                        del_port(br, port);
> -                    }
> -                }
> -
> -                error = commit_txn(txn, true);
> -                VLOG_INFO_RL(&rl, "%s %s %s: %s",
> -                             cmd_name, br_name, port_name, strerror(error));
> -            } while (error == EAGAIN);
>         }
>         send_simple_reply(seq, error);
>     }
> -
>     return error;
>  }
>
> -/* The caller is responsible for freeing '*ovs_name' if the call is
> - * successful. */
> -static int
> -linux_bridge_to_ovs_bridge(const struct ovsrec_open_vswitch *ovs,
> -                           const char *linux_name,
> -                           const struct ovsrec_bridge **ovs_bridge,
> -                           int *br_vlan)
> +static char *
> +linux_bridge_to_ovs_bridge(const char *linux_name)
>  {
> -    *ovs_bridge = find_bridge(ovs, linux_name);
> -    if (*ovs_bridge) {
> -        /* Bridge name is the same.  We are interested in VLAN 0. */
> -        *br_vlan = 0;
> -        return 0;
> -    } else {
> -        /* No such Open vSwitch bridge 'linux_name', but there might be an
> -         * internal port named 'linux_name' on some other bridge
> -         * 'ovs_bridge'.  If so then we are interested in the VLAN assigned to
> -         * port 'linux_name' on the bridge named 'ovs_bridge'. */
> -        size_t i, j;
> -
> -        for (i = 0; i < ovs->n_bridges; i++) {
> -            const struct ovsrec_bridge *br = ovs->bridges[i];
> -
> -            for (j = 0; j < br->n_ports; j++) {
> -                const struct ovsrec_port *port = br->ports[j];
> -
> -                if (!strcmp(port->name, linux_name)) {
> -                    *ovs_bridge = br;
> -                    *br_vlan = port->n_tag ? *port->tag : -1;
> -                    return 0;
> -                }
> -            }
> +    char *save_ptr = NULL;
> +    const char *br_name;
> +    char *br_name_copy;
> +    char *output;
>
> -        }
> -        return ENODEV;
> +    output = capture_vsctl(vsctl_program, VSCTL_OPTIONS, "br-to-parent",
> +                           linux_name, (char *) NULL);
> +    if (!output) {
> +        return NULL;
> +    }
> +
> +    br_name = strtok_r(output, " \t\r\n", &save_ptr);
> +    if (!br_name) {
> +        free(output);
> +        return NULL;
> +    }
> +    br_name_copy = xstrdup(br_name);
> +
> +    free(output);
> +
> +    return br_name_copy;
> +}
> +
> +static void
> +get_bridge_ifaces(const char *br_name, struct sset *ifaces)
> +{
> +    char *save_ptr = NULL;
> +    char *output;
> +    char *iface;
> +
> +    output = capture_vsctl(vsctl_program, VSCTL_OPTIONS, "list-ifaces",
> +                           br_name, (char *) NULL);
> +    if (!output) {
> +        return;
> +    }
> +
> +    for (iface = strtok_r(output, " \t\r\n", &save_ptr); iface;
> +         iface = strtok_r(NULL, " \t\r\n", &save_ptr)) {
> +        sset_add(ifaces, iface);
>     }
> +    free(output);
>  }
>
>  static int
> -handle_fdb_query_cmd(const struct ovsrec_open_vswitch *ovs,
> -                     struct ofpbuf *buffer)
> +handle_fdb_query_cmd(struct ofpbuf *buffer)
>  {
>     /* This structure is copied directly from the Linux 2.6.30 header files.
>      * It would be more straightforward to #include <linux/if_bridge.h>, but
> @@ -802,15 +438,14 @@ handle_fdb_query_cmd(const struct ovsrec_open_vswitch *ovs,
>      * pretend that the former is the case even though the latter is the
>      * implementation. */
>     const char *linux_name;   /* Name used by brctl. */
> -    const struct ovsrec_bridge *ovs_bridge;  /* Bridge used by ovs-vswitchd. */
>     int br_vlan;                /* VLAN tag. */
>     struct sset ifaces;
>
>     struct ofpbuf query_data;
>     const char *iface_name;
>     struct ofpbuf *reply;
> -    char *unixctl_command;
>     uint64_t count, skip;
> +    char *br_name;
>     char *output;
>     char *save_ptr;
>     uint32_t seq;
> @@ -823,18 +458,18 @@ handle_fdb_query_cmd(const struct ovsrec_open_vswitch *ovs,
>     }
>
>     /* Figure out vswitchd bridge and VLAN. */
> -    error = linux_bridge_to_ovs_bridge(ovs, linux_name,
> -                                       &ovs_bridge, &br_vlan);
> -    if (error) {
> +    br_name = linux_bridge_to_ovs_bridge(linux_name);
> +    if (!br_name) {
> +        error = EINVAL;
>         send_simple_reply(seq, error);
>         return error;
>     }
>
>     /* Fetch the forwarding database using ovs-appctl. */
> -    unixctl_command = xasprintf("fdb/show %s", ovs_bridge->name);
> -    error = execute_appctl_command(unixctl_command, &output);
> -    free(unixctl_command);
> -    if (error) {
> +    output = capture_vsctl(appctl_program, "fdb/show", br_name,
> +                           (char *) NULL);
> +    if (!output) {
> +        error = ECHILD;
>         send_simple_reply(seq, error);
>         return error;
>     }
> @@ -842,7 +477,7 @@ handle_fdb_query_cmd(const struct ovsrec_open_vswitch *ovs,
>     /* Fetch the MAC address for each interface on the bridge, so that we can
>      * fill in the is_local field in the response. */
>     sset_init(&ifaces);
> -    get_bridge_ifaces(ovs_bridge, &ifaces, br_vlan);
> +    get_bridge_ifaces(linux_name, &ifaces);
>     local_macs = xmalloc(sset_count(&ifaces) * sizeof *local_macs);
>     n_local_macs = 0;
>     SSET_FOR_EACH (iface_name, &ifaces) {
> @@ -928,18 +563,26 @@ handle_fdb_query_cmd(const struct ovsrec_open_vswitch *ovs,
>  }
>
>  static void
> -send_ifindex_reply(uint32_t seq, struct sset *ifaces)
> +send_ifindex_reply(uint32_t seq, char *output)
>  {
> +    size_t allocated_indices;
> +    char *save_ptr = NULL;
>     struct ofpbuf *reply;
>     const char *iface;
>     size_t n_indices;
>     int *indices;
>
> -    /* Convert 'ifaces' into ifindexes. */
> -    n_indices = 0;
> -    indices = xmalloc(sset_count(ifaces) * sizeof *indices);
> -    SSET_FOR_EACH (iface, ifaces) {
> -        int ifindex = if_nametoindex(iface);
> +    indices = NULL;
> +    n_indices = allocated_indices = 0;
> +    for (iface = strtok_r(output, " \t\r\n", &save_ptr); iface;
> +         iface = strtok_r(NULL, " \t\r\n", &save_ptr)) {
> +        int ifindex;
> +
> +        if (n_indices >= allocated_indices) {
> +            indices = x2nrealloc(indices, &allocated_indices, sizeof *indices);
> +        }
> +
> +        ifindex = if_nametoindex(iface);
>         if (ifindex) {
>             indices[n_indices++] = ifindex;
>         }
> @@ -956,14 +599,10 @@ send_ifindex_reply(uint32_t seq, struct sset *ifaces)
>  }
>
>  static int
> -handle_get_bridges_cmd(const struct ovsrec_open_vswitch *ovs,
> -                       struct ofpbuf *buffer)
> +handle_get_bridges_cmd(struct ofpbuf *buffer)
>  {
> -    struct sset bridges;
> -    size_t i, j;
> -
> +    char *output;
>     uint32_t seq;
> -
>     int error;
>
>     /* Parse Netlink command.
> @@ -975,39 +614,22 @@ handle_get_bridges_cmd(const struct ovsrec_open_vswitch *ovs,
>         return error;
>     }
>
> -    /* Get all the real bridges and all the fake ones. */
> -    sset_init(&bridges);
> -    for (i = 0; i < ovs->n_bridges; i++) {
> -        const struct ovsrec_bridge *br = ovs->bridges[i];
> -
> -        sset_add(&bridges, br->name);
> -        for (j = 0; j < br->n_ports; j++) {
> -            const struct ovsrec_port *port = br->ports[j];
> -
> -            if (port->fake_bridge) {
> -                sset_add(&bridges, port->name);
> -            }
> -        }
> +    output = capture_vsctl(vsctl_program, VSCTL_OPTIONS, "list-br", (char *) NULL);
> +    if (!output) {
> +        return ENODEV;
>     }
>
> -    send_ifindex_reply(seq, &bridges);
> -    sset_destroy(&bridges);
> -
> +    send_ifindex_reply(seq, output);
> +    free(output);
>     return 0;
>  }
>
>  static int
> -handle_get_ports_cmd(const struct ovsrec_open_vswitch *ovs,
> -                     struct ofpbuf *buffer)
> +handle_get_ports_cmd(struct ofpbuf *buffer)
>  {
> -    uint32_t seq;
> -
>     const char *linux_name;
> -    const struct ovsrec_bridge *ovs_bridge;
> -    int br_vlan;
> -
> -    struct sset ports;
> -
> +    uint32_t seq;
> +    char *output;
>     int error;
>
>     /* Parse Netlink command. */
> @@ -1016,19 +638,14 @@ handle_get_ports_cmd(const struct ovsrec_open_vswitch *ovs,
>         return error;
>     }
>
> -    error = linux_bridge_to_ovs_bridge(ovs, linux_name,
> -                                       &ovs_bridge, &br_vlan);
> -    if (error) {
> -        send_simple_reply(seq, error);
> -        return error;
> +    output = capture_vsctl(vsctl_program, VSCTL_OPTIONS, "list-ports", linux_name,
> +                           (char *) NULL);
> +    if (!output) {
> +        return ENODEV;
>     }
>
> -    sset_init(&ports);
> -    get_bridge_ports(ovs_bridge, &ports, br_vlan);
> -    sset_find_and_delete(&ports, linux_name);
> -    send_ifindex_reply(seq, &ports); /* XXX bonds won't show up */
> -    sset_destroy(&ports);
> -
> +    send_ifindex_reply(seq, output);
> +    free(output);
>     return 0;
>  }
>
> @@ -1063,11 +680,10 @@ brc_recv_update__(void)
>  }
>
>  static void
> -brc_recv_update(struct ovsdb_idl *idl)
> +brc_recv_update(void)
>  {
>     struct ofpbuf *buffer;
>     struct genlmsghdr *genlmsghdr;
> -    const struct ovsrec_open_vswitch *ovs;
>
>     buffer = brc_recv_update__();
>     if (!buffer) {
> @@ -1086,16 +702,6 @@ brc_recv_update(struct ovsdb_idl *idl)
>         goto error;
>     }
>
> -    /* Get the Open vSwitch configuration.  Just drop the request on the floor
> -     * if a valid configuration doesn't exist.  (We could check this earlier,
> -     * but we want to drain pending Netlink messages even when there is no Open
> -     * vSwitch configuration.) */
> -    ovs = ovsrec_open_vswitch_first(idl);
> -    if (!ovs) {
> -        VLOG_WARN_RL(&rl, "could not find valid configuration to update");
> -        goto error;
> -    }
> -
>     /* Service all pending network device notifications before executing the
>      * command.  This is very important to avoid a race in a scenario like the
>      * following, which is what happens with XenServer Tools version 5.0.0
> @@ -1118,31 +724,31 @@ brc_recv_update(struct ovsdb_idl *idl)
>
>     switch (genlmsghdr->cmd) {
>     case BRC_GENL_C_DP_ADD:
> -        handle_bridge_cmd(idl, ovs, buffer, true);
> +        handle_bridge_cmd(buffer, true);
>         break;
>
>     case BRC_GENL_C_DP_DEL:
> -        handle_bridge_cmd(idl, ovs, buffer, false);
> +        handle_bridge_cmd(buffer, false);
>         break;
>
>     case BRC_GENL_C_PORT_ADD:
> -        handle_port_cmd(idl, ovs, buffer, true);
> +        handle_port_cmd(buffer, true);
>         break;
>
>     case BRC_GENL_C_PORT_DEL:
> -        handle_port_cmd(idl, ovs, buffer, false);
> +        handle_port_cmd(buffer, false);
>         break;
>
>     case BRC_GENL_C_FDB_QUERY:
> -        handle_fdb_query_cmd(ovs, buffer);
> +        handle_fdb_query_cmd(buffer);
>         break;
>
>     case BRC_GENL_C_GET_BRIDGES:
> -        handle_get_bridges_cmd(ovs, buffer);
> +        handle_get_bridges_cmd(buffer);
>         break;
>
>     case BRC_GENL_C_GET_PORTS:
> -        handle_get_ports_cmd(ovs, buffer);
> +        handle_get_ports_cmd(buffer);
>         break;
>
>     default:
> @@ -1153,18 +759,12 @@ brc_recv_update(struct ovsdb_idl *idl)
>
>  error:
>     ofpbuf_delete(buffer);
> -    return;
>  }
>
>  static void
> -netdev_changed_cb(const struct rtnetlink_link_change *change, void *idl_)
> +netdev_changed_cb(const struct rtnetlink_link_change *change,
> +                  void *aux OVS_UNUSED)
>  {
> -    struct ovsdb_idl *idl = idl_;
> -    const struct ovsrec_open_vswitch *ovs;
> -    const struct ovsrec_interface *iface;
> -    struct ovsdb_idl_txn *txn;
> -    struct ovsrec_port *port;
> -    struct ovsrec_bridge *br;
>     char br_name[IFNAMSIZ];
>     const char *port_name;
>
> @@ -1177,11 +777,6 @@ netdev_changed_cb(const struct rtnetlink_link_change *change, void *idl_)
>         return;
>     }
>
> -    ovs = ovsrec_open_vswitch_first(idl);
> -    if (!ovs) {
> -        return;
> -    }
> -
>     port_name = change->ifname;
>     if (!if_indextoname(change->master_ifindex, br_name)) {
>         return;
> @@ -1190,23 +785,10 @@ netdev_changed_cb(const struct rtnetlink_link_change *change, void *idl_)
>     VLOG_INFO("network device %s destroyed, removing from bridge %s",
>               port_name, br_name);
>
> -    br = find_bridge(ovs, br_name);
> -    if (!br) {
> -        VLOG_WARN("no bridge named %s from which to remove %s",
> -                  br_name, port_name);
> -        return;
> -    }
> -
> -    iface = find_interface(br, port_name, &port);
> -    if (!iface) {
> -        return;
> -    }
> -
> -    txn = ovsdb_idl_txn_create(idl);
> -    del_interface(br, port, iface);
> -    ovsdb_idl_txn_add_comment(txn, "ovs-brcompatd: destroy port %s",
> -                              port_name);
> -    commit_txn(txn, false);
> +    run_vsctl(vsctl_program, VSCTL_OPTIONS,
> +              "--", "--if-exists", "del-port", br_name, port_name,
> +              "--", "comment", "ovs-brcompatd:", port_name, "disappeared",
> +              (char *) NULL);
>  }
>
>  int
> @@ -1215,19 +797,15 @@ main(int argc, char *argv[])
>     extern struct vlog_module VLM_reconnect;
>     struct rtnetlink_notifier link_notifier;
>     struct unixctl_server *unixctl;
> -    const char *remote;
> -    struct ovsdb_idl *idl;
>     int retval;
>
>     proctitle_init(argc, argv);
>     set_program_name(argv[0]);
> -    vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
>     vlog_set_levels(&VLM_reconnect, VLF_ANY_FACILITY, VLL_WARN);
>
> -    remote = parse_options(argc, argv);
> +    parse_options(argc, argv);
>     signal(SIGPIPE, SIG_IGN);
>     process_init();
> -    ovsrec_init();
>
>     daemonize_start();
>
> @@ -1246,27 +824,14 @@ main(int argc, char *argv[])
>
>     daemonize_complete();
>
> -    idl = ovsdb_idl_create(remote, &ovsrec_idl_class, true);
> -
>     for (;;) {
> -        const struct ovsrec_open_vswitch *ovs;
> -
> -        ovsdb_idl_run(idl);
> -
>         unixctl_server_run(unixctl);
>         rtnetlink_link_notifier_run();
> -        brc_recv_update(idl);
> +        brc_recv_update();
>
> -        ovs = ovsrec_open_vswitch_first(idl);
> -        if (!ovs && ovsdb_idl_has_ever_connected(idl)) {
> -            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> -            VLOG_WARN_RL(&rl, "%s: database does not contain any Open vSwitch "
> -                         "configuration", remote);
> -        }
>         netdev_run();
>
>         nl_sock_wait(brc_sock, POLLIN);
> -        ovsdb_idl_wait(idl);
>         unixctl_server_wait(unixctl);
>         rtnetlink_link_notifier_wait();
>         netdev_wait();
> @@ -1274,37 +839,16 @@ main(int argc, char *argv[])
>     }
>
>     rtnetlink_link_notifier_unregister(&link_notifier);
> -    ovsdb_idl_destroy(idl);
>
>     return 0;
>  }
>
>  static void
> -validate_appctl_command(void)
> -{
> -    const char *p;
> -    int n;
> -
> -    n = 0;
> -    for (p = strchr(appctl_command, '%'); p; p = strchr(p + 2, '%')) {
> -        if (p[1] == '%') {
> -            /* Nothing to do. */
> -        } else if (p[1] == 's') {
> -            n++;
> -        } else {
> -            VLOG_FATAL("only '%%s' and '%%%%' allowed in --appctl-command");
> -        }
> -    }
> -    if (n != 1) {
> -        VLOG_FATAL("'%%s' must appear exactly once in --appctl-command");
> -    }
> -}
> -
> -static const char *
>  parse_options(int argc, char *argv[])
>  {
>     enum {
> -        OPT_APPCTL_COMMAND,
> +        OPT_APPCTL,
> +        OPT_VSCTL,
>         VLOG_OPTION_ENUMS,
>         LEAK_CHECKER_OPTION_ENUMS,
>         DAEMON_OPTION_ENUMS
> @@ -1312,15 +856,17 @@ parse_options(int argc, char *argv[])
>     static struct option long_options[] = {
>         {"help",             no_argument, NULL, 'h'},
>         {"version",          no_argument, NULL, 'V'},
> -        {"appctl-command",   required_argument, NULL, OPT_APPCTL_COMMAND},
> +        {"appctl",           required_argument, NULL, OPT_APPCTL},
> +        {"vsctl",            required_argument, NULL, OPT_VSCTL},
>         DAEMON_LONG_OPTIONS,
>         VLOG_LONG_OPTIONS,
>         LEAK_CHECKER_LONG_OPTIONS,
>         {NULL, 0, NULL, 0},
>     };
>     char *short_options = long_options_to_short_options(long_options);
> +    const char *appctl = "ovs-appctl";
> +    const char *vsctl = "ovs-vsctl";
>
> -    appctl_command = xasprintf("%s/ovs-appctl %%s", ovs_bindir());
>     for (;;) {
>         int c;
>
> @@ -1338,8 +884,12 @@ parse_options(int argc, char *argv[])
>             OVS_PRINT_VERSION(0, 0);
>             exit(EXIT_SUCCESS);
>
> -        case OPT_APPCTL_COMMAND:
> -            appctl_command = optarg;
> +        case OPT_APPCTL:
> +            appctl = optarg;
> +            break;
> +
> +        case OPT_VSCTL:
> +            vsctl = optarg;
>             break;
>
>         VLOG_OPTION_HANDLERS
> @@ -1355,28 +905,33 @@ parse_options(int argc, char *argv[])
>     }
>     free(short_options);
>
> -    validate_appctl_command();
> +    appctl_program = process_search_path(appctl);
> +    if (!appctl_program) {
> +        VLOG_FATAL("%s: not found in $PATH (use --appctl to specify an "
> +                   "alternate location)", appctl);
> +    }
>
> -    argc -= optind;
> -    argv += optind;
> +    vsctl_program = process_search_path(vsctl);
> +    if (!vsctl_program) {
> +        VLOG_FATAL("%s: not found in $PATH (use --vsctl to specify an "
> +                   "alternate location)", vsctl);
> +    }
>
> -    if (argc != 1) {
> -        VLOG_FATAL("database socket is non-option argument; "
> +    if (argc != optind) {
> +        VLOG_FATAL("no non-option arguments are supported; "
>                    "use --help for usage");
>     }
> -
> -    return argv[0];
>  }
>
>  static void
>  usage(void)
>  {
>     printf("%s: bridge compatibility front-end for ovs-vswitchd\n"
> -           "usage: %s [OPTIONS] CONFIG\n"
> -           "CONFIG is the configuration file used by ovs-vswitchd.\n",
> +           "usage: %s [OPTIONS]\n",
>            program_name, program_name);
>     printf("\nConfiguration options:\n"
> -           "  --appctl-command=COMMAND  shell command to run ovs-appctl\n"
> +           "  --appctl=PROGRAM        overrides $PATH for finding ovs-appctl\n"
> +           "  --vsctl=PROGRAM         overrides $PATH for finding ovs-vsctl\n"
>           );
>     daemon_usage();
>     vlog_usage();
> @@ -1384,6 +939,5 @@ usage(void)
>            "  -h, --help              display this help message\n"
>            "  -V, --version           display version information\n");
>     leak_checker_usage();
> -    printf("\nThe default appctl command is:\n%s\n", appctl_command);
>     exit(EXIT_SUCCESS);
>  }
> --
> 1.7.4.4
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
>



More information about the dev mailing list