Merge branch 'master' into next
authorJustin Pettit <jpettit@nicira.com>
Fri, 5 Feb 2010 23:58:27 +0000 (15:58 -0800)
committerJustin Pettit <jpettit@nicira.com>
Sat, 6 Feb 2010 01:14:55 +0000 (17:14 -0800)
Conflicts:
COPYING
datapath/datapath.h
lib/automake.mk
lib/dpif-provider.h
lib/dpif.c
lib/hmap.h
lib/netdev-provider.h
lib/netdev.c
lib/stream-ssl.h
ofproto/executer.c
ofproto/ofproto.c
ofproto/ofproto.h
tests/automake.mk
utilities/ovs-ofctl.c
utilities/ovs-vsctl.in
vswitchd/ovs-vswitchd.conf.5.in
xenserver/etc_init.d_vswitch
xenserver/etc_xensource_scripts_vif
xenserver/opt_xensource_libexec_interface-reconfigure

38 files changed:
1  2 
COPYING
acinclude.m4
configure.ac
datapath/actions.c
datapath/datapath.c
datapath/datapath.h
lib/automake.mk
lib/dpif-linux.c
lib/dpif-netdev.c
lib/dpif-provider.h
lib/dpif.c
lib/dpif.h
lib/hmap.h
lib/netdev-provider.h
lib/netdev.c
lib/netdev.h
lib/stream-ssl.h
lib/vlog-modules.def
ofproto/automake.mk
ofproto/ofproto-sflow.c
ofproto/ofproto.c
ofproto/ofproto.h
tests/automake.mk
tests/library.at
utilities/automake.mk
utilities/ovs-discover.c
utilities/ovs-dpctl.c
utilities/ovs-ofctl.c
vswitchd/automake.mk
vswitchd/bridge.c
vswitchd/ovs-vswitchd.8.in
vswitchd/vswitch-idl.ann
vswitchd/vswitch.ovsschema
xenserver/etc_init.d_vswitch
xenserver/etc_init.d_vswitch-xapi-update
xenserver/etc_xensource_scripts_vif
xenserver/opt_xensource_libexec_InterfaceReconfigureVswitch.py
xenserver/vswitch-xen.spec

diff --combined COPYING
+++ b/COPYING
@@@ -23,26 -23,6 +23,30 @@@ Files under the xenserver directory ar
  basis.  Some files are under an uncertain license that may not be
  DFSG-compliant or GPL-compatible.  Refer to each file for details.
  
 +The files under ovsdb/simplejson are covered by the following license:
 +
 +    Copyright (c) 2006 Bob Ippolito
 +
 +    Permission is hereby granted, free of charge, to any person
 +    obtaining a copy of this software and associated documentation
 +    files (the "Software"), to deal in the Software without
 +    restriction, including without limitation the rights to use, copy,
 +    modify, merge, publish, distribute, sublicense, and/or sell copies
 +    of the Software, and to permit persons to whom the Software is
 +    furnished to do so, subject to the following conditions:
 +
 +    The above copyright notice and this permission notice shall be
 +    included in all copies or substantial portions of the Software.
 +
 +    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 +    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 +    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 +    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 +    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 +    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 +    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 +    DEALINGS IN THE SOFTWARE.
++
+ Files lib/sflow*.[ch] are licensed under the terms of the InMon sFlow
+ licence that is available at:
+         http://www.inmon.com/technology/sflowlicense.txt
diff --combined acinclude.m4
@@@ -42,14 -42,7 +42,14 @@@ AC_DEFUN([OVS_CHECK_LINUX26], 
      AC_MSG_CHECKING([for Linux 2.6 source directory])
      KSRC26=$KBUILD26
      if test ! -e $KSRC26/include/linux/kernel.h; then
 -      KSRC26=`(cd $KBUILD26 && pwd -P) | sed 's,-[[^-]]*$,-common,'`
 +      case `echo "$KBUILD26" | sed 's,/*$,,'` in # (
 +        */build)
 +          KSRC26=`echo "$KBUILD26" | sed 's,/build/*$,/source,'`
 +          ;; # (
 +        *)
 +          KSRC26=`(cd $KBUILD26 && pwd -P) | sed 's,-[[^-]]*$,-common,'`
 +          ;;
 +      esac
        if test ! -e $KSRC26/include/linux/kernel.h; then
          AC_MSG_ERROR([cannot find source directory])
        fi
@@@ -118,16 -111,6 +118,16 @@@ AC_DEFUN([OVS_CHECK_VETH], 
    fi
  ])
  
 +AC_DEFUN([OVS_CHECK_GRE], [
 +  AC_MSG_CHECKING([whether to build gre module])
 +  if test "$sublevel" -ge 18; then
 +    AC_MSG_RESULT([yes])
 +    AC_SUBST([BUILD_GRE], 1)
 +  else
 +    AC_MSG_RESULT([no])
 +  fi
 +])
 +
  AC_DEFUN([OVS_CHECK_LOG2_H], [
    AC_MSG_CHECKING([for $KSRC26/include/linux/log2.h])
    if test -e $KSRC26/include/linux/log2.h; then
@@@ -146,8 -129,6 +146,8 @@@ AC_DEFUN([OVS_CHECK_LINUX26_COMPAT], 
    rm -f datapath/linux-2.6/kcompat.h.new
    mkdir -p datapath/linux-2.6
    : > datapath/linux-2.6/kcompat.h.new
 +  OVS_GREP_IFELSE([$KSRC26/include/linux/types.h], [bool],
 +                  [OVS_DEFINE([HAVE_BOOL_TYPE])])
    OVS_GREP_IFELSE([$KSRC26/include/linux/skbuff.h], [skb_transport_header],
                    [OVS_DEFINE([HAVE_SKBUFF_HEADER_HELPERS])])
    OVS_GREP_IFELSE([$KSRC26/include/linux/skbuff.h], [raw],
                    [OVS_DEFINE([HAVE_CSUM_UNFOLD])])
    OVS_GREP_IFELSE([$KSRC26/include/linux/skbuff.h], [skb_cow],
                    [OVS_DEFINE([HAVE_SKB_COW])])
 +  OVS_GREP_IFELSE([$KSRC26/include/net/netlink.h], [nla_get_be16],
 +                  [OVS_DEFINE([HAVE_NLA_GET_BE16])])
 +  OVS_GREP_IFELSE([$KSRC26/include/linux/in.h], [ipv4_is_multicast],
 +                  [OVS_DEFINE([HAVE_IPV4_IS_MULTICAST])])
    # Check for the proto_data_valid member in struct sk_buff.  The [^@]
    # is necessary because some versions of this header remove the
    # member but retain the kerneldoc comment that describes it (which
                    [OVS_DEFINE([HAVE_PROTO_DATA_VALID])])
    OVS_CHECK_LOG2_H
    OVS_CHECK_VETH
 +  OVS_CHECK_GRE
    if cmp -s datapath/linux-2.6/kcompat.h.new \
              datapath/linux-2.6/kcompat.h >/dev/null 2>&1; then
      rm datapath/linux-2.6/kcompat.h.new
@@@ -215,6 -191,7 +215,7 @@@ AC_DEFUN([OVS_CHECK_STRTOK_R]
                             char *token1, *token2;
                             token1 = strtok_r(string, ":", &save_ptr);
                             token2 = strtok_r(NULL, ":", &save_ptr);
+                            freopen ("/dev/null", "w", stdout);
                             printf ("%s %s\n", token1, token2);
                             return 0;
                            ]])],
@@@ -259,4 -236,14 +260,14 @@@ dnl Example: OVS_ENABLE_OPTION([-Wdecla
  AC_DEFUN([OVS_ENABLE_OPTION], 
    [OVS_CHECK_CC_OPTION([$1], [WARNING_FLAGS="$WARNING_FLAGS $1"])
     AC_SUBST([WARNING_FLAGS])])
+ dnl OVS_CONDITIONAL_CC_OPTION([OPTION], [CONDITIONAL])
+ dnl Check whether the given C compiler OPTION is accepted.
+ dnl If so, enable the given Automake CONDITIONAL.
+ dnl Example: OVS_CONDITIONAL_CC_OPTION([-Wno-unused], [HAVE_WNO_UNUSED])
+ AC_DEFUN([OVS_CONDITIONAL_CC_OPTION],
+   [OVS_CHECK_CC_OPTION(
+     [$1], [ovs_have_cc_option=yes], [ovs_have_cc_option=no])
+    AM_CONDITIONAL([$2], [test $ovs_have_cc_option = yes])])
  dnl ----------------------------------------------------------------------
diff --combined configure.ac
@@@ -1,4 -1,4 +1,4 @@@
 -# Copyright (c) 2008, 2009 Nicira Networks
 +# Copyright (c) 2008, 2009, 2010 Nicira Networks
  #
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
@@@ -13,7 -13,7 +13,7 @@@
  # limitations under the License.
  
  AC_PREREQ(2.63)
- AC_INIT(openvswitch, 0.90.6, ovs-bugs@openvswitch.org)
+ AC_INIT(openvswitch, 0.99.1, ovs-bugs@openvswitch.org)
  NX_BUILDNR
  AC_CONFIG_SRCDIR([datapath/datapath.c])
  AC_CONFIG_MACRO_DIR([m4])
@@@ -38,8 -38,6 +38,8 @@@ AC_USE_SYSTEM_EXTENSION
  AC_C_BIGENDIAN
  AC_SYS_LARGEFILE
  
 +AC_SEARCH_LIBS([pow], [m])
 +
  OVS_CHECK_COVERAGE
  OVS_CHECK_NDEBUG
  OVS_CHECK_NETLINK
@@@ -58,6 -56,7 +58,6 @@@ OVS_CHECK_MALLOC_HOOK
  OVS_CHECK_VALGRIND
  OVS_CHECK_TTY_LOCK_DIR
  OVS_CHECK_SOCKET_LIBS
 -OVS_CHECK_FAULT_LIBS
  
  AC_CHECK_FUNCS([strsignal])
  
@@@ -76,6 -75,7 +76,7 @@@ OVS_ENABLE_OPTION([-Wold-style-definiti
  OVS_ENABLE_OPTION([-Wmissing-prototypes])
  OVS_ENABLE_OPTION([-Wmissing-field-initializers])
  OVS_ENABLE_OPTION([-Wno-override-init])
+ OVS_CONDITIONAL_CC_OPTION([-Wno-unused], [HAVE_WNO_UNUSED])
  
  AC_ARG_VAR(KARCH, [Kernel Architecture String])
  AC_SUBST(KARCH)
@@@ -88,7 -88,4 +89,7 @@@ datapath/linux-2.6/Makefil
  datapath/linux-2.6/Makefile.main
  tests/atlocal])
  
 +dnl This makes sure that include/openflow gets created in the build directory.
 +AC_CONFIG_COMMANDS([include/openflow/openflow.h.stamp])
 +
  AC_OUTPUT
diff --combined datapath/actions.c
@@@ -213,43 -213,10 +213,43 @@@ static void update_csum(__sum16 *sum, s
                        __be32 from, __be32 to, int pseudohdr)
  {
        __be32 diff[] = { ~from, to };
 -      if (skb->ip_summed != CHECKSUM_PARTIAL) {
 +
 +/* On older kernels, CHECKSUM_PARTIAL and CHECKSUM_COMPLETE are both defined
 + * as CHECKSUM_HW.  However, we can make some inferences so that we can update
 + * the checksums appropriately. */
 +      enum {
 +              CSUM_PARTIAL,   /* Partial checksum, skb->csum undefined. */
 +              CSUM_PACKET,    /* In-packet checksum, skb->csum undefined. */
 +              CSUM_COMPLETE,  /* In-packet checksum, skb->csum valid. */
 +      } csum_type;
 +
 +      csum_type = CSUM_PACKET;
 +#ifndef CHECKSUM_HW
 +      /* Newer kernel, just map between kernel types and ours. */
 +      if (skb->ip_summed == CHECKSUM_PARTIAL)
 +              csum_type = CSUM_PARTIAL;
 +      else if (skb->ip_summed == CHECKSUM_COMPLETE)
 +              csum_type = CSUM_COMPLETE;
 +#else
 +      /* In theory this could be either CHECKSUM_PARTIAL or CHECKSUM_COMPLETE.
 +       * However, we should only get CHECKSUM_PARTIAL packets from Xen, which
 +       * uses some special fields to represent this (see below).  Since we
 +       * can only make one type work, pick the one that actually happens in
 +       * practice. */
 +      if (skb->ip_summed == CHECKSUM_HW)
 +              csum_type = CSUM_COMPLETE;
 +#endif
 +#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
 +      /* Xen has a special way of representing CHECKSUM_PARTIAL on older
 +       * kernels. */
 +      if (skb->proto_csum_blank)
 +              csum_type = CSUM_PARTIAL;
 +#endif
 +
 +      if (csum_type != CSUM_PARTIAL) {
                *sum = csum_fold(csum_partial((char *)diff, sizeof(diff),
                                ~csum_unfold(*sum)));
 -              if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
 +              if (csum_type == CSUM_COMPLETE && pseudohdr)
                        skb->csum = ~csum_partial((char *)diff, sizeof(diff),
                                                ~skb->csum);
        } else if (pseudohdr)
@@@ -309,7 -276,7 +309,7 @@@ set_tp_port(struct sk_buff *skb, struc
                u16 old = *f;
                u16 new = a->tp_port;
                update_csum((u16*)(skb_transport_header(skb) + check_ofs), 
 -                              skb, old, new, 1);
 +                              skb, old, new, 0);
                *f = new;
        }
        return skb;
@@@ -335,7 -302,6 +335,7 @@@ int dp_xmit_skb(struct sk_buff *skb
                return -E2BIG;
        }
  
 +      forward_ip_summed(skb);
        dev_queue_xmit(skb);
  
        return len;
@@@ -400,6 -366,28 +400,28 @@@ output_control(struct datapath *dp, str
        return dp_output_control(dp, skb, _ODPL_ACTION_NR, arg);
  }
  
+ /* Send a copy of this packet up to the sFlow agent, along with extra
+  * information about what happened to it. */
+ static void sflow_sample(struct datapath *dp, struct sk_buff *skb,
+                        const union odp_action *a, int n_actions,
+                        gfp_t gfp, struct net_bridge_port *nbp)
+ {
+       struct odp_sflow_sample_header *hdr;
+       unsigned int actlen = n_actions * sizeof(union odp_action);
+       unsigned int hdrlen = sizeof(struct odp_sflow_sample_header);
+       struct sk_buff *nskb;
+       nskb = skb_copy_expand(skb, actlen + hdrlen, 0, gfp);
+       if (!nskb)
+               return;
+       memcpy(__skb_push(nskb, actlen), a, actlen);
+       hdr = (struct odp_sflow_sample_header*)__skb_push(nskb, hdrlen);
+       hdr->n_actions = n_actions;
+       hdr->sample_pool = atomic_read(&nbp->sflow_pool);
+       dp_output_control(dp, nskb, _ODPL_SFLOW_NR, 0);
+ }
  /* Execute a list of actions against 'skb'. */
  int execute_actions(struct datapath *dp, struct sk_buff *skb,
                    struct odp_flow_key *key,
         * is slightly obscure just to avoid that. */
        int prev_port = -1;
        int err;
+       if (dp->sflow_probability) {
+               struct net_bridge_port *p = skb->dev->br_port;
+               if (p) {
+                       atomic_inc(&p->sflow_pool);
+                       if (dp->sflow_probability == UINT_MAX ||
+                           net_random() < dp->sflow_probability)
+                               sflow_sample(dp, skb, a, n_actions, gfp, p);
+               }
+       }
        for (; n_actions > 0; a++, n_actions--) {
                WARN_ON_ONCE(skb_shared(skb));
                if (prev_port != -1) {
diff --combined datapath/datapath.c
@@@ -349,6 -349,7 +349,7 @@@ static int new_nbp(struct datapath *dp
        p->port_no = port_no;
        p->dp = dp;
        p->dev = dev;
+       atomic_set(&p->sflow_pool, 0);
        if (!is_dp_dev(dev))
                rcu_assign_pointer(dev->br_port, p);
        else {
@@@ -419,7 -420,6 +420,7 @@@ got_port_no
        if (err)
                goto out_put;
  
 +      set_dp_devs_mtu(dp, dev);
        dp_sysfs_add_if(dp->ports[port_no]);
  
        err = __put_user(port_no, &port.port);
@@@ -576,10 -576,9 +577,10 @@@ static int dp_frame_hook(struct net_bri
  #endif
  
  #if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
 -/* This code is copied verbatim from net/dev/core.c in Xen's
 - * linux-2.6.18-92.1.10.el5.xs5.0.0.394.644.  We can't call those functions
 - * directly because they aren't exported. */
 +/* This code is based on a skb_checksum_setup from net/dev/core.c from a
 + * combination of Lenny's 2.6.26 Xen kernel and Xen's
 + * linux-2.6.18-92.1.10.el5.xs5.0.0.394.644.  We can't call this function
 + * directly because it isn't exported in all versions. */
  static int skb_pull_up_to(struct sk_buff *skb, void *ptr)
  {
        if (ptr < (void *)skb->tail)
  
  int vswitch_skb_checksum_setup(struct sk_buff *skb)
  {
 -      if (skb->proto_csum_blank) {
 -              if (skb->protocol != htons(ETH_P_IP))
 -                      goto out;
 -              if (!skb_pull_up_to(skb, skb->nh.iph + 1))
 -                      goto out;
 -              skb->h.raw = (unsigned char *)skb->nh.iph + 4*skb->nh.iph->ihl;
 -              switch (skb->nh.iph->protocol) {
 -              case IPPROTO_TCP:
 -                      skb->csum = offsetof(struct tcphdr, check);
 -                      break;
 -              case IPPROTO_UDP:
 -                      skb->csum = offsetof(struct udphdr, check);
 -                      break;
 -              default:
 -                      if (net_ratelimit())
 -                              printk(KERN_ERR "Attempting to checksum a non-"
 -                                     "TCP/UDP packet, dropping a protocol"
 -                                     " %d packet", skb->nh.iph->protocol);
 -                      goto out;
 -              }
 -              if (!skb_pull_up_to(skb, skb->h.raw + skb->csum + 2))
 -                      goto out;
 -              skb->ip_summed = CHECKSUM_HW;
 -              skb->proto_csum_blank = 0;
 +      struct iphdr *iph;
 +      unsigned char *th;
 +      int err = -EPROTO;
 +      __u16 csum_start, csum_offset;
 +
 +      if (!skb->proto_csum_blank)
 +              return 0;
 +
 +      if (skb->protocol != htons(ETH_P_IP))
 +              goto out;
 +
 +      if (!skb_pull_up_to(skb, skb_network_header(skb) + 1))
 +              goto out;
 +
 +      iph = ip_hdr(skb);
 +      th = skb_network_header(skb) + 4 * iph->ihl;
 +
 +      csum_start = th - skb->head;
 +      switch (iph->protocol) {
 +      case IPPROTO_TCP:
 +              csum_offset = offsetof(struct tcphdr, check);
 +              break;
 +      case IPPROTO_UDP:
 +              csum_offset = offsetof(struct udphdr, check);
 +              break;
 +      default:
 +              if (net_ratelimit())
 +                      printk(KERN_ERR "Attempting to checksum a non-"
 +                             "TCP/UDP packet, dropping a protocol"
 +                             " %d packet", iph->protocol);
 +              goto out;
        }
 -      return 0;
 +
 +      if (!skb_pull_up_to(skb, th + csum_offset + 2))
 +              goto out;
 +
 +      skb->ip_summed = CHECKSUM_PARTIAL;
 +      skb->proto_csum_blank = 0;
 +
 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
 +      skb->csum_start = csum_start;
 +      skb->csum_offset = csum_offset;
 +#else
 +      skb_set_transport_header(skb, csum_start - skb_headroom(skb));
 +      skb->csum = csum_offset;
 +#endif
 +
 +      err = 0;
 +
  out:
 -      return -EPROTO;
 +      return err;
  }
- #else
- int vswitch_skb_checksum_setup(struct sk_buff *skb) { return 0; }
- #endif /* CONFIG_XEN && linux == 2.6.18 */
+ #endif /* CONFIG_XEN && HAVE_PROTO_DATA_VALID */
  
 + /* Types of checksums that we can receive (these all refer to L4 checksums):
 + * 1. CHECKSUM_NONE: Device that did not compute checksum, contains full
 + *    (though not verified) checksum in packet but not in skb->csum.  Packets
 + *    from the bridge local port will also have this type.
 + * 2. CHECKSUM_COMPLETE (CHECKSUM_HW): Good device that computes checksums,
 + *    also the GRE module.  This is the same as CHECKSUM_NONE, except it has
 + *    a valid skb->csum.  Importantly, both contain a full checksum (not
 + *    verified) in the packet itself.  The only difference is that if the
 + *    packet gets to L4 processing on this machine (not in DomU) we won't
 + *    have to recompute the checksum to verify.  Most hardware devices do not
 + *    produce packets with this type, even if they support receive checksum
 + *    offloading (they produce type #5).
 + * 3. CHECKSUM_PARTIAL (CHECKSUM_HW): Packet without full checksum and needs to
 + *    be computed if it is sent off box.  Unfortunately on earlier kernels,
 + *    this case is impossible to distinguish from #2, despite having opposite
 + *    meanings.  Xen adds an extra field on earlier kernels (see #4) in order
 + *    to distinguish the different states.  The only real user of this type
 + *    with bridging is Xen (on later kernels).
 + * 4. CHECKSUM_UNNECESSARY (with proto_csum_blank true): This packet was
 + *    generated locally by a Xen DomU and has a partial checksum.  If it is
 + *    handled on this machine (Dom0 or DomU), then the checksum will not be
 + *    computed.  If it goes off box, the checksum in the packet needs to
 + *    completed.  Calling skb_checksum_setup converts this to CHECKSUM_HW
 + *    (CHECKSUM_PARTIAL) so that the checksum can be completed.  In later
 + *    kernels, this combination is replaced with CHECKSUM_PARTIAL.
 + * 5. CHECKSUM_UNNECESSARY (with proto_csum_blank false): Packet with a correct
 + *    full checksum or using a protocol without a checksum.  skb->csum is
 + *    undefined.  This is common from devices with receive checksum
 + *    offloading.  This is somewhat similar to CHECKSUM_NONE, except that
 + *    nobody will try to verify the checksum with CHECKSUM_UNNECESSARY.
 + *
 + * Note that on earlier kernels, CHECKSUM_COMPLETE and CHECKSUM_PARTIAL are
 + * both defined as CHECKSUM_HW.  Normally the meaning of CHECKSUM_HW is clear
 + * based on whether it is on the transmit or receive path.  After the datapath
 + * it will be intepreted as CHECKSUM_PARTIAL.  If the packet already has a
 + * checksum, we will panic.  Since we can receive packets with checksums, we
 + * assume that all CHECKSUM_HW packets have checksums and map them to
 + * CHECKSUM_NONE, which has a similar meaning (the it is only different if the
 + * packet is processed by the local IP stack, in which case it will need to
 + * be reverified).  If we receive a packet with CHECKSUM_HW that really means
 + * CHECKSUM_PARTIAL, it will be sent with the wrong checksum.  However, there
 + * shouldn't be any devices that do this with bridging.
 + *
 + * The bridge has similar behavior and this function closely resembles
 + * skb_forward_csum().  It is slightly different because we are only concerned
 + * with bridging and not other types of forwarding and can get away with
 + * slightly more optimal behavior.*/
 +void
 +forward_ip_summed(struct sk_buff *skb)
 +{
 +#ifdef CHECKSUM_HW
 +      if (skb->ip_summed == CHECKSUM_HW)
 +              skb->ip_summed = CHECKSUM_NONE;
 +#endif
 +}
 +
  /* Append each packet in 'skb' list to 'queue'.  There will be only one packet
   * unless we broke up a GSO packet. */
  static int
@@@ -796,15 -714,12 +795,14 @@@ dp_output_control(struct datapath *dp, 
        int err;
  
        WARN_ON_ONCE(skb_shared(skb));
-       BUG_ON(queue_no != _ODPL_MISS_NR && queue_no != _ODPL_ACTION_NR);
+       BUG_ON(queue_no != _ODPL_MISS_NR && queue_no != _ODPL_ACTION_NR && queue_no != _ODPL_SFLOW_NR);
        queue = &dp->queues[queue_no];
        err = -ENOBUFS;
        if (skb_queue_len(queue) >= DP_MAX_QUEUE_LEN)
                goto err_kfree_skb;
  
 +      forward_ip_summed(skb);
 +
        /* Break apart GSO packets into their component pieces.  Otherwise
         * userspace may try to stuff a 64kB packet into a 1500-byte MTU. */
        if (skb_is_gso(skb)) {
@@@ -1320,29 -1235,6 +1318,29 @@@ int dp_min_mtu(const struct datapath *d
        return mtu ? mtu : ETH_DATA_LEN;
  }
  
 +/* Sets the MTU of all datapath devices to the minimum of the ports. 'dev'
 + * is the device whose MTU may have changed.  Must be called with RTNL lock
 + * and dp_mutex. */
 +void set_dp_devs_mtu(const struct datapath *dp, struct net_device *dev)
 +{
 +      struct net_bridge_port *p;
 +      int mtu;
 +
 +      ASSERT_RTNL();
 +
 +      if (is_dp_dev(dev))
 +              return;
 +
 +      mtu = dp_min_mtu(dp);
 +
 +      list_for_each_entry_rcu (p, &dp->port_list, node) {
 +              struct net_device *br_dev = p->dev;
 +
 +              if (is_dp_dev(br_dev))
 +                      dev_set_mtu(br_dev, mtu);
 +      }
 +}
 +
  static int
  put_port(const struct net_bridge_port *p, struct odp_port __user *uop)
  {
@@@ -1499,6 -1391,7 +1497,7 @@@ static long openvswitch_ioctl(struct fi
        int dp_idx = iminor(f->f_dentry->d_inode);
        struct datapath *dp;
        int drop_frags, listeners, port_no;
+       unsigned int sflow_probability;
        int err;
  
        /* Handle commands with special locking requirements up front. */
                set_listen_mask(f, listeners);
                break;
  
+       case ODP_GET_SFLOW_PROBABILITY:
+               err = put_user(dp->sflow_probability, (unsigned int __user *)argp);
+               break;
+       case ODP_SET_SFLOW_PROBABILITY:
+               err = get_user(sflow_probability, (unsigned int __user *)argp);
+               if (!err)
+                       dp->sflow_probability = sflow_probability;
+               break;
        case ODP_PORT_QUERY:
                err = query_port(dp, (struct odp_port __user *)argp);
                break;
diff --combined datapath/datapath.h
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (c) 2009 Nicira Networks.
+  * Copyright (c) 2009, 2010 Nicira Networks.
   * Distributed under the terms of the GNU GPL version 2.
   *
   * Significant portions of this file may be copied from parts of the Linux
@@@ -79,9 -79,22 +79,22 @@@ struct dp_bucket 
        struct sw_flow *flows[];
  };
  
- #define DP_N_QUEUES 2
+ #define DP_N_QUEUES 3
  #define DP_MAX_QUEUE_LEN 100
  
+ /**
+  * struct dp_stats_percpu - per-cpu packet processing statistics for a given
+  * datapath.
+  * @n_frags: Number of IP fragments processed by datapath.
+  * @n_hit: Number of received packets for which a matching flow was found in
+  * the flow table.
+  * @n_miss: Number of received packets that had no matching flow in the flow
+  * table.  The sum of @n_hit and @n_miss is the number of packets that have
+  * been received by the datapath.
+  * @n_lost: Number of received packets that had no matching flow in the flow
+  * table that could not be sent to userspace (normally due to an overflow in
+  * one of the datapath's queues).
+  */
  struct dp_stats_percpu {
        u64 n_frags;
        u64 n_hit;
@@@ -95,10 -108,29 +108,29 @@@ struct dp_port_group 
        u16 ports[];
  };
  
+ /**
+  * struct datapath - datapath for flow-based packet switching
+  * @mutex: Mutual exclusion for ioctls.
+  * @dp_idx: Datapath number (index into the dps[] array in datapath.c).
+  * @ifobj: Represents /sys/class/net/<devname>/brif.
+  * @drop_frags: Drop all IP fragments if nonzero.
+  * @queues: %DP_N_QUEUES sets of queued packets for userspace to handle.
+  * @waitqueue: Waitqueue, for waiting for new packets in @queues.
+  * @n_flows: Number of flows currently in flow table.
+  * @table: Current flow table (RCU protected).
+  * @groups: Port groups, used by ODPAT_OUTPUT_GROUP action (RCU protected).
+  * @n_ports: Number of ports currently in @ports.
+  * @ports: Map from port number to &struct net_bridge_port.  %ODPP_LOCAL port
+  * always exists, other ports may be %NULL.
+  * @port_list: List of all ports in @ports in arbitrary order.
+  * @stats_percpu: Per-CPU datapath statistics.
+  * @sflow_probability: Number of packets out of UINT_MAX to sample to the
+  * %ODPL_SFLOW queue, e.g. (@sflow_probability/UINT_MAX) is the probability of
+  * sampling a given packet.
+  */
  struct datapath {
        struct mutex mutex;
        int dp_idx;
        struct kobject ifobj;
  
        int drop_frags;
        /* Switch ports. */
        unsigned int n_ports;
        struct net_bridge_port *ports[DP_MAX_PORTS];
-       struct list_head port_list; /* All ports, including local_port. */
+       struct list_head port_list;
  
        /* Stats. */
        struct dp_stats_percpu *stats_percpu;
+       /* sFlow Sampling */
+       unsigned int sflow_probability;
  };
  
+ /**
+  * struct net_bridge_port - one port within a datapath
+  * @port_no: Index into @dp's @ports array.
+  * @dp: Datapath to which this port belongs.
+  * @dev: The network device attached to this port.  The @br_port member in @dev
+  * points back to this &struct net_bridge_port.
+  * @kobj: Represents /sys/class/net/<devname>/brport.
+  * @linkname: The name of the link from /sys/class/net/<datapath>/brif to this
+  * &struct net_bridge_port.  (We keep this around so that we can delete it
+  * if @dev gets renamed.)  Set to the null string when no link exists.
+  * @node: Element in @dp's @port_list.
+  * @sflow_pool: Number of packets that were candidates for sFlow sampling,
+  * regardless of whether they were actually chosen and sent down to userspace.
+  */
  struct net_bridge_port {
        u16 port_no;
        struct datapath *dp;
        struct net_device *dev;
        struct kobject kobj;
        char linkname[IFNAMSIZ];
-       struct list_head node;   /* Element in datapath.ports. */
+       struct list_head node;
+       atomic_t sflow_pool;
  };
  
  extern struct notifier_block dp_device_notifier;
@@@ -151,7 -201,6 +201,7 @@@ void dp_process_received_packet(struct 
  int dp_del_port(struct net_bridge_port *);
  int dp_output_control(struct datapath *, struct sk_buff *, int, u32 arg);
  int dp_min_mtu(const struct datapath *dp);
 +void set_dp_devs_mtu(const struct datapath *dp, struct net_device *dev);
  
  struct datapath *get_dp(int dp_idx);
  
@@@ -160,16 -209,13 +210,15 @@@ static inline const char *dp_name(cons
        return dp->ports[ODPP_LOCAL]->dev->name;
  }
  
- #ifdef CONFIG_XEN
- int skb_checksum_setup(struct sk_buff *skb);
+ #if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
+ int vswitch_skb_checksum_setup(struct sk_buff *skb);
  #else
- static inline int skb_checksum_setup(struct sk_buff *skb)
+ static inline int vswitch_skb_checksum_setup(struct sk_buff *skb)
  {
        return 0;
  }
  #endif
  
- int vswitch_skb_checksum_setup(struct sk_buff *skb);
 +void forward_ip_summed(struct sk_buff *skb);
 +
  #endif /* datapath.h */
diff --combined lib/automake.mk
@@@ -1,4 -1,4 +1,4 @@@
- # Copyright (C) 2009 Nicira Networks, Inc.
+ # Copyright (C) 2009, 2010 Nicira Networks, Inc.
  #
  # Copying and distribution of this file, with or without modification,
  # are permitted in any medium without royalty provided the copyright
@@@ -8,14 -8,12 +8,14 @@@
  noinst_LIBRARIES += lib/libopenvswitch.a
  
  lib_libopenvswitch_a_SOURCES = \
 +      lib/aes128.c \
 +      lib/aes128.h \
        lib/backtrace.c \
        lib/backtrace.h \
        lib/bitmap.c \
        lib/bitmap.h \
 -      lib/cfg.c \
 -      lib/cfg.h \
 +      lib/byteq.c \
 +      lib/byteq.h \
        lib/classifier.c \
        lib/classifier.h \
        lib/command-line.c \
        lib/dynamic-string.h \
        lib/fatal-signal.c \
        lib/fatal-signal.h \
 -      lib/fault.c \
 -      lib/fault.h \
        lib/flow.c \
        lib/flow.h \
        lib/hash.c \
        lib/hash.h \
        lib/hmap.c \
        lib/hmap.h \
 +      lib/json.c \
 +      lib/json.h \
 +      lib/jsonrpc.c \
 +      lib/jsonrpc.h \
        lib/leak-checker.c \
        lib/leak-checker.h \
        lib/learning-switch.c \
        lib/learning-switch.h \
        lib/list.c \
        lib/list.h \
 +      lib/lockfile.c \
 +      lib/lockfile.h \
        lib/mac-learning.c \
        lib/mac-learning.h \
        lib/netdev-linux.c \
        lib/ofp-print.h \
        lib/ofpbuf.c \
        lib/ofpbuf.h \
 +      lib/ovsdb-data.c \
 +      lib/ovsdb-data.h \
 +      lib/ovsdb-error.c \
 +      lib/ovsdb-error.h \
 +      lib/ovsdb-idl-provider.h \
 +      lib/ovsdb-idl.c \
 +      lib/ovsdb-idl.h \
 +      lib/ovsdb-parser.c \
 +      lib/ovsdb-parser.h \
 +      lib/ovsdb-types.c \
 +      lib/ovsdb-types.h \
        lib/packets.c \
        lib/packets.h \
        lib/pcap.c \
        lib/random.h \
        lib/rconn.c \
        lib/rconn.h \
 +      lib/reconnect.c \
 +      lib/reconnect.h \
        lib/rtnetlink.c \
        lib/rtnetlink.h \
        lib/sat-math.h \
        lib/signals.h \
        lib/socket-util.c \
        lib/socket-util.h \
 +      lib/sort.c \
 +      lib/sort.h \
        lib/stp.c \
        lib/stp.h \
 +      lib/stream-fd.c \
 +      lib/stream-fd.h \
 +      lib/stream-provider.h \
 +      lib/stream-ssl.h \
 +      lib/stream-tcp.c \
 +      lib/stream-unix.c \
 +      lib/stream.c \
 +      lib/stream.h \
+       lib/string.h \
        lib/svec.c \
        lib/svec.h \
        lib/tag.c \
        lib/timeval.c \
        lib/timeval.h \
        lib/type-props.h \
 +      lib/unicode.c \
 +      lib/unicode.h \
        lib/unixctl.c \
        lib/unixctl.h \
        lib/util.c \
        lib/util.h \
 +      lib/uuid.c \
 +      lib/uuid.h \
        lib/valgrind.h \
        lib/vconn-provider.h \
 -      lib/vconn-ssl.h \
        lib/vconn-stream.c \
 -      lib/vconn-stream.h \
 -      lib/vconn-tcp.c \
 -      lib/vconn-unix.c \
        lib/vconn.c \
        lib/vconn.h \
        lib/vlog-modules.def \
@@@ -154,6 -126,19 +155,19 @@@ nodist_lib_libopenvswitch_a_SOURCES = 
        lib/dirs.c
  CLEANFILES += $(nodist_lib_libopenvswitch_a_SOURCES)
  
+ noinst_LIBRARIES += lib/libsflow.a
+ lib_libsflow_a_SOURCES = \
+       lib/sflow_api.h \
+       lib/sflow.h \
+       lib/sflow_agent.c \
+       lib/sflow_sampler.c \
+       lib/sflow_poller.c \
+       lib/sflow_receiver.c
+ lib_libsflow_a_CFLAGS = $(AM_CFLAGS)
+ if HAVE_WNO_UNUSED
+ lib_libsflow_a_CFLAGS += -Wno-unused
+ endif
  if HAVE_NETLINK
  lib_libopenvswitch_a_SOURCES += \
        lib/netlink-protocol.h \
  endif
  
  if HAVE_OPENSSL
 -lib_libopenvswitch_a_SOURCES += \
 -      lib/vconn-ssl.c 
 +lib_libopenvswitch_a_SOURCES += lib/stream-ssl.c
  nodist_lib_libopenvswitch_a_SOURCES += lib/dhparams.c
  lib/dhparams.c: lib/dh1024.pem lib/dh2048.pem lib/dh4096.pem
        (echo '#include "lib/dhparams.h"' &&                            \
@@@ -181,20 -167,10 +195,20 @@@ EXTRA_DIST += 
  
  EXTRA_DIST += \
        lib/common.man \
 +      lib/common-syn.man \
        lib/daemon.man \
 +      lib/daemon-syn.man \
        lib/dpif.man \
        lib/leak-checker.man \
 +      lib/ssl-bootstrap.man \
 +      lib/ssl-bootstrap-syn.man \
 +      lib/ssl-peer-ca-cert.man \
 +      lib/ssl.man \
 +      lib/ssl-syn.man \
 +      lib/vconn-active.man \
 +      lib/vconn-passive.man \
        lib/vlog-unixctl.man \
 +      lib/vlog-syn.man \
        lib/vlog.man
  
  
@@@ -213,9 -189,9 +227,9 @@@ install-data-local
  
  # All the source files that have coverage counters.
  COVERAGE_FILES = \
 -      lib/cfg.c \
        lib/dpif.c \
        lib/flow.c \
 +      lib/lockfile.c \
        lib/hmap.c \
        lib/mac-learning.c \
        lib/netdev.c \
        lib/process.c \
        lib/rconn.c \
        lib/rtnetlink.c \
 +      lib/stream.c \
        lib/timeval.c \
        lib/unixctl.c \
        lib/util.c \
        ofproto/ofproto.c \
        ofproto/pktbuf.c \
        vswitchd/bridge.c \
 -      vswitchd/mgmt.c \
        vswitchd/ovs-brcompatd.c
  lib/coverage-counters.c: $(COVERAGE_FILES) lib/coverage-scan.pl
        (cd $(srcdir) && $(PERL) lib/coverage-scan.pl $(COVERAGE_FILES)) > $@.tmp
diff --combined lib/dpif-linux.c
@@@ -95,10 -95,10 +95,10 @@@ dpif_linux_enumerate(struct svec *all_d
          int retval;
  
          sprintf(devname, "dp%d", i);
 -        retval = dpif_open(devname, &dpif);
 +        retval = dpif_open(devname, "system", &dpif);
          if (!retval) {
              svec_add(all_dps, devname);
 -            dpif_close(dpif);
 +            dpif_uninit(dpif, true);
          } else if (retval != ENODEV && !error) {
              error = retval;
          }
  }
  
  static int
 -dpif_linux_open(const char *name UNUSED, char *suffix, bool create,
 +dpif_linux_open(const char *name, const char *type UNUSED, bool create,
                  struct dpif **dpifp)
  {
      int minor;
              && isdigit((unsigned char)name[2]) ? atoi(name + 2) : -1;
      if (create) {
          if (minor >= 0) {
 -            return create_minor(suffix, minor, dpifp);
 +            return create_minor(name, minor, dpifp);
          } else {
              /* Scan for unused minor number. */
              for (minor = 0; minor < ODP_MAX; minor++) {
 -                int error = create_minor(suffix, minor, dpifp);
 +                int error = create_minor(name, minor, dpifp);
                  if (error != EBUSY) {
                      return error;
                  }
          int error;
  
          if (minor < 0) {
 -            error = lookup_minor(suffix, &minor);
 +            error = lookup_minor(name, &minor);
              if (error) {
                  return error;
              }
                  VLOG_WARN("%s: probe returned unexpected error: %s",
                            dpif_name(*dpifp), strerror(error));
              }
 -            dpif_close(*dpifp);
 +            dpif_uninit(*dpifp, true);
              return error;
          }
  
@@@ -196,6 -196,7 +196,7 @@@ dpif_linux_delete(struct dpif *dpif_
  static int
  dpif_linux_get_stats(const struct dpif *dpif_, struct odp_stats *stats)
  {
+     memset(stats, 0, sizeof *stats);
      return do_ioctl(dpif_, ODP_DP_STATS, stats);
  }
  
@@@ -395,6 -396,19 +396,19 @@@ dpif_linux_recv_set_mask(struct dpif *d
      return do_ioctl(dpif_, ODP_SET_LISTEN_MASK, &listen_mask);
  }
  
+ static int
+ dpif_linux_get_sflow_probability(const struct dpif *dpif_,
+                                  uint32_t *probability)
+ {
+     return do_ioctl(dpif_, ODP_GET_SFLOW_PROBABILITY, probability);
+ }
+ static int
+ dpif_linux_set_sflow_probability(struct dpif *dpif_, uint32_t probability)
+ {
+     return do_ioctl(dpif_, ODP_SET_SFLOW_PROBABILITY, &probability);
+ }
  static int
  dpif_linux_recv(struct dpif *dpif_, struct ofpbuf **bufp)
  {
@@@ -446,7 -460,8 +460,7 @@@ dpif_linux_recv_wait(struct dpif *dpif_
  }
  
  const struct dpif_class dpif_linux_class = {
 -    "",                         /* This is the default class. */
 -    "linux",
 +    "system",
      NULL,
      NULL,
      dpif_linux_enumerate,
      dpif_linux_execute,
      dpif_linux_recv_get_mask,
      dpif_linux_recv_set_mask,
+     dpif_linux_get_sflow_probability,
+     dpif_linux_set_sflow_probability,
      dpif_linux_recv,
      dpif_linux_recv_wait,
  };
@@@ -554,13 -571,14 +570,14 @@@ make_openvswitch_device(int minor, cha
      struct stat s;
      char fn[128];
  
+     *fnp = NULL;
      major = get_openvswitch_major();
      if (major < 0) {
          return -major;
      }
      dev = makedev(major, minor);
  
-     *fnp = NULL;
      sprintf(fn, "%s/dp%d", dirname, minor);
      if (!stat(fn, &s)) {
          if (!S_ISCHR(s.st_mode)) {
@@@ -668,11 -686,11 +685,11 @@@ static in
  finish_open(struct dpif *dpif_, const char *local_ifname)
  {
      struct dpif_linux *dpif = dpif_linux_cast(dpif_);
 -    dpif->local_ifname = strdup(local_ifname);
 +    dpif->local_ifname = xstrdup(local_ifname);
      dpif->local_ifindex = if_nametoindex(local_ifname);
      if (!dpif->local_ifindex) {
          int error = errno;
 -        dpif_close(dpif_);
 +        dpif_uninit(dpif_, true);
          VLOG_WARN("could not get ifindex of %s device: %s",
                    local_ifname, strerror(errno));
          return error;
@@@ -689,7 -707,7 +706,7 @@@ create_minor(const char *name, int mino
          if (!error) {
              error = finish_open(*dpifp, name);
          } else {
 -            dpif_close(*dpifp);
 +            dpif_uninit(*dpifp, true);
          }
      }
      return error;
diff --combined lib/dpif-netdev.c
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Copyright (c) 2009 Nicira Networks.
 + * Copyright (c) 2009, 2010 Nicira Networks.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
@@@ -196,7 -196,7 +196,7 @@@ create_dpif_netdev(struct dp_netdev *dp
  
      dp->open_cnt++;
  
 -    dpname = xasprintf("netdev:dp%d", dp->dp_idx);
 +    dpname = xasprintf("dp%d", dp->dp_idx);
      dpif = xmalloc(sizeof *dpif);
      dpif_init(&dpif->dpif, &dpif_netdev_class, dpname, dp->dp_idx, dp->dp_idx);
      dpif->dp = dp;
@@@ -219,7 -219,7 +219,7 @@@ create_dp_netdev(const char *name, int 
      }
  
      /* Create datapath. */
 -    dp_netdevs[dp_idx] = dp = xcalloc(1, sizeof *dp);
 +    dp_netdevs[dp_idx] = dp = xzalloc(sizeof *dp);
      list_push_back(&dp_netdev_list, &dp->node);
      dp->dp_idx = dp_idx;
      dp->open_cnt = 0;
      error = do_add_port(dp, name, ODP_PORT_INTERNAL, ODPP_LOCAL);
      if (error) {
          dp_netdev_free(dp);
 -        return error;
 +        return ENODEV;
      }
  
      *dpifp = create_dpif_netdev(dp);
  }
  
  static int
 -dpif_netdev_open(const char *name UNUSED, char *suffix, bool create,
 +dpif_netdev_open(const char *name, const char *type UNUSED, bool create,
                   struct dpif **dpifp)
  {
      if (create) {
 -        if (find_dp_netdev(suffix)) {
 +        if (find_dp_netdev(name)) {
              return EEXIST;
          } else {
 -            int dp_idx = name_to_dp_idx(suffix);
 +            int dp_idx = name_to_dp_idx(name);
              if (dp_idx >= 0) {
 -                return create_dp_netdev(suffix, dp_idx, dpifp);
 +                return create_dp_netdev(name, dp_idx, dpifp);
              } else {
                  /* Scan for unused dp_idx number. */
                  for (dp_idx = 0; dp_idx < N_DP_NETDEVS; dp_idx++) {
 -                    int error = create_dp_netdev(suffix, dp_idx, dpifp);
 +                    int error = create_dp_netdev(name, dp_idx, dpifp);
                      if (error != EBUSY) {
                          return error;
                      }
              }
          }
      } else {
 -        struct dp_netdev *dp = find_dp_netdev(suffix);
 +        struct dp_netdev *dp = find_dp_netdev(name);
          if (dp) {
              *dpifp = create_dpif_netdev(dp);
              return 0;
@@@ -363,7 -363,6 +363,7 @@@ do_add_port(struct dp_netdev *dp, cons
  {
      bool internal = (flags & ODP_PORT_INTERNAL) != 0;
      struct dp_netdev_port *port;
 +    struct netdev_options netdev_options;
      struct netdev *netdev;
      int mtu;
      int error;
      /* XXX reject devices already in some dp_netdev. */
  
      /* Open and validate network device. */
 -    if (!internal) {
 -        error = netdev_open(devname, NETDEV_ETH_TYPE_ANY, &netdev);
 +    memset(&netdev_options, 0, sizeof netdev_options);
 +    netdev_options.name = devname;
 +    netdev_options.ethertype = NETDEV_ETH_TYPE_ANY;
 +    netdev_options.may_create = true;
 +    if (internal) {
 +        netdev_options.type = "tap";
      } else {
 -        error = netdev_create(devname, "tap", NULL);
 -        if (!error) {
 -            error = netdev_open(devname, NETDEV_ETH_TYPE_ANY, &netdev);
 -            if (error) {
 -                netdev_destroy(devname);
 -            }
 -        }
 +        netdev_options.may_open = true;
      }
 +
 +    error = netdev_open(&netdev_options, &netdev);
      if (error) {
          return error;
      }
@@@ -488,7 -487,9 +488,7 @@@ do_del_port(struct dp_netdev *dp, uint1
  
      name = xstrdup(netdev_get_name(port->netdev));
      netdev_close(port->netdev);
 -    if (port->internal) {
 -        netdev_destroy(name);
 -    }
 +
      free(name);
      free(port);
  
@@@ -803,7 -804,7 +803,7 @@@ add_flow(struct dpif *dpif, struct odp_
      struct dp_netdev_flow *flow;
      int error;
  
 -    flow = xcalloc(1, sizeof *flow);
 +    flow = xzalloc(sizeof *flow);
      flow->key = odp_flow->key;
      flow->key.reserved = 0;
  
@@@ -1303,6 -1304,7 +1303,6 @@@ dp_netdev_execute_actions(struct dp_net
  }
  
  const struct dpif_class dpif_netdev_class = {
 -    "netdev",
      "netdev",
      dp_netdev_run,
      dp_netdev_wait,
      dpif_netdev_execute,
      dpif_netdev_recv_get_mask,
      dpif_netdev_recv_set_mask,
+     NULL,                       /* get_sflow_probability */
+     NULL,                       /* set_sflow_probability */
      dpif_netdev_recv,
      dpif_netdev_recv_wait,
  };
diff --combined lib/dpif-provider.h
  #include <assert.h>
  #include "dpif.h"
  
+ #ifdef  __cplusplus
+ extern "C" {
+ #endif
  /* Open vSwitch datapath interface.
   *
   * This structure should be treated as opaque by dpif implementations. */
  struct dpif {
-     const struct dpif_class *class;
+     const struct dpif_class *dpif_class;
 -    char *name;
 +    char *base_name;
 +    char *full_name;
      uint8_t netflow_engine_type;
      uint8_t netflow_engine_id;
  };
  
  void dpif_init(struct dpif *, const struct dpif_class *, const char *name,
                 uint8_t netflow_engine_type, uint8_t netflow_engine_id);
 +void dpif_uninit(struct dpif *dpif, bool close);
 +
  static inline void dpif_assert_class(const struct dpif *dpif,
-                                      const struct dpif_class *class)
+                                      const struct dpif_class *dpif_class)
  {
-     assert(dpif->class == class);
+     assert(dpif->dpif_class == dpif_class);
  }
  
  /* Datapath interface class structure, to be defined by each implementation of
   * EWOULDBLOCK or EINPROGRESS.  We may relax this requirement in the future if
   * and when we encounter performance problems. */
  struct dpif_class {
 -    /* Prefix for names of dpifs in this class, e.g. "netdev:".
 +    /* Type of dpif in this class, e.g. "system", "netdev", etc.
       *
 -     * One dpif class may have the empty string "" as its prefix, in which case
 -     * that dpif class is associated with dpif names that don't match any other
 -     * class name. */
 -    const char *prefix;
 -
 -    /* Class name, for use in error messages. */
 -    const char *name;
 +     * One of the providers should supply a "system" type, since this is
 +     * the type assumed if no type is specified when opening a dpif. */
 +    const char *type;
  
      /* Performs periodic work needed by dpifs of this class, if any is
       * necessary. */
       * case this function may be a null pointer. */
      int (*enumerate)(struct svec *all_dps);
  
 -    /* Attempts to open an existing dpif, if 'create' is false, or to open an
 -     * existing dpif or create a new one, if 'create' is true.  'name' is the
 -     * full dpif name provided by the user, e.g. "udatapath:/var/run/mypath".
 -     * This name is useful for error messages but must not be modified.
 -     *
 -     * 'suffix' is a copy of 'name' following the dpif's 'prefix'.
 +    /* Attempts to open an existing dpif called 'name', if 'create' is false,
 +     * or to open an existing dpif or create a new one, if 'create' is true.
 +     * 'type' corresponds to the 'type' field used in the dpif_class
 +     * structure.
       *
       * If successful, stores a pointer to the new dpif in '*dpifp'.  On failure
       * there are no requirements on what is stored in '*dpifp'. */
 -    int (*open)(const char *name, char *suffix, bool create,
 +    int (*open)(const char *name, const char *type, bool create,
                  struct dpif **dpifp);
  
      /* Closes 'dpif' and frees associated memory. */
       *
       * If successful, 'dpif' will not be used again except as an argument for
       * the 'close' member function. */
-     int (*delete)(struct dpif *dpif);
+     int (*destroy)(struct dpif *dpif);
  
      /* Retrieves statistics for 'dpif' into 'stats'. */
      int (*get_stats)(const struct dpif *dpif, struct odp_stats *stats);
       * corresponding type when it calls the recv member function. */
      int (*recv_set_mask)(struct dpif *dpif, int listen_mask);
  
+     /* Retrieves 'dpif''s sFlow sampling probability into '*probability'.
+      * Return value is 0 or a positive errno value.  EOPNOTSUPP indicates that
+      * the datapath does not support sFlow, as does a null pointer.
+      *
+      * '*probability' is expressed as the number of packets out of UINT_MAX to
+      * sample, e.g. probability/UINT_MAX is the probability of sampling a given
+      * packet. */
+     int (*get_sflow_probability)(const struct dpif *dpif,
+                                  uint32_t *probability);
+     /* Sets 'dpif''s sFlow sampling probability to 'probability'.  Return value
+      * is 0 or a positive errno value.  EOPNOTSUPP indicates that the datapath
+      * does not support sFlow, as does a null pointer.
+      *
+      * 'probability' is expressed as the number of packets out of UINT_MAX to
+      * sample, e.g. probability/UINT_MAX is the probability of sampling a given
+      * packet. */
+     int (*set_sflow_probability)(struct dpif *dpif, uint32_t probability);
      /* Attempts to receive a message from 'dpif'.  If successful, stores the
       * message into '*packetp'.  The message, if one is received, must begin
       * with 'struct odp_msg' as a header.  Only messages of the types selected
  extern const struct dpif_class dpif_linux_class;
  extern const struct dpif_class dpif_netdev_class;
  
+ #ifdef  __cplusplus
+ }
+ #endif
  #endif /* dpif-provider.h */
diff --combined lib/dpif.c
@@@ -33,7 -33,6 +33,7 @@@
  #include "ofpbuf.h"
  #include "packets.h"
  #include "poll-loop.h"
 +#include "shash.h"
  #include "svec.h"
  #include "util.h"
  #include "valgrind.h"
  #include "vlog.h"
  #define THIS_MODULE VLM_dpif
  
 -static const struct dpif_class *dpif_classes[] = {
 +static const struct dpif_class *base_dpif_classes[] = {
      &dpif_linux_class,
      &dpif_netdev_class,
  };
 -enum { N_DPIF_CLASSES = ARRAY_SIZE(dpif_classes) };
 +
 +struct registered_dpif_class {
 +    struct dpif_class dpif_class;
 +    int refcount;
 +};
 +static struct shash dpif_classes = SHASH_INITIALIZER(&dpif_classes);
  
  /* Rate limit for individual messages going to or from the datapath, output at
   * DBG level.  This is very high because, if these are enabled, it is because
@@@ -69,21 -63,6 +69,21 @@@ static void log_flow_put(struct dpif *
  static bool should_log_flow_message(int error);
  static void check_rw_odp_flow(struct odp_flow *);
  
 +static void
 +dp_initialize(void)
 +{
 +    static int status = -1;
 +
 +    if (status < 0) {
 +        int i;
 +
 +        status = 0;
 +        for (i = 0; i < ARRAY_SIZE(base_dpif_classes); i++) {
 +            dp_register_provider(base_dpif_classes[i]);
 +        }
 +    }
 +}
 +
  /* Performs periodic work needed by all the various kinds of dpifs.
   *
   * If your program opens any dpifs, it must call both this function and
  void
  dp_run(void)
  {
 -    int i;
 -    for (i = 0; i < N_DPIF_CLASSES; i++) {
 -        const struct dpif_class *class = dpif_classes[i];
 -        if (class->run) {
 -            class->run();
 +    struct shash_node *node;
 +    SHASH_FOR_EACH(node, &dpif_classes) {
 +        const struct registered_dpif_class *registered_class = node->data;
 +        if (registered_class->dpif_class.run) {
 +            registered_class->dpif_class.run();
          }
      }
  }
  void
  dp_wait(void)
  {
 -    int i;
 -    for (i = 0; i < N_DPIF_CLASSES; i++) {
 -        const struct dpif_class *class = dpif_classes[i];
 -        if (class->wait) {
 -            class->wait();
 +    struct shash_node *node;
 +    SHASH_FOR_EACH(node, &dpif_classes) {
 +        const struct registered_dpif_class *registered_class = node->data;
 +        if (registered_class->dpif_class.wait) {
 +            registered_class->dpif_class.wait();
          }
      }
  }
  
 -/* Clears 'all_dps' and enumerates the names of all known created datapaths, 
 - * where possible, into it.  The caller must first initialize 'all_dps'.
 - * Returns 0 if successful, otherwise a positive errno value.
 +/* Registers a new datapath provider.  After successful registration, new
 + * datapaths of that type can be opened using dpif_open(). */
 +int
 +dp_register_provider(const struct dpif_class *new_class)
 +{
 +    struct registered_dpif_class *registered_class;
 +
 +    if (shash_find(&dpif_classes, new_class->type)) {
 +        VLOG_WARN("attempted to register duplicate datapath provider: %s",
 +                  new_class->type);
 +        return EEXIST;
 +    }
 +
 +    registered_class = xmalloc(sizeof *registered_class);
 +    memcpy(&registered_class->dpif_class, new_class,
 +           sizeof registered_class->dpif_class);
 +    registered_class->refcount = 0;
 +
 +    shash_add(&dpif_classes, new_class->type, registered_class);
 +
 +    return 0;
 +}
 +
 +/* Unregisters a datapath provider.  'type' must have been previously
 + * registered and not currently be in use by any dpifs.  After unregistration
 + * new datapaths of that type cannot be opened using dpif_open(). */
 +int
 +dp_unregister_provider(const char *type)
 +{
 +    struct shash_node *node;
 +    struct registered_dpif_class *registered_class;
 +
 +    node = shash_find(&dpif_classes, type);
 +    if (!node) {
 +        VLOG_WARN("attempted to unregister a datapath provider that is not "
 +                  "registered: %s", type);
 +        return EAFNOSUPPORT;
 +    }
 +
 +    registered_class = node->data;
 +    if (registered_class->refcount) {
 +        VLOG_WARN("attempted to unregister in use datapath provider: %s", type);
 +        return EBUSY;
 +    }
 +
 +    shash_delete(&dpif_classes, node);
 +    free(registered_class);
 +
 +    return 0;
 +}
 +
 +/* Clears 'types' and enumerates the types of all currently registered datapath
 + * providers into it.  The caller must first initialize the svec. */
 +void
 +dp_enumerate_types(struct svec *types)
 +{
 +    struct shash_node *node;
 +
 +    dp_initialize();
 +    svec_clear(types);
 +
 +    SHASH_FOR_EACH(node, &dpif_classes) {
 +        const struct registered_dpif_class *registered_class = node->data;
 +        svec_add(types, registered_class->dpif_class.type);
 +    }
 +}
 +
 +/* Clears 'names' and enumerates the names of all known created datapaths with
 + * the given 'type'.  The caller must first initialize the svec. Returns 0 if
 + * successful, otherwise a positive errno value.
   *
   * Some kinds of datapaths might not be practically enumerable.  This is not
   * considered an error. */
  int
 -dp_enumerate(struct svec *all_dps)
 +dp_enumerate_names(const char *type, struct svec *names)
  {
 +    const struct registered_dpif_class *registered_class;
 +    const struct dpif_class *dpif_class;
      int error;
 -    int i;
 -
 -    svec_clear(all_dps);
 -    error = 0;
 -    for (i = 0; i < N_DPIF_CLASSES; i++) {
 -        const struct dpif_class *class = dpif_classes[i];
 -        int retval = class->enumerate ? class->enumerate(all_dps) : 0;
 -        if (retval) {
 -            VLOG_WARN("failed to enumerate %s datapaths: %s",
 -                      class->name, strerror(retval));
 -            if (!error) {
 -                error = retval;
 -            }
 -        }
 +
 +    dp_initialize();
 +    svec_clear(names);
 +
 +    registered_class = shash_find_data(&dpif_classes, type);
 +    if (!registered_class) {
 +        VLOG_WARN("could not enumerate unknown type: %s", type);
 +        return EAFNOSUPPORT;
 +    }
 +
 +    dpif_class = &registered_class->dpif_class;
 +    error = dpif_class->enumerate ? dpif_class->enumerate(names) : 0;
 +
 +    if (error) {
 +        VLOG_WARN("failed to enumerate %s datapaths: %s", dpif_class->type,
 +                   strerror(error));
      }
 +
      return error;
  }
  
 +/* Parses 'datapath name', which is of the form type@name into its
 + * component pieces.  'name' and 'type' must be freed by the caller. */
 +void
 +dp_parse_name(const char *datapath_name_, char **name, char **type)
 +{
 +    char *datapath_name = xstrdup(datapath_name_);
 +    char *separator;
 +
 +    separator = strchr(datapath_name, '@');
 +    if (separator) {
 +        *separator = '\0';
 +        *type = datapath_name;
 +        *name = xstrdup(separator + 1);
 +    } else {
 +        *name = datapath_name;
 +        *type = NULL;
 +    }
 +}
 +
  static int
 -do_open(const char *name_, bool create, struct dpif **dpifp)
 +do_open(const char *name, const char *type, bool create, struct dpif **dpifp)
  {
 -    char *name = xstrdup(name_);
 -    char *prefix, *suffix, *colon;
      struct dpif *dpif = NULL;
      int error;
 -    int i;
 +    struct registered_dpif_class *registered_class;
  
 -    colon = strchr(name, ':');
 -    if (colon) {
 -        *colon = '\0';
 -        prefix = name;
 -        suffix = colon + 1;
 -    } else {
 -        prefix = "";
 -        suffix = name;
 +    dp_initialize();
 +
 +    if (!type || *type == '\0') {
 +        type = "system";
      }
  
 -    for (i = 0; i < N_DPIF_CLASSES; i++) {
 -        const struct dpif_class *class = dpif_classes[i];
 -        if (!strcmp(prefix, class->prefix)) {
 -            error = class->open(name_, suffix, create, &dpif);
 -            goto exit;
 -        }
 +    registered_class = shash_find_data(&dpif_classes, type);
 +    if (!registered_class) {
 +        VLOG_WARN("could not create datapath %s of unknown type %s", name,
 +                  type);
 +        error = EAFNOSUPPORT;
 +        goto exit;
 +    }
 +
 +    error = registered_class->dpif_class.open(name, type, create, &dpif);
 +    if (!error) {
 +        registered_class->refcount++;
      }
 -    error = EAFNOSUPPORT;
  
  exit:
      *dpifp = error ? NULL : dpif;
      return error;
  }
  
 -/* Tries to open an existing datapath named 'name'.  Will fail if no datapath
 - * named 'name' exists.  Returns 0 if successful, otherwise a positive errno
 - * value.  On success stores a pointer to the datapath in '*dpifp', otherwise a
 - * null pointer. */
 +/* Tries to open an existing datapath named 'name' and type 'type'.  Will fail
 + * if no datapath with 'name' and 'type' exists.  'type' may be either NULL or
 + * the empty string to specify the default system type.  Returns 0 if
 + * successful, otherwise a positive errno value.  On success stores a pointer
 + * to the datapath in '*dpifp', otherwise a null pointer. */
  int
 -dpif_open(const char *name, struct dpif **dpifp)
 +dpif_open(const char *name, const char *type, struct dpif **dpifp)
  {
 -    return do_open(name, false, dpifp);
 +    return do_open(name, type, false, dpifp);
  }
  
 -/* Tries to create and open a new datapath with the given 'name'.  Will fail if
 - * a datapath named 'name' already exists.  Returns 0 if successful, otherwise
 - * a positive errno value.  On success stores a pointer to the datapath in
 - * '*dpifp', otherwise a null pointer. */
 +/* Tries to create and open a new datapath with the given 'name' and 'type'.
 + * 'type' may be either NULL or the empty string to specify the default system
 + * type.  Will fail if a datapath with 'name' and 'type' already exists.
 + * Returns 0 if successful, otherwise a positive errno value.  On success
 + * stores a pointer to the datapath in '*dpifp', otherwise a null pointer. */
  int
 -dpif_create(const char *name, struct dpif **dpifp)
 +dpif_create(const char *name, const char *type, struct dpif **dpifp)
  {
 -    return do_open(name, true, dpifp);
 +    return do_open(name, type, true, dpifp);
  }
  
 -/* Tries to open a datapath with the given 'name', creating it if it does not
 - * exist.  Returns 0 if successful, otherwise a positive errno value.  On
 - * success stores a pointer to the datapath in '*dpifp', otherwise a null
 - * pointer. */
 +/* Tries to open a datapath with the given 'name' and 'type', creating it if it
 + * does not exist.  'type' may be either NULL or the empty string to specify
 + * the default system type.  Returns 0 if successful, otherwise a positive
 + * errno value. On success stores a pointer to the datapath in '*dpifp',
 + * otherwise a null pointer. */
  int
 -dpif_create_and_open(const char *name, struct dpif **dpifp)
 +dpif_create_and_open(const char *name, const char *type, struct dpif **dpifp)
  {
      int error;
  
 -    error = dpif_create(name, dpifp);
 +    error = dpif_create(name, type, dpifp);
      if (error == EEXIST || error == EBUSY) {
 -        error = dpif_open(name, dpifp);
 +        error = dpif_open(name, type, dpifp);
          if (error) {
              VLOG_WARN("datapath %s already exists but cannot be opened: %s",
                        name, strerror(error));
@@@ -317,31 -204,17 +317,32 @@@ voi
  dpif_close(struct dpif *dpif)
  {
      if (dpif) {
 -        char *name = dpif->name;
 -        dpif->dpif_class->close(dpif);
 -        free(name);
 +        struct registered_dpif_class *registered_class;
 +
-         registered_class = shash_find_data(&dpif_classes, dpif->class->type);
++        registered_class = shash_find_data(&dpif_classes, 
++                dpif->dpif_class->type);
 +        assert(registered_class);
 +        assert(registered_class->refcount);
 +
 +        registered_class->refcount--;
 +        dpif_uninit(dpif, true);
      }
  }
  
 -/* Returns the name of datapath 'dpif' (for use in log messages). */
 +/* Returns the name of datapath 'dpif' prefixed with the type
 + * (for use in log messages). */
  const char *
  dpif_name(const struct dpif *dpif)
  {
 -    return dpif->name;
 +    return dpif->full_name;
 +}
 +
 +/* Returns the name of datapath 'dpif' without the type
 + * (for use in device names). */
 +const char *
 +dpif_base_name(const struct dpif *dpif)
 +{
 +    return dpif->base_name;
  }
  
  /* Enumerates all names that may be used to open 'dpif' into 'all_names'.  The
  int
  dpif_get_all_names(const struct dpif *dpif, struct svec *all_names)
  {
-     if (dpif->class->get_all_names) {
-         int error = dpif->class->get_all_names(dpif, all_names);
+     if (dpif->dpif_class->get_all_names) {
+         int error = dpif->dpif_class->get_all_names(dpif, all_names);
          if (error) {
              VLOG_WARN_RL(&error_rl,
                           "failed to retrieve names for datpath %s: %s",
          }
          return error;
      } else {
 -        svec_add(all_names, dpif_name(dpif));
 +        svec_add(all_names, dpif_base_name(dpif));
          return 0;
      }
  }
@@@ -380,7 -253,7 +381,7 @@@ dpif_delete(struct dpif *dpif
  
      COVERAGE_INC(dpif_destroy);
  
-     error = dpif->class->delete(dpif);
+     error = dpif->dpif_class->destroy(dpif);
      log_operation(dpif, "delete", error);
      return error;
  }
  int
  dpif_get_dp_stats(const struct dpif *dpif, struct odp_stats *stats)
  {
-     int error = dpif->class->get_stats(dpif, stats);
+     int error = dpif->dpif_class->get_stats(dpif, stats);
      if (error) {
          memset(stats, 0, sizeof *stats);
      }
  int
  dpif_get_drop_frags(const struct dpif *dpif, bool *drop_frags)
  {
-     int error = dpif->class->get_drop_frags(dpif, drop_frags);
+     int error = dpif->dpif_class->get_drop_frags(dpif, drop_frags);
      if (error) {
          *drop_frags = false;
      }
  int
  dpif_set_drop_frags(struct dpif *dpif, bool drop_frags)
  {
-     int error = dpif->class->set_drop_frags(dpif, drop_frags);
+     int error = dpif->dpif_class->set_drop_frags(dpif, drop_frags);
      log_operation(dpif, "set_drop_frags", error);
      return error;
  }
@@@ -439,7 -312,7 +440,7 @@@ dpif_port_add(struct dpif *dpif, const 
  
      COVERAGE_INC(dpif_port_add);
  
-     error = dpif->class->port_add(dpif, devname, flags, &port_no);
+     error = dpif->dpif_class->port_add(dpif, devname, flags, &port_no);
      if (!error) {
          VLOG_DBG_RL(&dpmsg_rl, "%s: added %s as port %"PRIu16,
                      dpif_name(dpif), devname, port_no);
@@@ -463,7 -336,7 +464,7 @@@ dpif_port_del(struct dpif *dpif, uint16
  
      COVERAGE_INC(dpif_port_del);
  
-     error = dpif->class->port_del(dpif, port_no);
+     error = dpif->dpif_class->port_del(dpif, port_no);
      log_operation(dpif, "port_del", error);
      return error;
  }
@@@ -475,7 -348,7 +476,7 @@@ in
  dpif_port_query_by_number(const struct dpif *dpif, uint16_t port_no,
                            struct odp_port *port)
  {
-     int error = dpif->class->port_query_by_number(dpif, port_no, port);
+     int error = dpif->dpif_class->port_query_by_number(dpif, port_no, port);
      if (!error) {
          VLOG_DBG_RL(&dpmsg_rl, "%s: port %"PRIu16" is device %s",
                      dpif_name(dpif), port_no, port->devname);
@@@ -494,7 -367,7 +495,7 @@@ in
  dpif_port_query_by_name(const struct dpif *dpif, const char *devname,
                          struct odp_port *port)
  {
-     int error = dpif->class->port_query_by_name(dpif, devname, port);
+     int error = dpif->dpif_class->port_query_by_name(dpif, devname, port);
      if (!error) {
          VLOG_DBG_RL(&dpmsg_rl, "%s: device %s is on port %"PRIu16,
                      dpif_name(dpif), devname, port->port);
@@@ -559,7 -432,7 +560,7 @@@ dpif_port_list(const struct dpif *dpif
          }
  
          ports = xcalloc(stats.n_ports, sizeof *ports);
-         retval = dpif->class->port_list(dpif, ports, stats.n_ports);
+         retval = dpif->dpif_class->port_list(dpif, ports, stats.n_ports);
          if (retval < 0) {
              /* Hard error. */
              error = -retval;
@@@ -607,7 -480,7 +608,7 @@@ exit
  int
  dpif_port_poll(const struct dpif *dpif, char **devnamep)
  {
-     int error = dpif->class->port_poll(dpif, devnamep);
+     int error = dpif->dpif_class->port_poll(dpif, devnamep);
      if (error) {
          *devnamep = NULL;
      }
  void
  dpif_port_poll_wait(const struct dpif *dpif)
  {
-     dpif->class->port_poll_wait(dpif);
+     dpif->dpif_class->port_poll_wait(dpif);
  }
  
  /* Retrieves a list of the port numbers in port group 'group' in 'dpif'.
@@@ -640,8 -513,8 +641,8 @@@ dpif_port_group_get(const struct dpif *
      *ports = NULL;
      *n_ports = 0;
      for (;;) {
-         int retval = dpif->class->port_group_get(dpif, group,
-                                                  *ports, *n_ports);
+         int retval = dpif->dpif_class->port_group_get(dpif, group,
+                                                       *ports, *n_ports);
          if (retval < 0) {
              /* Hard error. */
              error = -retval;
@@@ -679,7 -552,7 +680,7 @@@ dpif_port_group_set(struct dpif *dpif, 
  
      COVERAGE_INC(dpif_port_group_set);
  
-     error = dpif->class->port_group_set(dpif, group, ports, n_ports);
+     error = dpif->dpif_class->port_group_set(dpif, group, ports, n_ports);
      log_operation(dpif, "port_group_set", error);
      return error;
  }
@@@ -693,7 -566,7 +694,7 @@@ dpif_flow_flush(struct dpif *dpif
  
      COVERAGE_INC(dpif_flow_flush);
  
-     error = dpif->class->flow_flush(dpif);
+     error = dpif->dpif_class->flow_flush(dpif);
      log_operation(dpif, "flow_flush", error);
      return error;
  }
@@@ -719,7 -592,7 +720,7 @@@ dpif_flow_get(const struct dpif *dpif, 
      COVERAGE_INC(dpif_flow_get);
  
      check_rw_odp_flow(flow);
-     error = dpif->class->flow_get(dpif, flow, 1);
+     error = dpif->dpif_class->flow_get(dpif, flow, 1);
      if (!error) {
          error = flow->stats.error;
      }
@@@ -769,7 -642,7 +770,7 @@@ dpif_flow_get_multiple(const struct dpi
          check_rw_odp_flow(&flows[i]);
      }
  
-     error = dpif->class->flow_get(dpif, flows, n);
+     error = dpif->dpif_class->flow_get(dpif, flows, n);
      log_operation(dpif, "flow_get_multiple", error);
      return error;
  }
@@@ -797,7 -670,7 +798,7 @@@ dpif_flow_put(struct dpif *dpif, struc
  
      COVERAGE_INC(dpif_flow_put);
  
-     error = dpif->class->flow_put(dpif, put);
+     error = dpif->dpif_class->flow_put(dpif, put);
      if (should_log_flow_message(error)) {
          log_flow_put(dpif, error, put);
      }
@@@ -819,7 -692,7 +820,7 @@@ dpif_flow_del(struct dpif *dpif, struc
      check_rw_odp_flow(flow);
      memset(&flow->stats, 0, sizeof flow->stats);
  
-     error = dpif->class->flow_del(dpif, flow);
+     error = dpif->dpif_class->flow_del(dpif, flow);
      if (should_log_flow_message(error)) {
          log_flow_operation(dpif, "delete flow", error, flow);
      }
@@@ -848,7 -721,7 +849,7 @@@ dpif_flow_list(const struct dpif *dpif
              flows[i].n_actions = 0;
          }
      }
-     retval = dpif->class->flow_list(dpif, flows, n);
+     retval = dpif->dpif_class->flow_list(dpif, flows, n);
      if (retval < 0) {
          *n_out = 0;
          VLOG_WARN_RL(&error_rl, "%s: flow list failed (%s)",
@@@ -925,7 -798,8 +926,8 @@@ dpif_execute(struct dpif *dpif, uint16_
  
      COVERAGE_INC(dpif_execute);
      if (n_actions > 0) {
-         error = dpif->class->execute(dpif, in_port, actions, n_actions, buf);
+         error = dpif->dpif_class->execute(dpif, in_port, actions,
+                                           n_actions, buf);
      } else {
          error = 0;
      }
  int
  dpif_recv_get_mask(const struct dpif *dpif, int *listen_mask)
  {
-     int error = dpif->class->recv_get_mask(dpif, listen_mask);
+     int error = dpif->dpif_class->recv_get_mask(dpif, listen_mask);
      if (error) {
          *listen_mask = 0;
      }
  int
  dpif_recv_set_mask(struct dpif *dpif, int listen_mask)
  {
-     int error = dpif->class->recv_set_mask(dpif, listen_mask);
+     int error = dpif->dpif_class->recv_set_mask(dpif, listen_mask);
      log_operation(dpif, "recv_set_mask", error);
      return error;
  }
  
+ /* Retrieve the sFlow sampling probability.  '*probability' is expressed as the
+  * number of packets out of UINT_MAX to sample, e.g. probability/UINT_MAX is
+  * the probability of sampling a given packet.
+  *
+  * Returns 0 if successful, otherwise a positive errno value.  EOPNOTSUPP
+  * indicates that 'dpif' does not support sFlow sampling. */
+ int
+ dpif_get_sflow_probability(const struct dpif *dpif, uint32_t *probability)
+ {
+     int error = (dpif->dpif_class->get_sflow_probability
+                  ? dpif->dpif_class->get_sflow_probability(dpif, probability)
+                  : EOPNOTSUPP);
+     if (error) {
+         *probability = 0;
+     }
+     log_operation(dpif, "get_sflow_probability", error);
+     return error;
+ }
+ /* Set the sFlow sampling probability.  'probability' is expressed as the
+  * number of packets out of UINT_MAX to sample, e.g. probability/UINT_MAX is
+  * the probability of sampling a given packet.
+  *
+  * Returns 0 if successful, otherwise a positive errno value.  EOPNOTSUPP
+  * indicates that 'dpif' does not support sFlow sampling. */
+ int
+ dpif_set_sflow_probability(struct dpif *dpif, uint32_t probability)
+ {
+     int error = (dpif->dpif_class->set_sflow_probability
+                  ? dpif->dpif_class->set_sflow_probability(dpif, probability)
+                  : EOPNOTSUPP);
+     log_operation(dpif, "set_sflow_probability", error);
+     return error;
+ }
  /* Attempts to receive a message from 'dpif'.  If successful, stores the
   * message into '*packetp'.  The message, if one is received, will begin with
   * 'struct odp_msg' as a header.  Only messages of the types selected with
  int
  dpif_recv(struct dpif *dpif, struct ofpbuf **packetp)
  {
-     int error = dpif->class->recv(dpif, packetp);
+     int error = dpif->dpif_class->recv(dpif, packetp);
      if (!error) {
          if (VLOG_IS_DBG_ENABLED()) {
              struct ofpbuf *buf = *packetp;
                          "%zu on port %"PRIu16": %s", dpif_name(dpif),
                          (msg->type == _ODPL_MISS_NR ? "miss"
                           : msg->type == _ODPL_ACTION_NR ? "action"
+                          : msg->type == _ODPL_SFLOW_NR ? "sFlow"
                           : "<unknown>"),
                          payload_len, msg->port, s);
              free(s);
@@@ -1020,7 -930,7 +1058,7 @@@ dpif_recv_purge(struct dpif *dpif
          return error;
      }
  
-     for (i = 0; i < stats.max_miss_queue + stats.max_action_queue; i++) {
+     for (i = 0; i < stats.max_miss_queue + stats.max_action_queue + stats.max_sflow_queue; i++) {
          struct ofpbuf *buf;
          error = dpif_recv(dpif, &buf);
          if (error) {
  void
  dpif_recv_wait(struct dpif *dpif)
  {
-     dpif->class->recv_wait(dpif);
+     dpif->dpif_class->recv_wait(dpif);
  }
  
  /* Obtains the NetFlow engine type and engine ID for 'dpif' into '*engine_type'
@@@ -1050,35 -960,15 +1088,36 @@@ dpif_get_netflow_ids(const struct dpif 
  }
  \f
  void
- dpif_init(struct dpif *dpif, const struct dpif_class *class, const char *name,
+ dpif_init(struct dpif *dpif, const struct dpif_class *dpif_class,
+           const char *name,
            uint8_t netflow_engine_type, uint8_t netflow_engine_id)
  {
-     dpif->class = class;
+     dpif->dpif_class = dpif_class;
 -    dpif->name = xstrdup(name);
 +    dpif->base_name = xstrdup(name);
-     dpif->full_name = xasprintf("%s@%s", class->type, name);
++    dpif->full_name = xasprintf("%s@%s", dpif_class->type, name);
      dpif->netflow_engine_type = netflow_engine_type;
      dpif->netflow_engine_id = netflow_engine_id;
  }
-         dpif->class->close(dpif);
 +
 +/* Undoes the results of initialization.
 + *
 + * Normally this function only needs to be called from dpif_close().
 + * However, it may be called by providers due to an error on opening
 + * that occurs after initialization.  It this case dpif_close() would
 + * never be called. */
 +void
 +dpif_uninit(struct dpif *dpif, bool close)
 +{
 +    char *base_name = dpif->base_name;
 +    char *full_name = dpif->full_name;
 +
 +    if (close) {
++        dpif->dpif_class->close(dpif);
 +    }
 +
 +    free(base_name);
 +    free(full_name);
 +}
  \f
  static void
  log_operation(const struct dpif *dpif, const char *operation, int error)
diff --combined lib/dpif.h
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Copyright (c) 2008, 2009 Nicira Networks.
 + * Copyright (c) 2008, 2009, 2010 Nicira Networks.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
  #ifndef DPIF_H
  #define DPIF_H 1
  
 -/* Operations for the datapath running in the local kernel.  The interface can
 - * generalize to multiple types of local datapaths, but the implementation only
 - * supports the openflow kernel module. */
 -
  #include "openvswitch/datapath-protocol.h"
  #include <stdbool.h>
  #include <stddef.h>
  struct dpif;
  struct ofpbuf;
  struct svec;
 +struct dpif_class;
  
  void dp_run(void);
  void dp_wait(void);
 -int dp_enumerate(struct svec *);
  
 -int dpif_open(const char *name, struct dpif **);
 -int dpif_create(const char *name, struct dpif **);
 -int dpif_create_and_open(const char *name, struct dpif **);
 +int dp_register_provider(const struct dpif_class *);
 +int dp_unregister_provider(const char *type);
 +void dp_enumerate_types(struct svec *types);
 +
 +int dp_enumerate_names(const char *type, struct svec *names);
 +void dp_parse_name(const char *datapath_name, char **name, char **type);
 +
 +int dpif_open(const char *name, const char *type, struct dpif **);
 +int dpif_create(const char *name, const char *type, struct dpif **);
 +int dpif_create_and_open(const char *name, const char *type, struct dpif **);
  void dpif_close(struct dpif *);
  
  const char *dpif_name(const struct dpif *);
 +const char *dpif_base_name(const struct dpif *);
  int dpif_get_all_names(const struct dpif *, struct svec *);
  
  int dpif_delete(struct dpif *);
@@@ -88,6 -84,8 +88,8 @@@ int dpif_execute(struct dpif *, uint16_
  
  int dpif_recv_get_mask(const struct dpif *, int *listen_mask);
  int dpif_recv_set_mask(struct dpif *, int listen_mask);
+ int dpif_get_sflow_probability(const struct dpif *, uint32_t *probability);
+ int dpif_set_sflow_probability(struct dpif *, uint32_t probability);
  int dpif_recv(struct dpif *, struct ofpbuf **);
  int dpif_recv_purge(struct dpif *);
  void dpif_recv_wait(struct dpif *);
diff --combined lib/hmap.h
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Copyright (c) 2008, 2009 Nicira Networks.
 + * Copyright (c) 2008, 2009, 2010 Nicira Networks.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
  #include <stdlib.h>
  #include "util.h"
  
+ #ifdef  __cplusplus
+ extern "C" {
+ #endif
  /* A hash map node, to be embedded inside the data structure being mapped. */
  struct hmap_node {
      size_t hash;                /* Hash value. */
@@@ -33,27 -37,9 +37,27 @@@ static inline size_t hmap_node_hash(con
      return node->hash;
  }
  
 +#define HMAP_NODE_NULL ((struct hmap_node *) 1)
 +
 +/* Returns true if 'node' has been set to null by hmap_node_nullify() and has
 + * not been un-nullified by being inserted into an hmap. */
 +static inline bool
 +hmap_node_is_null(const struct hmap_node *node)
 +{
 +    return node->next == HMAP_NODE_NULL;
 +}
 +
 +/* Marks 'node' with a distinctive value that can be tested with
 + * hmap_node_is_null().  */
 +static inline void
 +hmap_node_nullify(struct hmap_node *node)
 +{
 +    node->next = HMAP_NODE_NULL;
 +}
 +
  /* A hash map. */
  struct hmap {
 -    struct hmap_node **buckets;
 +    struct hmap_node **buckets; /* Must point to 'one' iff 'mask' == 0. */
      struct hmap_node *one;
      size_t mask;
      size_t n;
@@@ -66,7 -52,6 +70,7 @@@
  void hmap_init(struct hmap *);
  void hmap_destroy(struct hmap *);
  void hmap_swap(struct hmap *a, struct hmap *b);
- void hmap_moved(struct hmap *);
++void hmap_moved(struct hmap *hmap);
  static inline size_t hmap_count(const struct hmap *);
  static inline bool hmap_is_empty(const struct hmap *);
  
@@@ -80,50 -65,23 +84,51 @@@ static inline void hmap_insert_fast(str
                                      struct hmap_node *, size_t hash);
  static inline void hmap_insert(struct hmap *, struct hmap_node *, size_t hash);
  static inline void hmap_remove(struct hmap *, struct hmap_node *);
 -static inline void hmap_moved(struct hmap *,
 -                              struct hmap_node *, struct hmap_node *);
 -static inline void hmap_replace(struct hmap *,
 -                                const struct hmap_node *old_node,
 -                                struct hmap_node *new_node);
 -/* Search. */
 +void hmap_node_moved(struct hmap *, struct hmap_node *, struct hmap_node *);
 +static inline void hmap_replace(struct hmap *, const struct hmap_node *old,
 +                                struct hmap_node *new);
 +
 +/* Search.
 + *
 + * HMAP_FOR_EACH_WITH_HASH iterates NODE over all of the nodes in HMAP that
 + * have hash value equal to HASH.  HMAP_FOR_EACH_IN_BUCKET iterates NODE over
 + * all of the nodes in HMAP that would fall in the same bucket as HASH.  STRUCT
 + * and MEMBER must be the name of the struct that contains the 'struct
 + * hmap_node' and the name of the 'struct hmap_node' member, respectively.
 + *
 + * These macros may be used interchangeably to search for a particular value in
 + * an hmap, see, e.g. shash_find() for an example.  Usually, using
 + * HMAP_FOR_EACH_WITH_HASH provides an optimization, because comparing a hash
 + * value is usually cheaper than comparing an entire hash map key.  But for
 + * simple hash map keys, it makes sense to use HMAP_FOR_EACH_IN_BUCKET because
 + * it avoids doing two comparisons when a single simple comparison suffices.
 + *
 + * The loop should not change NODE to point to a different node or insert or
 + * delete nodes in HMAP (unless it "break"s out of the loop to terminate
 + * iteration).
 + *
 + * HASH is only evaluated once.
 + */
  #define HMAP_FOR_EACH_WITH_HASH(NODE, STRUCT, MEMBER, HASH, HMAP)       \
      for ((NODE) = CONTAINER_OF(hmap_first_with_hash(HMAP, HASH),        \
                                 STRUCT, MEMBER);                         \
           &(NODE)->MEMBER != NULL;                                       \
           (NODE) = CONTAINER_OF(hmap_next_with_hash(&(NODE)->MEMBER),    \
                                 STRUCT, MEMBER))
 +#define HMAP_FOR_EACH_IN_BUCKET(NODE, STRUCT, MEMBER, HASH, HMAP)       \
 +    for ((NODE) = CONTAINER_OF(hmap_first_in_bucket(HMAP, HASH),        \
 +                               STRUCT, MEMBER);                         \
 +         &(NODE)->MEMBER != NULL;                                       \
 +         (NODE) = CONTAINER_OF(hmap_next_in_bucket(&(NODE)->MEMBER),    \
 +                               STRUCT, MEMBER))
  
  static inline struct hmap_node *hmap_first_with_hash(const struct hmap *,
                                                       size_t hash);
  static inline struct hmap_node *hmap_next_with_hash(const struct hmap_node *);
 +static inline struct hmap_node *hmap_first_in_bucket(const struct hmap *,
 +                                                     size_t hash);
 +static inline struct hmap_node *hmap_next_in_bucket(const struct hmap_node *);
  
  /* Iteration.
   *
@@@ -207,24 -165,36 +212,24 @@@ hmap_remove(struct hmap *hmap, struct h
      hmap->n--;
  }
  
- /* Puts 'new' in the position in 'hmap' currently occupied by 'old'.  The 'new'
-  * node must hash to the same value as 'old'.  The client is responsible for
-  * ensuring that the replacement does not violate any client-imposed
-  * invariants (e.g. uniqueness of keys within a map).
 -/* Adjusts 'hmap' to compensate for 'old_node' having moved position in memory
 - * to 'node' (e.g. due to realloc()). */
 -static inline void
 -hmap_moved(struct hmap *hmap,
 -           struct hmap_node *old_node, struct hmap_node *node)
 -{
 -    struct hmap_node **bucket = &hmap->buckets[node->hash & hmap->mask];
 -    while (*bucket != old_node) {
 -        bucket = &(*bucket)->next;
 -    }
 -    *bucket = node;
 -}
 -
+ /* Puts 'new_node' in the position in 'hmap' currently occupied by 'old_node'.
+  * The 'new_node' must hash to the same value as 'old_node'.  The client is
+  * responsible for ensuring that the replacement does not violate any
+  * client-imposed invariants (e.g. uniqueness of keys within a map).
   *
-  * Afterward, 'old' is not part of 'hmap', and the client is responsible for
-  * freeing it (if this is desirable). */
+  * Afterward, 'old_node' is not part of 'hmap', and the client is responsible
+  * for freeing it (if this is desirable). */
  static inline void
  hmap_replace(struct hmap *hmap,
-              const struct hmap_node *old, struct hmap_node *new)
+              const struct hmap_node *old_node, struct hmap_node *new_node)
  {
-     struct hmap_node **bucket = &hmap->buckets[old->hash & hmap->mask];
-     while (*bucket != old) {
+     struct hmap_node **bucket = &hmap->buckets[old_node->hash & hmap->mask];
+     while (*bucket != old_node) {
          bucket = &(*bucket)->next;
      }
-     *bucket = new;
-     new->hash = old->hash;
-     new->next = old->next;
+     *bucket = new_node;
+     new_node->hash = old_node->hash;
++    new_node->next = old_node->next;
  }
  
  static inline struct hmap_node *
@@@ -244,28 -214,6 +249,28 @@@ hmap_first_with_hash(const struct hmap 
      return hmap_next_with_hash__(hmap->buckets[hash & hmap->mask], hash);
  }
  
 +/* Returns the first node in 'hmap' in the bucket in which the given 'hash'
 + * would land, or a null pointer if that bucket is empty. */
 +static inline struct hmap_node *
 +hmap_first_in_bucket(const struct hmap *hmap, size_t hash)
 +{
 +    return hmap->buckets[hash & hmap->mask];
 +}
 +
 +/* Returns the next node in the same bucket as 'node', or a null pointer if
 + * there are no more nodes in that bucket.
 + *
 + * If the hash map has been reallocated since 'node' was visited, some nodes
 + * may be skipped; if new nodes with the same hash value have been added, they
 + * will be skipped.  (Removing 'node' from the hash map does not prevent
 + * calling this function, since node->next is preserved, although freeing
 + * 'node' of course does.) */
 +static inline struct hmap_node *
 +hmap_next_in_bucket(const struct hmap_node *node)
 +{
 +    return node->next;
 +}
 +
  /* Returns the next node in the same hash map as 'node' with the same hash
   * value, or a null pointer if no more nodes have that hash value.
   *
@@@ -316,4 -264,8 +321,8 @@@ hmap_next(const struct hmap *hmap, cons
              : hmap_next__(hmap, (node->hash & hmap->mask) + 1));
  }
  
+ #ifdef  __cplusplus
+ }
+ #endif
  #endif /* hmap.h */
diff --combined lib/netdev-provider.h
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Copyright (c) 2009 Nicira Networks.
 + * Copyright (c) 2009, 2010 Nicira Networks.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
  /* Generic interface to network devices. */
  
  #include <assert.h>
 +
  #include "netdev.h"
  #include "list.h"
  #include "shash.h"
  
 -/* A network device object that was created through the netdev_create()
 - * call.
+ #ifdef  __cplusplus
+ extern "C" {
+ #endif
 +struct arg {
 +    char *key;
 +    char *value;
 +};
 +
 +/* A network device (e.g. an Ethernet device).
   *
   * This structure should be treated as opaque by network device
   * implementations. */
 -struct netdev_obj {
 -    const struct netdev_class *netdev_class;
 -    int ref_cnt;
 -    bool created;                    /* Was netdev_create() called? */
 +struct netdev_dev {
 +    char *name;                         /* Name of network device. */
-     const struct netdev_class *class;   /* Functions to control this device. */
++    const struct netdev_class *netdev_class; /* Functions to control 
++                                                this device. */
 +    int ref_cnt;                        /* Times this devices was opened. */
 +    struct shash_node *node;            /* Pointer to element in global map. */
 +    struct arg *args;                   /* Argument list from last config. */
 +    int n_args;                         /* Number of arguments in 'args'. */
  };
  
 -void netdev_obj_init(struct netdev_obj *, const char *name,
 -                     const struct netdev_class *, bool created);
 -static inline void netdev_obj_assert_class(const struct netdev_obj *netdev_obj,
 +void netdev_dev_init(struct netdev_dev *, const char *name,
 +                     const struct netdev_class *);
 +void netdev_dev_uninit(struct netdev_dev *, bool destroy);
 +const char *netdev_dev_get_type(const struct netdev_dev *);
 +const char *netdev_dev_get_name(const struct netdev_dev *);
 +struct netdev_dev *netdev_dev_from_name(const char *name);
 +void netdev_dev_get_devices(const struct netdev_class *,
 +                            struct shash *device_list);
 +
 +static inline void netdev_dev_assert_class(const struct netdev_dev *netdev_dev,
-                                            const struct netdev_class *class)
+                                            const struct netdev_class *class_)
  {
-     assert(netdev_dev->class == class);
 -    assert(netdev_obj->netdev_class == class_);
++    assert(netdev_dev->netdev_class == class_);
  }
  
 -/* A network device (e.g. an Ethernet device).
 +/* A instance of an open network device.
   *
   * This structure should be treated as opaque by network device
   * implementations. */
  struct netdev {
 -    const struct netdev_class *netdev_class;
 -    char *name;                      /* e.g. "eth0" */
 +    struct netdev_dev *netdev_dev;   /* Parent netdev_dev. */
 +    struct list node;                /* Element in global list. */
  
      enum netdev_flags save_flags;    /* Initial device flags. */
      enum netdev_flags changed_flags; /* Flags that we changed. */
 -    struct list node;                /* Element in global list. */
  };
  
 -void netdev_init(struct netdev *, const char *name,
 -                 const struct netdev_class *);
 +void netdev_init(struct netdev *, struct netdev_dev *);
 +void netdev_uninit(struct netdev *, bool close);
 +struct netdev_dev *netdev_get_dev(const struct netdev *);
 +
  static inline void netdev_assert_class(const struct netdev *netdev,
-                                        const struct netdev_class *class)
+                                        const struct netdev_class *netdev_class)
  {
-     netdev_dev_assert_class(netdev_get_dev(netdev), class);
 -    assert(netdev->netdev_class == netdev_class);
++    netdev_dev_assert_class(netdev_get_dev(netdev), netdev_class);
  }
 -const char *netdev_get_type(const struct netdev *netdev);
  
  /* A network device notifier.
   *
@@@ -102,17 -91,17 +107,17 @@@ struct netdev_class 
      /* Type of netdevs in this class, e.g. "system", "tap", "gre", etc.
       *
       * One of the providers should supply a "system" type, since this is
 -     * the type assumed when a device name was not bound through the 
 -     * netdev_create() call.  The "system" type corresponds to an 
 -     * existing network device on the system. */
 +     * the type assumed if no type is specified when opening a netdev.
 +     * The "system" type corresponds to an existing network device on
 +     * the system. */
      const char *type;
  
 -    /* Called only once, at program startup.  Returning an error from this
 -     * function will prevent any network device in this class from being
 -     * opened.
 +    /* Called when the netdev provider is registered, typically at program
 +     * startup.  Returning an error from this function will prevent any network
 +     * device in this class from being opened.
       *
       * This function may be set to null if a network device class needs no
 -     * initialization at program startup. */
 +     * initialization at registration time. */
      int (*init)(void);
  
      /* Performs periodic work needed by netdevs of this class.  May be null if
       * to be called.  May be null if nothing is needed here. */
      void (*wait)(void);
  
 -    /* Attempts to create a network device object of 'type' with 'name'.  
 +    /* Attempts to create a network device of 'type' with 'name'.
       * 'type' corresponds to the 'type' field used in the netdev_class
 -     * structure.  
 -     *
 -     * The 'created' flag indicates that the user called netdev_create()
 -     * and thus will eventually call netdev_destroy().  If the flag is 
 -     * false, then the object was dynamically created based on a call to 
 -     * netdev_open() without first calling netdev_create() and will be
 -     * automatically destroyed when no more netdevs have 'name' open.  A 
 -     * provider implementation should pass this flag to netdev_obj_init(). */
 -    int (*create)(const char *name, const char *type, 
 -                  const struct shash *args, bool created);
 -
 -    /* Destroys 'netdev_obj'.  
 +     * structure. On success sets 'netdev_devp' to the newly created device. */
 +    int (*create)(const char *name, const char *type, const struct shash *args,
 +                  struct netdev_dev **netdev_devp);
 +
 +    /* Destroys 'netdev_dev'.
       *
 -     * Netdev objects maintain a reference count that is incremented on 
 -     * netdev_open() and decremented on netdev_close().  If 'netdev_obj' 
 -     * has a non-zero reference count, then this function will not be 
 +     * Netdev devices maintain a reference count that is incremented on
 +     * netdev_open() and decremented on netdev_close().  If 'netdev_dev'
 +     * has a non-zero reference count, then this function will not be
       * called. */
 -    void (*destroy)(struct netdev_obj *netdev_obj);
 +    void (*destroy)(struct netdev_dev *netdev_dev);
  
 -    /* Reconfigures the device object 'netdev_obj' with 'args'. 
 +    /* Reconfigures the device 'netdev_dev' with 'args'.
       *
       * If this netdev class does not support reconfiguring a netdev
 -     * object, this may be a null pointer.
 +     * device, this may be a null pointer.
       */
 -    int (*reconfigure)(struct netdev_obj *netdev_obj, 
 -                       const struct shash *args);
 +    int (*reconfigure)(struct netdev_dev *netdev_dev, const struct shash *args);
  
 -    /* Attempts to open a network device.  On success, sets '*netdevp' to the
 -     * new network device.  'name' is the network device name provided by
 -     * the user.  This name is useful for error messages but must not be
 -     * modified.
 +    /* Attempts to open a network device.  On success, sets 'netdevp'
 +     * to the new network device.
       *
       * 'ethertype' may be a 16-bit Ethernet protocol value in host byte order
       * to capture frames of that type received on the device.  It may also be
       * one of the 'enum netdev_pseudo_ethertype' values to receive frames in
       * one of those categories. */
 -    int (*open)(const char *name, int ethertype, struct netdev **netdevp);
 +    int (*open)(struct netdev_dev *netdev_dev, int ethertype,
 +                struct netdev **netdevp);
  
      /* Closes 'netdev'. */
      void (*close)(struct netdev *netdev);
       * The MTU is the maximum size of transmitted (and received) packets, in
       * bytes, not including the hardware header; thus, this is typically 1500
       * bytes for Ethernet devices.*/
 -    int (*get_mtu)(const struct netdev *, int *mtup);
 +    int (*get_mtu)(const struct netdev *netdev, int *mtup);
  
      /* Returns the ifindex of 'netdev', if successful, as a positive number.
       * On failure, returns a negative errno value.
       * ifindex value should be unique within a host and remain stable at least
       * until reboot.  SNMP says an ifindex "ranges between 1 and the value of
       * ifNumber" but many systems do not follow this rule anyhow. */
 -    int (*get_ifindex)(const struct netdev *);
 +    int (*get_ifindex)(const struct netdev *netdev);
  
      /* Sets 'carrier' to true if carrier is active (link light is on) on
       * 'netdev'. */
       * A network device that supports some statistics but not others, it should
       * set the values of the unsupported statistics to all-1-bits
       * (UINT64_MAX). */
 -    int (*get_stats)(const struct netdev *netdev, struct netdev_stats *stats);
 +    int (*get_stats)(const struct netdev *netdev, struct netdev_stats *);
  
      /* Stores the features supported by 'netdev' into each of '*current',
       * '*advertised', '*supported', and '*peer'.  Each value is a bitmap of
       *
       * This function may be set to null for a network device that does not
       * support configuring advertisements. */
 -    int (*set_advertisements)(struct netdev *, uint32_t advertise);
 +    int (*set_advertisements)(struct netdev *netdev, uint32_t advertise);
  
      /* If 'netdev' is a VLAN network device (e.g. one created with vconfig(8)),
       * sets '*vlan_vid' to the VLAN VID associated with that device and returns
       * 0.
       *
 -     * Returns ENOENT if 'netdev_name' is the name of a network device that is
 -     * not a VLAN device.
 +     * Returns ENOENT if 'netdev' is a network device that is not a
 +     * VLAN device.
       *
       * This function should be set to null if it doesn't make any sense for
       * your network device (it probably doesn't). */
       *
       * This function may be set to null if it would always return EOPNOTSUPP
       * anyhow. */
 -    int (*set_in4)(struct netdev *, struct in_addr addr, struct in_addr mask);
 +    int (*set_in4)(struct netdev *netdev, struct in_addr addr,
 +                   struct in_addr mask);
  
      /* If 'netdev' has an assigned IPv6 address, sets '*in6' to that address.
       *
       *
       * This function may be set to null if it would always return EOPNOTSUPP
       * anyhow. */
 -    int (*arp_lookup)(const struct netdev *, uint32_t ip, uint8_t mac[6]);
 +    int (*arp_lookup)(const struct netdev *netdev, uint32_t ip, uint8_t mac[6]);
  
 -    /* Retrieves the current set of flags on 'netdev' into '*old_flags'.  Then,
 -     * turns off the flags that are set to 1 in 'off' and turns on the flags
 -     * that are set to 1 in 'on'.  (No bit will be set to 1 in both 'off' and
 -     * 'on'; that is, off & on == 0.)
 +    /* Retrieves the current set of flags on 'netdev' into '*old_flags'.
 +     * Then, turns off the flags that are set to 1 in 'off' and turns on the
 +     * flags that are set to 1 in 'on'.  (No bit will be set to 1 in both 'off'
 +     * and 'on'; that is, off & on == 0.)
       *
       * This function may be invoked from a signal handler.  Therefore, it
       * should not do anything that is not signal-safe (such as logging). */
       * will have its 'netdev', 'cb', and 'aux' members set to the values of the
       * corresponding parameters. */
      int (*poll_add)(struct netdev *netdev,
 -                    void (*cb)(struct netdev_notifier *), void *aux,
 +                    void (*cb)(struct netdev_notifier *notifier), void *aux,
                      struct netdev_notifier **notifierp);
  
      /* Cancels poll notification for 'notifier'. */
  
  extern const struct netdev_class netdev_linux_class;
  extern const struct netdev_class netdev_tap_class;
 +extern const struct netdev_class netdev_gre_class;
  
+ #ifdef  __cplusplus
+ }
+ #endif
  #endif /* netdev.h */
diff --combined lib/netdev.c
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Copyright (c) 2008, 2009 Nicira Networks.
 + * Copyright (c) 2008, 2009, 2010 Nicira Networks.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
  #include "coverage.h"
  #include "dynamic-string.h"
  #include "fatal-signal.h"
 +#include "hash.h"
  #include "list.h"
  #include "netdev-provider.h"
  #include "ofpbuf.h"
+ #include "openflow/openflow.h"
  #include "packets.h"
  #include "poll-loop.h"
  #include "shash.h"
  #define THIS_MODULE VLM_netdev
  #include "vlog.h"
  
 -static const struct netdev_class *netdev_classes[] = {
 +static const struct netdev_class *base_netdev_classes[] = {
      &netdev_linux_class,
      &netdev_tap_class,
 +    &netdev_gre_class,
  };
 -static int n_netdev_classes = ARRAY_SIZE(netdev_classes);
 +
 +static struct shash netdev_classes = SHASH_INITIALIZER(&netdev_classes);
  
  /* All created network devices. */
 -static struct shash netdev_obj_shash = SHASH_INITIALIZER(&netdev_obj_shash);
 +static struct shash netdev_dev_shash = SHASH_INITIALIZER(&netdev_dev_shash);
  
  /* All open network devices. */
  static struct list netdev_list = LIST_INITIALIZER(&netdev_list);
   * additional log messages. */
  static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
  
 -static void restore_all_flags(void *aux);
 +static void close_all_netdevs(void *aux UNUSED);
  static int restore_flags(struct netdev *netdev);
 +void update_device_args(struct netdev_dev *, const struct shash *args);
  
 -/* Attempts to initialize the netdev module.  Returns 0 if successful,
 - * otherwise a positive errno value.
 - *
 - * Calling this function is optional.  If not called explicitly, it will
 - * automatically be called upon the first attempt to open or create a 
 - * network device. */
 -int
 +static void
  netdev_initialize(void)
  {
      static int status = -1;
 +
      if (status < 0) {
 -        int i, j;
 +        int i;
  
 -        fatal_signal_add_hook(restore_all_flags, NULL, true);
 +        fatal_signal_add_hook(close_all_netdevs, NULL, NULL, true);
  
          status = 0;
 -        for (i = j = 0; i < n_netdev_classes; i++) {
 -            const struct netdev_class *class = netdev_classes[i];
 -            if (class->init) {
 -                int retval = class->init();
 -                if (!retval) {
 -                    netdev_classes[j++] = class;
 -                } else {
 -                    VLOG_ERR("failed to initialize %s network device "
 -                             "class: %s", class->type, strerror(retval));
 -                    if (!status) {
 -                        status = retval;
 -                    }
 -                }
 -            } else {
 -                netdev_classes[j++] = class;
 -            }
 +        for (i = 0; i < ARRAY_SIZE(base_netdev_classes); i++) {
 +            netdev_register_provider(base_netdev_classes[i]);
          }
 -        n_netdev_classes = j;
      }
 -    return status;
  }
  
  /* Performs periodic work needed by all the various kinds of netdevs.
  void
  netdev_run(void)
  {
 -    int i;
 -    for (i = 0; i < n_netdev_classes; i++) {
 -        const struct netdev_class *class = netdev_classes[i];
 +    struct shash_node *node;
 +    SHASH_FOR_EACH(node, &netdev_classes) {
 +        const struct netdev_class *class = node->data;
          if (class->run) {
              class->run();
          }
  void
  netdev_wait(void)
  {
 -    int i;
 -    for (i = 0; i < n_netdev_classes; i++) {
 -        const struct netdev_class *class = netdev_classes[i];
 +    struct shash_node *node;
 +    SHASH_FOR_EACH(node, &netdev_classes) {
 +        const struct netdev_class *class = node->data;
          if (class->wait) {
              class->wait();
          }
      }
  }
  
 -/* Attempts to create a network device object of 'type' with 'name'.  'type' 
 - * corresponds to the 'type' field used in the netdev_class * structure.  
 - * Arguments for creation are provided in 'args', which may be empty or NULL 
 - * if none are needed. */
 +/* Initializes and registers a new netdev provider.  After successful
 + * registration, new netdevs of that type can be opened using netdev_open(). */
  int
 -netdev_create(const char *name, const char *type, const struct shash *args)
 +netdev_register_provider(const struct netdev_class *new_class)
  {
 -    struct shash empty_args = SHASH_INITIALIZER(&empty_args);
 -    int i;
 +    struct netdev_class *new_provider;
  
 -    netdev_initialize();
 +    if (shash_find(&netdev_classes, new_class->type)) {
 +        VLOG_WARN("attempted to register duplicate netdev provider: %s",
 +                   new_class->type);
 +        return EEXIST;
 +    }
  
 -    if (!args) {
 -        args = &empty_args;
 +    if (new_class->init) {
 +        int error = new_class->init();
 +        if (error) {
 +            VLOG_ERR("failed to initialize %s network device class: %s",
 +                     new_class->type, strerror(error));
 +            return error;
 +        }
      }
  
 -    if (shash_find(&netdev_obj_shash, name)) {
 -        VLOG_WARN("attempted to create a netdev object with bound name: %s",
 -                name);
 -        return EEXIST;
 +    new_provider = xmalloc(sizeof *new_provider);
 +    memcpy(new_provider, new_class, sizeof *new_provider);
 +
 +    shash_add(&netdev_classes, new_class->type, new_provider);
 +
 +    return 0;
 +}
 +
 +/* Unregisters a netdev provider.  'type' must have been previously
 + * registered and not currently be in use by any netdevs.  After unregistration
 + * new netdevs of that type cannot be opened using netdev_open(). */
 +int
 +netdev_unregister_provider(const char *type)
 +{
 +    struct shash_node *del_node, *netdev_dev_node;
 +
 +    del_node = shash_find(&netdev_classes, type);
 +    if (!del_node) {
 +        VLOG_WARN("attempted to unregister a netdev provider that is not "
 +                  "registered: %s", type);
 +        return EAFNOSUPPORT;
      }
  
 -    for (i = 0; i < n_netdev_classes; i++) {
 -        const struct netdev_class *class = netdev_classes[i];
 -        if (!strcmp(type, class->type)) {
 -            return class->create(name, type, args, true);
 +    SHASH_FOR_EACH(netdev_dev_node, &netdev_dev_shash) {
 +        struct netdev_dev *netdev_dev = netdev_dev_node->data;
-         if (!strcmp(netdev_dev->class->type, type)) {
++        if (!strcmp(netdev_dev->netdev_class->type, type)) {
 +            VLOG_WARN("attempted to unregister in use netdev provider: %s",
 +                      type);
 +            return EBUSY;
          }
      }
  
 -    VLOG_WARN("could not create netdev object of unknown type: %s", type);
 +    shash_delete(&netdev_classes, del_node);
 +    free(del_node->data);
  
 -    return EINVAL;
 +    return 0;
  }
  
 -/* Destroys netdev object 'name'.  Netdev objects maintain a reference count
 - * which is incremented on netdev_open() and decremented on netdev_close().  
 - * If 'name' has a non-zero reference count, it will not destroy the object 
 - * and return EBUSY. */
 -int
 -netdev_destroy(const char *name)
 +/* Clears 'types' and enumerates the types of all currently registered netdev
 + * providers into it.  The caller must first initialize the svec. */
 +void
 +netdev_enumerate_types(struct svec *types)
  {
      struct shash_node *node;
 -    struct netdev_obj *netdev_obj;
  
 -    node = shash_find(&netdev_obj_shash, name);
 -    if (!node) {
 -        return ENODEV;
 +    netdev_initialize();
 +    svec_clear(types);
 +
 +    SHASH_FOR_EACH(node, &netdev_classes) {
 +        const struct netdev_class *netdev_class = node->data;
 +        svec_add(types, netdev_class->type);
      }
 +}
 +
 +/* Compares 'args' to those used to those used by 'dev'.  Returns true
 + * if the arguments are the same, false otherwise.  Does not update the
 + * values stored in 'dev'. */
 +static bool
 +compare_device_args(const struct netdev_dev *dev, const struct shash *args)
 +{
 +    const struct shash_node **new_args;
 +    bool result = true;
 +    int i;
  
 -    netdev_obj = node->data;
 -    if (netdev_obj->ref_cnt != 0) {
 -        VLOG_WARN("attempt to destroy open netdev object (%d): %s", 
 -                netdev_obj->ref_cnt, name);
 -        return EBUSY;
 +    if (shash_count(args) != dev->n_args) {
 +        return false;
      }
  
 -    shash_delete(&netdev_obj_shash, node);
 -    netdev_obj->netdev_class->destroy(netdev_obj);
 +    new_args = shash_sort(args);
 +    for (i = 0; i < dev->n_args; i++) {
 +        if (strcmp(dev->args[i].key, new_args[i]->name) || 
 +            strcmp(dev->args[i].value, new_args[i]->data)) {
 +            result = false;
 +            goto finish;
 +        }
 +    }
  
 -    return 0;
 +finish:
 +    free(new_args);
 +    return result;
  }
  
 -/* Reconfigures the device object 'name' with 'args'.  'args' may be empty 
 - * or NULL if none are needed. */
 -int
 -netdev_reconfigure(const char *name, const struct shash *args)
 +static int
 +compare_args(const void *a_, const void *b_)
  {
 -    struct shash empty_args = SHASH_INITIALIZER(&empty_args);
 -    struct netdev_obj *netdev_obj;
 +    const struct arg *a = a_;
 +    const struct arg *b = b_;
 +    return strcmp(a->key, b->key);
 +}
  
 -    if (!args) {
 -        args = &empty_args;
 +void
 +update_device_args(struct netdev_dev *dev, const struct shash *args)
 +{
 +    struct shash_node *node;
 +    int i;
 +
 +    if (dev->n_args) {
 +        for (i = 0; i < dev->n_args; i++) {
 +            free(dev->args[i].key);
 +            free(dev->args[i].value);
 +        }
 +
 +        free(dev->args);
 +        dev->n_args = 0;
 +    }
 +
 +    if (!args || shash_is_empty(args)) {
 +        return;
      }
  
 -    netdev_obj = shash_find_data(&netdev_obj_shash, name);
 -    if (!netdev_obj) {
 +    dev->n_args = shash_count(args);
 +    dev->args = xmalloc(dev->n_args * sizeof *dev->args);
 +
 +    i = 0;
 +    SHASH_FOR_EACH(node, args) {
 +        dev->args[i].key = xstrdup(node->name);
 +        dev->args[i].value = xstrdup(node->data);
 +        i++;
 +    }
 +
 +    qsort(dev->args, dev->n_args, sizeof *dev->args, compare_args);
 +}
 +
 +static int
 +create_device(struct netdev_options *options, struct netdev_dev **netdev_devp)
 +{
 +    struct netdev_class *netdev_class;
 +
 +    if (!options->may_create) {
 +        VLOG_WARN("attempted to create a device that may not be created: %s",
 +                  options->name);
          return ENODEV;
      }
  
 -    if (netdev_obj->netdev_class->reconfigure) {
 -        return netdev_obj->netdev_class->reconfigure(netdev_obj, args);
 +    if (!options->type || strlen(options->type) == 0) {
 +        /* Default to system. */
 +        options->type = "system";
      }
  
 -    return 0;
 +    netdev_class = shash_find_data(&netdev_classes, options->type);
 +    if (!netdev_class) {
 +        VLOG_WARN("could not create netdev %s of unknown type %s",
 +                  options->name, options->type);
 +        return EAFNOSUPPORT;
 +    }
 +
 +    return netdev_class->create(options->name, options->type, options->args,
 +                                netdev_devp);
  }
  
  /* Opens the network device named 'name' (e.g. "eth0") and returns zero if
   * successful, otherwise a positive errno value.  On success, sets '*netdevp'
   * to the new network device, otherwise to null.
   *
 + * If this is the first time the device has been opened, then create is called
 + * before opening.  The device is  created using the given type and arguments.
 + *
   * 'ethertype' may be a 16-bit Ethernet protocol value in host byte order to
   * capture frames of that type received on the device.  It may also be one of
   * the 'enum netdev_pseudo_ethertype' values to receive frames in one of those
 - * categories. */
 + * categories.
 + *
 + * If the 'may_create' flag is set then this is allowed to be the first time
 + * the device is opened (i.e. the refcount will be 1 after this call).  It
 + * may be set to false if the device should have already been created.
 + *
 + * If the 'may_open' flag is set then the call will succeed even if another
 + * caller has already opened it.  It may be to false if the device should not
 + * currently be open. */
 +
  int
 -netdev_open(const char *name, int ethertype, struct netdev **netdevp)
 +netdev_open(struct netdev_options *options, struct netdev **netdevp)
  {
 -    struct netdev_obj *netdev_obj;
 -    struct netdev *netdev = NULL;
 +    struct shash empty_args = SHASH_INITIALIZER(&empty_args);
 +    struct netdev_dev *netdev_dev;
      int error;
 -    int i;
  
 +    *netdevp = NULL;
      netdev_initialize();
  
 -    netdev_obj = shash_find_data(&netdev_obj_shash, name);
 -    if (netdev_obj) {
 -        error = netdev_obj->netdev_class->open(name, ethertype, &netdev);
 -    } else {
 -        /* Default to "system". */
 -        error = EAFNOSUPPORT;
 -        for (i = 0; i < n_netdev_classes; i++) {
 -            const struct netdev_class *class = netdev_classes[i];
 -            if (!strcmp(class->type, "system")) {
 -                struct shash empty_args = SHASH_INITIALIZER(&empty_args);
 -
 -                /* Dynamically create the netdev object, but indicate
 -                 * that it should be destroyed when the the last user
 -                 * closes its handle. */
 -                error = class->create(name, "system", &empty_args, false);
 -                if (!error) {
 -                    error = class->open(name, ethertype, &netdev);
 -                    netdev_obj = shash_find_data(&netdev_obj_shash, name);
 -                }
 -                break;
 -            }
 +    if (!options->args) {
 +        options->args = &empty_args;
 +    }
 +
 +    netdev_dev = shash_find_data(&netdev_dev_shash, options->name);
 +
 +    if (!netdev_dev) {
 +        error = create_device(options, &netdev_dev);
 +        if (error) {
 +            return error;
          }
 +        update_device_args(netdev_dev, options->args);
 +
 +    } else if (options->may_open) {
 +        if (!shash_is_empty(options->args) &&
 +            !compare_device_args(netdev_dev, options->args)) {
 +
 +            VLOG_WARN("%s: attempted to open already created netdev with "
 +                      "different arguments", options->name);
 +            return EINVAL;
 +        }
 +    } else {
 +        VLOG_WARN("%s: attempted to create a netdev device with bound name",
 +                  options->name);
 +        return EEXIST;
      }
-     error = netdev_dev->class->open(netdev_dev, options->ethertype, netdevp);
 +
++    error = netdev_dev->netdev_class->open(netdev_dev, options->ethertype, 
++                netdevp);
 +
      if (!error) {
 -        netdev_obj->ref_cnt++;
 +        netdev_dev->ref_cnt++;
 +    } else {
 +        if (!netdev_dev->ref_cnt) {
 +            netdev_dev_uninit(netdev_dev, true);
 +        }
      }
  
 -    *netdevp = error ? NULL : netdev;
      return error;
  }
  
-     if (netdev_dev->class->reconfigure) {
 +int
 +netdev_open_default(const char *name, struct netdev **netdevp)
 +{
 +    struct netdev_options options;
 +
 +    memset(&options, 0, sizeof options);
 +
 +    options.name = name;
 +    options.ethertype = NETDEV_ETH_TYPE_NONE;
 +    options.may_create = true;
 +    options.may_open = true;
 +
 +    return netdev_open(&options, netdevp);
 +}
 +
 +/* Reconfigures the device 'netdev' with 'args'.  'args' may be empty
 + * or NULL if none are needed. */
 +int
 +netdev_reconfigure(struct netdev *netdev, const struct shash *args)
 +{
 +    struct shash empty_args = SHASH_INITIALIZER(&empty_args);
 +    struct netdev_dev *netdev_dev = netdev_get_dev(netdev);
 +
 +    if (!args) {
 +        args = &empty_args;
 +    }
 +
-             return netdev_dev->class->reconfigure(netdev_dev, args);
++    if (netdev_dev->netdev_class->reconfigure) {
 +        if (!compare_device_args(netdev_dev, args)) {
 +            update_device_args(netdev_dev, args);
++            return netdev_dev->netdev_class->reconfigure(netdev_dev, args);
 +        }
 +    } else if (!shash_is_empty(args)) {
 +        VLOG_WARN("%s: arguments provided to device that does not have a "
 +                  "reconfigure function", netdev_get_name(netdev));
 +    }
 +
 +    return 0;
 +}
 +
  /* Closes and destroys 'netdev'. */
  void
  netdev_close(struct netdev *netdev)
  {
      if (netdev) {
 -        struct netdev_obj *netdev_obj;
 -        char *name = netdev->name;
 -        int error;
 -
 -        netdev_obj = shash_find_data(&netdev_obj_shash, name);
 -        assert(netdev_obj);
 -        if (netdev_obj->ref_cnt > 0) {
 -            netdev_obj->ref_cnt--;
 -        } else {
 -            VLOG_WARN("netdev %s closed too many times", name);
 -        }
 +        struct netdev_dev *netdev_dev = netdev_get_dev(netdev);
  
 -        /* If the reference count for the netdev object is zero, and it
 -         * was dynamically created by netdev_open(), destroy it. */
 -        if (!netdev_obj->ref_cnt && !netdev_obj->created) {
 -            netdev_destroy(name);
 -        }
 +        assert(netdev_dev->ref_cnt);
 +        netdev_dev->ref_cnt--;
 +        netdev_uninit(netdev, true);
  
 -        /* Restore flags that we changed, if any. */
 -        fatal_signal_block();
 -        error = restore_flags(netdev);
 -        list_remove(&netdev->node);
 -        fatal_signal_unblock();
 -        if (error) {
 -            VLOG_WARN("failed to restore network device flags on %s: %s",
 -                      name, strerror(error));
 +        /* If the reference count for the netdev device is zero, destroy it. */
 +        if (!netdev_dev->ref_cnt) {
 +            netdev_dev_uninit(netdev_dev, true);
          }
 -
 -        /* Free. */
 -        netdev->netdev_class->close(netdev);
 -        free(name);
      }
  }
  
@@@ -419,7 -311,7 +421,7 @@@ netdev_exists(const char *name
      struct netdev *netdev;
      int error;
  
 -    error = netdev_open(name, NETDEV_ETH_TYPE_NONE, &netdev);
 +    error = netdev_open_default(name, &netdev);
      if (!error) {
          netdev_close(netdev);
          return true;
      }
  }
  
 -/* Initializes 'svec' with a list of the names of all known network devices. */
 +/*  Clears 'svec' and enumerates the names of all known network devices. */
  int
  netdev_enumerate(struct svec *svec)
  {
 -    int error;
 -    int i;
 -
 -    svec_init(svec);
 +    struct shash_node *node;
 +    int error = 0;
  
      netdev_initialize();
 +    svec_clear(svec);
  
 -    error = 0;
 -    for (i = 0; i < n_netdev_classes; i++) {
 -        const struct netdev_class *class = netdev_classes[i];
 -        if (class->enumerate) {
 -            int retval = class->enumerate(svec);
 +    SHASH_FOR_EACH(node, &netdev_classes) {
 +        const struct netdev_class *netdev_class = node->data;
 +        if (netdev_class->enumerate) {
 +            int retval = netdev_class->enumerate(svec);
              if (retval) {
                  VLOG_WARN("failed to enumerate %s network devices: %s",
 -                          class->type, strerror(retval));
 +                          netdev_class->type, strerror(retval));
                  if (!error) {
                      error = retval;
                  }
              }
          }
      }
 +
      return error;
  }
  
@@@ -479,8 -372,8 +481,8 @@@ netdev_recv(struct netdev *netdev, stru
      assert(buffer->size == 0);
      assert(ofpbuf_tailroom(buffer) >= ETH_TOTAL_MIN);
  
-     retval = netdev_get_dev(netdev)->class->recv(netdev, buffer->data,
 -    retval = netdev->netdev_class->recv(netdev,
 -                                        buffer->data, ofpbuf_tailroom(buffer));
++    retval = netdev_get_dev(netdev)->netdev_class->recv(netdev, buffer->data,
 +             ofpbuf_tailroom(buffer));
      if (retval >= 0) {
          COVERAGE_INC(netdev_received);
          buffer->size += retval;
  void
  netdev_recv_wait(struct netdev *netdev)
  {
-     netdev_get_dev(netdev)->class->recv_wait(netdev);
 -    netdev->netdev_class->recv_wait(netdev);
++    netdev_get_dev(netdev)->netdev_class->recv_wait(netdev);
  }
  
  /* Discards all packets waiting to be received from 'netdev'. */
  int
  netdev_drain(struct netdev *netdev)
  {
-     return netdev_get_dev(netdev)->class->drain(netdev);
 -    return netdev->netdev_class->drain(netdev);
++    return netdev_get_dev(netdev)->netdev_class->drain(netdev);
  }
  
  /* Sends 'buffer' on 'netdev'.  Returns 0 if successful, otherwise a positive
  int
  netdev_send(struct netdev *netdev, const struct ofpbuf *buffer)
  {
-     int error = netdev_get_dev(netdev)->class->send(netdev, buffer->data,
-                                                     buffer->size);
 -    int error = netdev->netdev_class->send(netdev, buffer->data, buffer->size);
++    int error = netdev_get_dev(netdev)->netdev_class->send(netdev, 
++            buffer->data, buffer->size);
      if (!error) {
          COVERAGE_INC(netdev_sent);
      }
  void
  netdev_send_wait(struct netdev *netdev)
  {
-     return netdev_get_dev(netdev)->class->send_wait(netdev);
 -    return netdev->netdev_class->send_wait(netdev);
++    return netdev_get_dev(netdev)->netdev_class->send_wait(netdev);
  }
  
  /* Attempts to set 'netdev''s MAC address to 'mac'.  Returns 0 if successful,
  int
  netdev_set_etheraddr(struct netdev *netdev, const uint8_t mac[ETH_ADDR_LEN])
  {
-     return netdev_get_dev(netdev)->class->set_etheraddr(netdev, mac);
 -    return netdev->netdev_class->set_etheraddr(netdev, mac);
++    return netdev_get_dev(netdev)->netdev_class->set_etheraddr(netdev, mac);
  }
  
  /* Retrieves 'netdev''s MAC address.  If successful, returns 0 and copies the
  int
  netdev_get_etheraddr(const struct netdev *netdev, uint8_t mac[ETH_ADDR_LEN])
  {
-     return netdev_get_dev(netdev)->class->get_etheraddr(netdev, mac);
 -    return netdev->netdev_class->get_etheraddr(netdev, mac);
++    return netdev_get_dev(netdev)->netdev_class->get_etheraddr(netdev, mac);
  }
  
  /* Returns the name of the network device that 'netdev' represents,
  const char *
  netdev_get_name(const struct netdev *netdev)
  {
 -    return netdev->name;
 +    return netdev_get_dev(netdev)->name;
  }
  
  /* Retrieves the MTU of 'netdev'.  The MTU is the maximum size of transmitted
  int
  netdev_get_mtu(const struct netdev *netdev, int *mtup)
  {
-     int error = netdev_get_dev(netdev)->class->get_mtu(netdev, mtup);
 -    int error = netdev->netdev_class->get_mtu(netdev, mtup);
++    int error = netdev_get_dev(netdev)->netdev_class->get_mtu(netdev, mtup);
      if (error) {
          VLOG_WARN_RL(&rl, "failed to retrieve MTU for network device %s: %s",
                       netdev_get_name(netdev), strerror(error));
  int
  netdev_get_ifindex(const struct netdev *netdev)
  {
-     return netdev_get_dev(netdev)->class->get_ifindex(netdev);
 -    return netdev->netdev_class->get_ifindex(netdev);
++    return netdev_get_dev(netdev)->netdev_class->get_ifindex(netdev);
  }
  
  /* Stores the features supported by 'netdev' into each of '*current',
@@@ -626,23 -518,50 +628,51 @@@ netdev_get_features(struct netdev *netd
          peer = &dummy[3];
      }
  
-     error = netdev_get_dev(netdev)->class->get_features(netdev, current,
-                                                         advertised, supported,
-                                                         peer);
 -    error = netdev->netdev_class->get_features(netdev, current, advertised,
 -                                               supported, peer);
++    error = netdev_get_dev(netdev)->netdev_class->get_features(netdev, current,
++            advertised, supported, peer);
      if (error) {
          *current = *advertised = *supported = *peer = 0;
      }
      return error;
  }
  
+ /* Returns the maximum speed of a network connection that has the "enum
+  * ofp_port_features" bits in 'features', in bits per second.  If no bits that
+  * indicate a speed are set in 'features', assumes 100Mbps. */
+ uint64_t
+ netdev_features_to_bps(uint32_t features)
+ {
+     enum {
+         F_10000MB = OFPPF_10GB_FD,
+         F_1000MB = OFPPF_1GB_HD | OFPPF_1GB_FD,
+         F_100MB = OFPPF_100MB_HD | OFPPF_100MB_FD,
+         F_10MB = OFPPF_10MB_HD | OFPPF_10MB_FD
+     };
+     return (  features & F_10000MB  ? UINT64_C(10000000000)
+             : features & F_1000MB   ? UINT64_C(1000000000)
+             : features & F_100MB    ? UINT64_C(100000000)
+             : features & F_10MB     ? UINT64_C(10000000)
+                                     : UINT64_C(100000000));
+ }
+ /* Returns true if any of the "enum ofp_port_features" bits that indicate a
+  * full-duplex link are set in 'features', otherwise false. */
+ bool
+ netdev_features_is_full_duplex(uint32_t features)
+ {
+     return (features & (OFPPF_10MB_FD | OFPPF_100MB_FD | OFPPF_1GB_FD
+                         | OFPPF_10GB_FD)) != 0;
+ }
  /* Set the features advertised by 'netdev' to 'advertise'.  Returns 0 if
   * successful, otherwise a positive errno value. */
  int
  netdev_set_advertisements(struct netdev *netdev, uint32_t advertise)
  {
-     return (netdev_get_dev(netdev)->class->set_advertisements
-             ? netdev_get_dev(netdev)->class->set_advertisements(netdev,
-                                                                 advertise)
 -    return (netdev->netdev_class->set_advertisements
 -            ? netdev->netdev_class->set_advertisements(netdev, advertise)
++    return (netdev_get_dev(netdev)->netdev_class->set_advertisements
++            ? netdev_get_dev(netdev)->netdev_class->set_advertisements(
++                    netdev, advertise)
              : EOPNOTSUPP);
  }
  
@@@ -666,9 -585,8 +696,9 @@@ netdev_get_in4(const struct netdev *net
      struct in_addr netmask;
      int error;
  
-     error = (netdev_get_dev(netdev)->class->get_in4
-              ? netdev_get_dev(netdev)->class->get_in4(netdev, &address,
-                                                       &netmask)
 -    error = (netdev->netdev_class->get_in4
 -             ? netdev->netdev_class->get_in4(netdev, &address, &netmask)
++    error = (netdev_get_dev(netdev)->netdev_class->get_in4
++             ? netdev_get_dev(netdev)->netdev_class->get_in4(netdev, 
++                    &address, &netmask)
               : EOPNOTSUPP);
      if (address_) {
          address_->s_addr = error ? 0 : address.s_addr;
  int
  netdev_set_in4(struct netdev *netdev, struct in_addr addr, struct in_addr mask)
  {
-     return (netdev_get_dev(netdev)->class->set_in4
-             ? netdev_get_dev(netdev)->class->set_in4(netdev, addr, mask)
 -    return (netdev->netdev_class->set_in4
 -            ? netdev->netdev_class->set_in4(netdev, addr, mask)
++    return (netdev_get_dev(netdev)->netdev_class->set_in4
++            ? netdev_get_dev(netdev)->netdev_class->set_in4(netdev, addr, mask)
              : EOPNOTSUPP);
  }
  
@@@ -696,8 -614,8 +726,8 @@@ in
  netdev_add_router(struct netdev *netdev, struct in_addr router)
  {
      COVERAGE_INC(netdev_add_router);
-     return (netdev_get_dev(netdev)->class->add_router
-             ? netdev_get_dev(netdev)->class->add_router(netdev, router)
 -    return (netdev->netdev_class->add_router
 -            ? netdev->netdev_class->add_router(netdev, router)
++    return (netdev_get_dev(netdev)->netdev_class->add_router
++            ? netdev_get_dev(netdev)->netdev_class->add_router(netdev, router)
              : EOPNOTSUPP);
  }
  
@@@ -713,9 -631,9 +743,9 @@@ netdev_get_next_hop(const struct netde
                      const struct in_addr *host, struct in_addr *next_hop,
                      char **netdev_name)
  {
-     int error = (netdev_get_dev(netdev)->class->get_next_hop
-                  ? netdev_get_dev(netdev)->class->get_next_hop(host, next_hop,
-                                                                netdev_name)
 -    int error = (netdev->netdev_class->get_next_hop
 -                 ? netdev->netdev_class->get_next_hop(host, next_hop,
 -                                                      netdev_name)
++    int error = (netdev_get_dev(netdev)->netdev_class->get_next_hop
++                 ? netdev_get_dev(netdev)->netdev_class->get_next_hop(
++                        host, next_hop, netdev_name)
                   : EOPNOTSUPP);
      if (error) {
          next_hop->s_addr = 0;
@@@ -741,9 -659,8 +771,9 @@@ netdev_get_in6(const struct netdev *net
      struct in6_addr dummy;
      int error;
  
-     error = (netdev_get_dev(netdev)->class->get_in6
-              ? netdev_get_dev(netdev)->class->get_in6(netdev, in6 ? in6
-                                                                   : &dummy)
 -    error = (netdev->netdev_class->get_in6
 -             ? netdev->netdev_class->get_in6(netdev, in6 ? in6 : &dummy)
++    error = (netdev_get_dev(netdev)->netdev_class->get_in6
++             ? netdev_get_dev(netdev)->netdev_class->get_in6(netdev, 
++                    in6 ? in6 : &dummy)
               : EOPNOTSUPP);
      if (error && in6) {
          memset(in6, 0, sizeof *in6);
@@@ -763,8 -680,8 +793,8 @@@ do_update_flags(struct netdev *netdev, 
      enum netdev_flags old_flags;
      int error;
  
-     error = netdev_get_dev(netdev)->class->update_flags(netdev, off & ~on, on,
-                                                         &old_flags);
 -    error = netdev->netdev_class->update_flags(netdev, off & ~on,
 -                                               on, &old_flags);
++    error = netdev_get_dev(netdev)->netdev_class->update_flags(netdev, 
++                off & ~on, on, &old_flags);
      if (error) {
          VLOG_WARN_RL(&rl, "failed to %s flags for network device %s: %s",
                       off || on ? "set" : "get", netdev_get_name(netdev),
@@@ -837,8 -754,8 +867,9 @@@ in
  netdev_arp_lookup(const struct netdev *netdev,
                    uint32_t ip, uint8_t mac[ETH_ADDR_LEN])
  {
-     int error = (netdev_get_dev(netdev)->class->arp_lookup
-                  ? netdev_get_dev(netdev)->class->arp_lookup(netdev, ip, mac)
 -    int error = (netdev->netdev_class->arp_lookup
 -                 ? netdev->netdev_class->arp_lookup(netdev, ip, mac)
++    int error = (netdev_get_dev(netdev)->netdev_class->arp_lookup
++                 ? netdev_get_dev(netdev)->netdev_class->arp_lookup(netdev, 
++                        ip, mac)
                   : EOPNOTSUPP);
      if (error) {
          memset(mac, 0, ETH_ADDR_LEN);
  int
  netdev_get_carrier(const struct netdev *netdev, bool *carrier)
  {
-     int error = (netdev_get_dev(netdev)->class->get_carrier
-                  ? netdev_get_dev(netdev)->class->get_carrier(netdev, carrier)
 -    int error = (netdev->netdev_class->get_carrier
 -                 ? netdev->netdev_class->get_carrier(netdev, carrier)
++    int error = (netdev_get_dev(netdev)->netdev_class->get_carrier
++                 ? netdev_get_dev(netdev)->netdev_class->get_carrier(netdev, 
++                        carrier)
                   : EOPNOTSUPP);
      if (error) {
          *carrier = false;
@@@ -867,8 -784,8 +899,8 @@@ netdev_get_stats(const struct netdev *n
      int error;
  
      COVERAGE_INC(netdev_get_stats);
-     error = (netdev_get_dev(netdev)->class->get_stats
-              ? netdev_get_dev(netdev)->class->get_stats(netdev, stats)
 -    error = (netdev->netdev_class->get_stats
 -             ? netdev->netdev_class->get_stats(netdev, stats)
++    error = (netdev_get_dev(netdev)->netdev_class->get_stats
++             ? netdev_get_dev(netdev)->netdev_class->get_stats(netdev, stats)
               : EOPNOTSUPP);
      if (error) {
          memset(stats, 0xff, sizeof *stats);
@@@ -883,9 -800,9 +915,9 @@@ in
  netdev_set_policing(struct netdev *netdev, uint32_t kbits_rate,
                      uint32_t kbits_burst)
  {
-     return (netdev_get_dev(netdev)->class->set_policing
-             ? netdev_get_dev(netdev)->class->set_policing(netdev, kbits_rate,
-                                                           kbits_burst)
 -    return (netdev->netdev_class->set_policing
 -            ? netdev->netdev_class->set_policing(netdev,
 -                                                 kbits_rate, kbits_burst)
++    return (netdev_get_dev(netdev)->netdev_class->set_policing
++            ? netdev_get_dev(netdev)->netdev_class->set_policing(netdev, 
++                    kbits_rate, kbits_burst)
              : EOPNOTSUPP);
  }
  
  int
  netdev_get_vlan_vid(const struct netdev *netdev, int *vlan_vid)
  {
-     int error = (netdev_get_dev(netdev)->class->get_vlan_vid
-                  ? netdev_get_dev(netdev)->class->get_vlan_vid(netdev, vlan_vid)
 -    int error = (netdev->netdev_class->get_vlan_vid
 -                 ? netdev->netdev_class->get_vlan_vid(netdev, vlan_vid)
++    int error = (netdev_get_dev(netdev)->netdev_class->get_vlan_vid
++                 ? netdev_get_dev(netdev)->netdev_class->get_vlan_vid(netdev, 
++                        vlan_vid)
                   : ENOENT);
      if (error) {
          *vlan_vid = 0;
@@@ -912,7 -829,7 +945,7 @@@ struct netdev 
  netdev_find_dev_by_in4(const struct in_addr *in4)
  {
      struct netdev *netdev;
 -    struct svec dev_list;
 +    struct svec dev_list = SVEC_EMPTY_INITIALIZER;
      size_t i;
  
      netdev_enumerate(&dev_list);
          const char *name = dev_list.names[i];
          struct in_addr dev_in4;
  
 -        if (!netdev_open(name, NETDEV_ETH_TYPE_NONE, &netdev)
 +        if (!netdev_open_default(name, &netdev)
              && !netdev_get_in4(netdev, &dev_in4, NULL)
              && dev_in4.s_addr == in4->s_addr) {
              goto exit;
@@@ -934,140 -851,46 +967,140 @@@ exit
      return netdev;
  }
  \f
 -/* Initializes 'netdev_obj' as a netdev object named 'name' of the 
 +/* Initializes 'netdev_dev' as a netdev device named 'name' of the
-  * specified 'class'.
+  * specified 'netdev_class'.
   *
 - * This function adds 'netdev_obj' to a netdev-owned shash, so it is
 - * very important that 'netdev_obj' only be freed after calling
 - * netdev_destroy().  */
 + * This function adds 'netdev_dev' to a netdev-owned shash, so it is
 + * very important that 'netdev_dev' only be freed after calling
 + * the refcount drops to zero.  */
  void
 -netdev_obj_init(struct netdev_obj *netdev_obj, const char *name,
 -                const struct netdev_class *netdev_class, bool created)
 +netdev_dev_init(struct netdev_dev *netdev_dev, const char *name,
-                 const struct netdev_class *class)
++                const struct netdev_class *class_)
  {
 -    assert(!shash_find(&netdev_obj_shash, name));
 +    assert(!shash_find(&netdev_dev_shash, name));
  
 -    netdev_obj->netdev_class = netdev_class;
 -    netdev_obj->ref_cnt = 0;
 -    netdev_obj->created = created;
 -    shash_add(&netdev_obj_shash, name, netdev_obj);
 +    memset(netdev_dev, 0, sizeof *netdev_dev);
-     netdev_dev->class = class;
++    netdev_dev->netdev_class = class_;
 +    netdev_dev->name = xstrdup(name);
 +    netdev_dev->node = shash_add(&netdev_dev_shash, name, netdev_dev);
  }
  
 -/* Initializes 'netdev' as a netdev named 'name' of the specified
 - * 'netdev_class'.
 +/* Undoes the results of initialization.
 + *
 + * Normally this function does not need to be called as netdev_close has
 + * the same effect when the refcount drops to zero.
 + * However, it may be called by providers due to an error on creation
 + * that occurs after initialization.  It this case netdev_close() would
 + * never be called. */
 +void
 +netdev_dev_uninit(struct netdev_dev *netdev_dev, bool destroy)
 +{
 +    char *name = netdev_dev->name;
 +
 +    assert(!netdev_dev->ref_cnt);
 +
 +    shash_delete(&netdev_dev_shash, netdev_dev->node);
 +    update_device_args(netdev_dev, NULL);
 +
 +    if (destroy) {
-         netdev_dev->class->destroy(netdev_dev);
++        netdev_dev->netdev_class->destroy(netdev_dev);
 +    }
 +    free(name);
 +}
 +
 +/* Returns the class type of 'netdev_dev'.
 + *
 + * The caller must not free the returned value. */
 +const char *
 +netdev_dev_get_type(const struct netdev_dev *netdev_dev)
 +{
-     return netdev_dev->class->type;
++    return netdev_dev->netdev_class->type;
 +}
 +
 +/* Returns the name of 'netdev_dev'.
 + *
 + * The caller must not free the returned value. */
 +const char *
 +netdev_dev_get_name(const struct netdev_dev *netdev_dev)
 +{
 +    return netdev_dev->name;
 +}
 +
 +/* Returns the netdev_dev with 'name' or NULL if there is none.
 + *
 + * The caller must not free the returned value. */
 +struct netdev_dev *
 +netdev_dev_from_name(const char *name)
 +{
 +    return shash_find_data(&netdev_dev_shash, name);
 +}
 +
 +/* Fills 'device_list' with devices that match 'class'.
 + *
 + * The caller is responsible for initializing and destroying 'device_list'
 + * but the contained netdev_devs must not be freed. */
 +void
- netdev_dev_get_devices(const struct netdev_class *class,
++netdev_dev_get_devices(const struct netdev_class *class_,
 +                       struct shash *device_list)
 +{
 +    struct shash_node *node;
 +    SHASH_FOR_EACH (node, &netdev_dev_shash) {
 +        struct netdev_dev *dev = node->data;
 +
-         if (dev->class == class) {
++        if (dev->netdev_class == class_) {
 +            shash_add(device_list, node->name, node->data);
 +        }
 +    }
 +}
 +
 +/* Initializes 'netdev' as a instance of the netdev_dev.
   *
   * This function adds 'netdev' to a netdev-owned linked list, so it is very
   * important that 'netdev' only be freed after calling netdev_close(). */
  void
 -netdev_init(struct netdev *netdev, const char *name,
 -            const struct netdev_class *netdev_class)
 +netdev_init(struct netdev *netdev, struct netdev_dev *netdev_dev)
  {
 -    netdev->netdev_class = netdev_class;
 -    netdev->name = xstrdup(name);
 -    netdev->save_flags = 0;
 -    netdev->changed_flags = 0;
 +    memset(netdev, 0, sizeof *netdev);
 +    netdev->netdev_dev = netdev_dev;
      list_push_back(&netdev_list, &netdev->node);
  }
  
-         netdev_get_dev(netdev)->class->close(netdev);
 +/* Undoes the results of initialization.
 + *
 + * Normally this function only needs to be called from netdev_close().
 + * However, it may be called by providers due to an error on opening
 + * that occurs after initialization.  It this case netdev_close() would
 + * never be called. */
 +void
 +netdev_uninit(struct netdev *netdev, bool close)
 +{
 +    /* Restore flags that we changed, if any. */
 +    int error = restore_flags(netdev);
 +    list_remove(&netdev->node);
 +    if (error) {
 +        VLOG_WARN("failed to restore network device flags on %s: %s",
 +                  netdev_get_name(netdev), strerror(error));
 +    }
 +
 +    if (close) {
++        netdev_get_dev(netdev)->netdev_class->close(netdev);
 +    }
 +}
 +
 +
  /* Returns the class type of 'netdev'.  
   *
   * The caller must not free the returned value. */
 -const char *netdev_get_type(const struct netdev *netdev)
 +const char *
 +netdev_get_type(const struct netdev *netdev)
  {
-     return netdev_get_dev(netdev)->class->type;
 -    return netdev->netdev_class->type;
++    return netdev_get_dev(netdev)->netdev_class->type;
 +}
 +
 +struct netdev_dev *
 +netdev_get_dev(const struct netdev *netdev)
 +{
 +    return netdev->netdev_dev;
  }
  
  /* Initializes 'notifier' as a netdev notifier for 'netdev', for which
@@@ -1107,7 -930,7 +1140,8 @@@ netdev_monitor_destroy(struct netdev_mo
  
          SHASH_FOR_EACH (node, &monitor->polled_netdevs) {
              struct netdev_notifier *notifier = node->data;
-             netdev_get_dev(notifier->netdev)->class->poll_remove(notifier);
 -            notifier->netdev->netdev_class->poll_remove(notifier);
++            netdev_get_dev(notifier->netdev)->netdev_class->poll_remove(
++                    notifier);
          }
  
          shash_destroy(&monitor->polled_netdevs);
@@@ -1137,12 -960,11 +1171,11 @@@ netdev_monitor_add(struct netdev_monito
      const char *netdev_name = netdev_get_name(netdev);
      int error = 0;
      if (!shash_find(&monitor->polled_netdevs, netdev_name)
-         && netdev_get_dev(netdev)->class->poll_add)
 -        && netdev->netdev_class->poll_add)
++            && netdev_get_dev(netdev)->netdev_class->poll_add)
      {
          struct netdev_notifier *notifier;
-         error = netdev_get_dev(netdev)->class->poll_add(netdev,
-                                                         netdev_monitor_cb,
-                                                         monitor, &notifier);
 -        error = netdev->netdev_class->poll_add(netdev, netdev_monitor_cb,
 -                                               monitor, &notifier);
++        error = netdev_get_dev(netdev)->netdev_class->poll_add(netdev,
++                    netdev_monitor_cb, monitor, &notifier);
          if (!error) {
              assert(notifier->netdev == netdev);
              shash_add(&monitor->polled_netdevs, netdev_name, notifier);
@@@ -1164,7 -986,7 +1197,7 @@@ netdev_monitor_remove(struct netdev_mon
      if (node) {
          /* Cancel future notifications. */
          struct netdev_notifier *notifier = node->data;
-         netdev_get_dev(netdev)->class->poll_remove(notifier);
 -        netdev->netdev_class->poll_remove(notifier);
++        netdev_get_dev(netdev)->netdev_class->poll_remove(notifier);
          shash_delete(&monitor->polled_netdevs, node);
  
          /* Drop any pending notification. */
@@@ -1222,20 -1044,21 +1255,20 @@@ restore_flags(struct netdev *netdev
      if (netdev->changed_flags) {
          enum netdev_flags restore = netdev->save_flags & netdev->changed_flags;
          enum netdev_flags old_flags;
-         return netdev_get_dev(netdev)->class->update_flags(netdev,
 -        return netdev->netdev_class->update_flags(netdev,
 -                                                  netdev->changed_flags
 -                                                  & ~restore,
 -                                                  restore, &old_flags);
++        return netdev_get_dev(netdev)->netdev_class->update_flags(netdev,
 +                                           netdev->changed_flags & ~restore,
 +                                           restore, &old_flags);
      }
      return 0;
  }
  
 -/* Retores all the flags on all network devices that we modified.  Called from
 - * a signal handler, so it does not attempt to report error conditions. */
 +/* Close all netdevs on shutdown so they can do any needed cleanup such as
 + * destroying devices, restoring flags, etc. */
  static void
 -restore_all_flags(void *aux UNUSED)
 +close_all_netdevs(void *aux UNUSED)
  {
 -    struct netdev *netdev;
 -    LIST_FOR_EACH (netdev, struct netdev, node, &netdev_list) {
 -        restore_flags(netdev);
 +    struct netdev *netdev, *next;
 +    LIST_FOR_EACH_SAFE(netdev, next, struct netdev, node, &netdev_list) {
 +        netdev_close(netdev);
      }
  }
diff --combined lib/netdev.h
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Copyright (c) 2008, 2009 Nicira Networks.
 + * Copyright (c) 2008, 2009, 2010 Nicira Networks.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
@@@ -76,28 -76,18 +76,28 @@@ struct netdev_stats 
      uint64_t tx_window_errors;
  };
  
 +struct netdev_options {
 +    const char *name;
 +    const char *type;
 +    const struct shash *args;
 +    int ethertype;
 +    bool may_create;
 +    bool may_open;
 +};
 +
  struct netdev;
 +struct netdev_class;
  
 -int netdev_initialize(void);
  void netdev_run(void);
  void netdev_wait(void);
  
 -int netdev_create(const char *name, const char *type, 
 -                  const struct shash *args);
 -int netdev_destroy(const char *name);
 -int netdev_reconfigure(const char *name, const struct shash *args);
 +int netdev_register_provider(const struct netdev_class *);
 +int netdev_unregister_provider(const char *type);
 +void netdev_enumerate_types(struct svec *types);
  
 -int netdev_open(const char *name, int ethertype, struct netdev **);
 +int netdev_open(struct netdev_options *, struct netdev **);
 +int netdev_open_default(const char *name, struct netdev **);
 +int netdev_reconfigure(struct netdev *, const struct shash *args);
  void netdev_close(struct netdev *);
  
  bool netdev_exists(const char *name);
  int netdev_enumerate(struct svec *);
  
  const char *netdev_get_name(const struct netdev *);
 +const char *netdev_get_type(const struct netdev *);
  int netdev_get_mtu(const struct netdev *, int *mtup);
  int netdev_get_ifindex(const struct netdev *);
  
@@@ -123,6 -112,8 +123,8 @@@ int netdev_get_carrier(const struct net
  int netdev_get_features(struct netdev *,
                          uint32_t *current, uint32_t *advertised,
                          uint32_t *supported, uint32_t *peer);
+ uint64_t netdev_features_to_bps(uint32_t features);
+ bool netdev_features_is_full_duplex(uint32_t features);
  int netdev_set_advertisements(struct netdev *, uint32_t advertise);
  
  int netdev_get_in4(const struct netdev *, struct in_addr *address,
diff --combined lib/stream-ssl.h
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Copyright (c) 2008 Nicira Networks.
 + * Copyright (c) 2008, 2009 Nicira Networks.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
 -#ifndef VCONN_SSL_H
 -#define VCONN_SSL_H 1
 +#ifndef STREAM_SSL_H
 +#define STREAM_SSL_H 1
  
  #include <stdbool.h>
  
  #ifdef HAVE_OPENSSL
 -bool vconn_ssl_is_configured(void);
 -void vconn_ssl_set_private_key_file(const char *file_name);
 -void vconn_ssl_set_certificate_file(const char *file_name);
 -void vconn_ssl_set_ca_cert_file(const char *file_name, bool bootstrap);
 -void vconn_ssl_set_peer_ca_cert_file(const char *file_name);
 +bool stream_ssl_is_configured(void);
 +void stream_ssl_set_private_key_file(const char *file_name);
 +void stream_ssl_set_certificate_file(const char *file_name);
 +void stream_ssl_set_ca_cert_file(const char *file_name, bool bootstrap);
 +void stream_ssl_set_peer_ca_cert_file(const char *file_name);
  
- #define STREAM_SSL_LONG_OPTIONS                     \
+ /* Define the long options for SSL support.
+  *
+  * Note that the definition includes a final comma, and therefore a comma 
+  * must not be supplied when using the definition.  This is done so that 
+  * compilation succeeds whether or not HAVE_OPENSSL is defined. */
 -#define VCONN_SSL_LONG_OPTIONS                      \
++#define STREAM_SSL_LONG_OPTIONS                      \
          {"private-key", required_argument, 0, 'p'}, \
          {"certificate", required_argument, 0, 'c'}, \
          {"ca-cert",     required_argument, 0, 'C'},
  
 -#define VCONN_SSL_OPTION_HANDLERS                       \
 +#define STREAM_SSL_OPTION_HANDLERS                      \
          case 'p':                                       \
 -            vconn_ssl_set_private_key_file(optarg);     \
 +            stream_ssl_set_private_key_file(optarg);    \
              break;                                      \
                                                          \
          case 'c':                                       \
 -            vconn_ssl_set_certificate_file(optarg);     \
 +            stream_ssl_set_certificate_file(optarg);    \
              break;                                      \
                                                          \
          case 'C':                                       \
 -            vconn_ssl_set_ca_cert_file(optarg, false);  \
 +            stream_ssl_set_ca_cert_file(optarg, false); \
              break;
  #else /* !HAVE_OPENSSL */
 -static inline bool vconn_ssl_is_configured(void) 
 +static inline bool stream_ssl_is_configured(void) 
  {
      return false;
  }
 -#define VCONN_SSL_LONG_OPTIONS
 -#define VCONN_SSL_OPTION_HANDLERS
 +#define STREAM_SSL_LONG_OPTIONS
 +#define STREAM_SSL_OPTION_HANDLERS
  #endif /* !HAVE_OPENSSL */
  
 -#endif /* vconn-ssl.h */
 +#endif /* stream-ssl.h */
diff --combined lib/vlog-modules.def
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Copyright (c) 2008, 2009 Nicira Networks.
 + * Copyright (c) 2008, 2009, 2010 Nicira Networks.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
@@@ -19,6 -19,8 +19,6 @@@ VLOG_MODULE(backtrace
  VLOG_MODULE(brcompatd)
  VLOG_MODULE(bridge)
  VLOG_MODULE(chain)
 -VLOG_MODULE(cfg)
 -VLOG_MODULE(cfg_mod)
  VLOG_MODULE(collectors)
  VLOG_MODULE(controller)
  VLOG_MODULE(coverage)
@@@ -32,16 -34,17 +32,16 @@@ VLOG_MODULE(dpif
  VLOG_MODULE(dpif_linux)
  VLOG_MODULE(dpif_netdev)
  VLOG_MODULE(dpctl)
 -VLOG_MODULE(executer)
  VLOG_MODULE(ezio_term)
  VLOG_MODULE(fail_open)
  VLOG_MODULE(fatal_signal)
 -VLOG_MODULE(fault)
  VLOG_MODULE(flow)
  VLOG_MODULE(in_band)
 +VLOG_MODULE(jsonrpc)
  VLOG_MODULE(leak_checker)
  VLOG_MODULE(learning_switch)
 +VLOG_MODULE(lockfile)
  VLOG_MODULE(mac_learning)
 -VLOG_MODULE(mgmt)
  VLOG_MODULE(netdev)
  VLOG_MODULE(netdev_linux)
  VLOG_MODULE(netflow)
@@@ -50,13 -53,6 +50,13 @@@ VLOG_MODULE(ofctl
  VLOG_MODULE(ovs_discover)
  VLOG_MODULE(ofproto)
  VLOG_MODULE(openflowd)
 +VLOG_MODULE(ovsdb_client)
 +VLOG_MODULE(ovsdb_file)
 +VLOG_MODULE(ovsdb_idl)
 +VLOG_MODULE(ovsdb_log)
 +VLOG_MODULE(ovsdb_jsonrpc_server)
 +VLOG_MODULE(ovsdb_server)
 +VLOG_MODULE(ovsdb_tool)
  VLOG_MODULE(pktbuf)
  VLOG_MODULE(pcap)
  VLOG_MODULE(poll_loop)
@@@ -64,14 -60,9 +64,15 @@@ VLOG_MODULE(port_watcher
  VLOG_MODULE(proc_net_compat)
  VLOG_MODULE(process)
  VLOG_MODULE(rconn)
 +VLOG_MODULE(reconnect)
  VLOG_MODULE(rtnetlink)
+ VLOG_MODULE(sflow)
  VLOG_MODULE(stp)
 +VLOG_MODULE(stream_fd)
 +VLOG_MODULE(stream_ssl)
 +VLOG_MODULE(stream_tcp)
 +VLOG_MODULE(stream_unix)
 +VLOG_MODULE(stream)
  VLOG_MODULE(stats)
  VLOG_MODULE(status)
  VLOG_MODULE(svec)
@@@ -87,7 -78,6 +88,7 @@@ VLOG_MODULE(vconn_ssl
  VLOG_MODULE(vconn_stream)
  VLOG_MODULE(vconn_unix)
  VLOG_MODULE(vconn)
 +VLOG_MODULE(vsctl)
  VLOG_MODULE(vlog)
  VLOG_MODULE(wcelim)
  VLOG_MODULE(vswitchd)
diff --combined ofproto/automake.mk
@@@ -11,6 -11,8 +11,6 @@@ ofproto_libofproto_a_SOURCES = 
        ofproto/collectors.h \
        ofproto/discovery.c \
        ofproto/discovery.h \
 -      ofproto/executer.c \
 -      ofproto/executer.h \
        ofproto/fail-open.c \
        ofproto/fail-open.h \
        ofproto/in-band.c \
        ofproto/netflow.h \
        ofproto/ofproto.c \
        ofproto/ofproto.h \
+       ofproto/ofproto-sflow.c \
+       ofproto/ofproto-sflow.h \
        ofproto/pktbuf.c \
        ofproto/pktbuf.h \
        ofproto/pinsched.c \
        ofproto/pinsched.h \
        ofproto/status.c \
        ofproto/status.h
 -
 -include ofproto/commands/automake.mk
diff --combined ofproto/ofproto-sflow.c
index 0000000,b37db42..1b659d1
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,607 +1,607 @@@
 -        if (!netdev_open(agent_device, NETDEV_ETH_TYPE_NONE, &netdev)) {
+ /*
+  * Copyright (c) 2009, 2010 InMon Corp.
+  * Copyright (c) 2009 Nicira Networks.
+  *
+  * Licensed under the Apache License, Version 2.0 (the "License");
+  * you may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *     http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing, software
+  * distributed under the License is distributed on an "AS IS" BASIS,
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  */
+ #include <config.h>
+ #include "ofproto-sflow.h"
+ #include <inttypes.h>
+ #include <stdlib.h>
+ #include "collectors.h"
+ #include "dpif.h"
+ #include "compiler.h"
+ #include "netdev.h"
+ #include "ofpbuf.h"
+ #include "ofproto.h"
+ #include "poll-loop.h"
+ #include "port-array.h"
+ #include "sflow_api.h"
+ #include "socket-util.h"
+ #include "timeval.h"
+ #define THIS_MODULE VLM_sflow
+ #include "vlog.h"
+ struct ofproto_sflow_port {
+     struct netdev *netdev;      /* Underlying network device, for stats. */
+     SFLDataSource_instance dsi; /* sFlow library's notion of port number. */
+ };
+ struct ofproto_sflow {
+     struct ofproto *ofproto;
+     struct collectors *collectors;
+     SFLAgent *sflow_agent;
+     struct ofproto_sflow_options *options;
+     struct dpif *dpif;
+     time_t next_tick;
+     size_t n_flood, n_all;
+     struct port_array ports;    /* Indexed by ODP port number. */
+ };
+ #define RECEIVER_INDEX 1
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+ static bool
+ nullable_string_is_equal(const char *a, const char *b)
+ {
+     return a ? b && !strcmp(a, b) : !b;
+ }
+ static bool
+ ofproto_sflow_options_equal(const struct ofproto_sflow_options *a,
+                             const struct ofproto_sflow_options *b)
+ {
+     return (svec_equal(&a->targets, &b->targets)
+             && a->sampling_rate == b->sampling_rate
+             && a->polling_interval == b->polling_interval
+             && a->header_len == b->header_len
+             && a->sub_id == b->sub_id
+             && nullable_string_is_equal(a->agent_device, b->agent_device)
+             && nullable_string_is_equal(a->control_ip, b->control_ip));
+ }
+ static struct ofproto_sflow_options *
+ ofproto_sflow_options_clone(const struct ofproto_sflow_options *old)
+ {
+     struct ofproto_sflow_options *new = xmemdup(old, sizeof *old);
+     svec_clone(&new->targets, &old->targets);
+     new->agent_device = old->agent_device ? xstrdup(old->agent_device) : NULL;
+     new->control_ip = old->control_ip ? xstrdup(old->control_ip) : NULL;
+     return new;
+ }
+ static void
+ ofproto_sflow_options_destroy(struct ofproto_sflow_options *options)
+ {
+     if (options) {
+         svec_destroy(&options->targets);
+         free(options->agent_device);
+         free(options->control_ip);
+         free(options);
+     }
+ }
+ /* sFlow library callback to allocate memory. */
+ static void *
+ sflow_agent_alloc_cb(void *magic UNUSED, SFLAgent *agent UNUSED, size_t bytes)
+ {
+     return calloc(1, bytes);
+ }
+ /* sFlow library callback to free memory. */
+ static int
+ sflow_agent_free_cb(void *magic UNUSED, SFLAgent *agent UNUSED, void *obj)
+ {
+     free(obj);
+     return 0;
+ }
+ /* sFlow library callback to report error. */
+ static void
+ sflow_agent_error_cb(void *magic UNUSED, SFLAgent *agent UNUSED, char *msg)
+ {
+     VLOG_WARN("sFlow agent error: %s", msg);
+ }
+ /* sFlow library callback to send datagram. */
+ static void
+ sflow_agent_send_packet_cb(void *os_, SFLAgent *agent UNUSED,
+                            SFLReceiver *receiver UNUSED, u_char *pkt,
+                            uint32_t pktLen)
+ {
+     struct ofproto_sflow *os = os_;
+     collectors_send(os->collectors, pkt, pktLen);
+ }
+ static void
+ sflow_agent_get_counters(void *os_, SFLPoller *poller,
+                          SFL_COUNTERS_SAMPLE_TYPE *cs)
+ {
+     struct ofproto_sflow *os = os_;
+     SFLCounters_sample_element elem;
+     struct ofproto_sflow_port *osp;
+     SFLIf_counters *counters;
+     struct netdev_stats stats;
+     enum netdev_flags flags;
+     uint32_t current;
+     osp = port_array_get(&os->ports, poller->bridgePort);
+     if (!osp) {
+         return;
+     }
+     elem.tag = SFLCOUNTERS_GENERIC;
+     counters = &elem.counterBlock.generic;
+     counters->ifIndex = SFL_DS_INDEX(poller->dsi);
+     counters->ifType = 6;
+     if (!netdev_get_features(osp->netdev, &current, NULL, NULL, NULL)) {
+       /* The values of ifDirection come from MAU MIB (RFC 2668): 0 = unknown,
+          1 = full-duplex, 2 = half-duplex, 3 = in, 4=out */
+         counters->ifSpeed = netdev_features_to_bps(current);
+         counters->ifDirection = (netdev_features_is_full_duplex(current)
+                                  ? 1 : 2);
+     } else {
+         counters->ifSpeed = 100000000;
+         counters->ifDirection = 0;
+     }
+     if (!netdev_get_flags(osp->netdev, &flags) && flags & NETDEV_UP) {
+         bool carrier;
+         counters->ifStatus = 1; /* ifAdminStatus up. */
+         if (!netdev_get_carrier(osp->netdev, &carrier) && carrier) {
+             counters->ifStatus |= 2; /* ifOperStatus us. */
+         }
+     } else {
+         counters->ifStatus = 0;  /* Down. */
+     }
+     /* XXX
+        1. Is the multicast counter filled in?
+        2. Does the multicast counter include broadcasts?
+        3. Does the rx_packets counter include multicasts/broadcasts?
+     */
+     netdev_get_stats(osp->netdev, &stats);
+     counters->ifInOctets = stats.rx_bytes;
+     counters->ifInUcastPkts = stats.rx_packets;
+     counters->ifInMulticastPkts = stats.multicast;
+     counters->ifInBroadcastPkts = -1;
+     counters->ifInDiscards = stats.rx_dropped;
+     counters->ifInErrors = stats.rx_errors;
+     counters->ifInUnknownProtos = -1;
+     counters->ifOutOctets = stats.tx_bytes;
+     counters->ifOutUcastPkts = stats.tx_packets;
+     counters->ifOutMulticastPkts = -1;
+     counters->ifOutBroadcastPkts = -1;
+     counters->ifOutDiscards = stats.tx_dropped;
+     counters->ifOutErrors = stats.tx_errors;
+     counters->ifPromiscuousMode = 0;
+     SFLADD_ELEMENT(cs, &elem);
+     sfl_poller_writeCountersSample(poller, cs);
+ }
+ /* Obtains an address to use for the local sFlow agent and stores it into
+  * '*agent_addr'.  Returns true if successful, false on failure.
+  *
+  * The sFlow agent address should be a local IP address that is persistent and
+  * reachable over the network, if possible.  The IP address associated with
+  * 'agent_device' is used if it has one, and otherwise 'control_ip', the IP
+  * address used to talk to the controller. */
+ static bool
+ sflow_choose_agent_address(const char *agent_device, const char *control_ip,
+                            SFLAddress *agent_addr)
+ {
+     struct in_addr in4;
+     memset(agent_addr, 0, sizeof *agent_addr);
+     agent_addr->type = SFLADDRESSTYPE_IP_V4;
+     if (agent_device) {
+         struct netdev *netdev;
 -    error = netdev_open(netdev_name, NETDEV_ETH_TYPE_NONE, &netdev);
++        if (!netdev_open_default(agent_device, &netdev)) {
+             int error = netdev_get_in4(netdev, &in4, NULL);
+             netdev_close(netdev);
+             if (!error) {
+                 goto success;
+             }
+         }
+     }
+     if (control_ip && !lookup_ip(control_ip, &in4)) {
+         goto success;
+     }
+     VLOG_ERR("could not determine IP address for sFlow agent");
+     return false;
+ success:
+     agent_addr->address.ip_v4.addr = in4.s_addr;
+     return true;
+ }
+ void
+ ofproto_sflow_clear(struct ofproto_sflow *os)
+ {
+     struct ofproto_sflow_port *osp;
+     unsigned int odp_port;
+     if (os->sflow_agent) {
+         sfl_agent_release(os->sflow_agent);
+         os->sflow_agent = NULL;
+     }
+     collectors_destroy(os->collectors);
+     os->collectors = NULL;
+     ofproto_sflow_options_destroy(os->options);
+     os->options = NULL;
+     PORT_ARRAY_FOR_EACH (osp, &os->ports, odp_port) {
+         ofproto_sflow_del_port(os, odp_port);
+     }
+     port_array_clear(&os->ports);
+     /* Turn off sampling to save CPU cycles. */
+     dpif_set_sflow_probability(os->dpif, 0);
+ }
+ bool
+ ofproto_sflow_is_enabled(const struct ofproto_sflow *os)
+ {
+     return os->collectors != NULL;
+ }
+ struct ofproto_sflow *
+ ofproto_sflow_create(struct dpif *dpif)
+ {
+     struct ofproto_sflow *os;
+     os = xcalloc(1, sizeof *os);
+     os->dpif = dpif;
+     os->next_tick = time_now() + 1;
+     port_array_init(&os->ports);
+     return os;
+ }
+ void
+ ofproto_sflow_destroy(struct ofproto_sflow *os)
+ {
+     if (os) {
+         ofproto_sflow_clear(os);
+         port_array_destroy(&os->ports);
+         free(os);
+     }
+ }
+ static void
+ ofproto_sflow_add_poller(struct ofproto_sflow *os,
+                          struct ofproto_sflow_port *osp, uint16_t odp_port)
+ {
+     SFLPoller *poller = sfl_agent_addPoller(os->sflow_agent, &osp->dsi, os,
+                                             sflow_agent_get_counters);
+     sfl_poller_set_sFlowCpInterval(poller, os->options->polling_interval);
+     sfl_poller_set_sFlowCpReceiver(poller, RECEIVER_INDEX);
+     sfl_poller_set_bridgePort(poller, odp_port);
+ }
+ static void
+ ofproto_sflow_add_sampler(struct ofproto_sflow *os,
+                         struct ofproto_sflow_port *osp,
+                         u_int32_t sampling_rate, u_int32_t header_len)
+ {
+     SFLSampler *sampler = sfl_agent_addSampler(os->sflow_agent, &osp->dsi);
+     sfl_sampler_set_sFlowFsPacketSamplingRate(sampler, sampling_rate);
+     sfl_sampler_set_sFlowFsMaximumHeaderSize(sampler, header_len);
+     sfl_sampler_set_sFlowFsReceiver(sampler, RECEIVER_INDEX);
+ }
+ void
+ ofproto_sflow_add_port(struct ofproto_sflow *os, uint16_t odp_port,
+                        const char *netdev_name)
+ {
+     struct ofproto_sflow_port *osp;
+     struct netdev *netdev;
+     uint32_t ifindex;
+     int error;
+     ofproto_sflow_del_port(os, odp_port);
+     /* Open network device. */
++    error = netdev_open_default(netdev_name, &netdev);
+     if (error) {
+         VLOG_WARN_RL(&rl, "failed to open network device \"%s\": %s",
+                      netdev_name, strerror(error));
+         return;
+     }
+     /* Add to table of ports. */
+     osp = xmalloc(sizeof *osp);
+     osp->netdev = netdev;
+     ifindex = netdev_get_ifindex(netdev);
+     if (ifindex <= 0) {
+         ifindex = (os->sflow_agent->subId << 16) + odp_port;
+     }
+     SFL_DS_SET(osp->dsi, 0, ifindex, 0);
+     port_array_set(&os->ports, odp_port, osp);
+     /* Add poller. */
+     if (os->sflow_agent) {
+         ofproto_sflow_add_poller(os, osp, odp_port);
+     }
+ }
+ void
+ ofproto_sflow_del_port(struct ofproto_sflow *os, uint16_t odp_port)
+ {
+     struct ofproto_sflow_port *osp = port_array_get(&os->ports, odp_port);
+     if (osp) {
+         if (os->sflow_agent) {
+             sfl_agent_removePoller(os->sflow_agent, &osp->dsi);
+             sfl_agent_removeSampler(os->sflow_agent, &osp->dsi);
+         }
+         netdev_close(osp->netdev);
+         free(osp);
+         port_array_set(&os->ports, odp_port, NULL);
+     }
+ }
+ void
+ ofproto_sflow_set_options(struct ofproto_sflow *os,
+                           const struct ofproto_sflow_options *options)
+ {
+     struct ofproto_sflow_port *osp;
+     bool options_changed;
+     SFLReceiver *receiver;
+     unsigned int odp_port;
+     SFLAddress agentIP;
+     time_t now;
+     int error;
+     if (!options->targets.n || !options->sampling_rate) {
+         /* No point in doing any work if there are no targets or nothing to
+          * sample. */
+         ofproto_sflow_clear(os);
+         return;
+     }
+     options_changed = (!os->options
+                        || !ofproto_sflow_options_equal(options, os->options));
+     /* Configure collectors if options have changed or if we're shortchanged in
+      * collectors (which indicates that opening one or more of the configured
+      * collectors failed, so that we should retry). */
+     if (options_changed
+         || collectors_count(os->collectors) < options->targets.n) {
+         collectors_destroy(os->collectors);
+         error = collectors_create(&options->targets,
+                                   SFL_DEFAULT_COLLECTOR_PORT, &os->collectors);
+         if (os->collectors == NULL) {
+             VLOG_WARN_RL(&rl, "no collectors could be initialized, "
+                          "sFlow disabled");
+             ofproto_sflow_clear(os);
+             return;
+         }
+     }
+     /* Avoid reconfiguring if options didn't change. */
+     if (!options_changed) {
+         return;
+     }
+     ofproto_sflow_options_destroy(os->options);
+     os->options = ofproto_sflow_options_clone(options);
+     /* Choose agent IP address. */
+     if (!sflow_choose_agent_address(options->agent_device,
+                                     options->control_ip, &agentIP)) {
+         ofproto_sflow_clear(os);
+         return;
+     }
+     /* Create agent. */
+     VLOG_INFO("creating sFlow agent %d", options->sub_id);
+     if (os->sflow_agent) {
+         sfl_agent_release(os->sflow_agent);
+     }
+     os->sflow_agent = xcalloc(1, sizeof *os->sflow_agent);
+     now = time_now();
+     sfl_agent_init(os->sflow_agent,
+                    &agentIP,
+                    options->sub_id,
+                    now,         /* Boot time. */
+                    now,         /* Current time. */
+                    os,          /* Pointer supplied to callbacks. */
+                    sflow_agent_alloc_cb,
+                    sflow_agent_free_cb,
+                    sflow_agent_error_cb,
+                    sflow_agent_send_packet_cb);
+     receiver = sfl_agent_addReceiver(os->sflow_agent);
+     sfl_receiver_set_sFlowRcvrOwner(receiver, "Open vSwitch sFlow");
+     sfl_receiver_set_sFlowRcvrTimeout(receiver, 0xffffffff);
+     /* Set the sampling_rate down in the datapath. */
+     dpif_set_sflow_probability(os->dpif,
+                                MAX(1, UINT32_MAX / options->sampling_rate));
+     /* Add samplers and pollers for the currently known ports. */
+     PORT_ARRAY_FOR_EACH (osp, &os->ports, odp_port) {
+         ofproto_sflow_add_sampler(os, osp,
+                                   options->sampling_rate, options->header_len);
+     }
+ }
+ static int
+ ofproto_sflow_odp_port_to_ifindex(const struct ofproto_sflow *os,
+                                   uint16_t odp_port)
+ {
+     struct ofproto_sflow_port *osp = port_array_get(&os->ports, odp_port);
+     return osp ? SFL_DS_INDEX(osp->dsi) : 0;
+ }
+ void
+ ofproto_sflow_received(struct ofproto_sflow *os, struct odp_msg *msg)
+ {
+     SFL_FLOW_SAMPLE_TYPE fs;
+     SFLFlow_sample_element hdrElem;
+     SFLSampled_header *header;
+     SFLFlow_sample_element switchElem;
+     SFLSampler *sampler;
+     const struct odp_sflow_sample_header *hdr;
+     const union odp_action *actions;
+     struct ofpbuf payload;
+     size_t n_actions, n_outputs;
+     size_t min_size;
+     flow_t flow;
+     size_t i;
+     /* Get odp_sflow_sample_header. */
+     min_size = sizeof *msg + sizeof *hdr;
+     if (min_size > msg->length) {
+         VLOG_WARN_RL(&rl, "sFlow packet too small (%"PRIu32" < %zu)",
+                      msg->length, min_size);
+         return;
+     }
+     hdr = (const struct odp_sflow_sample_header *) (msg + 1);
+     /* Get actions. */
+     n_actions = hdr->n_actions;
+     if (n_actions > 65536 / sizeof *actions) {
+         VLOG_WARN_RL(&rl, "too many actions in sFlow packet (%zu > %zu)",
+                      65536 / sizeof *actions, n_actions);
+         return;
+     }
+     min_size += n_actions * sizeof *actions;
+     if (min_size > msg->length) {
+         VLOG_WARN_RL(&rl, "sFlow packet with %zu actions too small "
+                      "(%"PRIu32" < %zu)",
+                      n_actions, msg->length, min_size);
+         return;
+     }
+     actions = (const union odp_action *) (hdr + 1);
+     /* Get packet payload and extract flow. */
+     payload.data = (union odp_action *) (actions + n_actions);
+     payload.size = msg->length - min_size;
+     flow_extract(&payload, msg->port, &flow);
+     /* Build a flow sample */
+     memset(&fs, 0, sizeof fs);
+     fs.input = ofproto_sflow_odp_port_to_ifindex(os, msg->port);
+     fs.output = 0;              /* Filled in correctly below. */
+     fs.sample_pool = hdr->sample_pool;
+     /* We are going to give it to the sampler that represents this input port.
+      * By implementing "ingress-only" sampling like this we ensure that we
+      * never have to offer the same sample to more than one sampler. */
+     sampler = sfl_agent_getSamplerByIfIndex(os->sflow_agent, fs.input);
+     if (!sampler) {
+         VLOG_WARN_RL(&rl, "no sampler for input ifIndex (%"PRIu32")",
+                      fs.input);
+         return;
+     }
+     /* Sampled header. */
+     memset(&hdrElem, 0, sizeof hdrElem);
+     hdrElem.tag = SFLFLOW_HEADER;
+     header = &hdrElem.flowType.header;
+     header->header_protocol = SFLHEADER_ETHERNET_ISO8023;
+     header->frame_length = payload.size;
+     header->stripped = 4; /* Ethernet FCS stripped off. */
+     header->header_length = MIN(payload.size,
+                                 sampler->sFlowFsMaximumHeaderSize);
+     header->header_bytes = payload.data;
+     /* Add extended switch element. */
+     memset(&switchElem, 0, sizeof(switchElem));
+     switchElem.tag = SFLFLOW_EX_SWITCH;
+     switchElem.flowType.sw.src_vlan = ntohs(flow.dl_vlan);
+     switchElem.flowType.sw.src_priority = -1; /* XXX */
+     switchElem.flowType.sw.dst_vlan = -1;     /* Filled in correctly below. */
+     switchElem.flowType.sw.dst_priority = switchElem.flowType.sw.src_priority;
+     /* Figure out the output ports. */
+     n_outputs = 0;
+     for (i = 0; i < n_actions; i++) {
+         const union odp_action *a = &actions[i];
+         switch (a->type) {
+         case ODPAT_OUTPUT:
+             fs.output = ofproto_sflow_odp_port_to_ifindex(os, a->output.port);
+             n_outputs++;
+             break;
+         case ODPAT_OUTPUT_GROUP:
+             n_outputs += (a->output_group.group == DP_GROUP_FLOOD ? os->n_flood
+                           : a->output_group.group == DP_GROUP_ALL ? os->n_all
+                           : 0);
+             break;
+         case ODPAT_SET_VLAN_VID:
+             switchElem.flowType.sw.dst_vlan = ntohs(a->vlan_vid.vlan_vid);
+             break;
+         case ODPAT_SET_VLAN_PCP:
+             switchElem.flowType.sw.dst_priority = a->vlan_pcp.vlan_pcp;
+             break;
+         default:
+             break;
+         }
+     }
+     /* Set output port, as defined by http://www.sflow.org/sflow_version_5.txt
+        (search for "Input/output port information"). */
+     if (!n_outputs) {
+         /* This value indicates that the packet was dropped for an unknown
+          * reason. */
+         fs.output = 0x40000000 | 256;
+     } else if (n_outputs > 1 || !fs.output) {
+         /* Setting the high bit means "multiple output ports". */
+         fs.output = 0x80000000 | n_outputs;
+     }
+     /* Submit the flow sample to be encoded into the next datagram. */
+     SFLADD_ELEMENT(&fs, &hdrElem);
+     SFLADD_ELEMENT(&fs, &switchElem);
+     sfl_sampler_writeFlowSample(sampler, &fs);
+ }
+ void
+ ofproto_sflow_set_group_sizes(struct ofproto_sflow *os,
+                               size_t n_flood, size_t n_all)
+ {
+     os->n_flood = n_flood;
+     os->n_all = n_all;
+ }
+ void
+ ofproto_sflow_run(struct ofproto_sflow *os)
+ {
+     if (ofproto_sflow_is_enabled(os)) {
+         time_t now = time_now();
+         if (now >= os->next_tick) {
+             sfl_agent_tick(os->sflow_agent, now);
+             os->next_tick = now + 1;
+         }
+     }
+ }
+ void
+ ofproto_sflow_wait(struct ofproto_sflow *os)
+ {
+     if (ofproto_sflow_is_enabled(os)) {
+         poll_timer_wait(os->next_tick * 1000 - time_msec());
+     }
+ }
diff --combined ofproto/ofproto.c
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Copyright (c) 2009 Nicira Networks.
 + * Copyright (c) 2009, 2010 Nicira Networks.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
@@@ -27,6 -27,7 +27,6 @@@
  #include "discovery.h"
  #include "dpif.h"
  #include "dynamic-string.h"
 -#include "executer.h"
  #include "fail-open.h"
  #include "in-band.h"
  #include "mac-learning.h"
  #include "netflow.h"
  #include "odp-util.h"
  #include "ofp-print.h"
+ #include "ofproto-sflow.h"
  #include "ofpbuf.h"
  #include "openflow/nicira-ext.h"
  #include "openflow/openflow.h"
 -#include "openflow/openflow-mgmt.h"
  #include "openvswitch/datapath-protocol.h"
  #include "packets.h"
  #include "pinsched.h"
  #include "shash.h"
  #include "status.h"
  #include "stp.h"
 +#include "stream-ssl.h"
  #include "svec.h"
  #include "tag.h"
  #include "timeval.h"
  #include "unixctl.h"
  #include "vconn.h"
 -#include "vconn-ssl.h"
  #include "xtoxll.h"
  
  #define THIS_MODULE VLM_ofproto
  #include "vlog.h"
  
- enum {
-     DP_GROUP_FLOOD = 0,
-     DP_GROUP_ALL = 1
- };
+ #include "sflow_api.h"
  
  enum {
      TABLEID_HASH = 0,
@@@ -174,7 -174,7 +172,7 @@@ struct ofconn 
  };
  
  static struct ofconn *ofconn_create(struct ofproto *, struct rconn *);
 -static void ofconn_destroy(struct ofconn *, struct ofproto *);
 +static void ofconn_destroy(struct ofconn *);
  static void ofconn_run(struct ofconn *, struct ofproto *);
  static void ofconn_wait(struct ofconn *);
  static void queue_tx(struct ofpbuf *msg, const struct ofconn *ofconn,
@@@ -184,6 -184,7 +182,6 @@@ struct ofproto 
      /* Settings. */
      uint64_t datapath_id;       /* Datapath ID. */
      uint64_t fallback_dpid;     /* Datapath ID if no better choice found. */
 -    uint64_t mgmt_id;           /* Management channel identifier. */
      char *manufacturer;         /* Manufacturer. */
      char *hardware;             /* Hardware. */
      char *software;             /* Software version. */
      struct discovery *discovery;
      struct fail_open *fail_open;
      struct pinsched *miss_sched, *action_sched;
 -    struct executer *executer;
      struct netflow *netflow;
+     struct ofproto_sflow *sflow;
  
      /* Flow table. */
      struct classifier cls;
@@@ -249,14 -252,14 +248,15 @@@ static void handle_odp_msg(struct ofpro
  static void handle_openflow(struct ofconn *, struct ofproto *,
                              struct ofpbuf *);
  
- static void refresh_port_group(struct ofproto *, unsigned int group);
+ static void refresh_port_groups(struct ofproto *);
  static void update_port(struct ofproto *, const char *devname);
  static int init_ports(struct ofproto *);
  static void reinit_ports(struct ofproto *);
  
  int
 -ofproto_create(const char *datapath, const struct ofhooks *ofhooks, void *aux,
 +ofproto_create(const char *datapath, const char *datapath_type,
 +               const struct ofhooks *ofhooks, void *aux,
                 struct ofproto **ofprotop)
  {
      struct odp_stats stats;
      *ofprotop = NULL;
  
      /* Connect to datapath and start listening for messages. */
 -    error = dpif_open(datapath, &dpif);
 +    error = dpif_open(datapath, datapath_type, &dpif);
      if (error) {
          VLOG_ERR("failed to open datapath %s: %s", datapath, strerror(error));
          return error;
          dpif_close(dpif);
          return error;
      }
-     error = dpif_recv_set_mask(dpif, ODPL_MISS | ODPL_ACTION);
+     error = dpif_recv_set_mask(dpif, ODPL_MISS | ODPL_ACTION | ODPL_SFLOW);
      if (error) {
          VLOG_ERR("failed to listen on datapath %s: %s",
                   datapath, strerror(error));
      dpif_recv_purge(dpif);
  
      /* Initialize settings. */
 -    p = xcalloc(1, sizeof *p);
 +    p = xzalloc(sizeof *p);
      p->fallback_dpid = pick_fallback_dpid();
      p->datapath_id = p->fallback_dpid;
      p->manufacturer = xstrdup("Nicira Networks, Inc.");
      p->discovery = NULL;
      p->fail_open = NULL;
      p->miss_sched = p->action_sched = NULL;
 -    p->executer = NULL;
      p->netflow = NULL;
+     p->sflow = NULL;
  
      /* Initialize flow table. */
      classifier_init(&p->cls);
      p->ss_cat = switch_status_register(p->switch_status, "remote",
                                         rconn_status_cb, p->controller->rconn);
  
 -    /* Almost done... */
 -    error = init_ports(p);
 -    if (error) {
 -        ofproto_destroy(p);
 -        return error;
 -    }
 -
      /* Pick final datapath ID. */
      p->datapath_id = pick_datapath_id(p);
      VLOG_INFO("using datapath ID %012"PRIx64, p->datapath_id);
@@@ -363,6 -375,12 +364,6 @@@ ofproto_set_datapath_id(struct ofproto 
      }
  }
  
 -void
 -ofproto_set_mgmt_id(struct ofproto *p, uint64_t mgmt_id)
 -{
 -    p->mgmt_id = mgmt_id;
 -}
 -
  void
  ofproto_set_probe_interval(struct ofproto *p, int probe_interval)
  {
@@@ -519,7 -537,7 +520,7 @@@ in
  ofproto_set_netflow(struct ofproto *ofproto,
                      const struct netflow_options *nf_options)
  {
 -    if (nf_options->collectors.n) {
 +    if (nf_options && nf_options->collectors.n) {
          if (!ofproto->netflow) {
              ofproto->netflow = netflow_create();
          }
      }
  }
  
+ void
+ ofproto_set_sflow(struct ofproto *ofproto,
+                   const struct ofproto_sflow_options *oso)
+ {
+     struct ofproto_sflow *os = ofproto->sflow;
+     if (oso) {
+         if (!os) {
+             struct ofport *ofport;
+             unsigned int odp_port;
+             os = ofproto->sflow = ofproto_sflow_create(ofproto->dpif);
+             refresh_port_groups(ofproto);
+             PORT_ARRAY_FOR_EACH (ofport, &ofproto->ports, odp_port) {
+                 ofproto_sflow_add_port(os, odp_port,
+                                        netdev_get_name(ofport->netdev));
+             }
+         }
+         ofproto_sflow_set_options(os, oso);
+     } else {
+         ofproto_sflow_destroy(os);
+         ofproto->sflow = NULL;
+     }
+ }
  void
  ofproto_set_failure(struct ofproto *ofproto, bool fail_open)
  {
@@@ -586,12 -628,36 +611,12 @@@ ofproto_set_stp(struct ofproto *ofprot
      }
  }
  
 -int
 -ofproto_set_remote_execution(struct ofproto *ofproto, const char *command_acl,
 -                             const char *command_dir)
 -{
 -    if (command_acl) {
 -        if (!ofproto->executer) {
 -            return executer_create(command_acl, command_dir,
 -                                   &ofproto->executer);
 -        } else {
 -            executer_set_acl(ofproto->executer, command_acl, command_dir);
 -        }
 -    } else {
 -        executer_destroy(ofproto->executer);
 -        ofproto->executer = NULL;
 -    }
 -    return 0;
 -}
 -
  uint64_t
  ofproto_get_datapath_id(const struct ofproto *ofproto)
  {
      return ofproto->datapath_id;
  }
  
 -uint64_t
 -ofproto_get_mgmt_id(const struct ofproto *ofproto)
 -{
 -    return ofproto->mgmt_id;
 -}
 -
  int
  ofproto_get_probe_interval(const struct ofproto *ofproto)
  {
@@@ -659,7 -725,7 +684,7 @@@ ofproto_destroy(struct ofproto *p
  
      LIST_FOR_EACH_SAFE (ofconn, next_ofconn, struct ofconn, node,
                          &p->all_conns) {
 -        ofconn_destroy(ofconn, p);
 +        ofconn_destroy(ofconn);
      }
  
      dpif_close(p->dpif);
      fail_open_destroy(p->fail_open);
      pinsched_destroy(p->miss_sched);
      pinsched_destroy(p->action_sched);
 -    executer_destroy(p->executer);
      netflow_destroy(p->netflow);
+     ofproto_sflow_destroy(p->sflow);
  
      switch_status_unregister(p->ss_cat);
  
@@@ -723,10 -791,6 +749,10 @@@ ofproto_run1(struct ofproto *p
      int error;
      int i;
  
 +    if (shash_is_empty(&p->port_by_name)) {
 +        init_ports(p);
 +    }
 +
      for (i = 0; i < 50; i++) {
          struct ofpbuf *buf;
          int error;
      }
      pinsched_run(p->miss_sched, send_packet_in_miss, p);
      pinsched_run(p->action_sched, send_packet_in_action, p);
 -    if (p->executer) {
 -        executer_run(p->executer);
 -    }
  
      LIST_FOR_EACH_SAFE (ofconn, next_ofconn, struct ofconn, node,
                          &p->all_conns) {
      if (p->netflow) {
          netflow_run(p->netflow);
      }
+     if (p->sflow) {
+         ofproto_sflow_run(p->sflow);
+     }
  
      return 0;
  }
@@@ -882,6 -952,12 +911,9 @@@ ofproto_wait(struct ofproto *p
      }
      pinsched_wait(p->miss_sched);
      pinsched_wait(p->action_sched);
 -    if (p->executer) {
 -        executer_wait(p->executer);
 -    }
+     if (p->sflow) {
+         ofproto_sflow_wait(p->sflow);
+     }
      if (!tag_set_is_empty(&p->revalidate_set)) {
          poll_immediate_wake();
      }
@@@ -1022,7 -1098,7 +1054,7 @@@ reinit_ports(struct ofproto *p
      svec_destroy(&devnames);
  }
  
- static void
+ static size_t
  refresh_port_group(struct ofproto *p, unsigned int group)
  {
      uint16_t *ports;
      }
      dpif_port_group_set(p->dpif, group, ports, n_ports);
      free(ports);
+     return n_ports;
  }
  
  static void
  refresh_port_groups(struct ofproto *p)
  {
-     refresh_port_group(p, DP_GROUP_FLOOD);
-     refresh_port_group(p, DP_GROUP_ALL);
+     size_t n_flood = refresh_port_group(p, DP_GROUP_FLOOD);
+     size_t n_all = refresh_port_group(p, DP_GROUP_ALL);
+     if (p->sflow) {
+         ofproto_sflow_set_group_sizes(p->sflow, n_flood, n_all);
+     }
  }
  
  static struct ofport *
  make_ofport(const struct odp_port *odp_port)
  {
 +    struct netdev_options netdev_options;
      enum netdev_flags flags;
      struct ofport *ofport;
      struct netdev *netdev;
      bool carrier;
      int error;
  
 -    error = netdev_open(odp_port->devname, NETDEV_ETH_TYPE_NONE, &netdev);
 +    memset(&netdev_options, 0, sizeof netdev_options);
 +    netdev_options.name = odp_port->devname;
 +    netdev_options.ethertype = NETDEV_ETH_TYPE_NONE;
 +    netdev_options.may_open = true;
 +
 +    error = netdev_open(&netdev_options, &netdev);
      if (error) {
          VLOG_WARN_RL(&rl, "ignoring port %s (%"PRIu16") because netdev %s "
                       "cannot be opened (%s)",
@@@ -1152,19 -1227,29 +1189,29 @@@ send_port_status(struct ofproto *p, con
  static void
  ofport_install(struct ofproto *p, struct ofport *ofport)
  {
+     uint16_t odp_port = ofp_port_to_odp_port(ofport->opp.port_no);
+     const char *netdev_name = (const char *) ofport->opp.name;
      netdev_monitor_add(p->netdev_monitor, ofport->netdev);
-     port_array_set(&p->ports, ofp_port_to_odp_port(ofport->opp.port_no),
-                    ofport);
-     shash_add(&p->port_by_name, (char *) ofport->opp.name, ofport);
+     port_array_set(&p->ports, odp_port, ofport);
+     shash_add(&p->port_by_name, netdev_name, ofport);
+     if (p->sflow) {
+         ofproto_sflow_add_port(p->sflow, odp_port, netdev_name);
+     }
  }
  
  static void
  ofport_remove(struct ofproto *p, struct ofport *ofport)
  {
+     uint16_t odp_port = ofp_port_to_odp_port(ofport->opp.port_no);
      netdev_monitor_remove(p->netdev_monitor, ofport->netdev);
-     port_array_set(&p->ports, ofp_port_to_odp_port(ofport->opp.port_no), NULL);
+     port_array_set(&p->ports, odp_port, NULL);
      shash_delete(&p->port_by_name,
                   shash_find(&p->port_by_name, (char *) ofport->opp.name));
+     if (p->sflow) {
+         ofproto_sflow_del_port(p->sflow, odp_port);
+     }
  }
  
  static void
@@@ -1290,8 -1375,12 +1337,8 @@@ ofconn_create(struct ofproto *p, struc
  }
  
  static void
 -ofconn_destroy(struct ofconn *ofconn, struct ofproto *p)
 +ofconn_destroy(struct ofconn *ofconn)
  {
 -    if (p->executer) {
 -        executer_rconn_closing(p->executer, ofconn->rconn);
 -    }
 -
      list_remove(&ofconn->node);
      rconn_destroy(ofconn->rconn);
      rconn_packet_counter_destroy(ofconn->packet_in_counter);
@@@ -1324,7 -1413,7 +1371,7 @@@ ofconn_run(struct ofconn *ofconn, struc
      }
  
      if (ofconn != p->controller && !rconn_is_alive(ofconn->rconn)) {
 -        ofconn_destroy(ofconn, p);
 +        ofconn_destroy(ofconn);
      }
  }
  
@@@ -1346,7 -1435,7 +1393,7 @@@ rule_create(struct ofproto *ofproto, st
              const union ofp_action *actions, size_t n_actions,
              uint16_t idle_timeout, uint16_t hard_timeout)
  {
 -    struct rule *rule = xcalloc(1, sizeof *rule);
 +    struct rule *rule = xzalloc(sizeof *rule);
      rule->idle_timeout = idle_timeout;
      rule->hard_timeout = hard_timeout;
      rule->used = rule->created = time_msec();
@@@ -2249,7 -2338,7 +2296,7 @@@ update_port_config(struct ofproto *p, s
  #undef REVALIDATE_BITS
      if (mask & OFPPC_NO_FLOOD) {
          port->opp.config ^= OFPPC_NO_FLOOD;
-         refresh_port_group(p, DP_GROUP_FLOOD);
+         refresh_port_groups(p);
      }
      if (mask & OFPPC_NO_PACKET_IN) {
          port->opp.config ^= OFPPC_NO_PACKET_IN;
@@@ -2450,7 -2539,7 +2497,7 @@@ query_stats(struct ofproto *p, struct r
      byte_count = rule->byte_count;
  
      n_odp_flows = rule->cr.wc.wildcards ? list_size(&rule->list) : 1;
 -    odp_flows = xcalloc(1, n_odp_flows * sizeof *odp_flows);
 +    odp_flows = xzalloc(n_odp_flows * sizeof *odp_flows);
      if (rule->cr.wc.wildcards) {
          size_t i = 0;
          LIST_FOR_EACH (subrule, struct rule, list, &rule->list) {
@@@ -2908,6 -2997,58 +2955,6 @@@ handle_flow_mod(struct ofproto *p, stru
      }
  }
  
 -static void
 -send_capability_reply(struct ofproto *p, struct ofconn *ofconn, uint32_t xid)
 -{
 -    struct ofmp_capability_reply *ocr;
 -    struct ofpbuf *b;
 -    char capabilities[] = "com.nicira.mgmt.manager=false\n";
 -
 -    ocr = make_openflow_xid(sizeof(*ocr), OFPT_VENDOR, xid, &b);
 -    ocr->header.header.vendor = htonl(NX_VENDOR_ID);
 -    ocr->header.header.subtype = htonl(NXT_MGMT);
 -    ocr->header.type = htons(OFMPT_CAPABILITY_REPLY);
 -
 -    ocr->format = htonl(OFMPCOF_SIMPLE);
 -    ocr->mgmt_id = htonll(p->mgmt_id);
 -
 -    ofpbuf_put(b, capabilities, strlen(capabilities));
 -
 -    queue_tx(b, ofconn, ofconn->reply_counter);
 -}
 -
 -static int
 -handle_ofmp(struct ofproto *p, struct ofconn *ofconn, 
 -            struct ofmp_header *ofmph)
 -{
 -    size_t msg_len = ntohs(ofmph->header.header.length);
 -    if (msg_len < sizeof(*ofmph)) {
 -        VLOG_WARN_RL(&rl, "dropping short managment message: %zu\n", msg_len);
 -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
 -    }
 -
 -    if (ofmph->type == htons(OFMPT_CAPABILITY_REQUEST)) {
 -        struct ofmp_capability_request *ofmpcr;
 -
 -        if (msg_len < sizeof(struct ofmp_capability_request)) {
 -            VLOG_WARN_RL(&rl, "dropping short capability request: %zu\n",
 -                    msg_len);
 -            return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
 -        }
 -
 -        ofmpcr = (struct ofmp_capability_request *)ofmph;
 -        if (ofmpcr->format != htonl(OFMPCAF_SIMPLE)) {
 -            /* xxx Find a better type than bad subtype */
 -            return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE);
 -        }
 -
 -        send_capability_reply(p, ofconn, ofmph->header.header.xid);
 -        return 0;
 -    } else {
 -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE);
 -    }
 -}
 -
  static int
  handle_vendor(struct ofproto *p, struct ofconn *ofconn, void *msg)
  {
      case NXT_STATUS_REQUEST:
          return switch_status_handle_request(p->switch_status, ofconn->rconn,
                                              msg);
 -
 -    case NXT_ACT_SET_CONFIG:
 -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE); /* XXX */
 -
 -    case NXT_ACT_GET_CONFIG:
 -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE); /* XXX */
 -
 -    case NXT_COMMAND_REQUEST:
 -        if (p->executer) {
 -            return executer_handle_request(p->executer, ofconn->rconn, msg);
 -        }
 -        break;
 -
 -    case NXT_MGMT:
 -        return handle_ofmp(p, ofconn, msg);
      }
  
      return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE);
@@@ -2999,7 -3155,7 +3046,7 @@@ handle_openflow(struct ofconn *ofconn, 
  }
  \f
  static void
- handle_odp_msg(struct ofproto *p, struct ofpbuf *packet)
+ handle_odp_miss_msg(struct ofproto *p, struct ofpbuf *packet)
  {
      struct odp_msg *msg = packet->data;
      uint16_t in_port = odp_port_to_ofp_port(msg->port);
      struct ofpbuf payload;
      flow_t flow;
  
-     /* Handle controller actions. */
-     if (msg->type == _ODPL_ACTION_NR) {
-         COVERAGE_INC(ofproto_ctlr_action);
-         pinsched_send(p->action_sched, in_port, packet,
-                       send_packet_in_action, p);
-         return;
-     }
      payload.data = msg + 1;
      payload.size = msg->length - sizeof *msg;
      flow_extract(&payload, msg->port, &flow);
          ofpbuf_delete(packet);
      }
  }
+ static void
+ handle_odp_msg(struct ofproto *p, struct ofpbuf *packet)
+ {
+     struct odp_msg *msg = packet->data;
+     switch (msg->type) {
+     case _ODPL_ACTION_NR:
+         COVERAGE_INC(ofproto_ctlr_action);
+         pinsched_send(p->action_sched, odp_port_to_ofp_port(msg->port), packet,
+                       send_packet_in_action, p);
+         break;
+     case _ODPL_SFLOW_NR:
+         if (p->sflow) {
+             ofproto_sflow_received(p->sflow, msg);
+         }
+         ofpbuf_delete(packet);
+         break;
+     case _ODPL_MISS_NR:
+         handle_odp_miss_msg(p, packet);
+         break;
+     default:
+         VLOG_WARN_RL(&rl, "received ODP message of unexpected type %"PRIu32,
+                      msg->type);
+         break;
+     }
+ }
  \f
  static void
  revalidate_cb(struct cls_rule *sub_, void *cbdata_)
diff --combined ofproto/ofproto.h
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Copyright (c) 2009 Nicira Networks.
 + * Copyright (c) 2009, 2010 Nicira Networks.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
@@@ -29,6 -29,11 +29,11 @@@ struct ofhooks
  struct ofproto;
  struct svec;
  
+ enum {
+     DP_GROUP_FLOOD = 0,
+     DP_GROUP_ALL = 1
+ };
  struct ofexpired {
      flow_t flow;
      uint64_t packet_count;      /* Packets from subrules. */
      long long int used;         /* Last-used time (0 if never used). */
  };
  
 -int ofproto_create(const char *datapath, const struct ofhooks *, void *aux,
+ struct ofproto_sflow_options {
+     struct svec targets;
+     uint32_t sampling_rate;
+     uint32_t polling_interval;
+     uint32_t header_len;
+     uint32_t sub_id;
+     char *agent_device;
+     char *control_ip;
+ };
 +int ofproto_create(const char *datapath, const char *datapath_type,
 +                   const struct ofhooks *, void *aux,
                     struct ofproto **ofprotop);
  void ofproto_destroy(struct ofproto *);
  int ofproto_run(struct ofproto *);
@@@ -48,6 -62,7 +63,6 @@@ bool ofproto_is_alive(const struct ofpr
  
  /* Configuration. */
  void ofproto_set_datapath_id(struct ofproto *, uint64_t datapath_id);
 -void ofproto_set_mgmt_id(struct ofproto *, uint64_t mgmt_id);
  void ofproto_set_probe_interval(struct ofproto *, int probe_interval);
  void ofproto_set_max_backoff(struct ofproto *, int max_backoff);
  void ofproto_set_desc(struct ofproto *,
@@@ -62,12 -77,16 +77,13 @@@ int ofproto_set_listeners(struct ofprot
  int ofproto_set_snoops(struct ofproto *, const struct svec *snoops);
  int ofproto_set_netflow(struct ofproto *,
                          const struct netflow_options *nf_options);
+ void ofproto_set_sflow(struct ofproto *, const struct ofproto_sflow_options *);
  void ofproto_set_failure(struct ofproto *, bool fail_open);
  void ofproto_set_rate_limit(struct ofproto *, int rate_limit, int burst_limit);
  int ofproto_set_stp(struct ofproto *, bool enable_stp);
 -int ofproto_set_remote_execution(struct ofproto *, const char *command_acl,
 -                                 const char *command_dir);
  
  /* Configuration querying. */
  uint64_t ofproto_get_datapath_id(const struct ofproto *);
 -uint64_t ofproto_get_mgmt_id(const struct ofproto *);
  int ofproto_get_probe_interval(const struct ofproto *);
  int ofproto_get_max_backoff(const struct ofproto *);
  bool ofproto_get_in_band(const struct ofproto *);
diff --combined tests/automake.mk
@@@ -6,143 -6,17 +6,143 @@@ EXTRA_DIST += 
        $(srcdir)/tests/testsuite
  TESTSUITE_AT = \
        tests/testsuite.at \
 -      tests/lcov-pre.at \
 +      tests/ovsdb-macros.at \
        tests/library.at \
 +      tests/check-structs.at \
 +      tests/daemon.at \
 +      tests/vconn.at \
 +      tests/dir_name.at \
 +      tests/aes128.at \
 +      tests/uuid.at \
 +      tests/json.at \
 +      tests/jsonrpc.at \
 +      tests/timeval.at \
 +      tests/lockfile.at \
 +      tests/reconnect.at \
 +      tests/ovsdb.at \
 +      tests/ovsdb-log.at \
 +      tests/ovsdb-types.at \
 +      tests/ovsdb-data.at \
 +      tests/ovsdb-column.at \
 +      tests/ovsdb-table.at \
 +      tests/ovsdb-row.at \
 +      tests/ovsdb-condition.at \
 +      tests/ovsdb-mutation.at \
 +      tests/ovsdb-query.at \
 +      tests/ovsdb-transaction.at \
 +      tests/ovsdb-execution.at \
 +      tests/ovsdb-trigger.at \
 +      tests/ovsdb-file.at \
 +      tests/ovsdb-server.at \
 +      tests/ovsdb-monitor.at \
 +      tests/ovsdb-idl.at \
        tests/stp.at \
 -      tests/ovs-vsctl.at \
 -      tests/lcov-post.at
 +      tests/ovs-vsctl.at
  TESTSUITE = $(srcdir)/tests/testsuite
  DISTCLEANFILES += tests/atconfig tests/atlocal $(TESTSUITE)
  
 +AUTOTEST_PATH = utilities:vswitchd:ovsdb:tests
 +
  check-local: tests/atconfig tests/atlocal $(TESTSUITE)
 -      $(SHELL) '$(TESTSUITE)' -C tests AUTOTEST_PATH='utilities:vswitchd:tests' $(TESTSUITEFLAGS)
 +      $(SHELL) '$(TESTSUITE)' -C tests AUTOTEST_PATH=$(AUTOTEST_PATH) $(TESTSUITEFLAGS)
 +\f
 +# lcov support
 +
 +lcov_wrappers = \
 +      tests/lcov/ovs-appctl \
 +      tests/lcov/ovs-vsctl \
 +      tests/lcov/ovsdb-client \
 +      tests/lcov/ovsdb-server \
 +      tests/lcov/ovsdb-tool \
 +      tests/lcov/test-aes128 \
 +      tests/lcov/test-classifier \
 +      tests/lcov/test-csum \
 +      tests/lcov/test-dhcp-client \
 +      tests/lcov/test-dir_name \
 +      tests/lcov/test-flows \
 +      tests/lcov/test-hash \
 +      tests/lcov/test-hmap \
 +      tests/lcov/test-json \
 +      tests/lcov/test-jsonrpc \
 +      tests/lcov/test-list \
 +      tests/lcov/test-lockfile \
 +      tests/lcov/test-ovsdb \
 +      tests/lcov/test-reconnect \
 +      tests/lcov/test-sha1 \
 +      tests/lcov/test-stp \
 +      tests/lcov/test-timeval \
 +      tests/lcov/test-type-props \
 +      tests/lcov/test-uuid \
 +      tests/lcov/test-vconn
 +
 +$(lcov_wrappers): tests/lcov-wrapper.in
 +      @test -d tests/lcov || mkdir tests/lcov
 +      sed -e 's,[@]abs_top_builddir[@],$(abs_top_builddir),' \
 +          -e 's,[@]wrap_program[@],$@,' \
 +              $(top_srcdir)/tests/lcov-wrapper.in > $@.tmp
 +      chmod +x $@.tmp
 +      mv $@.tmp $@
 +CLEANFILES += $(lcov_wrappers)
 +EXTRA_DIST += tests/lcov-wrapper.in
 +
 +LCOV = lcov -b $(abs_top_builddir) -d $(abs_top_builddir) -q
 +check-lcov: all tests/atconfig tests/atlocal $(TESTSUITE) $(lcov_wrappers)
 +      rm -fr tests/coverage.html tests/coverage.info
 +      $(LCOV) -c -i -o - > tests/coverage.info
 +      $(SHELL) '$(TESTSUITE)' -C tests CHECK_LCOV=true AUTOTEST_PATH='tests/lcov:$(AUTOTEST_PATH)' $(TESTSUITEFLAGS); \
 +              rc=$$?; \
 +              echo "Producing coverage.html..."; \
 +              cd tests && genhtml -q -o coverage.html coverage.info; \
 +              exit $$rc
 +\f
 +# valgrind support
 +
 +valgrind_wrappers = \
 +      tests/valgrind/ovs-appctl \
 +      tests/valgrind/ovs-vsctl \
 +      tests/valgrind/ovsdb-client \
 +      tests/valgrind/ovsdb-server \
 +      tests/valgrind/ovsdb-tool \
 +      tests/valgrind/test-aes128 \
 +      tests/valgrind/test-classifier \
 +      tests/valgrind/test-csum \
 +      tests/valgrind/test-dhcp-client \
 +      tests/valgrind/test-dir_name \
 +      tests/valgrind/test-flows \
 +      tests/valgrind/test-hash \
 +      tests/valgrind/test-hmap \
 +      tests/valgrind/test-json \
 +      tests/valgrind/test-jsonrpc \
 +      tests/valgrind/test-list \
 +      tests/valgrind/test-lockfile \
 +      tests/valgrind/test-ovsdb \
 +      tests/valgrind/test-reconnect \
 +      tests/valgrind/test-sha1 \
 +      tests/valgrind/test-stp \
 +      tests/valgrind/test-timeval \
 +      tests/valgrind/test-type-props \
 +      tests/valgrind/test-uuid \
 +      tests/valgrind/test-vconn
  
 +$(valgrind_wrappers): tests/valgrind-wrapper.in
 +      @test -d tests/valgrind || mkdir tests/valgrind
 +      sed -e 's,[@]wrap_program[@],$@,' \
 +              $(top_srcdir)/tests/valgrind-wrapper.in > $@.tmp
 +      chmod +x $@.tmp
 +      mv $@.tmp $@
 +CLEANFILES += $(valgrind_wrappers)
 +EXTRA_DIST += tests/valgrind-wrapper.in
 +
 +VALGRIND = valgrind --log-file=valgrind.%p --leak-check=full \
 +      --suppressions=$(abs_top_srcdir)/tests/openssl.supp --num-callers=20
 +EXTRA_DIST += tests/openssl.supp
 +check-valgrind: all tests/atconfig tests/atlocal $(TESTSUITE) $(valgrind_wrappers)
 +      $(SHELL) '$(TESTSUITE)' -C tests CHECK_VALGRIND=true VALGRIND='$(VALGRIND)' AUTOTEST_PATH='tests/valgrind:$(AUTOTEST_PATH)' -d $(TESTSUITEFLAGS)
 +      @echo
 +      @echo '----------------------------------------------------------------------'
 +      @echo 'Valgrind output can be found in tests/testsuite.dir/*/valgrind.*'
 +      @echo '----------------------------------------------------------------------'
 +\f
  clean-local:
        test ! -f '$(TESTSUITE)' || $(SHELL) '$(TESTSUITE)' -C tests --clean
  
@@@ -156,17 -30,13 +156,17 @@@ $(TESTSUITE): package.m4 $(TESTSUITE_AT
  $(srcdir)/package.m4: $(top_srcdir)/configure.ac
        :;{ \
          echo '# Signature of the current package.' && \
 -        echo 'm4_define([AT_PACKAGE_NAME],      [@PACKAGE_NAME@])' && \
 -        echo 'm4_define([AT_PACKAGE_TARNAME],   [@PACKAGE_TARNAME@])' && \
 -        echo 'm4_define([AT_PACKAGE_VERSION],   [@PACKAGE_VERSION@])' && \
 -        echo 'm4_define([AT_PACKAGE_STRING],    [@PACKAGE_STRING@])' && \
 -        echo 'm4_define([AT_PACKAGE_BUGREPORT], [@PACKAGE_BUGREPORT@])'; \
 +        echo 'm4_define([AT_PACKAGE_NAME],      [$(PACKAGE_NAME)])' && \
 +        echo 'm4_define([AT_PACKAGE_TARNAME],   [$(PACKAGE_TARNAME)])' && \
 +        echo 'm4_define([AT_PACKAGE_VERSION],   [$(PACKAGE_VERSION)])' && \
 +        echo 'm4_define([AT_PACKAGE_STRING],    [$(PACKAGE_STRING)])' && \
 +        echo 'm4_define([AT_PACKAGE_BUGREPORT], [$(PACKAGE_BUGREPORT)])'; \
        } >'$(srcdir)/package.m4'
  
 +noinst_PROGRAMS += tests/test-aes128
 +tests_test_aes128_SOURCES = tests/test-aes128.c
 +tests_test_aes128_LDADD = lib/libopenvswitch.a
 +
  noinst_PROGRAMS += tests/test-classifier
  tests_test_classifier_SOURCES = tests/test-classifier.c
  tests_test_classifier_LDADD = lib/libopenvswitch.a
@@@ -175,10 -45,6 +175,10 @@@ noinst_PROGRAMS += tests/test-csu
  tests_test_csum_SOURCES = tests/test-csum.c
  tests_test_csum_LDADD = lib/libopenvswitch.a
  
 +noinst_PROGRAMS += tests/test-dir_name
 +tests_test_dir_name_SOURCES = tests/test-dir_name.c
 +tests_test_dir_name_LDADD = lib/libopenvswitch.a
 +
  noinst_PROGRAMS += tests/test-flows
  tests_test_flows_SOURCES = tests/test-flows.c
  tests_test_flows_LDADD = lib/libopenvswitch.a
@@@ -192,75 -58,29 +192,78 @@@ noinst_PROGRAMS += tests/test-hma
  tests_test_hmap_SOURCES = tests/test-hmap.c
  tests_test_hmap_LDADD = lib/libopenvswitch.a
  
 +noinst_PROGRAMS += tests/test-json
 +tests_test_json_SOURCES = tests/test-json.c
 +tests_test_json_LDADD = lib/libopenvswitch.a
 +
 +noinst_PROGRAMS += tests/test-jsonrpc
 +tests_test_jsonrpc_SOURCES = tests/test-jsonrpc.c
 +tests_test_jsonrpc_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
 +
  noinst_PROGRAMS += tests/test-list
  tests_test_list_SOURCES = tests/test-list.c
  tests_test_list_LDADD = lib/libopenvswitch.a
  
 +noinst_PROGRAMS += tests/test-lockfile
 +tests_test_lockfile_SOURCES = tests/test-lockfile.c
 +tests_test_lockfile_LDADD = lib/libopenvswitch.a
 +
 +noinst_PROGRAMS += tests/test-ovsdb
 +tests_test_ovsdb_SOURCES = \
 +      tests/test-ovsdb.c \
 +      tests/idltest.c \
 +      tests/idltest.h
 +EXTRA_DIST += tests/uuidfilt.pl
 +tests_test_ovsdb_LDADD = ovsdb/libovsdb.a lib/libopenvswitch.a $(SSL_LIBS)
 +
 +# idltest schema and IDL
 +OVSIDL_BUILT +=       tests/idltest.c tests/idltest.h tests/idltest.ovsidl
 +IDLTEST_IDL_FILES = tests/idltest.ovsschema tests/idltest.ann
 +EXTRA_DIST += $(IDLTEST_IDL_FILES)
 +tests/idltest.ovsidl: $(IDLTEST_IDL_FILES)
 +      $(OVSDB_IDLC) -C $(srcdir) annotate $(IDLTEST_IDL_FILES) > $@.tmp
 +      mv $@.tmp $@
 +
 +tests/idltest.c: tests/idltest.h
 +
 +noinst_PROGRAMS += tests/test-reconnect
 +tests_test_reconnect_SOURCES = tests/test-reconnect.c
 +tests_test_reconnect_LDADD = lib/libopenvswitch.a
 +
  noinst_PROGRAMS += tests/test-sha1
  tests_test_sha1_SOURCES = tests/test-sha1.c
  tests_test_sha1_LDADD = lib/libopenvswitch.a
  
 +noinst_PROGRAMS += tests/test-timeval
 +tests_test_timeval_SOURCES = tests/test-timeval.c
 +tests_test_timeval_LDADD = lib/libopenvswitch.a
 +
+ noinst_PROGRAMS += tests/test-strtok_r
+ tests_test_strtok_r_SOURCES = tests/test-strtok_r.c
  noinst_PROGRAMS += tests/test-type-props
  tests_test_type_props_SOURCES = tests/test-type-props.c
  
  noinst_PROGRAMS += tests/test-dhcp-client
  tests_test_dhcp_client_SOURCES = tests/test-dhcp-client.c
 -tests_test_dhcp_client_LDADD = lib/libopenvswitch.a $(FAULT_LIBS)
 +tests_test_dhcp_client_LDADD = lib/libopenvswitch.a
  
  noinst_PROGRAMS += tests/test-stp
  tests_test_stp_SOURCES = tests/test-stp.c
  tests_test_stp_LDADD = lib/libopenvswitch.a
  
 +noinst_PROGRAMS += tests/test-uuid
 +tests_test_uuid_SOURCES = tests/test-uuid.c
 +tests_test_uuid_LDADD = lib/libopenvswitch.a
 +
  noinst_PROGRAMS += tests/test-vconn
  tests_test_vconn_SOURCES = tests/test-vconn.c
  tests_test_vconn_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
 -
 +EXTRA_DIST += \
 +      tests/testpki-cacert.pem \
 +      tests/testpki-cert.pem \
 +      tests/testpki-cert2.pem \
 +      tests/testpki-privkey.pem \
 +      tests/testpki-privkey2.pem \
 +      tests/testpki-req.pem \
 +      tests/testpki-req2.pem
diff --combined tests/library.at
@@@ -2,35 -2,42 +2,39 @@@ AT_BANNER([library unit tests]
  
  AT_SETUP([test flow extractor])
  AT_CHECK([$PERL `which flowgen.pl` >/dev/null 3>flows 4>pcap])
 -OVS_CHECK_LCOV([test-flows <flows 3<pcap], [0], [checked 247 packets, 0 errors
 +AT_CHECK([test-flows <flows 3<pcap], [0], [checked 247 packets, 0 errors
  ])
  AT_CLEANUP
  
  AT_SETUP([test TCP/IP checksumming])
 -OVS_CHECK_LCOV([test-csum], [0], [ignore])
 +AT_CHECK([test-csum], [0], [ignore])
  AT_CLEANUP
  
  AT_SETUP([test flow classifier])
 -OVS_CHECK_LCOV([test-classifier], [0], [ignore])
 +AT_KEYWORDS([slow])
 +AT_CHECK([test-classifier], [0], [ignore])
  AT_CLEANUP
  
  AT_SETUP([test hash functions])
 -OVS_CHECK_LCOV([test-hash], [0], [ignore])
 +AT_CHECK([test-hash], [0], [ignore])
  AT_CLEANUP
  
  AT_SETUP([test hash map])
 -OVS_CHECK_LCOV([test-hmap], [0], [ignore])
 +AT_CHECK([test-hmap], [0], [ignore])
  AT_CLEANUP
  
  AT_SETUP([test linked lists])
 -OVS_CHECK_LCOV([test-list], [0], [ignore])
 +AT_CHECK([test-list], [0], [ignore])
  AT_CLEANUP
  
  AT_SETUP([test SHA-1])
 -OVS_CHECK_LCOV([test-sha1], [0], [ignore])
 +AT_CHECK([test-sha1], [0], [ignore])
  AT_CLEANUP
  
  AT_SETUP([test type properties])
 -OVS_CHECK_LCOV([test-type-props], [0], [ignore])
 -AT_CLEANUP
 -
 -AT_SETUP([test vconn library])
 -OVS_CHECK_LCOV([test-vconn], [0], [ignore])
 +AT_CHECK([test-type-props], [0], [ignore])
  AT_CLEANUP
+ AT_SETUP([test strtok_r bug fix])
+ AT_CHECK([test-strtok_r], [0], [ignore])
+ AT_CLEANUP
diff --combined utilities/automake.mk
@@@ -1,12 -1,12 +1,12 @@@
  bin_PROGRAMS += \
        utilities/ovs-appctl \
 -      utilities/ovs-cfg-mod \
        utilities/ovs-controller \
        utilities/ovs-discover \
        utilities/ovs-dpctl \
        utilities/ovs-kill \
        utilities/ovs-ofctl \
        utilities/ovs-openflowd \
 +      utilities/ovs-vsctl \
        utilities/ovs-wdt
  noinst_PROGRAMS += utilities/nlmon
  bin_SCRIPTS += utilities/ovs-pki utilities/ovs-vsctl
@@@ -15,6 -15,7 +15,6 @@@ dist_sbin_SCRIPTS += utilities/ovs-moni
  
  EXTRA_DIST += \
        utilities/ovs-appctl.8.in \
 -      utilities/ovs-cfg-mod.8.in \
        utilities/ovs-controller.8.in \
        utilities/ovs-discover.8.in \
        utilities/ovs-dpctl.8.in \
        utilities/ovs-pki-cgi.in \
        utilities/ovs-pki.8.in \
        utilities/ovs-pki.in \
 -      utilities/ovs-vsctl.8.in \
 -      utilities/ovs-vsctl.in
 +      utilities/ovs-vsctl.8.in
  DISTCLEANFILES += \
        utilities/ovs-appctl.8 \
 -      utilities/ovs-cfg-mod.8 \
        utilities/ovs-controller.8 \
        utilities/ovs-discover.8 \
        utilities/ovs-dpctl.8 \
        utilities/ovs-pki \
        utilities/ovs-pki-cgi \
        utilities/ovs-pki.8 \
 -      utilities/ovs-vsctl \
        utilities/ovs-vsctl.8
  
  man_MANS += \
        utilities/ovs-appctl.8 \
 -      utilities/ovs-cfg-mod.8 \
        utilities/ovs-controller.8 \
        utilities/ovs-discover.8 \
        utilities/ovs-dpctl.8 \
  utilities_ovs_appctl_SOURCES = utilities/ovs-appctl.c
  utilities_ovs_appctl_LDADD = lib/libopenvswitch.a
  
 -utilities_ovs_cfg_mod_SOURCES = utilities/ovs-cfg-mod.c
 -utilities_ovs_cfg_mod_LDADD = lib/libopenvswitch.a
 -
  utilities_ovs_controller_SOURCES = utilities/ovs-controller.c
 -utilities_ovs_controller_LDADD = lib/libopenvswitch.a $(FAULT_LIBS) $(SSL_LIBS)
 +utilities_ovs_controller_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
  
  utilities_ovs_discover_SOURCES = utilities/ovs-discover.c
  utilities_ovs_discover_LDADD = lib/libopenvswitch.a
  
  utilities_ovs_dpctl_SOURCES = utilities/ovs-dpctl.c
 -utilities_ovs_dpctl_LDADD = lib/libopenvswitch.a $(FAULT_LIBS)
 +utilities_ovs_dpctl_LDADD = lib/libopenvswitch.a
  
  utilities_ovs_kill_SOURCES = utilities/ovs-kill.c
  utilities_ovs_kill_LDADD = lib/libopenvswitch.a
  
  utilities_ovs_ofctl_SOURCES = utilities/ovs-ofctl.c
 -utilities_ovs_ofctl_LDADD = lib/libopenvswitch.a $(FAULT_LIBS) $(SSL_LIBS)
 +utilities_ovs_ofctl_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
  
  utilities_ovs_openflowd_SOURCES = utilities/ovs-openflowd.c
  utilities_ovs_openflowd_LDADD = \
        ofproto/libofproto.a \
+       lib/libsflow.a \
        lib/libopenvswitch.a \
 -      $(FAULT_LIBS) \
        $(SSL_LIBS)
  
 +utilities_ovs_vsctl_SOURCES = utilities/ovs-vsctl.c vswitchd/vswitch-idl.c
 +utilities_ovs_vsctl_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
 +
  utilities_ovs_wdt_SOURCES = utilities/ovs-wdt.c
  
  utilities_nlmon_SOURCES = utilities/nlmon.c
diff --combined utilities/ovs-discover.c
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Copyright (c) 2008, 2009 Nicira Networks.
 + * Copyright (c) 2008, 2009, 2010 Nicira Networks.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
@@@ -75,7 -75,6 +75,7 @@@ main(int argc, char *argv[]
      int retval;
      int i;
  
 +    proctitle_init(argc, argv);
      set_program_name(argv[0]);
      time_init();
      vlog_init();
          struct iface *iface = &ifaces[i];
          dhclient_init(iface->dhcp, 0);
      }
 -    fatal_signal_add_hook(release_ifaces, NULL, true);
 +    fatal_signal_add_hook(release_ifaces, NULL, NULL, true);
  
      retval = regcomp(&accept_controller_regex, accept_controller_re,
                       REG_NOSUB | REG_EXTENDED);
  
      retval = unixctl_server_create(NULL, &unixctl);
      if (retval) {
 -        ovs_fatal(retval, "Could not listen for unixctl connections");
 +        exit(EXIT_FAILURE);
      }
  
      die_if_already_running();
  
      signal(SIGPIPE, SIG_IGN);
      for (;;) {
 -        fatal_signal_block();
          for (i = 0; i < n_ifaces; i++) {
              struct iface *iface = &ifaces[i];
              dhclient_run(iface->dhcp);
              dhclient_wait(iface->dhcp);
          }
          unixctl_server_wait(unixctl);
 -        fatal_signal_unblock();
          poll_block();
      }
  
@@@ -214,7 -215,7 +214,7 @@@ iface_init(struct iface *iface, const c
           * persists past program termination. */
          struct netdev *netdev;
  
 -        retval = netdev_open(iface->name, NETDEV_ETH_TYPE_NONE, &netdev);
 +        retval = netdev_open_default(iface->name, &netdev);
          if (retval) {
              ovs_error(retval, "Could not open %s device", iface->name);
              return false;
@@@ -281,7 -282,8 +281,8 @@@ parse_options(int argc, char *argv[]
          OPT_ACCEPT_VCONN = UCHAR_MAX + 1,
          OPT_EXIT_WITHOUT_BIND,
          OPT_EXIT_AFTER_BIND,
-         OPT_NO_DETACH
+         OPT_NO_DETACH,
+         VLOG_OPTION_ENUMS
      };
      static struct option long_options[] = {
          {"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN},
          {"timeout",     required_argument, 0, 't'},
          {"pidfile",     optional_argument, 0, OPT_PIDFILE},
          {"overwrite-pidfile", no_argument, 0, OPT_OVERWRITE_PIDFILE},
-         {"verbose",     optional_argument, 0, 'v'},
          {"help",        no_argument, 0, 'h'},
          {"version",     no_argument, 0, 'V'},
+         VLOG_LONG_OPTIONS,
          {0, 0, 0, 0},
      };
      char *short_options = long_options_to_short_options(long_options);
              OVS_PRINT_VERSION(0, 0);
              exit(EXIT_SUCCESS);
  
-         case 'v':
-             vlog_set_verbosity(optarg);
-             break;
+         VLOG_OPTION_HANDLERS
  
          case '?':
              exit(EXIT_FAILURE);
diff --combined utilities/ovs-dpctl.c
@@@ -1,5 -1,5 +1,5 @@@
  /*
 - * Copyright (c) 2008, 2009 Nicira Networks.
 + * Copyright (c) 2008, 2009, 2010 Nicira Networks.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
  #include "vlog.h"
  #define THIS_MODULE VLM_dpctl
  
 -struct command {
 -    const char *name;
 -    int min_args;
 -    int max_args;
 -    void (*handler)(int argc, char *argv[]);
 -};
 -
 -static struct command all_commands[];
 +static const struct command all_commands[];
  
  static void usage(void) NO_RETURN;
  static void parse_options(int argc, char *argv[]);
  
 -int main(int argc, char *argv[])
 +int
 +main(int argc, char *argv[])
  {
 -    struct command *p;
 -
      set_program_name(argv[0]);
      time_init();
      vlog_init();
      parse_options(argc, argv);
      signal(SIGPIPE, SIG_IGN);
 -
 -    argc -= optind;
 -    argv += optind;
 -    if (argc < 1)
 -        ovs_fatal(0, "missing command name; use --help for help");
 -
 -    for (p = all_commands; p->name != NULL; p++) {
 -        if (!strcmp(p->name, argv[0])) {
 -            int n_arg = argc - 1;
 -            if (n_arg < p->min_args)
 -                ovs_fatal(0, "'%s' command requires at least %d arguments",
 -                          p->name, p->min_args);
 -            else if (n_arg > p->max_args)
 -                ovs_fatal(0, "'%s' command takes at most %d arguments",
 -                          p->name, p->max_args);
 -            else {
 -                p->handler(argc, argv);
 -                if (ferror(stdout)) {
 -                    ovs_fatal(0, "write to stdout failed");
 -                }
 -                if (ferror(stderr)) {
 -                    ovs_fatal(0, "write to stderr failed");
 -                }
 -                exit(0);
 -            }
 -        }
 -    }
 -    ovs_fatal(0, "unknown command '%s'; use --help for help", argv[0]);
 -
 +    run_command(argc - optind, argv + optind, all_commands);
      return 0;
  }
  
  static void
  parse_options(int argc, char *argv[])
  {
+     enum {
+         OPT_DUMMY = UCHAR_MAX + 1,
+         VLOG_OPTION_ENUMS
+     };
      static struct option long_options[] = {
          {"timeout", required_argument, 0, 't'},
-         {"verbose", optional_argument, 0, 'v'},
          {"help", no_argument, 0, 'h'},
          {"version", no_argument, 0, 'V'},
+         VLOG_LONG_OPTIONS,
          {0, 0, 0, 0},
      };
      char *short_options = long_options_to_short_options(long_options);
              OVS_PRINT_VERSION(0, 0);
              exit(EXIT_SUCCESS);
  
-         case 'v':
-             vlog_set_verbosity(optarg);
-             break;
+         VLOG_OPTION_HANDLERS
  
          case '?':
              exit(EXIT_FAILURE);
@@@ -166,7 -204,7 +168,7 @@@ static int if_up(const char *netdev_nam
      struct netdev *netdev;
      int retval;
  
 -    retval = netdev_open(netdev_name, NETDEV_ETH_TYPE_NONE, &netdev);
 +    retval = netdev_open_default(netdev_name, &netdev);
      if (!retval) {
          retval = netdev_turn_flags_on(netdev, NETDEV_UP, true);
          netdev_close(netdev);
      return retval;
  }
  
 +static int
 +parsed_dpif_open(const char *arg_, bool create, struct dpif **dpifp)
 +{
 +    int result;
 +    char *name, *type;
 +
 +    dp_parse_name(arg_, &name, &type);
 +
 +    if (create) {
 +        result = dpif_create(name, type, dpifp);
 +    } else {
 +        result = dpif_open(name, type, dpifp);
 +    }
 +
 +    free(name);
 +    free(type);
 +    return result;
 +}
 +
  static void
  do_add_dp(int argc UNUSED, char *argv[])
  {
      struct dpif *dpif;
 -    run(dpif_create(argv[1], &dpif), "add_dp");
 +    run(parsed_dpif_open(argv[1], true, &dpif), "add_dp");
      dpif_close(dpif);
      if (argc > 2) {
          do_add_if(argc, argv);
@@@ -208,7 -227,7 +210,7 @@@ static voi
  do_del_dp(int argc UNUSED, char *argv[])
  {
      struct dpif *dpif;
 -    run(dpif_open(argv[1], &dpif), "opening datapath");
 +    run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
      run(dpif_delete(dpif), "del_dp");
      dpif_close(dpif);
  }
@@@ -235,7 -254,7 +237,7 @@@ do_add_if(int argc UNUSED, char *argv[]
      struct dpif *dpif;
      int i;
  
 -    run(dpif_open(argv[1], &dpif), "opening datapath");
 +    run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
      for (i = 2; i < argc; i++) {
          char *save_ptr = NULL;
          char *devname, *suboptions;
@@@ -313,7 -332,7 +315,7 @@@ do_del_if(int argc UNUSED, char *argv[]
      struct dpif *dpif;
      int i;
  
 -    run(dpif_open(argv[1], &dpif), "opening datapath");
 +    run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
      for (i = 2; i < argc; i++) {
          const char *name = argv[i];
          uint16_t port;
@@@ -385,7 -404,7 +387,7 @@@ do_show(int argc, char *argv[]
              struct dpif *dpif;
              int error;
  
 -            error = dpif_open(name, &dpif);
 +            error = parsed_dpif_open(name, false, &dpif);
              if (!error) {
                  show_dpif(dpif);
              } else {
              int error;
  
              sprintf(name, "dp%u", i);
 -            error = dpif_open(name, &dpif);
 +            error = parsed_dpif_open(name, false, &dpif);
              if (!error) {
                  show_dpif(dpif);
              } else if (error != ENODEV) {
  static void
  do_dump_dps(int argc UNUSED, char *argv[] UNUSED)
  {
 -    struct svec all_dps;
 +    struct svec dpif_names, dpif_types;
      unsigned int i;
 -    int error;
 +    int error = 0;
 +
 +    svec_init(&dpif_names);
 +    svec_init(&dpif_types);
 +    dp_enumerate_types(&dpif_types);
 +
 +    for (i = 0; i < dpif_types.n; i++) {
 +        unsigned int j;
 +        int retval;
  
 -    svec_init(&all_dps);
 -    error = dp_enumerate(&all_dps);
 +        retval = dp_enumerate_names(dpif_types.names[i], &dpif_names);
 +        if (retval) {
 +            error = retval;
 +        }
  
 -    for (i = 0; i < all_dps.n; i++) {
 -        struct dpif *dpif;
 -        if (!dpif_open(all_dps.names[i], &dpif)) {
 -            printf("%s\n", dpif_name(dpif));
 -            dpif_close(dpif);
 +        for (j = 0; j < dpif_names.n; j++) {
 +            struct dpif *dpif;
 +            if (!dpif_open(dpif_names.names[j], dpif_types.names[i], &dpif)) {
 +                printf("%s\n", dpif_name(dpif));
 +                dpif_close(dpif);
 +            }
          }
      }
  
 -    svec_destroy(&all_dps);
 +    svec_destroy(&dpif_names);
 +    svec_destroy(&dpif_types);
      if (error) {
          exit(EXIT_FAILURE);
      }
@@@ -460,7 -467,7 +462,7 @@@ do_dump_flows(int argc UNUSED, char *ar
      struct ds ds;
      size_t i;
  
 -    run(dpif_open(argv[1], &dpif), "opening datapath");
 +    run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
      run(dpif_flow_list_all(dpif, &flows, &n_flows), "listing all flows");
  
      ds_init(&ds);
@@@ -486,7 -493,7 +488,7 @@@ do_del_flows(int argc UNUSED, char *arg
  {
      struct dpif *dpif;
  
 -    run(dpif_open(argv[1], &dpif), "opening datapath");
 +    run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
      run(dpif_flow_flush(dpif), "deleting all flows");
      dpif_close(dpif);
  }
@@@ -498,7 -505,7 +500,7 @@@ do_dump_groups(int argc UNUSED, char *a
      struct dpif *dpif;
      unsigned int i;
  
 -    run(dpif_open(argv[1], &dpif), "opening datapath");
 +    run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
      run(dpif_get_dp_stats(dpif, &stats), "get datapath stats");
      for (i = 0; i < stats.max_groups; i++) {
          uint16_t *ports;
@@@ -524,7 -531,7 +526,7 @@@ do_help(int argc UNUSED, char *argv[] U
      usage();
  }
  
 -static struct command all_commands[] = {
 +static const struct command all_commands[] = {
      { "add-dp", 1, INT_MAX, do_add_dp },
      { "del-dp", 1, 1, do_del_dp },
      { "add-if", 2, INT_MAX, do_add_if },
diff --combined utilities/ovs-ofctl.c
@@@ -44,9 -44,9 +44,9 @@@
  #include "packets.h"
  #include "random.h"
  #include "socket-util.h"
 +#include "stream-ssl.h"
  #include "timeval.h"
  #include "util.h"
 -#include "vconn-ssl.h"
  #include "vconn.h"
  
  #include "vlog.h"
  #define MOD_PORT_CMD_FLOOD   "flood"
  #define MOD_PORT_CMD_NOFLOOD "noflood"
  
 +/* Use strict matching for flow mod commands? */
 +static bool strict;
  
 -/* Settings that may be configured by the user. */
 -struct settings {
 -    bool strict;        /* Use strict matching for flow mod commands */
 -};
 -
 -struct command {
 -    const char *name;
 -    int min_args;
 -    int max_args;
 -    void (*handler)(const struct settings *, int argc, char *argv[]);
 -};
 -
 -static struct command all_commands[];
 +static const struct command all_commands[];
  
  static void usage(void) NO_RETURN;
 -static void parse_options(int argc, char *argv[], struct settings *);
 +static void parse_options(int argc, char *argv[]);
  
 -int main(int argc, char *argv[])
 +int
 +main(int argc, char *argv[])
  {
 -    struct settings s;
 -    struct command *p;
 -
      set_program_name(argv[0]);
      time_init();
      vlog_init();
 -    parse_options(argc, argv, &s);
 +    parse_options(argc, argv);
      signal(SIGPIPE, SIG_IGN);
 -
 -    argc -= optind;
 -    argv += optind;
 -    if (argc < 1)
 -        ovs_fatal(0, "missing command name; use --help for help");
 -
 -    for (p = all_commands; p->name != NULL; p++) {
 -        if (!strcmp(p->name, argv[0])) {
 -            int n_arg = argc - 1;
 -            if (n_arg < p->min_args)
 -                ovs_fatal(0, "'%s' command requires at least %d arguments",
 -                          p->name, p->min_args);
 -            else if (n_arg > p->max_args)
 -                ovs_fatal(0, "'%s' command takes at most %d arguments",
 -                          p->name, p->max_args);
 -            else {
 -                p->handler(&s, argc, argv);
 -                if (ferror(stdout)) {
 -                    ovs_fatal(0, "write to stdout failed");
 -                }
 -                if (ferror(stderr)) {
 -                    ovs_fatal(0, "write to stderr failed");
 -                }
 -                exit(0);
 -            }
 -        }
 -    }
 -    ovs_fatal(0, "unknown command '%s'; use --help for help", argv[0]);
 -
 +    run_command(argc - optind, argv + optind, all_commands);
      return 0;
  }
  
  static void
 -parse_options(int argc, char *argv[], struct settings *s)
 +parse_options(int argc, char *argv[])
  {
      enum {
-         OPT_STRICT = UCHAR_MAX + 1
+         OPT_STRICT = UCHAR_MAX + 1,
+         VLOG_OPTION_ENUMS
      };
      static struct option long_options[] = {
          {"timeout", required_argument, 0, 't'},
-         {"verbose", optional_argument, 0, 'v'},
          {"strict", no_argument, 0, OPT_STRICT},
          {"help", no_argument, 0, 'h'},
          {"version", no_argument, 0, 'V'},
 -        VCONN_SSL_LONG_OPTIONS
+         VLOG_LONG_OPTIONS,
 +        STREAM_SSL_LONG_OPTIONS
          {0, 0, 0, 0},
      };
      char *short_options = long_options_to_short_options(long_options);
  
 -    /* Set defaults that we can figure out before parsing options. */
 -    s->strict = false;
 -
      for (;;) {
          unsigned long int timeout;
          int c;
              OVS_PRINT_VERSION(OFP_VERSION, OFP_VERSION);
              exit(EXIT_SUCCESS);
  
-         case 'v':
-             vlog_set_verbosity(optarg);
-             break;
          case OPT_STRICT:
 -            s->strict = true;
 +            strict = true;
              break;
  
 -        VCONN_SSL_OPTION_HANDLERS
+         VLOG_OPTION_HANDLERS
 +        STREAM_SSL_OPTION_HANDLERS
  
          case '?':
              exit(EXIT_FAILURE);
@@@ -164,6 -205,7 +162,6 @@@ usage(void
             "  mod-flows SWITCH FLOW       modify actions of matching FLOWs\n"
             "  del-flows SWITCH [FLOW]     delete matching FLOWs\n"
             "  monitor SWITCH MISSLEN EXP  print packets received from SWITCH\n"
 -           "  execute SWITCH CMD [ARG...] execute CMD with ARGS on SWITCH\n"
             "\nFor OpenFlow switches and controllers:\n"
             "  probe VCONN                 probe whether VCONN is up\n"
             "  ping VCONN [N]              latency of N-byte echos\n"
@@@ -204,36 -246,25 +202,36 @@@ static void run(int retval, const char 
  \f
  /* Generic commands. */
  
 +static void
 +open_vconn_socket(const char *name, struct vconn **vconnp)
 +{
 +    char *vconn_name = xasprintf("unix:%s", name);
 +    VLOG_INFO("connecting to %s", vconn_name);
 +    run(vconn_open_block(vconn_name, OFP_VERSION, vconnp),
 +        "connecting to %s", vconn_name);
 +    free(vconn_name);
 +}
 +
  static void
  open_vconn(const char *name, struct vconn **vconnp)
  {
      struct dpif *dpif;
      struct stat s;
 +    char *bridge_path, *datapath_name, *datapath_type;
 +
 +    bridge_path = xasprintf("%s/%s.mgmt", ovs_rundir, name);
 +    dp_parse_name(name, &datapath_name, &datapath_type);
  
      if (strstr(name, ":")) {
          run(vconn_open_block(name, OFP_VERSION, vconnp),
              "connecting to %s", name);
      } else if (!stat(name, &s) && S_ISSOCK(s.st_mode)) {
 -        char *vconn_name = xasprintf("unix:%s", name);
 -        VLOG_INFO("connecting to %s", vconn_name);
 -        run(vconn_open_block(vconn_name, OFP_VERSION, vconnp),
 -            "connecting to %s", vconn_name);
 -        free(vconn_name);
 -    } else if (!dpif_open(name, &dpif)) {
 +        open_vconn_socket(name, vconnp);
 +    } else if (!stat(bridge_path, &s) && S_ISSOCK(s.st_mode)) {
 +        open_vconn_socket(bridge_path, vconnp);
 +    } else if (!dpif_open(datapath_name, datapath_type, &dpif)) {
          char dpif_name[IF_NAMESIZE + 1];
          char *socket_name;
 -        char *vconn_name;
  
          run(dpif_port_get_name(dpif, ODPP_LOCAL, dpif_name, sizeof dpif_name),
              "obtaining name of %s", dpif_name);
                        name, socket_name);
          }
  
 -        vconn_name = xasprintf("unix:%s", socket_name);
 -        VLOG_INFO("connecting to %s", vconn_name);
 -        run(vconn_open_block(vconn_name, OFP_VERSION, vconnp),
 -            "connecting to %s", vconn_name);
 +        open_vconn_socket(socket_name, vconnp);
          free(socket_name);
 -        free(vconn_name);
      } else {
          ovs_fatal(0, "%s is not a valid connection method", name);
      }
 +
 +    free(datapath_name);
 +    free(datapath_type);
 +    free(bridge_path);
  }
  
  static void *
@@@ -341,14 -372,14 +339,14 @@@ dump_trivial_stats_transaction(const ch
  }
  
  static void
 -do_show(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
 +do_show(int argc UNUSED, char *argv[])
  {
      dump_trivial_transaction(argv[1], OFPT_FEATURES_REQUEST);
      dump_trivial_transaction(argv[1], OFPT_GET_CONFIG_REQUEST);
  }
  
  static void
 -do_status(const struct settings *s UNUSED, int argc, char *argv[])
 +do_status(int argc, char *argv[])
  {
      struct nicira_header *request, *reply;
      struct vconn *vconn;
  }
  
  static void
 -do_dump_desc(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
 +do_dump_desc(int argc UNUSED, char *argv[])
  {
      dump_trivial_stats_transaction(argv[1], OFPST_DESC);
  }
  
  static void
 -do_dump_tables(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
 +do_dump_tables(int argc UNUSED, char *argv[])
  {
      dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
  }
@@@ -782,7 -813,7 +780,7 @@@ str_to_flow(char *string, struct ofp_ma
  }
  
  static void
 -do_dump_flows(const struct settings *s UNUSED, int argc, char *argv[])
 +do_dump_flows(int argc, char *argv[])
  {
      struct ofp_flow_stats_request *req;
      uint16_t out_port;
  }
  
  static void
 -do_dump_aggregate(const struct settings *s UNUSED, int argc, char *argv[])
 +do_dump_aggregate(int argc, char *argv[])
  {
      struct ofp_aggregate_stats_request *req;
      struct ofpbuf *request;
  }
  
  static void
 -do_add_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
 +do_add_flow(int argc UNUSED, char *argv[])
  {
      struct vconn *vconn;
      struct ofpbuf *buffer;
  }
  
  static void
 -do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
 +do_add_flows(int argc UNUSED, char *argv[])
  {
      struct vconn *vconn;
      FILE *file;
  }
  
  static void
 -do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[])
 +do_mod_flows(int argc UNUSED, char *argv[])
  {
      uint16_t priority, idle_timeout, hard_timeout;
      struct vconn *vconn;
                  NULL, NULL, &priority, &idle_timeout, &hard_timeout);
      ofm = buffer->data;
      ofm->match = match;
 -    if (s->strict) {
 +    if (strict) {
          ofm->command = htons(OFPFC_MODIFY_STRICT);
      } else {
          ofm->command = htons(OFPFC_MODIFY);
      vconn_close(vconn);
  }
  
 -static void do_del_flows(const struct settings *s, int argc, char *argv[])
 +static void do_del_flows(int argc, char *argv[])
  {
      struct vconn *vconn;
      uint16_t priority;
      ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
      str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, NULL, 
                  &out_port, &priority, NULL, NULL);
 -    if (s->strict) {
 +    if (strict) {
          ofm->command = htons(OFPFC_DELETE_STRICT);
      } else {
          ofm->command = htons(OFPFC_DELETE);
  }
  
  static void
 -do_monitor(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
 +do_monitor(int argc UNUSED, char *argv[])
  {
      struct vconn *vconn;
  
  }
  
  static void
 -do_dump_ports(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
 +do_dump_ports(int argc UNUSED, char *argv[])
  {
      dump_trivial_stats_transaction(argv[1], OFPST_PORT);
  }
  
  static void
 -do_probe(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
 +do_probe(int argc UNUSED, char *argv[])
  {
      struct ofpbuf *request;
      struct vconn *vconn;
  }
  
  static void
 -do_mod_port(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
 +do_mod_port(int argc UNUSED, char *argv[])
  {
      struct ofpbuf *request, *reply;
      struct ofp_switch_features *osf;
  }
  
  static void
 -do_ping(const struct settings *s UNUSED, int argc, char *argv[])
 +do_ping(int argc, char *argv[])
  {
      size_t max_payload = 65535 - sizeof(struct ofp_header);
      unsigned int payload;
  }
  
  static void
 -do_benchmark(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
 +do_benchmark(int argc UNUSED, char *argv[])
  {
      size_t max_payload = 65535 - sizeof(struct ofp_header);
      struct timeval start, end;
  }
  
  static void
 -do_execute(const struct settings *s UNUSED, int argc, char *argv[])
 -{
 -    struct vconn *vconn;
 -    struct ofpbuf *request;
 -    struct nicira_header *nicira;
 -    struct nx_command_reply *ncr;
 -    uint32_t xid;
 -    int i;
 -
 -    nicira = make_openflow(sizeof *nicira, OFPT_VENDOR, &request);
 -    xid = nicira->header.xid;
 -    nicira->vendor = htonl(NX_VENDOR_ID);
 -    nicira->subtype = htonl(NXT_COMMAND_REQUEST);
 -    ofpbuf_put(request, argv[2], strlen(argv[2]));
 -    for (i = 3; i < argc; i++) {
 -        ofpbuf_put_zeros(request, 1);
 -        ofpbuf_put(request, argv[i], strlen(argv[i]));
 -    }
 -    update_openflow_length(request);
 -
 -    open_vconn(argv[1], &vconn);
 -    run(vconn_send_block(vconn, request), "send");
 -
 -    for (;;) {
 -        struct ofpbuf *reply;
 -        uint32_t status;
 -
 -        run(vconn_recv_xid(vconn, xid, &reply), "recv_xid");
 -        if (reply->size < sizeof *ncr) {
 -            ovs_fatal(0, "reply is too short (%zu bytes < %zu bytes)",
 -                      reply->size, sizeof *ncr);
 -        }
 -        ncr = reply->data;
 -        if (ncr->nxh.header.type != OFPT_VENDOR
 -            || ncr->nxh.vendor != htonl(NX_VENDOR_ID)
 -            || ncr->nxh.subtype != htonl(NXT_COMMAND_REPLY)) {
 -            ovs_fatal(0, "reply is invalid");
 -        }
 -
 -        status = ntohl(ncr->status);
 -        if (status & NXT_STATUS_STARTED) {
 -            /* Wait for a second reply. */
 -            continue;
 -        } else if (status & NXT_STATUS_EXITED) {
 -            fprintf(stderr, "process terminated normally with exit code %d",
 -                    status & NXT_STATUS_EXITSTATUS);
 -        } else if (status & NXT_STATUS_SIGNALED) {
 -            fprintf(stderr, "process terminated by signal %d",
 -                    status & NXT_STATUS_TERMSIG);
 -        } else if (status & NXT_STATUS_ERROR) {
 -            fprintf(stderr, "error executing command");
 -        } else {
 -            fprintf(stderr, "process terminated for unknown reason");
 -        }
 -        if (status & NXT_STATUS_COREDUMP) {
 -            fprintf(stderr, " (core dumped)");
 -        }
 -        putc('\n', stderr);
 -
 -        fwrite(ncr + 1, reply->size - sizeof *ncr, 1, stdout);
 -        break;
 -    }
 -}
 -
 -static void
 -do_help(const struct settings *s UNUSED, int argc UNUSED, char *argv[] UNUSED)
 +do_help(int argc UNUSED, char *argv[] UNUSED)
  {
      usage();
  }
  
 -static struct command all_commands[] = {
 +static const struct command all_commands[] = {
      { "show", 1, 1, do_show },
      { "status", 1, 2, do_status },
      { "monitor", 1, 3, do_monitor },
      { "probe", 1, 1, do_probe },
      { "ping", 1, 2, do_ping },
      { "benchmark", 3, 3, do_benchmark },
 -    { "execute", 2, INT_MAX, do_execute },
      { "help", 0, INT_MAX, do_help },
      { NULL, 0, 0, NULL },
  };
diff --combined vswitchd/automake.mk
@@@ -1,46 -1,39 +1,47 @@@
  sbin_PROGRAMS += vswitchd/ovs-vswitchd vswitchd/ovs-brcompatd
  man_MANS += \
 -      vswitchd/ovs-vswitchd.conf.5 \
        vswitchd/ovs-vswitchd.8 \
        vswitchd/ovs-brcompatd.8
  DISTCLEANFILES += \
 -      vswitchd/ovs-vswitchd.conf.5 \
        vswitchd/ovs-vswitchd.8 \
        vswitchd/ovs-brcompatd.8
  
  vswitchd_ovs_vswitchd_SOURCES = \
        vswitchd/bridge.c \
        vswitchd/bridge.h \
 -      vswitchd/mgmt.c \
 -      vswitchd/mgmt.h \
        vswitchd/proc-net-compat.c \
        vswitchd/proc-net-compat.h \
        vswitchd/ovs-vswitchd.c \
 -      vswitchd/ovs-vswitchd.h \
 +      vswitchd/vswitch-idl.c \
 +      vswitchd/vswitch-idl.h \
        vswitchd/xenserver.c \
        vswitchd/xenserver.h
  vswitchd_ovs_vswitchd_LDADD = \
        ofproto/libofproto.a \
+       lib/libsflow.a \
        lib/libopenvswitch.a \
 -      $(FAULT_LIBS) \
        $(SSL_LIBS)
  
  vswitchd_ovs_brcompatd_SOURCES = \
 -      vswitchd/ovs-brcompatd.c
 +      vswitchd/ovs-brcompatd.c \
 +      vswitchd/vswitch-idl.c \
 +      vswitchd/vswitch-idl.h
  
 -vswitchd_ovs_brcompatd_LDADD = \
 -      lib/libopenvswitch.a \
 -      $(FAULT_LIBS) 
 +vswitchd_ovs_brcompatd_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
  
  EXTRA_DIST += \
 -      vswitchd/ovs-vswitchd.conf.5.in \
        vswitchd/ovs-vswitchd.8.in \
        vswitchd/ovs-brcompatd.8.in
 +
 +
 +# vswitch schema and IDL
 +OVSIDL_BUILT += \
 +      vswitchd/vswitch-idl.c \
 +      vswitchd/vswitch-idl.h \
 +      vswitchd/vswitch-idl.ovsidl
 +VSWITCH_IDL_FILES = vswitchd/vswitch.ovsschema vswitchd/vswitch-idl.ann
 +noinst_DATA += vswitchd/vswitch-idl.txt
 +EXTRA_DIST += $(VSWITCH_IDL_FILES) vswitchd/vswitch-idl.txt
 +vswitchd/vswitch-idl.ovsidl: $(VSWITCH_IDL_FILES)
 +      $(OVSDB_IDLC) -C $(srcdir) annotate $(VSWITCH_IDL_FILES) > $@.tmp
 +      mv $@.tmp $@
diff --combined vswitchd/bridge.c
@@@ -1,4 -1,4 +1,4 @@@
 -/* Copyright (c) 2008, 2009 Nicira Networks
 +/* Copyright (c) 2008, 2009, 2010 Nicira Networks
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
@@@ -30,6 -30,7 +30,6 @@@
  #include <sys/types.h>
  #include <unistd.h>
  #include "bitmap.h"
 -#include "cfg.h"
  #include "coverage.h"
  #include "dirs.h"
  #include "dpif.h"
  #include "port-array.h"
  #include "proc-net-compat.h"
  #include "process.h"
 +#include "sha1.h"
  #include "shash.h"
  #include "socket-util.h"
 -#include "stp.h"
 +#include "stream-ssl.h"
  #include "svec.h"
  #include "timeval.h"
  #include "util.h"
  #include "unixctl.h"
  #include "vconn.h"
 -#include "vconn-ssl.h"
 +#include "vswitchd/vswitch-idl.h"
  #include "xenserver.h"
  #include "xtoxll.h"
+ #include "sflow_api.h"
  
  #define THIS_MODULE VLM_bridge
  #include "vlog.h"
@@@ -70,6 -71,8 +71,6 @@@ struct dst 
      uint16_t dp_ifidx;
  };
  
 -extern uint64_t mgmt_id;
 -
  struct iface {
      /* These members are always valid. */
      struct port *port;          /* Containing port. */
@@@ -83,9 -86,6 +84,9 @@@
      int dp_ifidx;               /* Index within kernel datapath. */
      struct netdev *netdev;      /* Network device. */
      bool enabled;               /* May be chosen for flows? */
 +
 +    /* This member is only valid *during* bridge_reconfigure(). */
 +    const struct ovsrec_interface *cfg;
  };
  
  #define BOND_MASK 0xff
@@@ -105,8 -105,8 +106,8 @@@ struct mirror 
      char *name;
  
      /* Selection criteria. */
 -    struct svec src_ports;
 -    struct svec dst_ports;
 +    struct shash src_ports;     /* Name is port name; data is always NULL. */
 +    struct shash dst_ports;     /* Name is port name; data is always NULL. */
      int *vlans;
      size_t n_vlans;
  
@@@ -135,15 -135,15 +136,15 @@@ struct port 
      tag_type no_ifaces_tag;     /* Tag for flows when all ifaces disabled. */
      int updelay, downdelay;     /* Delay before iface goes up/down, in ms. */
      bool bond_compat_is_stale;  /* Need to call port_update_bond_compat()? */
 +    bool bond_fake_iface;       /* Fake a bond interface for legacy compat? */
  
      /* Port mirroring info. */
      mirror_mask_t src_mirrors;  /* Mirrors triggered when packet received. */
      mirror_mask_t dst_mirrors;  /* Mirrors triggered when packet sent. */
      bool is_mirror_output_port; /* Does port mirroring send frames here? */
  
 -    /* Spanning tree info. */
 -    enum stp_state stp_state;   /* Always STP_FORWARDING if STP not in use. */
 -    tag_type stp_state_tag;     /* Tag for STP state change. */
 +    /* This member is only valid *during* bridge_reconfigure(). */
 +    const struct ovsrec_port *cfg;
  };
  
  #define DP_MAX_PORTS 255
@@@ -183,8 -183,9 +184,8 @@@ struct bridge 
      /* Port mirroring. */
      struct mirror *mirrors[MAX_MIRRORS];
  
 -    /* Spanning tree. */
 -    struct stp *stp;
 -    long long int stp_last_tick;
 +    /* This member is only valid *during* bridge_reconfigure(). */
 +    const struct ovsrec_bridge *cfg;
  };
  
  /* List of all bridges. */
@@@ -193,16 -194,14 +194,16 @@@ static struct list all_bridges = LIST_I
  /* Maximum number of datapaths. */
  enum { DP_MAX = 256 };
  
 -static struct bridge *bridge_create(const char *name);
 +static struct bridge *bridge_create(const struct ovsrec_bridge *br_cfg);
  static void bridge_destroy(struct bridge *);
  static struct bridge *bridge_lookup(const char *name);
 -static void bridge_unixctl_dump_flows(struct unixctl_conn *, const char *);
 +static unixctl_cb_func bridge_unixctl_dump_flows;
  static int bridge_run_one(struct bridge *);
 -static void bridge_reconfigure_one(struct bridge *);
 -static void bridge_reconfigure_controller(struct bridge *);
 -static void bridge_get_all_ifaces(const struct bridge *, struct svec *ifaces);
 +static void bridge_reconfigure_one(const struct ovsrec_open_vswitch *,
 +                                   struct bridge *);
 +static void bridge_reconfigure_controller(const struct ovsrec_open_vswitch *,
 +                                          struct bridge *);
 +static void bridge_get_all_ifaces(const struct bridge *, struct shash *ifaces);
  static void bridge_fetch_dp_ifaces(struct bridge *);
  static void bridge_flush(struct bridge *);
  static void bridge_pick_local_hw_addr(struct bridge *,
@@@ -212,9 -211,10 +213,9 @@@ static uint64_t bridge_pick_datapath_id
                                          const uint8_t bridge_ea[ETH_ADDR_LEN],
                                          struct iface *hw_addr_iface);
  static struct iface *bridge_get_local_iface(struct bridge *);
 -static const char *bridge_get_controller(const struct bridge *br);
  static uint64_t dpid_from_hash(const void *, size_t nbytes);
  
 -static void bridge_unixctl_fdb_show(struct unixctl_conn *, const char *args);
 +static unixctl_cb_func bridge_unixctl_fdb_show;
  
  static void bond_init(void);
  static void bond_run(struct bridge *);
@@@ -223,8 -223,8 +224,8 @@@ static void bond_rebalance_port(struct 
  static void bond_send_learning_packets(struct port *);
  static void bond_enable_slave(struct iface *iface, bool enable);
  
 -static void port_create(struct bridge *, const char *name);
 -static void port_reconfigure(struct port *);
 +static struct port *port_create(struct bridge *, const char *name);
 +static void port_reconfigure(struct port *, const struct ovsrec_port *);
  static void port_destroy(struct port *);
  static struct port *port_lookup(const struct bridge *, const char *name);
  static struct iface *port_lookup_iface(const struct port *, const char *name);
@@@ -234,14 -234,18 +235,14 @@@ static void port_update_bond_compat(str
  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 struct mirror *mirror_create(struct bridge *, const char *name);
  static void mirror_destroy(struct mirror *);
  static void mirror_reconfigure(struct bridge *);
 -static void mirror_reconfigure_one(struct mirror *);
 +static void mirror_reconfigure_one(struct mirror *, struct ovsrec_mirror *);
  static bool vlan_is_mirrored(const struct mirror *, int vlan);
  
 -static void brstp_reconfigure(struct bridge *);
 -static void brstp_adjust_timers(struct bridge *);
 -static void brstp_run(struct bridge *);
 -static void brstp_wait(struct bridge *);
 -
 -static void iface_create(struct port *, const char *name);
 +static struct iface *iface_create(struct port *port, 
 +                                  const struct ovsrec_interface *if_cfg);
  static void iface_destroy(struct iface *);
  static struct iface *iface_lookup(const struct bridge *, const char *name);
  static struct iface *iface_from_dp_ifidx(const struct bridge *,
@@@ -281,65 -285,53 +282,65 @@@ bridge_get_ifaces(struct svec *svec
      }
  }
  
 -/* The caller must already have called cfg_read(). */
  void
 -bridge_init(void)
 +bridge_init(const struct ovsrec_open_vswitch *cfg)
  {
 -    struct svec dpif_names;
 +    struct svec bridge_names;
 +    struct svec dpif_names, dpif_types;
      size_t i;
  
 -    unixctl_command_register("fdb/show", bridge_unixctl_fdb_show);
 +    unixctl_command_register("fdb/show", bridge_unixctl_fdb_show, NULL);
 +
 +    svec_init(&bridge_names);
 +    for (i = 0; i < cfg->n_bridges; i++) {
 +        svec_add(&bridge_names, cfg->bridges[i]->name);
 +    }
 +    svec_sort(&bridge_names);
  
      svec_init(&dpif_names);
 -    dp_enumerate(&dpif_names);
 -    for (i = 0; i < dpif_names.n; i++) {
 -        const char *dpif_name = dpif_names.names[i];
 +    svec_init(&dpif_types);
 +    dp_enumerate_types(&dpif_types);
 +    for (i = 0; i < dpif_types.n; i++) {
          struct dpif *dpif;
          int retval;
 +        size_t j;
  
 -        retval = dpif_open(dpif_name, &dpif);
 -        if (!retval) {
 -            struct svec all_names;
 -            size_t j;
 +        dp_enumerate_names(dpif_types.names[i], &dpif_names);
  
 -            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;
 +        for (j = 0; j < dpif_names.n; j++) {
 +            retval = dpif_open(dpif_names.names[j], dpif_types.names[i], &dpif);
 +            if (!retval) {
 +                struct svec all_names;
 +                size_t k;
 +
 +                svec_init(&all_names);
 +                dpif_get_all_names(dpif, &all_names);
 +                for (k = 0; k < all_names.n; k++) {
 +                    if (svec_contains(&bridge_names, all_names.names[k])) {
 +                        goto found;
 +                    }
                  }
 +                dpif_delete(dpif);
 +            found:
 +                svec_destroy(&all_names);
 +                dpif_close(dpif);
              }
 -            dpif_delete(dpif);
 -        found:
 -            svec_destroy(&all_names);
 -            dpif_close(dpif);
          }
      }
      svec_destroy(&dpif_names);
 +    svec_destroy(&dpif_types);
  
 -    unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows);
 +    unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows,
 +                             NULL);
  
      bond_init();
 -    bridge_reconfigure();
 +    bridge_reconfigure(cfg);
  }
  
  #ifdef HAVE_OPENSSL
  static bool
 -config_string_change(const char *key, char **valuep)
 +config_string_change(const char *value, char **valuep)
  {
 -    const char *value = cfg_get_string(0, "%s", key);
      if (value && (!*valuep || strcmp(value, *valuep))) {
          free(*valuep);
          *valuep = xstrdup(value);
  }
  
  static void
 -bridge_configure_ssl(void)
 +bridge_configure_ssl(const struct ovsrec_ssl *ssl)
  {
      /* XXX SSL should be configurable on a per-bridge basis.
       * XXX should be possible to de-configure SSL. */
      static char *cacert_file;
      struct stat s;
  
 -    if (config_string_change("ssl.private-key", &private_key_file)) {
 -        vconn_ssl_set_private_key_file(private_key_file);
 +    if (!ssl) {
 +        /* XXX We can't un-set SSL settings. */
 +        return;
 +    }
 +
 +    if (config_string_change(ssl->private_key, &private_key_file)) {
 +        stream_ssl_set_private_key_file(private_key_file);
      }
  
 -    if (config_string_change("ssl.certificate", &certificate_file)) {
 -        vconn_ssl_set_certificate_file(certificate_file);
 +    if (config_string_change(ssl->certificate, &certificate_file)) {
 +        stream_ssl_set_certificate_file(certificate_file);
      }
  
      /* We assume that even if the filename hasn't changed, if the CA cert 
       * boot-strapping mode.  This opens a small security hole, because
       * 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)
 +    if (config_string_change(ssl->ca_cert, &cacert_file)
          || (cacert_file && stat(cacert_file, &s) && errno == ENOENT)) {
 -        vconn_ssl_set_ca_cert_file(cacert_file,
 -                                   cfg_get_bool(0, "ssl.bootstrap-ca-cert"));
 +        stream_ssl_set_ca_cert_file(cacert_file, ssl->bootstrap_ca_cert);
      }
  }
  #endif
  /* Attempt to create the network device 'iface_name' through the netdev
   * library. */
  static int
 -set_up_iface(const char *iface_name, bool create) 
 +set_up_iface(const struct ovsrec_interface *iface_cfg, struct iface *iface,
 +             bool create)
  {
 -    const char *type;
 -    const char *arg;
 -    struct svec arg_svec;
 -    struct shash args;
 -    int error;
 +    struct shash_node *node;
 +    struct shash options;
 +    int error = 0;
      size_t i;
  
 -    /* If a type is not explicitly declared, then assume it's an existing
 -     * "system" device. */
 -    type = cfg_get_string(0, "iface.%s.type", iface_name);
 -    if (!type || !strcmp(type, "system")) {
 -        return 0;
 +    shash_init(&options);
 +    for (i = 0; i < iface_cfg->n_options; i++) {
 +        shash_add(&options, iface_cfg->key_options[i],
 +                  xstrdup(iface_cfg->value_options[i]));
      }
  
 -    svec_init(&arg_svec);
 -    cfg_get_subsections(&arg_svec, "iface.%s.args", iface_name);
 +    if (create) {
 +        struct netdev_options netdev_options;
 +
 +        memset(&netdev_options, 0, sizeof netdev_options);
 +        netdev_options.name = iface_cfg->name;
 +        netdev_options.type = iface_cfg->type;
 +        netdev_options.args = &options;
 +        netdev_options.ethertype = NETDEV_ETH_TYPE_NONE;
 +        netdev_options.may_create = true;
 +        if (iface_is_internal(iface->port->bridge, iface_cfg->name)) {
 +            netdev_options.may_open = true;
 +        }
  
 -    shash_init(&args);
 -    SVEC_FOR_EACH (i, arg, &arg_svec) {
 -        const char *value;
 +        error = netdev_open(&netdev_options, &iface->netdev);
  
 -        value = cfg_get_string(0, "iface.%s.args.%s", iface_name, arg);
 -        if (value) {
 -            shash_add(&args, arg, xstrdup(value));
 +        if (iface->netdev) {
 +            netdev_get_carrier(iface->netdev, &iface->enabled);
          }
 -    }
 +    } else if (iface->netdev) {
 +        const char *netdev_type = netdev_get_type(iface->netdev);
 +        const char *iface_type = iface_cfg->type && strlen(iface_cfg->type)
 +                                  ? iface_cfg->type : NULL;
  
 -    if (create) {
 -        error = netdev_create(iface_name, type, &args);
 -    } else {
 -        /* xxx Check to make sure that the type hasn't changed. */
 -        error = netdev_reconfigure(iface_name, &args);
 +        if (!iface_type || !strcmp(netdev_type, iface_type)) {
 +            error = netdev_reconfigure(iface->netdev, &options);
 +        } else {
 +            VLOG_WARN("%s: attempting change device type from %s to %s",
 +                      iface_cfg->name, netdev_type, iface_type);
 +            error = EINVAL;
 +        }
      }
  
 -    svec_destroy(&arg_svec);
 -    shash_destroy(&args);
 +    SHASH_FOR_EACH (node, &options) {
 +        free(node->data);
 +    }
 +    shash_destroy(&options);
  
      return error;
  }
  
  static int
 -create_iface(const char *iface_name)
 -{
 -    return set_up_iface(iface_name, true);
 -}
 -
 -static int
 -reconfigure_iface(const char *iface_name)
 +reconfigure_iface(const struct ovsrec_interface *iface_cfg, struct iface *iface)
  {
 -    return set_up_iface(iface_name, false);
 +    return set_up_iface(iface_cfg, iface, false);
  }
  
 -static void
 -destroy_iface(const char *iface_name)
 -{
 -    netdev_destroy(iface_name);
 -}
 -
 -
 -/* 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)
 +check_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;
 +    if (!iface->netdev) {
 +        int error = set_up_iface(iface->cfg, iface, true);
 +        if (error) {
 +            VLOG_WARN("could not open netdev on %s, dropping: %s", iface->name,
 +                                                               strerror(error));
 +            return false;
 +        }
      }
 +
 +    return true;
  }
  
  static bool
@@@ -482,10 -475,12 +483,10 @@@ static boo
  set_iface_properties(struct bridge *br UNUSED, struct iface *iface,
                     void *aux UNUSED)
  {
 -    int rate, burst;
 -
      /* Set policing attributes. */
 -    rate = cfg_get_int(0, "port.%s.ingress.policing-rate", iface->name);
 -    burst = cfg_get_int(0, "port.%s.ingress.policing-burst", iface->name);
 -    netdev_set_policing(iface->netdev, rate, burst);
 +    netdev_set_policing(iface->netdev,
 +                        iface->cfg->ingress_policing_rate,
 +                        iface->cfg->ingress_policing_burst);
  
      /* Set MAC address of internal interfaces other than the local
       * interface. */
@@@ -529,66 -524,50 +530,67 @@@ iterate_and_prune_ifaces(struct bridge 
  }
  
  void
 -bridge_reconfigure(void)
 +bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
  {
 -    struct svec old_br, new_br;
 +    struct ovsdb_idl_txn *txn;
 +    struct shash old_br, new_br;
 +    struct shash_node *node;
      struct bridge *br, *next;
      size_t i;
+     int sflow_bridge_number;
  
      COVERAGE_INC(bridge_reconfigure);
  
 +    txn = ovsdb_idl_txn_create(ovs_cfg->header_.table->idl);
 +
      /* Collect old and new bridges. */
 -    svec_init(&old_br);
 -    svec_init(&new_br);
 +    shash_init(&old_br);
 +    shash_init(&new_br);
      LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
 -        svec_add(&old_br, br->name);
 +        shash_add(&old_br, br->name, br);
 +    }
 +    for (i = 0; i < ovs_cfg->n_bridges; i++) {
 +        const struct ovsrec_bridge *br_cfg = ovs_cfg->bridges[i];
 +        if (!shash_add_once(&new_br, br_cfg->name, br_cfg)) {
 +            VLOG_WARN("more than one bridge named %s", br_cfg->name);
 +        }
      }
 -    cfg_get_subsections(&new_br, "bridge");
  
      /* Get rid of deleted bridges and add new bridges. */
 -    svec_sort(&old_br);
 -    svec_sort(&new_br);
 -    assert(svec_is_unique(&old_br));
 -    assert(svec_is_unique(&new_br));
      LIST_FOR_EACH_SAFE (br, next, struct bridge, node, &all_bridges) {
 -        if (!svec_contains(&new_br, br->name)) {
 +        struct ovsrec_bridge *br_cfg = shash_find_data(&new_br, br->name);
 +        if (br_cfg) {
 +            br->cfg = br_cfg;
 +        } else {
              bridge_destroy(br);
          }
      }
 -    for (i = 0; i < new_br.n; i++) {
 -        const char *name = new_br.names[i];
 -        if (!svec_contains(&old_br, name)) {
 -            bridge_create(name);
 +    SHASH_FOR_EACH (node, &new_br) {
 +        const char *br_name = node->name;
 +        const struct ovsrec_bridge *br_cfg = node->data;
 +        br = shash_find_data(&old_br, br_name);
 +        if (br) {
 +            /* If the bridge datapath type has changed, we need to tear it
 +             * down and recreate. */
 +            if (strcmp(br->cfg->datapath_type, br_cfg->datapath_type)) {
 +                bridge_destroy(br);
 +                bridge_create(br_cfg);
 +            }
 +        } else {
 +            bridge_create(br_cfg);
          }
      }
 -    svec_destroy(&old_br);
 -    svec_destroy(&new_br);
 +    shash_destroy(&old_br);
 +    shash_destroy(&new_br);
  
  #ifdef HAVE_OPENSSL
      /* Configure SSL. */
 -    bridge_configure_ssl();
 +    bridge_configure_ssl(ovs_cfg->ssl);
  #endif
  
      /* Reconfigure all bridges. */
      LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
 -        bridge_reconfigure_one(br);
 +        bridge_reconfigure_one(ovs_cfg, br);
      }
  
      /* Add and delete ports on all datapaths.
      LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
          struct odp_port *dpif_ports;
          size_t n_dpif_ports;
 -        struct svec want_ifaces;
 +        struct shash want_ifaces;
  
          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)
 +            if (!shash_find(&want_ifaces, p->devname)
                  && strcmp(p->devname, br->name)) {
                  int retval = dpif_port_del(br->dpif, p->port);
                  if (retval) {
                               p->devname, dpif_name(br->dpif),
                               strerror(retval));
                  }
 -                destroy_iface(p->devname);
              }
          }
 -        svec_destroy(&want_ifaces);
 +        shash_destroy(&want_ifaces);
          free(dpif_ports);
      }
      LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
          struct odp_port *dpif_ports;
          size_t n_dpif_ports;
 -        struct svec cur_ifaces, want_ifaces, add_ifaces;
 +        struct shash cur_ifaces, want_ifaces;
 +        struct shash_node *node;
  
 +        /* Get the set of interfaces currently in this datapath. */
          dpif_port_list(br->dpif, &dpif_ports, &n_dpif_ports);
 -        svec_init(&cur_ifaces);
 +        shash_init(&cur_ifaces);
          for (i = 0; i < n_dpif_ports; i++) {
 -            svec_add(&cur_ifaces, dpif_ports[i].devname);
 +            const char *name = dpif_ports[i].devname;
 +            if (!shash_find(&cur_ifaces, name)) {
 +                shash_add(&cur_ifaces, name, NULL);
 +            }
          }
          free(dpif_ports);
 -        svec_sort_unique(&cur_ifaces);
 -        bridge_get_all_ifaces(br, &want_ifaces);
 -        svec_diff(&want_ifaces, &cur_ifaces, &add_ifaces, NULL, NULL);
 -
 -        for (i = 0; i < cur_ifaces.n; i++) {
 -            const char *if_name = cur_ifaces.names[i];
 -            reconfigure_iface(if_name);
 -        }
  
 -        for (i = 0; i < add_ifaces.n; i++) {
 -            const char *if_name = add_ifaces.names[i];
 -            bool internal;
 -            int error;
 +        /* Get the set of interfaces we want on this datapath. */
 +        bridge_get_all_ifaces(br, &want_ifaces);
  
 -            /* Attempt to create the network interface in case it
 -             * doesn't exist yet. */
 -            error = create_iface(if_name);
 -            if (error) {
 -                VLOG_WARN("could not create iface %s: %s\n", if_name,
 -                        strerror(error));
 -                continue;
 -            }
 +        SHASH_FOR_EACH (node, &want_ifaces) {
 +            const char *if_name = node->name;
 +            struct iface *iface = node->data;
  
 -            /* Add to datapath. */
 -            internal = iface_is_internal(br, if_name);
 -            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));
 +            if (shash_find(&cur_ifaces, if_name)) {
 +                /* Already exists, just reconfigure it. */
 +                if (iface) {
 +                    reconfigure_iface(iface->cfg, iface);
 +                }
 +            } else {
 +                /* Need to add to datapath. */
 +                bool internal;
 +                int error;
 +
 +                /* Add to datapath. */
 +                internal = iface_is_internal(br, if_name);
 +                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));
 +                }
              }
          }
 -        svec_destroy(&cur_ifaces);
 -        svec_destroy(&want_ifaces);
 -        svec_destroy(&add_ifaces);
 +        shash_destroy(&cur_ifaces);
 +        shash_destroy(&want_ifaces);
      }
+     sflow_bridge_number = 0;
      LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
          uint8_t ea[8];
          uint64_t dpid;
          struct iface *local_iface;
          struct iface *hw_addr_iface;
 -        struct netflow_options nf_options;
 +        char *dpid_string;
  
          bridge_fetch_dp_ifaces(br);
 -        iterate_and_prune_ifaces(br, init_iface_netdev, NULL);
  
 +        iterate_and_prune_ifaces(br, check_iface_netdev, NULL);
          iterate_and_prune_ifaces(br, check_iface_dp_ifidx, NULL);
  
          /* Pick local port hardware address, datapath ID. */
          dpid = bridge_pick_datapath_id(br, ea, hw_addr_iface);
          ofproto_set_datapath_id(br->ofproto, dpid);
  
 +        dpid_string = xasprintf("%012"PRIx64, dpid);
 +        ovsrec_bridge_set_datapath_id(br->cfg, dpid_string);
 +        free(dpid_string);
 +
          /* Set NetFlow configuration on this bridge. */
 -        memset(&nf_options, 0, sizeof nf_options);
 -        dpif_get_netflow_ids(br->dpif, &nf_options.engine_type,
 -                             &nf_options.engine_id);
 -        nf_options.active_timeout = -1;
 -
 -        if (cfg_has("netflow.%s.engine-type", br->name)) {
 -            nf_options.engine_type = cfg_get_int(0, "netflow.%s.engine-type", 
 -                    br->name);
 -        }
 -        if (cfg_has("netflow.%s.engine-id", br->name)) {
 -            nf_options.engine_id = cfg_get_int(0, "netflow.%s.engine-id",
 -                                               br->name);
 -        }
 -        if (cfg_has("netflow.%s.active-timeout", br->name)) {
 -            nf_options.active_timeout = cfg_get_int(0,
 -                                                    "netflow.%s.active-timeout",
 -                                                    br->name);
 -        }
 -        if (cfg_has("netflow.%s.add-id-to-iface", br->name)) {
 -            nf_options.add_id_to_iface = cfg_get_bool(0,
 -                                                   "netflow.%s.add-id-to-iface",
 -                                                    br->name);
 -        }
 -        if (nf_options.add_id_to_iface && nf_options.engine_id > 0x7f) {
 -            VLOG_WARN("bridge %s: netflow port mangling may conflict with "
 -                    "another vswitch, choose an engine id less than 128", 
 -                    br->name);
 -        }
 -        if (nf_options.add_id_to_iface && br->n_ports > 508) {
 -            VLOG_WARN("bridge %s: netflow port mangling will conflict with "
 -                    "another port when more than 508 ports are used", 
 -                    br->name);
 -        }
 -        svec_init(&nf_options.collectors);
 -        cfg_get_all_keys(&nf_options.collectors, "netflow.%s.host", br->name);
 -        if (ofproto_set_netflow(br->ofproto, &nf_options)) {
 -            VLOG_ERR("bridge %s: problem setting netflow collectors", 
 -                    br->name);
 -        }
 -        svec_destroy(&nf_options.collectors);
 -
 -        if (cfg_has("sflow.%s.host", br->name)) {
 +        if (br->cfg->netflow) {
 +            struct ovsrec_netflow *nf_cfg = br->cfg->netflow;
 +            struct netflow_options opts;
 +
 +            memset(&opts, 0, sizeof opts);
 +
 +            dpif_get_netflow_ids(br->dpif, &opts.engine_type, &opts.engine_id);
 +            if (nf_cfg->engine_type) {
 +                opts.engine_type = *nf_cfg->engine_type;
 +            }
 +            if (nf_cfg->engine_id) {
 +                opts.engine_id = *nf_cfg->engine_id;
 +            }
 +
 +            opts.active_timeout = nf_cfg->active_timeout;
 +            if (!opts.active_timeout) {
 +                opts.active_timeout = -1;
 +            } else if (opts.active_timeout < 0) {
 +                VLOG_WARN("bridge %s: active timeout interval set to negative "
 +                          "value, using default instead (%d seconds)", br->name,
 +                          NF_ACTIVE_TIMEOUT_DEFAULT);
 +                opts.active_timeout = -1;
 +            }
 +
 +            opts.add_id_to_iface = nf_cfg->add_id_to_interface;
 +            if (opts.add_id_to_iface) {
 +                if (opts.engine_id > 0x7f) {
 +                    VLOG_WARN("bridge %s: netflow port mangling may conflict "
 +                              "with another vswitch, choose an engine id less "
 +                              "than 128", br->name);
 +                }
 +                if (br->n_ports > 508) {
 +                    VLOG_WARN("bridge %s: netflow port mangling will conflict "
 +                              "with another port when more than 508 ports are "
 +                              "used", br->name);
 +                }
 +            }
 +
 +            opts.collectors.n = nf_cfg->n_targets;
 +            opts.collectors.names = nf_cfg->targets;
 +            if (ofproto_set_netflow(br->ofproto, &opts)) {
 +                VLOG_ERR("bridge %s: problem setting netflow collectors", 
 +                         br->name);
 +            }
 +        } else {
 +            ofproto_set_netflow(br->ofproto, NULL);
 +        }
 +
++        /* Set sFlow configuration on this bridge. */
++        if (br->cfg->sflow) {
++            struct ovsrec_sflow *sflow_cfg = br->cfg->sflow;
+             struct ofproto_sflow_options oso;
 -            svec_init(&oso.targets);
 -            cfg_get_all_keys(&oso.targets, "sflow.%s.host", br->name);
++            memset(&oso, 0, sizeof oso);
++
++            oso.targets.n = sflow_cfg->n_targets;
++            oso.targets.names = sflow_cfg->targets;
+             oso.sampling_rate = SFL_DEFAULT_SAMPLING_RATE;
 -            if (cfg_has("sflow.%s.sampling", br->name)) {
 -                oso.sampling_rate = cfg_get_int(0, "sflow.%s.sampling",
 -                                                br->name);
++            if (sflow_cfg->sampling) {
++                oso.sampling_rate = *sflow_cfg->sampling;
+             }
+             oso.polling_interval = SFL_DEFAULT_POLLING_INTERVAL;
 -            if (cfg_has("sflow.%s.polling", br->name)) {
 -                oso.polling_interval = cfg_get_int(0, "sflow.%s.polling",
 -                                                   br->name);
++            if (sflow_cfg->polling) {
++                oso.polling_interval = *sflow_cfg->polling;
+             }
+             oso.header_len = SFL_DEFAULT_HEADER_SIZE;
 -            if (cfg_has("sflow.%s.header", br->name)) {
 -                oso.header_len = cfg_get_int(0, "sflow.%s.header", br->name);
++            if (sflow_cfg->header) {
++                oso.header_len = *sflow_cfg->header;
+             }
+             oso.sub_id = sflow_bridge_number++;
 -            oso.agent_device = (char *) cfg_get_string(0, "sflow.%s.agent",
 -                                                       br->name);
 -            oso.control_ip = (char *) cfg_get_string(0,
 -                                                     "bridge.%s.controller.ip",
 -                                                     br->name);
++            oso.agent_device = sflow_cfg->agent;
++
++#if 0       /* xxx foo */
++            ctrl = bridge_get_controller(ovs_cfg, br);
++            oso.control_ip = ctrl ? ctrl->local_ip : NULL;
++#endif
+             ofproto_set_sflow(br->ofproto, &oso);
+             svec_destroy(&oso.targets);
+         } else {
+             ofproto_set_sflow(br->ofproto, NULL);
+         }
          /* Update the controller and related settings.  It would be more
           * straightforward to call this from bridge_reconfigure_one(), but we
           * can't do it there for two reasons.  First, and most importantly, at
           * yet; when a controller is configured, resetting the datapath ID will
           * immediately disconnect from the controller, so it's better to set
           * the datapath ID before the controller. */
 -        bridge_reconfigure_controller(br);
 +        bridge_reconfigure_controller(ovs_cfg, br);
      }
      LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
          for (i = 0; i < br->n_ports; i++) {
          }
      }
      LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
 -        brstp_reconfigure(br);
          iterate_and_prune_ifaces(br, set_iface_properties, NULL);
      }
 +
 +    ovsrec_open_vswitch_set_cur_cfg(ovs_cfg, ovs_cfg->next_cfg);
 +
 +    ovsdb_idl_txn_commit(txn);
 +    ovsdb_idl_txn_destroy(txn); /* XXX */
 +}
 +
 +static const char *
 +bridge_get_other_config(const struct ovsrec_bridge *br_cfg, const char *key)
 +{
 +    size_t i;
 +
 +    for (i = 0; i < br_cfg->n_other_config; i++) {
 +        if (!strcmp(br_cfg->key_other_config[i], key)) {
 +            return br_cfg->value_other_config[i];
 +        }
 +    }
 +    return NULL;
  }
  
  static void
  bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
                            struct iface **hw_addr_iface)
  {
 -    uint64_t requested_ea;
 +    const char *hwaddr;
      size_t i, j;
      int error;
  
      *hw_addr_iface = NULL;
  
      /* Did the user request a particular MAC? */
 -    requested_ea = cfg_get_mac(0, "bridge.%s.mac", br->name);
 -    if (requested_ea) {
 -        eth_addr_from_uint64(requested_ea, ea);
 +    hwaddr = bridge_get_other_config(br->cfg, "hwaddr");
 +    if (hwaddr && eth_addr_from_string(hwaddr, ea)) {
          if (eth_addr_is_multicast(ea)) {
              VLOG_ERR("bridge %s: cannot set MAC address to multicast "
                       "address "ETH_ADDR_FMT, br->name, ETH_ADDR_ARGS(ea));
          }
      }
  
 -    /* Otherwise choose the minimum MAC address among all of the interfaces.
 -     * (Xen uses FE:FF:FF:FF:FF:FF for virtual interfaces so this will get the
 -     * MAC of the physical interface in such an environment.) */
 +    /* Otherwise choose the minimum non-local MAC address among all of the
 +     * interfaces. */
      memset(ea, 0xff, sizeof ea);
      for (i = 0; i < br->n_ports; i++) {
          struct port *port = br->ports[i];
          uint8_t iface_ea[ETH_ADDR_LEN];
 -        uint64_t iface_ea_u64;
          struct iface *iface;
  
          /* Mirror output ports don't participate. */
          }
  
          /* Choose the MAC address to represent the port. */
 -        iface_ea_u64 = cfg_get_mac(0, "port.%s.mac", port->name);
 -        if (iface_ea_u64) {
 -            /* User specified explicitly. */
 -            eth_addr_from_uint64(iface_ea_u64, iface_ea);
 -
 +        if (port->cfg->mac && eth_addr_from_string(port->cfg->mac, iface_ea)) {
              /* Find the interface with this Ethernet address (if any) so that
               * we can provide the correct devname to the caller. */
              iface = NULL;
              }
  
              /* The local port doesn't count (since we're trying to choose its
 -             * MAC address anyway).  Other internal ports don't count because
 -             * we really want a physical MAC if we can get it, and internal
 -             * ports typically have randomly generated MACs. */
 -            if (iface->dp_ifidx == ODPP_LOCAL
 -                || cfg_get_bool(0, "iface.%s.internal", iface->name)) {
 +             * MAC address anyway). */
 +            if (iface->dp_ifidx == ODPP_LOCAL) {
                  continue;
              }
  
  
          /* Compare against our current choice. */
          if (!eth_addr_is_multicast(iface_ea) &&
 +            !eth_addr_is_local(iface_ea) &&
              !eth_addr_is_reserved(iface_ea) &&
              !eth_addr_is_zero(iface_ea) &&
              memcmp(iface_ea, ea, ETH_ADDR_LEN) < 0)
              *hw_addr_iface = iface;
          }
      }
 -    if (eth_addr_is_multicast(ea) || eth_addr_is_vif(ea)) {
 +    if (eth_addr_is_multicast(ea)) {
          memcpy(ea, br->default_ea, ETH_ADDR_LEN);
          *hw_addr_iface = NULL;
          VLOG_WARN("bridge %s: using default bridge Ethernet "
@@@ -916,11 -914,10 +958,11 @@@ bridge_pick_datapath_id(struct bridge *
       * stable from one run to the next, so that policy set on a datapath
       * "sticks".
       */
 +    const char *datapath_id;
      uint64_t dpid;
  
 -    dpid = cfg_get_dpid(0, "bridge.%s.datapath-id", br->name);
 -    if (dpid) {
 +    datapath_id = bridge_get_other_config(br->cfg, "datapath-id");
 +    if (datapath_id && dpid_from_string(datapath_id, &dpid)) {
          return dpid;
      }
  
@@@ -1019,6 -1016,7 +1061,6 @@@ bridge_wait(void
  
          mac_learning_wait(br->ml);
          bond_wait(br);
 -        brstp_wait(br);
      }
  }
  
@@@ -1054,8 -1052,7 +1096,8 @@@ bridge_get_local_iface(struct bridge *b
  \f
  /* Bridge unixctl user interface functions. */
  static void
 -bridge_unixctl_fdb_show(struct unixctl_conn *conn, const char *args)
 +bridge_unixctl_fdb_show(struct unixctl_conn *conn,
 +                        const char *args, void *aux UNUSED)
  {
      struct ds ds = DS_EMPTY_INITIALIZER;
      const struct bridge *br;
  }
  \f
  /* Bridge reconfiguration functions. */
 -
  static struct bridge *
 -bridge_create(const char *name)
 +bridge_create(const struct ovsrec_bridge *br_cfg)
  {
      struct bridge *br;
      int error;
  
 -    assert(!bridge_lookup(name));
 -    br = xcalloc(1, sizeof *br);
 +    assert(!bridge_lookup(br_cfg->name));
 +    br = xzalloc(sizeof *br);
  
 -    error = dpif_create_and_open(name, &br->dpif);
 +    error = dpif_create_and_open(br_cfg->name, br_cfg->datapath_type,
 +                                 &br->dpif);
      if (error) {
          free(br);
          return NULL;
      }
      dpif_flow_flush(br->dpif);
  
 -    error = ofproto_create(name, &bridge_ofhooks, br, &br->ofproto);
 +    error = ofproto_create(br_cfg->name, br_cfg->datapath_type, &bridge_ofhooks,
 +                           br, &br->ofproto);
      if (error) {
 -        VLOG_ERR("failed to create switch %s: %s", name, strerror(error));
 +        VLOG_ERR("failed to create switch %s: %s", br_cfg->name,
 +                 strerror(error));
          dpif_delete(br->dpif);
          dpif_close(br->dpif);
          free(br);
          return NULL;
      }
  
 -    br->name = xstrdup(name);
 +    br->name = xstrdup(br_cfg->name);
 +    br->cfg = br_cfg;
      br->ml = mac_learning_create();
      br->sent_config_request = false;
      eth_addr_random(br->default_ea);
@@@ -1182,8 -1176,7 +1224,8 @@@ bridge_get_datapathid(const char *name
  /* Handle requests for a listing of all flows known by the OpenFlow
   * stack, including those normally hidden. */
  static void
 -bridge_unixctl_dump_flows(struct unixctl_conn *conn, const char *args)
 +bridge_unixctl_dump_flows(struct unixctl_conn *conn,
 +                          const char *args, void *aux UNUSED)
  {
      struct bridge *br;
      struct ds results;
@@@ -1213,6 -1206,7 +1255,6 @@@ bridge_run_one(struct bridge *br
  
      mac_learning_run(br->ml, ofproto_get_revalidate_set(br->ofproto));
      bond_run(br);
 -    brstp_run(br);
  
      error = ofproto_run2(br->ofproto, br->flush);
      br->flush = false;
      return error;
  }
  
 -static const char *
 -bridge_get_controller(const struct bridge *br)
 +static const struct ovsrec_controller *
 +bridge_get_controller(const struct ovsrec_open_vswitch *ovs_cfg,
 +                      const struct bridge *br)
  {
 -    const char *controller;
 +    const struct ovsrec_controller *controller;
 +
 +    controller = (br->cfg->controller ? br->cfg->controller
 +                  : ovs_cfg->controller ? ovs_cfg->controller
 +                  : NULL);
  
 -    controller = cfg_get_string(0, "bridge.%s.controller", br->name);
 -    if (!controller) {
 -        controller = cfg_get_string(0, "mgmt.controller");
 +    if (controller && !strcmp(controller->target, "none")) {
 +        return NULL;
      }
 -    return controller && controller[0] ? controller : NULL;
 +
 +    return controller;
  }
  
  static bool
@@@ -1254,64 -1243,66 +1296,64 @@@ check_duplicate_ifaces(struct bridge *b
  }
  
  static void
 -bridge_reconfigure_one(struct bridge *br)
 +bridge_reconfigure_one(const struct ovsrec_open_vswitch *ovs_cfg,
 +                       struct bridge *br)
  {
 -    struct svec old_ports, new_ports, ifaces;
 +    struct shash old_ports, new_ports;
 +    struct svec ifaces;
      struct svec listeners, old_listeners;
      struct svec snoops, old_snoops;
 +    struct shash_node *node;
      size_t i;
  
      /* Collect old ports. */
 -    svec_init(&old_ports);
 +    shash_init(&old_ports);
      for (i = 0; i < br->n_ports; i++) {
 -        svec_add(&old_ports, br->ports[i]->name);
 +        shash_add(&old_ports, br->ports[i]->name, br->ports[i]);
      }
 -    svec_sort(&old_ports);
 -    assert(svec_is_unique(&old_ports));
  
      /* Collect new 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)) {
 +    shash_init(&new_ports);
 +    for (i = 0; i < br->cfg->n_ports; i++) {
 +        const char *name = br->cfg->ports[i]->name;
 +        if (!shash_add_once(&new_ports, name, br->cfg->ports[i])) {
 +            VLOG_WARN("bridge %s: %s specified twice as bridge port",
 +                      br->name, name);
 +        }
 +    }
 +
 +    /* If we have a controller, then we need a local port.  Complain if the
 +     * user didn't specify one.
 +     *
 +     * XXX perhaps we should synthesize a port ourselves in this case. */
 +    if (bridge_get_controller(ovs_cfg, 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 (!error && !shash_find(&new_ports, local_name)) {
 +            VLOG_WARN("bridge %s: controller specified but no local port "
 +                      "(port named %s) defined",
 +                      br->name, local_name);
          }
      }
 -    if (!svec_is_unique(&new_ports)) {
 -        VLOG_WARN("bridge %s: %s specified twice as bridge port",
 -                  br->name, svec_get_duplicate(&new_ports));
 -        svec_unique(&new_ports);
 -    }
 -
 -    ofproto_set_mgmt_id(br->ofproto, mgmt_id);
  
      /* Get rid of deleted ports and add new ports. */
 -    for (i = 0; i < br->n_ports; ) {
 -        struct port *port = br->ports[i];
 -        if (!svec_contains(&new_ports, port->name)) {
 -            port_destroy(port);
 -        } else {
 -            i++;
 +    SHASH_FOR_EACH (node, &old_ports) {
 +        if (!shash_find(&new_ports, node->name)) {
 +            port_destroy(node->data);
          }
      }
 -    for (i = 0; i < new_ports.n; i++) {
 -        const char *name = new_ports.names[i];
 -        if (!svec_contains(&old_ports, name)) {
 -            port_create(br, name);
 +    SHASH_FOR_EACH (node, &new_ports) {
 +        struct port *port = shash_find_data(&old_ports, node->name);
 +        if (!port) {
 +            port = port_create(br, node->name);
          }
 +        port_reconfigure(port, node->data);
      }
 -    svec_destroy(&old_ports);
 -    svec_destroy(&new_ports);
 -
 -    /* Reconfigure all ports. */
 -    for (i = 0; i < br->n_ports; i++) {
 -        port_reconfigure(br->ports[i]);
 -    }
 +    shash_destroy(&old_ports);
 +    shash_destroy(&new_ports);
  
      /* Check and delete duplicate interfaces. */
      svec_init(&ifaces);
       * versa.  (XXX Should we delete all flows if we are switching from one
       * controller to another?) */
  
 +#if 0
      /* Configure OpenFlow management listeners. */
      svec_init(&listeners);
      cfg_get_all_strings(&listeners, "bridge.%s.openflow.listeners", br->name);
      }
      svec_destroy(&snoops);
      svec_destroy(&old_snoops);
 +#else
 +    /* Default listener. */
 +    svec_init(&listeners);
 +    svec_add_nocopy(&listeners, xasprintf("punix:%s/%s.mgmt",
 +                                          ovs_rundir, br->name));
 +    svec_init(&old_listeners);
 +    ofproto_get_listeners(br->ofproto, &old_listeners);
 +    if (!svec_equal(&listeners, &old_listeners)) {
 +        ofproto_set_listeners(br->ofproto, &listeners);
 +    }
 +    svec_destroy(&listeners);
 +    svec_destroy(&old_listeners);
 +
 +    /* Default snoop. */
 +    svec_init(&snoops);
 +    svec_add_nocopy(&snoops, xasprintf("punix:%s/%s.snoop",
 +                                       ovs_rundir, br->name));
 +    svec_init(&old_snoops);
 +    ofproto_get_snoops(br->ofproto, &old_snoops);
 +    if (!svec_equal(&snoops, &old_snoops)) {
 +        ofproto_set_snoops(br->ofproto, &snoops);
 +    }
 +    svec_destroy(&snoops);
 +    svec_destroy(&old_snoops);
 +#endif
  
      mirror_reconfigure(br);
  }
  
  static void
 -bridge_reconfigure_controller(struct bridge *br)
 +bridge_reconfigure_controller(const struct ovsrec_open_vswitch *ovs_cfg,
 +                              struct bridge *br)
  {
      char *pfx = xasprintf("bridge.%s.controller", br->name);
 -    const char *controller;
 +    const struct ovsrec_controller *c;
  
 -    controller = bridge_get_controller(br);
 -    if ((br->controller != NULL) != (controller != NULL)) {
 +    c = bridge_get_controller(ovs_cfg, br);
 +    if ((br->controller != NULL) != (c != NULL)) {
          ofproto_flush_flows(br->ofproto);
      }
      free(br->controller);
 -    br->controller = controller ? xstrdup(controller) : NULL;
 +    br->controller = c ? xstrdup(c->target) : NULL;
  
 -    if (controller) {
 -        const char *fail_mode;
 +    if (c) {
          int max_backoff, probe;
          int rate_limit, burst_limit;
  
 -        if (!strcmp(controller, "discover")) {
 -            bool update_resolv_conf = true;
 -
 -            if (cfg_has("%s.update-resolv.conf", pfx)) {
 -                update_resolv_conf = cfg_get_bool(0, "%s.update-resolv.conf",
 -                        pfx);
 -            }
 +        if (!strcmp(c->target, "discover")) {
              ofproto_set_discovery(br->ofproto, true,
 -                                  cfg_get_string(0, "%s.accept-regex", pfx),
 -                                  update_resolv_conf);
 +                                  c->discover_accept_regex,
 +                                  c->discover_update_resolv_conf);
          } else {
              struct iface *local_iface;
 +            struct in_addr ip;
              bool in_band;
  
 -            in_band = (!cfg_is_valid(CFG_BOOL | CFG_REQUIRED,
 -                                     "%s.in-band", pfx)
 -                       || cfg_get_bool(0, "%s.in-band", pfx));
 +            in_band = (!c->connection_mode
 +                       || !strcmp(c->connection_mode, "out-of-band"));
              ofproto_set_discovery(br->ofproto, false, NULL, NULL);
              ofproto_set_in_band(br->ofproto, in_band);
  
              local_iface = bridge_get_local_iface(br);
 -            if (local_iface
 -                && cfg_is_valid(CFG_IP | CFG_REQUIRED, "%s.ip", pfx)) {
 +            if (local_iface && c->local_ip && inet_aton(c->local_ip, &ip)) {
                  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);
 +
 +                if (!c->local_netmask || !inet_aton(c->local_netmask, &mask)) {
 +                    mask.s_addr = 0;
 +                }
 +                if (!c->local_gateway
 +                    || !inet_aton(c->local_gateway, &gateway)) {
 +                    gateway.s_addr = 0;
 +                }
  
                  netdev_turn_flags_on(netdev, NETDEV_UP, true);
                  if (!mask.s_addr) {
              }
          }
  
 -        fail_mode = cfg_get_string(0, "%s.fail-mode", pfx);
 -        if (!fail_mode) {
 -            fail_mode = cfg_get_string(0, "mgmt.fail-mode");
 -        }
          ofproto_set_failure(br->ofproto,
 -                            (!fail_mode
 -                             || !strcmp(fail_mode, "standalone")
 -                             || !strcmp(fail_mode, "open")));
 -
 -        probe = cfg_get_int(0, "%s.inactivity-probe", pfx);
 -        if (probe < 5) {
 -            probe = cfg_get_int(0, "mgmt.inactivity-probe");
 -            if (probe < 5) {
 -                probe = 5;
 -            }
 -        }
 +                            (!c->fail_mode
 +                             || !strcmp(c->fail_mode, "standalone")
 +                             || !strcmp(c->fail_mode, "open")));
 +
 +        probe = c->inactivity_probe ? *c->inactivity_probe / 1000 : 5;
          ofproto_set_probe_interval(br->ofproto, probe);
  
 -        max_backoff = cfg_get_int(0, "%s.max-backoff", pfx);
 -        if (!max_backoff) {
 -            max_backoff = cfg_get_int(0, "mgmt.max-backoff");
 -            if (!max_backoff) {
 -                max_backoff = 8;
 -            }
 -        }
 +        max_backoff = c->max_backoff ? *c->max_backoff / 1000 : 8;
          ofproto_set_max_backoff(br->ofproto, max_backoff);
  
 -        rate_limit = cfg_get_int(0, "%s.rate-limit", pfx);
 -        if (!rate_limit) {
 -            rate_limit = cfg_get_int(0, "mgmt.rate-limit");
 -        }
 -        burst_limit = cfg_get_int(0, "%s.burst-limit", pfx);
 -        if (!burst_limit) {
 -            burst_limit = cfg_get_int(0, "mgmt.burst-limit");
 -        }
 +        rate_limit = c->controller_rate_limit ? *c->controller_rate_limit : 0;
 +        burst_limit = c->controller_burst_limit ? *c->controller_burst_limit : 0;
          ofproto_set_rate_limit(br->ofproto, rate_limit, burst_limit);
 -
 -        ofproto_set_stp(br->ofproto, cfg_get_bool(0, "%s.stp", pfx));
 -
 -        if (cfg_has("%s.commands.acl", pfx)) {
 -            struct svec command_acls;
 -            char *command_acl;
 -
 -            svec_init(&command_acls);
 -            cfg_get_all_strings(&command_acls, "%s.commands.acl", pfx);
 -            command_acl = svec_join(&command_acls, ",", "");
 -
 -            ofproto_set_remote_execution(br->ofproto, command_acl,
 -                                         cfg_get_string(0, "%s.commands.dir",
 -                                                        pfx));
 -
 -            svec_destroy(&command_acls);
 -            free(command_acl);
 -        } else {
 -            ofproto_set_remote_execution(br->ofproto, NULL, NULL);
 -        }
      } else {
          union ofp_action action;
          flow_t flow;
          ofproto_set_max_backoff(br->ofproto, 1);
          ofproto_set_probe_interval(br->ofproto, 5);
          ofproto_set_failure(br->ofproto, false);
 -        ofproto_set_stp(br->ofproto, false);
      }
      free(pfx);
  
  }
  
  static void
 -bridge_get_all_ifaces(const struct bridge *br, struct svec *ifaces)
 +bridge_get_all_ifaces(const struct bridge *br, struct shash *ifaces)
  {
      size_t i, j;
  
 -    svec_init(ifaces);
 +    shash_init(ifaces);
      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];
 -            svec_add(ifaces, iface->name);
 +            shash_add_once(ifaces, iface->name, iface);
          }
 -        if (port->n_ifaces > 1
 -            && cfg_get_bool(0, "bonding.%s.fake-iface", port->name)) {
 -            svec_add(ifaces, port->name);
 +        if (port->n_ifaces > 1 && port->cfg->bond_fake_iface) {
 +            shash_add_once(ifaces, port->name, NULL);
          }
      }
 -    svec_sort_unique(ifaces);
  }
  
  /* For robustness, in case the administrator moves around datapath ports behind
@@@ -1554,13 -1566,6 +1596,13 @@@ bridge_fetch_dp_ifaces(struct bridge *b
                  port_array_set(&br->ifaces, p->port, iface);
                  iface->dp_ifidx = p->port;
              }
 +
 +            if (iface->cfg) {
 +                int64_t ofport = (iface->dp_ifidx >= 0
 +                                  ? odp_port_to_ofp_port(iface->dp_ifidx)
 +                                  : -1);
 +                ovsrec_interface_set_ofport(iface->cfg, &ofport, 1);
 +            }
          }
      }
      free(dpif_ports);
@@@ -1790,6 -1795,18 +1832,6 @@@ set_dst(struct dst *p, const flow_t *fl
          const struct port *in_port, const struct port *out_port,
          tag_type *tags)
  {
 -    /* STP handling.
 -     *
 -     * XXX This uses too many tags: any broadcast flow will get one tag per
 -     * destination port, and thus a broadcast on a switch of any size is likely
 -     * to have all tag bits set.  We should figure out a way to be smarter.
 -     *
 -     * This is OK when STP is disabled, because stp_state_tag is 0 then. */
 -    *tags |= out_port->stp_state_tag;
 -    if (!(out_port->stp_state & (STP_DISABLED | STP_FORWARDING))) {
 -        return false;
 -    }
 -
      p->vlan = (out_port->vlan >= 0 ? OFP_VLAN_NONE
                : in_port->vlan >= 0 ? in_port->vlan
                : ntohs(flow->dl_vlan));
@@@ -1882,6 -1899,7 +1924,6 @@@ compose_dsts(const struct bridge *br, c
      struct dst *dst = dsts;
      size_t i;
  
 -    *tags |= in_port->stp_state_tag;
      if (out_port == FLOOD_PORT) {
          /* XXX use ODP_FLOOD if no vlans or bonding. */
          /* XXX even better, define each VLAN as a datapath port group */
@@@ -2110,6 -2128,13 +2152,6 @@@ process_flow(struct bridge *br, const f
          goto done;
      }
  
 -    /* Drop frames for ports that STP wants entirely killed (both for
 -     * forwarding and for learning).  Later, after we do learning, we'll drop
 -     * the frames that STP wants to do learning but not forwarding on. */
 -    if (in_port->stp_state & (STP_LISTENING | STP_BLOCKING)) {
 -        goto done;
 -    }
 -
      /* Drop frames for reserved multicast addresses. */
      if (eth_addr_is_reserved(flow->dl_dst)) {
          goto done;
          return false;
      }
  
 -    /* Don't send packets out their input ports.  Don't forward frames that STP
 -     * wants us to discard. */
 -    if (in_port == out_port || in_port->stp_state == STP_LEARNING) {
 +    /* Don't send packets out their input ports. */
 +    if (in_port == out_port) {
          out_port = NULL;
      }
  
@@@ -2224,6 -2250,14 +2266,6 @@@ bridge_normal_ofhook_cb(const flow_t *f
  {
      struct bridge *br = br_;
  
 -#if 0
 -    if (flow->dl_type == htons(OFP_DL_TYPE_NOT_ETH_TYPE)
 -        && eth_addr_equals(flow->dl_dst, stp_eth_addr)) {
 -        brstp_receive(br, flow, payload);
 -        return true;
 -    }
 -#endif
 -
      COVERAGE_INC(bridge_process_flow);
      return process_flow(br, flow, packet, actions, tags, nf_output_iface);
  }
@@@ -2664,8 -2698,7 +2706,8 @@@ bond_send_learning_packets(struct port 
  /* Bonding unixctl user interface functions. */
  
  static void
 -bond_unixctl_list(struct unixctl_conn *conn, const char *args UNUSED)
 +bond_unixctl_list(struct unixctl_conn *conn,
 +                  const char *args UNUSED, void *aux UNUSED)
  {
      struct ds ds = DS_EMPTY_INITIALIZER;
      const struct bridge *br;
@@@ -2715,8 -2748,7 +2757,8 @@@ bond_find(const char *name
  }
  
  static void
 -bond_unixctl_show(struct unixctl_conn *conn, const char *args)
 +bond_unixctl_show(struct unixctl_conn *conn,
 +                  const char *args, void *aux UNUSED)
  {
      struct ds ds = DS_EMPTY_INITIALIZER;
      const struct port *port;
  }
  
  static void
 -bond_unixctl_migrate(struct unixctl_conn *conn, const char *args_)
 +bond_unixctl_migrate(struct unixctl_conn *conn, const char *args_,
 +                     void *aux UNUSED)
  {
      char *args = (char *) args_;
      char *save_ptr = NULL;
  }
  
  static void
 -bond_unixctl_set_active_slave(struct unixctl_conn *conn, const char *args_)
 +bond_unixctl_set_active_slave(struct unixctl_conn *conn, const char *args_,
 +                              void *aux UNUSED)
  {
      char *args = (char *) args_;
      char *save_ptr = NULL;
@@@ -2919,22 -2949,19 +2961,22 @@@ enable_slave(struct unixctl_conn *conn
  }
  
  static void
 -bond_unixctl_enable_slave(struct unixctl_conn *conn, const char *args)
 +bond_unixctl_enable_slave(struct unixctl_conn *conn, const char *args,
 +                          void *aux UNUSED)
  {
      enable_slave(conn, args, true);
  }
  
  static void
 -bond_unixctl_disable_slave(struct unixctl_conn *conn, const char *args)
 +bond_unixctl_disable_slave(struct unixctl_conn *conn, const char *args,
 +                           void *aux UNUSED)
  {
      enable_slave(conn, args, false);
  }
  
  static void
 -bond_unixctl_hash(struct unixctl_conn *conn, const char *args)
 +bond_unixctl_hash(struct unixctl_conn *conn, const char *args,
 +                  void *aux UNUSED)
  {
        uint8_t mac[ETH_ADDR_LEN];
        uint8_t hash;
  static void
  bond_init(void)
  {
 -    unixctl_command_register("bond/list", bond_unixctl_list);
 -    unixctl_command_register("bond/show", bond_unixctl_show);
 -    unixctl_command_register("bond/migrate", bond_unixctl_migrate);
 +    unixctl_command_register("bond/list", bond_unixctl_list, NULL);
 +    unixctl_command_register("bond/show", bond_unixctl_show, NULL);
 +    unixctl_command_register("bond/migrate", bond_unixctl_migrate, NULL);
      unixctl_command_register("bond/set-active-slave",
 -                             bond_unixctl_set_active_slave);
 -    unixctl_command_register("bond/enable-slave", bond_unixctl_enable_slave);
 -    unixctl_command_register("bond/disable-slave", bond_unixctl_disable_slave);
 -    unixctl_command_register("bond/hash", bond_unixctl_hash);
 +                             bond_unixctl_set_active_slave, NULL);
 +    unixctl_command_register("bond/enable-slave", bond_unixctl_enable_slave,
 +                             NULL);
 +    unixctl_command_register("bond/disable-slave", bond_unixctl_disable_slave,
 +                             NULL);
 +    unixctl_command_register("bond/hash", bond_unixctl_hash, NULL);
  }
  \f
  /* Port functions. */
  
 -static void
 +static struct port *
  port_create(struct bridge *br, const char *name)
  {
      struct port *port;
  
 -    port = xcalloc(1, sizeof *port);
 +    port = xzalloc(sizeof *port);
      port->bridge = br;
      port->port_idx = br->n_ports;
      port->vlan = -1;
      port->trunks = NULL;
      port->name = xstrdup(name);
      port->active_iface = -1;
 -    port->stp_state = STP_DISABLED;
 -    port->stp_state_tag = 0;
  
      if (br->n_ports >= br->allocated_ports) {
          br->ports = x2nrealloc(br->ports, &br->allocated_ports,
  
      VLOG_INFO("created port %s on bridge %s", port->name, br->name);
      bridge_flush(br);
 +
 +    return port;
  }
  
  static void
 -port_reconfigure(struct port *port)
 +port_reconfigure(struct port *port, const struct ovsrec_port *cfg)
  {
 -    bool bonded = cfg_has_section("bonding.%s", port->name);
 -    struct svec old_ifaces, new_ifaces;
 +    struct shash old_ifaces, new_ifaces;
 +    struct shash_node *node;
      unsigned long *trunks;
      int vlan;
      size_t i;
  
 +    port->cfg = cfg;
 +
      /* Collect old and new interfaces. */
 -    svec_init(&old_ifaces);
 -    svec_init(&new_ifaces);
 +    shash_init(&old_ifaces);
 +    shash_init(&new_ifaces);
      for (i = 0; i < port->n_ifaces; i++) {
 -        svec_add(&old_ifaces, port->ifaces[i]->name);
 +        shash_add(&old_ifaces, port->ifaces[i]->name, port->ifaces[i]);
      }
 -    svec_sort(&old_ifaces);
 -    if (bonded) {
 -        cfg_get_all_keys(&new_ifaces, "bonding.%s.slave", port->name);
 -        if (!new_ifaces.n) {
 -            VLOG_ERR("port %s: no interfaces specified for bonded port",
 -                     port->name);
 -        } else if (new_ifaces.n == 1) {
 -            VLOG_WARN("port %s: only 1 interface specified for bonded port",
 -                      port->name);
 -        }
 -
 -        port->updelay = cfg_get_int(0, "bonding.%s.updelay", port->name);
 -        if (port->updelay < 0) {
 -            port->updelay = 0;
 +    for (i = 0; i < cfg->n_interfaces; i++) {
 +        const char *name = cfg->interfaces[i]->name;
 +        if (!shash_add_once(&new_ifaces, name, cfg->interfaces[i])) {
 +            VLOG_WARN("port %s: %s specified twice as port interface",
 +                      port->name, name);
          }
 -        port->downdelay = cfg_get_int(0, "bonding.%s.downdelay", port->name);
 -        if (port->downdelay < 0) {
 -            port->downdelay = 0;
 -        }
 -    } else {
 -        svec_init(&new_ifaces);
 -        svec_add(&new_ifaces, port->name);
 +    }
 +    port->updelay = cfg->bond_updelay;
 +    if (port->updelay < 0) {
 +        port->updelay = 0;
 +    }
 +    port->updelay = cfg->bond_downdelay;
 +    if (port->downdelay < 0) {
 +        port->downdelay = 0;
      }
  
      /* Get rid of deleted interfaces and add new interfaces. */
 -    for (i = 0; i < port->n_ifaces; i++) {
 -        struct iface *iface = port->ifaces[i];
 -        if (!svec_contains(&new_ifaces, iface->name)) {
 -            iface_destroy(iface);
 -        } else {
 -            i++;
 +    SHASH_FOR_EACH (node, &old_ifaces) {
 +        if (!shash_find(&new_ifaces, node->name)) {
 +            iface_destroy(node->data);
          }
      }
 -    for (i = 0; i < new_ifaces.n; i++) {
 -        const char *name = new_ifaces.names[i];
 -        if (!svec_contains(&old_ifaces, name)) {
 -            iface_create(port, name);
 +    SHASH_FOR_EACH (node, &new_ifaces) {
 +        const struct ovsrec_interface *if_cfg = node->data;
 +        struct iface *iface;
 +
 +        iface = shash_find_data(&old_ifaces, if_cfg->name);
 +        if (!iface) {
 +            iface = iface_create(port, if_cfg);
 +        } else {
 +            iface->cfg = if_cfg;
          }
      }
  
      /* Get VLAN tag. */
      vlan = -1;
 -    if (cfg_has("vlan.%s.tag", port->name)) {
 -        if (!bonded) {
 -            vlan = cfg_get_vlan(0, "vlan.%s.tag", port->name);
 +    if (cfg->tag) {
 +        if (port->n_ifaces < 2) {
 +            vlan = *cfg->tag;
              if (vlan >= 0 && vlan <= 4095) {
                  VLOG_DBG("port %s: assigning VLAN tag %d", port->name, vlan);
 +            } else {
 +                vlan = -1;
              }
          } else {
              /* It's possible that bonded, VLAN-tagged ports make sense.  Maybe
      /* Get trunked VLANs. */
      trunks = NULL;
      if (vlan < 0) {
 -        size_t n_trunks, n_errors;
 +        size_t n_errors;
          size_t i;
  
          trunks = bitmap_allocate(4096);
 -        n_trunks = cfg_count("vlan.%s.trunks", port->name);
          n_errors = 0;
 -        for (i = 0; i < n_trunks; i++) {
 -            int trunk = cfg_get_vlan(i, "vlan.%s.trunks", port->name);
 +        for (i = 0; i < cfg->n_trunks; i++) {
 +            int trunk = cfg->trunks[i];
              if (trunk >= 0) {
                  bitmap_set1(trunks, trunk);
              } else {
          }
          if (n_errors) {
              VLOG_ERR("port %s: invalid values for %zu trunk VLANs",
 -                     port->name, n_trunks);
 +                     port->name, cfg->n_trunks);
          }
 -        if (n_errors == n_trunks) {
 +        if (n_errors == cfg->n_trunks) {
              if (n_errors) {
                  VLOG_ERR("port %s: no valid trunks, trunking all VLANs",
                           port->name);
              bitmap_set_multiple(trunks, 0, 4096, 1);
          }
      } else {
 -        if (cfg_has("vlan.%s.trunks", port->name)) {
 -            VLOG_ERR("ignoring vlan.%s.trunks in favor of vlan.%s.vlan",
 -                     port->name, port->name);
 +        if (cfg->n_trunks) {
 +            VLOG_ERR("port %s: ignoring trunks in favor of implicit vlan",
 +                     port->name);
          }
      }
      if (trunks == NULL
      bitmap_free(port->trunks);
      port->trunks = trunks;
  
 -    svec_destroy(&old_ifaces);
 -    svec_destroy(&new_ifaces);
 +    shash_destroy(&old_ifaces);
 +    shash_destroy(&new_ifaces);
  }
  
  static void
@@@ -3118,7 -3146,7 +3160,7 @@@ port_destroy(struct port *port
      if (port) {
          struct bridge *br = port->bridge;
          struct port *del;
 -        size_t i;
 +        int i;
  
          proc_net_compat_update_vlan(port->name, NULL, 0);
          proc_net_compat_update_bond(port->name, NULL);
@@@ -3189,7 -3217,6 +3231,7 @@@ port_update_bonding(struct port *port
              free(port->bond_hash);
              port->bond_hash = NULL;
              port->bond_compat_is_stale = true;
 +            port->bond_fake_iface = false;
          }
      } else {
          if (!port->bond_hash) {
              bond_choose_active_iface(port);
          }
          port->bond_compat_is_stale = true;
 +        port->bond_fake_iface = port->cfg->bond_fake_iface;
      }
  }
  
@@@ -3265,10 -3291,10 +3307,10 @@@ port_update_bond_compat(struct port *po
          netdev_get_etheraddr(iface->netdev, slave->mac);
      }
  
 -    if (cfg_get_bool(0, "bonding.%s.fake-iface", port->name)) {
 +    if (port->bond_fake_iface) {
          struct netdev *bond_netdev;
  
 -        if (!netdev_open(port->name, NETDEV_ETH_TYPE_NONE, &bond_netdev)) {
 +        if (!netdev_open_default(port->name, &bond_netdev)) {
              if (bond.up) {
                  netdev_turn_flags_on(bond_netdev, NETDEV_UP, true);
              } else {
@@@ -3321,14 -3347,12 +3363,14 @@@ port_update_vlan_compat(struct port *po
  \f
  /* Interface functions. */
  
 -static void
 -iface_create(struct port *port, const char *name)
 +static struct iface *
 +iface_create(struct port *port, const struct ovsrec_interface *if_cfg)
  {
      struct iface *iface;
 +    char *name = if_cfg->name;
 +    int error;
  
 -    iface = xcalloc(1, sizeof *iface);
 +    iface = xzalloc(sizeof *iface);
      iface->port = port;
      iface->port_ifidx = port->n_ifaces;
      iface->name = xstrdup(name);
      iface->tag = tag_create_random();
      iface->delay_expires = LLONG_MAX;
      iface->netdev = NULL;
 +    iface->cfg = if_cfg;
  
      if (port->n_ifaces >= port->allocated_ifaces) {
          port->ifaces = x2nrealloc(port->ifaces, &port->allocated_ifaces,
          port->bridge->has_bonded_ports = true;
      }
  
 +    /* Attempt to create the network interface in case it
 +     * doesn't exist yet. */
 +    if (!iface_is_internal(port->bridge, iface->name)) {
 +        error = set_up_iface(if_cfg, iface, true);
 +        if (error) {
 +            VLOG_WARN("could not create iface %s: %s", iface->name,
 +                    strerror(error));
 +        }
 +    }
 +
      VLOG_DBG("attached network device %s to port %s", iface->name, port->name);
  
      bridge_flush(port->bridge);
 +
 +    return iface;
  }
  
  static void
@@@ -3381,6 -3392,8 +3423,6 @@@ iface_destroy(struct iface *iface
          del->port_ifidx = iface->port_ifidx;
  
          netdev_close(iface->netdev);
 -        free(iface->name);
 -        free(iface);
  
          if (del_active) {
              ofproto_revalidate(port->bridge->ofproto, port->active_iface_tag);
              bond_send_learning_packets(port);
          }
  
 +        free(iface->name);
 +        free(iface);
 +
          bridge_flush(port->bridge);
      }
  }
@@@ -3429,25 -3439,20 +3471,25 @@@ iface_from_dp_ifidx(const struct bridg
   * reason why this function takes a name instead of a struct iface: the fake
   * interfaces created this way do not have a struct iface. */
  static bool
 -iface_is_internal(const struct bridge *br, const char *iface)
 +iface_is_internal(const struct bridge *br, const char *if_name)
  {
 -    if (!strcmp(iface, br->name)
 -        || cfg_get_bool(0, "iface.%s.internal", iface)) {
 +    /* XXX wastes time */
 +    struct iface *iface;
 +    struct port *port;
 +
 +    if (!strcmp(if_name, br->name)) {
          return true;
      }
  
 -    if (cfg_get_bool(0, "bonding.%s.fake-iface", iface)) {
 -        struct port *port = port_lookup(br, iface);
 -        if (port && port->n_ifaces > 1) {
 -            return true;
 -        }
 +    iface = iface_lookup(br, if_name);
 +    if (iface && !strcmp(iface->cfg->type, "internal")) {
 +        return true;
      }
  
 +    port = port_lookup(br, if_name);
 +    if (port && port->n_ifaces > 1 && port->cfg->bond_fake_iface) {
 +        return true;
 +    }
      return false;
  }
  
  static void
  iface_set_mac(struct iface *iface)
  {
 -    uint64_t mac = cfg_get_mac(0, "iface.%s.mac", iface->name);
 -    if (mac) {
 -        static uint8_t ea[ETH_ADDR_LEN];
 +    uint8_t ea[ETH_ADDR_LEN];
  
 -        eth_addr_from_uint64(mac, ea);
 +    if (iface->cfg->mac && eth_addr_from_string(iface->cfg->mac, ea)) {
          if (eth_addr_is_multicast(ea)) {
              VLOG_ERR("interface %s: cannot set MAC to multicast address",
                       iface->name);
  static void
  mirror_reconfigure(struct bridge *br)
  {
 -    struct svec old_mirrors, new_mirrors;
 -    size_t i, n_rspan_vlans;
 +    struct shash old_mirrors, new_mirrors;
 +    struct shash_node *node;
      unsigned long *rspan_vlans;
 +    int i;
  
 -    /* Collect old and new mirrors. */
 -    svec_init(&old_mirrors);
 -    svec_init(&new_mirrors);
 -    cfg_get_subsections(&new_mirrors, "mirror.%s", br->name);
 +    /* Collect old mirrors. */
 +    shash_init(&old_mirrors);
      for (i = 0; i < MAX_MIRRORS; i++) {
          if (br->mirrors[i]) {
 -            svec_add(&old_mirrors, br->mirrors[i]->name);
 +            shash_add(&old_mirrors, br->mirrors[i]->name, br->mirrors[i]);
          }
      }
  
 -    /* Get rid of deleted mirrors and add new mirrors. */
 -    svec_sort(&old_mirrors);
 -    assert(svec_is_unique(&old_mirrors));
 -    svec_sort(&new_mirrors);
 -    assert(svec_is_unique(&new_mirrors));
 -    for (i = 0; i < MAX_MIRRORS; i++) {
 -        struct mirror *m = br->mirrors[i];
 -        if (m && !svec_contains(&new_mirrors, m->name)) {
 -            mirror_destroy(m);
 +    /* Collect new mirrors. */
 +    shash_init(&new_mirrors);
 +    for (i = 0; i < br->cfg->n_mirrors; i++) {
 +        struct ovsrec_mirror *cfg = br->cfg->mirrors[i];
 +        if (!shash_add_once(&new_mirrors, cfg->name, cfg)) {
 +            VLOG_WARN("bridge %s: %s specified twice as mirror",
 +                      br->name, cfg->name);
          }
      }
 -    for (i = 0; i < new_mirrors.n; i++) {
 -        const char *name = new_mirrors.names[i];
 -        if (!svec_contains(&old_mirrors, name)) {
 -            mirror_create(br, name);
 +
 +    /* Get rid of deleted mirrors and add new mirrors. */
 +    SHASH_FOR_EACH (node, &old_mirrors) {
 +        if (!shash_find(&new_mirrors, node->name)) {
 +            mirror_destroy(node->data);
          }
      }
 -    svec_destroy(&old_mirrors);
 -    svec_destroy(&new_mirrors);
 -
 -    /* Reconfigure all mirrors. */
 -    for (i = 0; i < MAX_MIRRORS; i++) {
 -        if (br->mirrors[i]) {
 -            mirror_reconfigure_one(br->mirrors[i]);
 +    SHASH_FOR_EACH (node, &new_mirrors) {
 +        struct mirror *mirror = shash_find_data(&old_mirrors, node->name);
 +        if (!mirror) {
 +            mirror = mirror_create(br, node->name);
 +            if (!mirror) {
 +                break;
 +            }
          }
 +        mirror_reconfigure_one(mirror, node->data);
      }
 +    shash_destroy(&old_mirrors);
 +    shash_destroy(&new_mirrors);
  
      /* Update port reserved status. */
      for (i = 0; i < br->n_ports; i++) {
          }
      }
  
 -    /* Update learning disabled vlans (for RSPAN). */
 +    /* Update flooded vlans (for RSPAN). */
      rspan_vlans = NULL;
 -    n_rspan_vlans = cfg_count("vlan.%s.disable-learning", br->name);
 -    if (n_rspan_vlans) {
 +    if (br->cfg->n_flood_vlans) {
          rspan_vlans = bitmap_allocate(4096);
  
 -        for (i = 0; i < n_rspan_vlans; i++) {
 -            int vlan = cfg_get_vlan(i, "vlan.%s.disable-learning", br->name);
 -            if (vlan >= 0) {
 +        for (i = 0; i < br->cfg->n_flood_vlans; i++) {
 +            int64_t vlan = br->cfg->flood_vlans[i];
 +            if (vlan >= 0 && vlan < 4096) {
                  bitmap_set1(rspan_vlans, vlan);
 -                VLOG_INFO("bridge %s: disabling learning on vlan %d\n",
 +                VLOG_INFO("bridge %s: disabling learning on vlan %"PRId64,
                            br->name, vlan);
              } else {
 -                VLOG_ERR("bridge %s: invalid value '%s' for learning disabled "
 -                         "VLAN", br->name,
 -                       cfg_get_string(i, "vlan.%s.disable-learning", br->name));
 +                VLOG_ERR("bridge %s: invalid value %"PRId64 "for flood VLAN",
 +                         br->name, vlan);
              }
          }
      }
 -    if (mac_learning_set_disabled_vlans(br->ml, rspan_vlans)) {
 +    if (mac_learning_set_flood_vlans(br->ml, rspan_vlans)) {
          bridge_flush(br);
      }
  }
  
 -static void
 +static struct mirror *
  mirror_create(struct bridge *br, const char *name)
  {
      struct mirror *m;
          if (i >= MAX_MIRRORS) {
              VLOG_WARN("bridge %s: maximum of %d port mirrors reached, "
                        "cannot create %s", br->name, MAX_MIRRORS, name);
 -            return;
 +            return NULL;
          }
          if (!br->mirrors[i]) {
              break;
      VLOG_INFO("created port mirror %s on bridge %s", name, br->name);
      bridge_flush(br);
  
 -    br->mirrors[i] = m = xcalloc(1, sizeof *m);
 +    br->mirrors[i] = m = xzalloc(sizeof *m);
      m->bridge = br;
      m->idx = i;
      m->name = xstrdup(name);
 -    svec_init(&m->src_ports);
 -    svec_init(&m->dst_ports);
 +    shash_init(&m->src_ports);
 +    shash_init(&m->dst_ports);
      m->vlans = NULL;
      m->n_vlans = 0;
      m->out_vlan = -1;
      m->out_port = NULL;
 +
 +    return m;
  }
  
  static void
@@@ -3601,8 -3607,8 +3643,8 @@@ mirror_destroy(struct mirror *m
              br->ports[i]->dst_mirrors &= ~(MIRROR_MASK_C(1) << m->idx);
          }
  
 -        svec_destroy(&m->src_ports);
 -        svec_destroy(&m->dst_ports);
 +        shash_destroy(&m->src_ports);
 +        shash_destroy(&m->dst_ports);
          free(m->vlans);
  
          m->bridge->mirrors[m->idx] = NULL;
  }
  
  static void
 -prune_ports(struct mirror *m, struct svec *ports)
 +mirror_collect_ports(struct mirror *m, struct ovsrec_port **ports, int n_ports,
 +                     struct shash *names)
  {
 -    struct svec tmp;
      size_t i;
  
 -    svec_sort_unique(ports);
 -
 -    svec_init(&tmp);
 -    for (i = 0; i < ports->n; i++) {
 -        const char *name = ports->names[i];
 +    for (i = 0; i < n_ports; i++) {
 +        const char *name = ports[i]->name;
          if (port_lookup(m->bridge, name)) {
 -            svec_add(&tmp, name);
 +            shash_add_once(names, name, NULL);
          } else {
 -            VLOG_WARN("mirror.%s.%s: cannot match on nonexistent port %s",
 -                      m->bridge->name, m->name, name);
 +            VLOG_WARN("bridge %s: mirror %s cannot match on nonexistent "
 +                      "port %s", m->bridge->name, m->name, name);
          }
      }
 -    svec_swap(ports, &tmp);
 -    svec_destroy(&tmp);
  }
  
  static size_t
 -prune_vlans(struct mirror *m, struct svec *vlan_strings, int **vlans)
 +mirror_collect_vlans(struct mirror *m, const struct ovsrec_mirror *cfg,
 +                     int **vlans)
  {
 -    size_t n_vlans, i;
 -
 -    /* This isn't perfect: it won't combine "0" and "00", and the textual sort
 -     * order won't give us numeric sort order.  But that's good enough for what
 -     * we need right now. */
 -    svec_sort_unique(vlan_strings);
 +    size_t n_vlans;
 +    size_t i;
  
 -    *vlans = xmalloc(sizeof *vlans * vlan_strings->n);
 +    *vlans = xmalloc(sizeof *vlans * cfg->n_select_vlan);
      n_vlans = 0;
 -    for (i = 0; i < vlan_strings->n; i++) {
 -        const char *name = vlan_strings->names[i];
 -        int vlan;
 -        if (!str_to_int(name, 10, &vlan) || vlan < 0 || vlan > 4095) {
 -            VLOG_WARN("mirror.%s.%s.select.vlan: ignoring invalid VLAN %s",
 -                      m->bridge->name, m->name, name);
 +    for (i = 0; i < cfg->n_select_vlan; i++) {
 +        int64_t vlan = cfg->select_vlan[i];
 +        if (vlan < 0 || vlan > 4095) {
 +            VLOG_WARN("bridge %s: mirror %s selects invalid VLAN %"PRId64,
 +                      m->bridge->name, m->name, vlan);
          } else {
              (*vlans)[n_vlans++] = vlan;
          }
@@@ -3677,10 -3692,13 +3719,10 @@@ port_trunks_any_mirrored_vlan(const str
  }
  
  static void
 -mirror_reconfigure_one(struct mirror *m)
 +mirror_reconfigure_one(struct mirror *m, struct ovsrec_mirror *cfg)
  {
 -    char *pfx = xasprintf("mirror.%s.%s", m->bridge->name, m->name);
 -    struct svec src_ports, dst_ports, ports;
 -    struct svec vlan_strings;
 +    struct shash src_ports, dst_ports;
      mirror_mask_t mirror_bit;
 -    const char *out_port_name;
      struct port *out_port;
      int out_vlan;
      size_t n_vlans;
      size_t i;
      bool mirror_all_ports;
      bool any_ports_specified;
 +    bool any_vlans_specified;
  
      /* Get output port. */
 -    out_port_name = cfg_get_key(0, "mirror.%s.%s.output.port",
 -                                m->bridge->name, m->name);
 -    if (out_port_name) {
 -        out_port = port_lookup(m->bridge, out_port_name);
 +    if (cfg->output_port) {
 +        out_port = port_lookup(m->bridge, cfg->output_port->name);
          if (!out_port) {
 -            VLOG_ERR("%s.output.port: bridge %s does not have a port "
 -                      "named %s", pfx, m->bridge->name, out_port_name);
 +            VLOG_ERR("bridge %s: mirror %s outputs to port not on bridge",
 +                     m->bridge->name, m->name);
              mirror_destroy(m);
 -            free(pfx);
              return;
          }
          out_vlan = -1;
  
 -        if (cfg_has("%s.output.vlan", pfx)) {
 -            VLOG_ERR("%s.output.port and %s.output.vlan both specified; "
 -                     "ignoring %s.output.vlan", pfx, pfx, pfx);
 +        if (cfg->output_vlan) {
 +            VLOG_ERR("bridge %s: mirror %s specifies both output port and "
 +                     "output vlan; ignoring output vlan",
 +                     m->bridge->name, m->name);
          }
 -    } else if (cfg_has("%s.output.vlan", pfx)) {
 +    } else if (cfg->output_vlan) {
          out_port = NULL;
 -        out_vlan = cfg_get_vlan(0, "%s.output.vlan", pfx);
 +        out_vlan = *cfg->output_vlan;
      } else {
 -        VLOG_ERR("%s: neither %s.output.port nor %s.output.vlan specified, "
 -                 "but exactly one is required; disabling port mirror %s",
 -                 pfx, pfx, pfx, pfx);
 +        VLOG_ERR("bridge %s: mirror %s does not specify output; ignoring",
 +                 m->bridge->name, m->name);
          mirror_destroy(m);
 -        free(pfx);
          return;
      }
  
      /* Get all the ports, and drop duplicates and ports that don't exist. */
 -    svec_init(&src_ports);
 -    svec_init(&dst_ports);
 -    svec_init(&ports);
 -    cfg_get_all_keys(&src_ports, "%s.select.src-port", pfx);
 -    cfg_get_all_keys(&dst_ports, "%s.select.dst-port", pfx);
 -    cfg_get_all_keys(&ports, "%s.select.port", pfx);
 -    any_ports_specified = src_ports.n || dst_ports.n || ports.n;
 -    svec_append(&src_ports, &ports);
 -    svec_append(&dst_ports, &ports);
 -    svec_destroy(&ports);
 -    prune_ports(m, &src_ports);
 -    prune_ports(m, &dst_ports);
 -    if (any_ports_specified && !src_ports.n && !dst_ports.n) {
 -        VLOG_ERR("%s: none of the specified ports exist; "
 -                 "disabling port mirror %s", pfx, pfx);
 +    shash_init(&src_ports);
 +    shash_init(&dst_ports);
 +    mirror_collect_ports(m, cfg->select_src_port, cfg->n_select_src_port,
 +                         &src_ports);
 +    mirror_collect_ports(m, cfg->select_dst_port, cfg->n_select_dst_port,
 +                         &dst_ports);
 +    any_ports_specified = cfg->n_select_dst_port || cfg->n_select_dst_port;
 +    if (any_ports_specified
 +        && shash_is_empty(&src_ports) && shash_is_empty(&dst_ports)) {
 +        VLOG_ERR("bridge %s: disabling mirror %s since none of the specified "
 +                 "selection ports exists", m->bridge->name, m->name);
          mirror_destroy(m);
          goto exit;
      }
  
      /* Get all the vlans, and drop duplicate and invalid vlans. */
 -    svec_init(&vlan_strings);
 -    cfg_get_all_keys(&vlan_strings, "%s.select.vlan", pfx);
 -    n_vlans = prune_vlans(m, &vlan_strings, &vlans);
 -    svec_destroy(&vlan_strings);
 +    n_vlans = mirror_collect_vlans(m, cfg, &vlans);
 +    any_vlans_specified = cfg->n_select_vlan > 0;
 +    if (any_vlans_specified && !n_vlans) {
 +        VLOG_ERR("bridge %s: disabling mirror %s since none of the specified "
 +                 "VLANs exists", m->bridge->name, m->name);
 +        mirror_destroy(m);
 +        goto exit;
 +    }
  
      /* Update mirror data. */
 -    if (!svec_equal(&m->src_ports, &src_ports)
 -        || !svec_equal(&m->dst_ports, &dst_ports)
 +    if (!shash_equal_keys(&m->src_ports, &src_ports)
 +        || !shash_equal_keys(&m->dst_ports, &dst_ports)
          || m->n_vlans != n_vlans
          || memcmp(m->vlans, vlans, sizeof *vlans * n_vlans)
          || m->out_port != out_port
          || m->out_vlan != out_vlan) {
          bridge_flush(m->bridge);
      }
 -    svec_swap(&m->src_ports, &src_ports);
 -    svec_swap(&m->dst_ports, &dst_ports);
 +    shash_swap(&m->src_ports, &src_ports);
 +    shash_swap(&m->dst_ports, &dst_ports);
      free(m->vlans);
      m->vlans = vlans;
      m->n_vlans = n_vlans;
      m->out_vlan = out_vlan;
  
      /* If no selection criteria have been given, mirror for all ports. */
 -    mirror_all_ports = (!m->src_ports.n) && (!m->dst_ports.n) && (!m->n_vlans);
 +    mirror_all_ports = !any_ports_specified && !any_vlans_specified;
  
      /* Update ports. */
      mirror_bit = MIRROR_MASK_C(1) << m->idx;
          struct port *port = m->bridge->ports[i];
  
          if (mirror_all_ports
 -            || svec_contains(&m->src_ports, port->name)
 +            || shash_find(&m->src_ports, port->name)
              || (m->n_vlans
                  && (!port->vlan
                      ? port_trunks_any_mirrored_vlan(m, port)
              port->src_mirrors &= ~mirror_bit;
          }
  
 -        if (mirror_all_ports || svec_contains(&m->dst_ports, port->name)) {
 +        if (mirror_all_ports || shash_find(&m->dst_ports, port->name)) {
              port->dst_mirrors |= mirror_bit;
          } else {
              port->dst_mirrors &= ~mirror_bit;
  
      /* Clean up. */
  exit:
 -    svec_destroy(&src_ports);
 -    svec_destroy(&dst_ports);
 -    free(pfx);
 -}
 -\f
 -/* Spanning tree protocol. */
 -
 -static void brstp_update_port_state(struct port *);
 -
 -static void
 -brstp_send_bpdu(struct ofpbuf *pkt, int port_no, void *br_)
 -{
 -    struct bridge *br = br_;
 -    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 -    struct iface *iface = iface_from_dp_ifidx(br, port_no);
 -    if (!iface) {
 -        VLOG_WARN_RL(&rl, "%s: cannot send BPDU on unknown port %d",
 -                     br->name, port_no);
 -    } else {
 -        struct eth_header *eth = pkt->l2;
 -
 -        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);
 -
 -            flow_extract(pkt, ODPP_NONE, &flow);
 -            ofproto_send_packet(br->ofproto, &flow, &action, 1, pkt);
 -        }
 -    }
 -    ofpbuf_delete(pkt);
 -}
 -
 -static void
 -brstp_reconfigure(struct bridge *br)
 -{
 -    size_t i;
 -
 -    if (!cfg_get_bool(0, "stp.%s.enabled", br->name)) {
 -        if (br->stp) {
 -            stp_destroy(br->stp);
 -            br->stp = NULL;
 -
 -            bridge_flush(br);
 -        }
 -    } else {
 -        uint64_t bridge_address, bridge_id;
 -        int bridge_priority;
 -
 -        bridge_address = cfg_get_mac(0, "stp.%s.address", br->name);
 -        if (!bridge_address) {
 -            if (br->stp) {
 -                bridge_address = (stp_get_bridge_id(br->stp)
 -                                  & ((UINT64_C(1) << 48) - 1));
 -            } else {
 -                uint8_t mac[ETH_ADDR_LEN];
 -                eth_addr_random(mac);
 -                bridge_address = eth_addr_to_uint64(mac);
 -            }
 -        }
 -
 -        if (cfg_is_valid(CFG_INT | CFG_REQUIRED, "stp.%s.priority",
 -                         br->name)) {
 -            bridge_priority = cfg_get_int(0, "stp.%s.priority", br->name);
 -        } else {
 -            bridge_priority = STP_DEFAULT_BRIDGE_PRIORITY;
 -        }
 -
 -        bridge_id = bridge_address | ((uint64_t) bridge_priority << 48);
 -        if (!br->stp) {
 -            br->stp = stp_create(br->name, bridge_id, brstp_send_bpdu, br);
 -            br->stp_last_tick = time_msec();
 -            bridge_flush(br);
 -        } else {
 -            if (bridge_id != stp_get_bridge_id(br->stp)) {
 -                stp_set_bridge_id(br->stp, bridge_id);
 -                bridge_flush(br);
 -            }
 -        }
 -
 -        for (i = 0; i < br->n_ports; i++) {
 -            struct port *p = br->ports[i];
 -            int dp_ifidx;
 -            struct stp_port *sp;
 -            int path_cost, priority;
 -            bool enable;
 -
 -            if (!p->n_ifaces) {
 -                continue;
 -            }
 -            dp_ifidx = p->ifaces[0]->dp_ifidx;
 -            if (dp_ifidx < 0 || dp_ifidx >= STP_MAX_PORTS) {
 -                continue;
 -            }
 -
 -            sp = stp_get_port(br->stp, dp_ifidx);
 -            enable = (!cfg_is_valid(CFG_BOOL | CFG_REQUIRED,
 -                                    "stp.%s.port.%s.enabled",
 -                                    br->name, p->name)
 -                      || cfg_get_bool(0, "stp.%s.port.%s.enabled",
 -                                      br->name, p->name));
 -            if (p->is_mirror_output_port) {
 -                enable = false;
 -            }
 -            if (enable != (stp_port_get_state(sp) != STP_DISABLED)) {
 -                bridge_flush(br); /* Might not be necessary. */
 -                if (enable) {
 -                    stp_port_enable(sp);
 -                } else {
 -                    stp_port_disable(sp);
 -                }
 -            }
 -
 -            path_cost = cfg_get_int(0, "stp.%s.port.%s.path-cost",
 -                                    br->name, p->name);
 -            stp_port_set_path_cost(sp, path_cost ? path_cost : 19 /* XXX */);
 -
 -            priority = (cfg_is_valid(CFG_INT | CFG_REQUIRED,
 -                                     "stp.%s.port.%s.priority",
 -                                     br->name, p->name)
 -                        ? cfg_get_int(0, "stp.%s.port.%s.priority",
 -                                      br->name, p->name)
 -                        : STP_DEFAULT_PORT_PRIORITY);
 -            stp_port_set_priority(sp, priority);
 -        }
 -
 -        brstp_adjust_timers(br);
 -    }
 -    for (i = 0; i < br->n_ports; i++) {
 -        brstp_update_port_state(br->ports[i]);
 -    }
 -}
 -
 -static void
 -brstp_update_port_state(struct port *p)
 -{
 -    struct bridge *br = p->bridge;
 -    enum stp_state state;
 -
 -    /* Figure out new state. */
 -    state = STP_DISABLED;
 -    if (br->stp && p->n_ifaces > 0) {
 -        int dp_ifidx = p->ifaces[0]->dp_ifidx;
 -        if (dp_ifidx >= 0 && dp_ifidx < STP_MAX_PORTS) {
 -            state = stp_port_get_state(stp_get_port(br->stp, dp_ifidx));
 -        }
 -    }
 -
 -    /* Update state. */
 -    if (p->stp_state != state) {
 -        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 10);
 -        VLOG_INFO_RL(&rl, "port %s: STP state changed from %s to %s",
 -                     p->name, stp_state_name(p->stp_state),
 -                     stp_state_name(state));
 -        if (p->stp_state == STP_DISABLED) {
 -            bridge_flush(br);
 -        } else {
 -            ofproto_revalidate(p->bridge->ofproto, p->stp_state_tag);
 -        }
 -        p->stp_state = state;
 -        p->stp_state_tag = (p->stp_state == STP_DISABLED ? 0
 -                            : tag_create_random());
 -    }
 -}
 -
 -static void
 -brstp_adjust_timers(struct bridge *br)
 -{
 -    int hello_time = cfg_get_int(0, "stp.%s.hello-time", br->name);
 -    int max_age = cfg_get_int(0, "stp.%s.max-age", br->name);
 -    int forward_delay = cfg_get_int(0, "stp.%s.forward-delay", br->name);
 -
 -    stp_set_hello_time(br->stp, hello_time ? hello_time : 2000);
 -    stp_set_max_age(br->stp, max_age ? max_age : 20000);
 -    stp_set_forward_delay(br->stp, forward_delay ? forward_delay : 15000);
 -}
 -
 -static void
 -brstp_run(struct bridge *br)
 -{
 -    if (br->stp) {
 -        long long int now = time_msec();
 -        long long int elapsed = now - br->stp_last_tick;
 -        struct stp_port *sp;
 -
 -        if (elapsed > 0) {
 -            stp_tick(br->stp, MIN(INT_MAX, elapsed));
 -            br->stp_last_tick = now;
 -        }
 -        while (stp_get_changed_port(br->stp, &sp)) {
 -            struct port *p = port_from_dp_ifidx(br, stp_port_no(sp));
 -            if (p) {
 -                brstp_update_port_state(p);
 -            }
 -        }
 -    }
 -}
 -
 -static void
 -brstp_wait(struct bridge *br)
 -{
 -    if (br->stp) {
 -        poll_timer_wait(1000);
 -    }
 +    shash_destroy(&src_ports);
 +    shash_destroy(&dst_ports);
  }
@@@ -12,25 -12,21 +12,25 @@@ ovs\-vswitchd \- Open vSwitch daemo
  .
  .SH SYNOPSIS
  .B ovs\-vswitchd
 -\fIconfig\fR
 +\fIdatabase\fR
  .
  .SH DESCRIPTION
  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
 -\fBovs\-vswitchd.conf\fR(5).
 +The mandatory \fIdatabase\fR argument specifies the
 +\fBovsdb\-server\fR from which \fBovs\-vswitchd\fR's configuration
 +should be retrieved.  It takes one of the following forms:
 +.so ovsdb/remote-active.man
  .PP
 -At startup or upon receipt of a \fBSIGHUP\fR signal, \fBovs\-vswitchd\fR
 -reads the configuration file.  It sets up Open vSwitch datapaths and then 
 -operates switching across each bridge described in its configuration 
 -files.  If a logfile was specified on the command line it will also 
 -be opened or reopened.
 +\fBovs\-vswitchd\fR retrieves its configuration from \fIdatabase\fR at
 +startup.  It sets up Open vSwitch datapaths and then operates
 +switching across each bridge described in its configuration files.  As
 +the database changes, \fBovs\-vswitchd\fR automatically updates its
 +configuration to match.
 +.PP
 +Upon receipt of a SIGHUP signal, \fBovs\-vswitchd\fR reopens its log
 +file, if one was specified on the command line.
  .PP
  \fBovs\-vswitchd\fR switches may be configured with any of the following 
  features:
@@@ -52,6 -48,9 +52,9 @@@ Port mirroring, with optional VLAN tagg
  NetFlow v5 flow logging.
  .
  .IP \(bu
+ sFlow(R) monitoring.
+ .
+ .IP \(bu
  Connectivity to an external OpenFlow controller, such as NOX.
  .
  .PP
@@@ -79,8 -78,6 +82,8 @@@ actually in use.  It requires the \fBbr
  to be loaded.
  .
  .so lib/daemon.man
 +.so lib/ssl.man
 +.so lib/ssl-bootstrap.man
  .so lib/vlog.man
  .so lib/common.man
  .so lib/leak-checker.man
  \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.
 +how to configure Open vSwitch.
  .SS "BRIDGE COMMANDS"
  These commands manage bridges.
  .IP "\fBfdb/show\fR \fIbridge\fR"
@@@ -151,6 -157,6 +154,6 @@@ Returns the hash value which would be u
  .so lib/vlog-unixctl.man
  .SH "SEE ALSO"
  .BR ovs\-appctl (8),
 -.BR ovs\-vswitchd.conf (5),
  .BR ovs\-brcompatd (8),
 +.BR ovsdb\-server (1),
  \fBINSTALL.Linux\fR in the Open vSwitch distribution.
diff --combined vswitchd/vswitch-idl.ann
index ff5766a,0000000..b8e457d
mode 100644,000000..100644
--- /dev/null
@@@ -1,20 -1,0 +1,21 @@@
 +# -*- python -*-
 +
 +# This code, when invoked by "ovsdb-idlc annotate" (by the build
 +# process), annotates vswitch.ovsschema with additional data that give
 +# the ovsdb-idl engine information about the types involved, so that
 +# it can generate more programmer-friendly data structures.
 +
 +s["idlPrefix"] = "ovsrec_"
 +s["idlHeader"] = "\"vswitchd/vswitch-idl.h\""
 +s["tables"]["Open_vSwitch"]["columns"]["bridges"]["type"]["keyRefTable"] = "Bridge"
 +s["tables"]["Open_vSwitch"]["columns"]["controller"]["type"]["keyRefTable"] = "Controller"
 +s["tables"]["Open_vSwitch"]["columns"]["ssl"]["type"]["keyRefTable"] = "SSL"
 +s["tables"]["Bridge"]["columns"]["ports"]["type"]["keyRefTable"] = "Port"
 +s["tables"]["Bridge"]["columns"]["mirrors"]["type"]["keyRefTable"] = "Mirror"
 +s["tables"]["Bridge"]["columns"]["netflow"]["type"]["keyRefTable"] = "NetFlow"
++s["tables"]["Bridge"]["columns"]["sflow"]["type"]["keyRefTable"] = "sFlow"
 +s["tables"]["Bridge"]["columns"]["controller"]["type"]["keyRefTable"] = "Controller"
 +s["tables"]["Port"]["columns"]["interfaces"]["type"]["keyRefTable"] = "Interface"
 +s["tables"]["Mirror"]["columns"]["select_src_port"]["type"]["keyRefTable"] = "Port"
 +s["tables"]["Mirror"]["columns"]["select_dst_port"]["type"]["keyRefTable"] = "Port"
 +s["tables"]["Mirror"]["columns"]["output_port"]["type"]["keyRefTable"] = "Port"
index 7b0a539,0000000..022d65f
mode 100644,000000..100644
--- /dev/null
@@@ -1,216 -1,0 +1,237 @@@
 +{"name": "ovs_vswitchd_db",
 + "comment": "Configuration for one Open vSwitch daemon.",
 + "tables": {
 +   "Open_vSwitch": {
 +     "comment": "Configuration for an Open vSwitch daemon.",
 +     "columns": {
 +       "bridges": {
 +         "comment": "Set of bridges managed by the daemon.",
 +         "type": {"key": "uuid", "min": 0, "max": "unlimited"}},
 +       "controller": {
 +         "comment": "Default Controller used by bridges.",
 +         "type": {"key": "uuid", "min": 0, "max": 1}},
 +       "managers": {
 +         "comment": "Remote database clients to which the Open vSwitch's database server should connect or to which it should listen.",
 +         "type": {"key": "string", "min": 0, "max": "unlimited"}},
 +       "ssl": {
 +         "comment": "SSL used globally by the daemon.",
 +         "type": {"key": "uuid", "min": 0, "max": 1}},
 +       "next_cfg": {
 +         "comment": "Sequence number for client to increment when it modifies the configuration and wishes to wait for Open vSwitch to finish applying the changes.",
 +         "type": "integer"},
 +       "cur_cfg": {
 +         "comment": "Sequence number that Open vSwitch sets to the current value of 'next_cfg' after it finishing applying a set of configuration changes.",
 +         "type": "integer"}}},
 +   "Bridge": {
 +     "comment": "Configuration for a bridge within an Open_vSwitch.",
 +     "columns": {
 +       "name": {
 +         "comment": "Bridge identifier.  Should be alphanumeric and no more than about 8 bytes long.  Must be unique among the names of ports, interfaces, and bridges on a host.",
 +         "type": "string"},
 +       "datapath_type": {
 +         "comment": "Name of datapath provider.  The kernel datapath has type \"system\".  The userspace datapath has type \"netdev\".",
 +         "type": "string"},
 +       "datapath_id": {
 +         "comment": "Reports the OpenFlow datapath ID in use.  Exactly 12 hex digits.",
 +         "type": {"key": "string", "min": 0, "max": 1},
 +         "ephemeral": true},
 +       "ports": {
 +         "comment": "Ports included in the bridge.",
 +         "type": {"key": "uuid", "min": 0, "max": "unlimited"}},
 +       "mirrors": {
 +         "comment": "Port mirroring configuration.",
 +         "type": {"key": "uuid", "min": 0, "max": "unlimited"}},
 +       "netflow": {
 +         "comment": "NetFlow configuration.",
 +         "type": {"key": "uuid", "min": 0, "max": 1}},
++       "sflow": {
++         "comment": "sFlow configuration.",
++         "type": {"key": "uuid", "min": 0, "max": 1}},
 +       "controller": {
 +         "comment": "OpenFlow controller.  If unset, defaults to that specified by the parent Open_vSwitch.",
 +         "type": {"key": "uuid", "min": 0, "max": 1}},
 +       "other_config": {
 +         "comment": "Key-value pairs for configuring rarely used bridge features.  The currently defined key-value pairs are: \"datapath-id\", exactly 12 hex digits to set the OpenFlow datapath ID to a specific value; \"hwaddr\", exactly 12 hex digits in the form \"XX:XX:XX:XX:XX:XX\" to set the hardware address of the local port and influence the datapath ID.",
 +         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
 +       "external_ids": {
 +         "comment": "Key-value pairs that identify this bridge's role in external systems.  The currently defined key-value pairs are: \"xs-network-uuids\", a space-delimited set of the Citrix XenServer network UUIDs with which this bridge is associated; \"xs-network-names\", a semicolon-delimited set of Citrix XenServer network names with which this bridge is associated.",
 +         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
 +       "flood_vlans": {
 +         "comment": "VLAN IDs of VLANs on which MAC address learning should be disabled, so that packets are flooded instead of being sent to specific ports that are believed to contain packets' destination MACs.  This should ordinarily be used to disable MAC learning on VLANs used for mirroring (RSPAN VLANs).  It may also be useful for debugging.",
 +         "type": {"key": "integer", "min": 0, "max": 4096}
 +}}},
 +   "Port": {
 +     "comment": "A port within a Bridge.  May contain a single Interface or multiple (bonded) Interfaces.",
 +     "columns": {
 +       "name": {
 +         "comment": "Port name.  Should be alphanumeric and no more than about 8 bytes long.    May be the same as the interface name, for non-bonded ports.  Must otherwise be unique among the names of ports, interfaces, and bridges on a host.",
 +         "type": "string"},
 +       "interfaces": {
 +         "comment": "The Port's Interfaces.  If there is more than one, this is a bonded Port.",
 +         "type": {"key": "uuid", "min": 1, "max": "unlimited"}},
 +       "trunks": {
 +         "comment": "The 802.1Q VLAN(s) that this port trunks.  Should be empty if this port trunks all VLAN(s) or if this is not a trunk port.",
 +         "type": {"key": "integer", "min": 0, "max": 4096}},
 +       "tag": {
 +         "comment": "This port's implicitly tagged VLAN.  Should be empty if this is a trunk port.",
 +         "type": {"key": "integer", "min": 0, "max": 1}},
 +       "mac": {
 +         "comment": "The MAC address to use for this port for the purpose of choosing the bridge's MAC address.  This column does not necessarily reflect the port's actual MAC address, nor will setting it change the port's actual MAC address.  Exactly 12 hex digits in the form XX:XX:XX:XX:XX:XX.",
 +         "type": {"key": "string", "min": 0, "max": 1}},
 +       "bond_updelay": {
 +         "comment": "For a bonded port, the number of milliseconds for which carrier must stay up on an interface before the interface is considered to be up.  Ignored for non-bonded ports.",
 +         "type": "integer"},
 +       "bond_downdelay": {
 +         "comment": "For a bonded port, the number of milliseconds for which carrier must stay down on an interface before the interface is considered to be down.  Ignored for non-bonded ports.",
 +         "type": "integer"},
 +       "bond_fake_iface": {
 +         "comment": "For a bonded port, whether to create a fake interface with the name of the port.  Use only for compatibility with legacy software that requires this.",
 +         "type": "boolean"},
 +       "fake_bridge": {
 +         "comment": "Does this port represent a sub-bridge for its tagged VLAN within the Bridge?  See ovs-vsctl(8) for more information.",
 +         "type": "boolean"},
 +       "other_config": {
 +         "comment": "Key-value pairs for configuring rarely used port features.  The currently defined key-value pairs are: \"hwaddr\", exactly 12 hex digits in the form \"XX:XX:XX:XX:XX:XX\".",
 +         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
 +       "external_ids": {
 +         "comment": "Key-value pairs that identify this port's role in external systems.  No key-value pairs native to Port are currently defined.  For fake bridges (see the \"fake-bridge\" column), external IDs for the fake bridge are defined here by prefixing their keys with \"fake-bridge\", e.g. \"fake-bridge-xs-network-uuids\".",
 +         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}},
 +   "Interface": {
 +     "comment": "An interface within a Port.",
 +     "columns": {
 +       "name": {
 +         "comment": "Interface name.  Should be alphanumeric and no more than about 8 bytes long.  May be the same as the port name, for non-bonded ports.  Must otherwise be unique among the names of ports, interfaces, and bridges on a host.",
 +         "type": "string"},
 +       "type": {
 +         "comment": "The interface type.  Normal network devices, e.g.  eth0, have type \"system\" or \"\" (which are synonyms).  Internal ports have type \"internal\".  TUN/TAP devices have type \"tap\".  GRE devices have type \"gre\".",
 +         "type": "string"},
 +       "options": {
 +         "comment": "Configuration options whose interpretation varies based on \"type\".",
 +         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
 +       "ingress_policing_rate": {
 +         "comment": "Maximum rate for data received on this interface, in kbps.  Set to 0 to disable policing.",
 +         "type": "integer"},
 +       "ingress_policing_burst": {
 +         "comment": "Maximum burst size for data received on this interface, in kb.  The default burst size if set to 0 is 1000 kb.",
 +         "type": "integer"},
 +       "mac": {
 +         "comment": "Ethernet address to set for this interface.  If unset then the default MAC address is used.  May not be supported on all interfaces.  Exactly 12 hex digits in the form XX:XX:XX:XX:XX:XX.",
 +         "type": {"key": "string", "min": 0, "max": 1}},
 +       "external_ids": {
 +         "comment": "Key-value pairs that identify this interface's role in external systems.  The currently defined key-value pairs are: \"xs-vif-uuid\", the UUID of the Citrix XenServer VIF associated with this interface; \"xs-network-uuid\", the UUID of the Citrix XenServer network to which this interface is attached; \"xs-vif-vm-uuid\", the UUID of the Citrix XenServer VM to which this interface belongs; \"xs-vif-mac\", the value of the \"MAC\" field in the Citrix XenServer VIF record for this interface.",
 +         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
 +       "ofport": {
 +         "comment": "OpenFlow port number for this interface.  This is populated when the port number becomes known.  Before it is populated its value will be missing.  If the interface cannot be added then this is indicated by a value of -1.",
 +         "type": {"key": "integer", "min": 0, "max": 1},
 +         "ephemeral": true}}},
 +   "Mirror": {
 +     "comment": "A port mirror within a Bridge.",
 +     "columns": {
 +       "name": {
 +         "comment": "Arbitrary identifier for the Mirror.",
 +         "type": "string"},
 +       "select_src_port": {
 +         "comment": "Ports on which arriving packets are selected for mirroring.",
 +         "type": {"key": "uuid", "min": 0, "max": "unlimited"}},
 +       "select_dst_port": {
 +         "comment": "Ports on which departing packets are selected for mirroring.",
 +         "type": {"key": "uuid", "min": 0, "max": "unlimited"}},
 +       "select_vlan": {
 +         "comment": "VLANs on which packets are selected for mirroring.",
 +         "type": {"key": "integer", "min": 0, "max": 4096}},
 +       "output_port": {
 +         "comment": "Output port for selected packets.  Mutually exclusive with output_vlan.",
 +         "type": {"key": "uuid", "min": 0, "max": 1}},
 +       "output_vlan": {
 +         "comment": "Output VLAN for selected packets.  Mutually exclusive with output_port.",
 +         "type": {"key": "integer", "min": 0, "max": 1}}}},
 +   "NetFlow": {
 +     "comment": "A NetFlow target.",
 +     "columns": {
 +       "targets": {
 +         "comment": "NetFlow targets in the form \"IP:PORT\".",
 +         "type": {"key": "string", "min": 1, "max": "unlimited"}},
 +       "engine_type": {
 +         "comment": "Engine type to use in NetFlow messages.  Defaults to datapath index if not specified.",
 +         "type": {"key": "integer", "min": 0, "max": 1}},
 +       "engine_id": {
 +         "comment": "Engine ID to use in NetFlow messages.  Defaults to datapath index if not specified.",
 +         "type": {"key": "integer", "min": 0, "max": 1}},
 +       "add_id_to_interface": {
 +         "comment": "Place least-significant 7 bits of engine ID into most significant bits of ingress and egress interface fields of NetFlow records?",
 +         "type": "boolean"},
 +       "active_timeout": {
 +         "comment": "Active timeout interval, in seconds.  A value of 0 requests the default timeout; a negative value disables active timeouts.",
 +         "type": "integer"}}},
++   "sFlow": {
++     "comment": "A sFlow target.",
++     "columns": {
++       "targets": {
++         "comment": "sFlow targets in the form \"IP:PORT\".",
++         "type": {"key": "string", "min": 1, "max": "unlimited"}},
++       "sampling": {
++         "comment": "Rate at which packets should be sampled and sent to the collector.  If not specified, defaults to 400, which means one out of 400, on average, will be sent to the collector.",
++         "type": {"key": "integer", "min": 0, "max": 1}},
++       "polling": {
++         "comment": "Polling rate in seconds to send port statistics to the collector.  If not specified, defaults to 30 seconds.",
++         "type": {"key": "integer", "min": 0, "max": 1}},
++       "header": {
++         "comment": "Number of bytes of a sampled packet to send to the collector.  If not specified, defaults is 128 bytes.",
++         "type": {"key": "integer", "min": 0, "max": 1}},
++       "agent": {
++         "comment": "IP address to report as \"agent address\" to collectors.  If not specified, defaults to collector's \"local_ip\" value.  If neither is specified, sFlow is disabled.",
++         "type": {"key": "string", "min": 0, "max": 1}}}},
 +   "Controller": {
 +     "comment": "An OpenFlow controller.",
 +     "columns": {
 +       "target": {
 +         "comment": "Connection method for controller, e.g. \"ssl:...\", \"tcp:...\".  The special string \"discover\" enables controller discovery.  The special string \"none\" disables the controller.",
 +         "type": "string"},
 +       "max_backoff": {
 +         "comment": "Maximum number of milliseconds to wait between connection attempts.  Default is implementation-specific.",
 +         "type": {"key": "integer", "min": 0, "max": 1}},
 +       "inactivity_probe": {
 +         "comment": "Maximum number of milliseconds of idle time on connection to controller before sending an inactivity probe message.  Default is implementation-specific.",
 +         "type": {"key": "integer", "min": 0, "max": 1}},
 +       "fail_mode": {
 +         "comment": "Either \"standalone\" or \"secure\", or empty to use the implementation's default.",
 +         "type": {"key": "string", "min": 0, "max": 1}},
 +       "discover_accept_regex": {
 +         "comment": "If \"target\" is \"discover\", a POSIX extended regular expression against which the discovered controller location is validated.  If not specified, the default is implementation-specific.",
 +         "type": {"key": "string", "min": 0, "max": 1}},
 +       "discover_update_resolv_conf": {
 +         "comment": "If \"target\" is \"discover\", whether to update /etc/resolv.conf when the controller is discovered.  If not specified, the default is implementation-specific.",
 +         "type": {"key": "boolean", "min": 0, "max": 1}},
 +       "connection_mode": {
 +         "comment": "Either \"in-band\" or \"out-of-band\".  If not specified, the default is implementation-specific.",
 +         "type": {"key": "string", "min": 0, "max": 1}},
 +       "local_ip": {
 +         "comment": "If \"target\" is not \"discover\", the IP address to configure on the local port.",
 +         "type": {"key": "string", "min": 0, "max": 1}},
 +       "local_netmask": {
 +         "comment": "If \"target\" is not \"discover\", the IP netmask to configure on the local port.",
 +         "type": {"key": "string", "min": 0, "max": 1}},
 +       "local_gateway": {
 +         "comment": "If \"target\" is not \"discover\", the IP gateway to configure on the local port.",
 +         "type": {"key": "string", "min": 0, "max": 1}},
 +       "controller_rate_limit": {
 +         "comment": "The maximum rate at which packets will be forwarded to the OpenFlow controller, in packets per second.  If not specified, the default is implementation-specific.",
 +         "type": {"key": "integer", "min": 0, "max": 1}},
 +       "controller_burst_limit": {
 +         "comment": "The maximum number of unused packet credits that the bridge will allow to accumulate, in packets.  If not specified, the default is implementation-specific.",
 +         "type": {"key": "integer", "min": 0, "max": 1}}}},
 +   "SSL": {
 +     "comment": "SSL configuration for an Open_vSwitch.",
 +     "columns": {
 +       "private_key": {
 +         "comment": "Name of a PEM file containing the private key used as the switch's identity for SSL connections to the controller.",
 +         "type": "string"},
 +       "certificate": {
 +         "comment": "Name of a PEM file containing a certificate, signed by the certificate authority (CA) used by the controller and manager, that certifies the switch's private key, identifying a trustworthy switch.",
 +         "type": "string"},
 +       "ca_cert": {
 +         "comment": "Name of a PEM file containing the CA certificate used to verify that the switch is connected to a trustworthy controller.",
 +         "type": "string"},
 +       "bootstrap_ca_cert": {
 +         "comment": "If set to true, then Open vSwitch will attempt to obtain the CA certificate from the controller on its first SSL connection and save it to the named PEM file. If it is successful, it will immediately drop the connection and reconnect, and from then on all SSL connections must be authenticated by a certificate signed by the CA certificate thus obtained.  This option exposes the SSL connection to a man-in-the-middle attack obtaining the initial CA certificate, but it may be useful for bootstrapping.",
 +         "type": "boolean"}}}}}
@@@ -5,7 -5,7 +5,7 @@@
  # chkconfig: 2345 09 91
  # description: Manage vswitch kernel modules and user-space daemon
  
 -# Copyright (C) 2009 Nicira Networks, Inc.
 +# Copyright (C) 2009, 2010 Nicira Networks, Inc.
  #
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
@@@ -26,27 -26,10 +26,27 @@@ test -e /etc/sysconfig/vswitch && . /et
  # General config variables in /etc/sysconfig/vswitch
  : ${ENABLE_BRCOMPAT:=y}
  : ${ENABLE_FAKE_PROC_NET:=y}
 +: ${ENABLE_MONITOR:=y}
  : ${FORCE_COREFILES:=y}
  
 +# Config variables specific to ovsdb-server
 +: ${OVSDB_SERVER_REMOTES:=punix:/var/run/ovsdb-server db:Open_vSwitch,managers}
 +: ${OVSDB_SERVER_DB:=/etc/ovs-vswitchd.conf.db}
 +: ${OVSDB_SERVER_PIDFILE:=/var/run/ovsdb-server.pid}
 +: ${OVSDB_SERVER_RUN_DIR:=/var/xen/vswitch}
 +: ${OVSDB_SERVER_PRIORITY:=-10}
 +: ${OVSDB_SERVER_LOGFILE:=/var/log/ovsdb-server.log}
 +: ${OVSDB_SERVER_FILE_LOGLEVEL:=INFO}
 +: ${OVSDB_SERVER_SYSLOG_LOGLEVEL:=ERR}
 +: ${OVSDB_SERVER_MEMLEAK_LOGFILE:=}
 +: ${OVSDB_SERVER_STRACE_LOG:=}
 +: ${OVSDB_SERVER_STRACE_OPT:=}
 +: ${OVSDB_SERVER_VALGRIND_LOG:=}
 +: ${OVSDB_SERVER_VALGRIND_OPT:=}
 +
  # Config variables specific to ovs-vswitchd
 -: ${VSWITCHD_CONF:=/etc/ovs-vswitchd.conf}
 +: ${VSWITCHD_OVSDB_SERVER:=unix:/var/run/ovsdb-server}
 +: ${VSWITCHD_OVSDB_SCHEMA:=/usr/share/vswitch/vswitch.ovsschema}
  : ${VSWITCHD_PIDFILE:=/var/run/ovs-vswitchd.pid}
  : ${VSWITCHD_RUN_DIR:=/var/xen/vswitch}
  : ${VSWITCHD_PRIORITY:=-10}
  : ${BRCOMPATD_VALGRIND_OPT:=}
  
  # Full paths to executables & modules
 +ovsdb_server="/usr/sbin/ovsdb-server"
 +ovsdb_tool="/usr/bin/ovsdb-tool"
  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"
 -
 +vsctl="/usr/bin/ovs-vsctl"
  
  if [ "$ENABLE_FAKE_PROC_NET" = "y" ]; then
      if [ "$ENABLE_BRCOMPAT" != "y" ]; then
      fi
  fi
  
 +if test "$ENABLE_MONITOR" = "y"; then
 +    monitor_opt="--monitor"
 +else
 +    monitor_opt=
 +fi
 +
  function dp_list {
      "$dpctl" show | grep '^dp[0-9]\+:' | cut -d':' -f 1
  }
@@@ -117,9 -92,6 +117,9 @@@ function insert_modules_if_required 
      if [ -n "$BRCOMPATD_PIDFILE" ] && ! lsmod | grep -q "brcompat_mod"; then
          action "Inserting brcompat module" modprobe brcompat_mod
      fi
 +    if [ -f "/lib/modules/`uname -r`/kernel/net/vswitch/ip_gre_mod.ko" ] && ! lsmod | grep -q "ip_gre_mod"; then
 +        action "Inserting ip_gre module" modprobe ip_gre_mod
 +    fi
  }
  
  function remove_modules {
      if lsmod | grep -q "openvswitch_mod"; then
          action "Removing openvswitch module" rmmod openvswitch_mod.ko
      fi
 -}
 -
 -function reload_vswitchd {
 -    if [ -f "$VSWITCHD_PIDFILE" ]; then
 -        "$appctl" --target=/var/run/ovs-vswitchd.`cat $VSWITCHD_PIDFILE`.ctl vswitchd/reload
 +    if lsmod | grep -q "ip_gre_mod"; then
 +        action "Removing ip_gre module" rmmod ip_gre_mod.ko
      fi
  }
  
 -function reload_brcompatd {
 -    if [ -f "$BRCOMPATD_PIDFILE" ]; then
 -        "$appctl" --target=/var/run/ovs-brcompatd.`cat $BRCOMPATD_PIDFILE`.ctl vlog/reopen
 +function start_ovsdb_server {
 +    local syslog_opt="-vANY:SYSLOG:${OVSDB_SERVER_SYSLOG_LOGLEVEL}"
 +    local logfile_file_opt=""
 +    local logfile_level_opt=""
 +    if [ ! -d "$OVSDB_SERVER_RUN_DIR" ]; then
 +        mkdir -p "$OVSDB_SERVER_RUN_DIR"
 +    fi
 +    cd "$OVSDB_SERVER_RUN_DIR"
 +    local remotes=
 +    for remote in $OVSDB_SERVER_REMOTES; do
 +        remotes="$remotes --remote=$remote"
 +    done
 +    if [ -n "$OVSDB_SERVER_FILE_LOGLEVEL" ]; then
 +        logfile_level_opt="-vANY:FILE:${OVSDB_SERVER_FILE_LOGLEVEL}"
 +        logfile_file_opt="--log-file=$OVSDB_SERVER_LOGFILE"
 +    fi
 +    local leak_opt=""
 +    if [ -n "$OVSDB_SERVER_MEMLEAK_LOGFILE" ]; then
 +        leak_opt="--check-leaks=$OVSDB_SERVER_MEMLEAK_LOGFILE"
 +        if [ -e "$OVSDB_SERVER_MEMLEAK_LOGFILE" ]; then
 +            mv "$OVSDB_SERVER_MEMLEAK_LOGFILE" "$OVSDB_SERVER_MEMLEAK_LOGFILE.prev"
 +        fi
 +    fi
 +    local strace_opt=""
 +    local daemonize="y"
 +    if [ -n "$OVSDB_SERVER_STRACE_LOG" ] && [ -n "$OVSDB_SERVER_VALGRIND_LOG" ]; then
 +        printf "Can not start with both VALGRIND and STRACE\n"
 +        exit 1
 +    fi
 +    if [ -n "$OVSDB_SERVER_STRACE_LOG" ]; then
 +        strace_opt="strace -o $OVSDB_SERVER_STRACE_LOG $OVSDB_SERVER_STRACE_OPT"
 +        daemonize="n"
 +    fi
 +    if [ -n "$OVSDB_SERVER_VALGRIND_LOG" ]; then
 +        valgrind_opt="valgrind --log-file=$OVSDB_SERVER_VALGRIND_LOG $OVSDB_SERVER_VALGRIND_OPT"
 +        daemonize="n"
 +    fi
 +    if [ "$daemonize" != "y" ]; then
 +        # Start in background and force a "success" message
 +        action "Starting ovsdb_server ($strace_opt$valgrind_opt)" true
 +        (nice -n "$OVSDB_SERVER_PRIORITY" $strace_opt $valgrind_opt "$ovsdb_server" "$OVSDB_SERVER_DB" --pidfile="$OVSDB_SERVER_PIDFILE" --detach $monitor_opt --no-chdir -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt $remotes) &
 +    else
 +        action "Starting ovsdb-server" nice -n "$OVSDB_SERVER_PRIORITY" "$ovsdb_server" "$OVSDB_SERVER_DB" --pidfile="$OVSDB_SERVER_PIDFILE" --detach $monitor_opt --no-chdir -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt $remotes
      fi
  }
  
@@@ -220,9 -155,9 +220,9 @@@ function start_vswitchd 
      if [ "$daemonize" != "y" ]; then
          # Start in background and force a "success" message
          action "Starting ovs-vswitchd ($strace_opt$valgrind_opt)" true
 -        (nice -n "$VSWITCHD_PRIORITY" $strace_opt $valgrind_opt "$vswitchd" --pidfile="$VSWITCHD_PIDFILE" --detach --no-chdir $fake_proc_net_opt -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt "$VSWITCHD_CONF") &
 +        (nice -n "$VSWITCHD_PRIORITY" $strace_opt $valgrind_opt "$vswitchd" --pidfile="$VSWITCHD_PIDFILE" --detach $monitor_opt --no-chdir $fake_proc_net_opt -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt "$VSWITCHD_OVSDB_SERVER") &
      else
 -        action "Starting ovs-vswitchd" nice -n "$VSWITCHD_PRIORITY" "$vswitchd" --pidfile="$VSWITCHD_PIDFILE" --detach --no-chdir $fake_proc_net_opt -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt "$VSWITCHD_CONF"
 +        action "Starting ovs-vswitchd" nice -n "$VSWITCHD_PRIORITY" "$vswitchd" --pidfile="$VSWITCHD_PIDFILE" --detach $monitor_opt --no-chdir $fake_proc_net_opt -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt "$VSWITCHD_OVSDB_SERVER"
      fi
  }
  
@@@ -239,7 -174,7 +239,7 @@@ function start_brcompatd 
          logfile_file_opt="--log-file=$BRCOMPATD_LOGFILE"
      fi
      local leak_opt=""
 -    if [ -n "$BRCOMPATD_MEMLEAK_LOG" ]; then
 +    if [ -n "$BRCOMPATD_MEMLEAK_LOGFILE" ]; then
          leak_opt="--check-leaks=$BRCOMPATD_MEMLEAK_LOGFILE"
          if [ -e "$BRCOMPATD_MEMLEAK_LOGFILE" ]; then
              mv "$BRCOMPATD_MEMLEAK_LOGFILE" "$BRCOMPATD_MEMLEAK_LOGFILE.prev"
      if [ "$daemonize" != "y" ]; then
          # Start in background and force a "success" message
          action "Starting ovs-brcompatd ($strace_opt$valgrind_opt)" true
 -        (nice -n "$VSWITCHD_PRIORITY" $strace_opt $valgrind_opt "$brcompatd"--no-chdir --appctl-command="$appctl_cmd" --pidfile=$BRCOMPATD_PIDFILE -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt "$VSWITCHD_CONF") &
 +        (nice -n "$VSWITCHD_PRIORITY" $strace_opt $valgrind_opt "$brcompatd"--no-chdir --appctl-command="$appctl_cmd" --pidfile=$BRCOMPATD_PIDFILE -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt "$VSWITCHD_OVSDB_SERVER") &
      else
 -        action "Starting ovs-brcompatd" nice -n "$BRCOMPATD_PRIORITY" $strace_opt $valgrind_opt "$brcompatd" --no-chdir --appctl-command="$appctl_cmd" --pidfile=$BRCOMPATD_PIDFILE --detach -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt "$VSWITCHD_CONF"
 +        action "Starting ovs-brcompatd" nice -n "$BRCOMPATD_PRIORITY" $strace_opt $valgrind_opt "$brcompatd" --no-chdir --appctl-command="$appctl_cmd" --pidfile=$BRCOMPATD_PIDFILE --detach $monitor_opt -vANY:CONSOLE:EMER $syslog_opt $logfile_level_opt $logfile_file_opt $leak_opt "$VSWITCHD_OVSDB_SERVER"
 +    fi
 +}
 +
 +function stop_ovsdb_server {
 +    if [ -f "$OVSDB_SERVER_PIDFILE" ]; then
 +        local pid=$(cat "$OVSDB_SERVER_PIDFILE")
 +        action "Killing ovsdb-server ($pid)" kill -TERM $pid
 +        rm -f "$OVSDB_SERVER_PIDFILE"
      fi
  }
  
@@@ -304,6 -231,8 +304,6 @@@ WARNING!!
  
  Restarting vswitch on a live server is not guaranteed to work.  It is
  provided as a convenience for those situations in which it does work.
 -If you just want to reload the configuration file, use "reload"
 -instead of restart.
  
  EOF
      read -s -r -n 1 -p "Countinue with restart (y/N): " response
@@@ -329,34 -258,29 +329,34 @@@ function start 
      # ovs-vswitchd needs a few per bridge
      ulimit -n 4096
  
 -    if [ ! -e "$VSWITCHD_CONF" ]; then
 -        warning "$VSWITCHD_CONF does not exist"
 -        action "Creating empty $VSWITCHD_CONF" touch "$VSWITCHD_CONF"
 -    elif [ ! -e /var/run/vswitch.booted ]; then
 +    # Allow GRE traffic.
 +    iptables -I INPUT -p gre -j ACCEPT
 +
 +    if [ ! -e "$OVSDB_SERVER_DB" ]; then
 +        warning "$OVSDB_SERVER_DB does not exist"
 +
 +        action "Creating empty database $OVSDB_SERVER_DB" true
 +        $ovsdb_tool -vANY:console:emer create "$OVSDB_SERVER_DB" "$VSWITCHD_OVSDB_SCHEMA"
 +    fi
 +
 +    start_ovsdb_server
 +    $vsctl --no-wait init
 +    if [ ! -e /var/run/vswitch.booted ]; then
          touch /var/run/vswitch.booted
 -        /usr/bin/ovs-cfg-mod '-vANY:console:emer' -F "$VSWITCHD_CONF" \
 -            '--del-match=bridge.*' \
 -            '--del-match=port.*' \
 -            '--del-match=bonding.*' \
 -            '--del-match=iface.*' \
 -            '--del-match=vlan.*.trunks=*' \
 -            '--del-match=vlan.*.tag=*'
 +        for bridge in $($vsctl list-br); do
 +            $vsctl --no-wait del-br $bridge
 +        done
      fi
  
      start_vswitchd
      start_brcompatd
 -    reload_vswitchd  # ensures ovs-vswitchd has fully read config file.
      touch /var/lock/subsys/vswitch
  }
  
  function stop {
      stop_brcompatd
      stop_vswitchd
 +    stop_ovsdb_server
      rm -f /var/lock/subsys/vswitch
  }
  
@@@ -377,6 -301,10 +377,6 @@@ case "$1" i
      restart)
          restart
          ;;
 -    reload)
 -        reload_vswitchd
 -        reload_brcompatd
 -        ;;
      strace-vswitchd)
          shift
          strace -p $(cat "$VSWITCHD_PIDFILE") "$@"
          strace -p $(cat "$BRCOMPATD_PIDFILE") "$@"
          ;;
      status)
-         status -p ovsdb-server.pid ovsdb-server
-         status -p ovs-vswitchd.pid ovs-vswitchd
-         status -p ovs-brcompatd.pid ovs-brcompatd
++        status -p "$OVSDB_SERVER_PIDFILE" ovsdb-server
+         status -p "$VSWITCHD_PIDFILE" ovs-vswitchd
+         status -p "$BRCOMPATD_PIDFILE" ovs-brcompatd
          ;;
      version)
 +        /usr/sbin/ovsdb-server -V
          /usr/sbin/ovs-vswitchd -V
          /usr/sbin/ovs-brcompatd -V
          ;;
      help)
 -        printf "vswitch [start|stop|restart|reload|unload|status|version]\n"
 +        printf "vswitch [start|stop|restart|unload|status|version]\n"
          ;;
      *)
          printf "Unknown command: $1\n"
  
  . /etc/init.d/functions
  
 -test -e /etc/sysconfig/vswitch && . /etc/sysconfig/vswitch
 -: ${VSWITCHD_CONF:=/etc/ovs-vswitchd.conf}
 -: ${VSWITCHD_PIDFILE:=/var/run/ovs-vswitchd.pid}
 -: ${VSWITCHD_PRIORITY:=-5}
 -: ${VSWITCHD_LOGFILE:=/var/log/ovs-vswitchd.log}
 -: ${VSWITCHD_FILE_LOGLEVEL:=}
 -: ${VSWITCHD_SYSLOG_LOGLEVEL:=WARN}
 -: ${VSWITCHD_MEMLEAK_LOGFILE:=}
 -: ${BRCOMPATD_PIDFILE:=/var/run/ovs-brcompatd.pid}
 -: ${BRCOMPATD_PRIORITY:=-5}
 -: ${BRCOMPATD_LOGFILE:=/var/log/ovs-brcompatd.log}
 -: ${BRCOMPATD_FILE_LOGLEVEL:=}
 -: ${BRCOMPATD_SYSLOG_LOGLEVEL:=WARN}
 -: ${BRCOMPATD_MEMLEAK_LOGFILE:=}
 -
  function do_host_call {
      xe host-call-plugin host-uuid="$INSTALLATION_UUID" plugin="vswitch-cfg-update" fn="update" >/dev/null
  }
  
  function start {
      if [ ! -f /etc/xensource-inventory ]; then
-         printf "vxwitch-xapi-update ERROR: XenSource inventory not present in /etc/xensource-inventory\n"
+         printf "vswitch-xapi-update ERROR: XenSource inventory not present in /etc/xensource-inventory\n"
          exit 1
      fi
      source /etc/xensource-inventory
@@@ -45,7 -60,7 +45,7 @@@ case "$1" i
          start
          ;;
      help)
 -        printf "vswitch [start|stop|restart]\n"
 +        printf "vswitch-xapi-update [start|stop|restart]\n"
          ;;
      *)
          printf "Unknown command: $1\n"
@@@ -1,7 -1,6 +1,6 @@@
  #!/bin/sh
  
  # Copyright (C) 2008,2009 Citrix Systems, Inc.
- # Copyright (C) 2009 Nicira Networks, Inc.
  #
  # This program is free software; you can redistribute it and/or modify
  # it under the terms of the GNU Lesser General Public License as published
  
  # Keep other-config/ keys in sync with device.ml:vif_udev_keys
  
 -cfg_mod="/usr/bin/ovs-cfg-mod"
+ BRCTL="/usr/sbin/brctl"
+ IP="/sbin/ip"
  vsctl="/usr/bin/ovs-vsctl"
 -service="/sbin/service"
 +dump_vif_details="/usr/share/vswitch/scripts/dump-vif-details"
- service="/sbin/service"
- TYPE=`echo ${XENBUS_PATH} | cut -f 2 -d '/'`
- DOMID=`echo ${XENBUS_PATH} | cut -f 3 -d '/'`
- DEVID=`echo ${XENBUS_PATH} | cut -f 4 -d '/'`
- XAPI=/xapi/${DOMID}/hotplug/${TYPE}/${DEVID}
- HOTPLUG=/xapi/${DOMID}/hotplug/${TYPE}/${DEVID}
- PRIVATE=/xapi/${DOMID}/private/${TYPE}/${DEVID}
- BRCTL=/usr/sbin/brctl
- IP=/sbin/ip
  
  handle_promiscuous()
  {
-     local arg=$(xenstore-read "${PRIVATE}/other-config/promiscuous")
+     local arg=$(xenstore-read "${PRIVATE}/other-config/promiscuous" 2>/dev/null)
      if [ $? -eq 0 -a -n "${arg}" ] ; then
-         case "${arg}" in 
-             true|on) logger -t script-vif "${vif}: Promiscuous ports are not supported via vSwitch." ;;
-             *) ;;
-         esac
+       case $NETWORK_MODE in
+           bridge)
+               case "${arg}" in 
+                   true|on) echo 1 > /sys/class/net/${dev}/brport/promisc ;;
+                   *) echo 0 > /sys/class/net/${dev}/brport/promisc ;;
+               esac
+               ;;
+           vswitch)
+               logger -t script-vif "${dev}: Promiscuous ports are not supported via vSwitch."
+               ;;
+       esac
      fi
  }
  
  handle_ethtool()
  {
      local opt=$1
-     local arg=$(xenstore-read "${PRIVATE}/other-config/ethtool-${opt}")
+     local arg=$(xenstore-read "${PRIVATE}/other-config/ethtool-${opt}" 2>/dev/null)
      if [ $? -eq 0 -a -n "${arg}" ] ; then
          case "${arg}" in
-             true|on)   /sbin/ethtool -K "${vif}" "${opt}" on ;;
-             false|off) /sbin/ethtool -K "${vif}" "${opt}" off ;;
-             *) logger -t scripts-vif "Unknown ethtool argument ${opt}=${arg} on ${vif}/${VIFUUID}" ;;
+             true|on)   /sbin/ethtool -K "${dev}" "${opt}" on ;;
+             false|off) /sbin/ethtool -K "${dev}" "${opt}" off ;;
+             *) logger -t scripts-vif "Unknown ethtool argument ${opt}=${arg} on ${dev}/${VIFUUID}" ;;
          esac
      fi
  }
  
  handle_mtu()
  {
-     local mtu=$(xenstore-read "${PRIVATE}/MTU")
+     local mtu=$(xenstore-read "${PRIVATE}/MTU" 2>/dev/null)
      if [ $? -eq 0 -a -n "${mtu}" ]; then
-       echo "${mtu}" > /sys/class/net/${vif}/mtu
+       echo "${mtu}" > /sys/class/net/${dev}/mtu
      fi
  }
  
 -handle_vswitch_vif_details()
 -{
 -    local vif_details=
 -    local net_uuid=$(xenstore-read "${PRIVATE}/network-uuid" 2>/dev/null)
 -    if [ -n "${net_uuid}" ] ; then
 -      vif_details="$vif_details --add=port.${dev}.net-uuid=${net_uuid}"
 -    fi
 -
 -    local address=$(xenstore-read "/local/domain/$DOMID/device/vif/$DEVID/mac" 2>/dev/null)
 -    if [ -n "${address}" ] ; then
 -      vif_details="$vif_details --add=port.${dev}.vif-mac=${address}"
 -    fi
 -
 -    local vif_uuid=$(xenstore-read "${PRIVATE}/vif-uuid" 2>/dev/null)
 -    if [ -n "${vif_uuid}" ] ; then
 -      vif_details="$vif_details --add=port.${dev}.vif-uuid=${vif_uuid}"
 -    fi
 -
 -    local vm=$(xenstore-read "/local/domain/$DOMID/vm" 2>/dev/null)
 -    if [ $? -eq 0 -a -n "${vm}" ] ; then
 -      local vm_uuid=$(xenstore-read "$vm/uuid" 2>/dev/null)
 -    fi
 -    if [ -n "${vm_uuid}" ] ; then
 -      vif_details="$vif_details --add=port.${dev}.vm-uuid=${vm_uuid}"
 -    fi
 -    echo ${vif_details}
 -}
 -
  add_to_bridge()
  {
      local address=$(xenstore-read "${PRIVATE}/bridge-MAC")
      if [ $? -ne 0 -o -z "${address}" ]; then
        logger -t scripts-vif "Failed to read ${PRIVATE}/bridge-MAC from xenstore"
+       exit 1
      fi
      local bridge=$(xenstore-read "${PRIVATE}/bridge")
      if [ $? -ne 0 -o -z "${bridge}" ]; then
        logger -t scripts-vif "Failed to read ${PRIVATE}/bridge from xenstore"
+       exit 1
      fi
-     logger -t scripts-vif "Adding ${vif} to ${bridge} with address ${address}"
-     ${IP} link set "${vif}" down                        || logger -t scripts-vif "Failed to ip link set ${vif} down"
-     ${IP} link set "${vif}" arp off                     || logger -t scripts-vif "Failed to ip link set ${vif} arp off"
-     ${IP} link set "${vif}" multicast off               || logger -t scripts-vif "Failed to ip link set ${vif} multicast off"
-     ${IP} link set "${vif}" address "${address}"        || logger -t scripts-vif "Failed to ip link set ${vif} address ${address}"
-     ${IP} addr flush "${vif}"                           || logger -t scripts-vif "Failed to ip addr flush ${vif}"
-     local vif_details=$($dump_vif_details $DOMID $DEVID)
-     if [ $? -ne 0 -o -z "${vif_details}" ]; then
-           logger -t scripts-vif "Failed to retrieve vif details for vswitch"
-     fi
-     $vsctl add-port $bridge $vif $vif_details
+     logger -t scripts-vif "Adding ${dev} to ${bridge} with address ${address}"
+     ${IP} link set "${dev}" down                        || logger -t scripts-vif "Failed to ip link set ${dev} down"
+     ${IP} link set "${dev}" arp off                     || logger -t scripts-vif "Failed to ip link set ${dev} arp off"
+     ${IP} link set "${dev}" multicast off               || logger -t scripts-vif "Failed to ip link set ${dev} multicast off"
+     ${IP} link set "${dev}" address "${address}"        || logger -t scripts-vif "Failed to ip link set ${dev} address ${address}"
+     ${IP} addr flush "${dev}"                           || logger -t scripts-vif "Failed to ip addr flush ${dev}"
+     case $NETWORK_MODE in
+       bridge)
+           ${BRCTL} setfd "${bridge}" 0                        || logger -t scripts-vif "Failed to brctl setfd ${bridge} 0"
+           ${BRCTL} addif "${bridge}" "${dev}"                 || logger -t scripts-vif "Failed to brctl addif ${bridge} ${dev}"
+           ;;
+       vswitch)
 -          local VLAN_ID=$($vsctl br-to-vlan $bridge)
 -          local vid=
 -          if [ "$VLAN_ID" -ne 0 ] ; then
 -              bridge=$($vsctl br-to-parent $bridge)
 -              vid="--add=vlan.${dev}.tag=${VLAN_ID}"
 -          fi
 -
 -          if [ "$TYPE" = "vif" ] ; then
 -              local vif_details=$(handle_vswitch_vif_details)
 -          fi
 -
 -          $cfg_mod -F /etc/ovs-vswitchd.conf \
 -              --del-match="bridge.*.port=${dev}" \
 -              --del-match="vlan.${dev}.trunks=*" \
 -              --del-match="vlan.${dev}.tag=*" \
 -              --del-match="port.${dev}.[!0-9]*" \
 -              --add="bridge.$bridge.port=${dev}" \
 -              $vid $vif_details -c 
 -          $service vswitch reload
++              local vif_details=$($dump_vif_details $DOMID $DEVID)
++              if [ $? -ne 0 -o -z "${vif_details}" ]; then
++                      logger -t scripts-vif "Failed to retrieve vif details for vswitch"
++              fi
++
++              $vsctl add-port $bridge $dev $vif_details
+           ;;
+     esac
+           
+     ${IP} link set "${dev}" up                          || logger -t scripts-vif "Failed to ip link set ${dev} up"
+ }
  
-     ${IP} link set "${vif}" up                          || logger -t scripts-vif "Failed to ip link set ${vif} up"
+ remove_from_bridge()
+ {
+     case $NETWORK_MODE in
+       bridge)
+           # Nothing to do
+           ;;
+       vswitch)
 -          $cfg_mod -vANY:console:emer -F /etc/ovs-vswitchd.conf \
 -              --del-match="bridge.*.port=${dev}" \
 -              --del-match="vlan.${dev}.trunks=*" \
 -              --del-match="vlan.${dev}.tag=*" \
 -              --del-match="port.${dev}.[!0-9]*" -c
 -          $service vswitch reload
++        $vsctl del-port $bridge $dev
+           ;;
+     esac
  }
  
- echo Called as "$@" "$TYPE" "$DOMID" "$DEVID" | logger -t scripts-vif
- case "$1" in
- online)
-       handle_ethtool rx
-       handle_ethtool tx
-       handle_ethtool sg
-       handle_ethtool tso
-       handle_ethtool ufo
-       handle_ethtool gso
+ NETWORK_MODE=$(cat /etc/xensource/network.conf)
+ ACTION=$1
+ TYPE=$2
  
-       handle_mtu
-       add_to_bridge
-       handle_promiscuous
+ case $NETWORK_MODE in
+     bridge|vswitch) ;;
+     *)
+       logger -t scripts-vif "Unknown network mode $NETWORK_MODE"
+       exit 1
+       ;;
+ esac
  
-       xenstore-write "${HOTPLUG}/vif" "${vif}"
-       xenstore-write "${HOTPLUG}/hotplug" "online"
+ case ${TYPE} in
+     vif)
+       DOMID=`echo ${XENBUS_PATH} | cut -f 3 -d '/'`
+       DEVID=`echo ${XENBUS_PATH} | cut -f 4 -d '/'`
+       dev=vif${DOMID}.${DEVID}
+       ;;
+     tap)
+       dev=$INTERFACE
+       DOMID=`echo ${dev#tap} | cut -f 1 -d '.'`
+       DEVID=`echo ${dev#tap} | cut -f 2 -d '.'`
+       ;;
+     *)  
+       logger -t scripts-vif "unknown interface type ${TYPE}"
+       exit 1
+       ;;
+ esac
  
-       # xs-xen.pq.hq:91e986b8e49f netback-wait-for-hotplug
-       xenstore-write "/local/domain/0/backend/vif/${DOMID}/${DEVID}/hotplug-status" "connected"
+ XAPI=/xapi/${DOMID}/hotplug/vif/${DEVID}
+ HOTPLUG=/xapi/${DOMID}/hotplug/vif/${DEVID}
+ PRIVATE=/xapi/${DOMID}/private/vif/${DEVID}
  
+ logger -t scripts-vif "Called as \"$@\" domid:$DOMID devid:$DEVID mode:$NETWORK_MODE"
+ case "${ACTION}" in
+ online)
+       if [ "${TYPE}" = "vif" ] ; then
+           handle_ethtool rx
+           handle_ethtool tx
+           handle_ethtool sg
+           handle_ethtool tso
+           handle_ethtool ufo
+           handle_ethtool gso
+           handle_mtu
+           add_to_bridge
+           handle_promiscuous
+           xenstore-write "${HOTPLUG}/vif" "${dev}"
+           xenstore-write "${HOTPLUG}/hotplug" "online"
+           # xs-xen.pq.hq:91e986b8e49f netback-wait-for-hotplug
+           xenstore-write "/local/domain/0/backend/vif/${DOMID}/${DEVID}/hotplug-status" "connected"
+       fi
        ;;
+ add)
+       if [ "${TYPE}" = "tap" ] ; then
+           add_to_bridge
+       fi
+       ;;
  remove)
-       xenstore-rm "${HOTPLUG}/hotplug"
-       vif=vif${DOMID}.${DEVID}
-       logger -t scripts-vif "${vif} has been removed"
-       $vsctl del-port $bridge $vif
+       if [ "${TYPE}" = "vif" ] ;then
+           xenstore-rm "${HOTPLUG}/hotplug"
+       fi
+       logger -t scripts-vif "${dev} has been removed"
+       remove_from_bridge
        ;;
  esac
index 0000000,6f093a4..c083859
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,458 +1,447 @@@
 -    # The use of [!0-9] keeps an interface of 'eth0' from matching
 -    # VLANs attached to eth0 (such as 'eth0.123'), which are distinct
 -    # interfaces.
 -    return ['--del-match=bridge.*.port=%s' % netdev,
 -            '--del-match=port.%s.[!0-9]*' % netdev,
 -            '--del-match=bonding.*.slave=%s' % netdev,
 -            '--del-match=iface.%s.[!0-9]*' % netdev]
+ # Copyright (c) 2008,2009 Citrix Systems, Inc.
+ # Copyright (c) 2009 Nicira Networks.
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU Lesser General Public License as published
+ # by the Free Software Foundation; version 2.1 only. with the special
+ # exception on linking described in file LICENSE.
+ #
+ # This program is distributed in the hope that it will be useful,
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ # GNU Lesser General Public License for more details.
+ #
+ from InterfaceReconfigure import *
+ #
+ # Bare Network Devices -- network devices without IP configuration
+ #
+ def netdev_down(netdev):
+     """Bring down a bare network device"""
+     if not netdev_exists(netdev):
+         log("netdev: down: device %s does not exist, ignoring" % netdev)
+         return
+     run_command(["/sbin/ifconfig", netdev, 'down'])
+ def netdev_up(netdev, mtu=None):
+     """Bring up a bare network device"""
+     if not netdev_exists(netdev):
+         raise Error("netdev: up: device %s does not exist" % netdev)
+     if mtu:
+         mtu = ["mtu", mtu]
+     else:
+         mtu = []
+     run_command(["/sbin/ifconfig", netdev, 'up'] + mtu)
+ #
+ # Bridges
+ #
+ def pif_bridge_name(pif):
+     """Return the bridge name of a pif.
+     PIF must not be a VLAN and must be a bridged PIF."""
+     pifrec = db().get_pif_record(pif)
+     if pif_is_vlan(pif):
+         raise Error("PIF %(uuid)s cannot be a bridge, VLAN is %(VLAN)s" % pifrec)
+     nwrec = db().get_network_record(pifrec['network'])
+     if nwrec['bridge']:
+         return nwrec['bridge']
+     else:
+         raise Error("PIF %(uuid)s does not have a bridge name" % pifrec)
+ #
+ # PIF miscellanea
+ #
+ def pif_currently_in_use(pif):
+     """Determine if a PIF is currently in use.
+     A PIF is determined to be currently in use if
+     - PIF.currently-attached is true
+     - Any bond master is currently attached
+     - Any VLAN master is currently attached
+     """
+     rec = db().get_pif_record(pif)
+     if rec['currently_attached']:
+         log("configure_datapath: %s is currently attached" % (pif_netdev_name(pif)))
+         return True
+     for b in pif_get_bond_masters(pif):
+         if pif_currently_in_use(b):
+             log("configure_datapath: %s is in use by BOND master %s" % (pif_netdev_name(pif),pif_netdev_name(b)))
+             return True
+     for v in pif_get_vlan_masters(pif):
+         if pif_currently_in_use(v):
+             log("configure_datapath: %s is in use by VLAN master %s" % (pif_netdev_name(pif),pif_netdev_name(v)))
+             return True
+     return False
+ #
+ # Datapath Configuration
+ #
+ def pif_datapath(pif):
+     """Return the datapath PIF associated with PIF.
+ For a non-VLAN PIF, the datapath name is the bridge name.
+ For a VLAN PIF, the datapath name is the bridge name for the PIF's VLAN slave.
+ """
+     if pif_is_vlan(pif):
+         return pif_datapath(pif_get_vlan_slave(pif))
+     pifrec = db().get_pif_record(pif)
+     nwrec = db().get_network_record(pifrec['network'])
+     if not nwrec['bridge']:
+         return None
+     else:
+         return pif
+ def datapath_get_physical_pifs(pif):
+     """Return the PIFs for the physical network device(s) associated with a datapath PIF.
+ For a bond master PIF, these are the bond slave PIFs.
+ For a non-VLAN, non-bond master PIF, the PIF is its own physical device PIF.
+ A VLAN PIF cannot be a datapath PIF.
+ """
+     if pif_is_vlan(pif):
+         # Seems like overkill...
+         raise Error("get-physical-pifs should not get passed a VLAN")
+     elif pif_is_bond(pif):
+         return pif_get_bond_slaves(pif)
+     else:
+         return [pif]
+ def datapath_deconfigure_physical(netdev):
 -    pifrec = db().get_pif_record(pif)
++    return ['--', '--if-exists', 'del-port', netdev]
+ def datapath_configure_bond(pif,slaves):
 -    argv = ['--del-match=bonding.%s.[!0-9]*' % interface]
 -    argv += ["--add=bonding.%s.slave=%s" % (interface, pif_netdev_name(slave))
 -             for slave in slaves]
 -    argv += ['--add=bonding.%s.fake-iface=true' % interface]
++    bridge = pif_bridge_name(pif)
++    pifrec = db.get_pif_record(pif)
+     interface = pif_netdev_name(pif)
 -    if pifrec['MAC'] != "":
 -        argv += ['--add=port.%s.mac=%s' % (interface, pifrec['MAC'])]
++    argv = ['--', '--fake-iface', 'add-bond', bridge, interface]
++    for slave in slaves:
++        argv += [pif_netdev_name(slave)]
 -        argv += ["--add=bonding.%s.%s=%s" % (interface, name, val)]
++    # XXX need ovs-vsctl support
++    #if pifrec['MAC'] != "":
++    #    argv += ['--add=port.%s.mac=%s' % (interface, pifrec['MAC'])]
+     # Bonding options.
+     bond_options = {
+         "mode":   "balance-slb",
+         "miimon": "100",
+         "downdelay": "200",
+         "updelay": "31000",
+         "use_carrier": "1",
+         }
+     # override defaults with values from other-config whose keys
+     # being with "bond-"
+     oc = pifrec['other_config']
+     overrides = filter(lambda (key,val):
+                            key.startswith("bond-"), oc.items())
+     overrides = map(lambda (key,val): (key[5:], val), overrides)
+     bond_options.update(overrides)
+     for (name,val) in bond_options.items():
 -    # The use of [!0-9] keeps an interface of 'eth0' from matching
 -    # VLANs attached to eth0 (such as 'eth0.123'), which are distinct
 -    # interfaces.
 -    return ['--del-match=bonding.%s.[!0-9]*' % netdev,
 -            '--del-match=port.%s.[!0-9]*' % netdev]
++        # XXX need ovs-vsctl support for bond options
++        #argv += ["--add=bonding.%s.%s=%s" % (interface, name, val)]
++        pass
+     return argv
+ def datapath_deconfigure_bond(netdev):
 -    # The use of [!0-9] keeps an interface of 'eth0' from matching
 -    # VLANs attached to eth0 (such as 'eth0.123'), which are distinct
 -    # interfaces.
 -    return ['--del-match=bridge.*.port=%s' % interface,
 -            '--del-match=port.%s.[!0-9]*' % interface,
 -            '--del-match=iface.%s.[!0-9]*' % interface,
 -            '--del-match=vlan.%s.trunks=*' % interface,
 -            '--del-match=vlan.%s.tag=*' % interface]
++    return ['--', '--if-exists', 'del-port', netdev]
+ def datapath_deconfigure_ipdev(interface):
 -    #log("modifying configuration:")
 -    #for c in commands:
 -    #    log("  %s" % c)
 -
 -    rc = run_command(['/usr/bin/ovs-cfg-mod', '-vANY:console:emer',
 -                 '-F', '/etc/ovs-vswitchd.conf']
 -                + [c for c in commands if c[0] != '#'] + ['-c'])
 -    if not rc:
++    return ['--', '--if-exists', 'del-port', interface]
+ def datapath_modify_config(commands):
 -    run_command(['/sbin/service', 'vswitch', 'reload'])
++    if debug_mode():
++        log("modifying configuration:")
++        for c in commands:
++            log("  %s" % c)
++            
++    rc = run_command(['/usr/bin/ovs-vsctl'] + ['--timeout=20']
++                     + [c for c in commands if not c.startswith('#')])
++    if not rc:       
+         raise Error("Failed to modify vswitch configuration")
 -    - A list containing the necessary cfgmod command line arguments
+     return True
+ #
+ # Toplevel Datapath Configuration.
+ #
+ def configure_datapath(pif):
+     """Bring up the datapath configuration for PIF.
+     Should be careful not to glitch existing users of the datapath, e.g. other VLANs etc.
+     Should take care of tearing down other PIFs which encompass common physical devices.
+     Returns a tuple containing
 -    cfgmod_argv = []
++    - A list containing the necessary vsctl command line arguments
+     - A list of additional devices which should be brought up after
+       the configuration is applied.
+     """
 -        cfgmod_argv += ['# remove bridge %s' % b]
 -        cfgmod_argv += ['--del-match=bridge.%s.*' % b]
++    vsctl_argv = []
+     extra_up_ports = []
+     bridge = pif_bridge_name(pif)
+     physical_devices = datapath_get_physical_pifs(pif)
+     # Determine additional devices to deconfigure.
+     #
+     # Given all physical devices which are part of this PIF we need to
+     # consider:
+     # - any additional bond which a physical device is part of.
+     # - any additional physical devices which are part of an additional bond.
+     #
+     # Any of these which are not currently in use should be brought
+     # down and deconfigured.
+     extra_down_bonds = []
+     extra_down_ports = []
+     for p in physical_devices:
+         for bond in pif_get_bond_masters(p):
+             if bond == pif:
+                 log("configure_datapath: leaving bond %s up" % pif_netdev_name(bond))
+                 continue
+             if bond in extra_down_bonds:
+                 continue
+             if db().get_pif_record(bond)['currently_attached']:
+                 log("configure_datapath: implicitly tearing down currently-attached bond %s" % pif_netdev_name(bond))
+             extra_down_bonds += [bond]
+             for s in pif_get_bond_slaves(bond):
+                 if s in physical_devices:
+                     continue
+                 if s in extra_down_ports:
+                     continue
+                 if pif_currently_in_use(s):
+                     continue
+                 extra_down_ports += [s]
+     log("configure_datapath: bridge      - %s" % bridge)
+     log("configure_datapath: physical    - %s" % [pif_netdev_name(p) for p in physical_devices])
+     log("configure_datapath: extra ports - %s" % [pif_netdev_name(p) for p in extra_down_ports])
+     log("configure_datapath: extra bonds - %s" % [pif_netdev_name(p) for p in extra_down_bonds])
+     # Need to fully deconfigure any bridge which any of the:
+     # - physical devices
+     # - bond devices
+     # - sibling devices
+     # refers to
+     for brpif in physical_devices + extra_down_ports + extra_down_bonds:
+         if brpif == pif:
+             continue
+         b = pif_bridge_name(brpif)
+         #ifdown(b)
+         # XXX
+         netdev_down(b)
 -        cfgmod_argv += ['# deconfigure sibling physical device %s' % dev]
 -        cfgmod_argv += datapath_deconfigure_physical(dev)
++        vsctl_argv += ['# remove bridge %s' % b]
++        vsctl_argv += ['--', '--if-exists', 'del-br', b]
+     for n in extra_down_ports:
+         dev = pif_netdev_name(n)
 -        cfgmod_argv += ['# deconfigure bond device %s' % dev]
 -        cfgmod_argv += datapath_deconfigure_bond(dev)
++        vsctl_argv += ['# deconfigure sibling physical device %s' % dev]
++        vsctl_argv += datapath_deconfigure_physical(dev)
+         netdev_down(dev)
+     for n in extra_down_bonds:
+         dev = pif_netdev_name(n)
 -        cfgmod_argv += ['# deconfigure physical port %s' % dev]
 -        cfgmod_argv += datapath_deconfigure_physical(dev)
++        vsctl_argv += ['# deconfigure bond device %s' % dev]
++        vsctl_argv += datapath_deconfigure_bond(dev)
+         netdev_down(dev)
+     for p in physical_devices:
+         dev = pif_netdev_name(p)
 -        cfgmod_argv += ['# deconfigure bond %s' % pif_netdev_name(pif)]
 -        cfgmod_argv += datapath_deconfigure_bond(pif_netdev_name(pif))
 -        cfgmod_argv += ['--del-entry=bridge.%s.port=%s' % (bridge,pif_netdev_name(pif))]
 -        cfgmod_argv += ['# configure bond %s' % pif_netdev_name(pif)]
 -        cfgmod_argv += datapath_configure_bond(pif, physical_devices)
 -        cfgmod_argv += ['--add=bridge.%s.port=%s' % (bridge,pif_netdev_name(pif)) ]
++        vsctl_argv += ['# deconfigure physical port %s' % dev]
++        vsctl_argv += datapath_deconfigure_physical(dev)
++
+     if len(physical_devices) > 1:
 -    else:
++        vsctl_argv += ['# deconfigure bond %s' % pif_netdev_name(pif)]
++        vsctl_argv += datapath_deconfigure_bond(pif_netdev_name(pif))
++        vsctl_argv += ['# configure bond %s' % pif_netdev_name(pif)]
++        vsctl_argv += datapath_configure_bond(pif, physical_devices)
+         extra_up_ports += [pif_netdev_name(pif)]
 -        cfgmod_argv += ['# add physical device %s' % iface]
 -        cfgmod_argv += ['--add=bridge.%s.port=%s' % (bridge,iface) ]
++     else:
+         iface = pif_netdev_name(physical_devices[0])
 -    return cfgmod_argv,extra_up_ports
++        vsctl_argv += ['# add physical device %s' % iface]
++        vsctl_argv += ['--', 'add-port', bridge, iface]
 -    cfgmod_argv = []
++    return vsctl_argv,extra_up_ports
+ def deconfigure_datapath(pif):
 -        cfgmod_argv += ['# deconfigure physical port %s' % dev]
 -        cfgmod_argv += datapath_deconfigure_physical(dev)
++    vsctl_argv = []
+     bridge = pif_bridge_name(pif)
+     physical_devices = datapath_get_physical_pifs(pif)
+     log("deconfigure_datapath: bridge           - %s" % bridge)
+     log("deconfigure_datapath: physical devices - %s" % [pif_netdev_name(p) for p in physical_devices])
+     for p in physical_devices:
+         dev = pif_netdev_name(p)
 -        cfgmod_argv += ['# deconfigure bond %s' % pif_netdev_name(pif)]
 -        cfgmod_argv += datapath_deconfigure_bond(pif_netdev_name(pif))
++        vsctl_argv += ['# deconfigure physical port %s' % dev]
++        vsctl_argv += datapath_deconfigure_physical(dev)
+         netdev_down(dev)
+     if len(physical_devices) > 1:
 -    cfgmod_argv += ['# deconfigure bridge %s' % bridge]
 -    cfgmod_argv += ['--del-match=bridge.%s.*' % bridge]
++        vsctl_argv += ['# deconfigure bond %s' % pif_netdev_name(pif)]
++        vsctl_argv += datapath_deconfigure_bond(pif_netdev_name(pif))
 -    return cfgmod_argv
++    vsctl_argv += ['# deconfigure bridge %s' % bridge]
++    vsctl_argv += ['--', '--if-exists', 'del-br', bridge]
 -        cfgmod_argv = []
++    return vsctl_argv
+ #
+ #
+ #
+ class DatapathVswitch(Datapath):
+     def __init__(self, pif):
+         Datapath.__init__(self, pif)
+         self._dp = pif_datapath(pif)
+         self._ipdev = pif_ipdev_name(pif)
+         if pif_is_vlan(pif) and not self._dp:
+             raise Error("Unbridged VLAN devices not implemented yet")
+         
+         log("Configured for Vswitch datapath")
+     def configure_ipdev(self, cfg):
+         cfg.write("TYPE=Ethernet\n")
+     def preconfigure(self, parent):
 -        cfgmod_argv += c
++        vsctl_argv = []
+         extra_ports = []
+         pifrec = db().get_pif_record(self._pif)
+         ipdev = self._ipdev
+         bridge = pif_bridge_name(self._dp)
+         c,e = configure_datapath(self._dp)
 -        cfgmod_argv += ['# configure xs-network-uuids']
 -        cfgmod_argv += ['--del-match=bridge.%s.xs-network-uuids=*' % bridge]
++        vsctl_argv += c
+         extra_ports += e
 -            cfgmod_argv += ['--add=bridge.%s.xs-network-uuids=%s' % (bridge, nwrec['uuid'])]
 -
 -        cfgmod_argv += ["# deconfigure ipdev %s" % ipdev]
 -        cfgmod_argv += datapath_deconfigure_ipdev(ipdev)
 -        cfgmod_argv += ["# reconfigure ipdev %s" % ipdev]
 -        cfgmod_argv += ['--add=bridge.%s.port=%s' % (bridge, ipdev)]
 -        if bridge == ipdev:
 -            cfgmod_argv += ['--add=bridge.%s.mac=%s' % (bridge, pifrec['MAC'])]
 -        else:
 -            cfgmod_argv += ['--add=iface.%s.mac=%s' % (ipdev, pifrec['MAC'])]
 -            
 -        if pif_is_vlan(self._pif):
 -            cfgmod_argv += ['--add=vlan.%s.tag=%s' % (ipdev, pifrec['VLAN'])]
 -            cfgmod_argv += ['--add=iface.%s.internal=true' % (ipdev)]
 -            cfgmod_argv += ['--add=iface.%s.fake-bridge=true' % (ipdev)]
++        if pif_is_vlan(pif):
++            datapath = pif_datapath(pif)
++            vsctl_argv += ['--', 'add-br', bridge, datapath, pifrec['VLAN']]
++        else:
++            vsctl_argv += ['--', 'add-br', bridge]
++        xs_network_uuids = []
+         for nwpif in db().get_pifs_by_device(db().get_pif_record(self._pif)['device']):
+             rec = db().get_pif_record(nwpif)
+             # When state is read from dbcache PIF.currently_attached
+             # is always assumed to be false... Err on the side of
+             # listing even detached networks for the time being.
+             #if nwpif != pif and not rec['currently_attached']:
+             #    log("Network PIF %s not currently attached (%s)" % (rec['uuid'],pifrec['uuid']))
+             #    continue
+             nwrec = db().get_network_record(rec['network'])
 -        self._cfgmod_argv = cfgmod_argv
++            xs_network_uuids += [nwrec['uuid']]
++
++        vsctl_argv += ['# configure xs-network-uuids']
++        vsctl_argv += ['--', 'br-set-external-id', bridge,
++                'xs-network-uuids', ';'.join(xs_network_uuids)]
++
++        vsctl_argv += ["# deconfigure ipdev %s" % ipdev]
++        vsctl_argv += datapath_deconfigure_ipdev(ipdev)
++        vsctl_argv += ["# reconfigure ipdev %s" % ipdev]
++        vsctl_argv += ['--', 'add-port', bridge, ipdev]
++
++        # XXX Needs support in ovs-vsctl
++        #if bridge == ipdev:
++        #    vsctl_argv += ['--add=bridge.%s.mac=%s' % (bridge, pifrec['MAC'])]
++        #else:
++        #    vsctl_argv += ['--add=iface.%s.mac=%s' % (ipdev, pifrec['MAC'])]
 -        datapath_modify_config(self._cfgmod_argv)
++        self._vsctl_argv = vsctl_argv
+         self._extra_ports = extra_ports
+     def bring_down_existing(self):
+         pass
+     def configure(self):
+         # Bring up physical devices. ovs-vswitchd initially enables or
+         # disables bond slaves based on whether carrier is detected
+         # when they are added, and a network device that is down
+         # always reports "no carrier".
+         physical_devices = datapath_get_physical_pifs(self._dp)
+         
+         for p in physical_devices:
+             oc = db().get_pif_record(p)['other_config']
+             dev = pif_netdev_name(p)
+             mtu = mtu_setting(oc)
+             netdev_up(dev, mtu)
+             settings, offload = ethtool_settings(oc)
+             if len(settings):
+                 run_command(['/sbin/ethtool', '-s', dev] + settings)
+             if len(offload):
+                 run_command(['/sbin/ethtool', '-K', dev] + offload)
 -        cfgmod_argv = []
++        datapath_modify_config(self._vsctl_argv)
+     def post(self):
+         for p in self._extra_ports:
+             log("action_up: bring up %s" % p)
+             netdev_up(p)
+     def bring_down(self):
 -        #cfgmod_argv += ['# deconfigure xs-network-uuids']
 -        #cfgmod_argv += ['--del-entry=bridge.%s.xs-network-uuids=%s' % (bridge,nwrec['uuid'])]
++        vsctl_argv = []
+         dp = self._dp
+         ipdev = self._ipdev
+         
+         bridge = pif_bridge_name(dp)
+         #nw = db().get_pif_record(self._pif)['network']
+         #nwrec = db().get_network_record(nw)
 -        cfgmod_argv += ["# deconfigure ipdev %s" % ipdev]
 -        cfgmod_argv += datapath_deconfigure_ipdev(ipdev)
++        #vsctl_argv += ['# deconfigure xs-network-uuids']
++        #vsctl_argv += ['--del-entry=bridge.%s.xs-network-uuids=%s' % (bridge,nwrec['uuid'])]
+         log("deconfigure ipdev %s on %s" % (ipdev,bridge))
 -            cfgmod_argv += deconfigure_datapath(dp)
 -            datapath_modify_config(cfgmod_argv)
++        vsctl_argv += ["# deconfigure ipdev %s" % ipdev]
++        vsctl_argv += datapath_deconfigure_ipdev(ipdev)
+         if pif_is_vlan(self._pif):
+             # If the VLAN's slave is attached, leave datapath setup.
+             slave = pif_get_vlan_slave(self._pif)
+             if db().get_pif_record(slave)['currently_attached']:
+                 log("action_down: vlan slave is currently attached")
+                 dp = None
+             # If the VLAN's slave has other VLANs that are attached, leave datapath setup.
+             for master in pif_get_vlan_masters(slave):
+                 if master != self._pif and db().get_pif_record(master)['currently_attached']:
+                     log("action_down: vlan slave has other master: %s" % pif_netdev_name(master))
+                     dp = None
+             # Otherwise, take down the datapath too (fall through)
+             if dp:
+                 log("action_down: no more masters, bring down slave %s" % bridge)
+         else:
+             # Stop here if this PIF has attached VLAN masters.
+             masters = [db().get_pif_record(m)['VLAN'] for m in pif_get_vlan_masters(self._pif) if db().get_pif_record(m)['currently_attached']]
+             if len(masters) > 0:
+                 log("Leaving datapath %s up due to currently attached VLAN masters %s" % (bridge, masters))
+                 dp = None
+         if dp:
++            vsctl_argv += deconfigure_datapath(dp)
++            datapath_modify_config(vsctl_argv)
@@@ -67,10 -67,14 +67,16 @@@ install -d -m 755 $RPM_BUILD_ROOT/etc/x
  install -m 755 xenserver/etc_xapi.d_plugins_vswitch-cfg-update \
           $RPM_BUILD_ROOT/etc/xapi.d/plugins/vswitch-cfg-update
  install -d -m 755 $RPM_BUILD_ROOT/usr/share/vswitch/scripts
 +install -m 644 vswitchd/vswitch.ovsschema \
 +         $RPM_BUILD_ROOT/usr/share/vswitch/vswitch.ovsschema
  install -m 755 xenserver/opt_xensource_libexec_interface-reconfigure \
               $RPM_BUILD_ROOT/usr/share/vswitch/scripts/interface-reconfigure
+ install -m 755 xenserver/opt_xensource_libexec_InterfaceReconfigure.py \
+              $RPM_BUILD_ROOT/usr/share/vswitch/scripts/InterfaceReconfigure.py
+ install -m 755 xenserver/opt_xensource_libexec_InterfaceReconfigureBridge.py \
+              $RPM_BUILD_ROOT/usr/share/vswitch/scripts/InterfaceReconfigureBridge.py
+ install -m 755 xenserver/opt_xensource_libexec_InterfaceReconfigureVswitch.py \
+              $RPM_BUILD_ROOT/usr/share/vswitch/scripts/InterfaceReconfigureVswitch.py
  install -m 755 xenserver/etc_xensource_scripts_vif \
               $RPM_BUILD_ROOT/usr/share/vswitch/scripts/vif
  install -m 755 xenserver/usr_share_vswitch_scripts_dump-vif-details \
@@@ -105,6 -109,8 +111,6 @@@ rm 
      $RPM_BUILD_ROOT/usr/share/man/man8/ovs-openflowd.8 \
      $RPM_BUILD_ROOT/usr/share/man/man8/ovs-pki.8
  rm -f $RPM_BUILD_ROOT/lib/modules/%{xen_version}/kernel/net/vswitch/veth_mod.ko
 -rm -r \
 -    $RPM_BUILD_ROOT/usr/share/openvswitch/commands
  
  install -d -m 755 $RPM_BUILD_ROOT/var/lib/openvswitch
  
@@@ -129,15 -135,6 +135,15 @@@ EO
      elif md5sum -c --status <<EOF
  ca141d60061dcfdade73e75abc6529b5  /usr/sbin/brctl
  b8e9835862ef1a9cec2a3f477d26c989  /etc/xensource/scripts/vif
 +51970ad613a3996d5997e18e44db47da  /opt/xensource/libexec/interface-reconfigure
 +f6519085c2fc5f7bc4eccc294ed62000  /usr/sbin/xen-bugtool
 +EOF
 +    then
 +        printf "\nVerified host scripts from XenServer 5.5.0-24648p (Update 1)\n"
 +        printf "or 5.5.0-25727p (Update 2).\n\n"
 +    elif md5sum -c --status <<EOF
 +ca141d60061dcfdade73e75abc6529b5  /usr/sbin/brctl
 +b8e9835862ef1a9cec2a3f477d26c989  /etc/xensource/scripts/vif
  ce451d3c985fd1db6497a363f0d9dedb  /opt/xensource/libexec/interface-reconfigure
  2b53f500431fcba5276c896e9e4281b9  /usr/sbin/xen-bugtool
  EOF
@@@ -157,7 -154,7 +163,7 @@@ EO
      fi
  fi
  
- if test ! -e /var/lib/openvswitch/dbcache; then
+ if test ! -e /var/xapi/network.dbcache; then
      if test "$1" = 1; then
          printf "Creating xapi database cache...  "
      else
@@@ -195,16 -192,8 +201,16 @@@ net.ipv4.conf.all.arp_filter = 
  EOF
  fi
  
 -# Ensure ovs-vswitchd.conf exists
 -touch /etc/ovs-vswitchd.conf
 +if test ! -e /etc/ovs-vswitchd.conf.db; then
 +    # Create ovs-vswitchd config database
 +    ovsdb-tool -vANY:console:emer create /etc/ovs-vswitchd.conf.db \
 +            /usr/share/vswitch/vswitch.ovsschema \
 +
 +    # Create initial table in config database
 +    ovsdb-tool -vANY:console:emer transact /etc/ovs-vswitchd.conf.db \
 +            '[{"op": "insert", "table": "Open_vSwitch", "row": {}}]' \
 +            > /dev/null
 +fi
  
  # Create default or update existing /etc/sysconfig/vswitch.
  SYSCONFIG=/etc/sysconfig/vswitch
@@@ -226,13 -215,16 +232,16 @@@ mkdir -p /usr/lib/vswitch/xs-original 
      || printf "Could not create script backup directory.\n"
  for f in \
      /opt/xensource/libexec/interface-reconfigure \
+     /opt/xensource/libexec/InterfaceReconfigure.py \
+     /opt/xensource/libexec/InterfaceReconfigureBridge.py \
+     /opt/xensource/libexec/InterfaceReconfigureVswitch.py \
      /etc/xensource/scripts/vif \
      /usr/sbin/xen-bugtool \
      /usr/sbin/brctl
  do
      s=$(basename "$f")
      t=$(readlink "$f")
-     if [ "$t" != "/usr/share/vswitch/scripts/$s" ]; then
+     if [ -f "$f" ] && [ "$t" != "/usr/share/vswitch/scripts/$s" ]; then
          mv "$f" /usr/lib/vswitch/xs-original/ \
              || printf "Could not save original XenServer $s script\n"
          ln -s "/usr/share/vswitch/scripts/$s" "$f" \
@@@ -256,6 -248,9 +265,9 @@@ for s in vswitch vswitch-xapi-update; d
      chkconfig $s on || printf "Could not enable $s init script."
  done
  
+ # Configure system to use vswitch
+ echo vswitch > /etc/xensource/network.conf
  if [ "$1" = "1" ]; then    # $1 = 2 for upgrade
      printf "\nYou MUST reboot the server NOW to complete the change to the\n"
      printf "the vSwitch.  Attempts to modify networking on the server\n"
@@@ -301,10 -296,13 +313,13 @@@ if [ "$1" = "0" ]; then     # $1 = 1 fo
      done
  
      # Remove all configuration files
 -    rm -f /etc/ovs-vswitchd.conf
 +    rm -f /etc/ovs-vswitchd.conf.db
      rm -f /etc/sysconfig/vswitch
      rm -f /etc/ovs-vswitchd.cacert
-     rm -f /var/lib/openvswitch/dbcache
+     rm -f /var/xapi/network.dbcache
+     # Configure system to use bridge
+     echo bridge > /etc/xensource/network.conf
  
      printf "\nYou MUST reboot the server now to complete the change to\n"
      printf "standard Xen networking.  Attempts to modify networking on the\n"
  /etc/profile.d/vswitch.sh
  /lib/modules/%{xen_version}/kernel/net/vswitch/openvswitch_mod.ko
  /lib/modules/%{xen_version}/kernel/net/vswitch/brcompat_mod.ko
 +%if %(echo '%{xen_version}'|awk -F"." '{if ($3>=18) print 1; else print 0;}')
 +/lib/modules/%{xen_version}/kernel/net/vswitch/ip_gre_mod.ko
 +%endif
  /usr/share/vswitch/scripts/dump-vif-details
  /usr/share/vswitch/scripts/refresh-xs-network-uuids
  /usr/share/vswitch/scripts/interface-reconfigure
+ /usr/share/vswitch/scripts/InterfaceReconfigure.py
+ /usr/share/vswitch/scripts/InterfaceReconfigure.pyc
+ /usr/share/vswitch/scripts/InterfaceReconfigure.pyo
+ /usr/share/vswitch/scripts/InterfaceReconfigureBridge.py
+ /usr/share/vswitch/scripts/InterfaceReconfigureBridge.pyc
+ /usr/share/vswitch/scripts/InterfaceReconfigureBridge.pyo
+ /usr/share/vswitch/scripts/InterfaceReconfigureVswitch.py
+ /usr/share/vswitch/scripts/InterfaceReconfigureVswitch.pyc
+ /usr/share/vswitch/scripts/InterfaceReconfigureVswitch.pyo
  /usr/share/vswitch/scripts/vif
  /usr/share/vswitch/scripts/xen-bugtool
  /usr/share/vswitch/scripts/XSFeatureVSwitch.py
  # include them.
  /usr/share/vswitch/scripts/XSFeatureVSwitch.pyc
  /usr/share/vswitch/scripts/XSFeatureVSwitch.pyo
 +/usr/share/vswitch/vswitch.ovsschema
  /usr/sbin/ovs-brcompatd
  /usr/sbin/ovs-vswitchd
 +/usr/sbin/ovsdb-server
  /usr/bin/ovs-appctl
 -/usr/bin/ovs-cfg-mod
  /usr/bin/ovs-dpctl
  /usr/bin/ovs-ofctl
  /usr/bin/ovs-vsctl
 -/usr/share/man/man5/ovs-vswitchd.conf.5.gz
 +/usr/bin/ovsdb-client
 +/usr/bin/ovsdb-tool
 +/usr/share/man/man1/ovsdb-client.1.gz
 +/usr/share/man/man1/ovsdb-server.1.gz
 +/usr/share/man/man1/ovsdb-tool.1.gz
  /usr/share/man/man8/ovs-appctl.8.gz
  /usr/share/man/man8/ovs-brcompatd.8.gz
 -/usr/share/man/man8/ovs-cfg-mod.8.gz
  /usr/share/man/man8/ovs-dpctl.8.gz
  /usr/share/man/man8/ovs-ofctl.8.gz
  /usr/share/man/man8/ovs-vsctl.8.gz