Merge "master" into "next".
authorBen Pfaff <blp@nicira.com>
Wed, 24 Feb 2010 21:47:09 +0000 (13:47 -0800)
committerBen Pfaff <blp@nicira.com>
Wed, 24 Feb 2010 21:47:09 +0000 (13:47 -0800)
23 files changed:
1  2 
configure.ac
datapath/actions.c
include/openflow/openflow.h
include/openvswitch/datapath-protocol.h
lib/classifier.c
lib/classifier.h
lib/compiler.h
lib/dpif-netdev.c
lib/dpif.h
lib/flow.h
lib/ofp-print.c
lib/packets.h
lib/poll-loop.h
lib/rconn.c
lib/stp.c
lib/util.h
lib/vconn.c
lib/vconn.h
ofproto/netflow.h
ofproto/ofproto.c
ofproto/ofproto.h
ofproto/pinsched.c
ofproto/pktbuf.c

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.99.1, ovs-bugs@openvswitch.org)
+ AC_INIT(openvswitch, 0.99.2, 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])
  
@@@ -89,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
@@@ -15,7 -15,6 +15,7 @@@
  #include <linux/udp.h>
  #include <linux/in6.h>
  #include <linux/if_vlan.h>
 +#include <net/inet_ecn.h>
  #include <net/ip.h>
  #include <net/checksum.h>
  #include "datapath.h"
@@@ -93,7 -92,7 +93,7 @@@ modify_vlan_tci(struct datapath *dp, st
                mask = VLAN_VID_MASK;
                key->dl_vlan = htons(tci & mask);
        } else {
-               tci = a->vlan_pcp.vlan_pcp << 13;
+               tci = a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT;
                mask = VLAN_PCP_MASK;
        }
  
@@@ -214,43 -213,10 +214,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)
@@@ -286,30 -252,6 +286,30 @@@ static struct sk_buff *set_nw_addr(stru
        return skb;
  }
  
 +static struct sk_buff *set_nw_tos(struct sk_buff *skb,
 +                                 struct odp_flow_key *key,
 +                                 const struct odp_action_nw_tos *a,
 +                                 gfp_t gfp)
 +{
 +      if (key->dl_type != htons(ETH_P_IP))
 +              return skb;
 +
 +      skb = make_writable(skb, 0, gfp);
 +      if (skb) {
 +              struct iphdr *nh = ip_hdr(skb);
 +              u8 *f = &nh->tos;
 +              u8 old = *f;
 +              u8 new;
 +
 +              /* Set the DSCP bits and preserve the ECN bits. */
 +              new = (a->nw_tos & ~INET_ECN_MASK) | (nh->tos & INET_ECN_MASK);
 +              update_csum(&nh->check, skb, htons((uint16_t)old),
 +                              htons((uint16_t)new), 0);
 +              *f = new;
 +      }
 +      return skb;
 +}
 +
  static struct sk_buff *
  set_tp_port(struct sk_buff *skb, struct odp_flow_key *key,
            const struct odp_action_tp_port *a,
                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;
@@@ -360,7 -302,6 +360,7 @@@ int dp_xmit_skb(struct sk_buff *skb
                return -E2BIG;
        }
  
 +      forward_ip_summed(skb);
        dev_queue_xmit(skb);
  
        return len;
@@@ -516,10 -457,6 +516,10 @@@ int execute_actions(struct datapath *dp
                        skb = set_nw_addr(skb, key, &a->nw_addr, gfp);
                        break;
  
 +              case ODPAT_SET_NW_TOS:
 +                      skb = set_nw_tos(skb, key, &a->nw_tos, gfp);
 +                      break;
 +
                case ODPAT_SET_TP_SRC:
                case ODPAT_SET_TP_DST:
                        skb = set_tp_port(skb, key, &a->tp_port, gfp);
  #define OFP_ASSERT BOOST_STATIC_ASSERT
  #endif /* __cplusplus */
  
- #ifndef SWIG
- #define OFP_PACKED __attribute__((packed))
- #else
- #define OFP_PACKED              /* SWIG doesn't understand __attribute. */
- #endif
 +/* Version number:
 + * Non-experimental versions released: 0x01
 + * Experimental versions released: 0x81 -- 0x99
 + */
  /* The most significant bit being set in the version field indicates an
 - * experimental OpenFlow version.  
 + * experimental OpenFlow version.
   */
 -#define OFP_VERSION   0x97
 +#define OFP_VERSION   0x01
  
  #define OFP_MAX_TABLE_NAME_LEN 32
  #define OFP_MAX_PORT_NAME_LEN  16
  
  #define OFP_ETH_ALEN 6          /* Bytes in an Ethernet address. */
  
 -/* Port numbering.  Physical ports are numbered starting from 0. */
 +/* Port numbering.  Physical ports are numbered starting from 1. */
  enum ofp_port {
      /* Maximum number of physical switch ports. */
      OFPP_MAX = 0xff00,
  
      /* Fake output "ports". */
 -    OFPP_IN_PORT    = 0xfff8,  /* Send the packet out the input port.  This 
 -                                  virtual port must be explicitly used 
 -                                  in order to send back out of the input 
 +    OFPP_IN_PORT    = 0xfff8,  /* Send the packet out the input port.  This
 +                                  virtual port must be explicitly used
 +                                  in order to send back out of the input
                                    port. */
 -    OFPP_TABLE      = 0xfff9,  /* Perform actions in flow table.  
 +    OFPP_TABLE      = 0xfff9,  /* Perform actions in flow table.
                                    NB: This can only be the destination
                                    port for packet-out messages. */
      OFPP_NORMAL     = 0xfffa,  /* Process with normal L2/L3 switching. */
 -    OFPP_FLOOD      = 0xfffb,  /* All physical ports except input port and 
 +    OFPP_FLOOD      = 0xfffb,  /* All physical ports except input port and
                                    those disabled by STP. */
      OFPP_ALL        = 0xfffc,  /* All physical ports except input port. */
 -    OFPP_CONTROLLER = 0xfffd,  /* Send to controller. */ 
 +    OFPP_CONTROLLER = 0xfffd,  /* Send to controller. */
      OFPP_LOCAL      = 0xfffe,  /* Local openflow "port". */
      OFPP_NONE       = 0xffff   /* Not associated with a physical port. */
  };
@@@ -99,7 -89,7 +93,7 @@@ enum ofp_type 
  
      /* Asynchronous messages. */
      OFPT_PACKET_IN,           /* Async message */
 -    OFPT_FLOW_EXPIRED,        /* Async message */
 +    OFPT_FLOW_REMOVED,        /* Async message */
      OFPT_PORT_STATUS,         /* Async message */
  
      /* Controller command messages. */
  
      /* Statistics messages. */
      OFPT_STATS_REQUEST,       /* Controller/switch message */
 -    OFPT_STATS_REPLY          /* Controller/switch message */
 +    OFPT_STATS_REPLY,         /* Controller/switch message */
 +
 +    /* Barrier messages. */
 +    OFPT_BARRIER_REQUEST,     /* Controller/switch message */
 +    OFPT_BARRIER_REPLY,       /* Controller/switch message */
 +
 +    /* Queue Configuration messages. */
 +    OFPT_QUEUE_GET_CONFIG_REQUEST,  /* Controller/switch message */
 +    OFPT_QUEUE_GET_CONFIG_REPLY     /* Controller/switch message */
  };
  
  /* Header on all OpenFlow packets. */
@@@ -140,11 -122,14 +134,11 @@@ struct ofp_hello 
  #define OFP_DEFAULT_MISS_SEND_LEN   128
  
  enum ofp_config_flags {
 -    /* Tells datapath to notify the controller of expired flow entries. */
 -    OFPC_SEND_FLOW_EXP = 1 << 0,
 -
      /* Handling of IP fragments. */
 -    OFPC_FRAG_NORMAL   = 0 << 1,  /* No special handling for fragments. */
 -    OFPC_FRAG_DROP     = 1 << 1,  /* Drop fragments. */
 -    OFPC_FRAG_REASM    = 2 << 1,  /* Reassemble (only if OFPC_IP_REASM set). */
 -    OFPC_FRAG_MASK     = 3 << 1
 +    OFPC_FRAG_NORMAL   = 0,  /* No special handling for fragments. */
 +    OFPC_FRAG_DROP     = 1,  /* Drop fragments. */
 +    OFPC_FRAG_REASM    = 2,  /* Reassemble (only if OFPC_IP_REASM set). */
 +    OFPC_FRAG_MASK     = 3
  };
  
  /* Switch configuration. */
@@@ -162,23 -147,20 +156,23 @@@ enum ofp_capabilities 
      OFPC_TABLE_STATS    = 1 << 1,  /* Table statistics. */
      OFPC_PORT_STATS     = 1 << 2,  /* Port statistics. */
      OFPC_STP            = 1 << 3,  /* 802.1d spanning tree. */
 -    OFPC_MULTI_PHY_TX   = 1 << 4,  /* Supports transmitting through multiple
 -                                      physical interfaces */
 -    OFPC_IP_REASM       = 1 << 5   /* Can reassemble IP fragments. */
 +    OFPC_RESERVED       = 1 << 4,  /* Reserved, must not be set. */
 +    OFPC_IP_REASM       = 1 << 5,  /* Can reassemble IP fragments. */
 +    OFPC_QUEUE_STATS    = 1 << 6,  /* Queue statistics. */
 +    OFPC_ARP_MATCH_IP   = 1 << 7   /* Match IP addresses in ARP
 +                                      pkts. */
  };
  
  /* Flags to indicate behavior of the physical port.  These flags are
   * used in ofp_phy_port to describe the current configuration.  They are
 - * used in the ofp_port_mod message to configure the port's behavior. 
 + * used in the ofp_port_mod message to configure the port's behavior.
   */
  enum ofp_port_config {
      OFPPC_PORT_DOWN    = 1 << 0,  /* Port is administratively down. */
  
      OFPPC_NO_STP       = 1 << 1,  /* Disable 802.1D spanning tree on port. */
 -    OFPPC_NO_RECV      = 1 << 2,  /* Drop most packets received on port. */
 +    OFPPC_NO_RECV      = 1 << 2,  /* Drop all packets except 802.1D
 +                                     spanning tree packets. */
      OFPPC_NO_RECV_STP  = 1 << 3,  /* Drop received 802.1D STP packets. */
      OFPPC_NO_FLOOD     = 1 << 4,  /* Do not include this port when flooding. */
      OFPPC_NO_FWD       = 1 << 5,  /* Drop packets forwarded to port. */
@@@ -239,9 -221,8 +233,9 @@@ OFP_ASSERT(sizeof(struct ofp_phy_port) 
  /* Switch features. */
  struct ofp_switch_features {
      struct ofp_header header;
 -    uint64_t datapath_id;   /* Datapath unique ID.  Only the lower 48-bits
 -                               are meaningful. */
 +    uint64_t datapath_id;   /* Datapath unique ID.  The lower 48-bits are for
 +                               a MAC address, while the upper 16-bits are
 +                               implementer-defined. */
  
      uint32_t n_buffers;     /* Max packets buffered at once. */
  
@@@ -279,16 -260,16 +273,16 @@@ OFP_ASSERT(sizeof(struct ofp_port_statu
  struct ofp_port_mod {
      struct ofp_header header;
      uint16_t port_no;
 -    uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not 
 -                                      configurable.  This is used to 
 -                                      sanity-check the request, so it must 
 +    uint8_t hw_addr[OFP_ETH_ALEN]; /* The hardware address is not
 +                                      configurable.  This is used to
 +                                      sanity-check the request, so it must
                                        be the same as returned in an
                                        ofp_phy_port struct. */
  
      uint32_t config;        /* Bitmap of OFPPC_* flags. */
      uint32_t mask;          /* Bitmap of OFPPC_* flags to be changed. */
  
 -    uint32_t advertise;     /* Bitmap of "ofp_port_features"s.  Zero all 
 +    uint32_t advertise;     /* Bitmap of "ofp_port_features"s.  Zero all
                                 bits to prevent any action taking place. */
      uint8_t pad[4];         /* Pad to 64-bits. */
  };
@@@ -309,7 -290,7 +303,7 @@@ struct ofp_packet_in 
      uint8_t reason;         /* Reason packet is being sent (one of OFPR_*) */
      uint8_t pad;
      uint8_t data[0];        /* Ethernet frame, halfway through 32-bit word,
 -                               so the IP header is 32-bit aligned.  The 
 +                               so the IP header is 32-bit aligned.  The
                                 amount of data is inferred from the length
                                 field in the header.  Because of padding,
                                 offsetof(struct ofp_packet_in, data) ==
@@@ -326,15 -307,13 +320,15 @@@ enum ofp_action_type 
      OFPAT_SET_DL_DST,       /* Ethernet destination address. */
      OFPAT_SET_NW_SRC,       /* IP source address. */
      OFPAT_SET_NW_DST,       /* IP destination address. */
 +    OFPAT_SET_NW_TOS,       /* IP ToS (DSCP field, 6 bits). */
      OFPAT_SET_TP_SRC,       /* TCP/UDP source port. */
      OFPAT_SET_TP_DST,       /* TCP/UDP destination port. */
 +    OFPAT_ENQUEUE,          /* Output to queue. */
      OFPAT_VENDOR = 0xffff
  };
  
 -/* Action structure for OFPAT_OUTPUT, which sends packets out 'port'.  
 - * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max 
 +/* Action structure for OFPAT_OUTPUT, which sends packets out 'port'.
 + * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max
   * number of bytes to send.  A 'max_len' of zero means no bytes of the
   * packet should be sent. */
  struct ofp_action_output {
@@@ -385,15 -364,6 +379,15 @@@ struct ofp_action_nw_addr 
  };
  OFP_ASSERT(sizeof(struct ofp_action_nw_addr) == 8);
  
 +/* Action structure for OFPAT_SET_NW_TOS. */
 +struct ofp_action_nw_tos {
 +    uint16_t type;                  /* OFPAT_SET_TW_TOS. */
 +    uint16_t len;                   /* Length is 8. */
 +    uint8_t nw_tos;                 /* IP TOS (DSCP field, 6 bits). */
 +    uint8_t pad[3];
 +};
 +OFP_ASSERT(sizeof(struct ofp_action_nw_tos) == 8);
 +
  /* Action structure for OFPAT_SET_TP_SRC/DST. */
  struct ofp_action_tp_port {
      uint16_t type;                  /* OFPAT_SET_TP_SRC/DST. */
@@@ -407,19 -377,19 +401,19 @@@ OFP_ASSERT(sizeof(struct ofp_action_tp_
  struct ofp_action_vendor_header {
      uint16_t type;                  /* OFPAT_VENDOR. */
      uint16_t len;                   /* Length is a multiple of 8. */
 -    uint32_t vendor;                /* Vendor ID, which takes the same form 
 -                                       as in "struct ofp_vendor_header". */ 
 +    uint32_t vendor;                /* Vendor ID, which takes the same form
 +                                       as in "struct ofp_vendor_header". */
  };
  OFP_ASSERT(sizeof(struct ofp_action_vendor_header) == 8);
  
 -/* Action header that is common to all actions.  The length includes the 
 - * header and any padding used to make the action 64-bit aligned.  
 +/* Action header that is common to all actions.  The length includes the
 + * header and any padding used to make the action 64-bit aligned.
   * NB: The length of an action *must* always be a multiple of eight. */
  struct ofp_action_header {
      uint16_t type;                  /* One of OFPAT_*. */
 -    uint16_t len;                   /* Length of action, including this 
 -                                       header.  This is the length of action, 
 -                                       including any padding to make it 
 +    uint16_t len;                   /* Length of action, including this
 +                                       header.  This is the length of action,
 +                                       including any padding to make it
                                         64-bit aligned. */
      uint8_t pad[4];
  };
@@@ -433,7 -403,6 +427,7 @@@ union ofp_action 
      struct ofp_action_vlan_vid vlan_vid;
      struct ofp_action_vlan_pcp vlan_pcp;
      struct ofp_action_nw_addr nw_addr;
 +    struct ofp_action_nw_tos nw_tos;
      struct ofp_action_tp_port tp_port;
  };
  OFP_ASSERT(sizeof(union ofp_action) == 8);
@@@ -445,8 -414,8 +439,8 @@@ struct ofp_packet_out 
      uint16_t in_port;             /* Packet's input port (OFPP_NONE if none). */
      uint16_t actions_len;         /* Size of action array in bytes. */
      struct ofp_action_header actions[0]; /* Actions. */
 -    /* uint8_t data[0]; */        /* Packet data.  The length is inferred 
 -                                     from the length field in the header.  
 +    /* uint8_t data[0]; */        /* Packet data.  The length is inferred
 +                                     from the length field in the header.
                                       (Only meaningful if buffer_id == -1.) */
  };
  OFP_ASSERT(sizeof(struct ofp_packet_out) == 16);
@@@ -461,14 -430,14 +455,14 @@@ enum ofp_flow_mod_command 
  
  /* Flow wildcards. */
  enum ofp_flow_wildcards {
 -    OFPFW_IN_PORT  = 1 << 0,  /* Switch input port. */
 -    OFPFW_DL_VLAN  = 1 << 1,  /* VLAN. */
 -    OFPFW_DL_SRC   = 1 << 2,  /* Ethernet source address. */
 -    OFPFW_DL_DST   = 1 << 3,  /* Ethernet destination address. */
 -    OFPFW_DL_TYPE  = 1 << 4,  /* Ethernet frame type. */
 -    OFPFW_NW_PROTO = 1 << 5,  /* IP protocol. */
 -    OFPFW_TP_SRC   = 1 << 6,  /* TCP/UDP source port. */
 -    OFPFW_TP_DST   = 1 << 7,  /* TCP/UDP destination port. */
 +    OFPFW_IN_PORT    = 1 << 0,  /* Switch input port. */
 +    OFPFW_DL_VLAN    = 1 << 1,  /* VLAN vid. */
 +    OFPFW_DL_SRC     = 1 << 2,  /* Ethernet source address. */
 +    OFPFW_DL_DST     = 1 << 3,  /* Ethernet destination address. */
 +    OFPFW_DL_TYPE    = 1 << 4,  /* Ethernet frame type. */
 +    OFPFW_NW_PROTO   = 1 << 5,  /* IP protocol. */
 +    OFPFW_TP_SRC     = 1 << 6,  /* TCP/UDP source port. */
 +    OFPFW_TP_DST     = 1 << 7,  /* TCP/UDP destination port. */
  
      /* IP source address wildcard bit count.  0 is exact match, 1 ignores the
       * LSB, 2 ignores the 2 least-significant bits, ..., 32 and higher wildcard
      OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT,
      OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT,
  
 +    OFPFW_DL_VLAN_PCP = 1 << 20, /* VLAN priority. */
 +    OFPFW_NW_TOS = 1 << 21, /* IP ToS (DSCP field, 6 bits). */
 +
      /* Wildcard all fields. */
 -    OFPFW_ALL = ((1 << 20) - 1)
 +    OFPFW_ALL = ((1 << 22) - 1)
  };
  
 -/* The wildcards for ICMP type and code fields use the transport source 
 +/* The wildcards for ICMP type and code fields use the transport source
   * and destination port fields, respectively. */
  #define OFPFW_ICMP_TYPE OFPFW_TP_SRC
  #define OFPFW_ICMP_CODE OFPFW_TP_DST
@@@ -520,21 -486,17 +514,21 @@@ struct ofp_match 
      uint8_t dl_src[OFP_ETH_ALEN]; /* Ethernet source address. */
      uint8_t dl_dst[OFP_ETH_ALEN]; /* Ethernet destination address. */
      uint16_t dl_vlan;          /* Input VLAN. */
 +    uint8_t dl_vlan_pcp;       /* Input VLAN priority. */
 +    uint8_t pad1[1];           /* Align to 64-bits. */
      uint16_t dl_type;          /* Ethernet frame type. */
 -    uint8_t nw_proto;          /* IP protocol. */
 -    uint8_t pad;               /* Align to 32-bits. */
 +    uint8_t nw_tos;            /* IP ToS (DSCP field, 6 bits). */
 +    uint8_t nw_proto;          /* IP protocol or lower 8 bits of
 +                                  ARP opcode. */
 +    uint8_t pad2[2];           /* Align to 64-bits. */
      uint32_t nw_src;           /* IP source address. */
      uint32_t nw_dst;           /* IP destination address. */
      uint16_t tp_src;           /* TCP/UDP source port. */
      uint16_t tp_dst;           /* TCP/UDP destination port. */
  };
 -OFP_ASSERT(sizeof(struct ofp_match) == 36);
 +OFP_ASSERT(sizeof(struct ofp_match) == 40);
  
 -/* The match fields for ICMP type and code use the transport source and 
 +/* The match fields for ICMP type and code use the transport source and
   * destination port fields, respectively. */
  #define icmp_type tp_src
  #define icmp_code tp_dst
  /* By default, choose a priority in the middle. */
  #define OFP_DEFAULT_PRIORITY 0x8000
  
 +enum ofp_flow_mod_flags {
 +    OFPFF_SEND_FLOW_REM = 1 << 0,  /* Send flow removed message when flow
 +                                    * expires or is deleted. */
 +    OFPFF_CHECK_OVERLAP = 1 << 1,  /* Check for overlapping entries first. */
 +    OFPFF_EMERG         = 1 << 2   /* Ramark this is for emergency. */
 +};
 +
  /* Flow setup and teardown (controller -> datapath). */
  struct ofp_flow_mod {
      struct ofp_header header;
      struct ofp_match match;      /* Fields to match */
 +    uint64_t cookie;             /* Opaque controller-issued identifier. */
  
      /* Flow actions. */
      uint16_t command;             /* One of OFPFC_*. */
      uint16_t idle_timeout;        /* Idle time before discarding (seconds). */
      uint16_t hard_timeout;        /* Max time before discarding (seconds). */
      uint16_t priority;            /* Priority level of flow entry. */
 -    uint32_t buffer_id;           /* Buffered packet to apply to (or -1). 
 +    uint32_t buffer_id;           /* Buffered packet to apply to (or -1).
                                       Not meaningful for OFPFC_DELETE*. */
 -    uint16_t out_port;            /* For OFPFC_DELETE* commands, require 
 -                                     matching entries to include this as an 
 -                                     output port.  A value of OFPP_NONE 
 +    uint16_t out_port;            /* For OFPFC_DELETE* commands, require
 +                                     matching entries to include this as an
 +                                     output port.  A value of OFPP_NONE
                                       indicates no restriction. */
 -    uint8_t pad[2];               /* Align to 32-bits. */
 -    uint32_t reserved;            /* Reserved for future use. */
 -    struct ofp_action_header actions[0]; /* The action length is inferred 
 -                                            from the length field in the 
 +    uint16_t flags;               /* One of OFPFF_*. */
 +    struct ofp_action_header actions[0]; /* The action length is inferred
 +                                            from the length field in the
                                              header. */
  };
 -OFP_ASSERT(sizeof(struct ofp_flow_mod) == 64);
 +OFP_ASSERT(sizeof(struct ofp_flow_mod) == 72);
  
 -/* Why did this flow expire? */
 -enum ofp_flow_expired_reason {
 -    OFPER_IDLE_TIMEOUT,         /* Flow idle time exceeded idle_timeout. */
 -    OFPER_HARD_TIMEOUT          /* Time exceeded hard_timeout. */
 +/* Why was this flow removed? */
 +enum ofp_flow_removed_reason {
 +    OFPRR_IDLE_TIMEOUT,         /* Flow idle time exceeded idle_timeout. */
 +    OFPRR_HARD_TIMEOUT,         /* Time exceeded hard_timeout. */
 +    OFPRR_DELETE                /* Evicted by a DELETE flow mod. */
  };
  
 -/* Flow expiration (datapath -> controller). */
 -struct ofp_flow_expired {
 +/* Flow removed (datapath -> controller). */
 +struct ofp_flow_removed {
      struct ofp_header header;
      struct ofp_match match;   /* Description of fields. */
 +    uint64_t cookie;          /* Opaque controller-issued identifier. */
  
      uint16_t priority;        /* Priority level of flow entry. */
 -    uint8_t reason;           /* One of OFPER_*. */
 +    uint8_t reason;           /* One of OFPRR_*. */
      uint8_t pad[1];           /* Align to 32-bits. */
  
 -    uint32_t duration;        /* Time flow was alive in seconds. */
 -    uint8_t pad2[4];          /* Align to 64-bits. */
 -    uint64_t packet_count;    
 +    uint32_t duration_sec;    /* Time flow was alive in seconds. */
 +    uint32_t duration_nsec;   /* Time flow was alive in nanoseconds beyond
 +                                 duration_sec. */
 +    uint16_t idle_timeout;    /* Idle timeout from original flow mod. */
 +    uint8_t pad2[2];          /* Align to 64-bits. */
 +    uint64_t packet_count;
      uint64_t byte_count;
  };
 -OFP_ASSERT(sizeof(struct ofp_flow_expired) == 72);
 +OFP_ASSERT(sizeof(struct ofp_flow_removed) == 88);
  
  /* Values for 'type' in ofp_error_message.  These values are immutable: they
   * will not change in future versions of the protocol (although new values may
@@@ -612,15 -562,13 +606,15 @@@ enum ofp_error_type 
      OFPET_BAD_REQUEST,          /* Request was not understood. */
      OFPET_BAD_ACTION,           /* Error in action description. */
      OFPET_FLOW_MOD_FAILED,      /* Problem modifying flow entry. */
 -    OFPET_PORT_MOD_FAILED       /* OFPT_PORT_MOD failed. */
 +    OFPET_PORT_MOD_FAILED,      /* OFPT_PORT_MOD failed. */
 +    OFPET_QUEUE_OP_FAILED       /* Queue operation failed. */
  };
  
  /* ofp_error_msg 'code' values for OFPET_HELLO_FAILED.  'data' contains an
   * ASCII text string that may give failure details. */
  enum ofp_hello_failed_code {
 -    OFPHFC_INCOMPATIBLE         /* No compatible version. */
 +    OFPHFC_INCOMPATIBLE,        /* No compatible version. */
 +    OFPHFC_EPERM                /* Permissions error. */
  };
  
  /* ofp_error_msg 'code' values for OFPET_BAD_REQUEST.  'data' contains at least
@@@ -629,16 -577,15 +623,16 @@@ enum ofp_bad_request_code 
      OFPBRC_BAD_VERSION,         /* ofp_header.version not supported. */
      OFPBRC_BAD_TYPE,            /* ofp_header.type not supported. */
      OFPBRC_BAD_STAT,            /* ofp_stats_request.type not supported. */
 -    OFPBRC_BAD_VENDOR,          /* Vendor not supported (in ofp_vendor_header 
 +    OFPBRC_BAD_VENDOR,          /* Vendor not supported (in ofp_vendor_header
                                   * or ofp_stats_request or ofp_stats_reply). */
      OFPBRC_BAD_SUBTYPE,         /* Vendor subtype not supported. */
 -    OFPBRC_BAD_LENGTH,          /* Wrong request length for type. */
 +    OFPBRC_EPERM,               /* Permissions error. */
 +    OFPBRC_BAD_LEN,             /* Wrong request length for type. */
      OFPBRC_BUFFER_EMPTY,        /* Specified buffer has already been used. */
 -    OFPBRC_BAD_COOKIE           /* Specified buffer does not exist. */
 +    OFPBRC_BUFFER_UNKNOWN       /* Specified buffer does not exist. */
  };
  
 -/* ofp_error_msg 'code' values for OFPET_BAD_ACTION.  'data' contains at least 
 +/* ofp_error_msg 'code' values for OFPET_BAD_ACTION.  'data' contains at least
   * the first 64 bytes of the failed request. */
  enum ofp_bad_action_code {
      OFPBAC_BAD_TYPE,           /* Unknown action type. */
      OFPBAC_BAD_VENDOR_TYPE,    /* Unknown action type for vendor id. */
      OFPBAC_BAD_OUT_PORT,       /* Problem validating output action. */
      OFPBAC_BAD_ARGUMENT,       /* Bad action argument. */
 -    OFPBAC_TOO_MANY            /* Can't handle this many actions. */
 +    OFPBAC_EPERM,              /* Permissions error. */
 +    OFPBAC_TOO_MANY,           /* Can't handle this many actions. */
 +    OFPBAC_BAD_QUEUE           /* Problem validating output queue. */
  };
  
 -/* ofp_error_msg 'code' values for OFPET_FLOW_MOD_FAILED.  'data' contains 
 +/* ofp_error_msg 'code' values for OFPET_FLOW_MOD_FAILED.  'data' contains
   * at least the first 64 bytes of the failed request. */
  enum ofp_flow_mod_failed_code {
      OFPFMFC_ALL_TABLES_FULL,    /* Flow not added because of full tables. */
 -    OFPFMFC_BAD_COMMAND         /* Unknown command. */
 +    OFPFMFC_OVERLAP,            /* Attempted to add overlapping flow with
 +                                 * CHECK_OVERLAP flag set. */
 +    OFPFMFC_EPERM,              /* Permissions error. */
 +    OFPFMFC_BAD_EMERG_TIMEOUT,  /* Flow not added because of non-zero idle/hard
 +                                 * timeout. */
 +    OFPFMFC_BAD_COMMAND,        /* Unknown command. */
 +    OFPFMFC_UNSUPPORTED         /* Unsupported action list - cannot process in
 +                                   the order specified. */
  };
  
  /* ofp_error_msg 'code' values for OFPET_PORT_MOD_FAILED.  'data' contains
@@@ -673,27 -611,19 +667,27 @@@ enum ofp_port_mod_failed_code 
      OFPPMFC_BAD_HW_ADDR,         /* Specified hardware address is wrong. */
  };
  
 +/* ofp_error msg 'code' values for OFPET_QUEUE_OP_FAILED. 'data' contains
 + * at least the first 64 bytes of the failed request */
 +enum ofp_queue_op_failed_code {
 +    OFPQOFC_BAD_PORT,           /* Invalid port (or port does not exist). */
 +    OFPQOFC_BAD_QUEUE,          /* Queue does not exist. */
 +    OFPQOFC_EPERM               /* Permissions error. */
 +};
 +
  /* OFPT_ERROR: Error message (datapath -> controller). */
  struct ofp_error_msg {
      struct ofp_header header;
  
      uint16_t type;
      uint16_t code;
 -    uint8_t data[0];          /* Variable-length data.  Interpreted based 
 +    uint8_t data[0];          /* Variable-length data.  Interpreted based
                                   on the type and code. */
  };
  OFP_ASSERT(sizeof(struct ofp_error_msg) == 12);
  
  enum ofp_stats_types {
 -    /* Description of this OpenFlow switch. 
 +    /* Description of this OpenFlow switch.
       * The request body is empty.
       * The reply body is struct ofp_desc_stats. */
      OFPST_DESC,
      OFPST_TABLE,
  
      /* Physical port statistics.
 -     * The request body is empty.
 +     * The request body is struct ofp_port_stats_request.
       * The reply body is an array of struct ofp_port_stats. */
      OFPST_PORT,
  
 +    /* Queue statistics for a port
 +     * The request body defines the port
 +     * The reply body is an array of struct ofp_queue_stats */
 +    OFPST_QUEUE,
 +
      /* Vendor extension.
       * The request and reply bodies begin with a 32-bit vendor ID, which takes
 -     * the same form as in "struct ofp_vendor_header".  The request and reply 
 +     * the same form as in "struct ofp_vendor_header".  The request and reply
       * bodies are otherwise vendor-defined. */
      OFPST_VENDOR = 0xffff
  };
@@@ -752,17 -677,15 +746,17 @@@ OFP_ASSERT(sizeof(struct ofp_stats_repl
  
  #define DESC_STR_LEN   256
  #define SERIAL_NUM_LEN 32
 -/* Body of reply to OFPST_DESC request.  Each entry is a NULL-terminated 
 +/* Body of reply to OFPST_DESC request.  Each entry is a NULL-terminated
   * ASCII string. */
  struct ofp_desc_stats {
      char mfr_desc[DESC_STR_LEN];       /* Manufacturer description. */
      char hw_desc[DESC_STR_LEN];        /* Hardware description. */
      char sw_desc[DESC_STR_LEN];        /* Software description. */
      char serial_num[SERIAL_NUM_LEN];   /* Serial number. */
 +    char dp_desc[DESC_STR_LEN];        /* Human readable description of
 +                                          the datapath. */
  };
 -OFP_ASSERT(sizeof(struct ofp_desc_stats) == 800);
 +OFP_ASSERT(sizeof(struct ofp_desc_stats) == 1056);
  
  /* Body for ofp_stats_request of type OFPST_FLOW. */
  struct ofp_flow_stats_request {
      uint8_t table_id;         /* ID of table to read (from ofp_table_stats)
                                   or 0xff for all tables. */
      uint8_t pad;              /* Align to 32 bits. */
 -    uint16_t out_port;        /* Require matching entries to include this 
 -                                 as an output port.  A value of OFPP_NONE 
 +    uint16_t out_port;        /* Require matching entries to include this
 +                                 as an output port.  A value of OFPP_NONE
                                   indicates no restriction. */
  };
 -OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 40);
 +OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 44);
  
  /* Body of reply to OFPST_FLOW request. */
  struct ofp_flow_stats {
      uint8_t table_id;         /* ID of table flow came from. */
      uint8_t pad;
      struct ofp_match match;   /* Description of fields. */
 -    uint32_t duration;        /* Time flow has been alive in seconds. */
 +    uint32_t duration_sec;    /* Time flow has been alive in seconds. */
 +    uint32_t duration_nsec;   /* Time flow has been alive in nanoseconds
 +                                 beyond duration_sec. */
      uint16_t priority;        /* Priority of the entry. Only meaningful
                                   when this is not an exact-match entry. */
      uint16_t idle_timeout;    /* Number of seconds idle before expiration. */
      uint16_t hard_timeout;    /* Number of seconds before expiration. */
 -    uint16_t pad2[3];         /* Pad to 64 bits. */
 +    uint8_t pad2[6];          /* Align to 64 bits. */
 +    uint64_t cookie;          /* Opaque controller-issued identifier. */
      uint64_t packet_count;    /* Number of packets in flow. */
      uint64_t byte_count;      /* Number of bytes in flow. */
      struct ofp_action_header actions[0]; /* Actions. */
  };
 -OFP_ASSERT(sizeof(struct ofp_flow_stats) == 72);
 +OFP_ASSERT(sizeof(struct ofp_flow_stats) == 88);
  
  /* Body for ofp_stats_request of type OFPST_AGGREGATE. */
  struct ofp_aggregate_stats_request {
      uint8_t table_id;         /* ID of table to read (from ofp_table_stats)
                                   or 0xff for all tables. */
      uint8_t pad;              /* Align to 32 bits. */
 -    uint16_t out_port;        /* Require matching entries to include this 
 -                                 as an output port.  A value of OFPP_NONE 
 +    uint16_t out_port;        /* Require matching entries to include this
 +                                 as an output port.  A value of OFPP_NONE
                                   indicates no restriction. */
  };
 -OFP_ASSERT(sizeof(struct ofp_aggregate_stats_request) == 40);
 +OFP_ASSERT(sizeof(struct ofp_aggregate_stats_request) == 44);
  
  /* Body of reply to OFPST_AGGREGATE request. */
  struct ofp_aggregate_stats_reply {
@@@ -820,11 -740,11 +814,11 @@@ OFP_ASSERT(sizeof(struct ofp_aggregate_
  
  /* Body of reply to OFPST_TABLE request. */
  struct ofp_table_stats {
 -    uint8_t table_id;        /* Identifier of table.  Lower numbered tables 
 +    uint8_t table_id;        /* Identifier of table.  Lower numbered tables
                                  are consulted first. */
      uint8_t pad[3];          /* Align to 32-bits. */
      char name[OFP_MAX_TABLE_NAME_LEN];
 -    uint32_t wildcards;      /* Bitmap of OFPFW_* wildcards that are 
 +    uint32_t wildcards;      /* Bitmap of OFPFW_* wildcards that are
                                  supported by the table. */
      uint32_t max_entries;    /* Max number of entries supported. */
      uint32_t active_count;   /* Number of active entries. */
  };
  OFP_ASSERT(sizeof(struct ofp_table_stats) == 64);
  
 +/* Body for ofp_stats_request of type OFPST_PORT. */
 +struct ofp_port_stats_request {
 +    uint16_t port_no;        /* OFPST_PORT message may request statistics
 +                                for a single port (specified with port_no)
 +                                or for all ports (port_no == OFPP_NONE). */
 +    uint8_t pad[6];
 +};
 +OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 8);
 +
  /* Body of reply to OFPST_PORT request. If a counter is unsupported, set
   * the field to all ones. */
  struct ofp_port_stats {
      uint64_t tx_packets;     /* Number of transmitted packets. */
      uint64_t rx_bytes;       /* Number of received bytes. */
      uint64_t tx_bytes;       /* Number of transmitted bytes. */
 -    uint64_t rx_dropped;     /* Number of packets dropped by RX. */ 
 -    uint64_t tx_dropped;     /* Number of packets dropped by TX. */ 
 +    uint64_t rx_dropped;     /* Number of packets dropped by RX. */
 +    uint64_t tx_dropped;     /* Number of packets dropped by TX. */
      uint64_t rx_errors;      /* Number of receive errors.  This is a super-set
                                  of receive errors and should be great than or
                                  equal to the sum of all rx_*_err values. */
      uint64_t tx_errors;      /* Number of transmit errors.  This is a super-set
                                  of transmit errors. */
 -    uint64_t rx_frame_err;   /* Number of frame alignment errors. */ 
 -    uint64_t rx_over_err;    /* Number of packets with RX overrun. */ 
 -    uint64_t rx_crc_err;     /* Number of CRC errors. */ 
 -    uint64_t collisions;     /* Number of collisions. */ 
 +    uint64_t rx_frame_err;   /* Number of frame alignment errors. */
 +    uint64_t rx_over_err;    /* Number of packets with RX overrun. */
 +    uint64_t rx_crc_err;     /* Number of CRC errors. */
 +    uint64_t collisions;     /* Number of collisions. */
  };
  OFP_ASSERT(sizeof(struct ofp_port_stats) == 104);
  
@@@ -107,6 -107,7 +107,7 @@@ struct odp_stats 
  /* Logical ports. */
  #define ODPP_LOCAL      ((__u16)0)
  #define ODPP_NONE       ((__u16)-1)
+ #define ODPP_NORMAL     ((__u16)-2)
  
  /* Listening channels. */
  #define _ODPL_MISS_NR   0       /* Packet missed in flow table. */
@@@ -201,9 -202,7 +202,9 @@@ struct odp_flow_key 
      __u8   dl_dst[ETH_ALEN];     /* Ethernet destination address. */
      __u8   nw_proto;             /* IP protocol or lower 8 bits of 
                                      ARP opcode. */
 -    __u8   reserved;             /* Pad to 64 bits. */
 +    __u8   dl_vlan_pcp;          /* Input VLAN priority. */
 +    __u8   nw_tos;               /* IP ToS (DSCP field, 6 bits). */
 +    __u8   reserved[3];          /* Align to 32-bits...must be zeroed. */
  };
  
  /* Flags for ODP_FLOW. */
@@@ -249,10 -248,9 +250,10 @@@ struct odp_flowvec 
  #define ODPAT_SET_DL_DST        7    /* Ethernet destination address. */
  #define ODPAT_SET_NW_SRC        8    /* IP source address. */
  #define ODPAT_SET_NW_DST        9    /* IP destination address. */
 -#define ODPAT_SET_TP_SRC        10   /* TCP/UDP source port. */
 -#define ODPAT_SET_TP_DST        11   /* TCP/UDP destination port. */
 -#define ODPAT_N_ACTIONS         12
 +#define ODPAT_SET_NW_TOS        10   /* IP ToS/DSCP field (6 bits). */
 +#define ODPAT_SET_TP_SRC        11   /* TCP/UDP source port. */
 +#define ODPAT_SET_TP_DST        12   /* TCP/UDP destination port. */
 +#define ODPAT_N_ACTIONS         13
  
  struct odp_action_output {
      __u16 type;                  /* ODPAT_OUTPUT. */
@@@ -304,14 -302,6 +305,14 @@@ struct odp_action_nw_addr 
      __be32 nw_addr;             /* IP address. */
  };
  
 +struct odp_action_nw_tos {
 +    __u16 type;                  /* ODPAT_SET_NW_TOS. */
 +    __u8 nw_tos;                 /* IP ToS/DSCP field (6 bits). */
 +    __u8 reserved1;
 +    __u16 reserved2;
 +    __u16 reserved3;
 +};
 +
  /* Action structure for ODPAT_SET_TP_SRC/DST. */
  struct odp_action_tp_port {
      __u16 type;                  /* ODPAT_SET_TP_SRC/DST. */
@@@ -329,7 -319,6 +330,7 @@@ union odp_action 
      struct odp_action_vlan_pcp vlan_pcp;
      struct odp_action_dl_addr dl_addr;
      struct odp_action_nw_addr nw_addr;
 +    struct odp_action_nw_tos nw_tos;
      struct odp_action_tp_port tp_port;
  };
  
diff --combined lib/classifier.c
@@@ -19,6 -19,7 +19,7 @@@
  #include <assert.h>
  #include <errno.h>
  #include <netinet/in.h>
+ #include "dynamic-string.h"
  #include "flow.h"
  #include "hash.h"
  
@@@ -48,8 -49,6 +49,8 @@@ static struct cls_rule *search_exact_ta
                                             size_t hash, const flow_t *);
  static bool rules_match_1wild(const struct cls_rule *fixed,
                                const struct cls_rule *wild, int field_idx);
 +static bool rules_match_2wild(const struct cls_rule *wild1,
 +                              const struct cls_rule *wild2, int field_idx);
  
  /* Converts the flow in 'flow' into a cls_rule in 'rule', with the given
   * 'wildcards' and 'priority'.*/
@@@ -57,7 -56,7 +58,7 @@@ voi
  cls_rule_from_flow(struct cls_rule *rule, const flow_t *flow,
                     uint32_t wildcards, unsigned int priority)
  {
 -    assert(flow->reserved == 0);
 +    assert(!flow->reserved[0] && !flow->reserved[1] && !flow->reserved[2]);
      rule->flow = *flow;
      flow_wildcards_init(&rule->wc, wildcards);
      rule->priority = priority;
@@@ -77,6 -76,18 +78,18 @@@ cls_rule_from_match(struct cls_rule *ru
      rule->table_idx = table_idx_from_wildcards(rule->wc.wildcards);
  }
  
+ /* Converts 'rule' to a string and returns the string.  The caller must free
+  * the string (with free()). */
+ char *
+ cls_rule_to_string(const struct cls_rule *rule)
+ {
+     struct ds s = DS_EMPTY_INITIALIZER;
+     ds_put_format(&s, "wildcards=%x priority=%u ",
+                   rule->wc.wildcards, rule->priority);
+     flow_format(&s, &rule->flow);
+     return ds_cstr(&s);
+ }
  /* Prints cls_rule 'rule', for debugging.
   *
   * (The output could be improved and expanded, but this was good enough to
@@@ -104,8 -115,7 +117,8 @@@ cls_rule_moved(struct classifier *cls, 
          if (new->wc.wildcards) {
              list_moved(&new->node.list);
          } else {
 -            hmap_moved(&cls->exact_table, &old->node.hmap, &new->node.hmap);
 +            hmap_node_moved(&cls->exact_table,
 +                            &old->node.hmap, &new->node.hmap);
          }
      }
  }
@@@ -338,43 -348,6 +351,43 @@@ classifier_find_rule_exactly(const stru
      return NULL;
  }
  
 +/* Checks if the flow defined by 'target' with 'wildcards' at 'priority' 
 + * overlaps with any other rule at the same priority in the classifier.  
 + * Two rules are considered overlapping if a packet could match both. */
 +bool
 +classifier_rule_overlaps(const struct classifier *cls,
 +                         const flow_t *target, uint32_t wildcards,
 +                         unsigned int priority)
 +{
 +    struct cls_rule target_rule;
 +    const struct hmap *tbl;
 +
 +    if (!wildcards) {
 +        return search_exact_table(cls, flow_hash(target, 0), target) ?
 +            true : false;
 +    }
 +
 +    cls_rule_from_flow(&target_rule, target, wildcards, priority);
 +
 +    for (tbl = &cls->tables[0]; tbl < &cls->tables[CLS_N_FIELDS]; tbl++) {
 +        struct cls_bucket *bucket;
 +
 +        HMAP_FOR_EACH (bucket, struct cls_bucket, hmap_node, tbl) {
 +            struct cls_rule *rule;
 +
 +            LIST_FOR_EACH (rule, struct cls_rule, node.list,
 +                           &bucket->rules) {
 +                if (rule->priority == priority 
 +                        && rules_match_2wild(rule, &target_rule, 0)) {
 +                    return true;
 +                }
 +            }
 +        }
 +    }
 +
 +    return false;
 +}
 +
  /* Ignores target->priority.
   *
   * 'callback' is allowed to delete the rule that is passed as its argument, but
@@@ -801,23 -774,6 +814,23 @@@ rules_match_1wild(const struct cls_rul
  {
      return rules_match(fixed, wild, wild->wc.wildcards, wild->wc.nw_src_mask,
                         wild->wc.nw_dst_mask, field_idx);
 +}
 +
 +/* Returns true if 'wild1' and 'wild2' match, that is, if their fields
 + * are equal modulo wildcards in 'wild1' or 'wild2'.
 + *
 + * 'field_idx' is the index of the first field to be compared; fields before
 + * 'field_idx' are assumed to match.  Always returns true if 'field_idx' is
 + * CLS_N_FIELDS. */
 +static bool
 +rules_match_2wild(const struct cls_rule *wild1, const struct cls_rule *wild2,
 +                  int field_idx)
 +{
 +    return rules_match(wild1, wild2, 
 +                       wild1->wc.wildcards | wild2->wc.wildcards, 
 +                       wild1->wc.nw_src_mask & wild2->wc.nw_src_mask,
 +                       wild1->wc.nw_dst_mask & wild2->wc.nw_dst_mask, 
 +                       field_idx);
  }
  
  /* Searches 'bucket' for a rule that matches 'target'.  Returns the
diff --combined lib/classifier.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.
      /*        -----------------  -----------  -------- */   \
      CLS_FIELD(OFPFW_IN_PORT,     in_port,     IN_PORT)      \
      CLS_FIELD(OFPFW_DL_VLAN,     dl_vlan,     DL_VLAN)      \
 +    CLS_FIELD(OFPFW_DL_VLAN_PCP, dl_vlan_pcp, DL_VLAN_PCP)  \
      CLS_FIELD(OFPFW_DL_SRC,      dl_src,      DL_SRC)       \
      CLS_FIELD(OFPFW_DL_DST,      dl_dst,      DL_DST)       \
      CLS_FIELD(OFPFW_DL_TYPE,     dl_type,     DL_TYPE)      \
      CLS_FIELD(OFPFW_NW_SRC_MASK, nw_src,      NW_SRC)       \
      CLS_FIELD(OFPFW_NW_DST_MASK, nw_dst,      NW_DST)       \
      CLS_FIELD(OFPFW_NW_PROTO,    nw_proto,    NW_PROTO)     \
 +    CLS_FIELD(OFPFW_NW_TOS,      nw_tos,      NW_TOS)       \
      CLS_FIELD(OFPFW_TP_SRC,      tp_src,      TP_SRC)       \
      CLS_FIELD(OFPFW_TP_DST,      tp_dst,      TP_DST)
  
@@@ -125,6 -123,7 +125,7 @@@ void cls_rule_from_flow(struct cls_rul
                          unsigned int priority);
  void cls_rule_from_match(struct cls_rule *, const struct ofp_match *,
                           unsigned int priority);
+ char *cls_rule_to_string(const struct cls_rule *);
  void cls_rule_print(const struct cls_rule *);
  void cls_rule_moved(struct classifier *,
                      struct cls_rule *old, struct cls_rule *new);
@@@ -144,8 -143,6 +145,8 @@@ struct cls_rule *classifier_lookup_wild
                                          const flow_t *);
  struct cls_rule *classifier_lookup_exact(const struct classifier *,
                                           const flow_t *);
 +bool classifier_rule_overlaps(const struct classifier *, const flow_t *, 
 +                              uint32_t wildcards, unsigned int priority);
  
  typedef void cls_cb_func(struct cls_rule *, void *aux);
  
diff --combined lib/compiler.h
  #ifndef COMPILER_H
  #define COMPILER_H 1
  
+ #ifdef __GNUC__
  #define NO_RETURN __attribute__((__noreturn__))
  #define OVS_UNUSED __attribute__((__unused__))
- #define PACKED __attribute__((__packed__))
  #define PRINTF_FORMAT(FMT, ARG1) __attribute__((__format__(printf, FMT, ARG1)))
  #define STRFTIME_FORMAT(FMT) __attribute__((__format__(__strftime__, FMT, 0)))
  #define MALLOC_LIKE __attribute__((__malloc__))
  #define ALWAYS_INLINE __attribute__((always_inline))
- #define likely(x) __builtin_expect((x),1)
- #define unlikely(x) __builtin_expect((x),0)
 +#define WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
+ #else
+ #define NO_RETURN
+ #define OVS_UNUSED
+ #define PRINTF_FORMAT(FMT, ARG1)
+ #define STRFTIME_FORMAT(FMT)
+ #define MALLOC_LIKE
+ #define ALWAYS_INLINE
++#define WARN_UNUSED_RESULT
+ #endif
  
  #endif /* compiler.h */
diff --combined lib/dpif-netdev.c
@@@ -22,8 -22,8 +22,8 @@@
  #include <errno.h>
  #include <fcntl.h>
  #include <inttypes.h>
- #include <net/if.h>
  #include <netinet/in.h>
+ #include <net/if.h>
  #include <stdlib.h>
  #include <string.h>
  #include <sys/ioctl.h>
@@@ -64,7 -64,7 +64,7 @@@ struct dp_netdev 
      struct list node;
      int dp_idx;
      int open_cnt;
 -    bool deleted;
 +    bool destroyed;
  
      bool drop_frags;            /* Drop all IP fragments, if true. */
      struct ovs_queue queues[N_QUEUES]; /* Messages queued for dpif_recv(). */
@@@ -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 OVS_UNUSED, char *suffix, bool create,
 +dpif_netdev_open(const char *name, const char *type OVS_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;
@@@ -307,17 -307,17 +307,17 @@@ dpif_netdev_close(struct dpif *dpif
  {
      struct dp_netdev *dp = get_dp_netdev(dpif);
      assert(dp->open_cnt > 0);
 -    if (--dp->open_cnt == 0 && dp->deleted) {
 +    if (--dp->open_cnt == 0 && dp->destroyed) {
          dp_netdev_free(dp);
      }
      free(dpif);
  }
  
  static int
 -dpif_netdev_delete(struct dpif *dpif)
 +dpif_netdev_destroy(struct dpif *dpif)
  {
      struct dp_netdev *dp = get_dp_netdev(dpif);
 -    dp->deleted = true;
 +    dp->destroyed = true;
      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);
  
@@@ -663,7 -664,7 +663,7 @@@ dp_netdev_lookup_flow(const struct dp_n
  {
      struct dp_netdev_flow *flow;
  
 -    assert(key->reserved == 0);
 +    assert(!key->reserved[0] && !key->reserved[1] && !key->reserved[2]);
      HMAP_FOR_EACH_WITH_HASH (flow, struct dp_netdev_flow, node,
                               flow_hash(key, 0), &dp->flow_table) {
          if (flow_equal(&flow->key, key)) {
@@@ -751,7 -752,7 +751,7 @@@ dpif_netdev_validate_actions(const unio
  
                case ODPAT_SET_VLAN_PCP:
              *mutates = true;
-                       if (a->vlan_pcp.vlan_pcp & ~VLAN_PCP_MASK) {
+                       if (a->vlan_pcp.vlan_pcp & ~(VLAN_PCP_MASK >> VLAN_PCP_SHIFT)) {
                                return EINVAL;
              }
                        break;
          case ODPAT_SET_DL_DST:
          case ODPAT_SET_NW_SRC:
          case ODPAT_SET_NW_DST:
 +        case ODPAT_SET_NW_TOS:
          case ODPAT_SET_TP_SRC:
          case ODPAT_SET_TP_DST:
              *mutates = true;
@@@ -804,9 -804,9 +804,9 @@@ 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;
 +    memset(flow->key.reserved, 0, sizeof flow->key.reserved);
  
      error = set_flow_actions(flow, odp_flow);
      if (error) {
@@@ -1171,23 -1171,6 +1171,23 @@@ dp_netdev_set_nw_addr(struct ofpbuf *pa
      }
  }
  
 +static void
 +dp_netdev_set_nw_tos(struct ofpbuf *packet, flow_t *key,
 +                     const struct odp_action_nw_tos *a)
 +{
 +    if (key->dl_type == htons(ETH_TYPE_IP)) {
 +        struct ip_header *nh = packet->l3;
 +        uint8_t *field = &nh->ip_tos;
 +
 +        /* Set the DSCP bits and preserve the ECN bits. */
 +        uint8_t new = (a->nw_tos & IP_DSCP_MASK) | (nh->ip_tos & IP_ECN_MASK);
 +
 +        nh->ip_csum = recalc_csum16(nh->ip_csum, htons((uint16_t)*field),
 +                htons((uint16_t)a->nw_tos));
 +        *field = new;
 +    }
 +}
 +
  static void
  dp_netdev_set_tp_port(struct ofpbuf *packet, flow_t *key,
                        const struct odp_action_tp_port *a)
@@@ -1290,8 -1273,9 +1290,9 @@@ dp_netdev_execute_actions(struct dp_net
              break;
  
                case ODPAT_SET_VLAN_PCP:
-                       dp_netdev_modify_vlan_tci(packet, key, a->vlan_pcp.vlan_pcp << 13,
-                                       VLAN_PCP_MASK);
+                       dp_netdev_modify_vlan_tci(
+                 packet, key, a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT,
+                 VLAN_PCP_MASK);
              break;
  
                case ODPAT_STRIP_VLAN:
                        dp_netdev_set_nw_addr(packet, key, &a->nw_addr);
                        break;
  
 +              case ODPAT_SET_NW_TOS:
 +                      dp_netdev_set_nw_tos(packet, key, &a->nw_tos);
 +                      break;
 +
                case ODPAT_SET_TP_SRC:
                case ODPAT_SET_TP_DST:
                        dp_netdev_set_tp_port(packet, key, &a->tp_port);
  }
  
  const struct dpif_class dpif_netdev_class = {
 -    "netdev",
      "netdev",
      dp_netdev_run,
      dp_netdev_wait,
      dpif_netdev_open,
      dpif_netdev_close,
      NULL,                       /* get_all_names */
 -    dpif_netdev_delete,
 +    dpif_netdev_destroy,
      dpif_netdev_get_stats,
      dpif_netdev_get_drop_frags,
      dpif_netdev_set_drop_frags,
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>
  #include <stdint.h>
  
+ #ifdef  __cplusplus
+ extern "C" {
+ #endif
  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 *);
@@@ -97,4 -97,8 +101,8 @@@ void dpif_recv_wait(struct dpif *)
  void dpif_get_netflow_ids(const struct dpif *,
                            uint8_t *engine_type, uint8_t *engine_id);
  
+ #ifdef  __cplusplus
+ }
+ #endif
  #endif /* dpif.h */
diff --combined lib/flow.h
@@@ -16,6 -16,7 +16,7 @@@
  #ifndef FLOW_H
  #define FLOW_H 1
  
+ #include <sys/types.h>
  #include <netinet/in.h>
  #include <stdbool.h>
  #include <stdint.h>
@@@ -36,6 -37,7 +37,6 @@@ int flow_extract(struct ofpbuf *, uint1
  void flow_extract_stats(const flow_t *flow, struct ofpbuf *packet, 
          struct odp_flow_stats *stats);
  void flow_to_match(const flow_t *, uint32_t wildcards, struct ofp_match *);
 -void flow_to_ovs_match(const flow_t *, uint32_t wildcards, struct ofp_match *);
  void flow_from_match(flow_t *, uint32_t *wildcards, const struct ofp_match *);
  char *flow_to_string(const flow_t *);
  void flow_format(struct ds *, const flow_t *);
diff --combined lib/ofp-print.c
  
  #include <config.h>
  #include "ofp-print.h"
- #include "xtoxll.h"
  
  #include <errno.h>
  #include <inttypes.h>
+ #include <sys/types.h>
  #include <netinet/in.h>
  #include <sys/wait.h>
  #include <stdarg.h>
@@@ -35,6 -35,7 +35,7 @@@
  #include "packets.h"
  #include "pcap.h"
  #include "util.h"
+ #include "xtoxll.h"
  
  static void ofp_print_port_name(struct ds *string, uint16_t port);
  
@@@ -243,10 -244,6 +244,10 @@@ ofp_print_action(struct ds *string, con
              sizeof(struct ofp_action_nw_addr),
              sizeof(struct ofp_action_nw_addr),
          },
 +        [OFPAT_SET_NW_TOS] = {
 +            sizeof(struct ofp_action_nw_tos),
 +            sizeof(struct ofp_action_nw_tos),
 +        },
          [OFPAT_SET_TP_SRC] = {
              sizeof(struct ofp_action_tp_port),
              sizeof(struct ofp_action_tp_port),
          break;
      }
  
 +    case OFPAT_SET_NW_TOS: {
 +        struct ofp_action_nw_tos *nt = (struct ofp_action_nw_tos *)ah;
 +        ds_put_format(string, "mod_nw_tos:%d", nt->nw_tos);
 +        break;
 +    }
 +
      case OFPAT_SET_TP_SRC: {
          struct ofp_action_tp_port *ta = (struct ofp_action_tp_port *)ah;
          ds_put_format(string, "mod_tp_src:%d", ntohs(ta->tp_port));
@@@ -552,7 -543,7 +553,7 @@@ ofp_print_switch_features(struct ds *st
      int n_ports;
      int i;
  
 -    ds_put_format(string, " ver:0x%x, dpid:%"PRIx64"\n", 
 +    ds_put_format(string, " ver:0x%x, dpid:%016"PRIx64"\n", 
              osf->header.version, ntohll(osf->datapath_id));
      ds_put_format(string, "n_tables:%d, n_buffers:%d\n", osf->n_tables,
              ntohl(osf->n_buffers));
@@@ -582,6 -573,10 +583,6 @@@ ofp_print_switch_config(struct ds *stri
      uint16_t flags;
  
      flags = ntohs(osc->flags);
 -    if (flags & OFPC_SEND_FLOW_EXP) {
 -        flags &= ~OFPC_SEND_FLOW_EXP;
 -        ds_put_format(string, " (sending flow expirations)");
 -    }
      if (flags) {
          ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***", flags);
      }
@@@ -675,8 -670,6 +676,8 @@@ ofp_match_to_string(const struct ofp_ma
                 "%d", ntohs(om->in_port));
      print_wild(&f, "dl_vlan=", w & OFPFW_DL_VLAN, verbosity,
                 "0x%04x", ntohs(om->dl_vlan));
 +    print_wild(&f, "dl_vlan_pcp=", w & OFPFW_DL_VLAN_PCP, verbosity,
 +               "%d", om->dl_vlan_pcp);
      print_wild(&f, "dl_src=", w & OFPFW_DL_SRC, verbosity,
                 ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_src));
      print_wild(&f, "dl_dst=", w & OFPFW_DL_DST, verbosity,
      print_ip_netmask(&f, "nw_dst=", om->nw_dst,
                       (w & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT, verbosity);
      if (!skip_proto) {
 -        print_wild(&f, "nw_proto=", w & OFPFW_NW_PROTO, verbosity,
 -                   "%u", om->nw_proto);
 +        if (om->dl_type == htons(ETH_TYPE_ARP)) {
 +            print_wild(&f, "opcode=", w & OFPFW_NW_PROTO, verbosity,
 +                       "%u", om->nw_proto);
 +        } else {
 +            print_wild(&f, "nw_proto=", w & OFPFW_NW_PROTO, verbosity,
 +                       "%u", om->nw_proto);
 +            print_wild(&f, "nw_tos=", w & OFPFW_NW_TOS, verbosity,
 +                       "%u", om->nw_tos);
 +        }
      }
      if (om->nw_proto == IP_TYPE_ICMP) {
          print_wild(&f, "icmp_type=", w & OFPFW_ICMP_TYPE, verbosity,
@@@ -742,48 -728,41 +743,48 @@@ ofp_print_flow_mod(struct ds *string, c
      default:
          ds_put_format(string, " cmd:%d ", ntohs(ofm->command));
      }
 -    ds_put_format(string, "idle:%d hard:%d pri:%d buf:%#x", 
 +    ds_put_format(string, "cookie:%"PRIx64" idle:%d hard:%d pri:%d "
 +            "buf:%#x flags:%"PRIx16" ", ntohll(ofm->cookie), 
              ntohs(ofm->idle_timeout), ntohs(ofm->hard_timeout),
              ofm->match.wildcards ? ntohs(ofm->priority) : (uint16_t)-1,
 -            ntohl(ofm->buffer_id));
 +            ntohl(ofm->buffer_id), ntohs(ofm->flags));
      ofp_print_actions(string, ofm->actions,
                        len - offsetof(struct ofp_flow_mod, actions));
      ds_put_char(string, '\n');
  }
  
 -/* Pretty-print the OFPT_FLOW_EXPIRED packet of 'len' bytes at 'oh' to 'string'
 +/* Pretty-print the OFPT_FLOW_REMOVED packet of 'len' bytes at 'oh' to 'string'
   * at the given 'verbosity' level. */
  static void
 -ofp_print_flow_expired(struct ds *string, const void *oh,
 +ofp_print_flow_removed(struct ds *string, const void *oh, 
                         size_t len OVS_UNUSED, int verbosity)
  {
 -    const struct ofp_flow_expired *ofe = oh;
 +    const struct ofp_flow_removed *ofr = oh;
  
 -    ofp_print_match(string, &ofe->match, verbosity);
 +    ofp_print_match(string, &ofr->match, verbosity);
      ds_put_cstr(string, " reason=");
 -    switch (ofe->reason) {
 -    case OFPER_IDLE_TIMEOUT:
 +    switch (ofr->reason) {
 +    case OFPRR_IDLE_TIMEOUT:
          ds_put_cstr(string, "idle");
          break;
 -    case OFPER_HARD_TIMEOUT:
 +    case OFPRR_HARD_TIMEOUT:
          ds_put_cstr(string, "hard");
          break;
 +    case OFPRR_DELETE:
 +        ds_put_cstr(string, "delete");
 +        break;
      default:
 -        ds_put_format(string, "**%"PRIu8"**", ofe->reason);
 +        ds_put_format(string, "**%"PRIu8"**", ofr->reason);
          break;
      }
      ds_put_format(string, 
 -         " pri%"PRIu16" secs%"PRIu32" pkts%"PRIu64" bytes%"PRIu64"\n", 
 -         ofe->match.wildcards ? ntohs(ofe->priority) : (uint16_t)-1,
 -         ntohl(ofe->duration), ntohll(ofe->packet_count), 
 -         ntohll(ofe->byte_count));
 +         " cookie%"PRIx64" pri%"PRIu16" secs%"PRIu32" nsecs%"PRIu32
 +         " idle%"PRIu16" pkts%"PRIu64" bytes%"PRIu64"\n", 
 +         ntohll(ofr->cookie),
 +         ofr->match.wildcards ? ntohs(ofr->priority) : (uint16_t)-1,
 +         ntohl(ofr->duration_sec), ntohl(ofr->duration_nsec),
 +         ntohs(ofr->idle_timeout), ntohll(ofr->packet_count), 
 +         ntohll(ofr->byte_count));
  }
  
  static void
@@@ -814,7 -793,6 +815,7 @@@ static const struct error_type error_ty
  #define ERROR_CODE(TYPE, CODE) {TYPE, CODE, #CODE}
      ERROR_TYPE(OFPET_HELLO_FAILED),
      ERROR_CODE(OFPET_HELLO_FAILED, OFPHFC_INCOMPATIBLE),
 +    ERROR_CODE(OFPET_HELLO_FAILED, OFPHFC_EPERM),
  
      ERROR_TYPE(OFPET_BAD_REQUEST),
      ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_VERSION),
      ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT),
      ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR),
      ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE),
 -    ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH),
 +    ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_EPERM),
 +    ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN),
      ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BUFFER_EMPTY),
 -    ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_COOKIE),
 +    ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BUFFER_UNKNOWN),
  
      ERROR_TYPE(OFPET_BAD_ACTION),
      ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE),
      ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE),
      ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT),
      ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT),
 +    ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_EPERM),
      ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_TOO_MANY),
  
      ERROR_TYPE(OFPET_FLOW_MOD_FAILED),
      ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_ALL_TABLES_FULL),
 +    ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_OVERLAP),
 +    ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_EPERM),
 +    ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_BAD_EMERG_TIMEOUT),
      ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_BAD_COMMAND),
  
      ERROR_TYPE(OFPET_PORT_MOD_FAILED),
@@@ -933,16 -906,10 +934,16 @@@ ofp_desc_stats_reply(struct ds *string
  {
      const struct ofp_desc_stats *ods = body;
  
 -    ds_put_format(string, "Manufacturer: %s\n", ods->mfr_desc);
 -    ds_put_format(string, "Hardware: %s\n", ods->hw_desc);
 -    ds_put_format(string, "Software: %s\n", ods->sw_desc);
 -    ds_put_format(string, "Serial Num: %s\n", ods->serial_num);
 +    ds_put_format(string, "Manufacturer: %.*s\n", 
 +            (int) sizeof ods->mfr_desc, ods->mfr_desc);
 +    ds_put_format(string, "Hardware: %.*s\n",
 +            (int) sizeof ods->hw_desc, ods->hw_desc);
 +    ds_put_format(string, "Software: %.*s\n",
 +            (int) sizeof ods->sw_desc, ods->sw_desc);
 +    ds_put_format(string, "Serial Num: %.*s\n",
 +            (int) sizeof ods->serial_num, ods->serial_num);
 +    ds_put_format(string, "DP Description: %.*s\n",
 +            (int) sizeof ods->dp_desc, ods->dp_desc);
  }
  
  static void
@@@ -999,11 -966,7 +1000,11 @@@ ofp_flow_stats_reply(struct ds *string
              break;
          }
  
 -        ds_put_format(string, "  duration=%"PRIu32"s, ", ntohl(fs->duration));
 +        ds_put_format(string, "  cookie=%"PRIu64"s, ", ntohll(fs->cookie));
 +        ds_put_format(string, "duration_sec=%"PRIu32"s, ", 
 +                    ntohl(fs->duration_sec));
 +        ds_put_format(string, "duration_nsec=%"PRIu32"s, ", 
 +                    ntohl(fs->duration_nsec));
          ds_put_format(string, "table_id=%"PRIu8", ", fs->table_id);
          ds_put_format(string, "priority=%"PRIu16", ", 
                      fs->match.wildcards ? ntohs(fs->priority) : (uint16_t)-1);
@@@ -1068,14 -1031,6 +1069,14 @@@ static void print_port_stat(struct ds *
      }
  }
  
 +static void
 +ofp_port_stats_request(struct ds *string, const void *body_,
 +                       size_t len OVS_UNUSED, int verbosity OVS_UNUSED)
 +{
 +    const struct ofp_port_stats_request *psr = body_;
 +    ds_put_format(string, "port_no=%"PRIu16, ntohs(psr->port_no));
 +}
 +
  static void
  ofp_port_stats_reply(struct ds *string, const void *body, size_t len,
                       int verbosity)
@@@ -1200,9 -1155,7 +1201,9 @@@ print_stats(struct ds *string, int type
          {
              OFPST_PORT,
              "port",
 -            { 0, 0, NULL, },
 +            { sizeof(struct ofp_port_stats_request), 
 +              sizeof(struct ofp_port_stats_request), 
 +              ofp_port_stats_request },
              { 0, SIZE_MAX, ofp_port_stats_reply },
          },
          {
@@@ -1357,10 -1310,10 +1358,10 @@@ static const struct openflow_packet pac
          ofp_print_flow_mod,
      },
      {
 -        OFPT_FLOW_EXPIRED,
 -        "flow_expired",
 -        sizeof (struct ofp_flow_expired),
 -        ofp_print_flow_expired,
 +        OFPT_FLOW_REMOVED,
 +        "flow_removed",
 +        sizeof (struct ofp_flow_removed),
 +        ofp_print_flow_removed,
      },
      {
          OFPT_PORT_MOD,
          sizeof (struct ofp_vendor_header),
          NULL,
      },
 +    {
 +        OFPT_BARRIER_REQUEST,
 +        "barrier_request",
 +        sizeof (struct ofp_header),
 +        NULL,
 +    },
 +    {
 +        OFPT_BARRIER_REPLY,
 +        "barrier_reply",
 +        sizeof (struct ofp_header),
 +        NULL,
 +    }
  };
  
  /* Composes and returns a string representing the OpenFlow packet of 'len'
diff --combined lib/packets.h
@@@ -26,8 -26,6 +26,8 @@@
  
  struct ofpbuf;
  
 +bool dpid_from_string(const char *s, uint64_t *dpidp);
 +
  #define ETH_ADDR_LEN           6
  
  static const uint8_t eth_addr_broadcast[ETH_ADDR_LEN] OVS_UNUSED
@@@ -38,16 -36,21 +38,16 @@@ static inline bool eth_addr_is_broadcas
      return (ea[0] & ea[1] & ea[2] & ea[3] & ea[4] & ea[5]) == 0xff;
  }
  
 -/* Returns true if 'ea' is an Ethernet address used for virtual interfaces
 - * under XenServer.  Generally the actual Ethernet address is FE:FF:FF:FF:FF:FF
 - * but it can be FE:FE:FE:FE:FE:FE in some cases. */
 -static inline bool eth_addr_is_vif(const uint8_t ea[6])
 -{
 -    return ea[0] == 0xfe && (ea[1] & ea[2] & ea[3] & ea[4] & ea[5]) >= 0xfe;
 -}
 -
  static inline bool eth_addr_is_multicast(const uint8_t ea[6])
  {
      return ea[0] & 1;
  }
  static inline bool eth_addr_is_local(const uint8_t ea[6]) 
  {
 -    return ea[0] & 2;
 +    /* Local if it is either a locally administered address or a Nicira random
 +     * address. */
 +    return !!(ea[0] & 2)
 +       || (ea[0] == 0x00 && ea[1] == 0x23 && ea[2] == 0x20 && !!(ea[3] & 0x80));
  }
  static inline bool eth_addr_is_zero(const uint8_t ea[6]) 
  {
@@@ -86,18 -89,6 +86,18 @@@ static inline void eth_addr_random(uint
      random_bytes(ea, ETH_ADDR_LEN);
      eth_addr_mark_random(ea);
  }
 +static inline void eth_addr_nicira_random(uint8_t ea[ETH_ADDR_LEN])
 +{
 +    eth_addr_random(ea);
 +
 +    /* Set the OUI to the Nicira one. */
 +    ea[0] = 0x00;
 +    ea[1] = 0x23;
 +    ea[2] = 0x20;
 +
 +    /* Set the top bit to indicate random Nicira address. */
 +    ea[3] |= 0x80;
 +}
  /* Returns true if 'ea' is a reserved multicast address, that a bridge must
   * never forward, false otherwise. */
  static inline bool eth_addr_is_reserved(const uint8_t ea[ETH_ADDR_LEN])
              && (ea[5] & 0xf0) == 0x00);
  }
  
 +bool eth_addr_from_string(const char *, uint8_t ea[ETH_ADDR_LEN]);
 +
  void compose_benign_packet(struct ofpbuf *, const char *tag,
                             uint16_t snap_type,
                             const uint8_t eth_src[ETH_ADDR_LEN]);
@@@ -190,7 -179,10 +190,10 @@@ struct llc_snap_header 
  BUILD_ASSERT_DECL(LLC_SNAP_HEADER_LEN == sizeof(struct llc_snap_header));
  
  #define VLAN_VID_MASK 0x0fff
+ #define VLAN_VID_SHIFT 0
  #define VLAN_PCP_MASK 0xe000
+ #define VLAN_PCP_SHIFT 13
  
  #define VLAN_HEADER_LEN 4
  struct vlan_header {
@@@ -224,10 -216,6 +227,10 @@@ BUILD_ASSERT_DECL(VLAN_ETH_HEADER_LEN =
  #define IP_IHL(ip_ihl_ver) ((ip_ihl_ver) & 15)
  #define IP_IHL_VER(ihl, ver) (((ver) << 4) | (ihl))
  
 +/* TOS fields. */
 +#define IP_ECN_MASK 0x03
 +#define IP_DSCP_MASK 0xfc
 +
  #define IP_TYPE_ICMP 1
  #define IP_TYPE_TCP 6
  #define IP_TYPE_UDP 17
diff --combined lib/poll-loop.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.
  
  #include <poll.h>
  
+ #ifdef  __cplusplus
+ extern "C" {
+ #endif
  struct poll_waiter;
  
  /* Schedule events to wake up the following poll_block(). */
@@@ -44,7 -48,16 +48,11 @@@ void poll_immediate_wake(void)
  /* Wait until an event occurs. */
  void poll_block(void);
  
 -/* Autonomous function callbacks. */
 -typedef void poll_fd_func(int fd, short int revents, void *aux);
 -struct poll_waiter *poll_fd_callback(int fd, short int events,
 -                                     poll_fd_func *, void *aux);
 -
  /* Cancel a file descriptor callback or event. */
  void poll_cancel(struct poll_waiter *);
  
+ #ifdef  __cplusplus
+ }
+ #endif
  #endif /* poll-loop.h */
diff --combined lib/rconn.c
@@@ -76,6 -76,7 +76,7 @@@ struct rconn 
      time_t last_connected;
      unsigned int packets_sent;
      unsigned int seqno;
+     int last_error;
  
      /* In S_ACTIVE and S_IDLE, probably_admitted reports whether we believe
       * that the peer has made a (positive) admission control decision on our
@@@ -136,6 -137,7 +137,7 @@@ static void state_transition(struct rco
  static void set_vconn_name(struct rconn *, const char *name);
  static int try_send(struct rconn *);
  static int reconnect(struct rconn *);
+ static void report_error(struct rconn *, int error);
  static void disconnect(struct rconn *, int error);
  static void flush_queue(struct rconn *);
  static void question_connectivity(struct rconn *);
@@@ -176,7 -178,7 +178,7 @@@ rconn_new_from_vconn(const char *name, 
  struct rconn *
  rconn_create(int probe_interval, int max_backoff)
  {
 -    struct rconn *rc = xcalloc(1, sizeof *rc);
 +    struct rconn *rc = xzalloc(sizeof *rc);
  
      rc->state = S_VOID;
      rc->state_entered = time_now();
@@@ -272,6 -274,7 +274,7 @@@ voi
  rconn_reconnect(struct rconn *rc)
  {
      if (rc->state & (S_ACTIVE | S_IDLE)) {
+         VLOG_INFO("%s: disconnecting", rc->name);
          disconnect(rc, 0);
      }
  }
@@@ -341,7 -344,7 +344,7 @@@ reconnect(struct rconn *rc
      } else {
          VLOG_WARN("%s: connection failed (%s)", rc->name, strerror(retval));
          rc->backoff_deadline = TIME_MAX; /* Prevent resetting backoff. */
-         disconnect(rc, 0);
+         disconnect(rc, retval);
      }
      return retval;
  }
@@@ -381,7 -384,7 +384,7 @@@ run_CONNECTING(struct rconn *rc
      } else if (timed_out(rc)) {
          VLOG_INFO("%s: connection timed out", rc->name);
          rc->backoff_deadline = TIME_MAX; /* Prevent resetting backoff. */
-         disconnect(rc, 0);
+         disconnect(rc, ETIMEDOUT);
      }
  }
  
@@@ -446,7 -449,7 +449,7 @@@ run_IDLE(struct rconn *rc
          VLOG_ERR("%s: no response to inactivity probe after %u "
                   "seconds, disconnecting",
                   rc->name, elapsed_in_this_state(rc));
-         disconnect(rc, 0);
+         disconnect(rc, ETIMEDOUT);
      } else {
          do_tx_work(rc);
      }
@@@ -459,15 -462,6 +462,15 @@@ voi
  rconn_run(struct rconn *rc)
  {
      int old_state;
 +    size_t i;
 +
 +    if (rc->vconn) {
 +        vconn_run(rc->vconn);
 +    }
 +    for (i = 0; i < rc->n_monitors; i++) {
 +        vconn_run(rc->monitors[i]);
 +    }
 +
      do {
          old_state = rc->state;
          switch (rc->state) {
  void
  rconn_run_wait(struct rconn *rc)
  {
 -    unsigned int timeo = timeout(rc);
 +    unsigned int timeo;
 +    size_t i;
 +
 +    if (rc->vconn) {
 +        vconn_run_wait(rc->vconn);
 +    }
 +    for (i = 0; i < rc->n_monitors; i++) {
 +        vconn_run_wait(rc->monitors[i]);
 +    }
 +
 +    timeo = timeout(rc);
      if (timeo != UINT_MAX) {
          unsigned int expires = sat_add(rc->state_entered, timeo);
          unsigned int remaining = sat_sub(expires, time_now());
@@@ -530,6 -514,7 +533,7 @@@ rconn_recv(struct rconn *rc
              }
              return buffer;
          } else if (error != EAGAIN) {
+             report_error(rc, error);
              disconnect(rc, error);
          }
      }
@@@ -808,6 -793,22 +812,22 @@@ rconn_get_connection_seqno(const struc
  {
      return rc->seqno;
  }
+ /* Returns a value that explains why 'rc' last disconnected:
+  *
+  *   - 0 means that the last disconnection was caused by a call to
+  *     rconn_disconnect(), or that 'rc' is new and has not yet completed its
+  *     initial connection or connection attempt.
+  *
+  *   - EOF means that the connection was closed in the normal way by the peer.
+  *
+  *   - A positive integer is an errno value that represents the error.
+  */
+ int
+ rconn_get_last_error(const struct rconn *rc)
+ {
+     return rc->last_error;
+ }
  \f
  struct rconn_packet_counter *
  rconn_packet_counter_create(void)
@@@ -868,6 -869,7 +888,7 @@@ try_send(struct rconn *rc
      retval = vconn_send(rc->vconn, rc->txq.head);
      if (retval) {
          if (retval != EAGAIN) {
+             report_error(rc, retval);
              disconnect(rc, retval);
          }
          return retval;
      return 0;
  }
  
- /* Disconnects 'rc'.  'error' is used only for logging purposes.  If it is
-  * nonzero, then it should be EOF to indicate the connection was closed by the
-  * peer in a normal fashion or a positive errno value. */
+ /* Reports that 'error' caused 'rc' to disconnect.  'error' may be a positive
+  * errno value, or it may be EOF to indicate that the connection was closed
+  * normally. */
+ static void
+ report_error(struct rconn *rc, int error)
+ {
+     if (error == EOF) {
+         /* If 'rc' isn't reliable, then we don't really expect this connection
+          * to last forever anyway (probably it's a connection that we received
+          * via accept()), so use DBG level to avoid cluttering the logs. */
+         enum vlog_level level = rc->reliable ? VLL_INFO : VLL_DBG;
+         VLOG(level, "%s: connection closed by peer", rc->name);
+     } else {
+         VLOG_WARN("%s: connection dropped (%s)", rc->name, strerror(error));
+     }
+ }
+ /* Disconnects 'rc' and records 'error' as the error that caused 'rc''s last
+  * disconnection:
+  *
+  *   - 0 means that this disconnection is due to a request by 'rc''s client,
+  *     not due to any kind of network error.
+  *
+  *   - EOF means that the connection was closed in the normal way by the peer.
+  *
+  *   - A positive integer is an errno value that represents the error.
+  */
  static void
  disconnect(struct rconn *rc, int error)
  {
+     rc->last_error = error;
      if (rc->reliable) {
          time_t now = time_now();
  
          if (rc->state & (S_CONNECTING | S_ACTIVE | S_IDLE)) {
-             if (error > 0) {
-                 VLOG_WARN("%s: connection dropped (%s)",
-                           rc->name, strerror(error));
-             } else if (error == EOF) {
-                 if (rc->reliable) {
-                     VLOG_INFO("%s: connection closed by peer", rc->name);
-                 }
-             } else {
-                 VLOG_INFO("%s: connection dropped", rc->name);
-             }
              vconn_close(rc->vconn);
              rc->vconn = NULL;
              flush_queue(rc);
diff --combined lib/stp.c
+++ b/lib/stp.c
@@@ -18,6 -18,8 +18,8 @@@
   * applies to all modifications. */
  
  #include "stp.h"
+ #include <sys/types.h>
+ #include <netinet/in.h>
  #include <arpa/inet.h>
  #include <assert.h>
  #include <inttypes.h>
@@@ -214,7 -216,7 +216,7 @@@ stp_create(const char *name, stp_identi
      struct stp *stp;
      struct stp_port *p;
  
 -    stp = xcalloc(1, sizeof *stp);
 +    stp = xzalloc(sizeof *stp);
      stp->name = xstrdup(name);
      stp->bridge_id = bridge_id;
      if (!(stp->bridge_id >> 48)) {
  void
  stp_destroy(struct stp *stp)
  {
 -    free(stp);
 +    if (stp) {
 +        free(stp->name);
 +        free(stp);
 +    }
  }
  
  /* Runs 'stp' given that 'ms' milliseconds have passed. */
diff --combined lib/util.h
@@@ -76,8 -76,6 +76,6 @@@ extern const char *program_name
  #endif
  
  #define NOT_REACHED() abort()
- #define NOT_IMPLEMENTED() abort()
- #define NOT_TESTED() ((void) 0) /* XXX should print a message. */
  
  /* Given POINTER, the address of the given MEMBER in a STRUCT object, returns
     the STRUCT object. */
@@@ -98,7 -96,6 +96,7 @@@ void ovs_print_version(char *date, cha
  void out_of_memory(void) NO_RETURN;
  void *xmalloc(size_t) MALLOC_LIKE;
  void *xcalloc(size_t, size_t) MALLOC_LIKE;
 +void *xzalloc(size_t) MALLOC_LIKE;
  void *xrealloc(void *, size_t);
  void *xmemdup(const void *, size_t) MALLOC_LIKE;
  char *xmemdup0(const char *, size_t) MALLOC_LIKE;
@@@ -121,14 -118,6 +119,14 @@@ bool str_to_uint(const char *, int base
  bool str_to_ulong(const char *, int base, unsigned long *);
  bool str_to_ullong(const char *, int base, unsigned long long *);
  
 +bool str_to_double(const char *, double *);
 +
 +int hexit_value(int c);
 +
 +char *dir_name(const char *file_name);
 +
 +void ignore(bool x OVS_UNUSED);
 +
  #ifdef  __cplusplus
  }
  #endif
diff --combined lib/vconn.c
@@@ -90,8 -90,7 +90,8 @@@ check_vconn_classes(void
          struct vconn_class *class = vconn_classes[i];
          assert(class->name != NULL);
          assert(class->open != NULL);
 -        if (class->close || class->recv || class->send || class->wait) {
 +        if (class->close || class->recv || class->send
 +            || class->run || class->run_wait || class->wait) {
              assert(class->close != NULL);
              assert(class->recv != NULL);
              assert(class->send != NULL);
@@@ -164,6 -163,42 +164,42 @@@ vconn_usage(bool active, bool passive, 
  #endif
  }
  
+ /* Given 'name', a connection name in the form "TYPE:ARGS", stores the class
+  * named "TYPE" into '*classp' and returns 0.  Returns EAFNOSUPPORT and stores
+  * a null pointer into '*classp' if 'name' is in the wrong form or if no such
+  * class exists. */
+ static int
+ vconn_lookup_class(const char *name, struct vconn_class **classp)
+ {
+     size_t prefix_len;
+     prefix_len = strcspn(name, ":");
+     if (name[prefix_len] != '\0') {
+         size_t i;
+         for (i = 0; i < ARRAY_SIZE(vconn_classes); i++) {
+             struct vconn_class *class = vconn_classes[i];
+             if (strlen(class->name) == prefix_len
+                 && !memcmp(class->name, name, prefix_len)) {
+                 *classp = class;
+                 return 0;
+             }
+         }
+     }
+     *classp = NULL;
+     return EAFNOSUPPORT;
+ }
+ /* Returns 0 if 'name' is a connection name in the form "TYPE:ARGS" and TYPE is
+  * a supported connection type, otherwise EAFNOSUPPORT.  */
+ int
+ vconn_verify_name(const char *name)
+ {
+     struct vconn_class *class;
+     return vconn_lookup_class(name, &class);
+ }
  /* Attempts to connect to an OpenFlow device.  'name' is a connection name in
   * the form "TYPE:ARGS", where TYPE is an active vconn class's name and ARGS
   * are vconn class-specific.
  int
  vconn_open(const char *name, int min_version, struct vconn **vconnp)
  {
-     size_t prefix_len;
-     size_t i;
+     struct vconn_class *class;
+     struct vconn *vconn;
+     char *suffix_copy;
+     int error;
  
      COVERAGE_INC(vconn_open);
      check_vconn_classes();
  
-     *vconnp = NULL;
-     prefix_len = strcspn(name, ":");
-     if (prefix_len == strlen(name)) {
-         return EAFNOSUPPORT;
+     /* Look up the class. */
+     error = vconn_lookup_class(name, &class);
+     if (!class) {
+         goto error;
      }
-     for (i = 0; i < ARRAY_SIZE(vconn_classes); i++) {
-         struct vconn_class *class = vconn_classes[i];
-         if (strlen(class->name) == prefix_len
-             && !memcmp(class->name, name, prefix_len)) {
-             struct vconn *vconn;
-             char *suffix_copy = xstrdup(name + prefix_len + 1);
-             int retval = class->open(name, suffix_copy, &vconn);
-             free(suffix_copy);
-             if (!retval) {
-                 assert(vconn->state != VCS_CONNECTING
-                        || vconn->class->connect);
-                 vconn->min_version = min_version;
-                 *vconnp = vconn;
-             }
-             return retval;
-         }
+     /* Call class's "open" function. */
+     suffix_copy = xstrdup(strchr(name, ':') + 1);
+     error = class->open(name, suffix_copy, &vconn);
+     free(suffix_copy);
+     if (error) {
+         goto error;
      }
-     return EAFNOSUPPORT;
+     /* Success. */
+     assert(vconn->state != VCS_CONNECTING || vconn->class->connect);
+     vconn->min_version = min_version;
+     *vconnp = vconn;
+     return 0;
+ error:
+     *vconnp = NULL;
+     return error;
  }
  
 +/* Allows 'vconn' to perform maintenance activities, such as flushing output
 + * buffers. */
 +void
 +vconn_run(struct vconn *vconn)
 +{
 +    if (vconn->class->run) {
 +        (vconn->class->run)(vconn);
 +    }
 +}
 +
 +/* Arranges for the poll loop to wake up when 'vconn' needs to perform
 + * maintenance activities. */
 +void
 +vconn_run_wait(struct vconn *vconn)
 +{
 +    if (vconn->class->run_wait) {
 +        (vconn->class->run_wait)(vconn);
 +    }
 +}
 +
  int
  vconn_open_block(const char *name, int min_version, struct vconn **vconnp)
  {
  
      error = vconn_open(name, min_version, &vconn);
      while (error == EAGAIN) {
 +        vconn_run(vconn);
 +        vconn_run_wait(vconn);
          vconn_connect_wait(vconn);
          poll_block();
          error = vconn_connect(vconn);
@@@ -570,8 -585,6 +608,8 @@@ vconn_send_block(struct vconn *vconn, s
  {
      int retval;
      while ((retval = vconn_send(vconn, msg)) == EAGAIN) {
 +        vconn_run(vconn);
 +        vconn_run_wait(vconn);
          vconn_send_wait(vconn);
          poll_block();
      }
@@@ -584,8 -597,6 +622,8 @@@ vconn_recv_block(struct vconn *vconn, s
  {
      int retval;
      while ((retval = vconn_recv(vconn, msgp)) == EAGAIN) {
 +        vconn_run(vconn);
 +        vconn_run_wait(vconn);
          vconn_recv_wait(vconn);
          poll_block();
      }
@@@ -691,6 -702,42 +729,42 @@@ vconn_send_wait(struct vconn *vconn
      vconn_wait(vconn, WAIT_SEND);
  }
  
+ /* Given 'name', a connection name in the form "TYPE:ARGS", stores the class
+  * named "TYPE" into '*classp' and returns 0.  Returns EAFNOSUPPORT and stores
+  * a null pointer into '*classp' if 'name' is in the wrong form or if no such
+  * class exists. */
+ static int
+ pvconn_lookup_class(const char *name, struct pvconn_class **classp)
+ {
+     size_t prefix_len;
+     prefix_len = strcspn(name, ":");
+     if (name[prefix_len] != '\0') {
+         size_t i;
+         for (i = 0; i < ARRAY_SIZE(pvconn_classes); i++) {
+             struct pvconn_class *class = pvconn_classes[i];
+             if (strlen(class->name) == prefix_len
+                 && !memcmp(class->name, name, prefix_len)) {
+                 *classp = class;
+                 return 0;
+             }
+         }
+     }
+     *classp = NULL;
+     return EAFNOSUPPORT;
+ }
+ /* Returns 0 if 'name' is a connection name in the form "TYPE:ARGS" and TYPE is
+  * a supported connection type, otherwise EAFNOSUPPORT.  */
+ int
+ pvconn_verify_name(const char *name)
+ {
+     struct pvconn_class *class;
+     return pvconn_lookup_class(name, &class);
+ }
  /* Attempts to start listening for OpenFlow connections.  'name' is a
   * connection name in the form "TYPE:ARGS", where TYPE is an passive vconn
   * class's name and ARGS are vconn class-specific.
  int
  pvconn_open(const char *name, struct pvconn **pvconnp)
  {
-     size_t prefix_len;
-     size_t i;
+     struct pvconn_class *class;
+     struct pvconn *pvconn;
+     char *suffix_copy;
+     int error;
  
      check_vconn_classes();
  
-     *pvconnp = NULL;
-     prefix_len = strcspn(name, ":");
-     if (prefix_len == strlen(name)) {
-         return EAFNOSUPPORT;
+     /* Look up the class. */
+     error = pvconn_lookup_class(name, &class);
+     if (!class) {
+         goto error;
      }
-     for (i = 0; i < ARRAY_SIZE(pvconn_classes); i++) {
-         struct pvconn_class *class = pvconn_classes[i];
-         if (strlen(class->name) == prefix_len
-             && !memcmp(class->name, name, prefix_len)) {
-             char *suffix_copy = xstrdup(name + prefix_len + 1);
-             int retval = class->listen(name, suffix_copy, pvconnp);
-             free(suffix_copy);
-             if (retval) {
-                 *pvconnp = NULL;
-             }
-             return retval;
-         }
+     /* Call class's "open" function. */
+     suffix_copy = xstrdup(strchr(name, ':') + 1);
+     error = class->listen(name, suffix_copy, &pvconn);
+     free(suffix_copy);
+     if (error) {
+         goto error;
      }
-     return EAFNOSUPPORT;
+     /* Success. */
+     *pvconnp = pvconn;
+     return 0;
+ error:
+     *pvconnp = NULL;
+     return error;
  }
  
  /* Returns the name that was used to open 'pvconn'.  The caller must not
@@@ -886,19 -937,16 +964,19 @@@ make_flow_mod(uint16_t command, const f
      ofm->header.version = OFP_VERSION;
      ofm->header.type = OFPT_FLOW_MOD;
      ofm->header.length = htons(size);
 +    ofm->cookie = 0;
      ofm->match.wildcards = htonl(0);
      ofm->match.in_port = htons(flow->in_port == ODPP_LOCAL ? OFPP_LOCAL
                                 : flow->in_port);
      memcpy(ofm->match.dl_src, flow->dl_src, sizeof ofm->match.dl_src);
      memcpy(ofm->match.dl_dst, flow->dl_dst, sizeof ofm->match.dl_dst);
      ofm->match.dl_vlan = flow->dl_vlan;
 +    ofm->match.dl_vlan_pcp = flow->dl_vlan_pcp;
      ofm->match.dl_type = flow->dl_type;
      ofm->match.nw_src = flow->nw_src;
      ofm->match.nw_dst = flow->nw_dst;
      ofm->match.nw_proto = flow->nw_proto;
 +    ofm->match.nw_tos = flow->nw_tos;
      ofm->match.tp_src = flow->tp_src;
      ofm->match.tp_dst = flow->tp_dst;
      ofm->command = htons(command);
@@@ -1075,7 -1123,7 +1153,7 @@@ check_ofp_message(const struct ofp_head
                       "received %s message of length %zu (expected %zu)",
                       type_name, got_size, size);
          free(type_name);
 -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
 +        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
      }
  
      return 0;
@@@ -1111,7 -1159,7 +1189,7 @@@ check_ofp_message_array(const struct of
                       "(expected at least %zu)",
                       type_name, got_size, min_size);
          free(type_name);
 -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
 +        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
      }
      if ((got_size - min_size) % array_elt_size) {
          char *type_name = ofp_message_type_to_string(type);
                       type_name, got_size, min_size, got_size - min_size,
                       array_elt_size, (got_size - min_size) % array_elt_size);
          free(type_name);
 -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
 +        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
      }
      if (n_array_elts) {
          *n_array_elts = (got_size - min_size) / array_elt_size;
@@@ -1152,13 -1200,13 +1230,13 @@@ check_ofp_packet_out(const struct ofp_h
          VLOG_WARN_RL(&bad_ofmsg_rl, "packet-out claims %u bytes of actions "
                       "but message has room for only %zu bytes",
                       actions_len, extra);
 -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
 +        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
      }
      if (actions_len % sizeof(union ofp_action)) {
          VLOG_WARN_RL(&bad_ofmsg_rl, "packet-out claims %u bytes of actions, "
                       "which is not a multiple of %zu",
                       actions_len, sizeof(union ofp_action));
 -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
 +        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
      }
  
      n_actions = actions_len / sizeof(union ofp_action);
@@@ -1285,17 -1333,13 +1363,14 @@@ check_action(const union ofp_action *a
      switch (ntohs(a->type)) {
      case OFPAT_OUTPUT:
          error = check_action_port(ntohs(a->output.port), max_ports);
-         if (error) {
-             return error;
-         }
-         return check_action_exact_len(a, len, 8);
+         return error ? error : check_action_exact_len(a, len, 8);
  
      case OFPAT_SET_VLAN_VID:
      case OFPAT_SET_VLAN_PCP:
      case OFPAT_STRIP_VLAN:
      case OFPAT_SET_NW_SRC:
      case OFPAT_SET_NW_DST:
 +    case OFPAT_SET_NW_TOS:
      case OFPAT_SET_TP_SRC:
      case OFPAT_SET_TP_DST:
          return check_action_exact_len(a, len, 8);
          return check_action_exact_len(a, len, 16);
  
      case OFPAT_VENDOR:
-         if (a->vendor.vendor == htonl(NX_VENDOR_ID)) {
-             return check_nicira_action(a, len);
-         } else {
-             return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR);
-         }
-         break;
+         return (a->vendor.vendor == htonl(NX_VENDOR_ID)
+                 ? check_nicira_action(a, len)
+                 : ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR));
  
      default:
          VLOG_WARN_RL(&bad_ofmsg_rl, "unknown action type %"PRIu16,
                  ntohs(a->type));
          return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE);
      }
-     if (!len) {
-         VLOG_DBG_RL(&bad_ofmsg_rl, "action has invalid length 0");
-         return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
-     }
-     if (len % ACTION_ALIGNMENT) {
-         VLOG_DBG_RL(&bad_ofmsg_rl, "action length %u is not a multiple of %d",
-                     len, ACTION_ALIGNMENT);
-         return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
-     }
-     return 0;
  }
  
  int
@@@ -1347,7 -1377,15 +1408,15 @@@ validate_actions(const union ofp_actio
                          "action requires %u slots but only %u remain",
                          n_slots, slots_left);
              return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
+         } else if (!len) {
+             VLOG_DBG_RL(&bad_ofmsg_rl, "action has invalid length 0");
+             return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
+         } else if (len % ACTION_ALIGNMENT) {
+             VLOG_DBG_RL(&bad_ofmsg_rl, "action length %u is not a multiple "
+                         "of %d", len, ACTION_ALIGNMENT);
+             return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);
          }
          error = check_action(a, len, max_ports);
          if (error) {
              return error;
@@@ -1426,17 -1464,6 +1495,17 @@@ normalize_match(struct ofp_match *m
          if (wc & OFPFW_NW_DST_MASK) {
              m->nw_dst &= flow_nw_bits_to_mask(wc, OFPFW_NW_DST_SHIFT);
          }
 +    } else if (m->dl_type == htons(ETH_TYPE_ARP)) {
 +        if (wc & OFPFW_NW_PROTO) {
 +            m->nw_proto = 0;
 +        }
 +        if (wc & OFPFW_NW_SRC_MASK) {
 +            m->nw_src &= flow_nw_bits_to_mask(wc, OFPFW_NW_SRC_SHIFT);
 +        }
 +        if (wc & OFPFW_NW_DST_MASK) {
 +            m->nw_dst &= flow_nw_bits_to_mask(wc, OFPFW_NW_DST_SHIFT);
 +        }
 +        m->tp_src = m->tp_dst = 0;
      } else {
          /* Network and transport layer fields will always be extracted as
           * zeros, so we can do an exact-match on those values. */
@@@ -1486,7 -1513,6 +1555,7 @@@ vconn_init(struct vconn *vconn, struct 
      vconn->local_ip = 0;
      vconn->local_port = 0;
      vconn->name = xstrdup(name);
 +    assert(vconn->state != VCS_CONNECTING || class->connect);
  }
  
  void
diff --combined lib/vconn.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.
@@@ -35,6 -35,7 +35,7 @@@ struct vconn
  void vconn_usage(bool active, bool passive, bool bootstrap);
  
  /* Active vconns: virtual connections to OpenFlow devices. */
+ int vconn_verify_name(const char *name);
  int vconn_open(const char *name, int min_version, struct vconn **);
  void vconn_close(struct vconn *);
  const char *vconn_get_name(const struct vconn *);
@@@ -48,9 -49,6 +49,9 @@@ int vconn_send(struct vconn *, struct o
  int vconn_recv_xid(struct vconn *, uint32_t xid, struct ofpbuf **);
  int vconn_transact(struct vconn *, struct ofpbuf *, struct ofpbuf **);
  
 +void vconn_run(struct vconn *);
 +void vconn_run_wait(struct vconn *);
 +
  int vconn_open_block(const char *name, int min_version, struct vconn **);
  int vconn_send_block(struct vconn *, struct ofpbuf *);
  int vconn_recv_block(struct vconn *, struct ofpbuf **);
@@@ -66,6 -64,7 +67,7 @@@ void vconn_recv_wait(struct vconn *)
  void vconn_send_wait(struct vconn *);
  
  /* Passive vconns: virtual listeners for incoming OpenFlow connections. */
+ int pvconn_verify_name(const char *name);
  int pvconn_open(const char *name, struct pvconn **);
  const char *pvconn_get_name(const struct pvconn *);
  void pvconn_close(struct pvconn *);
diff --combined ofproto/netflow.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 NETFLOW_H
  #define NETFLOW_H 1
  
+ #include <stdint.h>
  #include "flow.h"
  #include "svec.h"
  
 +static const int NF_ACTIVE_TIMEOUT_DEFAULT = 600;
 +
  struct ofexpired;
  
  struct netflow_options {
diff --combined ofproto/ofproto.c
@@@ -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"
@@@ -38,6 -39,7 +38,6 @@@
  #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
@@@ -83,11 -85,8 +83,11 @@@ static int xlate_actions(const union of
  struct rule {
      struct cls_rule cr;
  
 +    uint64_t flow_cookie;       /* Controller-issued identifier. 
 +                                   (Kept in network-byte order.) */
      uint16_t idle_timeout;      /* In seconds from time of last use. */
      uint16_t hard_timeout;      /* In seconds from time of creation. */
 +    bool send_flow_removed;     /* Send a flow removed message? */
      long long int used;         /* Last-used time (0 if never used). */
      long long int created;      /* Creation time. */
      uint64_t packet_count;      /* Number of packets received. */
@@@ -145,8 -144,7 +145,8 @@@ rule_is_hidden(const struct rule *rule
  
  static struct rule *rule_create(struct ofproto *, struct rule *super,
                                  const union ofp_action *, size_t n_actions,
 -                                uint16_t idle_timeout, uint16_t hard_timeout);
 +                                uint16_t idle_timeout, uint16_t hard_timeout,
 +                                uint64_t flow_cookie, bool send_flow_removed);
  static void rule_free(struct rule *);
  static void rule_destroy(struct ofproto *, struct rule *);
  static struct rule *rule_from_cls_rule(const struct cls_rule *);
@@@ -159,13 -157,12 +159,13 @@@ static void rule_install(struct ofprot
                           struct rule *displaced_rule);
  static void rule_uninstall(struct ofproto *, struct rule *);
  static void rule_post_uninstall(struct ofproto *, struct rule *);
 +static void send_flow_removed(struct ofproto *p, struct rule *rule,
 +                              long long int now, uint8_t reason);
  
  struct ofconn {
      struct list node;
      struct rconn *rconn;
      struct pktbuf *pktbuf;
 -    bool send_flow_exp;
      int miss_send_len;
  
      struct rconn_packet_counter *packet_in_counter;
  };
  
  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,
@@@ -187,11 -184,11 +187,11 @@@ 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. */
 -    char *serial;               /* Serial number. */
 +    char *mfr_desc;             /* Manufacturer. */
 +    char *hw_desc;              /* Hardware. */
 +    char *sw_desc;              /* Software version. */
 +    char *serial_desc;          /* Serial number. */
 +    char *dp_desc;              /* Datapath description. */
  
      /* Datapath. */
      struct dpif *dpif;
      struct discovery *discovery;
      struct fail_open *fail_open;
      struct pinsched *miss_sched, *action_sched;
 -    struct executer *executer;
      struct netflow *netflow;
      struct ofproto_sflow *sflow;
  
@@@ -261,8 -259,7 +261,8 @@@ 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_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->hardware = xstrdup("Reference Implementation");
 -    p->software = xstrdup(VERSION BUILDNR);
 -    p->serial = xstrdup("None");
 +    p->mfr_desc = xstrdup(DEFAULT_MFR_DESC);
 +    p->hw_desc = xstrdup(DEFAULT_HW_DESC);
 +    p->sw_desc = xstrdup(DEFAULT_SW_DESC);
 +    p->serial_desc = xstrdup(DEFAULT_SERIAL_DESC);
 +    p->dp_desc = xstrdup(DEFAULT_DP_DESC);
  
      /* Initialize datapath. */
      p->dpif = dpif;
      p->discovery = NULL;
      p->fail_open = NULL;
      p->miss_sched = p->action_sched = NULL;
 -    p->executer = NULL;
      p->netflow = NULL;
      p->sflow = NULL;
  
      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);
 +    VLOG_INFO("using datapath ID %016"PRIx64, p->datapath_id);
  
      *ofprotop = p;
      return 0;
@@@ -366,11 -370,17 +366,11 @@@ ofproto_set_datapath_id(struct ofproto 
      uint64_t old_dpid = p->datapath_id;
      p->datapath_id = datapath_id ? datapath_id : pick_datapath_id(p);
      if (p->datapath_id != old_dpid) {
 -        VLOG_INFO("datapath ID changed to %012"PRIx64, p->datapath_id);
 +        VLOG_INFO("datapath ID changed to %016"PRIx64, p->datapath_id);
          rconn_reconnect(p->controller->rconn);
      }
  }
  
 -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)
  {
@@@ -390,52 -400,24 +390,52 @@@ ofproto_set_max_backoff(struct ofproto 
  
  void
  ofproto_set_desc(struct ofproto *p,
 -                 const char *manufacturer, const char *hardware,
 -                 const char *software, const char *serial)
 +                 const char *mfr_desc, const char *hw_desc,
 +                 const char *sw_desc, const char *serial_desc,
 +                 const char *dp_desc)
  {
 -    if (manufacturer) {
 -        free(p->manufacturer);
 -        p->manufacturer = xstrdup(manufacturer);
 +    struct ofp_desc_stats *ods;
 +
 +    if (mfr_desc) {
 +        if (strlen(mfr_desc) >= sizeof ods->mfr_desc) {
 +            VLOG_WARN("truncating mfr_desc, must be less than %zu characters",
 +                    sizeof ods->mfr_desc);
 +        }
 +        free(p->mfr_desc);
 +        p->mfr_desc = xstrdup(mfr_desc);
      }
 -    if (hardware) {
 -        free(p->hardware);
 -        p->hardware = xstrdup(hardware);
 +    if (hw_desc) {
 +        if (strlen(hw_desc) >= sizeof ods->hw_desc) {
 +            VLOG_WARN("truncating hw_desc, must be less than %zu characters",
 +                    sizeof ods->hw_desc);
 +        }
 +        free(p->hw_desc);
 +        p->hw_desc = xstrdup(hw_desc);
      }
 -    if (software) {
 -        free(p->software);
 -        p->software = xstrdup(software);
 +    if (sw_desc) {
 +        if (strlen(sw_desc) >= sizeof ods->sw_desc) {
 +            VLOG_WARN("truncating sw_desc, must be less than %zu characters",
 +                    sizeof ods->sw_desc);
 +        }
 +        free(p->sw_desc);
 +        p->sw_desc = xstrdup(sw_desc);
 +    }
 +    if (serial_desc) {
 +        if (strlen(serial_desc) >= sizeof ods->serial_num) {
 +            VLOG_WARN("truncating serial_desc, must be less than %zu "
 +                    "characters",
 +                    sizeof ods->serial_num);
 +        }
 +        free(p->serial_desc);
 +        p->serial_desc = xstrdup(serial_desc);
      }
 -    if (serial) {
 -        free(p->serial);
 -        p->serial = xstrdup(serial);
 +    if (dp_desc) {
 +        if (strlen(dp_desc) >= sizeof ods->dp_desc) {
 +            VLOG_WARN("truncating dp_desc, must be less than %zu characters",
 +                    sizeof ods->dp_desc);
 +        }
 +        free(p->dp_desc);
 +        p->dp_desc = xstrdup(dp_desc);
      }
  }
  
@@@ -555,7 -537,7 +555,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();
          }
@@@ -646,12 -628,36 +646,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)
  {
@@@ -714,15 -720,12 +714,15 @@@ ofproto_destroy(struct ofproto *p
          return;
      }
  
 +    /* Destroy fail-open early, because it touches the classifier. */
 +    ofproto_set_failure(p, false);
 +
      ofproto_flush_flows(p);
      classifier_destroy(&p->cls);
  
      LIST_FOR_EACH_SAFE (ofconn, next_ofconn, struct ofconn, node,
                          &p->all_conns) {
 -        ofconn_destroy(ofconn, p);
 +        ofconn_destroy(ofconn);
      }
  
      dpif_close(p->dpif);
      switch_status_destroy(p->switch_status);
      in_band_destroy(p->in_band);
      discovery_destroy(p->discovery);
 -    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);
  
  
      mac_learning_destroy(p->ml);
  
 +    free(p->mfr_desc);
 +    free(p->hw_desc);
 +    free(p->sw_desc);
 +    free(p->serial_desc);
 +    free(p->dp_desc);
 +
+     port_array_destroy(&p->ports);
      free(p);
  }
  
@@@ -792,10 -793,6 +794,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) {
@@@ -954,6 -954,9 +956,6 @@@ 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);
      }
@@@ -1022,8 -1025,7 +1024,8 @@@ ofproto_add_flow(struct ofproto *p
  {
      struct rule *rule;
      rule = rule_create(p, NULL, actions, n_actions,
 -                       idle_timeout >= 0 ? idle_timeout : 5 /* XXX */, 0);
 +                       idle_timeout >= 0 ? idle_timeout : 5 /* XXX */, 
 +                       0, 0, false);
      cls_rule_from_flow(&rule->cr, flow, wildcards, priority);
      rule_insert(p, rule, NULL, 0);
  }
@@@ -1134,19 -1136,13 +1136,19 @@@ refresh_port_groups(struct ofproto *p
  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)",
@@@ -1373,6 -1369,7 +1375,6 @@@ ofconn_create(struct ofproto *p, struc
      list_push_back(&p->all_conns, &ofconn->node);
      ofconn->rconn = rconn;
      ofconn->pktbuf = NULL;
 -    ofconn->send_flow_exp = false;
      ofconn->miss_send_len = 0;
      ofconn->packet_in_counter = rconn_packet_counter_create ();
      ofconn->reply_counter = rconn_packet_counter_create ();
  }
  
  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);
@@@ -1414,7 -1415,7 +1416,7 @@@ ofconn_run(struct ofconn *ofconn, struc
      }
  
      if (ofconn != p->controller && !rconn_is_alive(ofconn->rconn)) {
 -        ofconn_destroy(ofconn, p);
 +        ofconn_destroy(ofconn);
      }
  }
  
@@@ -1434,15 -1435,12 +1436,15 @@@ ofconn_wait(struct ofconn *ofconn
  static struct rule *
  rule_create(struct ofproto *ofproto, struct rule *super,
              const union ofp_action *actions, size_t n_actions,
 -            uint16_t idle_timeout, uint16_t hard_timeout)
 +            uint16_t idle_timeout, uint16_t hard_timeout,
 +            uint64_t flow_cookie, bool send_flow_removed)
  {
 -    struct rule *rule = xcalloc(1, sizeof *rule);
 +    struct rule *rule = xzalloc(sizeof *rule);
      rule->idle_timeout = idle_timeout;
      rule->hard_timeout = hard_timeout;
 +    rule->flow_cookie = flow_cookie;
      rule->used = rule->created = time_msec();
 +    rule->send_flow_removed = send_flow_removed;
      rule->super = super;
      if (super) {
          list_push_back(&super->list, &rule->list);
@@@ -1602,8 -1600,7 +1604,8 @@@ rule_create_subrule(struct ofproto *ofp
                      const flow_t *flow)
  {
      struct rule *subrule = rule_create(ofproto, rule, NULL, 0,
 -                                       rule->idle_timeout, rule->hard_timeout);
 +                                       rule->idle_timeout, rule->hard_timeout,
 +                                       0, false);
      COVERAGE_INC(ofproto_subrule_create);
      cls_rule_from_flow(&subrule->cr, flow, 0,
                         (rule->cr.priority <= UINT16_MAX ? UINT16_MAX
@@@ -1889,7 -1886,7 +1891,7 @@@ handle_features_request(struct ofproto 
      osf->n_buffers = htonl(pktbuf_capacity());
      osf->n_tables = 2;
      osf->capabilities = htonl(OFPC_FLOW_STATS | OFPC_TABLE_STATS |
 -                              OFPC_PORT_STATS | OFPC_MULTI_PHY_TX);
 +                              OFPC_PORT_STATS | OFPC_ARP_MATCH_IP);
      osf->actions = htonl((1u << OFPAT_OUTPUT) |
                           (1u << OFPAT_SET_VLAN_VID) |
                           (1u << OFPAT_SET_VLAN_PCP) |
                           (1u << OFPAT_SET_DL_DST) |
                           (1u << OFPAT_SET_NW_SRC) |
                           (1u << OFPAT_SET_NW_DST) |
 +                         (1u << OFPAT_SET_NW_TOS) |
                           (1u << OFPAT_SET_TP_SRC) |
                           (1u << OFPAT_SET_TP_DST));
  
@@@ -1922,6 -1918,9 +1924,6 @@@ handle_get_config_request(struct ofprot
      /* Figure out flags. */
      dpif_get_drop_frags(p->dpif, &drop_frags);
      flags = drop_frags ? OFPC_FRAG_DROP : OFPC_FRAG_NORMAL;
 -    if (ofconn->send_flow_exp) {
 -        flags |= OFPC_SEND_FLOW_EXP;
 -    }
  
      /* Send reply. */
      osc = make_openflow_xid(sizeof *osc, OFPT_GET_CONFIG_REPLY, oh->xid, &buf);
@@@ -1945,6 -1944,8 +1947,6 @@@ handle_set_config(struct ofproto *p, st
      }
      flags = ntohs(osc->flags);
  
 -    ofconn->send_flow_exp = (flags & OFPC_SEND_FLOW_EXP) != 0;
 -
      if (ofconn == p->controller) {
          switch (flags & OFPC_FRAG_MASK) {
          case OFPC_FRAG_NORMAL:
@@@ -2213,11 -2214,6 +2215,11 @@@ do_xlate_actions(const union ofp_actio
              oa->nw_addr.nw_addr = ia->nw_addr.nw_addr;
              break;
  
 +        case OFPAT_SET_NW_TOS:
 +            oa = odp_actions_add(ctx->out, ODPAT_SET_NW_TOS);
 +            oa->nw_tos.nw_tos = ia->nw_tos.nw_tos;
 +            break;
 +
          case OFPAT_SET_TP_SRC:
              oa = odp_actions_add(ctx->out, ODPAT_SET_TP_SRC);
              oa->tp_port.tp_port = ia->tp_port.tp_port;
@@@ -2421,12 -2417,10 +2423,12 @@@ handle_desc_stats_request(struct ofprot
  
      msg = start_stats_reply(request, sizeof *ods);
      ods = append_stats_reply(sizeof *ods, ofconn, &msg);
 -    strncpy(ods->mfr_desc, p->manufacturer, sizeof ods->mfr_desc);
 -    strncpy(ods->hw_desc, p->hardware, sizeof ods->hw_desc);
 -    strncpy(ods->sw_desc, p->software, sizeof ods->sw_desc);
 -    strncpy(ods->serial_num, p->serial, sizeof ods->serial_num);
 +    memset(ods, 0, sizeof *ods);
 +    ovs_strlcpy(ods->mfr_desc, p->mfr_desc, sizeof ods->mfr_desc);
 +    ovs_strlcpy(ods->hw_desc, p->hw_desc, sizeof ods->hw_desc);
 +    ovs_strlcpy(ods->sw_desc, p->sw_desc, sizeof ods->sw_desc);
 +    ovs_strlcpy(ods->serial_num, p->serial_desc, sizeof ods->serial_num);
 +    ovs_strlcpy(ods->dp_desc, p->dp_desc, sizeof ods->dp_desc);
      queue_tx(msg, ofconn, ofconn->reply_counter);
  
      return 0;
@@@ -2488,62 -2482,39 +2490,62 @@@ handle_table_stats_request(struct ofpro
      return 0;
  }
  
 +static void
 +append_port_stat(struct ofport *port, uint16_t port_no, struct ofconn *ofconn, 
 +                 struct ofpbuf *msg)
 +{
 +    struct netdev_stats stats;
 +    struct ofp_port_stats *ops;
 +
 +    /* Intentionally ignore return value, since errors will set 
 +     * 'stats' to all-1s, which is correct for OpenFlow, and 
 +     * netdev_get_stats() will log errors. */
 +    netdev_get_stats(port->netdev, &stats);
 +
 +    ops = append_stats_reply(sizeof *ops, ofconn, &msg);
 +    ops->port_no = htons(odp_port_to_ofp_port(port_no));
 +    memset(ops->pad, 0, sizeof ops->pad);
 +    ops->rx_packets = htonll(stats.rx_packets);
 +    ops->tx_packets = htonll(stats.tx_packets);
 +    ops->rx_bytes = htonll(stats.rx_bytes);
 +    ops->tx_bytes = htonll(stats.tx_bytes);
 +    ops->rx_dropped = htonll(stats.rx_dropped);
 +    ops->tx_dropped = htonll(stats.tx_dropped);
 +    ops->rx_errors = htonll(stats.rx_errors);
 +    ops->tx_errors = htonll(stats.tx_errors);
 +    ops->rx_frame_err = htonll(stats.rx_frame_errors);
 +    ops->rx_over_err = htonll(stats.rx_over_errors);
 +    ops->rx_crc_err = htonll(stats.rx_crc_errors);
 +    ops->collisions = htonll(stats.collisions);
 +}
 +
  static int
  handle_port_stats_request(struct ofproto *p, struct ofconn *ofconn,
 -                          struct ofp_stats_request *request)
 +                          struct ofp_stats_request *osr,
 +                          size_t arg_size)
  {
 +    struct ofp_port_stats_request *psr;
      struct ofp_port_stats *ops;
      struct ofpbuf *msg;
      struct ofport *port;
      unsigned int port_no;
  
 -    msg = start_stats_reply(request, sizeof *ops * 16);
 -    PORT_ARRAY_FOR_EACH (port, &p->ports, port_no) {
 -        struct netdev_stats stats;
 -
 -        /* Intentionally ignore return value, since errors will set 'stats' to
 -         * all-1s, which is correct for OpenFlow, and netdev_get_stats() will
 -         * log errors. */
 -        netdev_get_stats(port->netdev, &stats);
 -
 -        ops = append_stats_reply(sizeof *ops, ofconn, &msg);
 -        ops->port_no = htons(odp_port_to_ofp_port(port_no));
 -        memset(ops->pad, 0, sizeof ops->pad);
 -        ops->rx_packets = htonll(stats.rx_packets);
 -        ops->tx_packets = htonll(stats.tx_packets);
 -        ops->rx_bytes = htonll(stats.rx_bytes);
 -        ops->tx_bytes = htonll(stats.tx_bytes);
 -        ops->rx_dropped = htonll(stats.rx_dropped);
 -        ops->tx_dropped = htonll(stats.tx_dropped);
 -        ops->rx_errors = htonll(stats.rx_errors);
 -        ops->tx_errors = htonll(stats.tx_errors);
 -        ops->rx_frame_err = htonll(stats.rx_frame_errors);
 -        ops->rx_over_err = htonll(stats.rx_over_errors);
 -        ops->rx_crc_err = htonll(stats.rx_crc_errors);
 -        ops->collisions = htonll(stats.collisions);
 +    if (arg_size != sizeof *psr) {
 +        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
 +    }
 +    psr = (struct ofp_port_stats_request *) osr->body;
 +
 +    msg = start_stats_reply(osr, sizeof *ops * 16);
 +    if (psr->port_no != htons(OFPP_NONE)) {
 +        port = port_array_get(&p->ports, 
 +                ofp_port_to_odp_port(ntohs(psr->port_no)));
 +        if (port) {
 +            append_port_stat(port, ntohs(psr->port_no), ofconn, msg);
 +        }
 +    } else {
 +        PORT_ARRAY_FOR_EACH (port, &p->ports, port_no) {
 +            append_port_stat(port, port_no, ofconn, msg);
 +        }
      }
  
      queue_tx(msg, ofconn, ofconn->reply_counter);
@@@ -2570,7 -2541,7 +2572,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) {
@@@ -2606,9 -2577,6 +2608,9 @@@ flow_stats_cb(struct cls_rule *rule_, v
      struct ofp_flow_stats *ofs;
      uint64_t packet_count, byte_count;
      size_t act_len, len;
 +    long long int tdiff = time_msec() - rule->created;
 +    uint32_t sec = tdiff / 1000;
 +    uint32_t msec = tdiff - (sec * 1000);
  
      if (rule_is_hidden(rule) || !rule_has_out_port(rule, cbdata->out_port)) {
          return;
      ofs->table_id = rule->cr.wc.wildcards ? TABLEID_CLASSIFIER : TABLEID_HASH;
      ofs->pad = 0;
      flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofs->match);
 -    ofs->duration = htonl((time_msec() - rule->created) / 1000);
 +    ofs->duration_sec = htonl(sec);
 +    ofs->duration_nsec = htonl(msec * 1000000);
 +    ofs->cookie = rule->flow_cookie;
      ofs->priority = htons(rule->cr.priority);
      ofs->idle_timeout = htons(rule->idle_timeout);
      ofs->hard_timeout = htons(rule->hard_timeout);
@@@ -2655,7 -2621,7 +2657,7 @@@ handle_flow_stats_request(struct ofprot
      struct cls_rule target;
  
      if (arg_size != sizeof *fsr) {
 -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
 +        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
      }
      fsr = (struct ofp_flow_stats_request *) osr->body;
  
@@@ -2693,7 -2659,7 +2695,7 @@@ flow_stats_ds_cb(struct cls_rule *rule_
      }
  
      query_stats(cbdata->ofproto, rule, &packet_count, &byte_count);
 -    flow_to_ovs_match(&rule->cr.flow, rule->cr.wc.wildcards, &match);
 +    flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &match);
  
      ds_put_format(results, "duration=%llds, ",
                    (time_msec() - rule->created) / 1000);
@@@ -2763,7 -2729,7 +2765,7 @@@ handle_aggregate_stats_request(struct o
      struct ofpbuf *msg;
  
      if (arg_size != sizeof *asr) {
 -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
 +        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
      }
      asr = (struct ofp_aggregate_stats_request *) osr->body;
  
@@@ -2816,7 -2782,7 +2818,7 @@@ handle_stats_request(struct ofproto *p
          return handle_table_stats_request(p, ofconn, osr);
  
      case OFPST_PORT:
 -        return handle_port_stats_request(p, ofconn, osr);
 +        return handle_port_stats_request(p, ofconn, osr, arg_size);
  
      case OFPST_VENDOR:
          return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);
@@@ -2868,30 -2834,16 +2870,30 @@@ add_flow(struct ofproto *p, struct ofco
      uint16_t in_port;
      int error;
  
 +    if (ofm->flags & htons(OFPFF_CHECK_OVERLAP)) {
 +        flow_t flow;
 +        uint32_t wildcards;
 +
 +        flow_from_match(&flow, &wildcards, &ofm->match);
 +        if (classifier_rule_overlaps(&p->cls, &flow, wildcards,
 +                                     ntohs(ofm->priority))) {
 +            return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_OVERLAP);
 +        }
 +    }
 +
      rule = rule_create(p, NULL, (const union ofp_action *) ofm->actions,
                         n_actions, ntohs(ofm->idle_timeout),
 -                       ntohs(ofm->hard_timeout));
 +                       ntohs(ofm->hard_timeout),  ofm->cookie,
 +                       ofm->flags & htons(OFPFF_SEND_FLOW_REM));
      cls_rule_from_match(&rule->cr, &ofm->match, ntohs(ofm->priority));
  
 -    packet = NULL;
      error = 0;
      if (ofm->buffer_id != htonl(UINT32_MAX)) {
          error = pktbuf_retrieve(ofconn->pktbuf, ntohl(ofm->buffer_id),
                                  &packet, &in_port);
 +    } else {
 +        packet = NULL;
 +        in_port = UINT16_MAX;
      }
  
      rule_insert(p, rule, packet, in_port);
@@@ -2908,8 -2860,6 +2910,8 @@@ modify_flow(struct ofproto *p, const st
      }
  
      if (command == OFPFC_DELETE) {
 +        long long int now = time_msec();
 +        send_flow_removed(p, rule, now, OFPRR_DELETE);
          rule_remove(p, rule);
      } else {
          size_t actions_len = n_actions * sizeof *rule->actions;
          free(rule->actions);
          rule->actions = xmemdup(ofm->actions, actions_len);
          rule->n_actions = n_actions;
 +        rule->flow_cookie = ofm->cookie;
  
          if (rule->cr.wc.wildcards) {
              COVERAGE_INC(ofproto_mod_wc_flow);
@@@ -3018,14 -2967,6 +3020,14 @@@ handle_flow_mod(struct ofproto *p, stru
          return error;
      }
  
 +    /* We do not support the emergency flow cache.  It will hopefully
 +     * get dropped from OpenFlow in the near future. */
 +    if (ofm->flags & htons(OFPFF_EMERG)) {
 +        /* There isn't a good fit for an error code, so just state that the
 +         * flow table is full. */
 +        return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_ALL_TABLES_FULL);
 +    }
 +
      normalize_match(&ofm->match);
      if (!ofm->match.wildcards) {
          ofm->priority = htons(UINT16_MAX);
      }
  }
  
 -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)
  {
      struct nicira_header *nh;
  
      if (ntohs(ovh->header.length) < sizeof(struct ofp_vendor_header)) {
 -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
 +        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
      }
      if (ovh->vendor != htonl(NX_VENDOR_ID)) {
          return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);
      }
      if (ntohs(ovh->header.length) < sizeof(struct nicira_header)) {
 -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
 +        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
      }
  
      nh = 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);
  }
  
 +static int
 +handle_barrier_request(struct ofconn *ofconn, struct ofp_header *oh)
 +{
 +    struct ofp_header *ob;
 +    struct ofpbuf *buf;
 +
 +    /* Currently, everything executes synchronously, so we can just
 +     * immediately send the barrier reply. */
 +    ob = make_openflow_xid(sizeof *ob, OFPT_BARRIER_REPLY, oh->xid, &buf);
 +    queue_tx(buf, ofconn, ofconn->reply_counter);
 +    return 0;
 +}
 +
  static void
  handle_openflow(struct ofconn *ofconn, struct ofproto *p,
                  struct ofpbuf *ofp_msg)
          error = handle_vendor(p, ofconn, ofp_msg->data);
          break;
  
 +    case OFPT_BARRIER_REQUEST:
 +        error = handle_barrier_request(ofconn, oh);
 +        break;
 +
      default:
          if (VLOG_IS_WARN_ENABLED()) {
              char *s = ofp_to_string(oh, ntohs(oh->length), 2);
@@@ -3316,43 -3307,25 +3318,43 @@@ revalidate_rule(struct ofproto *p, stru
  }
  
  static struct ofpbuf *
 -compose_flow_exp(const struct rule *rule, long long int now, uint8_t reason)
 +compose_flow_removed(const struct rule *rule, long long int now, uint8_t reason)
  {
 -    struct ofp_flow_expired *ofe;
 +    struct ofp_flow_removed *ofr;
      struct ofpbuf *buf;
 -
 -    ofe = make_openflow(sizeof *ofe, OFPT_FLOW_EXPIRED, &buf);
 -    flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofe->match);
 -    ofe->priority = htons(rule->cr.priority);
 -    ofe->reason = reason;
 -    ofe->duration = htonl((now - rule->created) / 1000);
 -    ofe->packet_count = htonll(rule->packet_count);
 -    ofe->byte_count = htonll(rule->byte_count);
 +    long long int tdiff = time_msec() - rule->created;
 +    uint32_t sec = tdiff / 1000;
 +    uint32_t msec = tdiff - (sec * 1000);
 +
 +    ofr = make_openflow(sizeof *ofr, OFPT_FLOW_REMOVED, &buf);
 +    flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofr->match);
 +    ofr->cookie = rule->flow_cookie;
 +    ofr->priority = htons(rule->cr.priority);
 +    ofr->reason = reason;
 +    ofr->duration_sec = htonl(sec);
 +    ofr->duration_nsec = htonl(msec * 1000000);
 +    ofr->idle_timeout = htons(rule->idle_timeout);
 +    ofr->packet_count = htonll(rule->packet_count);
 +    ofr->byte_count = htonll(rule->byte_count);
  
      return buf;
  }
  
  static void
 -send_flow_exp(struct ofproto *p, struct rule *rule,
 -              long long int now, uint8_t reason)
 +uninstall_idle_flow(struct ofproto *ofproto, struct rule *rule)
 +{
 +    assert(rule->installed);
 +    assert(!rule->cr.wc.wildcards);
 +
 +    if (rule->super) {
 +        rule_remove(ofproto, rule);
 +    } else {
 +        rule_uninstall(ofproto, rule);
 +    }
 +}
 +static void
 +send_flow_removed(struct ofproto *p, struct rule *rule,
 +                  long long int now, uint8_t reason)
  {
      struct ofconn *ofconn;
      struct ofconn *prev;
  
      prev = NULL;
      LIST_FOR_EACH (ofconn, struct ofconn, node, &p->all_conns) {
 -        if (ofconn->send_flow_exp && rconn_is_connected(ofconn->rconn)) {
 +        if (rule->send_flow_removed && rconn_is_connected(ofconn->rconn)) {
              if (prev) {
                  queue_tx(ofpbuf_clone(buf), prev, prev->reply_counter);
              } else {
 -                buf = compose_flow_exp(rule, now, reason);
 +                buf = compose_flow_removed(rule, now, reason);
              }
              prev = ofconn;
          }
      }
  }
  
 -static void
 -uninstall_idle_flow(struct ofproto *ofproto, struct rule *rule)
 -{
 -    assert(rule->installed);
 -    assert(!rule->cr.wc.wildcards);
 -
 -    if (rule->super) {
 -        rule_remove(ofproto, rule);
 -    } else {
 -        rule_uninstall(ofproto, rule);
 -    }
 -}
  
  static void
  expire_rule(struct cls_rule *cls_rule, void *p_)
      }
  
      if (!rule_is_hidden(rule)) {
 -        send_flow_exp(p, rule, now,
 -                      (now >= hard_expire
 -                       ? OFPER_HARD_TIMEOUT : OFPER_IDLE_TIMEOUT));
 +        send_flow_removed(p, rule, now,
 +                          (now >= hard_expire
 +                           ? OFPRR_HARD_TIMEOUT : OFPRR_IDLE_TIMEOUT));
      }
      rule_remove(p, rule);
  }
@@@ -3584,7 -3569,10 +3586,7 @@@ static uint64_
  pick_fallback_dpid(void)
  {
      uint8_t ea[ETH_ADDR_LEN];
 -    eth_addr_random(ea);
 -    ea[0] = 0x00;               /* Set Nicira OUI. */
 -    ea[1] = 0x23;
 -    ea[2] = 0x20;
 +    eth_addr_nicira_random(ea);
      return eth_addr_to_uint64(ea);
  }
  \f
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.
  #include "netflow.h"
  #include "tag.h"
  
+ #ifdef  __cplusplus
+ extern "C" {
+ #endif
  struct odp_actions;
  struct ofhooks;
  struct ofproto;
@@@ -51,14 -55,7 +55,14 @@@ struct ofproto_sflow_options 
      char *control_ip;
  };
  
 -int ofproto_create(const char *datapath, const struct ofhooks *, void *aux,
 +#define DEFAULT_MFR_DESC "Nicira Networks, Inc."
 +#define DEFAULT_HW_DESC "Open vSwitch"
 +#define DEFAULT_SW_DESC VERSION BUILDNR
 +#define DEFAULT_SERIAL_DESC "None"
 +#define DEFAULT_DP_DESC "None"
 +
 +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 *);
@@@ -69,12 -66,12 +73,12 @@@ 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 *,
 -                      const char *manufacturer, const char *hardware,
 -                      const char *software, const char *serial);
 +                      const char *mfr_desc, const char *hw_desc,
 +                      const char *sw_desc, const char *serial_desc,
 +                      const char *dp_desc);
  int ofproto_set_in_band(struct ofproto *, bool in_band);
  int ofproto_set_discovery(struct ofproto *, bool discovery,
                            const char *accept_controller_re,
@@@ -88,9 -85,12 +92,9 @@@ void ofproto_set_sflow(struct ofproto *
  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 *);
@@@ -127,4 -127,8 +131,8 @@@ struct ofhooks 
  void ofproto_revalidate(struct ofproto *, tag_type);
  struct tag_set *ofproto_get_revalidate_set(struct ofproto *);
  
+ #ifdef  __cplusplus
+ }
+ #endif
  #endif /* ofproto.h */
diff --combined ofproto/pinsched.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 <config.h>
  #include "pinsched.h"
+ #include <sys/types.h>
+ #include <netinet/in.h>
  #include <arpa/inet.h>
+ #include <stdint.h>
  #include <stdlib.h>
  #include "ofpbuf.h"
  #include "openflow/openflow.h"
@@@ -227,7 -230,7 +230,7 @@@ pinsched_create(int rate_limit, int bur
  {
      struct pinsched *ps;
  
 -    ps = xcalloc(1, sizeof *ps);
 +    ps = xzalloc(sizeof *ps);
      port_array_init(&ps->queues);
      ps->n_queued = 0;
      ps->last_tx_port = PORT_ARRAY_SIZE;
diff --combined ofproto/pktbuf.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.
@@@ -63,7 -63,7 +63,7 @@@ pktbuf_capacity(void
  struct pktbuf *
  pktbuf_create(void)
  {
 -    return xcalloc(1, sizeof *pktbuf_create());
 +    return xzalloc(sizeof *pktbuf_create());
  }
  
  void
@@@ -151,9 -151,9 +151,9 @@@ pktbuf_get_null(void
   * datapath port number on which the packet was received in '*in_port'.  The
   * caller becomes responsible for freeing the buffer.  However, if 'id'
   * identifies a "null" packet buffer (created with pktbuf_get_null()), stores
-  * NULL in '*bufferp' and -1 in '*in_port'.
+  * NULL in '*bufferp' and UINT16_max in '*in_port'.
   *
-  * On failure, stores NULL in in '*bufferp' and -1 in '*in_port'. */
+  * On failure, stores NULL in in '*bufferp' and UINT16_MAX in '*in_port'. */
  int
  pktbuf_retrieve(struct pktbuf *pb, uint32_t id, struct ofpbuf **bufferp,
                  uint16_t *in_port)
      if (!pb) {
          VLOG_WARN_RL(&rl, "attempt to send buffered packet via connection "
                       "without buffers");
 -        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_COOKIE);
 +        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BUFFER_UNKNOWN);
      }
  
      p = &pb->packets[id & PKTBUF_MASK];
              error = ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BUFFER_EMPTY);
          }
      } else if (id >> PKTBUF_BITS != COOKIE_MAX) {
 -        COVERAGE_INC(pktbuf_bad_cookie);
 +        COVERAGE_INC(pktbuf_buffer_unknown);
          VLOG_WARN_RL(&rl, "cookie mismatch: %08"PRIx32" != %08"PRIx32,
                       id, (id & PKTBUF_MASK) | (p->cookie << PKTBUF_BITS));
 -        error = ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_COOKIE);
 +        error = ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BUFFER_UNKNOWN);
      } else {
          COVERAGE_INC(pktbuf_null_cookie);
          VLOG_INFO_RL(&rl, "Received null cookie %08"PRIx32" (this is normal "
          error = 0;
      }
      *bufferp = NULL;
-     *in_port = -1;
+     *in_port = UINT16_MAX;
      return error;
  }