X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=vswitchd%2Fovs-brcompatd.c;h=cea7fda5645e6396961b16bfb428fdca8b0115be;hb=5326a0fd22b8f01c5b0fd9a5763cb8ad9c885ea0;hp=39c110134f12f1ba64d020b28c2c43ade9ba45f2;hpb=d295e8e97acae13552a5b220d3fbcff8201064a2;p=openvswitch diff --git a/vswitchd/ovs-brcompatd.c b/vswitchd/ovs-brcompatd.c index 39c11013..cea7fda5 100644 --- a/vswitchd/ovs-brcompatd.c +++ b/vswitchd/ovs-brcompatd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2009, 2010 Nicira Networks +/* Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,21 +43,24 @@ #include "leak-checker.h" #include "netdev.h" #include "netlink.h" +#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" +#include "rtnetlink.h" +#include "rtnetlink-link.h" #include "signals.h" -#include "svec.h" +#include "sset.h" #include "timeval.h" #include "unixctl.h" #include "util.h" #include "vlog.h" #include "vswitchd/vswitch-idl.h" -VLOG_DEFINE_THIS_MODULE(brcompatd) +VLOG_DEFINE_THIS_MODULE(brcompatd); /* xxx Just hangs if datapath is rmmod/insmod. Learn to reconnect? */ @@ -84,9 +87,6 @@ static int prune_timeout = 5000; * which is replaced by the control command. */ static char *appctl_command; -/* Netlink socket to listen for interface changes. */ -static struct nl_sock *rtnl_sock; - /* Netlink socket to bridge compatibility kernel module. */ static struct nl_sock *brc_sock; @@ -97,11 +97,6 @@ static const struct nl_policy brc_multicast_policy[] = { [BRC_GENL_A_MC_GROUP] = {.type = NL_A_U32 } }; -static const struct nl_policy rtnlgrp_link_policy[] = { - [IFLA_IFNAME] = { .type = NL_A_STRING, .optional = false }, - [IFLA_MASTER] = { .type = NL_A_U32, .optional = true }, -}; - static int lookup_brc_multicast_group(int *multicast_group) { @@ -110,7 +105,7 @@ lookup_brc_multicast_group(int *multicast_group) struct nlattr *attrs[ARRAY_SIZE(brc_multicast_policy)]; int retval; - retval = nl_sock_create(NETLINK_GENERIC, 0, 0, 0, &sock); + retval = nl_sock_create(NETLINK_GENERIC, &sock); if (retval) { return retval; } @@ -155,12 +150,17 @@ brc_open(struct nl_sock **sock) return retval; } - retval = nl_sock_create(NETLINK_GENERIC, multicast_group, 0, 0, sock); + retval = nl_sock_create(NETLINK_GENERIC, sock); if (retval) { return retval; } - return 0; + retval = nl_sock_join_mcgroup(*sock, multicast_group); + if (retval) { + nl_sock_destroy(*sock); + *sock = NULL; + } + return retval; } static const struct nl_policy brc_dp_policy[] = { @@ -194,7 +194,8 @@ execute_appctl_command(const char *unixctl_command, char **output) argv[3] = NULL; /* Run process and log status. */ - error = process_run_capture(argv, &stdout_log, &stderr_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)); @@ -224,17 +225,14 @@ execute_appctl_command(const char *unixctl_command, char **output) } static void -do_get_bridge_parts(const struct ovsrec_bridge *br, struct svec *parts, +do_get_bridge_parts(const struct ovsrec_bridge *br, struct sset *parts, int vlan, bool break_down_bonds) { - struct svec ports; size_t i, j; - svec_init(&ports); for (i = 0; i < br->n_ports; i++) { const struct ovsrec_port *port = br->ports[i]; - svec_add(&ports, port->name); if (vlan >= 0) { int port_vlan = port->n_tag ? *port->tag : 0; if (vlan != port_vlan) { @@ -244,13 +242,12 @@ do_get_bridge_parts(const struct ovsrec_bridge *br, struct svec *parts, if (break_down_bonds) { for (j = 0; j < port->n_interfaces; j++) { const struct ovsrec_interface *iface = port->interfaces[j]; - svec_add(parts, iface->name); + sset_add(parts, iface->name); } } else { - svec_add(parts, port->name); + sset_add(parts, port->name); } } - svec_destroy(&ports); } /* Add all the interfaces for 'bridge' to 'ifaces', breaking bonded interfaces @@ -261,7 +258,7 @@ do_get_bridge_parts(const struct ovsrec_bridge *br, struct svec *parts, * reported. If 'vlan' > 0, only interfaces with implicit VLAN 'vlan' are * reported. */ static void -get_bridge_ifaces(const struct ovsrec_bridge *br, struct svec *ifaces, +get_bridge_ifaces(const struct ovsrec_bridge *br, struct sset *ifaces, int vlan) { do_get_bridge_parts(br, ifaces, vlan, true); @@ -274,7 +271,7 @@ get_bridge_ifaces(const struct ovsrec_bridge *br, struct svec *ifaces, * 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 svec *ports, +get_bridge_ports(const struct ovsrec_bridge *br, struct sset *ports, int vlan) { do_get_bridge_parts(br, ports, vlan, false); @@ -491,14 +488,6 @@ del_port(const struct ovsrec_bridge *br, const struct ovsrec_port *port) } ovsrec_bridge_set_ports(br, ports, n); free(ports); - - /* Delete all of the port's interfaces. */ - for (i = 0; i < port->n_interfaces; i++) { - ovsrec_interface_delete(port->interfaces[i]); - } - - /* Delete the port itself. */ - ovsrec_port_delete(port); } /* Delete 'iface' from 'port' (which must be within 'br'). If 'iface' was @@ -524,7 +513,6 @@ del_interface(const struct ovsrec_bridge *br, } ovsrec_port_set_interfaces(port, ifaces, n); free(ifaces); - ovsrec_interface_delete(iface); } } @@ -585,24 +573,6 @@ del_bridge(struct ovsdb_idl *idl, ovsdb_idl_txn_add_comment(txn, "ovs-brcompatd: delbr %s", br_name); - /* Delete everything that the bridge points to, then delete the bridge - * itself. */ - while (br->n_ports > 0) { - del_port(br, br->ports[0]); - } - for (i = 0; i < br->n_mirrors; i++) { - ovsrec_mirror_delete(br->mirrors[i]); - } - if (br->netflow) { - ovsrec_netflow_delete(br->netflow); - } - if (br->sflow) { - ovsrec_sflow_delete(br->sflow); - } - for (i = 0; i < br->n_controller; i++) { - ovsrec_controller_delete(br->controller[i]); - } - /* 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++) { @@ -613,9 +583,6 @@ del_bridge(struct ovsdb_idl *idl, ovsrec_open_vswitch_set_bridges(ovs, bridges, n); free(bridges); - /* Delete the bridge itself. */ - ovsrec_bridge_delete(br); - return commit_txn(txn, true); } @@ -841,9 +808,10 @@ handle_fdb_query_cmd(const struct ovsrec_open_vswitch *ovs, 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 svec ifaces; + struct sset ifaces; struct ofpbuf query_data; + const char *iface_name; struct ofpbuf *reply; char *unixctl_command; uint64_t count, skip; @@ -877,12 +845,11 @@ 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. */ - svec_init(&ifaces); + sset_init(&ifaces); get_bridge_ifaces(ovs_bridge, &ifaces, br_vlan); - local_macs = xmalloc(ifaces.n * sizeof *local_macs); + local_macs = xmalloc(sset_count(&ifaces) * sizeof *local_macs); n_local_macs = 0; - for (i = 0; i < ifaces.n; i++) { - const char *iface_name = ifaces.names[i]; + SSET_FOR_EACH (iface_name, &ifaces) { struct mac *mac = &local_macs[n_local_macs]; struct netdev *netdev; @@ -894,7 +861,7 @@ handle_fdb_query_cmd(const struct ovsrec_open_vswitch *ovs, netdev_close(netdev); } } - svec_destroy(&ifaces); + sset_destroy(&ifaces); /* Parse the response from ovs-appctl and convert it to binary format to * pass back to the kernel. */ @@ -916,7 +883,7 @@ handle_fdb_query_cmd(const struct ovsrec_open_vswitch *ovs, if (sscanf(line, "%d %d "ETH_ADDR_SCAN_FMT" %d", &port, &vlan, ETH_ADDR_SCAN_ARGS(mac), &age) != 2 + ETH_ADDR_SCAN_COUNT + 1) { - struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); VLOG_INFO_RL(&rl, "fdb/show output has invalid format: %s", line); continue; } @@ -959,27 +926,23 @@ handle_fdb_query_cmd(const struct ovsrec_open_vswitch *ovs, /* Free memory. */ ofpbuf_uninit(&query_data); + free(local_macs); return 0; } static void -send_ifindex_reply(uint32_t seq, struct svec *ifaces) +send_ifindex_reply(uint32_t seq, struct sset *ifaces) { struct ofpbuf *reply; const char *iface; size_t n_indices; int *indices; - size_t i; - - /* Make sure that any given interface only occurs once. This shouldn't - * happen, but who knows what people put into their configuration files. */ - svec_sort_unique(ifaces); /* Convert 'ifaces' into ifindexes. */ n_indices = 0; - indices = xmalloc(ifaces->n * sizeof *indices); - SVEC_FOR_EACH (i, iface, ifaces) { + indices = xmalloc(sset_count(ifaces) * sizeof *indices); + SSET_FOR_EACH (iface, ifaces) { int ifindex = if_nametoindex(iface); if (ifindex) { indices[n_indices++] = ifindex; @@ -1000,7 +963,7 @@ static int handle_get_bridges_cmd(const struct ovsrec_open_vswitch *ovs, struct ofpbuf *buffer) { - struct svec bridges; + struct sset bridges; size_t i, j; uint32_t seq; @@ -1017,22 +980,22 @@ handle_get_bridges_cmd(const struct ovsrec_open_vswitch *ovs, } /* Get all the real bridges and all the fake ones. */ - svec_init(&bridges); + sset_init(&bridges); for (i = 0; i < ovs->n_bridges; i++) { const struct ovsrec_bridge *br = ovs->bridges[i]; - svec_add(&bridges, br->name); + 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) { - svec_add(&bridges, port->name); + sset_add(&bridges, port->name); } } } send_ifindex_reply(seq, &bridges); - svec_destroy(&bridges); + sset_destroy(&bridges); return 0; } @@ -1047,7 +1010,7 @@ handle_get_ports_cmd(const struct ovsrec_open_vswitch *ovs, const struct ovsrec_bridge *ovs_bridge; int br_vlan; - struct svec ports; + struct sset ports; int error; @@ -1064,36 +1027,54 @@ handle_get_ports_cmd(const struct ovsrec_open_vswitch *ovs, return error; } - svec_init(&ports); + sset_init(&ports); get_bridge_ports(ovs_bridge, &ports, br_vlan); - svec_sort(&ports); - svec_del(&ports, linux_name); + sset_find_and_delete(&ports, linux_name); send_ifindex_reply(seq, &ports); /* XXX bonds won't show up */ - svec_destroy(&ports); + sset_destroy(&ports); return 0; } +static struct ofpbuf * +brc_recv_update__(void) +{ + for (;;) { + struct ofpbuf *buffer; + int retval; + + retval = nl_sock_recv(brc_sock, &buffer, false); + switch (retval) { + case 0: + if (nl_msg_nlmsgerr(buffer, NULL) + || nl_msg_nlmsghdr(buffer)->nlmsg_type == NLMSG_DONE) { + break; + } + return buffer; + + case ENOBUFS: + break; + + case EAGAIN: + return NULL; + + default: + VLOG_WARN_RL(&rl, "brc_recv_update: %s", strerror(retval)); + return NULL; + } + ofpbuf_delete(buffer); + } +} + static void brc_recv_update(struct ovsdb_idl *idl) { - int retval; struct ofpbuf *buffer; struct genlmsghdr *genlmsghdr; const struct ovsrec_open_vswitch *ovs; - buffer = NULL; - do { - ofpbuf_delete(buffer); - retval = nl_sock_recv(brc_sock, &buffer, false); - } while (retval == ENOBUFS - || (!retval - && (nl_msg_nlmsgerr(buffer, NULL) - || nl_msg_nlmsghdr(buffer)->nlmsg_type == NLMSG_DONE))); - if (retval) { - if (retval != EAGAIN) { - VLOG_WARN_RL(&rl, "brc_recv_update: %s", strerror(retval)); - } + buffer = brc_recv_update__(); + if (!buffer) { return; } @@ -1159,135 +1140,112 @@ error: return; } -/* Check for interface configuration changes announced through RTNL. */ static void -rtnl_recv_update(struct ovsdb_idl *idl, - const struct ovsrec_open_vswitch *ovs) +netdev_changed_cb(const struct rtnetlink_link_change *change, void *idl_) { - struct ofpbuf *buf; + 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; - int error = nl_sock_recv(rtnl_sock, &buf, false); - if (error == EAGAIN) { - /* Nothing to do. */ - } else if (error == ENOBUFS) { + if (!change) { VLOG_WARN_RL(&rl, "network monitor socket overflowed"); - } else if (error) { - VLOG_WARN_RL(&rl, "error on network monitor socket: %s", - strerror(error)); - } else { - struct nlattr *attrs[ARRAY_SIZE(rtnlgrp_link_policy)]; - struct nlmsghdr *nlh; - struct ifinfomsg *iim; - - nlh = ofpbuf_at(buf, 0, NLMSG_HDRLEN); - iim = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *iim); - if (!iim) { - VLOG_WARN_RL(&rl, "received bad rtnl message (no ifinfomsg)"); - ofpbuf_delete(buf); - return; - } + return; + } - if (!nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct ifinfomsg), - rtnlgrp_link_policy, - attrs, ARRAY_SIZE(rtnlgrp_link_policy))) { - VLOG_WARN_RL(&rl,"received bad rtnl message (policy)"); - ofpbuf_delete(buf); - return; - } - if (nlh->nlmsg_type == RTM_DELLINK && attrs[IFLA_MASTER]) { - const char *port_name = nl_attr_get_string(attrs[IFLA_IFNAME]); - char br_name[IFNAMSIZ]; - uint32_t br_idx = nl_attr_get_u32(attrs[IFLA_MASTER]); - - if (!if_indextoname(br_idx, br_name)) { - ofpbuf_delete(buf); - return; - } + if (change->nlmsg_type != RTM_DELLINK || !change->master_ifindex) { + return; + } - if (!netdev_exists(port_name)) { - /* Network device is really gone. */ - struct ovsdb_idl_txn *txn; - const struct ovsrec_interface *iface; - struct ovsrec_port *port; - struct ovsrec_bridge *br; - - 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); - ofpbuf_delete(buf); - return; - } + ovs = ovsrec_open_vswitch_first(idl); + if (!ovs) { + return; + } - txn = ovsdb_idl_txn_create(idl); + port_name = change->ifname; + if (!if_indextoname(change->master_ifindex, br_name)) { + return; + } - iface = find_interface(br, port_name, &port); - if (iface) { - del_interface(br, port, iface); - ovsdb_idl_txn_add_comment(txn, - "ovs-brcompatd: destroy port %s", - port_name); - } + if (netdev_exists(port_name)) { + /* A network device by that name exists even though the kernel + * told us it had disappeared. Probably, what happened was + * this: + * + * 1. Device destroyed. + * 2. Notification sent to us. + * 3. New device created with same name as old one. + * 4. ovs-brcompatd notified, removes device from bridge. + * + * There's no a priori reason that in this situation that the + * new device with the same name should remain in the bridge; + * on the contrary, that would be unexpected. *But* there is + * one important situation where, if we do this, bad things + * happen. This is the case of XenServer Tools version 5.0.0, + * which on boot of a Windows VM cause something like this to + * happen on the Xen host: + * + * i. Create tap1.0 and vif1.0. + * ii. Delete tap1.0. + * iii. Delete vif1.0. + * iv. Re-create vif1.0. + * + * (XenServer Tools 5.5.0 does not exhibit this behavior, and + * neither does a VM without Tools installed at all.) + * + * Steps iii and iv happen within a few seconds of each other. + * Step iv causes /etc/xensource/scripts/vif to run, which in + * turn calls ovs-cfg-mod to add the new device to the bridge. + * If step iv happens after step 4 (in our first list of + * steps), then all is well, but if it happens between 3 and 4 + * (which can easily happen if ovs-brcompatd has to wait to + * lock the configuration file), then we will remove the new + * incarnation from the bridge instead of the old one! + * + * So, to avoid this problem, we do nothing here. This is + * strictly incorrect except for this one particular case, and + * perhaps that will bite us someday. If that happens, then we + * will have to somehow track network devices by ifindex, since + * a new device will have a new ifindex even if it has the same + * name as an old device. + */ + VLOG_INFO("kernel reported network device %s removed but " + "a device by that name exists (XS Tools 5.0.0?)", + port_name); + return; + } - commit_txn(txn, false); - } else { - /* A network device by that name exists even though the kernel - * told us it had disappeared. Probably, what happened was - * this: - * - * 1. Device destroyed. - * 2. Notification sent to us. - * 3. New device created with same name as old one. - * 4. ovs-brcompatd notified, removes device from bridge. - * - * There's no a priori reason that in this situation that the - * new device with the same name should remain in the bridge; - * on the contrary, that would be unexpected. *But* there is - * one important situation where, if we do this, bad things - * happen. This is the case of XenServer Tools version 5.0.0, - * which on boot of a Windows VM cause something like this to - * happen on the Xen host: - * - * i. Create tap1.0 and vif1.0. - * ii. Delete tap1.0. - * iii. Delete vif1.0. - * iv. Re-create vif1.0. - * - * (XenServer Tools 5.5.0 does not exhibit this behavior, and - * neither does a VM without Tools installed at all.@.) - * - * Steps iii and iv happen within a few seconds of each other. - * Step iv causes /etc/xensource/scripts/vif to run, which in - * turn calls ovs-cfg-mod to add the new device to the bridge. - * If step iv happens after step 4 (in our first list of - * steps), then all is well, but if it happens between 3 and 4 - * (which can easily happen if ovs-brcompatd has to wait to - * lock the configuration file), then we will remove the new - * incarnation from the bridge instead of the old one! - * - * So, to avoid this problem, we do nothing here. This is - * strictly incorrect except for this one particular case, and - * perhaps that will bite us someday. If that happens, then we - * will have to somehow track network devices by ifindex, since - * a new device will have a new ifindex even if it has the same - * name as an old device. - */ - VLOG_INFO("kernel reported network device %s removed but " - "a device by that name exists (XS Tools 5.0.0?)", - port_name); - } - } - ofpbuf_delete(buf); + 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); } int 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; @@ -1303,7 +1261,6 @@ main(int argc, char *argv[]) process_init(); ovsrec_init(); - die_if_already_running(); daemonize_start(); retval = unixctl_server_create(NULL, &unixctl); @@ -1312,19 +1269,19 @@ main(int argc, char *argv[]) } if (brc_open(&brc_sock)) { - ovs_fatal(0, "could not open brcompat socket. Check " - "\"brcompat\" kernel module."); + VLOG_FATAL("could not open brcompat socket. Check " + "\"brcompat\" kernel module."); } + if (prune_timeout) { - if (nl_sock_create(NETLINK_ROUTE, RTNLGRP_LINK, 0, 0, &rtnl_sock)) { - ovs_fatal(0, "could not create rtnetlink socket"); - } + rtnetlink_link_notifier_register(&link_notifier, + netdev_changed_cb, NULL); } daemonize_complete(); - idl = ovsdb_idl_create(remote, &ovsrec_idl_class); + idl = ovsdb_idl_create(remote, &ovsrec_idl_class, true); for (;;) { const struct ovsrec_open_vswitch *ovs; @@ -1332,6 +1289,7 @@ main(int argc, char *argv[]) ovsdb_idl_run(idl); unixctl_server_run(unixctl); + rtnetlink_link_notifier_run(); brc_recv_update(idl); ovs = ovsrec_open_vswitch_first(idl); @@ -1353,19 +1311,21 @@ main(int argc, char *argv[]) * to see if they no longer exist. */ if (ovs && prune_timeout) { - rtnl_recv_update(idl, ovs); - nl_sock_wait(rtnl_sock, POLLIN); + rtnetlink_link_notifier_run(); poll_timer_wait(prune_timeout); } - nl_sock_wait(brc_sock, POLLIN); ovsdb_idl_wait(idl); unixctl_server_wait(unixctl); + rtnetlink_link_notifier_wait(); netdev_wait(); poll_block(); } + if (prune_timeout) { + rtnetlink_link_notifier_unregister(&link_notifier); + } ovsdb_idl_destroy(idl); return 0; @@ -1384,11 +1344,11 @@ validate_appctl_command(void) } else if (p[1] == 's') { n++; } else { - ovs_fatal(0, "only '%%s' and '%%%%' allowed in --appctl-command"); + VLOG_FATAL("only '%%s' and '%%%%' allowed in --appctl-command"); } } if (n != 1) { - ovs_fatal(0, "'%%s' must appear exactly once in --appctl-command"); + VLOG_FATAL("'%%s' must appear exactly once in --appctl-command"); } } @@ -1399,21 +1359,22 @@ parse_options(int argc, char *argv[]) OPT_PRUNE_TIMEOUT, OPT_APPCTL_COMMAND, VLOG_OPTION_ENUMS, - LEAK_CHECKER_OPTION_ENUMS + LEAK_CHECKER_OPTION_ENUMS, + DAEMON_OPTION_ENUMS }; static struct option long_options[] = { - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - {"prune-timeout", required_argument, 0, OPT_PRUNE_TIMEOUT}, - {"appctl-command", required_argument, 0, OPT_APPCTL_COMMAND}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'V'}, + {"prune-timeout", required_argument, NULL, OPT_PRUNE_TIMEOUT}, + {"appctl-command", required_argument, NULL, OPT_APPCTL_COMMAND}, DAEMON_LONG_OPTIONS, VLOG_LONG_OPTIONS, LEAK_CHECKER_LONG_OPTIONS, - {0, 0, 0, 0}, + {NULL, 0, NULL, 0}, }; char *short_options = long_options_to_short_options(long_options); - appctl_command = xasprintf("%s/ovs-appctl %%s", ovs_bindir); + appctl_command = xasprintf("%s/ovs-appctl %%s", ovs_bindir()); for (;;) { int c; @@ -1458,8 +1419,8 @@ parse_options(int argc, char *argv[]) argv += optind; if (argc != 1) { - ovs_fatal(0, "database socket is non-option argument; " - "use --help for usage"); + VLOG_FATAL("database socket is non-option argument; " + "use --help for usage"); } return argv[0];