Merge commit 'origin/citrix'
authorJustin Pettit <jpettit@nicira.com>
Sat, 12 Sep 2009 07:49:30 +0000 (00:49 -0700)
committerJustin Pettit <jpettit@nicira.com>
Sat, 12 Sep 2009 07:49:30 +0000 (00:49 -0700)
Conflicts:
vswitchd/ovs-vswitchd.8.in
vswitchd/ovs-vswitchd.conf.5.in
xenserver/etc_init.d_vswitch

1  2 
lib/automake.mk
lib/vconn.c
vswitchd/bridge.c
vswitchd/ovs-vswitchd.8.in
vswitchd/ovs-vswitchd.conf.5.in
xenserver/etc_init.d_vswitch

diff --combined lib/automake.mk
@@@ -32,11 -32,6 +32,11 @@@ lib_libopenvswitch_a_SOURCES = 
        lib/dhcp.h \
        lib/dhparams.h \
        lib/dirs.h \
 +      lib/dpif-linux.c \
 +      lib/dpif-netdev.c \
 +      lib/dpif-provider.h \
 +      lib/dpif.c \
 +      lib/dpif.h \
        lib/dynamic-string.c \
        lib/dynamic-string.h \
        lib/fatal-signal.c \
@@@ -57,8 -52,6 +57,8 @@@
        lib/list.h \
        lib/mac-learning.c \
        lib/mac-learning.h \
 +      lib/netdev-linux.c \
 +      lib/netdev-provider.h \
        lib/netdev.c \
        lib/netdev.h \
        lib/odp-util.c \
@@@ -82,8 -75,6 +82,8 @@@
        lib/random.h \
        lib/rconn.c \
        lib/rconn.h \
 +      lib/rtnetlink.c \
 +      lib/rtnetlink.h \
        lib/sat-math.h \
        lib/sha1.c \
        lib/sha1.h \
@@@ -126,6 -117,8 +126,6 @@@ CLEANFILES += $(nodist_lib_libopenvswit
  
  if HAVE_NETLINK
  lib_libopenvswitch_a_SOURCES += \
 -      lib/dpif.c \
 -      lib/dpif.h \
        lib/netlink-protocol.h \
        lib/netlink.c \
        lib/netlink.h
@@@ -155,6 -148,7 +155,7 @@@ EXTRA_DIST += 
        lib/daemon.man \
        lib/dpif.man \
        lib/leak-checker.man \
+       lib/vlog-unixctl.man \
        lib/vlog.man
  
  
@@@ -179,19 -173,17 +180,19 @@@ COVERAGE_FILES = 
        lib/hmap.c \
        lib/mac-learning.c \
        lib/netdev.c \
 +      lib/netdev-linux.c \
        lib/netlink.c \
        lib/odp-util.c \
        lib/poll-loop.c \
        lib/process.c \
        lib/rconn.c \
 +      lib/rtnetlink.c \
        lib/timeval.c \
        lib/unixctl.c \
        lib/util.c \
        lib/vconn.c \
 -      secchan/ofproto.c \
 -      secchan/pktbuf.c \
 +      ofproto/ofproto.c \
 +      ofproto/pktbuf.c \
        vswitchd/bridge.c \
        vswitchd/mgmt.c \
        vswitchd/ovs-brcompatd.c
diff --combined lib/vconn.c
@@@ -139,12 -139,12 +139,12 @@@ vconn_usage(bool active, bool passive, 
  
      if (passive) {
          printf("Passive OpenFlow connection methods:\n");
 -        printf("  ptcp:[PORT]             "
 -               "listen to TCP PORT (default: %d)\n",
 +        printf("  ptcp:[PORT][:IP]        "
 +               "listen to TCP PORT (default: %d) on IP\n",
                 OFP_TCP_PORT);
  #ifdef HAVE_OPENSSL
 -        printf("  pssl:[PORT]             "
 -               "listen for SSL on PORT (default: %d)\n",
 +        printf("  pssl:[PORT][:IP]        "
 +               "listen for SSL on PORT (default: %d) on IP\n",
                 OFP_SSL_PORT);
  #endif
          printf("  punix:FILE              "
@@@ -364,7 -364,7 +364,7 @@@ vcs_recv_hello(struct vconn *vconn
  
      if (retval != EAGAIN) {
          vconn->state = VCS_DISCONNECTED;
 -        vconn->error = retval;
 +        vconn->error = retval == EOF ? ECONNRESET : retval;
      }
  }
  
@@@ -458,7 -458,10 +458,7 @@@ vconn_recv(struct vconn *vconn, struct 
  static int
  do_recv(struct vconn *vconn, struct ofpbuf **msgp)
  {
 -    int retval;
 -
 -again:
 -    retval = (vconn->class->recv)(vconn, msgp);
 +    int retval = (vconn->class->recv)(vconn, msgp);
      if (!retval) {
          struct ofp_header *oh;
  
              && oh->type != OFPT_VENDOR)
          {
              if (vconn->version < 0) {
 -                if (oh->type == OFPT_PACKET_IN
 -                    || oh->type == OFPT_FLOW_EXPIRED
 -                    || oh->type == OFPT_PORT_STATUS) {
 -                    /* The kernel datapath is stateless and doesn't really
 -                     * support version negotiation, so it can end up sending
 -                     * these asynchronous message before version negotiation
 -                     * is complete.  Just ignore them.
 -                     *
 -                     * (After we move OFPT_PORT_STATUS messages from the kernel
 -                     * into secchan, we won't get those here, since secchan
 -                     * does proper version negotiation.) */
 -                    ofpbuf_delete(*msgp);
 -                    goto again;
 -                }
                  VLOG_ERR_RL(&bad_ofmsg_rl,
                              "%s: received OpenFlow message type %"PRIu8" "
                              "before version negotiation complete",
@@@ -1230,7 -1247,7 +1230,7 @@@ check_action(const union ofp_action *a
  {
      int error;
  
-     switch (a->type) {
+     switch (ntohs(a->type)) {
      case OFPAT_OUTPUT:
          error = check_action_port(ntohs(a->output.port), max_ports);
          if (error) {
diff --combined vswitchd/bridge.c
  #include "odp-util.h"
  #include "ofp-print.h"
  #include "ofpbuf.h"
 +#include "ofproto/ofproto.h"
  #include "packets.h"
  #include "poll-loop.h"
  #include "port-array.h"
  #include "proc-net-compat.h"
  #include "process.h"
 -#include "secchan/ofproto.h"
  #include "socket-util.h"
  #include "stp.h"
  #include "svec.h"
@@@ -71,18 -71,17 +71,18 @@@ struct dst 
  extern uint64_t mgmt_id;
  
  struct iface {
 +    /* These members are always valid. */
      struct port *port;          /* Containing port. */
      size_t port_ifidx;          /* Index within containing port. */
 -
      char *name;                 /* Host network device name. */
 -    int dp_ifidx;               /* Index within kernel datapath. */
 -
 -    uint8_t mac[ETH_ADDR_LEN];  /* Ethernet address (all zeros if unknowns). */
 -
      tag_type tag;               /* Tag associated with this interface. */
 -    bool enabled;               /* May be chosen for flows? */
      long long delay_expires;    /* Time after which 'enabled' may change. */
 +
 +    /* These members are valid only after bridge_reconfigure() causes them to
 +     * be initialized.*/
 +    int dp_ifidx;               /* Index within kernel datapath. */
 +    struct netdev *netdev;      /* Network device. */
 +    bool enabled;               /* May be chosen for flows? */
  };
  
  #define BOND_MASK 0xff
@@@ -160,7 -159,7 +160,7 @@@ struct bridge 
      struct ofproto *ofproto;    /* OpenFlow switch. */
  
      /* Kernel datapath information. */
 -    struct dpif dpif;           /* Kernel datapath. */
 +    struct dpif *dpif;          /* Datapath. */
      struct port_array ifaces;   /* Indexed by kernel datapath port number. */
  
      /* Bridge ports. */
@@@ -203,11 -202,10 +203,11 @@@ static void bridge_fetch_dp_ifaces(stru
  static void bridge_flush(struct bridge *);
  static void bridge_pick_local_hw_addr(struct bridge *,
                                        uint8_t ea[ETH_ADDR_LEN],
 -                                      const char **devname);
 +                                      struct iface **hw_addr_iface);
  static uint64_t bridge_pick_datapath_id(struct bridge *,
                                          const uint8_t bridge_ea[ETH_ADDR_LEN],
 -                                        const char *devname);
 +                                        struct iface *hw_addr_iface);
 +static struct iface *bridge_get_local_iface(struct bridge *);
  static uint64_t dpid_from_hash(const void *, size_t nbytes);
  
  static void bridge_unixctl_fdb_show(struct unixctl_conn *, const char *args);
@@@ -227,7 -225,6 +227,7 @@@ static struct port *port_from_dp_ifidx(
                                         uint16_t dp_ifidx);
  static void port_update_bond_compat(struct port *);
  static void port_update_vlan_compat(struct port *);
 +static void port_update_bonding(struct port *);
  
  static void mirror_create(struct bridge *, const char *name);
  static void mirror_destroy(struct mirror *);
@@@ -266,8 -263,8 +266,8 @@@ bridge_get_ifaces(struct svec *svec
              for (j = 0; j < port->n_ifaces; j++) {
                  struct iface *iface = port->ifaces[j];
                  if (iface->dp_ifidx < 0) {
 -                    VLOG_ERR("%s interface not in dp%u, ignoring",
 -                             iface->name, dpif_id(&br->dpif));
 +                    VLOG_ERR("%s interface not in datapath %s, ignoring",
 +                             iface->name, dpif_name(br->dpif));
                  } else {
                      if (iface->dp_ifidx != ODPP_LOCAL) {
                          svec_add(svec, iface->name);
  void
  bridge_init(void)
  {
 -    int retval;
 -    int i;
 -
 -    bond_init();
 +    struct svec dpif_names;
 +    size_t i;
  
      unixctl_command_register("fdb/show", bridge_unixctl_fdb_show);
  
 -    for (i = 0; i < DP_MAX; i++) {
 -        struct dpif dpif;
 -        char devname[16];
 +    svec_init(&dpif_names);
 +    dp_enumerate(&dpif_names);
 +    for (i = 0; i < dpif_names.n; i++) {
 +        const char *dpif_name = dpif_names.names[i];
 +        struct dpif *dpif;
 +        int retval;
  
 -        sprintf(devname, "dp%d", i);
 -        retval = dpif_open(devname, &dpif);
 +        retval = dpif_open(dpif_name, &dpif);
          if (!retval) {
 -            char dpif_name[IF_NAMESIZE];
 -            if (dpif_get_name(&dpif, dpif_name, sizeof dpif_name)
 -                || !cfg_has("bridge.%s.port", dpif_name)) {
 -                dpif_delete(&dpif);
 +            struct svec all_names;
 +            size_t j;
 +
 +            svec_init(&all_names);
 +            dpif_get_all_names(dpif, &all_names);
 +            for (j = 0; j < all_names.n; j++) {
 +                if (cfg_has("bridge.%s.port", all_names.names[j])) {
 +                    goto found;
 +                }
              }
 -            dpif_close(&dpif);
 -        } else if (retval != ENODEV) {
 -            VLOG_ERR("failed to delete datapath dp%d: %s",
 -                     i, strerror(retval));
 +            dpif_delete(dpif);
 +        found:
 +            svec_destroy(&all_names);
 +            dpif_close(dpif);
          }
      }
  
      unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows);
  
 +    bond_init();
      bridge_reconfigure();
  }
  
@@@ -357,105 -348,43 +357,105 @@@ bridge_configure_ssl(void
       * the old certificate will still be trusted until vSwitch is
       * restarted.  We may want to address this in vconn's SSL library. */
      if (config_string_change("ssl.ca-cert", &cacert_file)
 -            || (stat(cacert_file, &s) && errno == ENOENT)) {
 +        || (cacert_file && stat(cacert_file, &s) && errno == ENOENT)) {
          vconn_ssl_set_ca_cert_file(cacert_file,
                                     cfg_get_bool(0, "ssl.bootstrap-ca-cert"));
      }
  }
  #endif
  
 +/* iterate_and_prune_ifaces() callback function that opens the network device
 + * for 'iface', if it is not already open, and retrieves the interface's MAC
 + * address and carrier status. */
 +static bool
 +init_iface_netdev(struct bridge *br UNUSED, struct iface *iface,
 +                  void *aux UNUSED)
 +{
 +    if (iface->netdev) {
 +        return true;
 +    } else if (!netdev_open(iface->name, NETDEV_ETH_TYPE_NONE,
 +                            &iface->netdev)) {
 +        netdev_get_carrier(iface->netdev, &iface->enabled);
 +        return true;
 +    } else {
 +        /* If the network device can't be opened, then we're not going to try
 +         * to do anything with this interface. */
 +        return false;
 +    }
 +}
 +
 +static bool
 +check_iface_dp_ifidx(struct bridge *br, struct iface *iface, void *aux UNUSED)
 +{
 +    if (iface->dp_ifidx >= 0) {
 +        VLOG_DBG("%s has interface %s on port %d",
 +                 dpif_name(br->dpif),
 +                 iface->name, iface->dp_ifidx);
 +        return true;
 +    } else {
 +        VLOG_ERR("%s interface not in %s, dropping",
 +                 iface->name, dpif_name(br->dpif));
 +        return false;
 +    }
 +}
 +
 +static bool
 +set_iface_policing(struct bridge *br UNUSED, struct iface *iface,
 +                   void *aux UNUSED)
 +{
 +    int rate = cfg_get_int(0, "port.%s.ingress.policing-rate", iface->name);
 +    int burst = cfg_get_int(0, "port.%s.ingress.policing-burst", iface->name);
 +    netdev_set_policing(iface->netdev, rate, burst);
 +    return true;
 +}
 +
 +/* Calls 'cb' for each interfaces in 'br', passing along the 'aux' argument.
 + * Deletes from 'br' all the interfaces for which 'cb' returns false, and then
 + * deletes from 'br' any ports that no longer have any interfaces. */
 +static void
 +iterate_and_prune_ifaces(struct bridge *br,
 +                         bool (*cb)(struct bridge *, struct iface *,
 +                                    void *aux),
 +                         void *aux)
 +{
 +    size_t i, j;
 +
 +    for (i = 0; i < br->n_ports; ) {
 +        struct port *port = br->ports[i];
 +        for (j = 0; j < port->n_ifaces; ) {
 +            struct iface *iface = port->ifaces[j];
 +            if (cb(br, iface, aux)) {
 +                j++;
 +            } else {
 +                iface_destroy(iface);
 +            }
 +        }
 +
 +        if (port->n_ifaces) {
 +            i++;
 +        } else  {
 +            VLOG_ERR("%s port has no interfaces, dropping", port->name);
 +            port_destroy(port);
 +        }
 +    }
 +}
 +
  void
  bridge_reconfigure(void)
  {
 -    struct svec old_br, new_br, raw_new_br;
 +    struct svec old_br, new_br;
      struct bridge *br, *next;
 -    size_t i, j;
 +    size_t i;
  
      COVERAGE_INC(bridge_reconfigure);
  
 -    /* Collect old bridges. */
 +    /* Collect old and new bridges. */
      svec_init(&old_br);
 +    svec_init(&new_br);
      LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
          svec_add(&old_br, br->name);
      }
 -
 -    /* Collect new bridges. */
 -    svec_init(&raw_new_br);
 -    cfg_get_subsections(&raw_new_br, "bridge");
 -    svec_init(&new_br);
 -    for (i = 0; i < raw_new_br.n; i++) {
 -        const char *name = raw_new_br.names[i];
 -        if ((!strncmp(name, "dp", 2) && isdigit(name[2])) ||
 -            (!strncmp(name, "nl:", 3) && isdigit(name[3]))) {
 -            VLOG_ERR("%s is not a valid bridge name (bridges may not be "
 -                     "named \"dp\" or \"nl:\" followed by a digit)", name);
 -        } else {
 -            svec_add(&new_br, name);
 -        }
 -    }
 -    svec_destroy(&raw_new_br);
 +    cfg_get_subsections(&new_br, "bridge");
  
      /* Get rid of deleted bridges and add new bridges. */
      svec_sort(&old_br);
          size_t n_dpif_ports;
          struct svec want_ifaces;
  
 -        dpif_port_list(&br->dpif, &dpif_ports, &n_dpif_ports);
 +        dpif_port_list(br->dpif, &dpif_ports, &n_dpif_ports);
          bridge_get_all_ifaces(br, &want_ifaces);
          for (i = 0; i < n_dpif_ports; i++) {
              const struct odp_port *p = &dpif_ports[i];
              if (!svec_contains(&want_ifaces, p->devname)
                  && strcmp(p->devname, br->name)) {
 -                int retval = dpif_port_del(&br->dpif, p->port);
 +                int retval = dpif_port_del(br->dpif, p->port);
                  if (retval) {
 -                    VLOG_ERR("failed to remove %s interface from dp%u: %s",
 -                             p->devname, dpif_id(&br->dpif), strerror(retval));
 +                    VLOG_ERR("failed to remove %s interface from %s: %s",
 +                             p->devname, dpif_name(br->dpif),
 +                             strerror(retval));
                  }
              }
          }
          struct odp_port *dpif_ports;
          size_t n_dpif_ports;
          struct svec cur_ifaces, want_ifaces, add_ifaces;
 -        int next_port_no;
  
 -        dpif_port_list(&br->dpif, &dpif_ports, &n_dpif_ports);
 +        dpif_port_list(br->dpif, &dpif_ports, &n_dpif_ports);
          svec_init(&cur_ifaces);
          for (i = 0; i < n_dpif_ports; i++) {
              svec_add(&cur_ifaces, dpif_ports[i].devname);
          bridge_get_all_ifaces(br, &want_ifaces);
          svec_diff(&want_ifaces, &cur_ifaces, &add_ifaces, NULL, NULL);
  
 -        next_port_no = 1;
          for (i = 0; i < add_ifaces.n; i++) {
              const char *if_name = add_ifaces.names[i];
 -            for (;;) {
 -                bool internal;
 -                int error;
 -
 -                /* It's an internal interface if it's marked that way, or if
 -                 * it's a bonded interface for which we're faking up a network
 -                 * device. */
 -                internal = cfg_get_bool(0, "iface.%s.internal", if_name);
 -                if (cfg_get_bool(0, "bonding.%s.fake-iface", if_name)) {
 -                    struct port *port = port_lookup(br, if_name);
 -                    if (port && port->n_ifaces > 1) {
 -                        internal = true;
 -                    }
 -                }
 +            bool internal;
 +            int error;
  
 -                /* Add to datapath. */
 -                error = dpif_port_add(&br->dpif, if_name, next_port_no++,
 -                                      internal ? ODP_PORT_INTERNAL : 0);
 -                if (error != EEXIST) {
 -                    if (next_port_no >= 256) {
 -                        VLOG_ERR("ran out of valid port numbers on dp%u",
 -                                 dpif_id(&br->dpif));
 -                        goto out;
 -                    }
 -                    if (error) {
 -                        VLOG_ERR("failed to add %s interface to dp%u: %s",
 -                                 if_name, dpif_id(&br->dpif), strerror(error));
 -                    }
 -                    break;
 +            /* It's an internal interface if it's marked that way, or if
 +             * it's a bonded interface for which we're faking up a network
 +             * device. */
 +            internal = cfg_get_bool(0, "iface.%s.internal", if_name);
 +            if (cfg_get_bool(0, "bonding.%s.fake-iface", if_name)) {
 +                struct port *port = port_lookup(br, if_name);
 +                if (port && port->n_ifaces > 1) {
 +                    internal = true;
                  }
              }
 +
 +            /* Add to datapath. */
 +            error = dpif_port_add(br->dpif, if_name,
 +                                  internal ? ODP_PORT_INTERNAL : 0, NULL);
 +            if (error == EFBIG) {
 +                VLOG_ERR("ran out of valid port numbers on %s",
 +                         dpif_name(br->dpif));
 +                break;
 +            } else if (error) {
 +                VLOG_ERR("failed to add %s interface to %s: %s",
 +                         if_name, dpif_name(br->dpif), strerror(error));
 +            }
          }
 -    out:
          svec_destroy(&cur_ifaces);
          svec_destroy(&want_ifaces);
          svec_destroy(&add_ifaces);
      LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
          uint8_t ea[8];
          uint64_t dpid;
 -        struct iface *local_iface = NULL;
 -        const char *devname;
 -        uint8_t engine_type = br->dpif.minor;
 -        uint8_t engine_id = br->dpif.minor;
 +        struct iface *local_iface;
 +        struct iface *hw_addr_iface;
 +        uint8_t engine_type, engine_id;
          bool add_id_to_iface = false;
          struct svec nf_hosts;
  
          bridge_fetch_dp_ifaces(br);
 -        for (i = 0; i < br->n_ports; ) {
 -            struct port *port = br->ports[i];
 +        iterate_and_prune_ifaces(br, init_iface_netdev, NULL);
  
 -            for (j = 0; j < port->n_ifaces; ) {
 -                struct iface *iface = port->ifaces[j];
 -                if (iface->dp_ifidx < 0) {
 -                    VLOG_ERR("%s interface not in dp%u, dropping",
 -                             iface->name, dpif_id(&br->dpif));
 -                    iface_destroy(iface);
 -                } else {
 -                    if (iface->dp_ifidx == ODPP_LOCAL) {
 -                        local_iface = iface;
 -                    }
 -                    VLOG_DBG("dp%u has interface %s on port %d",
 -                             dpif_id(&br->dpif), iface->name, iface->dp_ifidx);
 -                    j++;
 -                }
 -            }
 -            if (!port->n_ifaces) {
 -                VLOG_ERR("%s port has no interfaces, dropping", port->name);
 -                port_destroy(port);
 -                continue;
 -            }
 -            i++;
 -        }
 +        iterate_and_prune_ifaces(br, check_iface_dp_ifidx, NULL);
  
          /* Pick local port hardware address, datapath ID. */
 -        bridge_pick_local_hw_addr(br, ea, &devname);
 +        bridge_pick_local_hw_addr(br, ea, &hw_addr_iface);
 +        local_iface = bridge_get_local_iface(br);
          if (local_iface) {
 -            int error = netdev_nodev_set_etheraddr(local_iface->name, ea);
 +            int error = netdev_set_etheraddr(local_iface->netdev, ea);
              if (error) {
                  static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
                  VLOG_ERR_RL(&rl, "bridge %s: failed to set bridge "
              }
          }
  
 -        dpid = bridge_pick_datapath_id(br, ea, devname);
 +        dpid = bridge_pick_datapath_id(br, ea, hw_addr_iface);
          ofproto_set_datapath_id(br->ofproto, dpid);
  
          /* Set NetFlow configuration on this bridge. */
 +        dpif_get_netflow_ids(br->dpif, &engine_type, &engine_id);
          if (cfg_has("netflow.%s.engine-type", br->name)) {
              engine_type = cfg_get_int(0, "netflow.%s.engine-type", 
                      br->name);
          for (i = 0; i < br->n_ports; i++) {
              struct port *port = br->ports[i];
              port_update_vlan_compat(port);
 +            port_update_bonding(port);
          }
      }
      LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
          brstp_reconfigure(br);
 +        iterate_and_prune_ifaces(br, set_iface_policing, NULL);
      }
  }
  
  static void
  bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
 -                          const char **devname)
 +                          struct iface **hw_addr_iface)
  {
      uint64_t requested_ea;
      size_t i, j;
      int error;
  
 -    *devname = NULL;
 +    *hw_addr_iface = NULL;
  
      /* Did the user request a particular MAC? */
      requested_ea = cfg_get_mac(0, "bridge.%s.mac", br->name);
              for (j = 0; j < port->n_ifaces; j++) {
                  struct iface *candidate = port->ifaces[j];
                  uint8_t candidate_ea[ETH_ADDR_LEN];
 -                if (!netdev_nodev_get_etheraddr(candidate->name, candidate_ea)
 +                if (!netdev_get_etheraddr(candidate->netdev, candidate_ea)
                      && eth_addr_equals(iface_ea, candidate_ea)) {
                      iface = candidate;
                  }
              }
  
              /* Grab MAC. */
 -            error = netdev_nodev_get_etheraddr(iface->name, iface_ea);
 +            error = netdev_get_etheraddr(iface->netdev, iface_ea);
              if (error) {
                  static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
                  VLOG_ERR_RL(&rl, "failed to obtain Ethernet address of %s: %s",
              memcmp(iface_ea, ea, ETH_ADDR_LEN) < 0)
          {
              memcpy(ea, iface_ea, ETH_ADDR_LEN);
 -            *devname = iface ? iface->name : NULL;
 +            *hw_addr_iface = iface;
          }
      }
      if (eth_addr_is_multicast(ea) || eth_addr_is_vif(ea)) {
          memcpy(ea, br->default_ea, ETH_ADDR_LEN);
 -        *devname = NULL;
 +        *hw_addr_iface = NULL;
          VLOG_WARN("bridge %s: using default bridge Ethernet "
                    "address "ETH_ADDR_FMT, br->name, ETH_ADDR_ARGS(ea));
      } else {
  
  /* Choose and returns the datapath ID for bridge 'br' given that the bridge
   * Ethernet address is 'bridge_ea'.  If 'bridge_ea' is the Ethernet address of
 - * a network device, then that network device's name must be passed in as
 - * 'devname'; if 'bridge_ea' was derived some other way, then 'devname' must be
 - * passed in as a null pointer. */
 + * an interface on 'br', then that interface must be passed in as
 + * 'hw_addr_iface'; if 'bridge_ea' was derived some other way, then
 + * 'hw_addr_iface' must be passed in as a null pointer. */
  static uint64_t
  bridge_pick_datapath_id(struct bridge *br,
                          const uint8_t bridge_ea[ETH_ADDR_LEN],
 -                        const char *devname)
 +                        struct iface *hw_addr_iface)
  {
      /*
       * The procedure for choosing a bridge MAC address will, in the most
          return dpid;
      }
  
 -    if (devname) {
 +    if (hw_addr_iface) {
          int vlan;
 -        if (!netdev_get_vlan_vid(devname, &vlan)) {
 +        if (!netdev_get_vlan_vid(hw_addr_iface->netdev, &vlan)) {
              /*
               * A bridge whose MAC address is taken from a VLAN network device
               * (that is, a network device created with vconfig(8) or similar
@@@ -897,26 -853,6 +897,26 @@@ bridge_flush(struct bridge *br
          mac_learning_flush(br->ml);
      }
  }
 +
 +/* Returns the 'br' interface for the ODPP_LOCAL port, or null if 'br' has no
 + * such interface. */
 +static struct iface *
 +bridge_get_local_iface(struct bridge *br)
 +{
 +    size_t i, j;
 +
 +    for (i = 0; i < br->n_ports; i++) {
 +        struct port *port = br->ports[i];
 +        for (j = 0; j < port->n_ifaces; j++) {
 +            struct iface *iface = port->ifaces[j];
 +            if (iface->dp_ifidx == ODPP_LOCAL) {
 +                return iface;
 +            }
 +        }
 +    }
 +
 +    return NULL;
 +}
  \f
  /* Bridge unixctl user interface functions. */
  static void
@@@ -959,7 -895,7 +959,7 @@@ bridge_create(const char *name
      br = xcalloc(1, sizeof *br);
  
      error = dpif_create(name, &br->dpif);
 -    if (error == EEXIST) {
 +    if (error == EEXIST || error == EBUSY) {
          error = dpif_open(name, &br->dpif);
          if (error) {
              VLOG_ERR("datapath %s already exists but cannot be opened: %s",
              free(br);
              return NULL;
          }
 -        dpif_flow_flush(&br->dpif);
 +        dpif_flow_flush(br->dpif);
      } else if (error) {
          VLOG_ERR("failed to create datapath %s: %s", name, strerror(error));
          free(br);
      error = ofproto_create(name, &bridge_ofhooks, br, &br->ofproto);
      if (error) {
          VLOG_ERR("failed to create switch %s: %s", name, strerror(error));
 -        dpif_delete(&br->dpif);
 -        dpif_close(&br->dpif);
 +        dpif_delete(br->dpif);
 +        dpif_close(br->dpif);
          free(br);
          return NULL;
      }
  
      list_push_back(&all_bridges, &br->node);
  
 -    VLOG_INFO("created bridge %s on dp%u", br->name, dpif_id(&br->dpif));
 +    VLOG_INFO("created bridge %s on %s", br->name, dpif_name(br->dpif));
  
      return br;
  }
@@@ -1010,12 -946,12 +1010,12 @@@ bridge_destroy(struct bridge *br
              port_destroy(br->ports[br->n_ports - 1]);
          }
          list_remove(&br->node);
 -        error = dpif_delete(&br->dpif);
 +        error = dpif_delete(br->dpif);
          if (error && error != ENOENT) {
 -            VLOG_ERR("failed to delete dp%u: %s",
 -                     dpif_id(&br->dpif), strerror(error));
 +            VLOG_ERR("failed to delete %s: %s",
 +                     dpif_name(br->dpif), strerror(error));
          }
 -        dpif_close(&br->dpif);
 +        dpif_close(br->dpif);
          ofproto_destroy(br->ofproto);
          free(br->controller);
          mac_learning_destroy(br->ml);
@@@ -1107,29 -1043,13 +1107,29 @@@ bridge_get_controller(const struct brid
      return controller && controller[0] ? controller : NULL;
  }
  
 +static bool
 +check_duplicate_ifaces(struct bridge *br, struct iface *iface, void *ifaces_)
 +{
 +    struct svec *ifaces = ifaces_;
 +    if (!svec_contains(ifaces, iface->name)) {
 +        svec_add(ifaces, iface->name);
 +        svec_sort(ifaces);
 +        return true;
 +    } else {
 +        VLOG_ERR("bridge %s: %s interface is on multiple ports, "
 +                 "removing from %s",
 +                 br->name, iface->name, iface->port->name);
 +        return false;
 +    }
 +}
 +
  static void
  bridge_reconfigure_one(struct bridge *br)
  {
      struct svec old_ports, new_ports, ifaces;
      struct svec listeners, old_listeners;
      struct svec snoops, old_snoops;
 -    size_t i, j;
 +    size_t i;
  
      /* Collect old ports. */
      svec_init(&old_ports);
      svec_init(&new_ports);
      cfg_get_all_keys(&new_ports, "bridge.%s.port", br->name);
      svec_sort(&new_ports);
 -    if (bridge_get_controller(br) && !svec_contains(&new_ports, br->name)) {
 -        svec_add(&new_ports, br->name);
 -        svec_sort(&new_ports);
 +    if (bridge_get_controller(br)) {
 +        char local_name[IF_NAMESIZE];
 +        int error;
 +
 +        error = dpif_port_get_name(br->dpif, ODPP_LOCAL,
 +                                   local_name, sizeof local_name);
 +        if (!error && !svec_contains(&new_ports, local_name)) {
 +            svec_add(&new_ports, local_name);
 +            svec_sort(&new_ports);
 +        }
      }
      if (!svec_is_unique(&new_ports)) {
          VLOG_WARN("bridge %s: %s specified twice as bridge port",
  
      /* Check and delete duplicate interfaces. */
      svec_init(&ifaces);
 -    for (i = 0; i < br->n_ports; ) {
 -        struct port *port = br->ports[i];
 -        for (j = 0; j < port->n_ifaces; ) {
 -            struct iface *iface = port->ifaces[j];
 -            if (svec_contains(&ifaces, iface->name)) {
 -                VLOG_ERR("bridge %s: %s interface is on multiple ports, "
 -                         "removing from %s",
 -                         br->name, iface->name, port->name);
 -                iface_destroy(iface);
 -            } else {
 -                svec_add(&ifaces, iface->name);
 -                svec_sort(&ifaces);
 -                j++;
 -            }
 -        }
 -        if (!port->n_ifaces) {
 -            VLOG_ERR("%s port has no interfaces, dropping", port->name);
 -            port_destroy(port);
 -        } else {
 -            i++;
 -        }
 -    }
 +    iterate_and_prune_ifaces(br, check_duplicate_ifaces, &ifaces);
      svec_destroy(&ifaces);
  
      /* Delete all flows if we're switching from connected to standalone or vice
@@@ -1268,8 -1202,9 +1268,8 @@@ bridge_reconfigure_controller(struct br
                                    cfg_get_string(0, "%s.accept-regex", pfx),
                                    update_resolv_conf);
          } else {
 -            struct netdev *netdev;
 +            struct iface *local_iface;
              bool in_band;
 -            int error;
  
              in_band = (!cfg_is_valid(CFG_BOOL | CFG_REQUIRED,
                                       "%s.in-band", pfx)
              ofproto_set_discovery(br->ofproto, false, NULL, NULL);
              ofproto_set_in_band(br->ofproto, in_band);
  
 -            error = netdev_open(br->name, NETDEV_ETH_TYPE_NONE, &netdev);
 -            if (!error) {
 -                if (cfg_is_valid(CFG_IP | CFG_REQUIRED, "%s.ip", pfx)) {
 -                    struct in_addr ip, mask, gateway;
 -                    ip.s_addr = cfg_get_ip(0, "%s.ip", pfx);
 -                    mask.s_addr = cfg_get_ip(0, "%s.netmask", pfx);
 -                    gateway.s_addr = cfg_get_ip(0, "%s.gateway", pfx);
 -
 -                    netdev_turn_flags_on(netdev, NETDEV_UP, true);
 -                    if (!mask.s_addr) {
 -                        mask.s_addr = guess_netmask(ip.s_addr);
 -                    }
 -                    if (!netdev_set_in4(netdev, ip, mask)) {
 -                        VLOG_INFO("bridge %s: configured IP address "IP_FMT", "
 -                                  "netmask "IP_FMT,
 -                                  br->name, IP_ARGS(&ip.s_addr),
 -                                  IP_ARGS(&mask.s_addr));
 -                    }
 +            local_iface = bridge_get_local_iface(br);
 +            if (local_iface
 +                && cfg_is_valid(CFG_IP | CFG_REQUIRED, "%s.ip", pfx)) {
 +                struct netdev *netdev = local_iface->netdev;
 +                struct in_addr ip, mask, gateway;
 +                ip.s_addr = cfg_get_ip(0, "%s.ip", pfx);
 +                mask.s_addr = cfg_get_ip(0, "%s.netmask", pfx);
 +                gateway.s_addr = cfg_get_ip(0, "%s.gateway", pfx);
 +
 +                netdev_turn_flags_on(netdev, NETDEV_UP, true);
 +                if (!mask.s_addr) {
 +                    mask.s_addr = guess_netmask(ip.s_addr);
 +                }
 +                if (!netdev_set_in4(netdev, ip, mask)) {
 +                    VLOG_INFO("bridge %s: configured IP address "IP_FMT", "
 +                              "netmask "IP_FMT,
 +                              br->name, IP_ARGS(&ip.s_addr),
 +                              IP_ARGS(&mask.s_addr));
 +                }
  
 -                    if (gateway.s_addr) {
 -                        if (!netdev_add_router(gateway)) {
 -                            VLOG_INFO("bridge %s: configured gateway "IP_FMT,
 -                                      br->name, IP_ARGS(&gateway.s_addr));
 -                        }
 +                if (gateway.s_addr) {
 +                    if (!netdev_add_router(netdev, gateway)) {
 +                        VLOG_INFO("bridge %s: configured gateway "IP_FMT,
 +                                  br->name, IP_ARGS(&gateway.s_addr));
                      }
                  }
 -                netdev_close(netdev);
              }
          }
  
@@@ -1432,17 -1368,17 +1432,17 @@@ bridge_fetch_dp_ifaces(struct bridge *b
      }
      port_array_clear(&br->ifaces);
  
 -    dpif_port_list(&br->dpif, &dpif_ports, &n_dpif_ports);
 +    dpif_port_list(br->dpif, &dpif_ports, &n_dpif_ports);
      for (i = 0; i < n_dpif_ports; i++) {
          struct odp_port *p = &dpif_ports[i];
          struct iface *iface = iface_lookup(br, p->devname);
          if (iface) {
              if (iface->dp_ifidx >= 0) {
 -                VLOG_WARN("dp%u reported interface %s twice",
 -                          dpif_id(&br->dpif), p->devname);
 +                VLOG_WARN("%s reported interface %s twice",
 +                          dpif_name(br->dpif), p->devname);
              } else if (iface_from_dp_ifidx(br, p->port)) {
 -                VLOG_WARN("dp%u reported interface %"PRIu16" twice",
 -                          dpif_id(&br->dpif), p->port);
 +                VLOG_WARN("%s reported interface %"PRIu16" twice",
 +                          dpif_name(br->dpif), p->port);
              } else {
                  port_array_set(&br->ifaces, p->port, iface);
                  iface->dp_ifidx = p->port;
@@@ -1955,7 -1891,7 +1955,7 @@@ process_flow(struct bridge *br, const f
              goto done;
          } else {
              /* Drop all multicast packets for which we have learned a different
-              * input port, because we probably sent the packet on one slaves
+              * input port, because we probably sent the packet on one slave
               * and got it back on the active slave.  Broadcast ARP replies are
               * an exception to this rule: the host has moved to another
               * switch. */
@@@ -2054,6 -1990,7 +2054,6 @@@ bridge_port_changed_ofhook_cb(enum ofp_
  
          bridge_flush(br);
      } else {
 -        memcpy(iface->mac, opp->hw_addr, ETH_ADDR_LEN);
          if (port->n_ifaces > 1) {
              bool up = !(opp->state & OFPPS_LINK_DOWN);
              bond_link_status_update(iface, up);
@@@ -3045,7 -2982,7 +3045,7 @@@ port_update_bond_compat(struct port *po
          if (slave->up) {
              bond.up = true;
          }
 -        memcpy(slave->mac, iface->mac, ETH_ADDR_LEN);
 +        netdev_get_etheraddr(iface->netdev, slave->mac);
      }
  
      proc_net_compat_update_bond(port->name, &bond);
@@@ -3076,8 -3013,7 +3076,8 @@@ port_update_vlan_compat(struct port *po
                  && p->n_ifaces
                  && (!vlandev_name || strcmp(p->name, vlandev_name) <= 0))
              {
 -                const uint8_t *ea = p->ifaces[0]->mac;
 +                uint8_t ea[ETH_ADDR_LEN];
 +                netdev_get_etheraddr(p->ifaces[0]->netdev, ea);
                  if (!eth_addr_is_multicast(ea) &&
                      !eth_addr_is_reserved(ea) &&
                      !eth_addr_is_zero(ea)) {
@@@ -3103,7 -3039,18 +3103,7 @@@ iface_create(struct port *port, const c
      iface->dp_ifidx = -1;
      iface->tag = tag_create_random();
      iface->delay_expires = LLONG_MAX;
 -
 -    if (!cfg_get_bool(0, "iface.%s.internal", iface->name)) {
 -        netdev_nodev_get_etheraddr(name, iface->mac);
 -        netdev_nodev_get_carrier(name, &iface->enabled);
 -    } else {
 -        /* Internal interfaces are created later by the call to dpif_port_add()
 -         * in bridge_reconfigure().  Until then, we can't obtain any
 -         * information about them.  (There's no real value in doing so, anyway,
 -         * because the 'mac' and 'enabled' values are only used for interfaces
 -         * that are bond slaves, and it doesn't normally make sense to bond an
 -         * internal interface.) */
 -    }
 +    iface->netdev = NULL;
  
      if (port->n_ifaces >= port->allocated_ifaces) {
          port->ifaces = x2nrealloc(port->ifaces, &port->allocated_ifaces,
  
      VLOG_DBG("attached network device %s to port %s", iface->name, port->name);
  
 -    port_update_bonding(port);
      bridge_flush(port->bridge);
  }
  
@@@ -3135,7 -3083,6 +3135,7 @@@ iface_destroy(struct iface *iface
          del = port->ifaces[iface->port_ifidx] = port->ifaces[--port->n_ifaces];
          del->port_ifidx = iface->port_ifidx;
  
 +        netdev_close(iface->netdev);
          free(iface->name);
          free(iface);
  
              bond_send_learning_packets(port);
          }
  
 -        port_update_bonding(port);
          bridge_flush(port->bridge);
      }
  }
@@@ -3492,25 -3440,23 +3492,25 @@@ brstp_send_bpdu(struct ofpbuf *pkt, in
      if (!iface) {
          VLOG_WARN_RL(&rl, "%s: cannot send BPDU on unknown port %d",
                       br->name, port_no);
 -    } else if (eth_addr_is_zero(iface->mac)) {
 -        VLOG_WARN_RL(&rl, "%s: cannot send BPDU on port %d with unknown MAC",
 -                     br->name, port_no);
      } else {
 -        union ofp_action action;
          struct eth_header *eth = pkt->l2;
 -        flow_t flow;
  
 -        memcpy(eth->eth_src, iface->mac, ETH_ADDR_LEN);
 +        netdev_get_etheraddr(iface->netdev, eth->eth_src);
 +        if (eth_addr_is_zero(eth->eth_src)) {
 +            VLOG_WARN_RL(&rl, "%s: cannot send BPDU on port %d "
 +                         "with unknown MAC", br->name, port_no);
 +        } else {
 +            union ofp_action action;
 +            flow_t flow;
  
 -        memset(&action, 0, sizeof action);
 -        action.type = htons(OFPAT_OUTPUT);
 -        action.output.len = htons(sizeof action);
 -        action.output.port = htons(port_no);
 +            memset(&action, 0, sizeof action);
 +            action.type = htons(OFPAT_OUTPUT);
 +            action.output.len = htons(sizeof action);
 +            action.output.port = htons(port_no);
  
 -        flow_extract(pkt, ODPP_NONE, &flow);
 -        ofproto_send_packet(br->ofproto, &flow, &action, 1, pkt);
 +            flow_extract(pkt, ODPP_NONE, &flow);
 +            ofproto_send_packet(br->ofproto, &flow, &action, 1, pkt);
 +        }
      }
      ofpbuf_delete(pkt);
  }
@@@ -1,16 -1,22 +1,16 @@@
 -.\" -*- nroff -*-
 -.de IQ
 -.  br
 -.  ns
 -.  IP "\\$1"
 -..
 -.TH ovs\-vswitchd 8 "March 2009" "Open vSwitch" "Open vSwitch Manual"
 +.TH ovs\-vswitchd 8 "June 2009" "Open vSwitch" "Open vSwitch Manual"
  .ds PN ovs\-vswitchd
  .
  .SH NAME
 -ovs\-vswitchd \- virtual switch daemon
 +ovs\-vswitchd \- Open vSwitch daemon
  .
  .SH SYNOPSIS
  .B ovs\-vswitchd
  \fIconfig\fR
  .
  .SH DESCRIPTION
 -A daemon that manages and controls any number of virtual switches on
 -the local machine.
 +A daemon that manages and controls any number of Open vSwitch switches 
 +on the local machine.
  .PP
  The mandatory \fIconfig\fR argument specifies a configuration file.
  For a description of \fBovs\-vswitchd\fR configuration syntax, see
@@@ -22,8 -28,8 +22,8 @@@ operates switching across each bridge d
  files.  If a logfile was specified on the command line it will also 
  be opened or reopened.
  .PP
 -\fBovs\-vswitchd\fR virtual switches may be configured with any of the
 -following features:
 +\fBovs\-vswitchd\fR switches may be configured with any of the following 
 +features:
  .
  .IP \(bu
  L2 switching with MAC learning.
@@@ -46,7 -52,7 +46,7 @@@ Connectivity to an external OpenFlow co
  .
  .PP
  Only a single instance of \fBovs\-vswitchd\fR is intended to run at a time.
 -A single \fBovs\-vswitchd\fR can manage any number of virtual switches, up
 +A single \fBovs\-vswitchd\fR can manage any number of switch instances, up
  to the maximum number of supported Open vSwitch datapaths.
  .PP
  \fBovs\-vswitchd\fR does all the necessary management of Open vSwitch datapaths
@@@ -56,7 -62,7 +56,7 @@@ to modify datapaths when \fBovs\-vswitc
  its operation.  (\fBovs\-dpctl\fR may still be useful for diagnostics.)
  .PP
  An Open vSwitch datapath kernel module must be loaded for \fBovs\-vswitchd\fR
 -to be useful.  Please refer to the \fBINSTALL\fR file included in the
 +to be useful.  Please refer to the \fBINSTALL.Linux\fR file included in the
  Open vSwitch distribution for instructions on how to build and load
  the Open vSwitch kernel module.
  .PP
@@@ -73,15 -79,73 +73,73 @@@ to be loaded
  .so lib/common.man
  .so lib/leak-checker.man
  .
- .SH "BUGS"
+ .SH "RUNTIME MANAGEMENT COMMANDS"
+ \fBovs\-appctl\fR(8) can send commands to a running
+ \fBovs\-vswitchd\fR process.  The currently supported commands are
+ described below.  The command descriptions assume an understanding of
+ how to configure Open vSwitch, as described in
+ \fBovs-vswitchd.conf\fR(5).
+ .SS "OVS\-VSWITCHD COMMANDS"
+ These commands manage the \fBovs-vswitchd\fR process.
+ .IP "\fBvswitchd/reload\fR"
+ Reloads the \fBovs\-vswitchd\fR configuration file, as if a
+ \fBSIGHUP\fR signal were received.  The command completes only after
+ reloading is finished, in particular after all datapaths have been
+ created and destroyed and ports added and removed as specified by the
+ new configuration.
+ .SS "BRIDGE COMMANDS"
+ These commands manage bridges.
+ .IP "\fBfdb/show\fR \fIbridge\fR"
+ Lists each MAC address/VLAN pair learned by the specified \fIbridge\fR,
+ along with the port on which it was learned and the age of the entry,
+ in seconds.
+ .SS "BOND COMMANDS"
+ These commands manage bonded ports on an Open vSwitch's bridges.  To
+ understand some of these commands, it is important to understand a
+ detail of the bonding implementation called ``MAC hashing.''  Instead
+ of directly assigning Ethernet source addresses to slaves, the bonding
+ implementation computes a function that maps an 48-bit Ethernet source
+ addresses into an 8-bit value (a ``MAC hash'' value).  All of the
+ Ethernet addresses that map to a single 8-bit value are then assigned
+ to a single slave.
+ .IP "\fBbond/list\fR"
+ Lists all of the bonds, and their slaves, on each bridge.
  .
- Only Open vSwitch kernel-based datapaths are currently supported.  In the
- future, this restriction may be lifted.
- .PP
- Only Linux 2.6.\fIx\fR is currently supported.
+ .IP "\fBbond/show\fR \fIport\fR"
+ Lists all of the bond-specific information about the given bonded
+ \fIport\fR: updelay, downdelay, time until the next rebalance.  Also
+ lists information about each slave: whether it is enabled or disabled,
+ the time to completion of an updelay or downdelay if one is in
+ progress, whether it is the active slave, the MAC hashes assigned to
+ the slave, and the MAC learning table entries that hash to each MAC.
+ .IP "\fBbond/migrate\fR \fIport\fR \fIhash\fR \fIslave\fR"
+ Assigns a given MAC hash to a new slave.  \fIport\fR specifies the
+ bond port, \fIhash\fR either the MAC hash to be migrated (as a decimal
+ number between 0 and 255) or an Ethernet address to be hashed, and
+ \fIslave\fR the new slave to be assigned.
+ .IP
+ The reassignment is not permanent: rebalancing or fail-over will
+ cause the MAC hash to be shifted to a new slave in the usual
+ manner.
+ .IP
+ A MAC hash cannot be migrated to a disabled slave.
+ .IP "\fBbond/set-active-slave\fR \fIport\fR \fIslave\fR"
+ Sets \fIslave\fR as the active slave on \fIport\fR.  \fIslave\fR must
+ currently be enabled.
+ .IP
+ The setting is not permanent: a new active slave will be selected
+ if \fIslave\fR becomes disabled.
+ .IP "\fBbond/enable-slave\fR \fIport\fR \fIslave\fR"
+ .IQ "\fBbond/disable-slave\fR \fIport\fR \fIslave\fR"
+ Enables (or disables) \fIslave\fR on the given bond \fIport\fR, skipping any
+ updelay (or downdelay).
+ .IP
+ This setting is not permanent: it persists only until the carrier
+ status of \fIslave\fR changes.
  .
+ .so lib/vlog-unixctl.man
  .SH "SEE ALSO"
  .BR ovs\-appctl (8),
  .BR ovs\-vswitchd.conf (5),
  .BR ovs\-brcompatd (8),
 -\fBINSTALL\fR in the Open vSwitch distribution.
 +\fBINSTALL.Linux\fR in the Open vSwitch distribution.
  .  RE
  .  PP
  ..
 -.TH ovs\-vswitchd.conf 5 "April 2009" "Open vSwitch" "Open vSwitch Manual"
 +.TH ovs\-vswitchd.conf 5 "June 2009" "Open vSwitch" "Open vSwitch Manual"
  .
  .SH NAME
  ovs\-vswitchd.conf \- configuration file for \fBovs\-vswitchd\fR
  .
  .SH DESCRIPTION
  This manual page describes the syntax for the configuration file used 
 -by \fBovs\-vswitchd\fR(8), the virtual switch daemon.
 +by \fBovs\-vswitchd\fR(8), the Open vSwitch daemon.
  .PP
  The configuration file is based on key-value pairs, which are given
  one per line in the form \fIkey\fB=\fIvalue\fR.  Each \fIkey\fR
@@@ -50,13 -50,14 +50,13 @@@ configure \fBovs\-vswitchd\fR
  .SS "Bridge Configuration"
  A bridge (switch) with a given \fIname\fR is configured by specifying
  the names of its network devices as values for key
 -\fBbridge.\fIname\fB.port\fR.  (The specified \fIname\fR may not begin
 -with \fBdp\fR or \fBnl:\fR followed by a digit.)
 +\fBbridge.\fIname\fB.port\fR.
  .PP
  The names given on \fBbridge.\fIname\fB.port\fR must be the names of
  existing network devices, except for ``internal ports.''  An internal
  port is a simulated network device that receives traffic only
 -through the virtual switch and switches any traffic sent it through
 -virtual switch.  An internal port may configured with an IP address,
 +through the switch and switches any traffic sent it through the
 +switch.  An internal port may configured with an IP address,
  etc. using the usual system tools (e.g. \fBifconfig\fR, \fBip\fR).  To
  designate network device \fInetdev\fR as an internal port, add
  \fBiface.\fInetdev\fB.internal=true\fR to the configuration file.
@@@ -354,7 -355,7 +354,7 @@@ This can be overridden with the \fBnetf
  \fBnetflow.\fIbridge\fB.engine-id\fR, respectively.  Each takes a value
  between 0 and 255, inclusive. 
  
 -Many NetFlow collectors do not expect multiple virtual switches to be
 +Many NetFlow collectors do not expect multiple switches to be
  sending messages from the same host, and they do not store the engine
  information which could be used to disambiguate the traffic.  To prevent
  flows from multiple switches appearing as if they came on the interface,
@@@ -428,7 -429,7 +428,7 @@@ switch will perform all configured brid
  .TP
  \fBdiscover\fR
  Use controller discovery to find the local OpenFlow controller.
 -Refer to \fBsecchan\fR(8) for information on how to configure a DHCP
 +Refer to \fB\ovs\-openflowd\fR(8) for information on how to configure a DHCP
  server to support controller discovery.  The following additional
  options control the discovery process:
  .
@@@ -441,8 -442,8 +441,8 @@@ the regular expression will be accepted
  .IP
  The default regular expression is \fBssl:.*\fR, meaning that only SSL
  controller connections will be accepted, when SSL is configured (see
 -\fBSSL Configuration\fR), and \fB.*\fR otherwise, meaning that any
 -controller will be accepted.
 +\fBSSL Configuration\fR), and \fBtcp:.*\fR otherwise, meaning that only
 +TCP controller connections will be accepted.
  .IP
  The regular expression is implicitly anchored at the beginning of the
  controller location string, as if it begins with \fB^\fR.
@@@ -487,7 -488,7 +487,7 @@@ not in use, the following additional se
  By default, or if this is set to \fBtrue\fR, \fBovs\-vswitchd\fR connects
  to the controller in-band.  If this is set to \fBfalse\fR,
  \fBovs\-vswitchd\fR connects to the controller out-of-band.  Refer to
 -\fBsecchan\fR(8) for a description of in-band and out-of-band control.
 +\fBovs\-openflowd\fR(8) for a description of in-band and out-of-band control.
  .IP "\fBbridge.\fIname\fB.controller.ip=\fIip\fR"
  If specified, the IP address to configure on the bridge's local port.
  .IP "\fBbridge.\fIname\fB.controller.netmask=\fInetmask\fR"
@@@ -505,11 -506,11 +505,11 @@@ This optional setting may be set to \fI
  The minimum value of \fIsecs\fR is 5 seconds.  The default is taken
  from \fBmgmt.inactivity-probe\fR (see above).
  .IP
 -When the virtual switch is connected to the controller, it waits for a
 +When the switch is connected to the controller, it waits for a
  message to be received from the controller for \fIsecs\fR seconds
  before it sends a inactivity probe to the controller.  After sending
  the inactivity probe, if no response is received for an additional
 -\fIsecs\fR seconds, the secure channel assumes that the connection has
 +\fIsecs\fR seconds, \fBovs-vswitchd\fR assumes that the connection has
  been broken and attempts to reconnect.
  .IP
  Changing the inactivity probe interval also changes the interval
@@@ -517,13 -518,14 +517,14 @@@ before entering standalone mode (see be
  .IP "\fBbridge.\fIname\fB.controller.fail-mode=\fBstandalone\fR|\fBsecure\fR"
  .IQ "\fBmgmt.fail-mode=standalone\fR|\fBsecure\fR"
  When a controller is configured, it is, ordinarily, responsible for
 -setting up all flows on the virtual switch.  Thus, if the connection to
 +setting up all flows on the switch.  Thus, if the connection to
  the controller fails, no new network connections can be set up.  If
  the connection to the controller stays down long enough, no packets
  can pass through the switch at all.
  .IP
  The first of these that is set takes effect.
- If the value is \fBstandalone\fR, \fBovs\-vswitchd\fR will take over
+ If the value is \fBstandalone\fR, or if neither of these settings
+ is set, \fBovs\-vswitchd\fR will take over
  responsibility for setting up
  flows when no message has been received from the controller for three
  times the inactivity probe interval (see above).  In this mode,
@@@ -532,9 -534,8 +533,8 @@@ MAC-learning switch.  \fBovs\-vswitchd\
  to the controller in the background and, when the connection succeeds,
  it discontinues its standalone behavior.
  .IP
- If this option is set to \fBsecure\fR, or if neither of these settings
- is set, \fBovs\-vswitchd\fR will not set up flows on its own when the
- controller connection fails.
+ If this option is set to \fBsecure\fR, \fBovs\-vswitchd\fR will not
+ set up flows on its own when the controller connection fails.
  .IP "\fBbridge.\fIname\fB.controller.max-backoff=\fIsecs\fR"
  Sets the maximum time between attempts to connect to the controller to
  \fIsecs\fR, which must be at least 1.  The actual interval between
@@@ -542,7 -543,7 +542,7 @@@ connection attempts starts at 1 second 
  attempt until it reaches the maximum.  The default maximum backoff
  time is taken from \fBmgmt.max-backoff\fR.
  .ST "Controller Rate-Limiting"
 -These settings configure how the virtual switch applies a ``token
 +These settings configure how the switch applies a ``token
  bucket'' to limit the rate at which packets in unknown flows are
  forwarded to the OpenFlow controller for flow-setup processing.  This
  feature prevents a single bridge from overwhelming a controller.
@@@ -595,23 -596,24 +595,23 @@@ When \fBovs\-vswitchd\fR is configured 
  for controller connectivity, the following settings are required:
  .TP
  \fBssl.private-key=\fIprivkey.pem\fR
 -Specifies a PEM file containing the private key used as the virtual
 +Specifies a PEM file containing the private key used as the 
  switch's identity for SSL connections to the controller.
  .TP
  \fBssl.certificate=\fIcert.pem\fR
  Specifies a PEM file containing a certificate, signed by the
  certificate authority (CA) used by the controller and manager, that
 -certifies the virtual switch's private key, identifying a trustworthy
 +certifies the switch's private key, identifying a trustworthy
  switch.
  .TP
  \fBssl.ca-cert=\fIcacert.pem\fR
  Specifies a PEM file containing the CA certificate used to verify that
 -the virtual switch is connected to a trustworthy controller.
 +the switch is connected to a trustworthy controller.
  .PP
  These files are read only once, at \fBovs\-vswitchd\fR startup time.  If
  their contents change, \fBovs\-vswitchd\fR must be killed and restarted.
  .PP
 -These SSL settings apply to all SSL connections made by the virtual
 -switch.
 +These SSL settings apply to all SSL connections made by the switch.
  .ST "CA Certificate Bootstrap"
  Ordinarily, all of the files named in the SSL configuration must exist
  when \fBovs\-vswitchd\fR starts.  However, if \fBssl.bootstrap-ca-cert\fR
@@@ -649,11 -651,8 +649,11 @@@ Listens for connections on the Unix dom
  Listens for SSL connections on \fIport\fR (default: 6633).  SSL must
  be configured when this form is used (see \fBSSL Configuration\fR,
  above).
 -.IP "\fBptcp:\fR[\fIport\fR]"
 +.IP "\fBptcp:\fR[\fIport\fR][\fB:\fIip\fR]"
  Listens for TCP connections on \fIport\fR (default: 6633).
 +By default, \fB\ovs\-vswitchd\fR listens for connections to any local
 +IP address, but \fIip\fR may be specified to limit connections to the
 +specified local \fIip\fR.
  .RE
  To entirely disable listening for management connections, set
  \fBbridge.\fIname\fB.openflow.listeners\fR to the single value
  test -e /etc/sysconfig/vswitch && . /etc/sysconfig/vswitch
  
  # General config variables in /etc/sysconfig/vswitch
 -VSWITCH_BASE="${VSWITCH_BASE:-/root/vswitch}"
 -ENABLE_BRCOMPAT="${ENABLE_BRCOMPAT:-y}"
 -ENABLE_FAKE_PROC_NET="${ENABLE_FAKE_PROC_NET:-y}"
 -FORCE_COREFILES="${FORCE_COREFILES:-y}"
 +: ${ENABLE_BRCOMPAT:=y}
 +: ${ENABLE_FAKE_PROC_NET:=y}
 +: ${FORCE_COREFILES:=y}
  
  # Config variables specific to ovs-vswitchd
 -VSWITCHD_CONF="${VSWITCHD_CONF:-/etc/ovs-vswitchd.conf}"
 -VSWITCHD_PIDFILE="${VSWITCHD_PIDFILE:-/var/run/ovs-vswitchd.pid}"
 -VSWITCHD_RUN_DIR="${VSWITCHD_RUN_DIR:-/var/xen/vswitch}"
 -VSWITCHD_PRIORITY="${VSWITCHD_PRIORITY:--10}"
 -VSWITCHD_LOGFILE="${VSWITCHD_LOGFILE:-/var/log/ovs-vswitchd.log}"
 -VSWITCHD_FILE_LOGLEVEL="${VSWITCHD_FILE_LOGLEVEL:-INFO}"
 -VSWITCHD_SYSLOG_LOGLEVEL="${VSWITCHD_SYSLOG_LOGLEVEL:-ERR}"
 -VSWITCHD_MEMLEAK_LOGFILE="${VSWITCHD_MEMLEAK_LOGFILE:-}"
 -VSWITCHD_STRACE_LOG="${VSWITCHD_STRACE_LOG:-}"
 -VSWITCHD_STRACE_OPT="${VSWITCHD_STRACE_OPT:-}"
 -VSWITCHD_VALGRIND_LOG="${VSWITCHD_VALGRIND_LOG:-}"
 -VSWITCHD_VALGRIND_OPT="${VSWITCHD_VALGRIND_OPT:-}"
 +: ${VSWITCHD_CONF:=/etc/ovs-vswitchd.conf}
 +: ${VSWITCHD_PIDFILE:=/var/run/ovs-vswitchd.pid}
 +: ${VSWITCHD_RUN_DIR:=/var/xen/vswitch}
 +: ${VSWITCHD_PRIORITY:=-10}
 +: ${VSWITCHD_LOGFILE:=/var/log/ovs-vswitchd.log}
- : ${VSWITCHD_FILE_LOGLEVEL:=}
- : ${VSWITCHD_SYSLOG_LOGLEVEL:=WARN}
++: ${VSWITCHD_FILE_LOGLEVEL:=INFO}
++: ${VSWITCHD_SYSLOG_LOGLEVEL:=ERR}
 +: ${VSWITCHD_MEMLEAK_LOGFILE:=}
 +: ${VSWITCHD_STRACE_LOG:=}
 +: ${VSWITCHD_STRACE_OPT:=}
 +: ${VSWITCHD_VALGRIND_LOG:=}
 +: ${VSWITCHD_VALGRIND_OPT:=}
  
  # Config variables specific to ovs-brcompatd
 -BRCOMPATD_PIDFILE="${BRCOMPATD_PIDFILE:-/var/run/ovs-brcompatd.pid}"
 -BRCOMPATD_RUN_DIR="${BRCOMPATD_RUN_DIR:-/var/xen/vswitch}"
 -BRCOMPATD_PRIORITY="${BRCOMPATD_PRIORITY:--10}"
 -BRCOMPATD_LOGFILE="${BRCOMPATD_LOGFILE:-/var/log/ovs-brcompatd.log}"
 -BRCOMPATD_FILE_LOGLEVEL="${BRCOMPATD_FILE_LOGLEVEL:-INFO}"
 -BRCOMPATD_SYSLOG_LOGLEVEL="${BRCOMPATD_SYSLOG_LOGLEVEL:-ERR}"
 -BRCOMPATD_MEMLEAK_LOGFILE="${BRCOMPATD_MEMLEAK_LOGFILE:-}"
 -BRCOMPATD_STRACE_LOG="${BRCOMPATD_STRACE_LOG:-}"
 -BRCOMPATD_STRACE_OPT="${BRCOMPATD_STRACE_OPT:-}"
 -BRCOMPATD_VALGRIND_LOG="${BRCOMPATD_VALGRIND_LOG:-}"
 -BRCOMPATD_VALGRIND_OPT="${BRCOMPATD_VALGRIND_OPT:-}"
 -
 -
 -
 +: ${BRCOMPATD_PIDFILE:=/var/run/ovs-brcompatd.pid}
 +: ${BRCOMPATD_RUN_DIR:=/var/xen/vswitch}
 +: ${BRCOMPATD_PRIORITY:=-10}
 +: ${BRCOMPATD_LOGFILE:=/var/log/ovs-brcompatd.log}
- : ${BRCOMPATD_FILE_LOGLEVEL:=}
- : ${BRCOMPATD_SYSLOG_LOGLEVEL:=INFO}
++: ${BRCOMPATD_FILE_LOGLEVEL:=INFO}
++: ${BRCOMPATD_SYSLOG_LOGLEVEL:=ERR}
 +: ${BRCOMPATD_MEMLEAK_LOGFILE:=}
 +: ${BRCOMPATD_STRACE_LOG:=}
 +: ${BRCOMPATD_STRACE_OPT:=}
 +: ${BRCOMPATD_VALGRIND_LOG:=}
 +: ${BRCOMPATD_VALGRIND_OPT:=}
  
  # Full paths to executables & modules
 -vswitchd="$VSWITCH_BASE/sbin/ovs-vswitchd"
 -brcompatd="$VSWITCH_BASE/sbin/ovs-brcompatd"
 -dpctl="$VSWITCH_BASE/bin/ovs-dpctl"
 -appctl="$VSWITCH_BASE/bin/ovs-appctl"
 -ofctl="$VSWITCH_BASE/bin/ovs-ofctl"
 +vswitchd="/usr/sbin/ovs-vswitchd"
 +brcompatd="/usr/sbin/ovs-brcompatd"
 +dpctl="/usr/bin/ovs-dpctl"
 +appctl="/usr/bin/ovs-appctl"
 +ofctl="/usr/bin/ovs-ofctl"
  
  
  if [ "$ENABLE_FAKE_PROC_NET" = "y" ]; then
@@@ -87,10 -91,10 +87,10 @@@ function remove_all_dp 
  function insert_modules_if_required {
      if ! lsmod | grep -q "openvswitch_mod"; then
          action "Inserting llc module" modprobe llc
 -        action "Inserting openvswitch module" insmod $VSWITCH_BASE/kernel_modules/openvswitch_mod.ko
 +        action "Inserting openvswitch module" modprobe openvswitch_mod
      fi
      if [ -n "$BRCOMPATD_PIDFILE" ] && ! lsmod | grep -q "brcompat_mod"; then
 -        action "Inserting brcompat module" insmod $VSWITCH_BASE/kernel_modules/brcompat_mod.ko
 +        action "Inserting brcompat module" modprobe brcompat_mod
      fi
  }
  
@@@ -111,6 -115,13 +111,13 @@@ function reload_vswitchd 
      fi
  }
  
+ function reload_brcompatd {
+     if [ -f "$BRCOMPATD_PIDFILE" ]; then
+         "$appctl" \
+             --target=ovs-brcompatd.$(cat "$BRCOMPATD_PIDFILE").ctl --reopen
+     fi
+ }
  function start_vswitchd {
      local syslog_opt="-vANY:SYSLOG:${VSWITCHD_SYSLOG_LOGLEVEL}"
      local logfile_file_opt=""
@@@ -165,7 -176,7 +172,7 @@@ function start_brcompatd 
          mkdir -p "$BRCOMPATD_RUN_DIR"
      fi
      cd "$BRCOMPATD_RUN_DIR"
-     if [ -n "$BRCOMPATD_FILE_LOGLEVEL" ]; then
+     if [ -n "$BRCOMPATD_FILE_LOGLEVEL" ]; then
          logfile_level_opt="-vANY:FILE:${BRCOMPATD_FILE_LOGLEVEL}"
          logfile_file_opt="--log-file=$BRCOMPATD_LOGFILE"
      fi
@@@ -288,6 -299,7 +295,7 @@@ case "$1" i
          ;;
      reload)
          reload_vswitchd
+         reload_brcompatd
          ;;
      strace-vswitchd)
          shift
          status -p ovs-brcompatd.pid ovs-brcompatd
          ;;
      version)
 -        "$VSWITCH_BASE"/sbin/ovs-vswitchd -V
 -        "$VSWITCH_BASE"/sbin/ovs-brcompatd -V
 +        /usr/sbin/ovs-vswitchd -V
 +        /usr/sbin/ovs-brcompatd -V
          ;;
      help)
          printf "vswitch [start|stop|restart|reload|unload|status|version]\n"