Merge "master" into "wdp".
authorBen Pfaff <blp@nicira.com>
Thu, 20 May 2010 20:37:37 +0000 (13:37 -0700)
committerBen Pfaff <blp@nicira.com>
Thu, 20 May 2010 20:37:37 +0000 (13:37 -0700)
87 files changed:
SubmittingPatches
datapath/Modules.mk
datapath/actions.c
datapath/actions.h
datapath/datapath.c
datapath/datapath.h
datapath/dp_notify.c
datapath/dp_sysfs_dp.c
datapath/dp_sysfs_if.c
datapath/flow.c
datapath/flow.h
datapath/linux-2.6/Modules.mk
datapath/linux-2.6/compat-2.6/include/linux/if_vlan.h [new file with mode: 0644]
datapath/odp-compat.h [deleted file]
datapath/vport-netdev.c
datapath/vport-netdev.h
datapath/vport.c
datapath/vport.h
datapath/xflow-compat.h [new file with mode: 0644]
include/openvswitch/automake.mk
include/openvswitch/datapath-protocol.h [deleted file]
include/openvswitch/gre.h
include/openvswitch/xflow.h [new file with mode: 0644]
lib/automake.mk
lib/classifier.c
lib/classifier.h
lib/dpif-netdev.c [deleted file]
lib/dpif.h [deleted file]
lib/flow.c
lib/flow.h
lib/hash.h
lib/hmap.h
lib/netdev-gre.c
lib/netdev-provider.h
lib/netdev.c
lib/netdev.h
lib/odp-util.c [deleted file]
lib/odp-util.h [deleted file]
lib/ofp-print.c
lib/ofpbuf.c
lib/packets.h
lib/rtnetlink.c
lib/svec.c
lib/svec.h
lib/vconn.c
lib/vlog-modules.def
lib/xfif-linux.c [moved from lib/dpif-linux.c with 58% similarity]
lib/xfif-netdev.c [new file with mode: 0644]
lib/xfif-provider.h [moved from lib/dpif-provider.h with 58% similarity]
lib/xfif.c [moved from lib/dpif.c with 58% similarity]
lib/xfif.h [new file with mode: 0644]
lib/xfif.man [moved from lib/dpif.man with 100% similarity]
lib/xflow-util.c [new file with mode: 0644]
lib/xflow-util.h [new file with mode: 0644]
ofproto/automake.mk
ofproto/discovery.c
ofproto/discovery.h
ofproto/fail-open.c
ofproto/in-band.c
ofproto/in-band.h
ofproto/ofproto-sflow.c
ofproto/ofproto-sflow.h
ofproto/ofproto.c
ofproto/ofproto.h
ofproto/pinsched.c
ofproto/pinsched.h
ofproto/pktbuf.c
ofproto/wdp-provider.h [new file with mode: 0644]
ofproto/wdp-xflow.c [new file with mode: 0644]
ofproto/wdp-xflow.h [new file with mode: 0644]
ofproto/wdp.c [new file with mode: 0644]
ofproto/wdp.h [new file with mode: 0644]
tests/automake.mk
tests/classifier.at [new file with mode: 0644]
tests/library.at
tests/test-classifier.c
tests/test-command-line.c [new file with mode: 0644]
tests/test-command-line.h [new file with mode: 0644]
tests/test-flows.c
tests/testsuite.at
utilities/ovs-dpctl.8.in
utilities/ovs-dpctl.c
utilities/ovs-ofctl.c
utilities/ovs-openflowd.8.in
utilities/ovs-openflowd.c
vswitchd/bridge.c
vswitchd/ovs-vswitchd.c

index 280f11e..99eb953 100644 (file)
@@ -145,7 +145,7 @@ true (at the time) for bridges named dpN.  Now that assumption has been
 eliminated, so this commit eliminates the restriction too.
 
 This change is also a cleanup in that it eliminates one form of the
-vswitch's dependence on specifics of the dpif implementation.
+vswitch's dependence on specifics of the xfif implementation.
 ---
  vswitchd/bridge.c               |   23 +++++------------------
  vswitchd/ovs-vswitchd.conf.5.in |    3 +--
@@ -195,10 +195,10 @@ index 32647ea..00cffbc 100644
 @@ -793,7 +780,7 @@ bridge_create(const char *name)
      br = xzalloc(sizeof *br);
  
-     error = dpif_create(name, &br->dpif);
+     error = xfif_create(name, &br->xfif);
 -    if (error == EEXIST) {
 +    if (error == EEXIST || error == EBUSY) {
-         error = dpif_open(name, &br->dpif);
+         error = xfif_open(name, &br->xfif);
          if (error) {
              VLOG_ERR("datapath %s already exists but cannot be opened: %s",
 diff --git a/vswitchd/ovs-vswitchd.conf.5.in b/vswitchd/ovs-vswitchd.conf.5.in
index ab9ae29..22616e2 100644 (file)
@@ -28,11 +28,11 @@ openvswitch_headers = \
        datapath.h \
        dp_sysfs.h \
        flow.h \
-       odp-compat.h \
        table.h \
        vport.h \
        vport-internal_dev.h \
-       vport-netdev.h
+       vport-netdev.h \
+       xflow-compat.h
 
 dist_sources = $(foreach module,$(dist_modules),$($(module)_sources))
 dist_headers = $(foreach module,$(dist_modules),$($(module)_headers))
index fed9830..baa58b7 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "actions.h"
 #include "datapath.h"
-#include "openvswitch/datapath-protocol.h"
+#include "openvswitch/xflow.h"
 #include "vport.h"
 
 static struct sk_buff *
@@ -47,7 +47,7 @@ make_writable(struct sk_buff *skb, unsigned min_headroom, gfp_t gfp)
        return NULL;
 }
 
-static void set_tunnel(struct sk_buff *skb, struct odp_flow_key *key,
+static void set_tunnel(struct sk_buff *skb, struct xflow_key *key,
                       __be32 tun_id)
 {
        OVS_CB(skb)->tun_id = key->tun_id = tun_id;
@@ -80,20 +80,13 @@ vlan_pull_tag(struct sk_buff *skb)
 
 static struct sk_buff *
 modify_vlan_tci(struct datapath *dp, struct sk_buff *skb,
-               struct odp_flow_key *key, const union odp_action *a,
+               struct xflow_key *key, const union xflow_action *a,
                int n_actions, gfp_t gfp)
 {
-       u16 tci, mask;
+       __be16 mask = a->dl_tci.mask;
+       __be16 tci = a->dl_tci.tci;
 
-       if (a->type == ODPAT_SET_VLAN_VID) {
-               tci = ntohs(a->vlan_vid.vlan_vid);
-               mask = VLAN_VID_MASK;
-               key->dl_vlan = a->vlan_vid.vlan_vid;
-       } else {
-               tci = a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT;
-               mask = VLAN_PCP_MASK;
-               key->dl_vlan_pcp = a->vlan_pcp.vlan_pcp;
-       }
+       key->dl_tci = (key->dl_tci & ~(mask | VLAN_TAG_PRESENT)) | tci;
 
        skb = make_writable(skb, VLAN_HLEN, gfp);
        if (!skb)
@@ -104,7 +97,7 @@ modify_vlan_tci(struct datapath *dp, struct sk_buff *skb,
                struct vlan_ethhdr *vh = vlan_eth_hdr(skb);
                __be16 old_tci = vh->h_vlan_TCI;
 
-               vh->h_vlan_TCI = htons((ntohs(vh->h_vlan_TCI) & ~mask) | tci);
+               vh->h_vlan_TCI = (vh->h_vlan_TCI & ~mask) | tci;
 
                if (OVS_CB(skb)->ip_summed == OVS_CSUM_COMPLETE) {
                        __be16 diff[] = { ~old_tci, vh->h_vlan_TCI };
@@ -154,10 +147,10 @@ modify_vlan_tci(struct datapath *dp, struct sk_buff *skb,
                                /* GSO can change the checksum type so update.*/
                                compute_ip_summed(segs, true);
 
-                               segs = __vlan_put_tag(segs, tci);
+                               segs = __vlan_put_tag(segs, ntohs(tci));
                                err = -ENOMEM;
                                if (segs) {
-                                       struct odp_flow_key segkey = *key;
+                                       struct xflow_key segkey = *key;
                                        err = execute_actions(dp, segs,
                                                              &segkey, a + 1,
                                                              n_actions - 1,
@@ -185,7 +178,7 @@ modify_vlan_tci(struct datapath *dp, struct sk_buff *skb,
                 * e.g. vconfig(8)), so call the software-only version
                 * __vlan_put_tag() directly instead.
                 */
-               skb = __vlan_put_tag(skb, tci);
+               skb = __vlan_put_tag(skb, ntohs(tci));
                if (!skb)
                        return ERR_PTR(-ENOMEM);
 
@@ -200,25 +193,25 @@ modify_vlan_tci(struct datapath *dp, struct sk_buff *skb,
 }
 
 static struct sk_buff *strip_vlan(struct sk_buff *skb,
-                                 struct odp_flow_key *key, gfp_t gfp)
+                                 struct xflow_key *key, gfp_t gfp)
 {
        skb = make_writable(skb, 0, gfp);
        if (skb) {
                vlan_pull_tag(skb);
-               key->dl_vlan = htons(ODP_VLAN_NONE);
+               key->dl_tci = htons(0);
        }
        return skb;
 }
 
 static struct sk_buff *set_dl_addr(struct sk_buff *skb,
-                                  struct odp_flow_key *key,
-                                  const struct odp_action_dl_addr *a,
+                                  struct xflow_key *key,
+                                  const struct xflow_action_dl_addr *a,
                                   gfp_t gfp)
 {
        skb = make_writable(skb, 0, gfp);
        if (skb) {
                struct ethhdr *eh = eth_hdr(skb);
-               if (a->type == ODPAT_SET_DL_SRC) {
+               if (a->type == XFLOWAT_SET_DL_SRC) {
                        memcpy(eh->h_source, a->dl_addr, ETH_ALEN);
                        memcpy(key->dl_src, a->dl_addr, ETH_ALEN);
                } else {
@@ -250,8 +243,8 @@ static void update_csum(__sum16 *sum, struct sk_buff *skb,
 }
 
 static struct sk_buff *set_nw_addr(struct sk_buff *skb,
-                                  struct odp_flow_key *key,
-                                  const struct odp_action_nw_addr *a,
+                                  struct xflow_key *key,
+                                  const struct xflow_action_nw_addr *a,
                                   gfp_t gfp)
 {
        if (key->dl_type != htons(ETH_P_IP))
@@ -260,7 +253,7 @@ static struct sk_buff *set_nw_addr(struct sk_buff *skb,
        skb = make_writable(skb, 0, gfp);
        if (skb) {
                struct iphdr *nh = ip_hdr(skb);
-               u32 *f = a->type == ODPAT_SET_NW_SRC ? &nh->saddr : &nh->daddr;
+               u32 *f = a->type == XFLOWAT_SET_NW_SRC ? &nh->saddr : &nh->daddr;
                u32 old = *f;
                u32 new = a->nw_addr;
 
@@ -274,7 +267,7 @@ static struct sk_buff *set_nw_addr(struct sk_buff *skb,
                update_csum(&nh->check, skb, old, new, 0);
                *f = new;
 
-               if (a->type == ODPAT_SET_NW_SRC)
+               if (a->type == XFLOWAT_SET_NW_SRC)
                        key->nw_src = a->nw_addr;
                else
                        key->nw_dst = a->nw_addr;
@@ -283,8 +276,8 @@ static struct sk_buff *set_nw_addr(struct sk_buff *skb,
 }
 
 static struct sk_buff *set_nw_tos(struct sk_buff *skb,
-                                  struct odp_flow_key *key,
-                                  const struct odp_action_nw_tos *a,
+                                  struct xflow_key *key,
+                                  const struct xflow_action_nw_tos *a,
                                   gfp_t gfp)
 {
        if (key->dl_type != htons(ETH_P_IP))
@@ -308,8 +301,8 @@ static struct sk_buff *set_nw_tos(struct sk_buff *skb,
 }
 
 static struct sk_buff *
-set_tp_port(struct sk_buff *skb, struct odp_flow_key *key,
-           const struct odp_action_tp_port *a,
+set_tp_port(struct sk_buff *skb, struct xflow_key *key,
+           const struct xflow_action_tp_port *a,
            gfp_t gfp)
 {
        int check_ofs;
@@ -327,13 +320,13 @@ set_tp_port(struct sk_buff *skb, struct odp_flow_key *key,
        skb = make_writable(skb, 0, gfp);
        if (skb) {
                struct udphdr *th = udp_hdr(skb);
-               u16 *f = a->type == ODPAT_SET_TP_SRC ? &th->source : &th->dest;
+               u16 *f = a->type == XFLOWAT_SET_TP_SRC ? &th->source : &th->dest;
                u16 old = *f;
                u16 new = a->tp_port;
                update_csum((u16*)(skb_transport_header(skb) + check_ofs), 
                                skb, old, new, 0);
                *f = new;
-               if (a->type == ODPAT_SET_TP_SRC)
+               if (a->type == XFLOWAT_SET_TP_SRC)
                        key->tp_src = a->tp_port;
                else
                        key->tp_dst = a->tp_port;
@@ -408,18 +401,18 @@ output_control(struct datapath *dp, struct sk_buff *skb, u32 arg, gfp_t gfp)
        skb = skb_clone(skb, gfp);
        if (!skb)
                return -ENOMEM;
-       return dp_output_control(dp, skb, _ODPL_ACTION_NR, arg);
+       return dp_output_control(dp, skb, _XFLOWL_ACTION_NR, arg);
 }
 
 /* Send a copy of this packet up to the sFlow agent, along with extra
  * information about what happened to it. */
 static void sflow_sample(struct datapath *dp, struct sk_buff *skb,
-                        const union odp_action *a, int n_actions,
+                        const union xflow_action *a, int n_actions,
                         gfp_t gfp, struct dp_port *dp_port)
 {
-       struct odp_sflow_sample_header *hdr;
-       unsigned int actlen = n_actions * sizeof(union odp_action);
-       unsigned int hdrlen = sizeof(struct odp_sflow_sample_header);
+       struct xflow_sflow_sample_header *hdr;
+       unsigned int actlen = n_actions * sizeof(union xflow_action);
+       unsigned int hdrlen = sizeof(struct xflow_sflow_sample_header);
        struct sk_buff *nskb;
 
        nskb = skb_copy_expand(skb, actlen + hdrlen, 0, gfp);
@@ -427,16 +420,16 @@ static void sflow_sample(struct datapath *dp, struct sk_buff *skb,
                return;
 
        memcpy(__skb_push(nskb, actlen), a, actlen);
-       hdr = (struct odp_sflow_sample_header*)__skb_push(nskb, hdrlen);
+       hdr = (struct xflow_sflow_sample_header*)__skb_push(nskb, hdrlen);
        hdr->n_actions = n_actions;
        hdr->sample_pool = atomic_read(&dp_port->sflow_pool);
-       dp_output_control(dp, nskb, _ODPL_SFLOW_NR, 0);
+       dp_output_control(dp, nskb, _XFLOWL_SFLOW_NR, 0);
 }
 
 /* Execute a list of actions against 'skb'. */
 int execute_actions(struct datapath *dp, struct sk_buff *skb,
-                   struct odp_flow_key *key,
-                   const union odp_action *a, int n_actions,
+                   struct xflow_key *key,
+                   const union xflow_action *a, int n_actions,
                    gfp_t gfp)
 {
        /* Every output action needs a separate clone of 'skb', but the common
@@ -466,16 +459,16 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
                }
 
                switch (a->type) {
-               case ODPAT_OUTPUT:
+               case XFLOWAT_OUTPUT:
                        prev_port = a->output.port;
                        break;
 
-               case ODPAT_OUTPUT_GROUP:
+               case XFLOWAT_OUTPUT_GROUP:
                        prev_port = output_group(dp, a->output_group.group,
                                                 skb, gfp);
                        break;
 
-               case ODPAT_CONTROLLER:
+               case XFLOWAT_CONTROLLER:
                        err = output_control(dp, skb, a->controller.arg, gfp);
                        if (err) {
                                kfree_skb(skb);
@@ -483,37 +476,36 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
                        }
                        break;
 
-               case ODPAT_SET_TUNNEL:
+               case XFLOWAT_SET_TUNNEL:
                        set_tunnel(skb, key, a->tunnel.tun_id);
                        break;
 
-               case ODPAT_SET_VLAN_VID:
-               case ODPAT_SET_VLAN_PCP:
+               case XFLOWAT_SET_DL_TCI:
                        skb = modify_vlan_tci(dp, skb, key, a, n_actions, gfp);
                        if (IS_ERR(skb))
                                return PTR_ERR(skb);
                        break;
 
-               case ODPAT_STRIP_VLAN:
+               case XFLOWAT_STRIP_VLAN:
                        skb = strip_vlan(skb, key, gfp);
                        break;
 
-               case ODPAT_SET_DL_SRC:
-               case ODPAT_SET_DL_DST:
+               case XFLOWAT_SET_DL_SRC:
+               case XFLOWAT_SET_DL_DST:
                        skb = set_dl_addr(skb, key, &a->dl_addr, gfp);
                        break;
 
-               case ODPAT_SET_NW_SRC:
-               case ODPAT_SET_NW_DST:
+               case XFLOWAT_SET_NW_SRC:
+               case XFLOWAT_SET_NW_DST:
                        skb = set_nw_addr(skb, key, &a->nw_addr, gfp);
                        break;
 
-               case ODPAT_SET_NW_TOS:
+               case XFLOWAT_SET_NW_TOS:
                        skb = set_nw_tos(skb, key, &a->nw_tos, gfp);
                        break;
 
-               case ODPAT_SET_TP_SRC:
-               case ODPAT_SET_TP_DST:
+               case XFLOWAT_SET_TP_SRC:
+               case XFLOWAT_SET_TP_DST:
                        skb = set_tp_port(skb, key, &a->tp_port, gfp);
                        break;
                }
index 9dfca36..a111464 100644 (file)
 
 struct datapath;
 struct sk_buff;
-struct odp_flow_key;
-union odp_action;
+struct xflow_key;
+union xflow_action;
 
 int execute_actions(struct datapath *dp, struct sk_buff *skb,
-                   struct odp_flow_key *key,
-                   const union odp_action *, int n_actions,
+                   struct xflow_key *key,
+                   const union xflow_action *, int n_actions,
                    gfp_t gfp);
 
 static inline void
index 1d007b0..b1d69a1 100644 (file)
 #include <net/inet_ecn.h>
 #include <linux/compat.h>
 
-#include "openvswitch/datapath-protocol.h"
+#include "openvswitch/xflow.h"
 #include "datapath.h"
 #include "actions.h"
 #include "flow.h"
-#include "odp-compat.h"
+#include "xflow-compat.h"
 #include "table.h"
 #include "vport-internal_dev.h"
 
@@ -65,18 +65,18 @@ EXPORT_SYMBOL(dp_ioctl_hook);
  * It is safe to access the datapath and dp_port structures with just
  * dp_mutex.
  */
-static struct datapath *dps[ODP_MAX];
+static struct datapath *dps[XFLOW_MAX];
 static DEFINE_MUTEX(dp_mutex);
 
 /* Number of milliseconds between runs of the maintenance thread. */
 #define MAINT_SLEEP_MSECS 1000
 
-static int new_dp_port(struct datapath *, struct odp_port *, int port_no);
+static int new_dp_port(struct datapath *, struct xflow_port *, int port_no);
 
 /* Must be called with rcu_read_lock or dp_mutex. */
 struct datapath *get_dp(int dp_idx)
 {
-       if (dp_idx < 0 || dp_idx >= ODP_MAX)
+       if (dp_idx < 0 || dp_idx >= XFLOW_MAX)
                return NULL;
        return rcu_dereference(dps[dp_idx]);
 }
@@ -97,7 +97,7 @@ static struct datapath *get_dp_locked(int dp_idx)
 /* Must be called with rcu_read_lock or RTNL lock. */
 const char *dp_name(const struct datapath *dp)
 {
-       return vport_get_name(dp->ports[ODPP_LOCAL]->vport);
+       return vport_get_name(dp->ports[XFLOWP_LOCAL]->vport);
 }
 
 static inline size_t br_nlmsg_size(void)
@@ -140,7 +140,7 @@ static int dp_fill_ifinfo(struct sk_buff *skb,
        hdr->ifi_change = 0;
 
        NLA_PUT_STRING(skb, IFLA_IFNAME, vport_get_name(port->vport));
-       NLA_PUT_U32(skb, IFLA_MASTER, vport_get_ifindex(dp->ports[ODPP_LOCAL]->vport));
+       NLA_PUT_U32(skb, IFLA_MASTER, vport_get_ifindex(dp->ports[XFLOWP_LOCAL]->vport));
        NLA_PUT_U32(skb, IFLA_MTU, vport_get_mtu(port->vport));
 #ifdef IFLA_OPERSTATE
        NLA_PUT_U8(skb, IFLA_OPERSTATE,
@@ -197,7 +197,7 @@ static struct kobj_type dp_ktype = {
 
 static int create_dp(int dp_idx, const char __user *devnamep)
 {
-       struct odp_port internal_dev_port;
+       struct xflow_port internal_dev_port;
        char devname[IFNAMSIZ];
        struct datapath *dp;
        int err;
@@ -254,8 +254,8 @@ static int create_dp(int dp_idx, const char __user *devnamep)
        /* Set up our datapath device. */
        BUILD_BUG_ON(sizeof(internal_dev_port.devname) != sizeof(devname));
        strcpy(internal_dev_port.devname, devname);
-       internal_dev_port.flags = ODP_PORT_INTERNAL;
-       err = new_dp_port(dp, &internal_dev_port, ODPP_LOCAL);
+       internal_dev_port.flags = XFLOW_PORT_INTERNAL;
+       err = new_dp_port(dp, &internal_dev_port, XFLOWP_LOCAL);
        if (err) {
                if (err == -EBUSY)
                        err = -EEXIST;
@@ -277,7 +277,7 @@ static int create_dp(int dp_idx, const char __user *devnamep)
        return 0;
 
 err_destroy_local_port:
-       dp_detach_port(dp->ports[ODPP_LOCAL], 1);
+       dp_detach_port(dp->ports[XFLOWP_LOCAL], 1);
 err_destroy_table:
        tbl_destroy(dp->table, NULL);
 err_free_dp:
@@ -297,14 +297,14 @@ static void do_destroy_dp(struct datapath *dp)
        int i;
 
        list_for_each_entry_safe (p, n, &dp->port_list, node)
-               if (p->port_no != ODPP_LOCAL)
+               if (p->port_no != XFLOWP_LOCAL)
                        dp_detach_port(p, 1);
 
        dp_sysfs_del_dp(dp);
 
        rcu_assign_pointer(dps[dp->dp_idx], NULL);
 
-       dp_detach_port(dp->ports[ODPP_LOCAL], 1);
+       dp_detach_port(dp->ports[XFLOWP_LOCAL], 1);
 
        tbl_destroy(dp->table, flow_free_tbl);
 
@@ -352,20 +352,20 @@ static struct kobj_type brport_ktype = {
 };
 
 /* Called with RTNL lock and dp_mutex. */
-static int new_dp_port(struct datapath *dp, struct odp_port *odp_port, int port_no)
+static int new_dp_port(struct datapath *dp, struct xflow_port *xflow_port, int port_no)
 {
        struct vport *vport;
        struct dp_port *p;
        int err;
 
-       vport = vport_locate(odp_port->devname);
+       vport = vport_locate(xflow_port->devname);
        if (!vport) {
                vport_lock();
 
-               if (odp_port->flags & ODP_PORT_INTERNAL)
-                       vport = __vport_add(odp_port->devname, "internal", NULL);
+               if (xflow_port->flags & XFLOW_PORT_INTERNAL)
+                       vport = __vport_add(xflow_port->devname, "internal", NULL);
                else
-                       vport = __vport_add(odp_port->devname, "netdev", NULL);
+                       vport = __vport_add(xflow_port->devname, "netdev", NULL);
 
                vport_unlock();
 
@@ -401,10 +401,10 @@ static int new_dp_port(struct datapath *dp, struct odp_port *odp_port, int port_
        return 0;
 }
 
-static int attach_port(int dp_idx, struct odp_port __user *portp)
+static int attach_port(int dp_idx, struct xflow_port __user *portp)
 {
        struct datapath *dp;
-       struct odp_port port;
+       struct xflow_port port;
        int port_no;
        int err;
 
@@ -450,7 +450,7 @@ int dp_detach_port(struct dp_port *p, int may_delete)
 
        ASSERT_RTNL();
 
-       if (p->port_no != ODPP_LOCAL)
+       if (p->port_no != XFLOWP_LOCAL)
                dp_sysfs_del_if(p);
        dp_ifinfo_notify(RTM_DELLINK, p);
 
@@ -488,7 +488,7 @@ static int detach_port(int dp_idx, int port_no)
        int err;
 
        err = -EINVAL;
-       if (port_no < 0 || port_no >= DP_MAX_PORTS || port_no == ODPP_LOCAL)
+       if (port_no < 0 || port_no >= DP_MAX_PORTS || port_no == XFLOWP_LOCAL)
                goto out;
 
        rtnl_lock();
@@ -518,7 +518,7 @@ void dp_process_received_packet(struct dp_port *p, struct sk_buff *skb)
        struct datapath *dp = p->dp;
        struct dp_stats_percpu *stats;
        int stats_counter_off;
-       struct odp_flow_key key;
+       struct xflow_key key;
        struct tbl_node *flow_node;
 
        WARN_ON_ONCE(skb_shared(skb));
@@ -526,7 +526,7 @@ void dp_process_received_packet(struct dp_port *p, struct sk_buff *skb)
 
        OVS_CB(skb)->dp_port = p;
 
-       if (flow_extract(skb, p ? p->port_no : ODPP_NONE, &key)) {
+       if (flow_extract(skb, p ? p->port_no : XFLOWP_NONE, &key)) {
                if (dp->drop_frags) {
                        kfree_skb(skb);
                        stats_counter_off = offsetof(struct dp_stats_percpu, n_frags);
@@ -544,7 +544,7 @@ void dp_process_received_packet(struct dp_port *p, struct sk_buff *skb)
                stats_counter_off = offsetof(struct dp_stats_percpu, n_hit);
        } else {
                stats_counter_off = offsetof(struct dp_stats_percpu, n_missed);
-               dp_output_control(dp, skb, _ODPL_MISS_NR, OVS_CB(skb)->tun_id);
+               dp_output_control(dp, skb, _XFLOWL_MISS_NR, OVS_CB(skb)->tun_id);
        }
 
 out:
@@ -735,10 +735,10 @@ queue_control_packets(struct sk_buff *skb, struct sk_buff_head *queue,
        if (OVS_CB(skb)->dp_port)
                port_no = OVS_CB(skb)->dp_port->port_no;
        else
-               port_no = ODPP_LOCAL;
+               port_no = XFLOWP_LOCAL;
 
        do {
-               struct odp_msg *header;
+               struct xflow_msg *header;
 
                nskb = skb->next;
                skb->next = NULL;
@@ -772,7 +772,7 @@ queue_control_packets(struct sk_buff *skb, struct sk_buff_head *queue,
                if (err)
                        goto err_kfree_skbs;
 
-               header = (struct odp_msg*)__skb_push(skb, sizeof *header);
+               header = (struct xflow_msg*)__skb_push(skb, sizeof *header);
                header->type = queue_no;
                header->length = skb->len;
                header->port = port_no;
@@ -802,7 +802,7 @@ dp_output_control(struct datapath *dp, struct sk_buff *skb, int queue_no,
        int err;
 
        WARN_ON_ONCE(skb_shared(skb));
-       BUG_ON(queue_no != _ODPL_MISS_NR && queue_no != _ODPL_ACTION_NR && queue_no != _ODPL_SFLOW_NR);
+       BUG_ON(queue_no != _XFLOWL_MISS_NR && queue_no != _XFLOWL_ACTION_NR && queue_no != _XFLOWL_SFLOW_NR);
        queue = &dp->queues[queue_no];
        err = -ENOBUFS;
        if (skb_queue_len(queue) >= DP_MAX_QUEUE_LEN)
@@ -863,36 +863,37 @@ static int validate_actions(const struct sw_flow_actions *actions)
        unsigned int i;
 
        for (i = 0; i < actions->n_actions; i++) {
-               const union odp_action *a = &actions->actions[i];
+               const union xflow_action *a = &actions->actions[i];
+               __be16 mask;
+
                switch (a->type) {
-               case ODPAT_OUTPUT:
+               case XFLOWAT_OUTPUT:
                        if (a->output.port >= DP_MAX_PORTS)
                                return -EINVAL;
                        break;
 
-               case ODPAT_OUTPUT_GROUP:
+               case XFLOWAT_OUTPUT_GROUP:
                        if (a->output_group.group >= DP_MAX_GROUPS)
                                return -EINVAL;
                        break;
 
-               case ODPAT_SET_VLAN_VID:
-                       if (a->vlan_vid.vlan_vid & htons(~VLAN_VID_MASK))
+               case XFLOWAT_SET_DL_TCI:
+                       mask = a->dl_tci.mask;
+                       if (mask != htons(VLAN_VID_MASK) &&
+                           mask != htons(VLAN_PCP_MASK) &&
+                           mask != htons(VLAN_VID_MASK | VLAN_PCP_MASK))
                                return -EINVAL;
-                       break;
-
-               case ODPAT_SET_VLAN_PCP:
-                       if (a->vlan_pcp.vlan_pcp
-                           & ~(VLAN_PCP_MASK >> VLAN_PCP_SHIFT))
+                       if (a->dl_tci.tci & ~mask)
                                return -EINVAL;
                        break;
 
-               case ODPAT_SET_NW_TOS:
+               case XFLOWAT_SET_NW_TOS:
                        if (a->nw_tos.nw_tos & INET_ECN_MASK)
                                return -EINVAL;
                        break;
 
                default:
-                       if (a->type >= ODPAT_N_ACTIONS)
+                       if (a->type >= XFLOWAT_N_ACTIONS)
                                return -EOPNOTSUPP;
                        break;
                }
@@ -901,7 +902,7 @@ static int validate_actions(const struct sw_flow_actions *actions)
        return 0;
 }
 
-static struct sw_flow_actions *get_actions(const struct odp_flow *flow)
+static struct sw_flow_actions *get_actions(const struct xflow_flow *flow)
 {
        struct sw_flow_actions *actions;
        int error;
@@ -913,7 +914,7 @@ static struct sw_flow_actions *get_actions(const struct odp_flow *flow)
 
        error = -EFAULT;
        if (copy_from_user(actions->actions, flow->actions,
-                          flow->n_actions * sizeof(union odp_action)))
+                          flow->n_actions * sizeof(union xflow_action)))
                goto error_free_actions;
        error = validate_actions(actions);
        if (error)
@@ -927,7 +928,7 @@ error:
        return ERR_PTR(error);
 }
 
-static void get_stats(struct sw_flow *flow, struct odp_flow_stats *stats)
+static void get_stats(struct sw_flow *flow, struct xflow_flow_stats *stats)
 {
        if (flow->used.tv_sec) {
                stats->used_sec = flow->used.tv_sec;
@@ -967,16 +968,14 @@ static int expand_table(struct datapath *dp)
        return 0;
 }
 
-static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf,
-                      struct odp_flow_stats *stats)
+static int do_put_flow(struct datapath *dp, struct xflow_flow_put *uf,
+                      struct xflow_flow_stats *stats)
 {
        struct tbl_node *flow_node;
        struct sw_flow *flow;
        struct tbl *table;
        int error;
 
-       memset(uf->flow.key.reserved, 0, sizeof uf->flow.key.reserved);
-
        table = rcu_dereference(dp->table);
        flow_node = tbl_lookup(table, &uf->flow.key, flow_hash(&uf->flow.key), flow_cmp);
        if (!flow_node) {
@@ -984,7 +983,7 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf,
                struct sw_flow_actions *acts;
 
                error = -ENOENT;
-               if (!(uf->flags & ODPPF_CREATE))
+               if (!(uf->flags & XFLOWPF_CREATE))
                        goto error;
 
                /* Expand table, if necessary, to make room. */
@@ -1016,7 +1015,7 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf,
                if (error)
                        goto error_free_flow_acts;
 
-               memset(stats, 0, sizeof(struct odp_flow_stats));
+               memset(stats, 0, sizeof(struct xflow_flow_stats));
        } else {
                /* We found a matching flow. */
                struct sw_flow_actions *old_acts, *new_acts;
@@ -1025,7 +1024,7 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf,
 
                /* Bail out if we're not allowed to modify an existing flow. */
                error = -EEXIST;
-               if (!(uf->flags & ODPPF_MODIFY))
+               if (!(uf->flags & XFLOWPF_MODIFY))
                        goto error;
 
                /* Swap actions. */
@@ -1036,7 +1035,7 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf,
                old_acts = rcu_dereference(flow->sf_acts);
                if (old_acts->n_actions != new_acts->n_actions ||
                    memcmp(old_acts->actions, new_acts->actions,
-                          sizeof(union odp_action) * old_acts->n_actions)) {
+                          sizeof(union xflow_action) * old_acts->n_actions)) {
                        rcu_assign_pointer(flow->sf_acts, new_acts);
                        flow_deferred_free_acts(old_acts);
                } else {
@@ -1046,7 +1045,7 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf,
                /* Fetch stats, then clear them if necessary. */
                spin_lock_bh(&flow->lock);
                get_stats(flow, stats);
-               if (uf->flags & ODPPF_ZERO_STATS)
+               if (uf->flags & XFLOWPF_ZERO_STATS)
                        clear_stats(flow);
                spin_unlock_bh(&flow->lock);
        }
@@ -1061,13 +1060,13 @@ error:
        return error;
 }
 
-static int put_flow(struct datapath *dp, struct odp_flow_put __user *ufp)
+static int put_flow(struct datapath *dp, struct xflow_flow_put __user *ufp)
 {
-       struct odp_flow_stats stats;
-       struct odp_flow_put uf;
+       struct xflow_flow_stats stats;
+       struct xflow_flow_put uf;
        int error;
 
-       if (copy_from_user(&uf, ufp, sizeof(struct odp_flow_put)))
+       if (copy_from_user(&uf, ufp, sizeof(struct xflow_flow_put)))
                return -EFAULT;
 
        error = do_put_flow(dp, &uf, &stats);
@@ -1075,29 +1074,29 @@ static int put_flow(struct datapath *dp, struct odp_flow_put __user *ufp)
                return error;
 
        if (copy_to_user(&ufp->flow.stats, &stats,
-                        sizeof(struct odp_flow_stats)))
+                        sizeof(struct xflow_flow_stats)))
                return -EFAULT;
 
        return 0;
 }
 
 static int do_answer_query(struct sw_flow *flow, u32 query_flags,
-                          struct odp_flow_stats __user *ustats,
-                          union odp_action __user *actions,
+                          struct xflow_flow_stats __user *ustats,
+                          union xflow_action __user *actions,
                           u32 __user *n_actionsp)
 {
        struct sw_flow_actions *sf_acts;
-       struct odp_flow_stats stats;
+       struct xflow_flow_stats stats;
        u32 n_actions;
 
        spin_lock_bh(&flow->lock);
        get_stats(flow, &stats);
-       if (query_flags & ODPFF_ZERO_TCP_FLAGS)
+       if (query_flags & XFLOWFF_ZERO_TCP_FLAGS)
                flow->tcp_flags = 0;
 
        spin_unlock_bh(&flow->lock);
 
-       if (copy_to_user(ustats, &stats, sizeof(struct odp_flow_stats)) ||
+       if (copy_to_user(ustats, &stats, sizeof(struct xflow_flow_stats)) ||
            get_user(n_actions, n_actionsp))
                return -EFAULT;
 
@@ -1107,7 +1106,7 @@ static int do_answer_query(struct sw_flow *flow, u32 query_flags,
        sf_acts = rcu_dereference(flow->sf_acts);
        if (put_user(sf_acts->n_actions, n_actionsp) ||
            (actions && copy_to_user(actions, sf_acts->actions,
-                                    sizeof(union odp_action) *
+                                    sizeof(union xflow_action) *
                                     min(sf_acts->n_actions, n_actions))))
                return -EFAULT;
 
@@ -1115,9 +1114,9 @@ static int do_answer_query(struct sw_flow *flow, u32 query_flags,
 }
 
 static int answer_query(struct sw_flow *flow, u32 query_flags,
-                       struct odp_flow __user *ufp)
+                       struct xflow_flow __user *ufp)
 {
-       union odp_action *actions;
+       union xflow_action *actions;
 
        if (get_user(actions, &ufp->actions))
                return -EFAULT;
@@ -1126,13 +1125,12 @@ static int answer_query(struct sw_flow *flow, u32 query_flags,
                               &ufp->stats, actions, &ufp->n_actions);
 }
 
-static struct sw_flow *do_del_flow(struct datapath *dp, struct odp_flow_key *key)
+static struct sw_flow *do_del_flow(struct datapath *dp, struct xflow_key *key)
 {
        struct tbl *table = rcu_dereference(dp->table);
        struct tbl_node *flow_node;
        int error;
 
-       memset(key->reserved, 0, sizeof key->reserved);
        flow_node = tbl_lookup(table, key, flow_hash(key), flow_cmp);
        if (!flow_node)
                return ERR_PTR(-ENOENT);
@@ -1148,10 +1146,10 @@ static struct sw_flow *do_del_flow(struct datapath *dp, struct odp_flow_key *key
        return flow_cast(flow_node);
 }
 
-static int del_flow(struct datapath *dp, struct odp_flow __user *ufp)
+static int del_flow(struct datapath *dp, struct xflow_flow __user *ufp)
 {
        struct sw_flow *flow;
-       struct odp_flow uf;
+       struct xflow_flow uf;
        int error;
 
        if (copy_from_user(&uf, ufp, sizeof uf))
@@ -1166,20 +1164,19 @@ static int del_flow(struct datapath *dp, struct odp_flow __user *ufp)
        return error;
 }
 
-static int do_query_flows(struct datapath *dp, const struct odp_flowvec *flowvec)
+static int do_query_flows(struct datapath *dp, const struct xflow_flowvec *flowvec)
 {
        struct tbl *table = rcu_dereference(dp->table);
        u32 i;
 
        for (i = 0; i < flowvec->n_flows; i++) {
-               struct odp_flow __user *ufp = &flowvec->flows[i];
-               struct odp_flow uf;
+               struct xflow_flow __user *ufp = &flowvec->flows[i];
+               struct xflow_flow uf;
                struct tbl_node *flow_node;
                int error;
 
                if (copy_from_user(&uf, ufp, sizeof uf))
                        return -EFAULT;
-               memset(uf.key.reserved, 0, sizeof uf.key.reserved);
 
                flow_node = tbl_lookup(table, &uf.key, flow_hash(&uf.key), flow_cmp);
                if (!flow_node)
@@ -1193,7 +1190,7 @@ static int do_query_flows(struct datapath *dp, const struct odp_flowvec *flowvec
 }
 
 struct list_flows_cbdata {
-       struct odp_flow __user *uflows;
+       struct xflow_flow __user *uflows;
        u32 n_flows;
        u32 listed_flows;
 };
@@ -1202,7 +1199,7 @@ static int list_flow(struct tbl_node *node, void *cbdata_)
 {
        struct sw_flow *flow = flow_cast(node);
        struct list_flows_cbdata *cbdata = cbdata_;
-       struct odp_flow __user *ufp = &cbdata->uflows[cbdata->listed_flows++];
+       struct xflow_flow __user *ufp = &cbdata->uflows[cbdata->listed_flows++];
        int error;
 
        if (copy_to_user(&ufp->key, &flow->key, sizeof flow->key))
@@ -1216,7 +1213,7 @@ static int list_flow(struct tbl_node *node, void *cbdata_)
        return 0;
 }
 
-static int do_list_flows(struct datapath *dp, const struct odp_flowvec *flowvec)
+static int do_list_flows(struct datapath *dp, const struct xflow_flowvec *flowvec)
 {
        struct list_flows_cbdata cbdata;
        int error;
@@ -1233,17 +1230,17 @@ static int do_list_flows(struct datapath *dp, const struct odp_flowvec *flowvec)
 
 static int do_flowvec_ioctl(struct datapath *dp, unsigned long argp,
                            int (*function)(struct datapath *,
-                                           const struct odp_flowvec *))
+                                           const struct xflow_flowvec *))
 {
-       struct odp_flowvec __user *uflowvec;
-       struct odp_flowvec flowvec;
+       struct xflow_flowvec __user *uflowvec;
+       struct xflow_flowvec flowvec;
        int retval;
 
-       uflowvec = (struct odp_flowvec __user *)argp;
+       uflowvec = (struct xflow_flowvec __user *)argp;
        if (copy_from_user(&flowvec, uflowvec, sizeof flowvec))
                return -EFAULT;
 
-       if (flowvec.n_flows > INT_MAX / sizeof(struct odp_flow))
+       if (flowvec.n_flows > INT_MAX / sizeof(struct xflow_flow))
                return -EINVAL;
 
        retval = function(dp, &flowvec);
@@ -1252,9 +1249,9 @@ static int do_flowvec_ioctl(struct datapath *dp, unsigned long argp,
                : put_user(retval, &uflowvec->n_flows));
 }
 
-static int do_execute(struct datapath *dp, const struct odp_execute *execute)
+static int do_execute(struct datapath *dp, const struct xflow_execute *execute)
 {
-       struct odp_flow_key key;
+       struct xflow_key key;
        struct sk_buff *skb;
        struct sw_flow_actions *actions;
        struct ethhdr *eth;
@@ -1322,9 +1319,9 @@ error:
        return err;
 }
 
-static int execute_packet(struct datapath *dp, const struct odp_execute __user *executep)
+static int execute_packet(struct datapath *dp, const struct xflow_execute __user *executep)
 {
-       struct odp_execute execute;
+       struct xflow_execute execute;
 
        if (copy_from_user(&execute, executep, sizeof execute))
                return -EFAULT;
@@ -1332,10 +1329,10 @@ static int execute_packet(struct datapath *dp, const struct odp_execute __user *
        return do_execute(dp, &execute);
 }
 
-static int get_dp_stats(struct datapath *dp, struct odp_stats __user *statsp)
+static int get_dp_stats(struct datapath *dp, struct xflow_stats __user *statsp)
 {
        struct tbl *table = rcu_dereference(dp->table);
-       struct odp_stats stats;
+       struct xflow_stats stats;
        int i;
 
        stats.n_flows = tbl_count(table);
@@ -1400,9 +1397,9 @@ void set_internal_devs_mtu(const struct datapath *dp)
 }
 
 static int
-put_port(const struct dp_port *p, struct odp_port __user *uop)
+put_port(const struct dp_port *p, struct xflow_port __user *uop)
 {
-       struct odp_port op;
+       struct xflow_port op;
 
        memset(&op, 0, sizeof op);
 
@@ -1411,15 +1408,15 @@ put_port(const struct dp_port *p, struct odp_port __user *uop)
        rcu_read_unlock();
 
        op.port = p->port_no;
-       op.flags = is_internal_vport(p->vport) ? ODP_PORT_INTERNAL : 0;
+       op.flags = is_internal_vport(p->vport) ? XFLOW_PORT_INTERNAL : 0;
 
        return copy_to_user(uop, &op, sizeof op) ? -EFAULT : 0;
 }
 
 static int
-query_port(struct datapath *dp, struct odp_port __user *uport)
+query_port(struct datapath *dp, struct xflow_port __user *uport)
 {
-       struct odp_port port;
+       struct xflow_port port;
 
        if (copy_from_user(&port, uport, sizeof port))
                return -EFAULT;
@@ -1465,7 +1462,7 @@ error_unlock:
 }
 
 static int
-do_list_ports(struct datapath *dp, struct odp_port __user *uports, int n_ports)
+do_list_ports(struct datapath *dp, struct xflow_port __user *uports, int n_ports)
 {
        int idx = 0;
        if (n_ports) {
@@ -1482,9 +1479,9 @@ do_list_ports(struct datapath *dp, struct odp_port __user *uports, int n_ports)
 }
 
 static int
-list_ports(struct datapath *dp, struct odp_portvec __user *upv)
+list_ports(struct datapath *dp, struct xflow_portvec __user *upv)
 {
-       struct odp_portvec pv;
+       struct xflow_portvec pv;
        int retval;
 
        if (copy_from_user(&pv, upv, sizeof pv))
@@ -1537,9 +1534,9 @@ error:
 }
 
 static int
-set_port_group(struct datapath *dp, const struct odp_port_group __user *upg)
+set_port_group(struct datapath *dp, const struct xflow_port_group __user *upg)
 {
-       struct odp_port_group pg;
+       struct xflow_port_group pg;
 
        if (copy_from_user(&pg, upg, sizeof pg))
                return -EFAULT;
@@ -1569,9 +1566,9 @@ do_get_port_group(struct datapath *dp,
        return 0;
 }
 
-static int get_port_group(struct datapath *dp, struct odp_port_group __user *upg)
+static int get_port_group(struct datapath *dp, struct xflow_port_group __user *upg)
 {
-       struct odp_port_group pg;
+       struct xflow_port_group pg;
 
        if (copy_from_user(&pg, upg, sizeof pg))
                return -EFAULT;
@@ -1600,54 +1597,54 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd,
 
        /* Handle commands with special locking requirements up front. */
        switch (cmd) {
-       case ODP_DP_CREATE:
+       case XFLOW_DP_CREATE:
                err = create_dp(dp_idx, (char __user *)argp);
                goto exit;
 
-       case ODP_DP_DESTROY:
+       case XFLOW_DP_DESTROY:
                err = destroy_dp(dp_idx);
                goto exit;
 
-       case ODP_PORT_ATTACH:
-               err = attach_port(dp_idx, (struct odp_port __user *)argp);
+       case XFLOW_PORT_ATTACH:
+               err = attach_port(dp_idx, (struct xflow_port __user *)argp);
                goto exit;
 
-       case ODP_PORT_DETACH:
+       case XFLOW_PORT_DETACH:
                err = get_user(port_no, (int __user *)argp);
                if (!err)
                        err = detach_port(dp_idx, port_no);
                goto exit;
 
-       case ODP_VPORT_ADD:
-               err = vport_add((struct odp_vport_add __user *)argp);
+       case XFLOW_VPORT_ADD:
+               err = vport_add((struct xflow_vport_add __user *)argp);
                goto exit;
 
-       case ODP_VPORT_MOD:
-               err = vport_mod((struct odp_vport_mod __user *)argp);
+       case XFLOW_VPORT_MOD:
+               err = vport_mod((struct xflow_vport_mod __user *)argp);
                goto exit;
 
-       case ODP_VPORT_DEL:
+       case XFLOW_VPORT_DEL:
                err = vport_del((char __user *)argp);
                goto exit;
 
-       case ODP_VPORT_STATS_GET:
-               err = vport_stats_get((struct odp_vport_stats_req __user *)argp);
+       case XFLOW_VPORT_STATS_GET:
+               err = vport_stats_get((struct xflow_vport_stats_req __user *)argp);
                goto exit;
 
-       case ODP_VPORT_ETHER_GET:
-               err = vport_ether_get((struct odp_vport_ether __user *)argp);
+       case XFLOW_VPORT_ETHER_GET:
+               err = vport_ether_get((struct xflow_vport_ether __user *)argp);
                goto exit;
 
-       case ODP_VPORT_ETHER_SET:
-               err = vport_ether_set((struct odp_vport_ether __user *)argp);
+       case XFLOW_VPORT_ETHER_SET:
+               err = vport_ether_set((struct xflow_vport_ether __user *)argp);
                goto exit;
 
-       case ODP_VPORT_MTU_GET:
-               err = vport_mtu_get((struct odp_vport_mtu __user *)argp);
+       case XFLOW_VPORT_MTU_GET:
+               err = vport_mtu_get((struct xflow_vport_mtu __user *)argp);
                goto exit;
 
-       case ODP_VPORT_MTU_SET:
-               err = vport_mtu_set((struct odp_vport_mtu __user *)argp);
+       case XFLOW_VPORT_MTU_SET:
+               err = vport_mtu_set((struct xflow_vport_mtu __user *)argp);
                goto exit;
        }
 
@@ -1657,15 +1654,15 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd,
                goto exit;
 
        switch (cmd) {
-       case ODP_DP_STATS:
-               err = get_dp_stats(dp, (struct odp_stats __user *)argp);
+       case XFLOW_DP_STATS:
+               err = get_dp_stats(dp, (struct xflow_stats __user *)argp);
                break;
 
-       case ODP_GET_DROP_FRAGS:
+       case XFLOW_GET_DROP_FRAGS:
                err = put_user(dp->drop_frags, (int __user *)argp);
                break;
 
-       case ODP_SET_DROP_FRAGS:
+       case XFLOW_SET_DROP_FRAGS:
                err = get_user(drop_frags, (int __user *)argp);
                if (err)
                        break;
@@ -1676,69 +1673,69 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd,
                err = 0;
                break;
 
-       case ODP_GET_LISTEN_MASK:
+       case XFLOW_GET_LISTEN_MASK:
                err = put_user(get_listen_mask(f), (int __user *)argp);
                break;
 
-       case ODP_SET_LISTEN_MASK:
+       case XFLOW_SET_LISTEN_MASK:
                err = get_user(listeners, (int __user *)argp);
                if (err)
                        break;
                err = -EINVAL;
-               if (listeners & ~ODPL_ALL)
+               if (listeners & ~XFLOWL_ALL)
                        break;
                err = 0;
                set_listen_mask(f, listeners);
                break;
 
-       case ODP_GET_SFLOW_PROBABILITY:
+       case XFLOW_GET_SFLOW_PROBABILITY:
                err = put_user(dp->sflow_probability, (unsigned int __user *)argp);
                break;
 
-       case ODP_SET_SFLOW_PROBABILITY:
+       case XFLOW_SET_SFLOW_PROBABILITY:
                err = get_user(sflow_probability, (unsigned int __user *)argp);
                if (!err)
                        dp->sflow_probability = sflow_probability;
                break;
 
-       case ODP_PORT_QUERY:
-               err = query_port(dp, (struct odp_port __user *)argp);
+       case XFLOW_PORT_QUERY:
+               err = query_port(dp, (struct xflow_port __user *)argp);
                break;
 
-       case ODP_PORT_LIST:
-               err = list_ports(dp, (struct odp_portvec __user *)argp);
+       case XFLOW_PORT_LIST:
+               err = list_ports(dp, (struct xflow_portvec __user *)argp);
                break;
 
-       case ODP_PORT_GROUP_SET:
-               err = set_port_group(dp, (struct odp_port_group __user *)argp);
+       case XFLOW_PORT_GROUP_SET:
+               err = set_port_group(dp, (struct xflow_port_group __user *)argp);
                break;
 
-       case ODP_PORT_GROUP_GET:
-               err = get_port_group(dp, (struct odp_port_group __user *)argp);
+       case XFLOW_PORT_GROUP_GET:
+               err = get_port_group(dp, (struct xflow_port_group __user *)argp);
                break;
 
-       case ODP_FLOW_FLUSH:
+       case XFLOW_FLOW_FLUSH:
                err = flush_flows(dp);
                break;
 
-       case ODP_FLOW_PUT:
-               err = put_flow(dp, (struct odp_flow_put __user *)argp);
+       case XFLOW_FLOW_PUT:
+               err = put_flow(dp, (struct xflow_flow_put __user *)argp);
                break;
 
-       case ODP_FLOW_DEL:
-               err = del_flow(dp, (struct odp_flow __user *)argp);
+       case XFLOW_FLOW_DEL:
+               err = del_flow(dp, (struct xflow_flow __user *)argp);
                break;
 
-       case ODP_FLOW_GET:
+       case XFLOW_FLOW_GET:
                err = do_flowvec_ioctl(dp, argp, do_query_flows);
                break;
 
-       case ODP_FLOW_LIST:
+       case XFLOW_FLOW_LIST:
                err = do_flowvec_ioctl(dp, argp, do_list_flows);
                break;
 
-       case ODP_EXECUTE:
-               err = execute_packet(dp, (struct odp_execute __user *)argp);
+       case XFLOW_EXECUTE:
+               err = execute_packet(dp, (struct xflow_execute __user *)argp);
                break;
 
        default:
@@ -1761,9 +1758,9 @@ static int dp_has_packet_of_interest(struct datapath *dp, int listeners)
 }
 
 #ifdef CONFIG_COMPAT
-static int compat_list_ports(struct datapath *dp, struct compat_odp_portvec __user *upv)
+static int compat_list_ports(struct datapath *dp, struct compat_xflow_portvec __user *upv)
 {
-       struct compat_odp_portvec pv;
+       struct compat_xflow_portvec pv;
        int retval;
 
        if (copy_from_user(&pv, upv, sizeof pv))
@@ -1776,9 +1773,9 @@ static int compat_list_ports(struct datapath *dp, struct compat_odp_portvec __us
        return put_user(retval, &upv->n_ports);
 }
 
-static int compat_set_port_group(struct datapath *dp, const struct compat_odp_port_group __user *upg)
+static int compat_set_port_group(struct datapath *dp, const struct compat_xflow_port_group __user *upg)
 {
-       struct compat_odp_port_group pg;
+       struct compat_xflow_port_group pg;
 
        if (copy_from_user(&pg, upg, sizeof pg))
                return -EFAULT;
@@ -1786,9 +1783,9 @@ static int compat_set_port_group(struct datapath *dp, const struct compat_odp_po
        return do_set_port_group(dp, compat_ptr(pg.ports), pg.n_ports, pg.group);
 }
 
-static int compat_get_port_group(struct datapath *dp, struct compat_odp_port_group __user *upg)
+static int compat_get_port_group(struct datapath *dp, struct compat_xflow_port_group __user *upg)
 {
-       struct compat_odp_port_group pg;
+       struct compat_xflow_port_group pg;
 
        if (copy_from_user(&pg, upg, sizeof pg))
                return -EFAULT;
@@ -1797,13 +1794,13 @@ static int compat_get_port_group(struct datapath *dp, struct compat_odp_port_gro
                                 pg.group, &pg.n_ports);
 }
 
-static int compat_get_flow(struct odp_flow *flow, const struct compat_odp_flow __user *compat)
+static int compat_get_flow(struct xflow_flow *flow, const struct compat_xflow_flow __user *compat)
 {
        compat_uptr_t actions;
 
-       if (!access_ok(VERIFY_READ, compat, sizeof(struct compat_odp_flow)) ||
-           __copy_from_user(&flow->stats, &compat->stats, sizeof(struct odp_flow_stats)) ||
-           __copy_from_user(&flow->key, &compat->key, sizeof(struct odp_flow_key)) ||
+       if (!access_ok(VERIFY_READ, compat, sizeof(struct compat_xflow_flow)) ||
+           __copy_from_user(&flow->stats, &compat->stats, sizeof(struct xflow_flow_stats)) ||
+           __copy_from_user(&flow->key, &compat->key, sizeof(struct xflow_key)) ||
            __get_user(actions, &compat->actions) ||
            __get_user(flow->n_actions, &compat->n_actions) ||
            __get_user(flow->flags, &compat->flags))
@@ -1813,10 +1810,10 @@ static int compat_get_flow(struct odp_flow *flow, const struct compat_odp_flow _
        return 0;
 }
 
-static int compat_put_flow(struct datapath *dp, struct compat_odp_flow_put __user *ufp)
+static int compat_put_flow(struct datapath *dp, struct compat_xflow_flow_put __user *ufp)
 {
-       struct odp_flow_stats stats;
-       struct odp_flow_put fp;
+       struct xflow_flow_stats stats;
+       struct xflow_flow_put fp;
        int error;
 
        if (compat_get_flow(&fp.flow, &ufp->flow) ||
@@ -1828,14 +1825,14 @@ static int compat_put_flow(struct datapath *dp, struct compat_odp_flow_put __use
                return error;
 
        if (copy_to_user(&ufp->flow.stats, &stats,
-                        sizeof(struct odp_flow_stats)))
+                        sizeof(struct xflow_flow_stats)))
                return -EFAULT;
 
        return 0;
 }
 
 static int compat_answer_query(struct sw_flow *flow, u32 query_flags,
-                              struct compat_odp_flow __user *ufp)
+                              struct compat_xflow_flow __user *ufp)
 {
        compat_uptr_t actions;
 
@@ -1846,10 +1843,10 @@ static int compat_answer_query(struct sw_flow *flow, u32 query_flags,
                               compat_ptr(actions), &ufp->n_actions);
 }
 
-static int compat_del_flow(struct datapath *dp, struct compat_odp_flow __user *ufp)
+static int compat_del_flow(struct datapath *dp, struct compat_xflow_flow __user *ufp)
 {
        struct sw_flow *flow;
-       struct odp_flow uf;
+       struct xflow_flow uf;
        int error;
 
        if (compat_get_flow(&uf, ufp))
@@ -1864,14 +1861,14 @@ static int compat_del_flow(struct datapath *dp, struct compat_odp_flow __user *u
        return error;
 }
 
-static int compat_query_flows(struct datapath *dp, struct compat_odp_flow *flows, u32 n_flows)
+static int compat_query_flows(struct datapath *dp, struct compat_xflow_flow *flows, u32 n_flows)
 {
        struct tbl *table = rcu_dereference(dp->table);
        u32 i;
 
        for (i = 0; i < n_flows; i++) {
-               struct compat_odp_flow __user *ufp = &flows[i];
-               struct odp_flow uf;
+               struct compat_xflow_flow __user *ufp = &flows[i];
+               struct xflow_flow uf;
                struct tbl_node *flow_node;
                int error;
 
@@ -1891,7 +1888,7 @@ static int compat_query_flows(struct datapath *dp, struct compat_odp_flow *flows
 }
 
 struct compat_list_flows_cbdata {
-       struct compat_odp_flow __user *uflows;
+       struct compat_xflow_flow __user *uflows;
        u32 n_flows;
        u32 listed_flows;
 };
@@ -1900,7 +1897,7 @@ static int compat_list_flow(struct tbl_node *node, void *cbdata_)
 {
        struct sw_flow *flow = flow_cast(node);
        struct compat_list_flows_cbdata *cbdata = cbdata_;
-       struct compat_odp_flow __user *ufp = &cbdata->uflows[cbdata->listed_flows++];
+       struct compat_xflow_flow __user *ufp = &cbdata->uflows[cbdata->listed_flows++];
        int error;
 
        if (copy_to_user(&ufp->key, &flow->key, sizeof flow->key))
@@ -1914,7 +1911,7 @@ static int compat_list_flow(struct tbl_node *node, void *cbdata_)
        return 0;
 }
 
-static int compat_list_flows(struct datapath *dp, struct compat_odp_flow *flows, u32 n_flows)
+static int compat_list_flows(struct datapath *dp, struct compat_xflow_flow *flows, u32 n_flows)
 {
        struct compat_list_flows_cbdata cbdata;
        int error;
@@ -1931,12 +1928,12 @@ static int compat_list_flows(struct datapath *dp, struct compat_odp_flow *flows,
 
 static int compat_flowvec_ioctl(struct datapath *dp, unsigned long argp,
                                int (*function)(struct datapath *,
-                                               struct compat_odp_flow *,
+                                               struct compat_xflow_flow *,
                                                u32 n_flows))
 {
-       struct compat_odp_flowvec __user *uflowvec;
-       struct compat_odp_flow __user *flows;
-       struct compat_odp_flowvec flowvec;
+       struct compat_xflow_flowvec __user *uflowvec;
+       struct compat_xflow_flow __user *flows;
+       struct compat_xflow_flowvec flowvec;
        int retval;
 
        uflowvec = compat_ptr(argp);
@@ -1944,12 +1941,12 @@ static int compat_flowvec_ioctl(struct datapath *dp, unsigned long argp,
            copy_from_user(&flowvec, uflowvec, sizeof flowvec))
                return -EFAULT;
 
-       if (flowvec.n_flows > INT_MAX / sizeof(struct compat_odp_flow))
+       if (flowvec.n_flows > INT_MAX / sizeof(struct compat_xflow_flow))
                return -EINVAL;
 
        flows = compat_ptr(flowvec.flows);
        if (!access_ok(VERIFY_WRITE, flows,
-                      flowvec.n_flows * sizeof(struct compat_odp_flow)))
+                      flowvec.n_flows * sizeof(struct compat_xflow_flow)))
                return -EFAULT;
 
        retval = function(dp, flows, flowvec.n_flows);
@@ -1958,13 +1955,13 @@ static int compat_flowvec_ioctl(struct datapath *dp, unsigned long argp,
                : put_user(retval, &uflowvec->n_flows));
 }
 
-static int compat_execute(struct datapath *dp, const struct compat_odp_execute __user *uexecute)
+static int compat_execute(struct datapath *dp, const struct compat_xflow_execute __user *uexecute)
 {
-       struct odp_execute execute;
+       struct xflow_execute execute;
        compat_uptr_t actions;
        compat_uptr_t data;
 
-       if (!access_ok(VERIFY_READ, uexecute, sizeof(struct compat_odp_execute)) ||
+       if (!access_ok(VERIFY_READ, uexecute, sizeof(struct compat_xflow_execute)) ||
            __get_user(execute.in_port, &uexecute->in_port) ||
            __get_user(actions, &uexecute->actions) ||
            __get_user(execute.n_actions, &uexecute->n_actions) ||
@@ -1985,35 +1982,35 @@ static long openvswitch_compat_ioctl(struct file *f, unsigned int cmd, unsigned
        int err;
 
        switch (cmd) {
-       case ODP_DP_DESTROY:
-       case ODP_FLOW_FLUSH:
+       case XFLOW_DP_DESTROY:
+       case XFLOW_FLOW_FLUSH:
                /* Ioctls that don't need any translation at all. */
                return openvswitch_ioctl(f, cmd, argp);
 
-       case ODP_DP_CREATE:
-       case ODP_PORT_ATTACH:
-       case ODP_PORT_DETACH:
-       case ODP_VPORT_DEL:
-       case ODP_VPORT_MTU_SET:
-       case ODP_VPORT_MTU_GET:
-       case ODP_VPORT_ETHER_SET:
-       case ODP_VPORT_ETHER_GET:
-       case ODP_VPORT_STATS_GET:
-       case ODP_DP_STATS:
-       case ODP_GET_DROP_FRAGS:
-       case ODP_SET_DROP_FRAGS:
-       case ODP_SET_LISTEN_MASK:
-       case ODP_GET_LISTEN_MASK:
-       case ODP_SET_SFLOW_PROBABILITY:
-       case ODP_GET_SFLOW_PROBABILITY:
-       case ODP_PORT_QUERY:
+       case XFLOW_DP_CREATE:
+       case XFLOW_PORT_ATTACH:
+       case XFLOW_PORT_DETACH:
+       case XFLOW_VPORT_DEL:
+       case XFLOW_VPORT_MTU_SET:
+       case XFLOW_VPORT_MTU_GET:
+       case XFLOW_VPORT_ETHER_SET:
+       case XFLOW_VPORT_ETHER_GET:
+       case XFLOW_VPORT_STATS_GET:
+       case XFLOW_DP_STATS:
+       case XFLOW_GET_DROP_FRAGS:
+       case XFLOW_SET_DROP_FRAGS:
+       case XFLOW_SET_LISTEN_MASK:
+       case XFLOW_GET_LISTEN_MASK:
+       case XFLOW_SET_SFLOW_PROBABILITY:
+       case XFLOW_GET_SFLOW_PROBABILITY:
+       case XFLOW_PORT_QUERY:
                /* Ioctls that just need their pointer argument extended. */
                return openvswitch_ioctl(f, cmd, (unsigned long)compat_ptr(argp));
 
-       case ODP_VPORT_ADD32:
+       case XFLOW_VPORT_ADD32:
                return compat_vport_add(compat_ptr(argp));
 
-       case ODP_VPORT_MOD32:
+       case XFLOW_VPORT_MOD32:
                return compat_vport_mod(compat_ptr(argp));
        }
 
@@ -2023,35 +2020,35 @@ static long openvswitch_compat_ioctl(struct file *f, unsigned int cmd, unsigned
                goto exit;
 
        switch (cmd) {
-       case ODP_PORT_LIST32:
+       case XFLOW_PORT_LIST32:
                err = compat_list_ports(dp, compat_ptr(argp));
                break;
 
-       case ODP_PORT_GROUP_SET32:
+       case XFLOW_PORT_GROUP_SET32:
                err = compat_set_port_group(dp, compat_ptr(argp));
                break;
 
-       case ODP_PORT_GROUP_GET32:
+       case XFLOW_PORT_GROUP_GET32:
                err = compat_get_port_group(dp, compat_ptr(argp));
                break;
 
-       case ODP_FLOW_PUT32:
+       case XFLOW_FLOW_PUT32:
                err = compat_put_flow(dp, compat_ptr(argp));
                break;
 
-       case ODP_FLOW_DEL32:
+       case XFLOW_FLOW_DEL32:
                err = compat_del_flow(dp, compat_ptr(argp));
                break;
 
-       case ODP_FLOW_GET32:
+       case XFLOW_FLOW_GET32:
                err = compat_flowvec_ioctl(dp, argp, compat_query_flows);
                break;
 
-       case ODP_FLOW_LIST32:
+       case XFLOW_FLOW_LIST32:
                err = compat_flowvec_ioctl(dp, argp, compat_list_flows);
                break;
 
-       case ODP_EXECUTE32:
+       case XFLOW_EXECUTE32:
                err = compat_execute(dp, compat_ptr(argp));
                break;
 
index 8e27283..8438e05 100644 (file)
@@ -71,14 +71,14 @@ struct dp_port_group {
  * @waitqueue: Waitqueue, for waiting for new packets in @queues.
  * @n_flows: Number of flows currently in flow table.
  * @table: Current flow table (RCU protected).
- * @groups: Port groups, used by ODPAT_OUTPUT_GROUP action (RCU protected).
+ * @groups: Port groups, used by XFLOWAT_OUTPUT_GROUP action (RCU protected).
  * @n_ports: Number of ports currently in @ports.
- * @ports: Map from port number to &struct dp_port.  %ODPP_LOCAL port
+ * @ports: Map from port number to &struct dp_port.  %XFLOWP_LOCAL port
  * always exists, other ports may be %NULL.
  * @port_list: List of all ports in @ports in arbitrary order.
  * @stats_percpu: Per-CPU datapath statistics.
  * @sflow_probability: Number of packets out of UINT_MAX to sample to the
- * %ODPL_SFLOW queue, e.g. (@sflow_probability/UINT_MAX) is the probability of
+ * %XFLOWL_SFLOW queue, e.g. (@sflow_probability/UINT_MAX) is the probability of
  * sampling a given packet.
  */
 struct datapath {
index e73a731..166582e 100644 (file)
@@ -45,7 +45,7 @@ static int dp_device_event(struct notifier_block *unused, unsigned long event,
                break;
 
        case NETDEV_CHANGENAME:
-               if (p->port_no != ODPP_LOCAL) {
+               if (p->port_no != XFLOWP_LOCAL) {
                        mutex_lock(&dp->mutex);
                        dp_sysfs_del_if(p);
                        dp_sysfs_add_if(p);
index 91dd56f..5e1362c 100644 (file)
@@ -281,7 +281,7 @@ static INTERNAL_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
 static ssize_t show_bridge_id(DEVICE_PARAMS, char *buf)
 {
        struct datapath *dp = sysfs_get_dp(to_net_dev(d));
-       const unsigned char *addr = vport_get_addr(dp->ports[ODPP_LOCAL]->vport);
+       const unsigned char *addr = vport_get_addr(dp->ports[XFLOWP_LOCAL]->vport);
 
        /* xxx Do we need a lock of some sort? */
        return sprintf(buf, "%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x\n",
@@ -469,7 +469,7 @@ static struct attribute_group bridge_group = {
  */
 int dp_sysfs_add_dp(struct datapath *dp)
 {
-       struct kobject *kobj = vport_get_kobj(dp->ports[ODPP_LOCAL]->vport);
+       struct kobject *kobj = vport_get_kobj(dp->ports[XFLOWP_LOCAL]->vport);
        int err;
 
        /* Create /sys/class/net/<devname>/bridge directory. */
@@ -498,7 +498,7 @@ int dp_sysfs_add_dp(struct datapath *dp)
 
 int dp_sysfs_del_dp(struct datapath *dp)
 {
-       struct kobject *kobj = vport_get_kobj(dp->ports[ODPP_LOCAL]->vport);
+       struct kobject *kobj = vport_get_kobj(dp->ports[XFLOWP_LOCAL]->vport);
 
        kobject_del(&dp->ifobj);
        sysfs_remove_group(kobj, &bridge_group);
index e06037c..6414968 100644 (file)
@@ -290,7 +290,7 @@ int dp_sysfs_add_if(struct dp_port *p)
 
        /* Create symlink from /sys/class/net/<devname>/brport/bridge to
         * /sys/class/net/<bridgename>. */
-       err = sysfs_create_link(&p->kobj, vport_get_kobj(dp->ports[ODPP_LOCAL]->vport),
+       err = sysfs_create_link(&p->kobj, vport_get_kobj(dp->ports[XFLOWP_LOCAL]->vport),
                                SYSFS_BRIDGE_PORT_LINK); /* "bridge" */
        if (err)
                goto err_del;
index 548c729..7265350 100644 (file)
@@ -122,10 +122,10 @@ struct sw_flow_actions *flow_actions_alloc(size_t n_actions)
 {
        struct sw_flow_actions *sfa;
 
-       if (n_actions > (PAGE_SIZE - sizeof *sfa) / sizeof(union odp_action))
+       if (n_actions > (PAGE_SIZE - sizeof *sfa) / sizeof(union xflow_action))
                return ERR_PTR(-EINVAL);
 
-       sfa = kmalloc(sizeof *sfa + n_actions * sizeof(union odp_action),
+       sfa = kmalloc(sizeof *sfa + n_actions * sizeof(union xflow_action),
                      GFP_KERNEL);
        if (!sfa)
                return ERR_PTR(-ENOMEM);
@@ -201,7 +201,7 @@ static int is_snap(const struct eth_snap_hdr *esh)
 /* Parses the Ethernet frame in 'skb', which was received on 'in_port',
  * and initializes 'key' to match.  Returns 1 if 'skb' contains an IP
  * fragment, 0 otherwise. */
-int flow_extract(struct sk_buff *skb, u16 in_port, struct odp_flow_key *key)
+int flow_extract(struct sk_buff *skb, u16 in_port, struct xflow_key *key)
 {
        struct ethhdr *eth;
        struct eth_snap_hdr *esh;
@@ -211,7 +211,7 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct odp_flow_key *key)
        memset(key, 0, sizeof *key);
        key->tun_id = OVS_CB(skb)->tun_id;
        key->in_port = in_port;
-       key->dl_vlan = htons(ODP_VLAN_NONE);
+       key->dl_tci = htons(0);
 
        if (skb->len < sizeof *eth)
                return 0;
@@ -223,13 +223,13 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct odp_flow_key *key)
        eth = eth_hdr(skb);
        esh = (struct eth_snap_hdr *) eth;
        nh_ofs = sizeof *eth;
-       if (likely(ntohs(eth->h_proto) >= ODP_DL_TYPE_ETH2_CUTOFF))
+       if (likely(ntohs(eth->h_proto) >= XFLOW_DL_TYPE_ETH2_CUTOFF))
                key->dl_type = eth->h_proto;
        else if (skb->len >= sizeof *esh && is_snap(esh)) {
                key->dl_type = esh->ethertype;
                nh_ofs = sizeof *esh;
        } else {
-               key->dl_type = htons(ODP_DL_TYPE_NOT_ETH_TYPE);
+               key->dl_type = htons(XFLOW_DL_TYPE_NOT_ETH_TYPE);
                if (skb->len >= nh_ofs + sizeof(struct llc_pdu_un)) {
                        nh_ofs += sizeof(struct llc_pdu_un); 
                }
@@ -240,8 +240,7 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct odp_flow_key *key)
            skb->len >= nh_ofs + sizeof(struct vlan_hdr)) {
                struct vlan_hdr *vh = (struct vlan_hdr*)(skb->data + nh_ofs);
                key->dl_type = vh->h_vlan_encapsulated_proto;
-               key->dl_vlan = vh->h_vlan_TCI & htons(VLAN_VID_MASK);
-               key->dl_vlan_pcp = (ntohs(vh->h_vlan_TCI) & VLAN_PCP_MASK) >> VLAN_PCP_SHIFT;
+               key->dl_tci = vh->h_vlan_TCI | htons(XFLOW_TCI_PRESENT);
                nh_ofs += sizeof(struct vlan_hdr);
        }
        memcpy(key->dl_src, eth->h_source, ETH_ALEN);
@@ -332,17 +331,17 @@ struct sw_flow *flow_cast(const struct tbl_node *node)
        return container_of(node, struct sw_flow, tbl_node);
 }
 
-u32 flow_hash(const struct odp_flow_key *key)
+u32 flow_hash(const struct xflow_key *key)
 {
        return jhash2((u32*)key, sizeof *key / sizeof(u32), hash_seed);
 }
 
 int flow_cmp(const struct tbl_node *node, void *key2_)
 {
-       const struct odp_flow_key *key1 = &flow_cast(node)->key;
-       const struct odp_flow_key *key2 = key2_;
+       const struct xflow_key *key1 = &flow_cast(node)->key;
+       const struct xflow_key *key2 = key2_;
 
-       return !memcmp(key1, key2, sizeof(struct odp_flow_key));
+       return !memcmp(key1, key2, sizeof(struct xflow_key));
 }
 
 /* Initializes the flow module.
index 4a393cb..5e2da59 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009 Nicira Networks.
+ * Copyright (c) 2009, 2010 Nicira Networks.
  * Distributed under the terms of the GNU GPL version 2.
  *
  * Significant portions of this file may be copied from parts of the Linux
@@ -15,7 +15,7 @@
 #include <linux/rcupdate.h>
 #include <linux/gfp.h>
 
-#include "openvswitch/datapath-protocol.h"
+#include "openvswitch/xflow.h"
 #include "table.h"
 
 struct sk_buff;
@@ -23,14 +23,14 @@ struct sk_buff;
 struct sw_flow_actions {
        struct rcu_head rcu;
        unsigned int n_actions;
-       union odp_action actions[];
+       union xflow_action actions[];
 };
 
 struct sw_flow {
        struct rcu_head rcu;
        struct tbl_node tbl_node;
 
-       struct odp_flow_key key;
+       struct xflow_key key;
        struct sw_flow_actions *sf_acts;
 
        struct timespec used;   /* Last used time. */
@@ -48,11 +48,11 @@ extern struct kmem_cache *flow_cache;
 struct sw_flow_actions *flow_actions_alloc(size_t n_actions);
 void flow_deferred_free(struct sw_flow *);
 void flow_deferred_free_acts(struct sw_flow_actions *);
-int flow_extract(struct sk_buff *, u16 in_port, struct odp_flow_key *);
+int flow_extract(struct sk_buff *, u16 in_port, struct xflow_key *);
 void flow_used(struct sw_flow *, struct sk_buff *);
 
 struct sw_flow *flow_cast(const struct tbl_node *);
-u32 flow_hash(const struct odp_flow_key *key);
+u32 flow_hash(const struct xflow_key *key);
 int flow_cmp(const struct tbl_node *, void *target);
 void flow_free_tbl(struct tbl_node *);
 
index c63e3ea..13f6751 100644 (file)
@@ -16,6 +16,7 @@ openvswitch_headers += \
        linux-2.6/compat-2.6/include/linux/if.h \
        linux-2.6/compat-2.6/include/linux/if_arp.h \
        linux-2.6/compat-2.6/include/linux/if_ether.h \
+       linux-2.6/compat-2.6/include/linux/if_vlan.h \
        linux-2.6/compat-2.6/include/linux/in.h \
        linux-2.6/compat-2.6/include/linux/inetdevice.h \
        linux-2.6/compat-2.6/include/linux/ip.h \
diff --git a/datapath/linux-2.6/compat-2.6/include/linux/if_vlan.h b/datapath/linux-2.6/compat-2.6/include/linux/if_vlan.h
new file mode 100644 (file)
index 0000000..63d25ae
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __LINUX_IF_VLAN_WRAPPER_H
+#define __LINUX_IF_VLAN_WRAPPER_H 1
+
+#include_next <linux/if_vlan.h>
+
+/* All of these were introduced in a single commit preceding 2.6.33, so
+ * presumably all of them or none of them are present. */
+#ifndef VLAN_PRIO_MASK
+#define VLAN_PRIO_MASK         0xe000 /* Priority Code Point */
+#define VLAN_PRIO_SHIFT                13
+#define VLAN_CFI_MASK          0x1000 /* Canonical Format Indicator */
+#define VLAN_TAG_PRESENT       VLAN_CFI_MASK
+#endif
+
+#endif
diff --git a/datapath/odp-compat.h b/datapath/odp-compat.h
deleted file mode 100644 (file)
index 3d7b803..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (c) 2010 Nicira Networks.
- * Distributed under the terms of the GNU GPL version 2.
- *
- * Significant portions of this file may be copied from parts of the Linux
- * kernel, by Linus Torvalds and others.
- */
-
-#ifndef ODP_COMPAT_H
-#define ODP_COMPAT_H 1
-
-/* 32-bit ioctl compatibility definitions for datapath protocol. */
-
-#ifdef CONFIG_COMPAT
-#include "openvswitch/datapath-protocol.h"
-#include <linux/compat.h>
-
-#define ODP_PORT_LIST32                _IOWR('O', 10, struct compat_odp_portvec)
-#define ODP_PORT_GROUP_SET32   _IOR('O', 11, struct compat_odp_port_group)
-#define ODP_PORT_GROUP_GET32   _IOWR('O', 12, struct compat_odp_port_group)
-#define ODP_FLOW_GET32         _IOWR('O', 13, struct compat_odp_flow)
-#define ODP_FLOW_PUT32         _IOWR('O', 14, struct compat_odp_flow)
-#define ODP_FLOW_LIST32                _IOWR('O', 15, struct compat_odp_flowvec)
-#define ODP_FLOW_DEL32         _IOWR('O', 17, struct compat_odp_flow)
-#define ODP_EXECUTE32          _IOR('O', 18, struct compat_odp_execute)
-#define ODP_FLOW_DEL32         _IOWR('O', 17, struct compat_odp_flow)
-#define ODP_VPORT_ADD32                _IOR('O', 21, struct compat_odp_vport_add)
-#define ODP_VPORT_MOD32                _IOR('O', 22, struct compat_odp_vport_mod)
-
-struct compat_odp_portvec {
-       compat_uptr_t ports;
-       u32 n_ports;
-};
-
-struct compat_odp_port_group {
-       compat_uptr_t ports;
-       u16 n_ports;            /* Number of ports. */
-       u16 group;              /* Group number. */
-};
-
-struct compat_odp_flow {
-       struct odp_flow_stats stats;
-       struct odp_flow_key key;
-       compat_uptr_t actions;
-       u32 n_actions;
-       u32 flags;
-};
-
-struct compat_odp_flow_put {
-       struct compat_odp_flow flow;
-       u32 flags;
-};
-
-struct compat_odp_flowvec {
-       compat_uptr_t flows;
-       u32 n_flows;
-};
-
-struct compat_odp_execute {
-       u16 in_port;
-       u16 reserved1;
-       u32 reserved2;
-
-       compat_uptr_t actions;
-       u32 n_actions;
-
-       compat_uptr_t data;
-       u32 length;
-};
-
-struct compat_odp_vport_add {
-       char port_type[VPORT_TYPE_SIZE];
-       char devname[16];            /* IFNAMSIZ */
-       compat_uptr_t config;
-};
-
-struct compat_odp_vport_mod {
-       char devname[16];            /* IFNAMSIZ */
-       compat_uptr_t config;
-};
-#endif /* CONFIG_COMPAT */
-
-#endif /* odp-compat.h */
index 8cc4421..24fa077 100644 (file)
@@ -249,7 +249,7 @@ netdev_get_kobj(const struct vport *vport)
 }
 
 int
-netdev_get_stats(const struct vport *vport, struct odp_vport_stats *stats)
+netdev_get_stats(const struct vport *vport, struct xflow_vport_stats *stats)
 {
        const struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
        const struct net_device_stats *netdev_stats;
index 19f176c..54a9fbf 100644 (file)
@@ -30,7 +30,7 @@ int netdev_set_addr(struct vport *, const unsigned char *addr);
 const char *netdev_get_name(const struct vport *);
 const unsigned char *netdev_get_addr(const struct vport *);
 struct kobject *netdev_get_kobj(const struct vport *);
-int netdev_get_stats(const struct vport *, struct odp_vport_stats *);
+int netdev_get_stats(const struct vport *, struct xflow_vport_stats *);
 unsigned netdev_get_dev_flags(const struct vport *);
 int netdev_is_running(const struct vport *);
 unsigned char netdev_get_operstate(const struct vport *);
index 691ab84..c7102ed 100644 (file)
@@ -189,7 +189,7 @@ vport_exit(void)
  * locks are held.
  */
 static int
-do_vport_add(struct odp_vport_add *vport_config)
+do_vport_add(struct xflow_vport_add *vport_config)
 {
        struct vport *vport;
        int err = 0;
@@ -219,11 +219,11 @@ out:
 }
 
 int
-vport_add(const struct odp_vport_add __user *uvport_config)
+vport_add(const struct xflow_vport_add __user *uvport_config)
 {
-       struct odp_vport_add vport_config;
+       struct xflow_vport_add vport_config;
 
-       if (copy_from_user(&vport_config, uvport_config, sizeof(struct odp_vport_add)))
+       if (copy_from_user(&vport_config, uvport_config, sizeof(struct xflow_vport_add)))
                return -EFAULT;
 
        return do_vport_add(&vport_config);
@@ -231,12 +231,12 @@ vport_add(const struct odp_vport_add __user *uvport_config)
 
 #ifdef CONFIG_COMPAT
 int
-compat_vport_add(struct compat_odp_vport_add *ucompat)
+compat_vport_add(struct compat_xflow_vport_add *ucompat)
 {
-       struct compat_odp_vport_add compat;
-       struct odp_vport_add vport_config;
+       struct compat_xflow_vport_add compat;
+       struct xflow_vport_add vport_config;
 
-       if (copy_from_user(&compat, ucompat, sizeof(struct compat_odp_vport_add)))
+       if (copy_from_user(&compat, ucompat, sizeof(struct compat_xflow_vport_add)))
                return -EFAULT;
 
        memcpy(vport_config.port_type, compat.port_type, VPORT_TYPE_SIZE);
@@ -257,7 +257,7 @@ compat_vport_add(struct compat_odp_vport_add *ucompat)
  * assumes no locks are held.
  */
 static int
-do_vport_mod(struct odp_vport_mod *vport_config)
+do_vport_mod(struct xflow_vport_mod *vport_config)
 {
        struct vport *vport;
        int err;
@@ -282,11 +282,11 @@ out:
 }
 
 int
-vport_mod(const struct odp_vport_mod __user *uvport_config)
+vport_mod(const struct xflow_vport_mod __user *uvport_config)
 {
-       struct odp_vport_mod vport_config;
+       struct xflow_vport_mod vport_config;
 
-       if (copy_from_user(&vport_config, uvport_config, sizeof(struct odp_vport_mod)))
+       if (copy_from_user(&vport_config, uvport_config, sizeof(struct xflow_vport_mod)))
                return -EFAULT;
 
        return do_vport_mod(&vport_config);
@@ -294,12 +294,12 @@ vport_mod(const struct odp_vport_mod __user *uvport_config)
 
 #ifdef CONFIG_COMPAT
 int
-compat_vport_mod(struct compat_odp_vport_mod *ucompat)
+compat_vport_mod(struct compat_xflow_vport_mod *ucompat)
 {
-       struct compat_odp_vport_mod compat;
-       struct odp_vport_mod vport_config;
+       struct compat_xflow_vport_mod compat;
+       struct xflow_vport_mod vport_config;
 
-       if (copy_from_user(&compat, ucompat, sizeof(struct compat_odp_vport_mod)))
+       if (copy_from_user(&compat, ucompat, sizeof(struct compat_xflow_vport_mod)))
                return -EFAULT;
 
        memcpy(vport_config.devname, compat.devname, IFNAMSIZ);
@@ -381,13 +381,13 @@ out:
  * function is for userspace callers and assumes no locks are held.
  */
 int
-vport_stats_get(struct odp_vport_stats_req __user *ustats_req)
+vport_stats_get(struct xflow_vport_stats_req __user *ustats_req)
 {
-       struct odp_vport_stats_req stats_req;
+       struct xflow_vport_stats_req stats_req;
        struct vport *vport;
        int err;
 
-       if (copy_from_user(&stats_req, ustats_req, sizeof(struct odp_vport_stats_req)))
+       if (copy_from_user(&stats_req, ustats_req, sizeof(struct xflow_vport_stats_req)))
                return -EFAULT;
 
        stats_req.devname[IFNAMSIZ - 1] = '\0';
@@ -408,7 +408,7 @@ vport_stats_get(struct odp_vport_stats_req __user *ustats_req)
        } else if (vport->ops->flags & VPORT_F_GEN_STATS) {
                int i;
 
-               memset(&stats_req.stats, 0, sizeof(struct odp_vport_stats));
+               memset(&stats_req.stats, 0, sizeof(struct xflow_vport_stats));
 
                for_each_possible_cpu(i) {
                        const struct vport_percpu_stats *percpu_stats;
@@ -444,7 +444,7 @@ out:
        vport_unlock();
 
        if (!err)
-               if (copy_to_user(ustats_req, &stats_req, sizeof(struct odp_vport_stats_req)))
+               if (copy_to_user(ustats_req, &stats_req, sizeof(struct xflow_vport_stats_req)))
                        err = -EFAULT;
 
        return err;
@@ -459,13 +459,13 @@ out:
  * userspace callers and assumes no locks are held.
  */
 int
-vport_ether_get(struct odp_vport_ether __user *uvport_ether)
+vport_ether_get(struct xflow_vport_ether __user *uvport_ether)
 {
-       struct odp_vport_ether vport_ether;
+       struct xflow_vport_ether vport_ether;
        struct vport *vport;
        int err = 0;
 
-       if (copy_from_user(&vport_ether, uvport_ether, sizeof(struct odp_vport_ether)))
+       if (copy_from_user(&vport_ether, uvport_ether, sizeof(struct xflow_vport_ether)))
                return -EFAULT;
 
        vport_ether.devname[IFNAMSIZ - 1] = '\0';
@@ -486,7 +486,7 @@ out:
        vport_unlock();
 
        if (!err)
-               if (copy_to_user(uvport_ether, &vport_ether, sizeof(struct odp_vport_ether)))
+               if (copy_to_user(uvport_ether, &vport_ether, sizeof(struct xflow_vport_ether)))
                        err = -EFAULT;
 
        return err;
@@ -503,13 +503,13 @@ out:
  * are held.
  */
 int
-vport_ether_set(struct odp_vport_ether __user *uvport_ether)
+vport_ether_set(struct xflow_vport_ether __user *uvport_ether)
 {
-       struct odp_vport_ether vport_ether;
+       struct xflow_vport_ether vport_ether;
        struct vport *vport;
        int err;
 
-       if (copy_from_user(&vport_ether, uvport_ether, sizeof(struct odp_vport_ether)))
+       if (copy_from_user(&vport_ether, uvport_ether, sizeof(struct xflow_vport_ether)))
                return -EFAULT;
 
        vport_ether.devname[IFNAMSIZ - 1] = '\0';
@@ -540,13 +540,13 @@ out:
  * callers and assumes no locks are held.
  */
 int
-vport_mtu_get(struct odp_vport_mtu __user *uvport_mtu)
+vport_mtu_get(struct xflow_vport_mtu __user *uvport_mtu)
 {
-       struct odp_vport_mtu vport_mtu;
+       struct xflow_vport_mtu vport_mtu;
        struct vport *vport;
        int err = 0;
 
-       if (copy_from_user(&vport_mtu, uvport_mtu, sizeof(struct odp_vport_mtu)))
+       if (copy_from_user(&vport_mtu, uvport_mtu, sizeof(struct xflow_vport_mtu)))
                return -EFAULT;
 
        vport_mtu.devname[IFNAMSIZ - 1] = '\0';
@@ -565,7 +565,7 @@ out:
        vport_unlock();
 
        if (!err)
-               if (copy_to_user(uvport_mtu, &vport_mtu, sizeof(struct odp_vport_mtu)))
+               if (copy_to_user(uvport_mtu, &vport_mtu, sizeof(struct xflow_vport_mtu)))
                        err = -EFAULT;
 
        return err;
@@ -581,13 +581,13 @@ out:
  * for userspace callers and assumes no locks are held.
  */
 int
-vport_mtu_set(struct odp_vport_mtu __user *uvport_mtu)
+vport_mtu_set(struct xflow_vport_mtu __user *uvport_mtu)
 {
-       struct odp_vport_mtu vport_mtu;
+       struct xflow_vport_mtu vport_mtu;
        struct vport *vport;
        int err;
 
-       if (copy_from_user(&vport_mtu, uvport_mtu, sizeof(struct odp_vport_mtu)))
+       if (copy_from_user(&vport_mtu, uvport_mtu, sizeof(struct xflow_vport_mtu)))
                return -EFAULT;
 
        vport_mtu.devname[IFNAMSIZ - 1] = '\0';
@@ -1053,7 +1053,7 @@ vport_get_ifindex(const struct vport *vport)
        if (!dp_port)
                return -EAGAIN;
 
-       return vport_get_ifindex(dp_port->dp->ports[ODPP_LOCAL]->vport);
+       return vport_get_ifindex(dp_port->dp->ports[XFLOWP_LOCAL]->vport);
 }
 
 /**
index a26f232..be9a07b 100644 (file)
@@ -14,8 +14,8 @@
 #include <linux/spinlock.h>
 
 #include "datapath.h"
-#include "openvswitch/datapath-protocol.h"
-#include "odp-compat.h"
+#include "openvswitch/xflow.h"
+#include "xflow-compat.h"
 
 struct vport;
 struct dp_port;
@@ -28,20 +28,20 @@ void vport_unlock(void);
 int vport_init(void);
 void vport_exit(void);
 
-int vport_add(const struct odp_vport_add __user *);
-int vport_mod(const struct odp_vport_mod __user *);
+int vport_add(const struct xflow_vport_add __user *);
+int vport_mod(const struct xflow_vport_mod __user *);
 int vport_del(const char __user *udevname);
 
 #ifdef CONFIG_COMPAT
-int compat_vport_add(struct compat_odp_vport_add __user *);
-int compat_vport_mod(struct compat_odp_vport_mod __user *);
+int compat_vport_add(struct compat_xflow_vport_add __user *);
+int compat_vport_mod(struct compat_xflow_vport_mod __user *);
 #endif
 
-int vport_stats_get(struct odp_vport_stats_req __user *);
-int vport_ether_get(struct odp_vport_ether __user *);
-int vport_ether_set(struct odp_vport_ether __user *);
-int vport_mtu_get(struct odp_vport_mtu __user *);
-int vport_mtu_set(struct odp_vport_mtu __user *);
+int vport_stats_get(struct xflow_vport_stats_req __user *);
+int vport_ether_get(struct xflow_vport_ether __user *);
+int vport_ether_set(struct xflow_vport_ether __user *);
+int vport_mtu_get(struct xflow_vport_mtu __user *);
+int vport_mtu_set(struct xflow_vport_mtu __user *);
 
 struct vport *__vport_add(const char *name, const char *type, const void __user *config);
 int __vport_mod(struct vport *, const void __user *config);
@@ -173,7 +173,7 @@ struct vport_ops {
        const char *(*get_name)(const struct vport *);
        const unsigned char *(*get_addr)(const struct vport *);
        struct kobject *(*get_kobj)(const struct vport *);
-       int (*get_stats)(const struct vport *, struct odp_vport_stats *);
+       int (*get_stats)(const struct vport *, struct xflow_vport_stats *);
 
        unsigned (*get_dev_flags)(const struct vport *);
        int (*is_running)(const struct vport *);
diff --git a/datapath/xflow-compat.h b/datapath/xflow-compat.h
new file mode 100644 (file)
index 0000000..7cffe27
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2010 Nicira Networks.
+ * Distributed under the terms of the GNU GPL version 2.
+ *
+ * Significant portions of this file may be copied from parts of the Linux
+ * kernel, by Linus Torvalds and others.
+ */
+
+#ifndef XFLOW_COMPAT_H
+#define XFLOW_COMPAT_H 1
+
+/* 32-bit ioctl compatibility definitions for datapath protocol. */
+
+#ifdef CONFIG_COMPAT
+#include "openvswitch/datapath-protocol.h"
+#include <linux/compat.h>
+
+#define XFLOW_PORT_LIST32              _IOWR('O', 10, struct compat_xflow_portvec)
+#define XFLOW_PORT_GROUP_SET32 _IOR('O', 11, struct compat_xflow_port_group)
+#define XFLOW_PORT_GROUP_GET32 _IOWR('O', 12, struct compat_xflow_port_group)
+#define XFLOW_FLOW_GET32               _IOWR('O', 13, struct compat_xflow_flow)
+#define XFLOW_FLOW_PUT32               _IOWR('O', 14, struct compat_xflow_flow)
+#define XFLOW_FLOW_LIST32              _IOWR('O', 15, struct compat_xflow_flowvec)
+#define XFLOW_FLOW_DEL32               _IOWR('O', 17, struct compat_xflow_flow)
+#define XFLOW_EXECUTE32                _IOR('O', 18, struct compat_xflow_execute)
+#define XFLOW_FLOW_DEL32               _IOWR('O', 17, struct compat_xflow_flow)
+#define XFLOW_VPORT_ADD32              _IOR('O', 21, struct compat_xflow_vport_add)
+#define XFLOW_VPORT_MOD32              _IOR('O', 22, struct compat_xflow_vport_mod)
+
+struct compat_xflow_portvec {
+       compat_uptr_t ports;
+       u32 n_ports;
+};
+
+struct compat_xflow_port_group {
+       compat_uptr_t ports;
+       u16 n_ports;            /* Number of ports. */
+       u16 group;              /* Group number. */
+};
+
+struct compat_xflow_flow {
+       struct xflow_flow_stats stats;
+       struct xflow_key key;
+       compat_uptr_t actions;
+       u32 n_actions;
+       u32 flags;
+};
+
+struct compat_xflow_flow_put {
+       struct compat_xflow_flow flow;
+       u32 flags;
+};
+
+struct compat_xflow_flowvec {
+       compat_uptr_t flows;
+       u32 n_flows;
+};
+
+struct compat_xflow_execute {
+       u16 in_port;
+       u16 reserved1;
+       u32 reserved2;
+
+       compat_uptr_t actions;
+       u32 n_actions;
+
+       compat_uptr_t data;
+       u32 length;
+};
+
+struct compat_xflow_vport_add {
+       char port_type[VPORT_TYPE_SIZE];
+       char devname[16];            /* IFNAMSIZ */
+       compat_uptr_t config;
+};
+
+struct compat_xflow_vport_mod {
+       char devname[16];            /* IFNAMSIZ */
+       compat_uptr_t config;
+};
+#endif /* CONFIG_COMPAT */
+
+#endif /* xflow-compat.h */
index 3cc83d8..2bdf044 100644 (file)
@@ -2,5 +2,5 @@ noinst_HEADERS += \
        include/openvswitch/gre.h \
        include/openvswitch/brcompat-netlink.h \
        include/openvswitch/internal_dev.h \
-       include/openvswitch/datapath-protocol.h
+       include/openvswitch/xflow.h
 
diff --git a/include/openvswitch/datapath-protocol.h b/include/openvswitch/datapath-protocol.h
deleted file mode 100644 (file)
index 826dc27..0000000
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * Copyright (c) 2009, 2010 Nicira Networks.
- *
- * This file is offered under your choice of two licenses: Apache 2.0 or GNU
- * GPL 2.0 or later.  The permission statements for each of these licenses is
- * given below.  You may license your modifications to this file under either
- * of these licenses or both.  If you wish to license your modifications under
- * only one of these licenses, delete the permission text for the other
- * license.
- *
- * ----------------------------------------------------------------------
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ----------------------------------------------------------------------
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- * ----------------------------------------------------------------------
- */
-
-/* Protocol between userspace and kernel datapath.
- *
- * Be sure to update datapath/odp-compat.h if you change any of the structures
- * in here. */
-
-#ifndef OPENVSWITCH_DATAPATH_PROTOCOL_H
-#define OPENVSWITCH_DATAPATH_PROTOCOL_H 1
-
-#ifdef __KERNEL__
-#include <linux/types.h>
-#else
-#include <sys/types.h>
-#endif
-#include <linux/if_ether.h>
-
-#define ODP_MAX 256             /* Maximum number of datapaths. */
-
-#define ODP_DP_CREATE           _IO('O', 0)
-#define ODP_DP_DESTROY          _IO('O', 1)
-#define ODP_DP_STATS            _IOW('O', 2, struct odp_stats)
-
-#define ODP_GET_DROP_FRAGS      _IOW('O', 3, int)
-#define ODP_SET_DROP_FRAGS      _IOR('O', 4, int)
-
-#define ODP_GET_LISTEN_MASK     _IOW('O', 5, int)
-#define ODP_SET_LISTEN_MASK     _IOR('O', 6, int)
-
-#define ODP_PORT_ATTACH         _IOR('O', 7, struct odp_port)
-#define ODP_PORT_DETACH         _IOR('O', 8, int)
-#define ODP_PORT_QUERY          _IOWR('O', 9, struct odp_port)
-#define ODP_PORT_LIST           _IOWR('O', 10, struct odp_portvec)
-
-#define ODP_PORT_GROUP_SET      _IOR('O', 11, struct odp_port_group)
-#define ODP_PORT_GROUP_GET      _IOWR('O', 12, struct odp_port_group)
-
-#define ODP_FLOW_GET            _IOWR('O', 13, struct odp_flow)
-#define ODP_FLOW_PUT            _IOWR('O', 14, struct odp_flow)
-#define ODP_FLOW_LIST           _IOWR('O', 15, struct odp_flowvec)
-#define ODP_FLOW_FLUSH          _IO('O', 16)
-#define ODP_FLOW_DEL            _IOWR('O', 17, struct odp_flow)
-
-#define ODP_EXECUTE             _IOR('O', 18, struct odp_execute)
-
-#define ODP_SET_SFLOW_PROBABILITY _IOR('O', 19, int)
-#define ODP_GET_SFLOW_PROBABILITY _IOW('O', 20, int)
-
-#define ODP_VPORT_ADD           _IOR('O', 21, struct odp_vport_add)
-#define ODP_VPORT_MOD           _IOR('O', 22, struct odp_vport_mod)
-#define ODP_VPORT_DEL           _IO('O', 23)
-#define ODP_VPORT_STATS_GET     _IOWR('O', 24, struct odp_vport_stats_req)
-#define ODP_VPORT_ETHER_GET     _IOWR('O', 25, struct odp_vport_ether)
-#define ODP_VPORT_ETHER_SET     _IOW('O', 26, struct odp_vport_ether)
-#define ODP_VPORT_MTU_GET       _IOWR('O', 27, struct odp_vport_mtu)
-#define ODP_VPORT_MTU_SET       _IOW('O', 28, struct odp_vport_mtu)
-
-struct odp_stats {
-    /* Flows. */
-    __u32 n_flows;              /* Number of flows in flow table. */
-    __u32 cur_capacity;         /* Current flow table capacity. */
-    __u32 max_capacity;         /* Maximum expansion of flow table capacity. */
-
-    /* Ports. */
-    __u32 n_ports;              /* Current number of ports. */
-    __u32 max_ports;            /* Maximum supported number of ports. */
-    __u16 max_groups;           /* Maximum number of port groups. */
-    __u16 reserved;
-
-    /* Lookups. */
-    __u64 n_frags;               /* Number of dropped IP fragments. */
-    __u64 n_hit;                 /* Number of flow table matches. */
-    __u64 n_missed;              /* Number of flow table misses. */
-    __u64 n_lost;                /* Number of misses not sent to userspace. */
-
-    /* Queues. */
-    __u16 max_miss_queue;       /* Max length of ODPL_MISS queue. */
-    __u16 max_action_queue;     /* Max length of ODPL_ACTION queue. */
-    __u16 max_sflow_queue;      /* Max length of ODPL_SFLOW queue. */
-};
-
-/* 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. */
-#define ODPL_MISS       (1 << _ODPL_MISS_NR)
-#define _ODPL_ACTION_NR 1       /* Packet output to ODPP_CONTROLLER. */
-#define ODPL_ACTION     (1 << _ODPL_ACTION_NR)
-#define _ODPL_SFLOW_NR  2       /* sFlow samples. */
-#define ODPL_SFLOW      (1 << _ODPL_SFLOW_NR)
-#define ODPL_ALL        (ODPL_MISS | ODPL_ACTION | ODPL_SFLOW)
-
-/**
- * struct odp_msg - format of messages read from datapath fd.
- * @type: One of the %_ODPL_* constants.
- * @length: Total length of message, including this header.
- * @port: Port that received the packet embedded in this message.
- * @reserved: Not currently used.  Should be set to 0.
- * @arg: Argument value whose meaning depends on @type.
- *
- * For @type == %_ODPL_MISS_NR, the header is followed by packet data.  The
- * @arg member is the ID (in network byte order) of the tunnel that
- * encapsulated this packet. It is 0 if the packet was not received on a tunnel.
- *
- * For @type == %_ODPL_ACTION_NR, the header is followed by packet data.  The
- * @arg member is copied from the &struct odp_action_controller that caused
- * the &struct odp_msg to be composed.
- *
- * For @type == %_ODPL_SFLOW_NR, the header is followed by &struct
- * odp_sflow_sample_header, then by an array of &union odp_action (the number
- * of which is specified in &struct odp_sflow_sample_header), then by packet
- * data.
- */
-struct odp_msg {
-    __u32 type;
-    __u32 length;
-    __u16 port;
-    __u16 reserved;
-    __u32 arg;
-};
-
-/**
- * struct odp_sflow_sample_header - header added to sFlow sampled packet.
- * @sample_pool: Number of packets that were candidates for sFlow sampling,
- * regardless of whether they were actually chosen and sent down to userspace.
- * @n_actions: Number of "union odp_action"s immediately following this header.
- *
- * This header follows &struct odp_msg when that structure's @type is
- * %_ODPL_SFLOW_NR, and it is itself followed by an array of &union odp_action
- * (the number of which is specified in @n_actions) and then by packet data.
- */
-struct odp_sflow_sample_header {
-    __u32 sample_pool;
-    __u32 n_actions;
-};
-
-#define ODP_PORT_INTERNAL (1 << 0) /* This port is simulated. */
-struct odp_port {
-    char devname[16];           /* IFNAMSIZ */
-    __u16 port;
-    __u16 flags;
-    __u32 reserved2;
-};
-
-struct odp_portvec {
-    struct odp_port *ports;
-    __u32 n_ports;
-};
-
-struct odp_port_group {
-    __u16 *ports;
-    __u16 n_ports;                /* Number of ports. */
-    __u16 group;                  /* Group number. */
-};
-
-struct odp_flow_stats {
-    __u64 n_packets;            /* Number of matched packets. */
-    __u64 n_bytes;              /* Number of matched bytes. */
-    __u64 used_sec;             /* Time last used. */
-    __u32 used_nsec;
-    __u8 tcp_flags;
-    __u8 ip_tos;
-    __u16 error;                /* Used by ODP_FLOW_GET. */
-};
-
-struct odp_flow_key {
-    __be32 tun_id;               /* Encapsulating tunnel ID. */
-    __be32 nw_src;               /* IP source address. */
-    __be32 nw_dst;               /* IP destination address. */
-    __u16  in_port;              /* Input switch port. */
-    __be16 dl_vlan;              /* Input VLAN. */
-    __be16 dl_type;              /* Ethernet frame type. */
-    __be16 tp_src;               /* TCP/UDP source port. */
-    __be16 tp_dst;               /* TCP/UDP destination port. */
-    __u8   dl_src[ETH_ALEN];     /* Ethernet source address. */
-    __u8   dl_dst[ETH_ALEN];     /* Ethernet destination address. */
-    __u8   nw_proto;             /* IP protocol or lower 8 bits of 
-                                    ARP opcode. */
-    __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. */
-#define ODPFF_ZERO_TCP_FLAGS (1 << 0) /* Zero the TCP flags. */
-
-struct odp_flow {
-    struct odp_flow_stats stats;
-    struct odp_flow_key key;
-    union odp_action *actions;
-    __u32 n_actions;
-    __u32 flags;
-};
-
-/* Flags for ODP_FLOW_PUT. */
-#define ODPPF_CREATE        (1 << 0) /* Allow creating a new flow. */
-#define ODPPF_MODIFY        (1 << 1) /* Allow modifying an existing flow. */
-#define ODPPF_ZERO_STATS    (1 << 2) /* Zero the stats of an existing flow. */
-
-/* ODP_FLOW_PUT argument. */
-struct odp_flow_put {
-    struct odp_flow flow;
-    __u32 flags;
-};
-
-struct odp_flowvec {
-    struct odp_flow *flows;
-    __u32 n_flows;
-};
-
-/* The VLAN id is 12 bits, so we can use the entire 16 bits to indicate
- * special conditions.  All ones is used to match that no VLAN id was
- * set. */
-#define ODP_VLAN_NONE      0xffff
-
-/* Action types. */
-#define ODPAT_OUTPUT            0    /* Output to switch port. */
-#define ODPAT_OUTPUT_GROUP      1    /* Output to all ports in group. */
-#define ODPAT_CONTROLLER        2    /* Send copy to controller. */
-#define ODPAT_SET_VLAN_VID      3    /* Set the 802.1q VLAN id. */
-#define ODPAT_SET_VLAN_PCP      4    /* Set the 802.1q priority. */
-#define ODPAT_STRIP_VLAN        5    /* Strip the 802.1q header. */
-#define ODPAT_SET_DL_SRC        6    /* Ethernet source address. */
-#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_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_SET_TUNNEL        13   /* Set the encapsulating tunnel ID. */
-#define ODPAT_N_ACTIONS         14
-
-struct odp_action_output {
-    __u16 type;                  /* ODPAT_OUTPUT. */
-    __u16 port;                  /* Output port. */
-    __u16 reserved1;
-    __u16 reserved2;
-};
-
-struct odp_action_output_group {
-    __u16 type;                 /* ODPAT_OUTPUT_GROUP. */
-    __u16 group;                /* Group number. */
-    __u16 reserved1;
-    __u16 reserved2;
-};
-
-struct odp_action_controller {
-    __u16 type;                 /* ODPAT_OUTPUT_CONTROLLER. */
-    __u16 reserved;
-    __u32 arg;                  /* Copied to struct odp_msg 'arg' member. */
-};
-
-struct odp_action_tunnel {
-    __u16 type;                 /* ODPAT_SET_TUNNEL. */
-    __u16 reserved;
-    __be32 tun_id;              /* Tunnel ID. */
-};
-
-/* Action structure for ODPAT_SET_VLAN_VID. */
-struct odp_action_vlan_vid {
-    __u16 type;                  /* ODPAT_SET_VLAN_VID. */
-    __be16 vlan_vid;             /* VLAN id. */
-    __u16 reserved1;
-    __u16 reserved2;
-};
-
-/* Action structure for ODPAT_SET_VLAN_PCP. */
-struct odp_action_vlan_pcp {
-    __u16 type;                  /* ODPAT_SET_VLAN_PCP. */
-    __u8 vlan_pcp;               /* VLAN priority. */
-    __u8 reserved1;
-    __u16 reserved2;
-    __u16 reserved3;
-};
-
-/* Action structure for ODPAT_SET_DL_SRC/DST. */
-struct odp_action_dl_addr {
-    __u16 type;                  /* ODPAT_SET_DL_SRC/DST. */
-    __u8 dl_addr[ETH_ALEN];      /* Ethernet address. */
-};
-
-/* Action structure for ODPAT_SET_NW_SRC/DST. */
-struct odp_action_nw_addr {
-    __u16 type;                 /* ODPAT_SET_TW_SRC/DST. */
-    __u16 reserved;
-    __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. */
-    __be16 tp_port;              /* TCP/UDP port. */
-    __u16 reserved1;
-    __u16 reserved2;
-};
-
-union odp_action {
-    __u16 type;
-    struct odp_action_output output;
-    struct odp_action_output_group output_group;
-    struct odp_action_controller controller;
-    struct odp_action_tunnel tunnel;
-    struct odp_action_vlan_vid vlan_vid;
-    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;
-};
-
-struct odp_execute {
-    __u16 in_port;
-    __u16 reserved1;
-    __u32 reserved2;
-
-    union odp_action *actions;
-    __u32 n_actions;
-
-    const void *data;
-    __u32 length;
-};
-
-#define VPORT_TYPE_SIZE     16
-struct odp_vport_add {
-    char port_type[VPORT_TYPE_SIZE];
-    char devname[16];            /* IFNAMSIZ */
-    void *config;
-};
-
-struct odp_vport_mod {
-    char devname[16];            /* IFNAMSIZ */
-    void *config;
-};
-
-struct odp_vport_stats {
-    __u64 rx_packets;
-    __u64 tx_packets;
-    __u64 rx_bytes;
-    __u64 tx_bytes;
-    __u64 rx_dropped;
-    __u64 tx_dropped;
-    __u64 rx_errors;
-    __u64 tx_errors;
-    __u64 rx_frame_err;
-    __u64 rx_over_err;
-    __u64 rx_crc_err;
-    __u64 collisions;
-};
-
-struct odp_vport_stats_req {
-    char devname[16];            /* IFNAMSIZ */
-    struct odp_vport_stats stats;
-};
-
-struct odp_vport_ether {
-    char devname[16];            /* IFNAMSIZ */
-    unsigned char ether_addr[ETH_ALEN];
-};
-
-struct odp_vport_mtu {
-    char devname[16];            /* IFNAMSIZ */
-    __u16 mtu;
-};
-
-/* Values below this cutoff are 802.3 packets and the two bytes
- * following MAC addresses are used as a frame length.  Otherwise, the
- * two bytes are used as the Ethernet type.
- */
-#define ODP_DL_TYPE_ETH2_CUTOFF   0x0600
-
-/* Value of dl_type to indicate that the frame does not include an
- * Ethernet type.
- */
-#define ODP_DL_TYPE_NOT_ETH_TYPE  0x05ff
-
-/* The VLAN id is 12-bits, so we can use the entire 16 bits to indicate
- * special conditions.  All ones indicates that no VLAN id was set.
- */
-#define ODP_VLAN_NONE      0xffff
-
-#endif /* openvswitch/datapath-protocol.h */
index 3c5691b..396a67d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
  *
  * This file is offered under your choice of two licenses: Apache 2.0 or GNU
  * GPL 2.0 or later.  The permission statements for each of these licenses is
 #ifndef OPENVSWITCH_GRE_H
 #define OPENVSWITCH_GRE_H 1
 
-#ifdef __KERNEL__
 #include <linux/types.h>
-#else
-#include <sys/types.h>
-#endif
 
 #define GRE_F_IN_CSUM          (1 << 0) /* Require incoming packets to have checksums. */
 #define GRE_F_OUT_CSUM         (1 << 1) /* Checksum outgoing packets. */
diff --git a/include/openvswitch/xflow.h b/include/openvswitch/xflow.h
new file mode 100644 (file)
index 0000000..37a900a
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2009, 2010 Nicira Networks.
+ *
+ * This file is offered under your choice of two licenses: Apache 2.0 or GNU
+ * GPL 2.0 or later.  The permission statements for each of these licenses is
+ * given below.  You may license your modifications to this file under either
+ * of these licenses or both.  If you wish to license your modifications under
+ * only one of these licenses, delete the permission text for the other
+ * license.
+ *
+ * ----------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * ----------------------------------------------------------------------
+ */
+
+/* Protocol between userspace and kernel datapath.
+ *
+ * Be sure to update datapath/xflow-compat.h if you change any of the
+ * structures in here. */
+
+#ifndef XFLOW_H
+#define XFLOW_H 1
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
+#include <linux/if_ether.h>
+
+#define XFLOW_MAX 256             /* Maximum number of datapaths. */
+
+#define XFLOW_DP_CREATE           _IO('O', 0)
+#define XFLOW_DP_DESTROY          _IO('O', 1)
+#define XFLOW_DP_STATS            _IOW('O', 2, struct xflow_stats)
+
+#define XFLOW_GET_DROP_FRAGS      _IOW('O', 3, int)
+#define XFLOW_SET_DROP_FRAGS      _IOR('O', 4, int)
+
+#define XFLOW_GET_LISTEN_MASK     _IOW('O', 5, int)
+#define XFLOW_SET_LISTEN_MASK     _IOR('O', 6, int)
+
+#define XFLOW_PORT_ATTACH         _IOR('O', 7, struct xflow_port)
+#define XFLOW_PORT_DETACH         _IOR('O', 8, int)
+#define XFLOW_PORT_QUERY          _IOWR('O', 9, struct xflow_port)
+#define XFLOW_PORT_LIST           _IOWR('O', 10, struct xflow_portvec)
+
+#define XFLOW_PORT_GROUP_SET      _IOR('O', 11, struct xflow_port_group)
+#define XFLOW_PORT_GROUP_GET      _IOWR('O', 12, struct xflow_port_group)
+
+#define XFLOW_FLOW_GET            _IOWR('O', 13, struct xflow_flow)
+#define XFLOW_FLOW_PUT            _IOWR('O', 14, struct xflow_flow)
+#define XFLOW_FLOW_LIST           _IOWR('O', 15, struct xflow_flowvec)
+#define XFLOW_FLOW_FLUSH          _IO('O', 16)
+#define XFLOW_FLOW_DEL            _IOWR('O', 17, struct xflow_flow)
+
+#define XFLOW_EXECUTE             _IOR('O', 18, struct xflow_execute)
+
+#define XFLOW_SET_SFLOW_PROBABILITY _IOR('O', 19, int)
+#define XFLOW_GET_SFLOW_PROBABILITY _IOW('O', 20, int)
+
+#define XFLOW_VPORT_ADD           _IOR('O', 21, struct xflow_vport_add)
+#define XFLOW_VPORT_MOD           _IOR('O', 22, struct xflow_vport_mod)
+#define XFLOW_VPORT_DEL           _IO('O', 23)
+#define XFLOW_VPORT_STATS_GET     _IOWR('O', 24, struct xflow_vport_stats_req)
+#define XFLOW_VPORT_ETHER_GET     _IOWR('O', 25, struct xflow_vport_ether)
+#define XFLOW_VPORT_ETHER_SET     _IOW('O', 26, struct xflow_vport_ether)
+#define XFLOW_VPORT_MTU_GET       _IOWR('O', 27, struct xflow_vport_mtu)
+#define XFLOW_VPORT_MTU_SET       _IOW('O', 28, struct xflow_vport_mtu)
+
+struct xflow_stats {
+    /* Flows. */
+    __u32 n_flows;              /* Number of flows in flow table. */
+    __u32 cur_capacity;         /* Current flow table capacity. */
+    __u32 max_capacity;         /* Maximum expansion of flow table capacity. */
+
+    /* Ports. */
+    __u32 n_ports;              /* Current number of ports. */
+    __u32 max_ports;            /* Maximum supported number of ports. */
+    __u16 max_groups;           /* Maximum number of port groups. */
+    __u16 reserved;
+
+    /* Lookups. */
+    __u64 n_frags;              /* Number of dropped IP fragments. */
+    __u64 n_hit;                /* Number of flow table matches. */
+    __u64 n_missed;             /* Number of flow table misses. */
+    __u64 n_lost;               /* Number of misses not sent to userspace. */
+
+    /* Queues. */
+    __u16 max_miss_queue;       /* Max length of XFLOWL_MISS queue. */
+    __u16 max_action_queue;     /* Max length of XFLOWL_ACTION queue. */
+    __u16 max_sflow_queue;      /* Max length of XFLOWL_SFLOW queue. */
+};
+
+/* Logical ports. */
+#define XFLOWP_LOCAL      ((__u16)0)
+#define XFLOWP_NONE       ((__u16)-1)
+#define XFLOWP_NORMAL     ((__u16)-2)
+
+/* Listening channels. */
+#define _XFLOWL_MISS_NR   0       /* Packet missed in flow table. */
+#define XFLOWL_MISS       (1 << _XFLOWL_MISS_NR)
+#define _XFLOWL_ACTION_NR 1       /* Packet output to XFLOWP_CONTROLLER. */
+#define XFLOWL_ACTION     (1 << _XFLOWL_ACTION_NR)
+#define _XFLOWL_SFLOW_NR  2       /* sFlow samples. */
+#define XFLOWL_SFLOW      (1 << _XFLOWL_SFLOW_NR)
+#define XFLOWL_ALL        (XFLOWL_MISS | XFLOWL_ACTION | XFLOWL_SFLOW)
+
+/**
+ * struct xflow_msg - format of messages read from datapath fd.
+ * @type: One of the %_XFLOWL_* constants.
+ * @length: Total length of message, including this header.
+ * @port: Port that received the packet embedded in this message.
+ * @reserved: Not currently used.  Should be set to 0.
+ * @arg: Argument value whose meaning depends on @type.
+ *
+ * For @type == %_XFLOWL_MISS_NR, the header is followed by packet data.  The
+ * @arg member is the ID (in network byte order) of the tunnel that
+ * encapsulated this packet. It is 0 if the packet was not received on a tunnel. *
+ * For @type == %_XFLOWL_ACTION_NR, the header is followed by packet data.  The
+ * @arg member is copied from the &struct xflow_action_controller that caused
+ * the &struct xflow_msg to be composed.
+ *
+ * For @type == %_XFLOWL_SFLOW_NR, the header is followed by &struct
+ * xflow_sflow_sample_header, then by an array of &union xflow_action (the
+ * number of which is specified in &struct xflow_sflow_sample_header), then by
+ * packet data.
+ */
+struct xflow_msg {
+    __u32 type;
+    __u32 length;
+    __u16 port;
+    __u16 reserved;
+    __u32 arg;
+};
+
+/**
+ * struct xflow_sflow_sample_header - header added to sFlow sampled packet.
+ * @sample_pool: Number of packets that were candidates for sFlow sampling,
+ * regardless of whether they were actually chosen and sent down to userspace.
+ * @n_actions: Number of "union xflow_action"s immediately following this
+ * header.
+ *
+ * This header follows &struct xflow_msg when that structure's @type is
+ * %_XFLOWL_SFLOW_NR, and it is itself followed by an array of &union
+ * xflow_action (the number of which is specified in @n_actions) and then by
+ * packet data.
+ */
+struct xflow_sflow_sample_header {
+    __u32 sample_pool;
+    __u32 n_actions;
+};
+
+#define XFLOW_PORT_INTERNAL (1 << 0) /* This port is simulated. */
+struct xflow_port {
+    char devname[16];           /* IFNAMSIZ */
+    __u16 port;
+    __u16 flags;
+    __u32 reserved2;
+};
+
+struct xflow_portvec {
+    struct xflow_port *ports;
+    __u32 n_ports;
+};
+
+struct xflow_port_group {
+    __u16 *ports;
+    __u16 n_ports;                /* Number of ports. */
+    __u16 group;                  /* Group number. */
+};
+
+struct xflow_flow_stats {
+    __u64 n_packets;            /* Number of matched packets. */
+    __u64 n_bytes;              /* Number of matched bytes. */
+    __u64 used_sec;             /* Time last used. */
+    __u32 used_nsec;
+    __u8 tcp_flags;
+    __u8 ip_tos;
+    __u16 error;                /* Used by XFLOW_FLOW_GET. */
+};
+
+/*
+ * The datapath protocol adopts the Linux convention for TCI fields: if an
+ * 802.1Q header is present then its TCI value is used verbatim except that the
+ * CFI bit (0x1000) is always set to 1, and all-bits-zero indicates no 802.1Q
+ * header.
+ */
+#define XFLOW_TCI_PRESENT 0x1000  /* CFI bit */
+
+struct xflow_key {
+    __be32 tun_id;               /* Encapsulating tunnel ID. */
+    __be32 nw_src;               /* IP source address. */
+    __be32 nw_dst;               /* IP destination address. */
+    __u16  in_port;              /* Input switch port. */
+    __be16 dl_tci;               /* All zeros if 802.1Q header absent,
+                                  * XFLOW_TCI_PRESENT set if present. */
+    __be16 dl_type;              /* Ethernet frame type. */
+    __be16 tp_src;               /* TCP/UDP source port. */
+    __be16 tp_dst;               /* TCP/UDP destination port. */
+    __u8   dl_src[ETH_ALEN];     /* Ethernet source address. */
+    __u8   dl_dst[ETH_ALEN];     /* Ethernet destination address. */
+    __u8   nw_proto;             /* IP protocol or low 8 bits of ARP opcode. */
+    __u8   nw_tos;               /* IP ToS (DSCP field, 6 bits). */
+};
+
+/* Flags for XFLOW_FLOW. */
+#define XFLOWFF_ZERO_TCP_FLAGS (1 << 0) /* Zero the TCP flags. */
+
+struct xflow_flow {
+    struct xflow_flow_stats stats;
+    struct xflow_key key;
+    union xflow_action *actions;
+    __u32 n_actions;
+    __u32 flags;
+};
+
+/* Flags for XFLOW_FLOW_PUT. */
+#define XFLOWPF_CREATE        (1 << 0) /* Allow creating a new flow. */
+#define XFLOWPF_MODIFY        (1 << 1) /* Allow modifying an existing flow. */
+#define XFLOWPF_ZERO_STATS    (1 << 2) /* Zero the stats of existing flow. */
+
+/* XFLOW_FLOW_PUT argument. */
+struct xflow_flow_put {
+    struct xflow_flow flow;
+    __u32 flags;
+};
+
+struct xflow_flowvec {
+    struct xflow_flow *flows;
+    __u32 n_flows;
+};
+
+/* Action types. */
+#define XFLOWAT_OUTPUT            0  /* Output to switch port. */
+#define XFLOWAT_OUTPUT_GROUP      1  /* Output to all ports in group. */
+#define XFLOWAT_CONTROLLER        2  /* Send copy to controller. */
+#define XFLOWAT_SET_DL_TCI        3  /* Set the 802.1q VLAN VID and/or PCP. */
+#define XFLOWAT_STRIP_VLAN        4  /* Strip the 802.1q header. */
+#define XFLOWAT_SET_DL_SRC        5  /* Ethernet source address. */
+#define XFLOWAT_SET_DL_DST        6  /* Ethernet destination address. */
+#define XFLOWAT_SET_NW_SRC        7  /* IP source address. */
+#define XFLOWAT_SET_NW_DST        8  /* IP destination address. */
+#define XFLOWAT_SET_NW_TOS        9  /* IP ToS/DSCP field (6 bits). */
+#define XFLOWAT_SET_TP_SRC        10 /* TCP/UDP source port. */
+#define XFLOWAT_SET_TP_DST        11 /* TCP/UDP destination port. */
+#define XFLOWAT_SET_TUNNEL        12 /* Set the encapsulating tunnel ID. */
+#define XFLOWAT_N_ACTIONS         13
+
+struct xflow_action_output {
+    __u16 type;                  /* XFLOWAT_OUTPUT. */
+    __u16 port;                  /* Output port. */
+    __u16 reserved1;
+    __u16 reserved2;
+};
+
+struct xflow_action_output_group {
+    __u16 type;                 /* XFLOWAT_OUTPUT_GROUP. */
+    __u16 group;                /* Group number. */
+    __u16 reserved1;
+    __u16 reserved2;
+};
+
+struct xflow_action_controller {
+    __u16 type;                 /* XFLOWAT_OUTPUT_CONTROLLER. */
+    __u16 reserved;
+    __u32 arg;                  /* Copied to struct xflow_msg 'arg' member. */
+};
+
+struct xflow_action_tunnel {
+    __u16 type;                 /* XFLOWAT_SET_TUNNEL. */
+    __u16 reserved;
+    __be32 tun_id;              /* Tunnel ID. */
+};
+
+/* Action structure for XFLOWAT_SET_DL_TCI. */
+struct xflow_action_dl_tci {
+    __u16 type;                  /* XFLOWAT_SET_DL_TCI. */
+    __be16 tci;                  /* New TCI.  Bits not in mask must be zero. */
+    __be16 mask;                 /* 0x0fff to set VID, 0xe000 to set PCP,
+                                    or 0xefff to set both. */
+    __u16 reserved;
+};
+
+/* Action structure for XFLOWAT_SET_DL_SRC/DST. */
+struct xflow_action_dl_addr {
+    __u16 type;                  /* XFLOWAT_SET_DL_SRC/DST. */
+    __u8 dl_addr[ETH_ALEN];      /* Ethernet address. */
+};
+
+/* Action structure for XFLOWAT_SET_NW_SRC/DST. */
+struct xflow_action_nw_addr {
+    __u16 type;                 /* XFLOWAT_SET_TW_SRC/DST. */
+    __u16 reserved;
+    __be32 nw_addr;             /* IP address. */
+};
+
+struct xflow_action_nw_tos {
+    __u16 type;                  /* XFLOWAT_SET_NW_TOS. */
+    __u8 nw_tos;                 /* IP ToS/DSCP field (6 bits). */
+    __u8 reserved1;
+    __u16 reserved2;
+    __u16 reserved3;
+};
+
+/* Action structure for XFLOWAT_SET_TP_SRC/DST. */
+struct xflow_action_tp_port {
+    __u16 type;                  /* XFLOWAT_SET_TP_SRC/DST. */
+    __be16 tp_port;              /* TCP/UDP port. */
+    __u16 reserved1;
+    __u16 reserved2;
+};
+
+union xflow_action {
+    __u16 type;
+    struct xflow_action_output output;
+    struct xflow_action_output_group output_group;
+    struct xflow_action_controller controller;
+    struct xflow_action_tunnel tunnel;
+    struct xflow_action_dl_tci dl_tci;
+    struct xflow_action_dl_addr dl_addr;
+    struct xflow_action_nw_addr nw_addr;
+    struct xflow_action_nw_tos nw_tos;
+    struct xflow_action_tp_port tp_port;
+};
+
+struct xflow_execute {
+    __u16 in_port;
+    __u16 reserved1;
+    __u32 reserved2;
+
+    union xflow_action *actions;
+    __u32 n_actions;
+
+    const void *data;
+    __u32 length;
+};
+
+#define VPORT_TYPE_SIZE     16
+struct xflow_vport_add {
+    char port_type[VPORT_TYPE_SIZE];
+    char devname[16];            /* IFNAMSIZ */
+    void *config;
+};
+
+struct xflow_vport_mod {
+    char devname[16];            /* IFNAMSIZ */
+    void *config;
+};
+
+struct xflow_vport_stats {
+    __u64 rx_packets;
+    __u64 tx_packets;
+    __u64 rx_bytes;
+    __u64 tx_bytes;
+    __u64 rx_dropped;
+    __u64 tx_dropped;
+    __u64 rx_errors;
+    __u64 tx_errors;
+    __u64 rx_frame_err;
+    __u64 rx_over_err;
+    __u64 rx_crc_err;
+    __u64 collisions;
+};
+
+struct xflow_vport_stats_req {
+    char devname[16];            /* IFNAMSIZ */
+    struct xflow_vport_stats stats;
+};
+
+struct xflow_vport_ether {
+    char devname[16];            /* IFNAMSIZ */
+    unsigned char ether_addr[ETH_ALEN];
+};
+
+struct xflow_vport_mtu {
+    char devname[16];            /* IFNAMSIZ */
+    __u16 mtu;
+};
+
+/* Values below this cutoff are 802.3 packets and the two bytes
+ * following MAC addresses are used as a frame length.  Otherwise, the
+ * two bytes are used as the Ethernet type.
+ */
+#define XFLOW_DL_TYPE_ETH2_CUTOFF   0x0600
+
+/* Value of dl_type to indicate that the frame does not include an
+ * Ethernet type.
+ */
+#define XFLOW_DL_TYPE_NOT_ETH_TYPE  0x05ff
+
+#endif /* openvswitch/xflow.h */
index 5667538..a6c9f61 100644 (file)
@@ -21,9 +21,9 @@ lib_libopenvswitch_a_SOURCES = \
        lib/command-line.c \
        lib/command-line.h \
        lib/compiler.h \
+       lib/coverage-counters.h \
        lib/coverage.c \
        lib/coverage.h \
-       lib/coverage-counters.h \
        lib/csum.c \
        lib/csum.h \
        lib/daemon.c \
@@ -34,11 +34,6 @@ lib_libopenvswitch_a_SOURCES = \
        lib/dhcp.h \
        lib/dhparams.h \
        lib/dirs.h \
-       lib/dpif-linux.c \
-       lib/dpif-netdev.c \
-       lib/dpif-provider.h \
-       lib/dpif.c \
-       lib/dpif.h \
        lib/dynamic-string.c \
        lib/dynamic-string.h \
        lib/fatal-signal.c \
@@ -68,8 +63,6 @@ lib_libopenvswitch_a_SOURCES = \
        lib/netdev-provider.h \
        lib/netdev.c \
        lib/netdev.h \
-       lib/odp-util.c \
-       lib/odp-util.h \
        lib/ofp-print.c \
        lib/ofp-print.h \
        lib/ofpbuf.c \
@@ -151,6 +144,13 @@ lib_libopenvswitch_a_SOURCES = \
        lib/vlog-modules.def \
        lib/vlog.c \
        lib/vlog.h \
+       lib/xfif-linux.c \
+       lib/xfif-netdev.c \
+       lib/xfif-provider.h \
+       lib/xfif.c \
+       lib/xfif.h \
+       lib/xflow-util.c \
+       lib/xflow-util.h \
        lib/xtoxll.h
 nodist_lib_libopenvswitch_a_SOURCES = \
        lib/coverage-counters.c \
@@ -196,25 +196,24 @@ EXTRA_DIST += \
        lib/dhparams.h
 
 EXTRA_DIST += \
-       lib/common.man \
        lib/common-syn.man \
-       lib/daemon.man \
+       lib/common.man \
        lib/daemon-syn.man \
-       lib/dpif.man \
+       lib/daemon.man \
        lib/leak-checker.man \
-       lib/ssl-bootstrap.man \
        lib/ssl-bootstrap-syn.man \
+       lib/ssl-bootstrap.man \
        lib/ssl-peer-ca-cert.man \
-       lib/ssl.man \
        lib/ssl-syn.man \
+       lib/ssl.man \
        lib/unixctl.man \
        lib/unixctl-syn.man \
        lib/vconn-active.man \
        lib/vconn-passive.man \
-       lib/vlog-unixctl.man \
        lib/vlog-syn.man \
-       lib/vlog.man
-
+       lib/vlog-unixctl.man \
+       lib/vlog.man \
+       lib/xfif.man
 
 lib/dirs.c: Makefile
        ($(ro_c) && \
@@ -231,15 +230,13 @@ install-data-local:
 
 # All the source files that have coverage counters.
 COVERAGE_FILES = \
-       lib/dpif.c \
        lib/flow.c \
-       lib/lockfile.c \
        lib/hmap.c \
+       lib/lockfile.c \
        lib/mac-learning.c \
-       lib/netdev.c \
        lib/netdev-linux.c \
+       lib/netdev.c \
        lib/netlink.c \
-       lib/odp-util.c \
        lib/poll-loop.c \
        lib/process.c \
        lib/rconn.c \
@@ -249,8 +246,12 @@ COVERAGE_FILES = \
        lib/unixctl.c \
        lib/util.c \
        lib/vconn.c \
+       lib/xfif.c \
+       lib/xflow-util.c \
        ofproto/ofproto.c \
        ofproto/pktbuf.c \
+       ofproto/wdp.c \
+       ofproto/wdp-xflow.c \
        vswitchd/bridge.c \
        vswitchd/ovs-brcompatd.c
 lib/coverage-counters.c: $(COVERAGE_FILES) lib/coverage-scan.pl
index 4bd8942..1aadfe5 100644 (file)
@@ -52,17 +52,16 @@ static bool rules_match_1wild(const struct cls_rule *fixed,
 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'.*/
+/* Converts the flow in 'flow' into a cls_rule in 'rule'. */
 void
-cls_rule_from_flow(const flow_t *flow, uint32_t wildcards,
-                   unsigned int priority, struct cls_rule *rule)
+cls_rule_from_flow(const flow_t *flow, struct cls_rule *rule)
 {
-    assert(!flow->reserved[0] && !flow->reserved[1] && !flow->reserved[2]);
     rule->flow = *flow;
-    flow_wildcards_init(&rule->wc, wildcards);
-    rule->priority = priority;
-    rule->table_idx = table_idx_from_wildcards(rule->wc.wildcards);
+    if (!rule->flow.wildcards && rule->flow.priority < UINT16_MAX) {
+        rule->flow.priority = UINT16_MAX;
+    }
+    flow_wildcards_init(&rule->wc, flow->wildcards);
+    rule->table_idx = table_idx_from_wildcards(flow->wildcards);
 }
 
 /* Converts the ofp_match in 'match' into a cls_rule in 'rule', with the given
@@ -73,11 +72,10 @@ cls_rule_from_match(const struct ofp_match *match, unsigned int priority,
                     bool tun_id_from_cookie, uint64_t cookie,
                     struct cls_rule *rule)
 {
-    uint32_t wildcards;
-    flow_from_match(match, tun_id_from_cookie, cookie, &rule->flow, &wildcards);
-    flow_wildcards_init(&rule->wc, wildcards);
-    rule->priority = rule->wc.wildcards ? priority : UINT16_MAX;
-    rule->table_idx = table_idx_from_wildcards(rule->wc.wildcards);
+    flow_from_match(match, rule->flow.wildcards ? priority : UINT16_MAX,
+                    tun_id_from_cookie, cookie, &rule->flow);
+    flow_wildcards_init(&rule->wc, rule->flow.wildcards);
+    rule->table_idx = table_idx_from_wildcards(rule->flow.wildcards);
 }
 
 /* Converts 'rule' to a string and returns the string.  The caller must free
@@ -87,7 +85,7 @@ 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);
+                  rule->flow.wildcards, rule->flow.priority);
     flow_format(&s, &rule->flow);
     return ds_cstr(&s);
 }
@@ -99,7 +97,8 @@ cls_rule_to_string(const struct cls_rule *rule)
 void
 cls_rule_print(const struct cls_rule *rule)
 {
-    printf("wildcards=%x priority=%u ", rule->wc.wildcards, rule->priority);
+    printf("wildcards=%x priority=%u ",
+           rule->flow.wildcards, rule->flow.priority);
     flow_print(stdout, &rule->flow);
     putc('\n', stdout);
 }
@@ -116,7 +115,7 @@ cls_rule_moved(struct classifier *cls, struct cls_rule *old,
                struct cls_rule *new)
 {
     if (old != new) {
-        if (new->wc.wildcards) {
+        if (new->flow.wildcards) {
             list_moved(&new->node.list);
         } else {
             hmap_node_moved(&cls->exact_table,
@@ -143,10 +142,10 @@ cls_rule_replace(struct classifier *cls, const struct cls_rule *old,
                  struct cls_rule *new)
 {
     assert(old != new);
-    assert(old->wc.wildcards == new->wc.wildcards);
-    assert(old->priority == new->priority);
+    assert(old->flow.wildcards == new->flow.wildcards);
+    assert(old->flow.priority == new->flow.priority);
 
-    if (new->wc.wildcards) {
+    if (new->flow.wildcards) {
         list_replace(&new->node.list, &old->node.list);
     } else {
         hmap_replace(&cls->exact_table, &old->node.hmap, &new->node.hmap);
@@ -209,6 +208,14 @@ classifier_count_exact(const struct classifier *cls)
     return hmap_count(&cls->exact_table);
 }
 
+/* Returns the number of rules in 'classifier' that have at least one
+ * wildcard. */
+int
+classifier_count_wild(const struct classifier *cls)
+{
+    return classifier_count(cls) - classifier_count_exact(cls);
+}
+
 /* Inserts 'rule' into 'cls'.  Transfers ownership of 'rule' to 'cls'.
  *
  * If 'cls' already contains an identical rule (including wildcards, values of
@@ -224,8 +231,8 @@ struct cls_rule *
 classifier_insert(struct classifier *cls, struct cls_rule *rule)
 {
     struct cls_rule *old;
-    assert((rule->wc.wildcards == 0) == (rule->table_idx == CLS_F_IDX_EXACT));
-    old = (rule->wc.wildcards
+    assert((rule->flow.wildcards == 0) == (rule->table_idx == CLS_F_IDX_EXACT));
+    old = (rule->flow.wildcards
            ? table_insert(&cls->tables[rule->table_idx], rule)
            : insert_exact_rule(cls, rule));
     if (!old) {
@@ -236,7 +243,7 @@ classifier_insert(struct classifier *cls, struct cls_rule *rule)
 
 /* Inserts 'rule' into 'cls'.  Transfers ownership of 'rule' to 'cls'.
  *
- * 'rule' must be an exact-match rule (rule->wc.wildcards must be 0) and 'cls'
+ * 'rule' must be an exact-match rule (rule->flow.wildcards must be 0) and 'cls'
  * must not contain any rule with an identical key. */
 void
 classifier_insert_exact(struct classifier *cls, struct cls_rule *rule)
@@ -251,7 +258,7 @@ classifier_insert_exact(struct classifier *cls, struct cls_rule *rule)
 void
 classifier_remove(struct classifier *cls, struct cls_rule *rule)
 {
-    if (rule->wc.wildcards) {
+    if (rule->flow.wildcards) {
         /* Remove 'rule' from bucket.  If that empties the bucket, remove the
          * bucket from its table. */
         struct hmap *table = &cls->tables[rule->table_idx];
@@ -307,10 +314,10 @@ classifier_lookup_wild(const struct classifier *cls, const flow_t *flow)
         struct cls_rule target;
         int i;
 
-        cls_rule_from_flow(flow, 0, 0, &target);
+        cls_rule_from_flow(flow, &target);
         for (i = 0; i < CLS_N_FIELDS; i++) {
             struct cls_rule *rule = search_table(&cls->tables[i], i, &target);
-            if (rule && (!best || rule->priority > best->priority)) {
+            if (rule && (!best || rule->flow.priority > best->flow.priority)) {
                 best = rule;
             }
         }
@@ -320,30 +327,29 @@ classifier_lookup_wild(const struct classifier *cls, const flow_t *flow)
 
 struct cls_rule *
 classifier_find_rule_exactly(const struct classifier *cls,
-                             const flow_t *target, uint32_t wildcards,
-                             unsigned int priority)
+                             const flow_t *target)
 {
     struct cls_bucket *bucket;
     int table_idx;
     uint32_t hash;
 
-    if (!wildcards) {
+    if (!target->wildcards) {
         /* Ignores 'priority'. */
         return search_exact_table(cls, flow_hash(target, 0), target);
     }
 
-    assert(wildcards == (wildcards & OVSFW_ALL));
-    table_idx = table_idx_from_wildcards(wildcards);
+    assert(target->wildcards == (target->wildcards & OVSFW_ALL));
+    table_idx = table_idx_from_wildcards(target->wildcards);
     hash = hash_fields(target, table_idx);
     HMAP_FOR_EACH_WITH_HASH (bucket, struct cls_bucket, hmap_node, hash,
                              &cls->tables[table_idx]) {
         if (equal_fields(&bucket->fixed, target, table_idx)) {
             struct cls_rule *pos;
             LIST_FOR_EACH (pos, struct cls_rule, node.list, &bucket->rules) {
-                if (pos->priority < priority) {
+                if (pos->flow.priority < target->priority) {
                     return NULL;
-                } else if (pos->priority == priority &&
-                           pos->wc.wildcards == wildcards &&
+                } else if (pos->flow.priority == target->priority &&
+                           pos->flow.wildcards == target->wildcards &&
                            flow_equal(target, &pos->flow)) {
                     return pos;
                 }
@@ -353,23 +359,21 @@ classifier_find_rule_exactly(const struct classifier *cls,
     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. */
+/* Checks if the flow defined by 'target' 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)
+classifier_rule_overlaps(const struct classifier *cls, const flow_t *target)
 {
     struct cls_rule target_rule;
     const struct hmap *tbl;
 
-    if (!wildcards) {
+    if (!target->wildcards) {
         return search_exact_table(cls, flow_hash(target, 0), target) ?
             true : false;
     }
 
-    cls_rule_from_flow(target, wildcards, priority, &target_rule);
+    cls_rule_from_flow(target, &target_rule);
 
     for (tbl = &cls->tables[0]; tbl < &cls->tables[CLS_N_FIELDS]; tbl++) {
         struct cls_bucket *bucket;
@@ -379,7 +383,7 @@ classifier_rule_overlaps(const struct classifier *cls,
 
             LIST_FOR_EACH (rule, struct cls_rule, node.list,
                            &bucket->rules) {
-                if (rule->priority == priority 
+                if (rule->flow.priority == target->priority 
                         && rules_match_2wild(rule, &target_rule, 0)) {
                     return true;
                 }
@@ -390,7 +394,7 @@ classifier_rule_overlaps(const struct classifier *cls,
     return false;
 }
 
-/* Ignores target->priority.
+/* Ignores target->flow.priority.
  *
  * 'callback' is allowed to delete the rule that is passed as its argument, but
  * it must not delete (or move) any other rules in 'cls' that are in the same
@@ -399,9 +403,12 @@ classifier_rule_overlaps(const struct classifier *cls,
  * wildcards and an exact-match rule will never be in the same table. */
 void
 classifier_for_each_match(const struct classifier *cls,
-                          const struct cls_rule *target,
+                          const flow_t *target_flow,
                           int include, cls_cb_func *callback, void *aux)
 {
+    struct cls_rule target;
+
+    cls_rule_from_flow(target_flow, &target);
     if (include & CLS_INC_WILD) {
         const struct hmap *table;
 
@@ -424,7 +431,7 @@ classifier_for_each_match(const struct classifier *cls,
                 prev_rule = NULL;
                 LIST_FOR_EACH (rule, struct cls_rule, node.list,
                                &bucket->rules) {
-                    if (rules_match_1wild(rule, target, 0)) {
+                    if (rules_match_1wild(rule, &target, 0)) {
                         if (prev_rule) {
                             callback(prev_rule, aux);
                         }
@@ -439,21 +446,21 @@ classifier_for_each_match(const struct classifier *cls,
     }
 
     if (include & CLS_INC_EXACT) {
-        if (target->wc.wildcards) {
+        if (target.flow.wildcards) {
             struct cls_rule *rule, *next_rule;
 
             HMAP_FOR_EACH_SAFE (rule, next_rule, struct cls_rule, node.hmap,
                                 &cls->exact_table) {
-                if (rules_match_1wild(rule, target, 0)) {
+                if (rules_match_1wild(rule, &target, 0)) {
                     callback(rule, aux);
                 }
             }
         } else {
             /* Optimization: there can be at most one match in the exact
              * table. */
-            size_t hash = flow_hash(&target->flow, 0);
+            size_t hash = flow_hash(&target.flow, 0);
             struct cls_rule *rule = search_exact_table(cls, hash,
-                                                       &target->flow);
+                                                       &target.flow);
             if (rule) {
                 callback(rule, aux);
             }
@@ -642,14 +649,14 @@ bucket_insert(struct cls_bucket *bucket, struct cls_rule *rule)
 {
     struct cls_rule *pos;
     LIST_FOR_EACH (pos, struct cls_rule, node.list, &bucket->rules) {
-        if (pos->priority == rule->priority) {
-            if (pos->wc.wildcards == rule->wc.wildcards
+        if (pos->flow.priority == rule->flow.priority) {
+            if (pos->flow.wildcards == rule->flow.wildcards
                 && rules_match_1wild(pos, rule, rule->table_idx))
             {
                 list_replace(&rule->node.list, &pos->node.list);
                 return pos;
             }
-        } else if (pos->priority < rule->priority) {
+        } else if (pos->flow.priority < rule->flow.priority) {
             break;
         }
     }
@@ -814,7 +821,7 @@ static bool
 rules_match_1wild(const struct cls_rule *fixed, const struct cls_rule *wild,
                   int field_idx)
 {
-    return rules_match(fixed, wild, wild->wc.wildcards, wild->wc.nw_src_mask,
+    return rules_match(fixed, wild, wild->flow.wildcards, wild->wc.nw_src_mask,
                        wild->wc.nw_dst_mask, field_idx);
 }
 
@@ -829,7 +836,7 @@ 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->flow.wildcards | wild2->flow.wildcards, 
                        wild1->wc.nw_src_mask & wild2->wc.nw_src_mask,
                        wild1->wc.nw_dst_mask & wild2->wc.nw_dst_mask, 
                        field_idx);
index 3551602..b515bf5 100644 (file)
 #include "openflow/nicira-ext.h"
 #include "openflow/openflow.h"
 
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
 /* Number of bytes of fields in a rule. */
 #define CLS_N_BYTES 37
 
@@ -119,27 +123,26 @@ struct cls_rule {
     } node;
     flow_t flow;                /* All field values. */
     struct flow_wildcards wc;   /* Wildcards for fields. */
-    unsigned int priority;      /* Larger numbers are higher priorities. */
     unsigned int table_idx;     /* Index into struct classifier 'tables'. */
 };
 
-void cls_rule_from_flow(const flow_t *, uint32_t wildcards,
-                        unsigned int priority, struct cls_rule *);
+void cls_rule_from_flow(const flow_t *, struct cls_rule *);
 void cls_rule_from_match(const struct ofp_match *, unsigned int priority,
                          bool tun_id_from_cookie, uint64_t cookie,
                          struct cls_rule *);
 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);
-void cls_rule_replace(struct classifier *, const struct cls_rule *old,
-                      struct cls_rule *new);
+                    struct cls_rule *old_rule, struct cls_rule *new_rule);
+void cls_rule_replace(struct classifier *, const struct cls_rule *old_rule,
+                      struct cls_rule *new_rule);
 
 void classifier_init(struct classifier *);
 void classifier_destroy(struct classifier *);
 bool classifier_is_empty(const struct classifier *);
 int classifier_count(const struct classifier *);
 int classifier_count_exact(const struct classifier *);
+int classifier_count_wild(const struct classifier *);
 struct cls_rule *classifier_insert(struct classifier *, struct cls_rule *);
 void classifier_insert_exact(struct classifier *, struct cls_rule *);
 void classifier_remove(struct classifier *, struct cls_rule *);
@@ -148,8 +151,7 @@ struct cls_rule *classifier_lookup_wild(const struct classifier *,
                                         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);
+bool classifier_rule_overlaps(const struct classifier *, const flow_t *);
 
 typedef void cls_cb_func(struct cls_rule *, void *aux);
 
@@ -160,12 +162,13 @@ enum {
 };
 void classifier_for_each(const struct classifier *, int include,
                          cls_cb_func *, void *aux);
-void classifier_for_each_match(const struct classifier *,
-                               const struct cls_rule *,
+void classifier_for_each_match(const struct classifier *, const flow_t *,
                                int include, cls_cb_func *, void *aux);
 struct cls_rule *classifier_find_rule_exactly(const struct classifier *,
-                                              const flow_t *target,
-                                              uint32_t wildcards,
-                                              unsigned int priority);
+                                              const flow_t *target);
+
+#ifdef  __cplusplus
+}
+#endif
 
 #endif /* classifier.h */
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
deleted file mode 100644 (file)
index 2f4463e..0000000
+++ /dev/null
@@ -1,1394 +0,0 @@
-/*
- * 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.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <config.h>
-#include "dpif.h"
-
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <netinet/in.h>
-#include <net/if.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "csum.h"
-#include "dpif-provider.h"
-#include "flow.h"
-#include "hmap.h"
-#include "list.h"
-#include "netdev.h"
-#include "odp-util.h"
-#include "ofp-print.h"
-#include "ofpbuf.h"
-#include "packets.h"
-#include "poll-loop.h"
-#include "queue.h"
-#include "timeval.h"
-#include "util.h"
-
-#include "vlog.h"
-#define THIS_MODULE VLM_dpif_netdev
-
-/* Configuration parameters. */
-enum { N_QUEUES = 2 };          /* Number of queues for dpif_recv(). */
-enum { MAX_QUEUE_LEN = 100 };   /* Maximum number of packets per queue. */
-enum { N_GROUPS = 16 };         /* Number of port groups. */
-enum { MAX_PORTS = 256 };       /* Maximum number of ports. */
-enum { MAX_FLOWS = 65536 };     /* Maximum number of flows in flow table. */
-
-/* Enough headroom to add a vlan tag, plus an extra 2 bytes to allow IP
- * headers to be aligned on a 4-byte boundary.  */
-enum { DP_NETDEV_HEADROOM = 2 + VLAN_HEADER_LEN };
-
-/* Datapath based on the network device interface from netdev.h. */
-struct dp_netdev {
-    struct list node;
-    int dp_idx;
-    int open_cnt;
-    bool destroyed;
-
-    bool drop_frags;            /* Drop all IP fragments, if true. */
-    struct ovs_queue queues[N_QUEUES]; /* Messages queued for dpif_recv(). */
-    struct hmap flow_table;     /* Flow table. */
-    struct odp_port_group groups[N_GROUPS];
-
-    /* Statistics. */
-    long long int n_frags;      /* Number of dropped IP fragments. */
-    long long int n_hit;        /* Number of flow table matches. */
-    long long int n_missed;     /* Number of flow table misses. */
-    long long int n_lost;       /* Number of misses not passed to client. */
-
-    /* Ports. */
-    int n_ports;
-    struct dp_netdev_port *ports[MAX_PORTS];
-    struct list port_list;
-    unsigned int serial;
-};
-
-/* A port in a netdev-based datapath. */
-struct dp_netdev_port {
-    int port_no;                /* Index into dp_netdev's 'ports'. */
-    struct list node;           /* Element in dp_netdev's 'port_list'. */
-    struct netdev *netdev;
-    bool internal;              /* Internal port (as ODP_PORT_INTERNAL)? */
-};
-
-/* A flow in dp_netdev's 'flow_table'. */
-struct dp_netdev_flow {
-    struct hmap_node node;      /* Element in dp_netdev's 'flow_table'. */
-    flow_t key;
-
-    /* Statistics. */
-       struct timeval used;        /* Last used time, in milliseconds. */
-       long long int packet_count; /* Number of packets matched. */
-       long long int byte_count;   /* Number of bytes matched. */
-       uint8_t ip_tos;             /* IP TOS value. */
-       uint16_t tcp_ctl;           /* Bitwise-OR of seen tcp_ctl values. */
-
-    /* Actions. */
-    union odp_action *actions;
-    unsigned int n_actions;
-};
-
-/* Interface to netdev-based datapath. */
-struct dpif_netdev {
-    struct dpif dpif;
-    struct dp_netdev *dp;
-    int listen_mask;
-    unsigned int dp_serial;
-};
-
-/* All netdev-based datapaths. */
-static struct dp_netdev *dp_netdevs[256];
-struct list dp_netdev_list = LIST_INITIALIZER(&dp_netdev_list);
-enum { N_DP_NETDEVS = ARRAY_SIZE(dp_netdevs) };
-
-/* Maximum port MTU seen so far. */
-static int max_mtu = ETH_PAYLOAD_MAX;
-
-static int get_port_by_number(struct dp_netdev *, uint16_t port_no,
-                              struct dp_netdev_port **portp);
-static int get_port_by_name(struct dp_netdev *, const char *devname,
-                            struct dp_netdev_port **portp);
-static void dp_netdev_free(struct dp_netdev *);
-static void dp_netdev_flow_flush(struct dp_netdev *);
-static int do_add_port(struct dp_netdev *, const char *devname, uint16_t flags,
-                       uint16_t port_no);
-static int do_del_port(struct dp_netdev *, uint16_t port_no);
-static int dp_netdev_output_control(struct dp_netdev *, const struct ofpbuf *,
-                                    int queue_no, int port_no, uint32_t arg);
-static int dp_netdev_execute_actions(struct dp_netdev *,
-                                     struct ofpbuf *, flow_t *,
-                                     const union odp_action *, int n);
-
-static struct dpif_netdev *
-dpif_netdev_cast(const struct dpif *dpif)
-{
-    dpif_assert_class(dpif, &dpif_netdev_class);
-    return CONTAINER_OF(dpif, struct dpif_netdev, dpif);
-}
-
-static struct dp_netdev *
-get_dp_netdev(const struct dpif *dpif)
-{
-    return dpif_netdev_cast(dpif)->dp;
-}
-
-static int
-name_to_dp_idx(const char *name)
-{
-    if (!strncmp(name, "dp", 2) && isdigit((unsigned char)name[2])) {
-        int dp_idx = atoi(name + 2);
-        if (dp_idx >= 0 && dp_idx < N_DP_NETDEVS) {
-            return dp_idx;
-        }
-    }
-    return -1;
-}
-
-static struct dp_netdev *
-find_dp_netdev(const char *name)
-{
-    int dp_idx;
-    size_t i;
-
-    dp_idx = name_to_dp_idx(name);
-    if (dp_idx >= 0) {
-        return dp_netdevs[dp_idx];
-    }
-
-    for (i = 0; i < N_DP_NETDEVS; i++) {
-        struct dp_netdev *dp = dp_netdevs[i];
-        if (dp) {
-            struct dp_netdev_port *port;
-            if (!get_port_by_name(dp, name, &port)) {
-                return dp;
-            }
-        }
-    }
-    return NULL;
-}
-
-static struct dpif *
-create_dpif_netdev(struct dp_netdev *dp)
-{
-    struct dpif_netdev *dpif;
-    char *dpname;
-
-    dp->open_cnt++;
-
-    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;
-    dpif->listen_mask = 0;
-    dpif->dp_serial = dp->serial;
-    free(dpname);
-
-    return &dpif->dpif;
-}
-
-static int
-create_dp_netdev(const char *name, int dp_idx, struct dpif **dpifp)
-{
-    struct dp_netdev *dp;
-    int error;
-    int i;
-
-    if (dp_netdevs[dp_idx]) {
-        return EBUSY;
-    }
-
-    /* Create datapath. */
-    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;
-    dp->drop_frags = false;
-    for (i = 0; i < N_QUEUES; i++) {
-        queue_init(&dp->queues[i]);
-    }
-    hmap_init(&dp->flow_table);
-    for (i = 0; i < N_GROUPS; i++) {
-        dp->groups[i].ports = NULL;
-        dp->groups[i].n_ports = 0;
-        dp->groups[i].group = i;
-    }
-    list_init(&dp->port_list);
-    error = do_add_port(dp, name, ODP_PORT_INTERNAL, ODPP_LOCAL);
-    if (error) {
-        dp_netdev_free(dp);
-        return ENODEV;
-    }
-
-    *dpifp = create_dpif_netdev(dp);
-    return 0;
-}
-
-static int
-dpif_netdev_open(const char *name, const char *type OVS_UNUSED, bool create,
-                 struct dpif **dpifp)
-{
-    if (create) {
-        if (find_dp_netdev(name)) {
-            return EEXIST;
-        } else {
-            int dp_idx = name_to_dp_idx(name);
-            if (dp_idx >= 0) {
-                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(name, dp_idx, dpifp);
-                    if (error != EBUSY) {
-                        return error;
-                    }
-                }
-
-                /* All datapath numbers in use. */
-                return ENOBUFS;
-            }
-        }
-    } else {
-        struct dp_netdev *dp = find_dp_netdev(name);
-        if (dp) {
-            *dpifp = create_dpif_netdev(dp);
-            return 0;
-        } else {
-            return ENODEV;
-        }
-    }
-}
-
-static void
-dp_netdev_free(struct dp_netdev *dp)
-{
-    int i;
-
-    dp_netdev_flow_flush(dp);
-    while (dp->n_ports > 0) {
-        struct dp_netdev_port *port = CONTAINER_OF(
-            dp->port_list.next, struct dp_netdev_port, node);
-        do_del_port(dp, port->port_no);
-    }
-    for (i = 0; i < N_QUEUES; i++) {
-        queue_destroy(&dp->queues[i]);
-    }
-    hmap_destroy(&dp->flow_table);
-    for (i = 0; i < N_GROUPS; i++) {
-        free(dp->groups[i].ports);
-    }
-    dp_netdevs[dp->dp_idx] = NULL;
-    list_remove(&dp->node);
-    free(dp);
-}
-
-static void
-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->destroyed) {
-        dp_netdev_free(dp);
-    }
-    free(dpif);
-}
-
-static int
-dpif_netdev_destroy(struct dpif *dpif)
-{
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-    dp->destroyed = true;
-    return 0;
-}
-
-static int
-dpif_netdev_get_stats(const struct dpif *dpif, struct odp_stats *stats)
-{
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-    memset(stats, 0, sizeof *stats);
-    stats->n_flows = hmap_count(&dp->flow_table);
-    stats->cur_capacity = hmap_capacity(&dp->flow_table);
-    stats->max_capacity = MAX_FLOWS;
-    stats->n_ports = dp->n_ports;
-    stats->max_ports = MAX_PORTS;
-    stats->max_groups = N_GROUPS;
-    stats->n_frags = dp->n_frags;
-    stats->n_hit = dp->n_hit;
-    stats->n_missed = dp->n_missed;
-    stats->n_lost = dp->n_lost;
-    stats->max_miss_queue = MAX_QUEUE_LEN;
-    stats->max_action_queue = MAX_QUEUE_LEN;
-    return 0;
-}
-
-static int
-dpif_netdev_get_drop_frags(const struct dpif *dpif, bool *drop_fragsp)
-{
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-    *drop_fragsp = dp->drop_frags;
-    return 0;
-}
-
-static int
-dpif_netdev_set_drop_frags(struct dpif *dpif, bool drop_frags)
-{
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-    dp->drop_frags = drop_frags;
-    return 0;
-}
-
-static int
-do_add_port(struct dp_netdev *dp, const char *devname, uint16_t flags,
-            uint16_t port_no)
-{
-    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. */
-    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 {
-        netdev_options.may_open = true;
-    }
-
-    error = netdev_open(&netdev_options, &netdev);
-    if (error) {
-        return error;
-    }
-    /* XXX reject loopback devices */
-    /* XXX reject non-Ethernet devices */
-
-    error = netdev_turn_flags_on(netdev, NETDEV_PROMISC, false);
-    if (error) {
-        netdev_close(netdev);
-        return error;
-    }
-
-    port = xmalloc(sizeof *port);
-    port->port_no = port_no;
-    port->netdev = netdev;
-    port->internal = internal;
-
-    netdev_get_mtu(netdev, &mtu);
-    if (mtu > max_mtu) {
-        max_mtu = mtu;
-    }
-
-    list_push_back(&dp->port_list, &port->node);
-    dp->ports[port_no] = port;
-    dp->n_ports++;
-    dp->serial++;
-
-    return 0;
-}
-
-static int
-dpif_netdev_port_add(struct dpif *dpif, const char *devname, uint16_t flags,
-                     uint16_t *port_nop)
-{
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-    int port_no;
-
-    for (port_no = 0; port_no < MAX_PORTS; port_no++) {
-        if (!dp->ports[port_no]) {
-            *port_nop = port_no;
-            return do_add_port(dp, devname, flags, port_no);
-        }
-    }
-    return EFBIG;
-}
-
-static int
-dpif_netdev_port_del(struct dpif *dpif, uint16_t port_no)
-{
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-    return port_no == ODPP_LOCAL ? EINVAL : do_del_port(dp, port_no);
-}
-
-static bool
-is_valid_port_number(uint16_t port_no)
-{
-    return port_no < MAX_PORTS;
-}
-
-static int
-get_port_by_number(struct dp_netdev *dp,
-                   uint16_t port_no, struct dp_netdev_port **portp)
-{
-    if (!is_valid_port_number(port_no)) {
-        *portp = NULL;
-        return EINVAL;
-    } else {
-        *portp = dp->ports[port_no];
-        return *portp ? 0 : ENOENT;
-    }
-}
-
-static int
-get_port_by_name(struct dp_netdev *dp,
-                 const char *devname, struct dp_netdev_port **portp)
-{
-    struct dp_netdev_port *port;
-
-    LIST_FOR_EACH (port, struct dp_netdev_port, node, &dp->port_list) {
-        if (!strcmp(netdev_get_name(port->netdev), devname)) {
-            *portp = port;
-            return 0;
-        }
-    }
-    return ENOENT;
-}
-
-static int
-do_del_port(struct dp_netdev *dp, uint16_t port_no)
-{
-    struct dp_netdev_port *port;
-    char *name;
-    int error;
-
-    error = get_port_by_number(dp, port_no, &port);
-    if (error) {
-        return error;
-    }
-
-    list_remove(&port->node);
-    dp->ports[port->port_no] = NULL;
-    dp->n_ports--;
-    dp->serial++;
-
-    name = xstrdup(netdev_get_name(port->netdev));
-    netdev_close(port->netdev);
-
-    free(name);
-    free(port);
-
-    return 0;
-}
-
-static void
-answer_port_query(const struct dp_netdev_port *port, struct odp_port *odp_port)
-{
-    memset(odp_port, 0, sizeof *odp_port);
-    ovs_strlcpy(odp_port->devname, netdev_get_name(port->netdev),
-                sizeof odp_port->devname);
-    odp_port->port = port->port_no;
-    odp_port->flags = port->internal ? ODP_PORT_INTERNAL : 0;
-}
-
-static int
-dpif_netdev_port_query_by_number(const struct dpif *dpif, uint16_t port_no,
-                                 struct odp_port *odp_port)
-{
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-    struct dp_netdev_port *port;
-    int error;
-
-    error = get_port_by_number(dp, port_no, &port);
-    if (!error) {
-        answer_port_query(port, odp_port);
-    }
-    return error;
-}
-
-static int
-dpif_netdev_port_query_by_name(const struct dpif *dpif, const char *devname,
-                               struct odp_port *odp_port)
-{
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-    struct dp_netdev_port *port;
-    int error;
-
-    error = get_port_by_name(dp, devname, &port);
-    if (!error) {
-        answer_port_query(port, odp_port);
-    }
-    return error;
-}
-
-static void
-dp_netdev_free_flow(struct dp_netdev *dp, struct dp_netdev_flow *flow)
-{
-    hmap_remove(&dp->flow_table, &flow->node);
-    free(flow->actions);
-    free(flow);
-}
-
-static void
-dp_netdev_flow_flush(struct dp_netdev *dp)
-{
-    struct dp_netdev_flow *flow, *next;
-
-    HMAP_FOR_EACH_SAFE (flow, next, struct dp_netdev_flow, node,
-                        &dp->flow_table) {
-        dp_netdev_free_flow(dp, flow);
-    }
-}
-
-static int
-dpif_netdev_flow_flush(struct dpif *dpif)
-{
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-    dp_netdev_flow_flush(dp);
-    return 0;
-}
-
-static int
-dpif_netdev_port_list(const struct dpif *dpif, struct odp_port *ports, int n)
-{
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-    struct dp_netdev_port *port;
-    int i;
-
-    i = 0;
-    LIST_FOR_EACH (port, struct dp_netdev_port, node, &dp->port_list) {
-        struct odp_port *odp_port = &ports[i];
-        if (i >= n) {
-            break;
-        }
-        answer_port_query(port, odp_port);
-        i++;
-    }
-    return dp->n_ports;
-}
-
-static int
-dpif_netdev_port_poll(const struct dpif *dpif_, char **devnamep OVS_UNUSED)
-{
-    struct dpif_netdev *dpif = dpif_netdev_cast(dpif_);
-    if (dpif->dp_serial != dpif->dp->serial) {
-        dpif->dp_serial = dpif->dp->serial;
-        return ENOBUFS;
-    } else {
-        return EAGAIN;
-    }
-}
-
-static void
-dpif_netdev_port_poll_wait(const struct dpif *dpif_)
-{
-    struct dpif_netdev *dpif = dpif_netdev_cast(dpif_);
-    if (dpif->dp_serial != dpif->dp->serial) {
-        poll_immediate_wake();
-    }
-}
-
-static int
-get_port_group(const struct dpif *dpif, int group_no,
-               struct odp_port_group **groupp)
-{
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-
-    if (group_no >= 0 && group_no < N_GROUPS) {
-        *groupp = &dp->groups[group_no];
-        return 0;
-    } else {
-        *groupp = NULL;
-        return EINVAL;
-    }
-}
-
-static int
-dpif_netdev_port_group_get(const struct dpif *dpif, int group_no,
-                           uint16_t ports[], int n)
-{
-    struct odp_port_group *group;
-    int error;
-
-    if (n < 0) {
-        return -EINVAL;
-    }
-
-    error = get_port_group(dpif, group_no, &group);
-    if (!error) {
-        memcpy(ports, group->ports, MIN(n, group->n_ports) * sizeof *ports);
-        return group->n_ports;
-    } else {
-        return -error;
-    }
-}
-
-static int
-dpif_netdev_port_group_set(struct dpif *dpif, int group_no,
-                           const uint16_t ports[], int n)
-{
-    struct odp_port_group *group;
-    int error;
-
-    if (n < 0 || n > MAX_PORTS) {
-        return EINVAL;
-    }
-
-    error = get_port_group(dpif, group_no, &group);
-    if (!error) {
-        free(group->ports);
-        group->ports = xmemdup(ports, n * sizeof *group->ports);
-        group->n_ports = n;
-        group->group = group_no;
-    }
-    return error;
-}
-
-static struct dp_netdev_flow *
-dp_netdev_lookup_flow(const struct dp_netdev *dp, const flow_t *key)
-{
-    struct dp_netdev_flow *flow;
-
-    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)) {
-            return flow;
-        }
-    }
-    return NULL;
-}
-
-static void
-answer_flow_query(struct dp_netdev_flow *flow, uint32_t query_flags,
-                  struct odp_flow *odp_flow)
-{
-    if (flow) {
-        odp_flow->key = flow->key;
-        odp_flow->stats.n_packets = flow->packet_count;
-        odp_flow->stats.n_bytes = flow->byte_count;
-        odp_flow->stats.used_sec = flow->used.tv_sec;
-        odp_flow->stats.used_nsec = flow->used.tv_usec * 1000;
-        odp_flow->stats.tcp_flags = TCP_FLAGS(flow->tcp_ctl);
-        odp_flow->stats.ip_tos = flow->ip_tos;
-        odp_flow->stats.error = 0;
-        if (odp_flow->n_actions > 0) {
-            unsigned int n = MIN(odp_flow->n_actions, flow->n_actions);
-            memcpy(odp_flow->actions, flow->actions,
-                   n * sizeof *odp_flow->actions);
-            odp_flow->n_actions = flow->n_actions;
-        }
-
-        if (query_flags & ODPFF_ZERO_TCP_FLAGS) {
-            flow->tcp_ctl = 0;
-        }
-
-    } else {
-        odp_flow->stats.error = ENOENT;
-    }
-}
-
-static int
-dpif_netdev_flow_get(const struct dpif *dpif, struct odp_flow flows[], int n)
-{
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-    int i;
-
-    for (i = 0; i < n; i++) {
-        struct odp_flow *odp_flow = &flows[i];
-        answer_flow_query(dp_netdev_lookup_flow(dp, &odp_flow->key),
-                          odp_flow->flags, odp_flow);
-    }
-    return 0;
-}
-
-static int
-dpif_netdev_validate_actions(const union odp_action *actions, int n_actions,
-                             bool *mutates)
-{
-    unsigned int i;
-
-    *mutates = false;
-    for (i = 0; i < n_actions; i++) {
-        const union odp_action *a = &actions[i];
-        switch (a->type) {
-        case ODPAT_OUTPUT:
-            if (a->output.port >= MAX_PORTS) {
-                return EINVAL;
-            }
-            break;
-
-        case ODPAT_OUTPUT_GROUP:
-            *mutates = true;
-            if (a->output_group.group >= N_GROUPS) {
-                return EINVAL;
-            }
-            break;
-
-        case ODPAT_CONTROLLER:
-            break;
-
-        case ODPAT_SET_VLAN_VID:
-            *mutates = true;
-            if (a->vlan_vid.vlan_vid & htons(~VLAN_VID_MASK)) {
-                return EINVAL;
-            }
-            break;
-
-        case ODPAT_SET_VLAN_PCP:
-            *mutates = true;
-            if (a->vlan_pcp.vlan_pcp & ~(VLAN_PCP_MASK >> VLAN_PCP_SHIFT)) {
-                return EINVAL;
-            }
-            break;
-
-        case ODPAT_SET_NW_TOS:
-            *mutates = true;
-            if (a->nw_tos.nw_tos & IP_ECN_MASK) {
-                return EINVAL;
-            }
-            break;
-
-        case ODPAT_STRIP_VLAN:
-        case ODPAT_SET_DL_SRC:
-        case ODPAT_SET_DL_DST:
-        case ODPAT_SET_NW_SRC:
-        case ODPAT_SET_NW_DST:
-        case ODPAT_SET_TP_SRC:
-        case ODPAT_SET_TP_DST:
-            *mutates = true;
-            break;
-
-        default:
-            return EOPNOTSUPP;
-        }
-    }
-    return 0;
-}
-
-static int
-set_flow_actions(struct dp_netdev_flow *flow, struct odp_flow *odp_flow)
-{
-    size_t n_bytes;
-    bool mutates;
-    int error;
-
-    if (odp_flow->n_actions >= 4096 / sizeof *odp_flow->actions) {
-        return EINVAL;
-    }
-    error = dpif_netdev_validate_actions(odp_flow->actions,
-                                         odp_flow->n_actions, &mutates);
-    if (error) {
-        return error;
-    }
-
-    n_bytes = odp_flow->n_actions * sizeof *flow->actions;
-    flow->actions = xrealloc(flow->actions, n_bytes);
-    flow->n_actions = odp_flow->n_actions;
-    memcpy(flow->actions, odp_flow->actions, n_bytes);
-    return 0;
-}
-
-static int
-add_flow(struct dpif *dpif, struct odp_flow *odp_flow)
-{
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-    struct dp_netdev_flow *flow;
-    int error;
-
-    flow = xzalloc(sizeof *flow);
-    flow->key = odp_flow->key;
-    memset(flow->key.reserved, 0, sizeof flow->key.reserved);
-
-    error = set_flow_actions(flow, odp_flow);
-    if (error) {
-        free(flow);
-        return error;
-    }
-
-    hmap_insert(&dp->flow_table, &flow->node, flow_hash(&flow->key, 0));
-    return 0;
-}
-
-static void
-clear_stats(struct dp_netdev_flow *flow)
-{
-    flow->used.tv_sec = 0;
-    flow->used.tv_usec = 0;
-    flow->packet_count = 0;
-    flow->byte_count = 0;
-    flow->ip_tos = 0;
-    flow->tcp_ctl = 0;
-}
-
-static int
-dpif_netdev_flow_put(struct dpif *dpif, struct odp_flow_put *put)
-{
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-    struct dp_netdev_flow *flow;
-
-    flow = dp_netdev_lookup_flow(dp, &put->flow.key);
-    if (!flow) {
-        if (put->flags & ODPPF_CREATE) {
-            if (hmap_count(&dp->flow_table) < MAX_FLOWS) {
-                return add_flow(dpif, &put->flow);
-            } else {
-                return EFBIG;
-            }
-        } else {
-            return ENOENT;
-        }
-    } else {
-        if (put->flags & ODPPF_MODIFY) {
-            int error = set_flow_actions(flow, &put->flow);
-            if (!error && put->flags & ODPPF_ZERO_STATS) {
-                clear_stats(flow);
-            }
-            return error;
-        } else {
-            return EEXIST;
-        }
-    }
-}
-
-
-static int
-dpif_netdev_flow_del(struct dpif *dpif, struct odp_flow *odp_flow)
-{
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-    struct dp_netdev_flow *flow;
-
-    flow = dp_netdev_lookup_flow(dp, &odp_flow->key);
-    if (flow) {
-        answer_flow_query(flow, 0, odp_flow);
-        dp_netdev_free_flow(dp, flow);
-        return 0;
-    } else {
-        return ENOENT;
-    }
-}
-
-static int
-dpif_netdev_flow_list(const struct dpif *dpif, struct odp_flow flows[], int n)
-{
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-    struct dp_netdev_flow *flow;
-    int i;
-
-    i = 0;
-    HMAP_FOR_EACH (flow, struct dp_netdev_flow, node, &dp->flow_table) {
-        if (i >= n) {
-            break;
-        }
-        answer_flow_query(flow, 0, &flows[i++]);
-    }
-    return hmap_count(&dp->flow_table);
-}
-
-static int
-dpif_netdev_execute(struct dpif *dpif, uint16_t in_port,
-                    const union odp_action actions[], int n_actions,
-                    const struct ofpbuf *packet)
-{
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-    struct ofpbuf copy;
-    bool mutates;
-    flow_t flow;
-    int error;
-
-    if (packet->size < ETH_HEADER_LEN || packet->size > UINT16_MAX) {
-        return EINVAL;
-    }
-
-    error = dpif_netdev_validate_actions(actions, n_actions, &mutates);
-    if (error) {
-        return error;
-    }
-
-    if (mutates) {
-        /* We need a deep copy of 'packet' since we're going to modify its
-         * data. */
-        ofpbuf_init(&copy, DP_NETDEV_HEADROOM + packet->size);
-        copy.data = (char*)copy.base + DP_NETDEV_HEADROOM;
-        ofpbuf_put(&copy, packet->data, packet->size);
-    } else {
-        /* We still need a shallow copy of 'packet', even though we won't
-         * modify its data, because flow_extract() modifies packet->l2, etc.
-         * We could probably get away with modifying those but it's more polite
-         * if we don't. */
-        copy = *packet;
-    }
-    flow_extract(&copy, 0, in_port, &flow);
-    error = dp_netdev_execute_actions(dp, &copy, &flow, actions, n_actions);
-    if (mutates) {
-        ofpbuf_uninit(&copy);
-    }
-    return error;
-}
-
-static int
-dpif_netdev_recv_get_mask(const struct dpif *dpif, int *listen_mask)
-{
-    struct dpif_netdev *dpif_netdev = dpif_netdev_cast(dpif);
-    *listen_mask = dpif_netdev->listen_mask;
-    return 0;
-}
-
-static int
-dpif_netdev_recv_set_mask(struct dpif *dpif, int listen_mask)
-{
-    struct dpif_netdev *dpif_netdev = dpif_netdev_cast(dpif);
-    if (!(listen_mask & ~ODPL_ALL)) {
-        dpif_netdev->listen_mask = listen_mask;
-        return 0;
-    } else {
-        return EINVAL;
-    }
-}
-
-static struct ovs_queue *
-find_nonempty_queue(struct dpif *dpif)
-{
-    struct dpif_netdev *dpif_netdev = dpif_netdev_cast(dpif);
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-    int mask = dpif_netdev->listen_mask;
-    int i;
-
-    for (i = 0; i < N_QUEUES; i++) {
-        struct ovs_queue *q = &dp->queues[i];
-        if (q->n && mask & (1u << i)) {
-            return q;
-        }
-    }
-    return NULL;
-}
-
-static int
-dpif_netdev_recv(struct dpif *dpif, struct ofpbuf **bufp)
-{
-    struct ovs_queue *q = find_nonempty_queue(dpif);
-    if (q) {
-        *bufp = queue_pop_head(q);
-        return 0;
-    } else {
-        return EAGAIN;
-    }
-}
-
-static void
-dpif_netdev_recv_wait(struct dpif *dpif)
-{
-    struct ovs_queue *q = find_nonempty_queue(dpif);
-    if (q) {
-        poll_immediate_wake();
-    } else {
-        /* No messages ready to be received, and dp_wait() will ensure that we
-         * wake up to queue new messages, so there is nothing to do. */
-    }
-}
-\f
-static void
-dp_netdev_flow_used(struct dp_netdev_flow *flow, const flow_t *key,
-                    const struct ofpbuf *packet)
-{
-    time_timeval(&flow->used);
-    flow->packet_count++;
-    flow->byte_count += packet->size;
-    if (key->dl_type == htons(ETH_TYPE_IP)) {
-        struct ip_header *nh = packet->l3;
-        flow->ip_tos = nh->ip_tos;
-
-        if (key->nw_proto == IPPROTO_TCP) {
-            struct tcp_header *th = packet->l4;
-            flow->tcp_ctl |= th->tcp_ctl;
-        }
-    }
-}
-
-static void
-dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port,
-                     struct ofpbuf *packet)
-{
-    struct dp_netdev_flow *flow;
-    flow_t key;
-
-    if (flow_extract(packet, 0, port->port_no, &key) && dp->drop_frags) {
-        dp->n_frags++;
-        return;
-    }
-
-    flow = dp_netdev_lookup_flow(dp, &key);
-    if (flow) {
-        dp_netdev_flow_used(flow, &key, packet);
-        dp_netdev_execute_actions(dp, packet, &key,
-                                  flow->actions, flow->n_actions);
-        dp->n_hit++;
-    } else {
-        dp->n_missed++;
-        dp_netdev_output_control(dp, packet, _ODPL_MISS_NR, port->port_no, 0);
-    }
-}
-
-static void
-dp_netdev_run(void)
-{
-    struct ofpbuf packet;
-    struct dp_netdev *dp;
-
-    ofpbuf_init(&packet, DP_NETDEV_HEADROOM + max_mtu);
-    LIST_FOR_EACH (dp, struct dp_netdev, node, &dp_netdev_list) {
-        struct dp_netdev_port *port;
-
-        LIST_FOR_EACH (port, struct dp_netdev_port, node, &dp->port_list) {
-            int error;
-
-            /* Reset packet contents. */
-            packet.data = (char*)packet.base + DP_NETDEV_HEADROOM;
-            packet.size = 0;
-
-            error = netdev_recv(port->netdev, &packet);
-            if (!error) {
-                dp_netdev_port_input(dp, port, &packet);
-            } else if (error != EAGAIN) {
-                struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
-                VLOG_ERR_RL(&rl, "error receiving data from %s: %s",
-                            netdev_get_name(port->netdev), strerror(error));
-            }
-        }
-    }
-    ofpbuf_uninit(&packet);
-}
-
-static void
-dp_netdev_wait(void)
-{
-    struct dp_netdev *dp;
-
-    LIST_FOR_EACH (dp, struct dp_netdev, node, &dp_netdev_list) {
-        struct dp_netdev_port *port;
-        LIST_FOR_EACH (port, struct dp_netdev_port, node, &dp->port_list) {
-            netdev_recv_wait(port->netdev);
-        }
-    }
-}
-
-
-/* Modify the TCI field of 'packet'.  If a VLAN tag is not present, one
- * is added with the TCI field set to 'tci'.  If a VLAN tag is present, 
- * then 'mask' bits are cleared before 'tci' is logically OR'd into the
- * TCI field.
- *
- * Note that the function does not ensure that 'tci' does not affect
- * bits outside of 'mask'.
- */
-static void
-dp_netdev_modify_vlan_tci(struct ofpbuf *packet, flow_t *key,
-                          uint16_t tci, uint16_t mask)
-{
-    struct vlan_eth_header *veh;
-
-    if (key->dl_vlan != htons(ODP_VLAN_NONE)) {
-        /* Clear 'mask' bits, but maintain other TCI bits. */
-        veh = packet->l2;
-        veh->veth_tci &= ~htons(mask);
-        veh->veth_tci |= htons(tci);
-    } else {
-        /* Insert new 802.1Q header. */
-        struct eth_header *eh = packet->l2;
-        struct vlan_eth_header tmp;
-        memcpy(tmp.veth_dst, eh->eth_dst, ETH_ADDR_LEN);
-        memcpy(tmp.veth_src, eh->eth_src, ETH_ADDR_LEN);
-        tmp.veth_type = htons(ETH_TYPE_VLAN);
-        tmp.veth_tci = htons(tci);
-        tmp.veth_next_type = eh->eth_type;
-
-        veh = ofpbuf_push_uninit(packet, VLAN_HEADER_LEN);
-        memcpy(veh, &tmp, sizeof tmp);
-        packet->l2 = (char*)packet->l2 - VLAN_HEADER_LEN;
-    }
-
-    key->dl_vlan = veh->veth_tci & htons(VLAN_VID_MASK);
-}
-
-static void
-dp_netdev_strip_vlan(struct ofpbuf *packet, flow_t *key)
-{
-    struct vlan_eth_header *veh = packet->l2;
-    if (veh->veth_type == htons(ETH_TYPE_VLAN)) {
-        struct eth_header tmp;
-
-        memcpy(tmp.eth_dst, veh->veth_dst, ETH_ADDR_LEN);
-        memcpy(tmp.eth_src, veh->veth_src, ETH_ADDR_LEN);
-        tmp.eth_type = veh->veth_next_type;
-
-        packet->size -= VLAN_HEADER_LEN;
-        packet->data = (char*)packet->data + VLAN_HEADER_LEN;
-        packet->l2 = (char*)packet->l2 + VLAN_HEADER_LEN;
-        memcpy(packet->data, &tmp, sizeof tmp);
-
-        key->dl_vlan = htons(ODP_VLAN_NONE);
-    }
-}
-
-static void
-dp_netdev_set_dl_src(struct ofpbuf *packet, flow_t *key,
-                     const uint8_t dl_addr[ETH_ADDR_LEN])
-{
-    struct eth_header *eh = packet->l2;
-    memcpy(eh->eth_src, dl_addr, sizeof eh->eth_src);
-    memcpy(key->dl_src, dl_addr, sizeof key->dl_src);
-}
-
-static void
-dp_netdev_set_dl_dst(struct ofpbuf *packet, flow_t *key,
-                     const uint8_t dl_addr[ETH_ADDR_LEN])
-{
-    struct eth_header *eh = packet->l2;
-    memcpy(eh->eth_dst, dl_addr, sizeof eh->eth_dst);
-    memcpy(key->dl_dst, dl_addr, sizeof key->dl_dst);
-}
-
-static void
-dp_netdev_set_nw_addr(struct ofpbuf *packet, flow_t *key,
-                      const struct odp_action_nw_addr *a)
-{
-    if (key->dl_type == htons(ETH_TYPE_IP)) {
-        struct ip_header *nh = packet->l3;
-        uint32_t *field;
-
-        field = a->type == ODPAT_SET_NW_SRC ? &nh->ip_src : &nh->ip_dst;
-        if (key->nw_proto == IP_TYPE_TCP) {
-            struct tcp_header *th = packet->l4;
-            th->tcp_csum = recalc_csum32(th->tcp_csum, *field, a->nw_addr);
-        } else if (key->nw_proto == IP_TYPE_UDP) {
-            struct udp_header *uh = packet->l4;
-            if (uh->udp_csum) {
-                uh->udp_csum = recalc_csum32(uh->udp_csum, *field, a->nw_addr);
-                if (!uh->udp_csum) {
-                    uh->udp_csum = 0xffff;
-                }
-            }
-        }
-        nh->ip_csum = recalc_csum32(nh->ip_csum, *field, a->nw_addr);
-        *field = a->nw_addr;
-
-        if (a->type == ODPAT_SET_NW_SRC) {
-            key->nw_src = a->type;
-        } else {
-            key->nw_dst = a->type;
-        }
-    }
-}
-
-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 | (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;
-        key->nw_tos = a->nw_tos;
-    }
-}
-
-static void
-dp_netdev_set_tp_port(struct ofpbuf *packet, flow_t *key,
-                      const struct odp_action_tp_port *a)
-{
-       if (key->dl_type == htons(ETH_TYPE_IP)) {
-        uint16_t *field;
-        if (key->nw_proto == IPPROTO_TCP) {
-            struct tcp_header *th = packet->l4;
-            field = a->type == ODPAT_SET_TP_SRC ? &th->tcp_src : &th->tcp_dst;
-            th->tcp_csum = recalc_csum16(th->tcp_csum, *field, a->tp_port);
-            *field = a->tp_port;
-        } else if (key->nw_proto == IPPROTO_UDP) {
-            struct udp_header *uh = packet->l4;
-            field = a->type == ODPAT_SET_TP_SRC ? &uh->udp_src : &uh->udp_dst;
-            uh->udp_csum = recalc_csum16(uh->udp_csum, *field, a->tp_port);
-            *field = a->tp_port;
-        } else {
-            return;
-        }
-
-        if (a->type == ODPAT_SET_TP_SRC) {
-            key->tp_src = a->tp_port;
-        } else {
-            key->tp_dst = a->tp_port;
-        }
-    }
-}
-
-static void
-dp_netdev_output_port(struct dp_netdev *dp, struct ofpbuf *packet,
-                      uint16_t out_port)
-{
-       struct dp_netdev_port *p = dp->ports[out_port];
-    if (p) {
-        netdev_send(p->netdev, packet);
-    }
-}
-
-static void
-dp_netdev_output_group(struct dp_netdev *dp, uint16_t group, uint16_t in_port,
-                       struct ofpbuf *packet)
-{
-       struct odp_port_group *g = &dp->groups[group];
-       int i;
-
-       for (i = 0; i < g->n_ports; i++) {
-        uint16_t out_port = g->ports[i];
-        if (out_port != in_port) {
-            dp_netdev_output_port(dp, packet, out_port);
-        }
-       }
-}
-
-static int
-dp_netdev_output_control(struct dp_netdev *dp, const struct ofpbuf *packet,
-                         int queue_no, int port_no, uint32_t arg)
-{
-    struct ovs_queue *q = &dp->queues[queue_no];
-    struct odp_msg *header;
-    struct ofpbuf *msg;
-    size_t msg_size;
-
-    if (q->n >= MAX_QUEUE_LEN) {
-        dp->n_lost++;
-        return ENOBUFS;
-    }
-
-    msg_size = sizeof *header + packet->size;
-    msg = ofpbuf_new(msg_size + DPIF_RECV_MSG_PADDING);
-    ofpbuf_reserve(msg, DPIF_RECV_MSG_PADDING);
-    header = ofpbuf_put_uninit(msg, sizeof *header);
-    header->type = queue_no;
-    header->length = msg_size;
-    header->port = port_no;
-    header->arg = arg;
-    ofpbuf_put(msg, packet->data, packet->size);
-    queue_push_tail(q, msg);
-
-    return 0;
-}
-
-static int
-dp_netdev_execute_actions(struct dp_netdev *dp,
-                          struct ofpbuf *packet, flow_t *key,
-                          const union odp_action *actions, int n_actions)
-{
-    int i;
-    for (i = 0; i < n_actions; i++) {
-        const union odp_action *a = &actions[i];
-
-               switch (a->type) {
-               case ODPAT_OUTPUT:
-            dp_netdev_output_port(dp, packet, a->output.port);
-                       break;
-
-               case ODPAT_OUTPUT_GROUP:
-                       dp_netdev_output_group(dp, a->output_group.group, key->in_port,
-                                   packet);
-                       break;
-
-               case ODPAT_CONTROLLER:
-            dp_netdev_output_control(dp, packet, _ODPL_ACTION_NR,
-                                     key->in_port, a->controller.arg);
-                       break;
-
-               case ODPAT_SET_VLAN_VID:
-                       dp_netdev_modify_vlan_tci(packet, key, ntohs(a->vlan_vid.vlan_vid),
-                                      VLAN_VID_MASK);
-            break;
-
-               case ODPAT_SET_VLAN_PCP:
-                       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_strip_vlan(packet, key);
-                       break;
-
-               case ODPAT_SET_DL_SRC:
-            dp_netdev_set_dl_src(packet, key, a->dl_addr.dl_addr);
-                       break;
-
-               case ODPAT_SET_DL_DST:
-            dp_netdev_set_dl_dst(packet, key, a->dl_addr.dl_addr);
-                       break;
-
-               case ODPAT_SET_NW_SRC:
-               case ODPAT_SET_NW_DST:
-                       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);
-                       break;
-               }
-       }
-    return 0;
-}
-
-const struct dpif_class dpif_netdev_class = {
-    "netdev",
-    dp_netdev_run,
-    dp_netdev_wait,
-    NULL,                       /* enumerate */
-    dpif_netdev_open,
-    dpif_netdev_close,
-    NULL,                       /* get_all_names */
-    dpif_netdev_destroy,
-    dpif_netdev_get_stats,
-    dpif_netdev_get_drop_frags,
-    dpif_netdev_set_drop_frags,
-    dpif_netdev_port_add,
-    dpif_netdev_port_del,
-    dpif_netdev_port_query_by_number,
-    dpif_netdev_port_query_by_name,
-    dpif_netdev_port_list,
-    dpif_netdev_port_poll,
-    dpif_netdev_port_poll_wait,
-    dpif_netdev_port_group_get,
-    dpif_netdev_port_group_set,
-    dpif_netdev_flow_get,
-    dpif_netdev_flow_put,
-    dpif_netdev_flow_del,
-    dpif_netdev_flow_flush,
-    dpif_netdev_flow_list,
-    dpif_netdev_execute,
-    dpif_netdev_recv_get_mask,
-    dpif_netdev_recv_set_mask,
-    NULL,                       /* get_sflow_probability */
-    NULL,                       /* set_sflow_probability */
-    dpif_netdev_recv,
-    dpif_netdev_recv_wait,
-};
diff --git a/lib/dpif.h b/lib/dpif.h
deleted file mode 100644 (file)
index 4789284..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#ifndef DPIF_H
-#define DPIF_H 1
-
-#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_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 *);
-
-int dpif_get_dp_stats(const struct dpif *, struct odp_stats *);
-int dpif_get_drop_frags(const struct dpif *, bool *drop_frags);
-int dpif_set_drop_frags(struct dpif *, bool drop_frags);
-
-int dpif_port_add(struct dpif *, const char *devname, uint16_t flags,
-                  uint16_t *port_no);
-int dpif_port_del(struct dpif *, uint16_t port_no);
-int dpif_port_query_by_number(const struct dpif *, uint16_t port_no,
-                              struct odp_port *);
-int dpif_port_query_by_name(const struct dpif *, const char *devname,
-                            struct odp_port *);
-int dpif_port_get_name(struct dpif *, uint16_t port_no,
-                       char *name, size_t name_size);
-int dpif_port_list(const struct dpif *, struct odp_port **, size_t *n_ports);
-
-int dpif_port_poll(const struct dpif *, char **devnamep);
-void dpif_port_poll_wait(const struct dpif *);
-
-int dpif_port_group_get(const struct dpif *, uint16_t group,
-                        uint16_t **ports, size_t *n_ports);
-int dpif_port_group_set(struct dpif *, uint16_t group,
-                        const uint16_t ports[], size_t n_ports);
-
-int dpif_flow_flush(struct dpif *);
-int dpif_flow_put(struct dpif *, struct odp_flow_put *);
-int dpif_flow_del(struct dpif *, struct odp_flow *);
-int dpif_flow_get(const struct dpif *, struct odp_flow *);
-int dpif_flow_get_multiple(const struct dpif *, struct odp_flow[], size_t n);
-int dpif_flow_list(const struct dpif *, struct odp_flow[], size_t n,
-                   size_t *n_out);
-int dpif_flow_list_all(const struct dpif *,
-                       struct odp_flow **flowsp, size_t *np);
-
-int dpif_execute(struct dpif *, uint16_t in_port,
-                 const union odp_action[], size_t n_actions,
-                 const struct ofpbuf *);
-
-int dpif_recv_get_mask(const struct dpif *, int *listen_mask);
-int dpif_recv_set_mask(struct dpif *, int listen_mask);
-int dpif_get_sflow_probability(const struct dpif *, uint32_t *probability);
-int dpif_set_sflow_probability(struct dpif *, uint32_t probability);
-int dpif_recv(struct dpif *, struct ofpbuf **);
-int dpif_recv_purge(struct dpif *);
-void dpif_recv_wait(struct dpif *);
-
-void dpif_get_netflow_ids(const struct dpif *,
-                          uint8_t *engine_type, uint8_t *engine_id);
-
-#ifdef  __cplusplus
-}
-#endif
-
-#endif /* dpif.h */
index 7ae90d2..bd50085 100644 (file)
@@ -25,7 +25,7 @@
 #include "hash.h"
 #include "ofpbuf.h"
 #include "openflow/openflow.h"
-#include "openvswitch/datapath-protocol.h"
+#include "openvswitch/xflow.h"
 #include "packets.h"
 #include "unaligned.h"
 #include "xtoxll.h"
@@ -91,7 +91,7 @@ pull_vlan(struct ofpbuf *packet)
 
 /* Returns 1 if 'packet' is an IP fragment, 0 otherwise.
  * 'tun_id' is in network byte order, while 'in_port' is in host byte order.
- * These byte orders are the same as they are in struct odp_flow_key. */
+ * These byte orders are the same as they are in struct xflow_key. */
 int
 flow_extract(struct ofpbuf *packet, uint32_t tun_id, uint16_t in_port,
              flow_t *flow)
@@ -226,7 +226,7 @@ flow_extract(struct ofpbuf *packet, uint32_t tun_id, uint16_t in_port,
  */
 void
 flow_extract_stats(const flow_t *flow, struct ofpbuf *packet, 
-        struct odp_flow_stats *stats)
+        struct xflow_flow_stats *stats)
 {
     memset(stats, '\0', sizeof(*stats));
 
@@ -243,18 +243,15 @@ flow_extract_stats(const flow_t *flow, struct ofpbuf *packet,
     stats->n_packets = 1;
 }
 
-/* Extract 'flow' with 'wildcards' into the OpenFlow match structure
- * 'match'. */
+/* Extract 'flow' into the OpenFlow match structure 'match'. */
 void
-flow_to_match(const flow_t *flow, uint32_t wildcards, bool tun_id_from_cookie,
+flow_to_match(const flow_t *flow, bool tun_id_from_cookie,
               struct ofp_match *match)
 {
-    if (!tun_id_from_cookie) {
-        wildcards &= OFPFW_ALL;
-    }
-    match->wildcards = htonl(wildcards);
+    uint32_t wildcard_mask = tun_id_from_cookie ? OVSFW_ALL : OFPFW_ALL;
+    match->wildcards = htonl(flow->wildcards & wildcard_mask);
 
-    match->in_port = htons(flow->in_port == ODPP_LOCAL ? OFPP_LOCAL
+    match->in_port = htons(flow->in_port == XFLOWP_LOCAL ? OFPP_LOCAL
                            : flow->in_port);
     match->dl_vlan = flow->dl_vlan;
     match->dl_vlan_pcp = flow->dl_vlan_pcp;
@@ -272,20 +269,20 @@ flow_to_match(const flow_t *flow, uint32_t wildcards, bool tun_id_from_cookie,
 }
 
 void
-flow_from_match(const struct ofp_match *match, bool tun_id_from_cookie,
-                uint64_t cookie, flow_t *flow, uint32_t *flow_wildcards)
+flow_from_match(const struct ofp_match *match, uint32_t priority,
+                bool tun_id_from_cookie, uint64_t cookie, flow_t *flow)
 {
-       uint32_t wildcards = ntohl(match->wildcards);
-
+    flow->wildcards = ntohl(match->wildcards);
+    flow->priority = priority;
     flow->nw_src = match->nw_src;
     flow->nw_dst = match->nw_dst;
-    if (tun_id_from_cookie && !(wildcards & NXFW_TUN_ID)) {
+    if (tun_id_from_cookie && !(flow->wildcards & NXFW_TUN_ID)) {
         flow->tun_id = htonl(ntohll(cookie) >> 32);
     } else {
-        wildcards |= NXFW_TUN_ID;
+        flow->wildcards |= NXFW_TUN_ID;
         flow->tun_id = 0;
     }
-    flow->in_port = (match->in_port == htons(OFPP_LOCAL) ? ODPP_LOCAL
+    flow->in_port = (match->in_port == htons(OFPP_LOCAL) ? XFLOWP_LOCAL
                      : ntohs(match->in_port));
     flow->dl_vlan = match->dl_vlan;
     flow->dl_vlan_pcp = match->dl_vlan_pcp;
@@ -296,11 +293,6 @@ flow_from_match(const struct ofp_match *match, bool tun_id_from_cookie,
     memcpy(flow->dl_dst, match->dl_dst, ETH_ADDR_LEN);
     flow->nw_tos = match->nw_tos;
     flow->nw_proto = match->nw_proto;
-    memset(flow->reserved, 0, sizeof flow->reserved);
-
-    if (flow_wildcards) {
-        *flow_wildcards = wildcards;
-    }
 }
 
 char *
@@ -314,7 +306,8 @@ flow_to_string(const flow_t *flow)
 void
 flow_format(struct ds *ds, const flow_t *flow)
 {
-    ds_put_format(ds, "tunnel%08"PRIx32":in_port%04"PRIx16
+    ds_put_format(ds, "wild%08"PRIx32" pri%"PRIu32" "
+                      "tunnel%08"PRIx32":in_port%04"PRIx16
                       ":vlan%"PRIu16":pcp%"PRIu8
                       " mac"ETH_ADDR_FMT"->"ETH_ADDR_FMT
                       " type%04"PRIx16
@@ -322,6 +315,8 @@ flow_format(struct ds *ds, const flow_t *flow)
                       " tos%"PRIu8
                       " ip"IP_FMT"->"IP_FMT
                       " port%"PRIu16"->%"PRIu16,
+                  flow->wildcards,
+                  flow->priority,
                   ntohl(flow->tun_id),
                   flow->in_port,
                   ntohs(flow->dl_vlan),
index 058404c..0cfe9e3 100644 (file)
 #include "openflow/nicira-ext.h"
 #include "openflow/openflow.h"
 #include "hash.h"
-#include "openvswitch/datapath-protocol.h"
+#include "openvswitch/xflow.h"
 #include "util.h"
 
 struct ds;
 struct ofp_match;
 struct ofpbuf;
 
-typedef struct odp_flow_key flow_t;
+typedef struct flow flow_t;
+struct flow {
+    uint32_t wildcards;         /* Wildcards. */
+    uint32_t priority;          /* Priority. */
+    uint32_t tun_id;            /* Encapsulating tunnel ID. */
+    uint32_t nw_src;            /* IP source address. */
+    uint32_t nw_dst;            /* IP destination address. */
+    uint16_t in_port;           /* Input switch port. */
+    uint16_t dl_vlan;           /* Input VLAN. */
+    uint16_t dl_type;           /* Ethernet frame type. */
+    uint16_t tp_src;            /* TCP/UDP source port. */
+    uint16_t tp_dst;            /* TCP/UDP destination port. */
+    uint8_t dl_src[ETH_ALEN];   /* Ethernet source address. */
+    uint8_t dl_dst[ETH_ALEN];   /* Ethernet destination address. */
+    uint8_t nw_proto;           /* IP protocol or low 8 bits of ARP opcode. */
+    uint8_t dl_vlan_pcp;        /* Input VLAN priority. */
+    uint8_t nw_tos;             /* IP ToS (DSCP field, 6 bits). */
+};
+
+/* Assert that there are FLOW_SIG_SIZE bytes of significant data in "struct
+ * flow", followed by FLOW_PAD_SIZE bytes of padding. */
+#define FLOW_SIG_SIZE 45
+#define FLOW_PAD_SIZE 3
+BUILD_ASSERT_DECL(offsetof(struct flow, nw_tos) == FLOW_SIG_SIZE - 1);
+BUILD_ASSERT_DECL(sizeof(((struct flow *)0)->nw_tos) == 1);
+BUILD_ASSERT_DECL(sizeof(struct flow) == FLOW_SIG_SIZE + FLOW_PAD_SIZE);
 
 int flow_extract(struct ofpbuf *, uint32_t tun_id, uint16_t in_port, flow_t *);
 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, bool tun_id_cookie,
-                   struct ofp_match *);
-void flow_from_match(const struct ofp_match *, bool tun_id_from_cookie,
-                     uint64_t cookie, flow_t *, uint32_t *wildcards);
+        struct xflow_flow_stats *stats);
+void flow_to_match(const flow_t *,
+                   bool tun_id_from_cookie, struct ofp_match *);
+void flow_from_match(const struct ofp_match *, uint32_t priority,
+                     bool tun_id_from_cookie, uint64_t cookie, flow_t *);
 char *flow_to_string(const flow_t *);
 void flow_format(struct ds *, const flow_t *);
 void flow_print(FILE *, const flow_t *);
@@ -50,7 +75,7 @@ static inline size_t flow_hash(const flow_t *, uint32_t basis);
 static inline int
 flow_compare(const flow_t *a, const flow_t *b)
 {
-    return memcmp(a, b, sizeof *a);
+    return memcmp(a, b, FLOW_SIG_SIZE);
 }
 
 static inline bool
@@ -62,14 +87,11 @@ flow_equal(const flow_t *a, const flow_t *b)
 static inline size_t
 flow_hash(const flow_t *flow, uint32_t basis)
 {
-    BUILD_ASSERT_DECL(!(sizeof *flow % sizeof(uint32_t)));
-    return hash_words((const uint32_t *) flow,
-                      sizeof *flow / sizeof(uint32_t), basis);
+    return hash_bytes(flow, FLOW_SIG_SIZE, basis);
 }
 
 /* Information on wildcards for a flow, as a supplement to flow_t. */
 struct flow_wildcards {
-    uint32_t wildcards;         /* enum ofp_flow_wildcards (in host order). */
     uint32_t nw_src_mask;       /* 1-bit in each significant nw_src bit. */
     uint32_t nw_dst_mask;       /* 1-bit in each significant nw_dst bit. */
 };
@@ -96,9 +118,9 @@ flow_nw_bits_to_mask(uint32_t wildcards, int shift)
 static inline void
 flow_wildcards_init(struct flow_wildcards *wc, uint32_t wildcards)
 {
-    wc->wildcards = wildcards & OVSFW_ALL;
-    wc->nw_src_mask = flow_nw_bits_to_mask(wc->wildcards, OFPFW_NW_SRC_SHIFT);
-    wc->nw_dst_mask = flow_nw_bits_to_mask(wc->wildcards, OFPFW_NW_DST_SHIFT);
+    wildcards &= OVSFW_ALL;
+    wc->nw_src_mask = flow_nw_bits_to_mask(wildcards, OFPFW_NW_SRC_SHIFT);
+    wc->nw_dst_mask = flow_nw_bits_to_mask(wildcards, OFPFW_NW_DST_SHIFT);
 }
 
 #endif /* flow.h */
index 5f6409c..40e429d 100644 (file)
@@ -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 <string.h>
 #include "util.h"
 
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
 /* This is the public domain lookup3 hash by Bob Jenkins from
  * http://burtleburtle.net/bob/c/lookup3.c, modified for style. */
 
@@ -76,8 +80,8 @@ static inline uint32_t hash_int(uint32_t x, uint32_t basis)
  * quality. */
 static inline uint32_t hash_boolean(bool x, uint32_t basis)
 {
-    enum { P0 = 0xc2b73583 };   /* This is hash_int(1, 0). */
-    enum { P1 = 0xe90f1258 };   /* This is hash_int(2, 0). */
+    const uint32_t P0 = 0xc2b73583; /* This is hash_int(1, 0). */
+    const uint32_t P1 = 0xe90f1258; /* This is hash_int(2, 0). */
     return (x ? P0 : P1) ^ HASH_ROT(basis, 1);
 }
 
@@ -103,4 +107,8 @@ static inline uint32_t hash_pointer(const void *p, uint32_t basis)
     return hash_int((uint32_t) (uintptr_t) p, basis);
 }
 
+#ifdef  __cplusplus
+}
+#endif
+
 #endif /* hash.h */
index 2f4a302..7aa7726 100644 (file)
@@ -87,7 +87,7 @@ static inline void hmap_remove(struct hmap *, struct hmap_node *);
 
 void hmap_node_moved(struct hmap *, struct hmap_node *, struct hmap_node *);
 static inline void hmap_replace(struct hmap *, const struct hmap_node *old,
-                                struct hmap_node *new);
+                                struct hmap_node *new_node);
 
 /* Search.
  *
index 4e28fee..39a51f7 100644 (file)
@@ -23,8 +23,8 @@
 #include "list.h"
 #include "netdev-provider.h"
 #include "openflow/openflow.h"
-#include "openvswitch/datapath-protocol.h"
 #include "openvswitch/gre.h"
+#include "openvswitch/xflow.h"
 #include "packets.h"
 #include "shash.h"
 #include "socket-util.h"
@@ -170,7 +170,7 @@ netdev_gre_create(const char *name, const char *type OVS_UNUSED,
                   const struct shash *args, struct netdev_dev **netdev_devp)
 {
     int err;
-    struct odp_vport_add ova;
+    struct xflow_vport_add ova;
     struct gre_port_config port_config;
     struct netdev_dev_gre *netdev_dev;
 
@@ -183,16 +183,16 @@ netdev_gre_create(const char *name, const char *type OVS_UNUSED,
         return err;
     }
 
-    err = do_ioctl(ODP_VPORT_ADD, &ova);
+    err = do_ioctl(XFLOW_VPORT_ADD, &ova);
     if (err == EEXIST) {
         VLOG_WARN("%s: destroying existing device", name);
 
-        err = do_ioctl(ODP_VPORT_DEL, ova.devname);
+        err = do_ioctl(XFLOW_VPORT_DEL, ova.devname);
         if (err) {
             return err;
         }
 
-        err = do_ioctl(ODP_VPORT_ADD, &ova);
+        err = do_ioctl(XFLOW_VPORT_ADD, &ova);
     }
 
     if (err) {
@@ -210,7 +210,7 @@ static int
 netdev_gre_reconfigure(struct netdev_dev *netdev_dev_, const struct shash *args)
 {
     const char *name = netdev_dev_get_name(netdev_dev_);
-    struct odp_vport_mod ovm;
+    struct xflow_vport_mod ovm;
     struct gre_port_config port_config;
     int err;
 
@@ -222,7 +222,7 @@ netdev_gre_reconfigure(struct netdev_dev *netdev_dev_, const struct shash *args)
         return err;
     }
 
-    return do_ioctl(ODP_VPORT_MOD, &ovm);
+    return do_ioctl(XFLOW_VPORT_MOD, &ovm);
 }
 
 static void
@@ -230,7 +230,7 @@ netdev_gre_destroy(struct netdev_dev *netdev_dev_)
 {
     struct netdev_dev_gre *netdev_dev = netdev_dev_gre_cast(netdev_dev_);
 
-    do_ioctl(ODP_VPORT_DEL, (char *)netdev_dev_get_name(netdev_dev_));
+    do_ioctl(XFLOW_VPORT_DEL, (char *)netdev_dev_get_name(netdev_dev_));
     free(netdev_dev);
 }
 
@@ -259,7 +259,7 @@ netdev_gre_set_etheraddr(struct netdev *netdev_,
                          const uint8_t mac[ETH_ADDR_LEN])
 {
     struct netdev_gre *netdev = netdev_gre_cast(netdev_);
-    struct odp_vport_ether vport_ether;
+    struct xflow_vport_ether vport_ether;
     int err;
 
     ovs_strlcpy(vport_ether.devname, netdev_get_name(netdev_),
@@ -267,7 +267,7 @@ netdev_gre_set_etheraddr(struct netdev *netdev_,
 
     memcpy(vport_ether.ether_addr, mac, ETH_ADDR_LEN);
 
-    err = ioctl(ioctl_fd, ODP_VPORT_ETHER_SET, &vport_ether);
+    err = ioctl(ioctl_fd, XFLOW_VPORT_ETHER_SET, &vport_ether);
     if (err) {
         return err;
     }
@@ -280,13 +280,13 @@ static int
 netdev_gre_get_etheraddr(const struct netdev *netdev_,
                          uint8_t mac[ETH_ADDR_LEN])
 {
-    struct odp_vport_ether vport_ether;
+    struct xflow_vport_ether vport_ether;
     int err;
 
     ovs_strlcpy(vport_ether.devname, netdev_get_name(netdev_),
                 sizeof vport_ether.devname);
 
-    err = ioctl(ioctl_fd, ODP_VPORT_ETHER_GET, &vport_ether);
+    err = ioctl(ioctl_fd, XFLOW_VPORT_ETHER_GET, &vport_ether);
     if (err) {
         return err;
     }
@@ -298,13 +298,13 @@ netdev_gre_get_etheraddr(const struct netdev *netdev_,
 static int
 netdev_gre_get_mtu(const struct netdev *netdev_, int *mtup)
 {
-    struct odp_vport_mtu vport_mtu;
+    struct xflow_vport_mtu vport_mtu;
     int err;
 
     ovs_strlcpy(vport_mtu.devname, netdev_get_name(netdev_),
                 sizeof vport_mtu.devname);
 
-    err = ioctl(ioctl_fd, ODP_VPORT_MTU_GET, &vport_mtu);
+    err = ioctl(ioctl_fd, XFLOW_VPORT_MTU_GET, &vport_mtu);
     if (err) {
         return err;
     }
@@ -324,11 +324,11 @@ static int
 netdev_gre_get_stats(const struct netdev *netdev_, struct netdev_stats *stats)
 {
     const char *name = netdev_get_name(netdev_);
-    struct odp_vport_stats_req ovsr;
+    struct xflow_vport_stats_req ovsr;
     int err;
 
     ovs_strlcpy(ovsr.devname, name, sizeof ovsr.devname);
-    err = do_ioctl(ODP_VPORT_STATS_GET, &ovsr);
+    err = do_ioctl(XFLOW_VPORT_STATS_GET, &ovsr);
     if (err) {
         return err;
     }
index eb62cc1..ddb4b1b 100644 (file)
@@ -74,6 +74,8 @@ struct netdev {
 
     enum netdev_flags save_flags;    /* Initial device flags. */
     enum netdev_flags changed_flags; /* Flags that we changed. */
+
+    int ref_cnt;                     /* Times this 'netdev' was opened. */
 };
 
 void netdev_init(struct netdev *, struct netdev_dev *);
index 09c00af..58f6ceb 100644 (file)
@@ -304,7 +304,6 @@ create_device(struct netdev_options *options, struct netdev_dev **netdev_devp)
  * If the 'may_open' flag is set then the call will succeed even if another
  * caller has already opened it.  It may be to false if the device should not
  * currently be open. */
-
 int
 netdev_open(struct netdev_options *options, struct netdev **netdevp)
 {
@@ -371,6 +370,14 @@ netdev_open_default(const char *name, struct netdev **netdevp)
     return netdev_open(&options, netdevp);
 }
 
+/* Increments the reference count on 'netdev'.  Returns 'netdev'. */
+struct netdev *
+netdev_reopen(struct netdev *netdev)
+{
+    netdev->ref_cnt++;
+    return netdev;
+}
+
 /* Reconfigures the device 'netdev' with 'args'.  'args' may be empty
  * or NULL if none are needed. */
 int
@@ -396,11 +403,13 @@ netdev_reconfigure(struct netdev *netdev, const struct shash *args)
     return 0;
 }
 
-/* Closes and destroys 'netdev'. */
+/* Decrements the reference count on 'netdev'.  If the reference count reaches
+ * zero, closes and destroys 'netdev'. */
 void
 netdev_close(struct netdev *netdev)
 {
-    if (netdev) {
+    assert(!netdev || netdev->ref_cnt > 0);
+    if (netdev && !--netdev->ref_cnt) {
         struct netdev_dev *netdev_dev = netdev_get_dev(netdev);
 
         assert(netdev_dev->ref_cnt);
@@ -1132,6 +1141,7 @@ netdev_init(struct netdev *netdev, struct netdev_dev *netdev_dev)
 {
     memset(netdev, 0, sizeof *netdev);
     netdev->netdev_dev = netdev_dev;
+    netdev->ref_cnt = 1;
     list_push_back(&netdev_list, &netdev->node);
 }
 
@@ -1139,7 +1149,7 @@ netdev_init(struct netdev *netdev, struct netdev_dev *netdev_dev)
  *
  * Normally this function only needs to be called from netdev_close().
  * However, it may be called by providers due to an error on opening
- * that occurs after initialization.  It this case netdev_close() would
+ * that occurs after initialization.  In this case netdev_close() would
  * never be called. */
 void
 netdev_uninit(struct netdev *netdev, bool close)
index 2a096ee..05d5f01 100644 (file)
@@ -101,6 +101,7 @@ void netdev_enumerate_types(struct svec *types);
 
 int netdev_open(struct netdev_options *, struct netdev **);
 int netdev_open_default(const char *name, struct netdev **);
+struct netdev *netdev_reopen(struct netdev *);
 int netdev_reconfigure(struct netdev *, const struct shash *args);
 void netdev_close(struct netdev *);
 
diff --git a/lib/odp-util.c b/lib/odp-util.c
deleted file mode 100644 (file)
index 67d1b3e..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * 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.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <config.h>
-#include "odp-util.h"
-#include <inttypes.h>
-#include <stdlib.h>
-#include <string.h>
-#include "coverage.h"
-#include "dynamic-string.h"
-#include "flow.h"
-#include "packets.h"
-#include "timeval.h"
-#include "util.h"
-
-union odp_action *
-odp_actions_add(struct odp_actions *actions, uint16_t type)
-{
-    union odp_action *a;
-    if (actions->n_actions < MAX_ODP_ACTIONS) {
-        a = &actions->actions[actions->n_actions++];
-    } else {
-        COVERAGE_INC(odp_overflow);
-        actions->n_actions = MAX_ODP_ACTIONS + 1;
-        a = &actions->actions[MAX_ODP_ACTIONS - 1];
-    }
-    memset(a, 0, sizeof *a);
-    a->type = type;
-    return a;
-}
-
-void
-format_odp_action(struct ds *ds, const union odp_action *a)
-{
-    switch (a->type) {
-    case ODPAT_OUTPUT:
-        ds_put_format(ds, "%"PRIu16, a->output.port);
-        break;
-    case ODPAT_OUTPUT_GROUP:
-        ds_put_format(ds, "g%"PRIu16, a->output_group.group);
-        break;
-    case ODPAT_CONTROLLER:
-        ds_put_format(ds, "ctl(%"PRIu32")", a->controller.arg);
-        break;
-    case ODPAT_SET_TUNNEL:
-        ds_put_format(ds, "set_tunnel(0x%08"PRIx32")", ntohl(a->tunnel.tun_id));
-        break;
-    case ODPAT_SET_VLAN_VID:
-        ds_put_format(ds, "set_vlan(%"PRIu16")", ntohs(a->vlan_vid.vlan_vid));
-        break;
-    case ODPAT_SET_VLAN_PCP:
-        ds_put_format(ds, "set_vlan_pcp(%"PRIu8")", a->vlan_pcp.vlan_pcp);
-        break;
-    case ODPAT_STRIP_VLAN:
-        ds_put_format(ds, "strip_vlan");
-        break;
-    case ODPAT_SET_DL_SRC:
-        ds_put_format(ds, "set_dl_src("ETH_ADDR_FMT")",
-               ETH_ADDR_ARGS(a->dl_addr.dl_addr));
-        break;
-    case ODPAT_SET_DL_DST:
-        ds_put_format(ds, "set_dl_dst("ETH_ADDR_FMT")",
-               ETH_ADDR_ARGS(a->dl_addr.dl_addr));
-        break;
-    case ODPAT_SET_NW_SRC:
-        ds_put_format(ds, "set_nw_src("IP_FMT")",
-                      IP_ARGS(&a->nw_addr.nw_addr));
-        break;
-    case ODPAT_SET_NW_DST:
-        ds_put_format(ds, "set_nw_dst("IP_FMT")",
-                      IP_ARGS(&a->nw_addr.nw_addr));
-        break;
-    case ODPAT_SET_NW_TOS:
-        ds_put_format(ds, "set_nw_tos(%"PRIu8")", a->nw_tos.nw_tos);
-        break;
-    case ODPAT_SET_TP_SRC:
-        ds_put_format(ds, "set_tp_src(%"PRIu16")", ntohs(a->tp_port.tp_port));
-        break;
-    case ODPAT_SET_TP_DST:
-        ds_put_format(ds, "set_tp_dst(%"PRIu16")", ntohs(a->tp_port.tp_port));
-        break;
-    default:
-        ds_put_format(ds, "***bad action 0x%"PRIx16"***", a->type);
-        break;
-    }
-}
-
-void
-format_odp_actions(struct ds *ds, const union odp_action *actions,
-                   size_t n_actions)
-{
-    size_t i;
-    for (i = 0; i < n_actions; i++) {
-        if (i) {
-            ds_put_char(ds, ',');
-        }
-        format_odp_action(ds, &actions[i]);
-    }
-    if (!n_actions) {
-        ds_put_cstr(ds, "drop");
-    }
-}
-
-void
-format_odp_flow_stats(struct ds *ds, const struct odp_flow_stats *s)
-{
-    ds_put_format(ds, "packets:%llu, bytes:%llu, used:",
-                  (unsigned long long int) s->n_packets,
-                  (unsigned long long int) s->n_bytes);
-    if (s->used_sec) {
-        long long int used = s->used_sec * 1000 + s->used_nsec / 1000000;
-        ds_put_format(ds, "%.3fs", (time_msec() - used) / 1000.0);
-    } else {
-        ds_put_format(ds, "never");
-    }
-}
-
-void
-format_odp_flow(struct ds *ds, const struct odp_flow *f)
-{
-    flow_format(ds, &f->key);
-    ds_put_cstr(ds, ", ");
-    format_odp_flow_stats(ds, &f->stats);
-    ds_put_cstr(ds, ", actions:");
-    format_odp_actions(ds, f->actions, f->n_actions);
-}
-
diff --git a/lib/odp-util.h b/lib/odp-util.h
deleted file mode 100644 (file)
index 6d67ec2..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2009 Nicira Networks.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ODP_UTIL_H
-#define ODP_UTIL_H 1
-
-#include <stdbool.h>
-#include <stdint.h>
-#include "openflow/openflow.h"
-#include "openvswitch/datapath-protocol.h"
-
-struct ds;
-
-/* The kernel datapaths limits actions to those that fit in a single page of
- * memory, so there is no point in allocating more than that.  */
-enum { MAX_ODP_ACTIONS = 4096 / sizeof(union odp_action) };
-
-struct odp_actions {
-    size_t n_actions;
-    union odp_action actions[MAX_ODP_ACTIONS];
-};
-
-static inline void
-odp_actions_init(struct odp_actions *actions)
-{
-    actions->n_actions = 0;
-}
-
-union odp_action *odp_actions_add(struct odp_actions *actions, uint16_t type);
-
-static inline bool
-odp_actions_overflow(const struct odp_actions *actions)
-{
-    return actions->n_actions > MAX_ODP_ACTIONS;
-}
-
-static inline uint16_t
-ofp_port_to_odp_port(uint16_t ofp_port)
-{
-    switch (ofp_port) {
-    case OFPP_LOCAL:
-        return ODPP_LOCAL;
-    case OFPP_NONE:
-        return ODPP_NONE;
-    default:
-        return ofp_port;
-    }
-}
-
-static inline uint16_t
-odp_port_to_ofp_port(uint16_t odp_port)
-{
-    switch (odp_port) {
-    case ODPP_LOCAL:
-        return OFPP_LOCAL;
-    case ODPP_NONE:
-        return OFPP_NONE;
-    default:
-        return odp_port;
-    }
-}
-
-void format_odp_action(struct ds *, const union odp_action *);
-void format_odp_actions(struct ds *, const union odp_action *actions,
-                        size_t n_actions);
-void format_odp_flow_stats(struct ds *, const struct odp_flow_stats *);
-void format_odp_flow(struct ds *, const struct odp_flow *);
-
-#endif /* odp-util.h */
index 7c1ebd0..804b5aa 100644 (file)
@@ -135,7 +135,7 @@ ofp_packet_in(struct ds *string, const void *oh, size_t len, int verbosity)
         packet.data = (void *) op->data;
         packet.size = data_len;
         flow_extract(&packet, 0, ntohs(op->in_port), &flow);
-        flow_to_match(&flow, 0, false, &match);
+        flow_to_match(&flow, false, &match);
         ofp_print_match(string, &match, verbosity);
         ds_put_char(string, '\n');
     }
index 1621bcc..47f1c44 100644 (file)
@@ -157,10 +157,9 @@ void
 ofpbuf_trim(struct ofpbuf *b)
 {
     /* XXX These could be supported, but the current client doesn't care. */
-    assert(b->data == b->base);
     assert(b->l2 == NULL && b->l3 == NULL && b->l4 == NULL && b->l7 == NULL);
     if (b->allocated > b->size) {
-        b->base = b->data = xrealloc(b->base, b->size);
+        b->base = b->data = xrealloc(b->data, b->size);
         b->allocated = b->size;
     }
 }
index 7ea462b..8d59bd2 100644 (file)
@@ -18,6 +18,8 @@
 #define PACKETS_H 1
 
 #include <inttypes.h>
+#include <sys/types.h>
+#include <netinet/in.h>
 #include <stdint.h>
 #include <string.h>
 #include "compiler.h"
@@ -195,6 +197,24 @@ BUILD_ASSERT_DECL(LLC_SNAP_HEADER_LEN == sizeof(struct llc_snap_header));
 #define VLAN_PCP_MASK 0xe000
 #define VLAN_PCP_SHIFT 13
 
+#define VLAN_CFI 0x1000
+
+/* Given the vlan_tci field from an 802.1Q header, in network byte order,
+ * returns the VLAN ID in host byte order. */
+static inline uint16_t
+vlan_tci_to_vid(uint16_t vlan_tci)
+{
+    return (ntohs(vlan_tci) & VLAN_VID_MASK) >> VLAN_VID_SHIFT;
+}
+
+/* Given the vlan_tci field from an 802.1Q header, in network byte order,
+ * returns the priority code point (PCP) in host byte order. */
+static inline int
+vlan_tci_to_pcp(uint16_t vlan_tci)
+{
+    return (ntohs(vlan_tci) & VLAN_PCP_MASK) >> VLAN_PCP_SHIFT;
+}
+
 #define VLAN_HEADER_LEN 4
 struct vlan_header {
     uint16_t vlan_tci;          /* Lowest 12 bits are VLAN ID. */
index 1d302ea..79541f3 100644 (file)
@@ -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.
@@ -47,7 +47,7 @@ static void rtnetlink_report_notify_error(void);
  * caller must not modify or free.
  *
  * This is probably not the function that you want.  You should probably be
- * using dpif_port_poll() or netdev_monitor_create(), which unlike this
+ * using xfif_port_poll() or netdev_monitor_create(), which unlike this
  * function are not Linux-specific.
  *
  * Returns 0 if successful, otherwise a positive errno value. */
index bc3df23..de8d0f8 100644 (file)
@@ -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.
@@ -110,6 +110,16 @@ svec_append(struct svec *svec, const struct svec *other)
     }
 }
 
+void
+svec_move(struct svec *svec, struct svec *other)
+{
+    size_t i;
+    for (i = 0; i < other->n; i++) {
+        svec_add_nocopy(svec, other->names[i]);
+    }
+    other->n = 0;
+}
+
 void
 svec_terminate(struct svec *svec)
 {
index d9bb8a7..9f2af05 100644 (file)
@@ -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.
@@ -41,6 +41,7 @@ void svec_add(struct svec *, const char *);
 void svec_add_nocopy(struct svec *, char *);
 void svec_del(struct svec *, const char *);
 void svec_append(struct svec *, const struct svec *);
+void svec_move(struct svec *, struct svec *);
 void svec_terminate(struct svec *);
 void svec_sort(struct svec *);
 void svec_sort_unique(struct svec *);
index 80ba471..918b4ab 100644 (file)
@@ -975,7 +975,7 @@ make_flow_mod(uint16_t command, const flow_t *flow, size_t actions_len)
     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
+    ofm->match.in_port = htons(flow->in_port == XFLOWP_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);
@@ -1066,7 +1066,7 @@ make_packet_out(const struct ofpbuf *packet, uint32_t buffer_id,
     opo->header.length = htons(size);
     opo->header.xid = htonl(0);
     opo->buffer_id = htonl(buffer_id);
-    opo->in_port = htons(in_port == ODPP_LOCAL ? OFPP_LOCAL : in_port);
+    opo->in_port = htons(in_port == XFLOWP_LOCAL ? OFPP_LOCAL : in_port);
     opo->actions_len = htons(actions_len);
     ofpbuf_put(out, actions, actions_len);
     if (packet) {
index 5c836d6..1b80bc3 100644 (file)
@@ -28,9 +28,6 @@ VLOG_MODULE(datapath)
 VLOG_MODULE(dhcp)
 VLOG_MODULE(dhcp_client)
 VLOG_MODULE(discovery)
-VLOG_MODULE(dpif)
-VLOG_MODULE(dpif_linux)
-VLOG_MODULE(dpif_netdev)
 VLOG_MODULE(dpctl)
 VLOG_MODULE(ezio_term)
 VLOG_MODULE(fail_open)
@@ -48,19 +45,19 @@ VLOG_MODULE(netdev_linux)
 VLOG_MODULE(netflow)
 VLOG_MODULE(netlink)
 VLOG_MODULE(ofctl)
-VLOG_MODULE(ovs_discover)
 VLOG_MODULE(ofproto)
 VLOG_MODULE(openflowd)
+VLOG_MODULE(ovs_discover)
 VLOG_MODULE(ovsdb_client)
 VLOG_MODULE(ovsdb_error)
 VLOG_MODULE(ovsdb_file)
 VLOG_MODULE(ovsdb_idl)
-VLOG_MODULE(ovsdb_log)
 VLOG_MODULE(ovsdb_jsonrpc_server)
+VLOG_MODULE(ovsdb_log)
 VLOG_MODULE(ovsdb_server)
 VLOG_MODULE(ovsdb_tool)
-VLOG_MODULE(pktbuf)
 VLOG_MODULE(pcap)
+VLOG_MODULE(pktbuf)
 VLOG_MODULE(poll_loop)
 VLOG_MODULE(port_watcher)
 VLOG_MODULE(proc_net_compat)
@@ -69,34 +66,39 @@ VLOG_MODULE(rconn)
 VLOG_MODULE(reconnect)
 VLOG_MODULE(rtnetlink)
 VLOG_MODULE(sflow)
+VLOG_MODULE(socket_util)
+VLOG_MODULE(stats)
+VLOG_MODULE(status)
 VLOG_MODULE(stp)
+VLOG_MODULE(stream)
 VLOG_MODULE(stream_fd)
 VLOG_MODULE(stream_ssl)
 VLOG_MODULE(stream_tcp)
 VLOG_MODULE(stream_unix)
-VLOG_MODULE(stream)
-VLOG_MODULE(stats)
-VLOG_MODULE(status)
 VLOG_MODULE(svec)
 VLOG_MODULE(switch)
+VLOG_MODULE(switchui)
 VLOG_MODULE(terminal)
 VLOG_MODULE(timeval)
 VLOG_MODULE(tty)
-VLOG_MODULE(socket_util)
-VLOG_MODULE(switchui)
 VLOG_MODULE(unixctl)
 VLOG_MODULE(util)
-VLOG_MODULE(vconn_tcp)
+VLOG_MODULE(vconn)
 VLOG_MODULE(vconn_ssl)
 VLOG_MODULE(vconn_stream)
+VLOG_MODULE(vconn_tcp)
 VLOG_MODULE(vconn_unix)
-VLOG_MODULE(vconn)
-VLOG_MODULE(vsctl)
 VLOG_MODULE(vlog)
-VLOG_MODULE(wcelim)
+VLOG_MODULE(vsctl)
 VLOG_MODULE(vswitchd)
 VLOG_MODULE(vt)
+VLOG_MODULE(wcelim)
+VLOG_MODULE(wdp)
+VLOG_MODULE(wdp_xflow)
 VLOG_MODULE(xenserver)
 VLOG_MODULE(xenserverd)
+VLOG_MODULE(xfif)
+VLOG_MODULE(xfif_linux)
+VLOG_MODULE(xfif_netdev)
 
 #undef VLOG_MODULE
similarity index 58%
rename from lib/dpif-linux.c
rename to lib/xfif-linux.c
index b7c9e3e..feb58a8 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 #include <config.h>
-#include "dpif.h"
+#include "xfif.h"
 
 #include <assert.h>
 #include <ctype.h>
@@ -30,7 +30,6 @@
 #include <sys/ioctl.h>
 #include <unistd.h>
 
-#include "dpif-provider.h"
 #include "netdev.h"
 #include "ofpbuf.h"
 #include "poll-loop.h"
 #include "shash.h"
 #include "svec.h"
 #include "util.h"
+#include "xfif-provider.h"
 
 #include "vlog.h"
-#define THIS_MODULE VLM_dpif_linux
+#define THIS_MODULE VLM_xfif_linux
 
 /* Datapath interface for the openvswitch Linux kernel module. */
-struct dpif_linux {
-    struct dpif dpif;
+struct xfif_linux {
+    struct xfif xfif;
     int fd;
 
-    /* Used by dpif_linux_get_all_names(). */
+    /* Used by xfif_linux_get_all_names(). */
     char *local_ifname;
     int minor;
 
@@ -60,25 +60,25 @@ struct dpif_linux {
 
 static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(9999, 5);
 
-static int do_ioctl(const struct dpif *, int cmd, const void *arg);
+static int do_ioctl(const struct xfif *, int cmd, const void *arg);
 static int lookup_minor(const char *name, int *minor);
-static int finish_open(struct dpif *, const char *local_ifname);
+static int finish_open(struct xfif *, const char *local_ifname);
 static int get_openvswitch_major(void);
-static int create_minor(const char *name, int minor, struct dpif **dpifp);
-static int open_minor(int minor, struct dpif **dpifp);
+static int create_minor(const char *name, int minor, struct xfif **xfifp);
+static int open_minor(int minor, struct xfif **xfifp);
 static int make_openvswitch_device(int minor, char **fnp);
-static void dpif_linux_port_changed(const struct rtnetlink_change *,
-                                    void *dpif);
+static void xfif_linux_port_changed(const struct rtnetlink_change *,
+                                    void *xfif);
 
-static struct dpif_linux *
-dpif_linux_cast(const struct dpif *dpif)
+static struct xfif_linux *
+xfif_linux_cast(const struct xfif *xfif)
 {
-    dpif_assert_class(dpif, &dpif_linux_class);
-    return CONTAINER_OF(dpif, struct dpif_linux, dpif);
+    xfif_assert_class(xfif, &xfif_linux_class);
+    return CONTAINER_OF(xfif, struct xfif_linux, xfif);
 }
 
 static int
-dpif_linux_enumerate(struct svec *all_dps)
+xfif_linux_enumerate(struct svec *all_dps)
 {
     int major;
     int error;
@@ -91,16 +91,16 @@ dpif_linux_enumerate(struct svec *all_dps)
     }
 
     error = 0;
-    for (i = 0; i < ODP_MAX; i++) {
-        struct dpif *dpif;
+    for (i = 0; i < XFLOW_MAX; i++) {
+        struct xfif *xfif;
         char devname[16];
         int retval;
 
         sprintf(devname, "dp%d", i);
-        retval = dpif_open(devname, "system", &dpif);
+        retval = xfif_open(devname, "system", &xfif);
         if (!retval) {
             svec_add(all_dps, devname);
-            dpif_uninit(dpif, true);
+            xfif_uninit(xfif, true);
         } else if (retval != ENODEV && !error) {
             error = retval;
         }
@@ -109,8 +109,8 @@ dpif_linux_enumerate(struct svec *all_dps)
 }
 
 static int
-dpif_linux_open(const char *name, const char *type OVS_UNUSED, bool create,
-                struct dpif **dpifp)
+xfif_linux_open(const char *name, const char *type OVS_UNUSED, bool create,
+                struct xfif **xfifp)
 {
     int minor;
 
@@ -118,11 +118,11 @@ dpif_linux_open(const char *name, const char *type OVS_UNUSED, bool create,
             && isdigit((unsigned char)name[2]) ? atoi(name + 2) : -1;
     if (create) {
         if (minor >= 0) {
-            return create_minor(name, minor, dpifp);
+            return create_minor(name, minor, xfifp);
         } else {
             /* Scan for unused minor number. */
-            for (minor = 0; minor < ODP_MAX; minor++) {
-                int error = create_minor(name, minor, dpifp);
+            for (minor = 0; minor < XFLOW_MAX; minor++) {
+                int error = create_minor(name, minor, xfifp);
                 if (error != EBUSY) {
                     return error;
                 }
@@ -132,8 +132,8 @@ dpif_linux_open(const char *name, const char *type OVS_UNUSED, bool create,
             return ENOBUFS;
         }
     } else {
-        struct dpif_linux *dpif;
-        struct odp_port port;
+        struct xfif_linux *xfif;
+        struct xflow_port port;
         int error;
 
         if (minor < 0) {
@@ -143,94 +143,94 @@ dpif_linux_open(const char *name, const char *type OVS_UNUSED, bool create,
             }
         }
 
-        error = open_minor(minor, dpifp);
+        error = open_minor(minor, xfifp);
         if (error) {
             return error;
         }
-        dpif = dpif_linux_cast(*dpifp);
+        xfif = xfif_linux_cast(*xfifp);
 
         /* We need the local port's ifindex for the poll function.  Start by
          * getting the local port's name. */
         memset(&port, 0, sizeof port);
-        port.port = ODPP_LOCAL;
-        if (ioctl(dpif->fd, ODP_PORT_QUERY, &port)) {
+        port.port = XFLOWP_LOCAL;
+        if (ioctl(xfif->fd, XFLOW_PORT_QUERY, &port)) {
             error = errno;
             if (error != ENODEV) {
                 VLOG_WARN("%s: probe returned unexpected error: %s",
-                          dpif_name(*dpifp), strerror(error));
+                          xfif_name(*xfifp), strerror(error));
             }
-            dpif_uninit(*dpifp, true);
+            xfif_uninit(*xfifp, true);
             return error;
         }
 
         /* Then use that to finish up opening. */
-        return finish_open(&dpif->dpif, port.devname);
+        return finish_open(&xfif->xfif, port.devname);
     }
 }
 
 static void
-dpif_linux_close(struct dpif *dpif_)
+xfif_linux_close(struct xfif *xfif_)
 {
-    struct dpif_linux *dpif = dpif_linux_cast(dpif_);
-    rtnetlink_notifier_unregister(&dpif->port_notifier);
-    shash_destroy(&dpif->changed_ports);
-    free(dpif->local_ifname);
-    close(dpif->fd);
-    free(dpif);
+    struct xfif_linux *xfif = xfif_linux_cast(xfif_);
+    rtnetlink_notifier_unregister(&xfif->port_notifier);
+    shash_destroy(&xfif->changed_ports);
+    free(xfif->local_ifname);
+    close(xfif->fd);
+    free(xfif);
 }
 
 static int
-dpif_linux_get_all_names(const struct dpif *dpif_, struct svec *all_names)
+xfif_linux_get_all_names(const struct xfif *xfif_, struct svec *all_names)
 {
-    struct dpif_linux *dpif = dpif_linux_cast(dpif_);
+    struct xfif_linux *xfif = xfif_linux_cast(xfif_);
 
-    svec_add_nocopy(all_names, xasprintf("dp%d", dpif->minor));
-    svec_add(all_names, dpif->local_ifname);
+    svec_add_nocopy(all_names, xasprintf("dp%d", xfif->minor));
+    svec_add(all_names, xfif->local_ifname);
     return 0;
 }
 
 static int
-dpif_linux_destroy(struct dpif *dpif_)
+xfif_linux_destroy(struct xfif *xfif_)
 {
-    struct odp_port *ports;
+    struct xflow_port *ports;
     size_t n_ports;
     int err;
     int i;
 
-    err = dpif_port_list(dpif_, &ports, &n_ports);
+    err = xfif_port_list(xfif_, &ports, &n_ports);
     if (err) {
         return err;
     }
 
     for (i = 0; i < n_ports; i++) {
-        if (ports[i].port != ODPP_LOCAL) {
-            err = do_ioctl(dpif_, ODP_VPORT_DEL, ports[i].devname);
+        if (ports[i].port != XFLOWP_LOCAL) {
+            err = do_ioctl(xfif_, XFLOW_VPORT_DEL, ports[i].devname);
             if (err) {
                 VLOG_WARN_RL(&error_rl, "%s: error deleting port %s (%s)",
-                             dpif_name(dpif_), ports[i].devname, strerror(err));
+                             xfif_name(xfif_), ports[i].devname, strerror(err));
             }
         }
     }
 
     free(ports);
 
-    return do_ioctl(dpif_, ODP_DP_DESTROY, NULL);
+    return do_ioctl(xfif_, XFLOW_DP_DESTROY, NULL);
 }
 
 static int
-dpif_linux_get_stats(const struct dpif *dpif_, struct odp_stats *stats)
+xfif_linux_get_stats(const struct xfif *xfif_, struct xflow_stats *stats)
 {
     memset(stats, 0, sizeof *stats);
-    return do_ioctl(dpif_, ODP_DP_STATS, stats);
+    return do_ioctl(xfif_, XFLOW_DP_STATS, stats);
 }
 
 static int
-dpif_linux_get_drop_frags(const struct dpif *dpif_, bool *drop_fragsp)
+xfif_linux_get_drop_frags(const struct xfif *xfif_, bool *drop_fragsp)
 {
     int drop_frags;
     int error;
 
-    error = do_ioctl(dpif_, ODP_GET_DROP_FRAGS, &drop_frags);
+    error = do_ioctl(xfif_, XFLOW_GET_DROP_FRAGS, &drop_frags);
     if (!error) {
         *drop_fragsp = drop_frags & 1;
     }
@@ -238,23 +238,23 @@ dpif_linux_get_drop_frags(const struct dpif *dpif_, bool *drop_fragsp)
 }
 
 static int
-dpif_linux_set_drop_frags(struct dpif *dpif_, bool drop_frags)
+xfif_linux_set_drop_frags(struct xfif *xfif_, bool drop_frags)
 {
     int drop_frags_int = drop_frags;
-    return do_ioctl(dpif_, ODP_SET_DROP_FRAGS, &drop_frags_int);
+    return do_ioctl(xfif_, XFLOW_SET_DROP_FRAGS, &drop_frags_int);
 }
 
 static int
-dpif_linux_port_add(struct dpif *dpif_, const char *devname, uint16_t flags,
+xfif_linux_port_add(struct xfif *xfif_, const char *devname, uint16_t flags,
                     uint16_t *port_no)
 {
-    struct odp_port port;
+    struct xflow_port port;
     int error;
 
     memset(&port, 0, sizeof port);
     strncpy(port.devname, devname, sizeof port.devname);
     port.flags = flags;
-    error = do_ioctl(dpif_, ODP_PORT_ATTACH, &port);
+    error = do_ioctl(xfif_, XFLOW_PORT_ATTACH, &port);
     if (!error) {
         *port_no = port.port;
     }
@@ -262,18 +262,18 @@ dpif_linux_port_add(struct dpif *dpif_, const char *devname, uint16_t flags,
 }
 
 static int
-dpif_linux_port_del(struct dpif *dpif_, uint16_t port_no)
+xfif_linux_port_del(struct xfif *xfif_, uint16_t port_no)
 {
     int tmp = port_no;
     int err;
-    struct odp_port port;
+    struct xflow_port port;
 
-    err = dpif_port_query_by_number(dpif_, port_no, &port);
+    err = xfif_port_query_by_number(xfif_, port_no, &port);
     if (err) {
         return err;
     }
 
-    err = do_ioctl(dpif_, ODP_PORT_DETACH, &tmp);
+    err = do_ioctl(xfif_, XFLOW_PORT_DETACH, &tmp);
     if (err) {
         return err;
     }
@@ -282,61 +282,61 @@ dpif_linux_port_del(struct dpif *dpif_, uint16_t port_no)
         /* Try deleting the port if no one has it open.  This shouldn't
          * actually be necessary unless the config changed while we weren't
          * running but it won't hurt anything if the port is already gone. */
-        do_ioctl(dpif_, ODP_VPORT_DEL, port.devname);
+        do_ioctl(xfif_, XFLOW_VPORT_DEL, port.devname);
     }
 
     return 0;
 }
 
 static int
-dpif_linux_port_query_by_number(const struct dpif *dpif_, uint16_t port_no,
-                          struct odp_port *port)
+xfif_linux_port_query_by_number(const struct xfif *xfif_, uint16_t port_no,
+                          struct xflow_port *port)
 {
     memset(port, 0, sizeof *port);
     port->port = port_no;
-    return do_ioctl(dpif_, ODP_PORT_QUERY, port);
+    return do_ioctl(xfif_, XFLOW_PORT_QUERY, port);
 }
 
 static int
-dpif_linux_port_query_by_name(const struct dpif *dpif_, const char *devname,
-                              struct odp_port *port)
+xfif_linux_port_query_by_name(const struct xfif *xfif_, const char *devname,
+                              struct xflow_port *port)
 {
     memset(port, 0, sizeof *port);
     strncpy(port->devname, devname, sizeof port->devname);
-    return do_ioctl(dpif_, ODP_PORT_QUERY, port);
+    return do_ioctl(xfif_, XFLOW_PORT_QUERY, port);
 }
 
 static int
-dpif_linux_flow_flush(struct dpif *dpif_)
+xfif_linux_flow_flush(struct xfif *xfif_)
 {
-    return do_ioctl(dpif_, ODP_FLOW_FLUSH, NULL);
+    return do_ioctl(xfif_, XFLOW_FLOW_FLUSH, NULL);
 }
 
 static int
-dpif_linux_port_list(const struct dpif *dpif_, struct odp_port *ports, int n)
+xfif_linux_port_list(const struct xfif *xfif_, struct xflow_port *ports, int n)
 {
-    struct odp_portvec pv;
+    struct xflow_portvec pv;
     int error;
 
     pv.ports = ports;
     pv.n_ports = n;
-    error = do_ioctl(dpif_, ODP_PORT_LIST, &pv);
+    error = do_ioctl(xfif_, XFLOW_PORT_LIST, &pv);
     return error ? -error : pv.n_ports;
 }
 
 static int
-dpif_linux_port_poll(const struct dpif *dpif_, char **devnamep)
+xfif_linux_port_poll(const struct xfif *xfif_, char **devnamep)
 {
-    struct dpif_linux *dpif = dpif_linux_cast(dpif_);
+    struct xfif_linux *xfif = xfif_linux_cast(xfif_);
 
-    if (dpif->change_error) {
-        dpif->change_error = false;
-        shash_clear(&dpif->changed_ports);
+    if (xfif->change_error) {
+        xfif->change_error = false;
+        shash_clear(&xfif->changed_ports);
         return ENOBUFS;
-    } else if (!shash_is_empty(&dpif->changed_ports)) {
-        struct shash_node *node = shash_first(&dpif->changed_ports);
+    } else if (!shash_is_empty(&xfif->changed_ports)) {
+        struct shash_node *node = shash_first(&xfif->changed_ports);
         *devnamep = xstrdup(node->name);
-        shash_delete(&dpif->changed_ports, node);
+        shash_delete(&xfif->changed_ports, node);
         return 0;
     } else {
         return EAGAIN;
@@ -344,10 +344,10 @@ dpif_linux_port_poll(const struct dpif *dpif_, char **devnamep)
 }
 
 static void
-dpif_linux_port_poll_wait(const struct dpif *dpif_)
+xfif_linux_port_poll_wait(const struct xfif *xfif_)
 {
-    struct dpif_linux *dpif = dpif_linux_cast(dpif_);
-    if (!shash_is_empty(&dpif->changed_ports) || dpif->change_error) {
+    struct xfif_linux *xfif = xfif_linux_cast(xfif_);
+    if (!shash_is_empty(&xfif->changed_ports) || xfif->change_error) {
         poll_immediate_wake();
     } else {
         rtnetlink_notifier_wait();
@@ -355,125 +355,125 @@ dpif_linux_port_poll_wait(const struct dpif *dpif_)
 }
 
 static int
-dpif_linux_port_group_get(const struct dpif *dpif_, int group,
+xfif_linux_port_group_get(const struct xfif *xfif_, int group,
                           uint16_t ports[], int n)
 {
-    struct odp_port_group pg;
+    struct xflow_port_group pg;
     int error;
 
     assert(n <= UINT16_MAX);
     pg.group = group;
     pg.ports = ports;
     pg.n_ports = n;
-    error = do_ioctl(dpif_, ODP_PORT_GROUP_GET, &pg);
+    error = do_ioctl(xfif_, XFLOW_PORT_GROUP_GET, &pg);
     return error ? -error : pg.n_ports;
 }
 
 static int
-dpif_linux_port_group_set(struct dpif *dpif_, int group,
+xfif_linux_port_group_set(struct xfif *xfif_, int group,
                           const uint16_t ports[], int n)
 {
-    struct odp_port_group pg;
+    struct xflow_port_group pg;
 
     assert(n <= UINT16_MAX);
     pg.group = group;
     pg.ports = (uint16_t *) ports;
     pg.n_ports = n;
-    return do_ioctl(dpif_, ODP_PORT_GROUP_SET, &pg);
+    return do_ioctl(xfif_, XFLOW_PORT_GROUP_SET, &pg);
 }
 
 static int
-dpif_linux_flow_get(const struct dpif *dpif_, struct odp_flow flows[], int n)
+xfif_linux_flow_get(const struct xfif *xfif_, struct xflow_flow flows[], int n)
 {
-    struct odp_flowvec fv;
+    struct xflow_flowvec fv;
     fv.flows = flows;
     fv.n_flows = n;
-    return do_ioctl(dpif_, ODP_FLOW_GET, &fv);
+    return do_ioctl(xfif_, XFLOW_FLOW_GET, &fv);
 }
 
 static int
-dpif_linux_flow_put(struct dpif *dpif_, struct odp_flow_put *put)
+xfif_linux_flow_put(struct xfif *xfif_, struct xflow_flow_put *put)
 {
-    return do_ioctl(dpif_, ODP_FLOW_PUT, put);
+    return do_ioctl(xfif_, XFLOW_FLOW_PUT, put);
 }
 
 static int
-dpif_linux_flow_del(struct dpif *dpif_, struct odp_flow *flow)
+xfif_linux_flow_del(struct xfif *xfif_, struct xflow_flow *flow)
 {
-    return do_ioctl(dpif_, ODP_FLOW_DEL, flow);
+    return do_ioctl(xfif_, XFLOW_FLOW_DEL, flow);
 }
 
 static int
-dpif_linux_flow_list(const struct dpif *dpif_, struct odp_flow flows[], int n)
+xfif_linux_flow_list(const struct xfif *xfif_, struct xflow_flow flows[], int n)
 {
-    struct odp_flowvec fv;
+    struct xflow_flowvec fv;
     int error;
 
     fv.flows = flows;
     fv.n_flows = n;
-    error = do_ioctl(dpif_, ODP_FLOW_LIST, &fv);
+    error = do_ioctl(xfif_, XFLOW_FLOW_LIST, &fv);
     return error ? -error : fv.n_flows;
 }
 
 static int
-dpif_linux_execute(struct dpif *dpif_, uint16_t in_port,
-                   const union odp_action actions[], int n_actions,
+xfif_linux_execute(struct xfif *xfif_, uint16_t in_port,
+                   const union xflow_action actions[], int n_actions,
                    const struct ofpbuf *buf)
 {
-    struct odp_execute execute;
+    struct xflow_execute execute;
     memset(&execute, 0, sizeof execute);
     execute.in_port = in_port;
-    execute.actions = (union odp_action *) actions;
+    execute.actions = (union xflow_action *) actions;
     execute.n_actions = n_actions;
     execute.data = buf->data;
     execute.length = buf->size;
-    return do_ioctl(dpif_, ODP_EXECUTE, &execute);
+    return do_ioctl(xfif_, XFLOW_EXECUTE, &execute);
 }
 
 static int
-dpif_linux_recv_get_mask(const struct dpif *dpif_, int *listen_mask)
+xfif_linux_recv_get_mask(const struct xfif *xfif_, int *listen_mask)
 {
-    return do_ioctl(dpif_, ODP_GET_LISTEN_MASK, listen_mask);
+    return do_ioctl(xfif_, XFLOW_GET_LISTEN_MASK, listen_mask);
 }
 
 static int
-dpif_linux_recv_set_mask(struct dpif *dpif_, int listen_mask)
+xfif_linux_recv_set_mask(struct xfif *xfif_, int listen_mask)
 {
-    return do_ioctl(dpif_, ODP_SET_LISTEN_MASK, &listen_mask);
+    return do_ioctl(xfif_, XFLOW_SET_LISTEN_MASK, &listen_mask);
 }
 
 static int
-dpif_linux_get_sflow_probability(const struct dpif *dpif_,
+xfif_linux_get_sflow_probability(const struct xfif *xfif_,
                                  uint32_t *probability)
 {
-    return do_ioctl(dpif_, ODP_GET_SFLOW_PROBABILITY, probability);
+    return do_ioctl(xfif_, XFLOW_GET_SFLOW_PROBABILITY, probability);
 }
 
 static int
-dpif_linux_set_sflow_probability(struct dpif *dpif_, uint32_t probability)
+xfif_linux_set_sflow_probability(struct xfif *xfif_, uint32_t probability)
 {
-    return do_ioctl(dpif_, ODP_SET_SFLOW_PROBABILITY, &probability);
+    return do_ioctl(xfif_, XFLOW_SET_SFLOW_PROBABILITY, &probability);
 }
 
 static int
-dpif_linux_recv(struct dpif *dpif_, struct ofpbuf **bufp)
+xfif_linux_recv(struct xfif *xfif_, struct ofpbuf **bufp)
 {
-    struct dpif_linux *dpif = dpif_linux_cast(dpif_);
+    struct xfif_linux *xfif = xfif_linux_cast(xfif_);
     struct ofpbuf *buf;
     int retval;
     int error;
 
-    buf = ofpbuf_new(65536 + DPIF_RECV_MSG_PADDING);
-    ofpbuf_reserve(buf, DPIF_RECV_MSG_PADDING);
-    retval = read(dpif->fd, ofpbuf_tail(buf), ofpbuf_tailroom(buf));
+    buf = ofpbuf_new(65536 + XFIF_RECV_MSG_PADDING);
+    ofpbuf_reserve(buf, XFIF_RECV_MSG_PADDING);
+    retval = read(xfif->fd, ofpbuf_tail(buf), ofpbuf_tailroom(buf));
     if (retval < 0) {
         error = errno;
         if (error != EAGAIN) {
             VLOG_WARN_RL(&error_rl, "%s: read failed: %s",
-                         dpif_name(dpif_), strerror(error));
+                         xfif_name(xfif_), strerror(error));
         }
-    } else if (retval >= sizeof(struct odp_msg)) {
-        struct odp_msg *msg = buf->data;
+    } else if (retval >= sizeof(struct xflow_msg)) {
+        struct xflow_msg *msg = buf->data;
         if (msg->length <= retval) {
             buf->size += retval;
             *bufp = buf;
@@ -481,16 +481,16 @@ dpif_linux_recv(struct dpif *dpif_, struct ofpbuf **bufp)
         } else {
             VLOG_WARN_RL(&error_rl, "%s: discarding message truncated "
                          "from %"PRIu32" bytes to %d",
-                         dpif_name(dpif_), msg->length, retval);
+                         xfif_name(xfif_), msg->length, retval);
             error = ERANGE;
         }
     } else if (!retval) {
-        VLOG_WARN_RL(&error_rl, "%s: unexpected end of file", dpif_name(dpif_));
+        VLOG_WARN_RL(&error_rl, "%s: unexpected end of file", xfif_name(xfif_));
         error = EPROTO;
     } else {
         VLOG_WARN_RL(&error_rl,
                      "%s: discarding too-short message (%d bytes)",
-                     dpif_name(dpif_), retval);
+                     xfif_name(xfif_), retval);
         error = ERANGE;
     }
 
@@ -500,55 +500,55 @@ dpif_linux_recv(struct dpif *dpif_, struct ofpbuf **bufp)
 }
 
 static void
-dpif_linux_recv_wait(struct dpif *dpif_)
+xfif_linux_recv_wait(struct xfif *xfif_)
 {
-    struct dpif_linux *dpif = dpif_linux_cast(dpif_);
-    poll_fd_wait(dpif->fd, POLLIN);
+    struct xfif_linux *xfif = xfif_linux_cast(xfif_);
+    poll_fd_wait(xfif->fd, POLLIN);
 }
 
-const struct dpif_class dpif_linux_class = {
+const struct xfif_class xfif_linux_class = {
     "system",
     NULL,
     NULL,
-    dpif_linux_enumerate,
-    dpif_linux_open,
-    dpif_linux_close,
-    dpif_linux_get_all_names,
-    dpif_linux_destroy,
-    dpif_linux_get_stats,
-    dpif_linux_get_drop_frags,
-    dpif_linux_set_drop_frags,
-    dpif_linux_port_add,
-    dpif_linux_port_del,
-    dpif_linux_port_query_by_number,
-    dpif_linux_port_query_by_name,
-    dpif_linux_port_list,
-    dpif_linux_port_poll,
-    dpif_linux_port_poll_wait,
-    dpif_linux_port_group_get,
-    dpif_linux_port_group_set,
-    dpif_linux_flow_get,
-    dpif_linux_flow_put,
-    dpif_linux_flow_del,
-    dpif_linux_flow_flush,
-    dpif_linux_flow_list,
-    dpif_linux_execute,
-    dpif_linux_recv_get_mask,
-    dpif_linux_recv_set_mask,
-    dpif_linux_get_sflow_probability,
-    dpif_linux_set_sflow_probability,
-    dpif_linux_recv,
-    dpif_linux_recv_wait,
+    xfif_linux_enumerate,
+    xfif_linux_open,
+    xfif_linux_close,
+    xfif_linux_get_all_names,
+    xfif_linux_destroy,
+    xfif_linux_get_stats,
+    xfif_linux_get_drop_frags,
+    xfif_linux_set_drop_frags,
+    xfif_linux_port_add,
+    xfif_linux_port_del,
+    xfif_linux_port_query_by_number,
+    xfif_linux_port_query_by_name,
+    xfif_linux_port_list,
+    xfif_linux_port_poll,
+    xfif_linux_port_poll_wait,
+    xfif_linux_port_group_get,
+    xfif_linux_port_group_set,
+    xfif_linux_flow_get,
+    xfif_linux_flow_put,
+    xfif_linux_flow_del,
+    xfif_linux_flow_flush,
+    xfif_linux_flow_list,
+    xfif_linux_execute,
+    xfif_linux_recv_get_mask,
+    xfif_linux_recv_set_mask,
+    xfif_linux_get_sflow_probability,
+    xfif_linux_set_sflow_probability,
+    xfif_linux_recv,
+    xfif_linux_recv_wait,
 };
 \f
 static int get_openvswitch_major(void);
 static int get_major(const char *target);
 
 static int
-do_ioctl(const struct dpif *dpif_, int cmd, const void *arg)
+do_ioctl(const struct xfif *xfif_, int cmd, const void *arg)
 {
-    struct dpif_linux *dpif = dpif_linux_cast(dpif_);
-    return ioctl(dpif->fd, cmd, arg) ? errno : 0;
+    struct xfif_linux *xfif = xfif_linux_cast(xfif_);
+    return ioctl(xfif->fd, cmd, arg) ? errno : 0;
 }
 
 static int
@@ -589,7 +589,7 @@ lookup_minor(const char *name, int *minorp)
         VLOG_WARN("%s ethtool bus_info has unexpected format", name);
         error = EPROTOTYPE;
         goto error_close_sock;
-    } else if (port_no != ODPP_LOCAL) {
+    } else if (port_no != XFLOWP_LOCAL) {
         /* This is an Open vSwitch device but not the local port.  We
          * intentionally support only using the name of the local port as the
          * name of a datapath; otherwise, it would be too difficult to
@@ -731,14 +731,14 @@ get_major(const char *target)
 }
 
 static int
-finish_open(struct dpif *dpif_, const char *local_ifname)
+finish_open(struct xfif *xfif_, const char *local_ifname)
 {
-    struct dpif_linux *dpif = dpif_linux_cast(dpif_);
-    dpif->local_ifname = xstrdup(local_ifname);
-    dpif->local_ifindex = if_nametoindex(local_ifname);
-    if (!dpif->local_ifindex) {
+    struct xfif_linux *xfif = xfif_linux_cast(xfif_);
+    xfif->local_ifname = xstrdup(local_ifname);
+    xfif->local_ifindex = if_nametoindex(local_ifname);
+    if (!xfif->local_ifindex) {
         int error = errno;
-        dpif_uninit(dpif_, true);
+        xfif_uninit(xfif_, true);
         VLOG_WARN("could not get ifindex of %s device: %s",
                   local_ifname, strerror(errno));
         return error;
@@ -747,22 +747,22 @@ finish_open(struct dpif *dpif_, const char *local_ifname)
 }
 
 static int
-create_minor(const char *name, int minor, struct dpif **dpifp)
+create_minor(const char *name, int minor, struct xfif **xfifp)
 {
-    int error = open_minor(minor, dpifp);
+    int error = open_minor(minor, xfifp);
     if (!error) {
-        error = do_ioctl(*dpifp, ODP_DP_CREATE, name);
+        error = do_ioctl(*xfifp, XFLOW_DP_CREATE, name);
         if (!error) {
-            error = finish_open(*dpifp, name);
+            error = finish_open(*xfifp, name);
         } else {
-            dpif_uninit(*dpifp, true);
+            xfif_uninit(*xfifp, true);
         }
     }
     return error;
 }
 
 static int
-open_minor(int minor, struct dpif **dpifp)
+open_minor(int minor, struct xfif **xfifp)
 {
     int error;
     char *fn;
@@ -775,25 +775,25 @@ open_minor(int minor, struct dpif **dpifp)
 
     fd = open(fn, O_RDONLY | O_NONBLOCK);
     if (fd >= 0) {
-        struct dpif_linux *dpif = xmalloc(sizeof *dpif);
-        error = rtnetlink_notifier_register(&dpif->port_notifier,
-                                           dpif_linux_port_changed, dpif);
+        struct xfif_linux *xfif = xmalloc(sizeof *xfif);
+        error = rtnetlink_notifier_register(&xfif->port_notifier,
+                                           xfif_linux_port_changed, xfif);
         if (!error) {
             char *name;
 
             name = xasprintf("dp%d", minor);
-            dpif_init(&dpif->dpif, &dpif_linux_class, name, minor, minor);
+            xfif_init(&xfif->xfif, &xfif_linux_class, name, minor, minor);
             free(name);
 
-            dpif->fd = fd;
-            dpif->local_ifname = NULL;
-            dpif->minor = minor;
-            dpif->local_ifindex = 0;
-            shash_init(&dpif->changed_ports);
-            dpif->change_error = false;
-            *dpifp = &dpif->dpif;
+            xfif->fd = fd;
+            xfif->local_ifname = NULL;
+            xfif->minor = minor;
+            xfif->local_ifindex = 0;
+            shash_init(&xfif->changed_ports);
+            xfif->change_error = false;
+            *xfifp = &xfif->xfif;
         } else {
-            free(dpif);
+            free(xfif);
         }
     } else {
         error = errno;
@@ -805,20 +805,20 @@ open_minor(int minor, struct dpif **dpifp)
 }
 
 static void
-dpif_linux_port_changed(const struct rtnetlink_change *change, void *dpif_)
+xfif_linux_port_changed(const struct rtnetlink_change *change, void *xfif_)
 {
-    struct dpif_linux *dpif = dpif_;
+    struct xfif_linux *xfif = xfif_;
 
     if (change) {
-        if (change->master_ifindex == dpif->local_ifindex
+        if (change->master_ifindex == xfif->local_ifindex
             && (change->nlmsg_type == RTM_NEWLINK
                 || change->nlmsg_type == RTM_DELLINK))
         {
             /* Our datapath changed, either adding a new port or deleting an
              * existing one. */
-            shash_add_once(&dpif->changed_ports, change->ifname, NULL);
+            shash_add_once(&xfif->changed_ports, change->ifname, NULL);
         }
     } else {
-        dpif->change_error = true;
+        xfif->change_error = true;
     }
 }
diff --git a/lib/xfif-netdev.c b/lib/xfif-netdev.c
new file mode 100644 (file)
index 0000000..57be768
--- /dev/null
@@ -0,0 +1,1381 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "xfif.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "csum.h"
+#include "flow.h"
+#include "hmap.h"
+#include "list.h"
+#include "netdev.h"
+#include "xflow-util.h"
+#include "ofp-print.h"
+#include "ofpbuf.h"
+#include "packets.h"
+#include "poll-loop.h"
+#include "queue.h"
+#include "timeval.h"
+#include "util.h"
+#include "xfif-provider.h"
+
+#include "vlog.h"
+#define THIS_MODULE VLM_xfif_netdev
+
+/* Configuration parameters. */
+enum { N_QUEUES = 2 };          /* Number of queues for xfif_recv(). */
+enum { MAX_QUEUE_LEN = 100 };   /* Maximum number of packets per queue. */
+enum { N_GROUPS = 16 };         /* Number of port groups. */
+enum { MAX_PORTS = 256 };       /* Maximum number of ports. */
+enum { MAX_FLOWS = 65536 };     /* Maximum number of flows in flow table. */
+
+/* Enough headroom to add a vlan tag, plus an extra 2 bytes to allow IP
+ * headers to be aligned on a 4-byte boundary.  */
+enum { XF_NETDEV_HEADROOM = 2 + VLAN_HEADER_LEN };
+
+/* Datapath based on the network device interface from netdev.h. */
+struct xf_netdev {
+    struct list node;
+    int xf_idx;
+    int open_cnt;
+    bool destroyed;
+
+    bool drop_frags;            /* Drop all IP fragments, if true. */
+    struct ovs_queue queues[N_QUEUES]; /* Messages queued for xfif_recv(). */
+    struct hmap flow_table;     /* Flow table. */
+    struct xflow_port_group groups[N_GROUPS];
+
+    /* Statistics. */
+    long long int n_frags;      /* Number of dropped IP fragments. */
+    long long int n_hit;        /* Number of flow table matches. */
+    long long int n_missed;     /* Number of flow table misses. */
+    long long int n_lost;       /* Number of misses not passed to client. */
+
+    /* Ports. */
+    int n_ports;
+    struct xf_netdev_port *ports[MAX_PORTS];
+    struct list port_list;
+    unsigned int serial;
+};
+
+/* A port in a netdev-based datapath. */
+struct xf_netdev_port {
+    int port_no;                /* Index into xf_netdev's 'ports'. */
+    struct list node;           /* Element in xf_netdev's 'port_list'. */
+    struct netdev *netdev;
+    bool internal;              /* Internal port (as XFLOW_PORT_INTERNAL)? */
+};
+
+/* A flow in xf_netdev's 'flow_table'. */
+struct xf_netdev_flow {
+    struct hmap_node node;      /* Element in xf_netdev's 'flow_table'. */
+    struct xflow_key key;
+
+    /* Statistics. */
+    struct timeval used;        /* Last used time, in milliseconds. */
+    long long int packet_count; /* Number of packets matched. */
+    long long int byte_count;   /* Number of bytes matched. */
+    uint8_t ip_tos;             /* IP TOS value. */
+    uint16_t tcp_ctl;           /* Bitwise-OR of seen tcp_ctl values. */
+
+    /* Actions. */
+    union xflow_action *actions;
+    unsigned int n_actions;
+};
+
+/* Interface to netdev-based datapath. */
+struct xfif_netdev {
+    struct xfif xfif;
+    struct xf_netdev *xf;
+    int listen_mask;
+    unsigned int xf_serial;
+};
+
+/* All netdev-based datapaths. */
+static struct xf_netdev *xf_netdevs[256];
+struct list xf_netdev_list = LIST_INITIALIZER(&xf_netdev_list);
+enum { N_XF_NETDEVS = ARRAY_SIZE(xf_netdevs) };
+
+/* Maximum port MTU seen so far. */
+static int max_mtu = ETH_PAYLOAD_MAX;
+
+static int get_port_by_number(struct xf_netdev *, uint16_t port_no,
+                              struct xf_netdev_port **portp);
+static int get_port_by_name(struct xf_netdev *, const char *devname,
+                            struct xf_netdev_port **portp);
+static void xf_netdev_free(struct xf_netdev *);
+static void xf_netdev_flow_flush(struct xf_netdev *);
+static int do_add_port(struct xf_netdev *, const char *devname, uint16_t flags,
+                       uint16_t port_no);
+static int do_del_port(struct xf_netdev *, uint16_t port_no);
+static int xf_netdev_output_control(struct xf_netdev *, const struct ofpbuf *,
+                                    int queue_no, int port_no, uint32_t arg);
+static int xf_netdev_execute_actions(struct xf_netdev *,
+                                     struct ofpbuf *, struct xflow_key *,
+                                     const union xflow_action *, int n);
+
+static struct xfif_netdev *
+xfif_netdev_cast(const struct xfif *xfif)
+{
+    xfif_assert_class(xfif, &xfif_netdev_class);
+    return CONTAINER_OF(xfif, struct xfif_netdev, xfif);
+}
+
+static struct xf_netdev *
+get_xf_netdev(const struct xfif *xfif)
+{
+    return xfif_netdev_cast(xfif)->xf;
+}
+
+static int
+name_to_xf_idx(const char *name)
+{
+    if (!strncmp(name, "xf", 2) && isdigit((unsigned char)name[2])) {
+        int xf_idx = atoi(name + 2);
+        if (xf_idx >= 0 && xf_idx < N_XF_NETDEVS) {
+            return xf_idx;
+        }
+    }
+    return -1;
+}
+
+static struct xf_netdev *
+find_xf_netdev(const char *name)
+{
+    int xf_idx;
+    size_t i;
+
+    xf_idx = name_to_xf_idx(name);
+    if (xf_idx >= 0) {
+        return xf_netdevs[xf_idx];
+    }
+
+    for (i = 0; i < N_XF_NETDEVS; i++) {
+        struct xf_netdev *xf = xf_netdevs[i];
+        if (xf) {
+            struct xf_netdev_port *port;
+            if (!get_port_by_name(xf, name, &port)) {
+                return xf;
+            }
+        }
+    }
+    return NULL;
+}
+
+static struct xfif *
+create_xfif_netdev(struct xf_netdev *xf)
+{
+    struct xfif_netdev *xfif;
+    char *xfname;
+
+    xf->open_cnt++;
+
+    xfname = xasprintf("xf%d", xf->xf_idx);
+    xfif = xmalloc(sizeof *xfif);
+    xfif_init(&xfif->xfif, &xfif_netdev_class, xfname, xf->xf_idx, xf->xf_idx);
+    xfif->xf = xf;
+    xfif->listen_mask = 0;
+    xfif->xf_serial = xf->serial;
+    free(xfname);
+
+    return &xfif->xfif;
+}
+
+static int
+create_xf_netdev(const char *name, int xf_idx, struct xfif **xfifp)
+{
+    struct xf_netdev *xf;
+    int error;
+    int i;
+
+    if (xf_netdevs[xf_idx]) {
+        return EBUSY;
+    }
+
+    /* Create datapath. */
+    xf_netdevs[xf_idx] = xf = xzalloc(sizeof *xf);
+    list_push_back(&xf_netdev_list, &xf->node);
+    xf->xf_idx = xf_idx;
+    xf->open_cnt = 0;
+    xf->drop_frags = false;
+    for (i = 0; i < N_QUEUES; i++) {
+        queue_init(&xf->queues[i]);
+    }
+    hmap_init(&xf->flow_table);
+    for (i = 0; i < N_GROUPS; i++) {
+        xf->groups[i].ports = NULL;
+        xf->groups[i].n_ports = 0;
+        xf->groups[i].group = i;
+    }
+    list_init(&xf->port_list);
+    error = do_add_port(xf, name, XFLOW_PORT_INTERNAL, XFLOWP_LOCAL);
+    if (error) {
+        xf_netdev_free(xf);
+        return ENODEV;
+    }
+
+    *xfifp = create_xfif_netdev(xf);
+    return 0;
+}
+
+static int
+xfif_netdev_open(const char *name, const char *type OVS_UNUSED, bool create,
+                 struct xfif **xfifp)
+{
+    if (create) {
+        if (find_xf_netdev(name)) {
+            return EEXIST;
+        } else {
+            int xf_idx = name_to_xf_idx(name);
+            if (xf_idx >= 0) {
+                return create_xf_netdev(name, xf_idx, xfifp);
+            } else {
+                /* Scan for unused xf_idx number. */
+                for (xf_idx = 0; xf_idx < N_XF_NETDEVS; xf_idx++) {
+                    int error = create_xf_netdev(name, xf_idx, xfifp);
+                    if (error != EBUSY) {
+                        return error;
+                    }
+                }
+
+                /* All datapath numbers in use. */
+                return ENOBUFS;
+            }
+        }
+    } else {
+        struct xf_netdev *xf = find_xf_netdev(name);
+        if (xf) {
+            *xfifp = create_xfif_netdev(xf);
+            return 0;
+        } else {
+            return ENODEV;
+        }
+    }
+}
+
+static void
+xf_netdev_free(struct xf_netdev *xf)
+{
+    int i;
+
+    xf_netdev_flow_flush(xf);
+    while (xf->n_ports > 0) {
+        struct xf_netdev_port *port = CONTAINER_OF(
+            xf->port_list.next, struct xf_netdev_port, node);
+        do_del_port(xf, port->port_no);
+    }
+    for (i = 0; i < N_QUEUES; i++) {
+        queue_destroy(&xf->queues[i]);
+    }
+    hmap_destroy(&xf->flow_table);
+    for (i = 0; i < N_GROUPS; i++) {
+        free(xf->groups[i].ports);
+    }
+    xf_netdevs[xf->xf_idx] = NULL;
+    list_remove(&xf->node);
+    free(xf);
+}
+
+static void
+xfif_netdev_close(struct xfif *xfif)
+{
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+    assert(xf->open_cnt > 0);
+    if (--xf->open_cnt == 0 && xf->destroyed) {
+        xf_netdev_free(xf);
+    }
+    free(xfif);
+}
+
+static int
+xfif_netdev_destroy(struct xfif *xfif)
+{
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+    xf->destroyed = true;
+    return 0;
+}
+
+static int
+xfif_netdev_get_stats(const struct xfif *xfif, struct xflow_stats *stats)
+{
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+    memset(stats, 0, sizeof *stats);
+    stats->n_flows = hmap_count(&xf->flow_table);
+    stats->cur_capacity = hmap_capacity(&xf->flow_table);
+    stats->max_capacity = MAX_FLOWS;
+    stats->n_ports = xf->n_ports;
+    stats->max_ports = MAX_PORTS;
+    stats->max_groups = N_GROUPS;
+    stats->n_frags = xf->n_frags;
+    stats->n_hit = xf->n_hit;
+    stats->n_missed = xf->n_missed;
+    stats->n_lost = xf->n_lost;
+    stats->max_miss_queue = MAX_QUEUE_LEN;
+    stats->max_action_queue = MAX_QUEUE_LEN;
+    return 0;
+}
+
+static int
+xfif_netdev_get_drop_frags(const struct xfif *xfif, bool *drop_fragsp)
+{
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+    *drop_fragsp = xf->drop_frags;
+    return 0;
+}
+
+static int
+xfif_netdev_set_drop_frags(struct xfif *xfif, bool drop_frags)
+{
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+    xf->drop_frags = drop_frags;
+    return 0;
+}
+
+static int
+do_add_port(struct xf_netdev *xf, const char *devname, uint16_t flags,
+            uint16_t port_no)
+{
+    bool internal = (flags & XFLOW_PORT_INTERNAL) != 0;
+    struct xf_netdev_port *port;
+    struct netdev_options netdev_options;
+    struct netdev *netdev;
+    int mtu;
+    int error;
+
+    /* XXX reject devices already in some xf_netdev. */
+
+    /* Open and validate network device. */
+    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 {
+        netdev_options.may_open = true;
+    }
+
+    error = netdev_open(&netdev_options, &netdev);
+    if (error) {
+        return error;
+    }
+    /* XXX reject loopback devices */
+    /* XXX reject non-Ethernet devices */
+
+    error = netdev_turn_flags_on(netdev, NETDEV_PROMISC, false);
+    if (error) {
+        netdev_close(netdev);
+        return error;
+    }
+
+    port = xmalloc(sizeof *port);
+    port->port_no = port_no;
+    port->netdev = netdev;
+    port->internal = internal;
+
+    netdev_get_mtu(netdev, &mtu);
+    if (mtu > max_mtu) {
+        max_mtu = mtu;
+    }
+
+    list_push_back(&xf->port_list, &port->node);
+    xf->ports[port_no] = port;
+    xf->n_ports++;
+    xf->serial++;
+
+    return 0;
+}
+
+static int
+xfif_netdev_port_add(struct xfif *xfif, const char *devname, uint16_t flags,
+                     uint16_t *port_nop)
+{
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+    int port_no;
+
+    for (port_no = 0; port_no < MAX_PORTS; port_no++) {
+        if (!xf->ports[port_no]) {
+            *port_nop = port_no;
+            return do_add_port(xf, devname, flags, port_no);
+        }
+    }
+    return EFBIG;
+}
+
+static int
+xfif_netdev_port_del(struct xfif *xfif, uint16_t port_no)
+{
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+    return port_no == XFLOWP_LOCAL ? EINVAL : do_del_port(xf, port_no);
+}
+
+static bool
+is_valid_port_number(uint16_t port_no)
+{
+    return port_no < MAX_PORTS;
+}
+
+static int
+get_port_by_number(struct xf_netdev *xf,
+                   uint16_t port_no, struct xf_netdev_port **portp)
+{
+    if (!is_valid_port_number(port_no)) {
+        *portp = NULL;
+        return EINVAL;
+    } else {
+        *portp = xf->ports[port_no];
+        return *portp ? 0 : ENOENT;
+    }
+}
+
+static int
+get_port_by_name(struct xf_netdev *xf,
+                 const char *devname, struct xf_netdev_port **portp)
+{
+    struct xf_netdev_port *port;
+
+    LIST_FOR_EACH (port, struct xf_netdev_port, node, &xf->port_list) {
+        if (!strcmp(netdev_get_name(port->netdev), devname)) {
+            *portp = port;
+            return 0;
+        }
+    }
+    return ENOENT;
+}
+
+static int
+do_del_port(struct xf_netdev *xf, uint16_t port_no)
+{
+    struct xf_netdev_port *port;
+    char *name;
+    int error;
+
+    error = get_port_by_number(xf, port_no, &port);
+    if (error) {
+        return error;
+    }
+
+    list_remove(&port->node);
+    xf->ports[port->port_no] = NULL;
+    xf->n_ports--;
+    xf->serial++;
+
+    name = xstrdup(netdev_get_name(port->netdev));
+    netdev_close(port->netdev);
+
+    free(name);
+    free(port);
+
+    return 0;
+}
+
+static void
+answer_port_query(const struct xf_netdev_port *port, struct xflow_port *xflow_port)
+{
+    memset(xflow_port, 0, sizeof *xflow_port);
+    ovs_strlcpy(xflow_port->devname, netdev_get_name(port->netdev),
+                sizeof xflow_port->devname);
+    xflow_port->port = port->port_no;
+    xflow_port->flags = port->internal ? XFLOW_PORT_INTERNAL : 0;
+}
+
+static int
+xfif_netdev_port_query_by_number(const struct xfif *xfif, uint16_t port_no,
+                                 struct xflow_port *xflow_port)
+{
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+    struct xf_netdev_port *port;
+    int error;
+
+    error = get_port_by_number(xf, port_no, &port);
+    if (!error) {
+        answer_port_query(port, xflow_port);
+    }
+    return error;
+}
+
+static int
+xfif_netdev_port_query_by_name(const struct xfif *xfif, const char *devname,
+                               struct xflow_port *xflow_port)
+{
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+    struct xf_netdev_port *port;
+    int error;
+
+    error = get_port_by_name(xf, devname, &port);
+    if (!error) {
+        answer_port_query(port, xflow_port);
+    }
+    return error;
+}
+
+static void
+xf_netdev_free_flow(struct xf_netdev *xf, struct xf_netdev_flow *flow)
+{
+    hmap_remove(&xf->flow_table, &flow->node);
+    free(flow->actions);
+    free(flow);
+}
+
+static void
+xf_netdev_flow_flush(struct xf_netdev *xf)
+{
+    struct xf_netdev_flow *flow, *next;
+
+    HMAP_FOR_EACH_SAFE (flow, next, struct xf_netdev_flow, node,
+                        &xf->flow_table) {
+        xf_netdev_free_flow(xf, flow);
+    }
+}
+
+static int
+xfif_netdev_flow_flush(struct xfif *xfif)
+{
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+    xf_netdev_flow_flush(xf);
+    return 0;
+}
+
+static int
+xfif_netdev_port_list(const struct xfif *xfif, struct xflow_port *ports, int n)
+{
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+    struct xf_netdev_port *port;
+    int i;
+
+    i = 0;
+    LIST_FOR_EACH (port, struct xf_netdev_port, node, &xf->port_list) {
+        struct xflow_port *xflow_port = &ports[i];
+        if (i >= n) {
+            break;
+        }
+        answer_port_query(port, xflow_port);
+        i++;
+    }
+    return xf->n_ports;
+}
+
+static int
+xfif_netdev_port_poll(const struct xfif *xfif_, char **devnamep OVS_UNUSED)
+{
+    struct xfif_netdev *xfif = xfif_netdev_cast(xfif_);
+    if (xfif->xf_serial != xfif->xf->serial) {
+        xfif->xf_serial = xfif->xf->serial;
+        return ENOBUFS;
+    } else {
+        return EAGAIN;
+    }
+}
+
+static void
+xfif_netdev_port_poll_wait(const struct xfif *xfif_)
+{
+    struct xfif_netdev *xfif = xfif_netdev_cast(xfif_);
+    if (xfif->xf_serial != xfif->xf->serial) {
+        poll_immediate_wake();
+    }
+}
+
+static int
+get_port_group(const struct xfif *xfif, int group_no,
+               struct xflow_port_group **groupp)
+{
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+
+    if (group_no >= 0 && group_no < N_GROUPS) {
+        *groupp = &xf->groups[group_no];
+        return 0;
+    } else {
+        *groupp = NULL;
+        return EINVAL;
+    }
+}
+
+static int
+xfif_netdev_port_group_get(const struct xfif *xfif, int group_no,
+                           uint16_t ports[], int n)
+{
+    struct xflow_port_group *group;
+    int error;
+
+    if (n < 0) {
+        return -EINVAL;
+    }
+
+    error = get_port_group(xfif, group_no, &group);
+    if (!error) {
+        memcpy(ports, group->ports, MIN(n, group->n_ports) * sizeof *ports);
+        return group->n_ports;
+    } else {
+        return -error;
+    }
+}
+
+static int
+xfif_netdev_port_group_set(struct xfif *xfif, int group_no,
+                           const uint16_t ports[], int n)
+{
+    struct xflow_port_group *group;
+    int error;
+
+    if (n < 0 || n > MAX_PORTS) {
+        return EINVAL;
+    }
+
+    error = get_port_group(xfif, group_no, &group);
+    if (!error) {
+        free(group->ports);
+        group->ports = xmemdup(ports, n * sizeof *group->ports);
+        group->n_ports = n;
+        group->group = group_no;
+    }
+    return error;
+}
+
+static struct xf_netdev_flow *
+xf_netdev_lookup_flow(const struct xf_netdev *xf,
+                      const struct xflow_key *key)
+{
+    struct xf_netdev_flow *flow;
+
+    HMAP_FOR_EACH_WITH_HASH (flow, struct xf_netdev_flow, node,
+                             xflow_key_hash(key, 0), &xf->flow_table) {
+        if (xflow_key_equal(&flow->key, key)) {
+            return flow;
+        }
+    }
+    return NULL;
+}
+
+static void
+answer_flow_query(struct xf_netdev_flow *flow, uint32_t query_flags,
+                  struct xflow_flow *xflow_flow)
+{
+    if (flow) {
+        xflow_flow->key = flow->key;
+        xflow_flow->stats.n_packets = flow->packet_count;
+        xflow_flow->stats.n_bytes = flow->byte_count;
+        xflow_flow->stats.used_sec = flow->used.tv_sec;
+        xflow_flow->stats.used_nsec = flow->used.tv_usec * 1000;
+        xflow_flow->stats.tcp_flags = TCP_FLAGS(flow->tcp_ctl);
+        xflow_flow->stats.ip_tos = flow->ip_tos;
+        xflow_flow->stats.error = 0;
+        if (xflow_flow->n_actions > 0) {
+            unsigned int n = MIN(xflow_flow->n_actions, flow->n_actions);
+            memcpy(xflow_flow->actions, flow->actions,
+                   n * sizeof *xflow_flow->actions);
+            xflow_flow->n_actions = flow->n_actions;
+        }
+
+        if (query_flags & XFLOWFF_ZERO_TCP_FLAGS) {
+            flow->tcp_ctl = 0;
+        }
+
+    } else {
+        xflow_flow->stats.error = ENOENT;
+    }
+}
+
+static int
+xfif_netdev_flow_get(const struct xfif *xfif, struct xflow_flow flows[], int n)
+{
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+    int i;
+
+    for (i = 0; i < n; i++) {
+        struct xflow_flow *xflow_flow = &flows[i];
+        answer_flow_query(xf_netdev_lookup_flow(xf, &xflow_flow->key),
+                          xflow_flow->flags, xflow_flow);
+    }
+    return 0;
+}
+
+static int
+xfif_netdev_validate_actions(const union xflow_action *actions, int n_actions,
+                             bool *mutates)
+{
+    unsigned int i;
+
+    *mutates = false;
+    for (i = 0; i < n_actions; i++) {
+        const union xflow_action *a = &actions[i];
+        switch (a->type) {
+        case XFLOWAT_OUTPUT:
+            if (a->output.port >= MAX_PORTS) {
+                return EINVAL;
+            }
+            break;
+
+        case XFLOWAT_OUTPUT_GROUP:
+            *mutates = true;
+            if (a->output_group.group >= N_GROUPS) {
+                return EINVAL;
+            }
+            break;
+
+        case XFLOWAT_CONTROLLER:
+            break;
+
+        case XFLOWAT_SET_DL_TCI:
+            *mutates = true;
+            if (a->dl_tci.mask != htons(VLAN_VID_MASK)
+                && a->dl_tci.mask != htons(VLAN_PCP_MASK)
+                && a->dl_tci.mask != htons(VLAN_VID_MASK | VLAN_PCP_MASK)) {
+                return EINVAL;
+            }
+            if (a->dl_tci.tci & ~a->dl_tci.mask){
+                return EINVAL;
+            }
+            break;
+
+        case XFLOWAT_SET_NW_TOS:
+            *mutates = true;
+            if (a->nw_tos.nw_tos & IP_ECN_MASK) {
+                return EINVAL;
+            }
+            break;
+
+        case XFLOWAT_STRIP_VLAN:
+        case XFLOWAT_SET_DL_SRC:
+        case XFLOWAT_SET_DL_DST:
+        case XFLOWAT_SET_NW_SRC:
+        case XFLOWAT_SET_NW_DST:
+        case XFLOWAT_SET_TP_SRC:
+        case XFLOWAT_SET_TP_DST:
+            *mutates = true;
+            break;
+
+        default:
+            return EOPNOTSUPP;
+        }
+    }
+    return 0;
+}
+
+static int
+set_flow_actions(struct xf_netdev_flow *flow, struct xflow_flow *xflow_flow)
+{
+    size_t n_bytes;
+    bool mutates;
+    int error;
+
+    if (xflow_flow->n_actions >= 4096 / sizeof *xflow_flow->actions) {
+        return EINVAL;
+    }
+    error = xfif_netdev_validate_actions(xflow_flow->actions,
+                                         xflow_flow->n_actions, &mutates);
+    if (error) {
+        return error;
+    }
+
+    n_bytes = xflow_flow->n_actions * sizeof *flow->actions;
+    flow->actions = xrealloc(flow->actions, n_bytes);
+    flow->n_actions = xflow_flow->n_actions;
+    memcpy(flow->actions, xflow_flow->actions, n_bytes);
+    return 0;
+}
+
+static int
+add_flow(struct xfif *xfif, struct xflow_flow *xflow_flow)
+{
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+    struct xf_netdev_flow *flow;
+    int error;
+
+    flow = xzalloc(sizeof *flow);
+    flow->key = xflow_flow->key;
+
+    error = set_flow_actions(flow, xflow_flow);
+    if (error) {
+        free(flow);
+        return error;
+    }
+
+    hmap_insert(&xf->flow_table, &flow->node,
+                xflow_key_hash(&flow->key, 0));
+    return 0;
+}
+
+static void
+clear_stats(struct xf_netdev_flow *flow)
+{
+    flow->used.tv_sec = 0;
+    flow->used.tv_usec = 0;
+    flow->packet_count = 0;
+    flow->byte_count = 0;
+    flow->ip_tos = 0;
+    flow->tcp_ctl = 0;
+}
+
+static int
+xfif_netdev_flow_put(struct xfif *xfif, struct xflow_flow_put *put)
+{
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+    struct xf_netdev_flow *flow;
+
+    flow = xf_netdev_lookup_flow(xf, &put->flow.key);
+    if (!flow) {
+        if (put->flags & XFLOWPF_CREATE) {
+            if (hmap_count(&xf->flow_table) < MAX_FLOWS) {
+                return add_flow(xfif, &put->flow);
+            } else {
+                return EFBIG;
+            }
+        } else {
+            return ENOENT;
+        }
+    } else {
+        if (put->flags & XFLOWPF_MODIFY) {
+            int error = set_flow_actions(flow, &put->flow);
+            if (!error && put->flags & XFLOWPF_ZERO_STATS) {
+                clear_stats(flow);
+            }
+            return error;
+        } else {
+            return EEXIST;
+        }
+    }
+}
+
+
+static int
+xfif_netdev_flow_del(struct xfif *xfif, struct xflow_flow *xflow_flow)
+{
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+    struct xf_netdev_flow *flow;
+
+    flow = xf_netdev_lookup_flow(xf, &xflow_flow->key);
+    if (flow) {
+        answer_flow_query(flow, 0, xflow_flow);
+        xf_netdev_free_flow(xf, flow);
+        return 0;
+    } else {
+        return ENOENT;
+    }
+}
+
+static int
+xfif_netdev_flow_list(const struct xfif *xfif, struct xflow_flow flows[], int n)
+{
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+    struct xf_netdev_flow *flow;
+    int i;
+
+    i = 0;
+    HMAP_FOR_EACH (flow, struct xf_netdev_flow, node, &xf->flow_table) {
+        if (i >= n) {
+            break;
+        }
+        answer_flow_query(flow, 0, &flows[i++]);
+    }
+    return hmap_count(&xf->flow_table);
+}
+
+static int
+xfif_netdev_execute(struct xfif *xfif, uint16_t in_port,
+                    const union xflow_action actions[], int n_actions,
+                    const struct ofpbuf *packet)
+{
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+    struct ofpbuf copy;
+    bool mutates;
+    struct xflow_key key;
+    flow_t flow;
+    int error;
+
+    if (packet->size < ETH_HEADER_LEN || packet->size > UINT16_MAX) {
+        return EINVAL;
+    }
+
+    error = xfif_netdev_validate_actions(actions, n_actions, &mutates);
+    if (error) {
+        return error;
+    }
+
+    if (mutates) {
+        /* We need a deep copy of 'packet' since we're going to modify its
+         * data. */
+        ofpbuf_init(&copy, XF_NETDEV_HEADROOM + packet->size);
+        copy.data = (char*)copy.base + XF_NETDEV_HEADROOM;
+        ofpbuf_put(&copy, packet->data, packet->size);
+    } else {
+        /* We still need a shallow copy of 'packet', even though we won't
+         * modify its data, because flow_extract() modifies packet->l2, etc.
+         * We could probably get away with modifying those but it's more polite
+         * if we don't. */
+        copy = *packet;
+    }
+    flow_extract(&copy, 0, in_port, &flow);
+    xflow_key_from_flow(&key, &flow);
+    error = xf_netdev_execute_actions(xf, &copy, &key, actions, n_actions);
+    if (mutates) {
+        ofpbuf_uninit(&copy);
+    }
+    return error;
+}
+
+static int
+xfif_netdev_recv_get_mask(const struct xfif *xfif, int *listen_mask)
+{
+    struct xfif_netdev *xfif_netdev = xfif_netdev_cast(xfif);
+    *listen_mask = xfif_netdev->listen_mask;
+    return 0;
+}
+
+static int
+xfif_netdev_recv_set_mask(struct xfif *xfif, int listen_mask)
+{
+    struct xfif_netdev *xfif_netdev = xfif_netdev_cast(xfif);
+    if (!(listen_mask & ~XFLOWL_ALL)) {
+        xfif_netdev->listen_mask = listen_mask;
+        return 0;
+    } else {
+        return EINVAL;
+    }
+}
+
+static struct ovs_queue *
+find_nonempty_queue(struct xfif *xfif)
+{
+    struct xfif_netdev *xfif_netdev = xfif_netdev_cast(xfif);
+    struct xf_netdev *xf = get_xf_netdev(xfif);
+    int mask = xfif_netdev->listen_mask;
+    int i;
+
+    for (i = 0; i < N_QUEUES; i++) {
+        struct ovs_queue *q = &xf->queues[i];
+        if (q->n && mask & (1u << i)) {
+            return q;
+        }
+    }
+    return NULL;
+}
+
+static int
+xfif_netdev_recv(struct xfif *xfif, struct ofpbuf **bufp)
+{
+    struct ovs_queue *q = find_nonempty_queue(xfif);
+    if (q) {
+        *bufp = queue_pop_head(q);
+        return 0;
+    } else {
+        return EAGAIN;
+    }
+}
+
+static void
+xfif_netdev_recv_wait(struct xfif *xfif)
+{
+    struct ovs_queue *q = find_nonempty_queue(xfif);
+    if (q) {
+        poll_immediate_wake();
+    } else {
+        /* No messages ready to be received, and xf_wait() will ensure that we
+         * wake up to queue new messages, so there is nothing to do. */
+    }
+}
+\f
+static void
+xf_netdev_flow_used(struct xf_netdev_flow *flow,
+                    const struct xflow_key *key,
+                    const struct ofpbuf *packet)
+{
+    time_timeval(&flow->used);
+    flow->packet_count++;
+    flow->byte_count += packet->size;
+    if (key->dl_type == htons(ETH_TYPE_IP)) {
+        struct ip_header *nh = packet->l3;
+        flow->ip_tos = nh->ip_tos;
+
+        if (key->nw_proto == IPPROTO_TCP) {
+            struct tcp_header *th = packet->l4;
+            flow->tcp_ctl |= th->tcp_ctl;
+        }
+    }
+}
+
+static void
+xf_netdev_port_input(struct xf_netdev *xf, struct xf_netdev_port *port,
+                     struct ofpbuf *packet)
+{
+    struct xf_netdev_flow *flow;
+    struct xflow_key key;
+    flow_t f;
+
+    if (flow_extract(packet, 0, port->port_no, &f) && xf->drop_frags) {
+        xf->n_frags++;
+        return;
+    }
+    xflow_key_from_flow(&key, &f);
+
+    flow = xf_netdev_lookup_flow(xf, &key);
+    if (flow) {
+        xf_netdev_flow_used(flow, &key, packet);
+        xf_netdev_execute_actions(xf, packet, &key,
+                                  flow->actions, flow->n_actions);
+        xf->n_hit++;
+    } else {
+        xf->n_missed++;
+        xf_netdev_output_control(xf, packet, _XFLOWL_MISS_NR, port->port_no, 0);
+    }
+}
+
+static void
+xf_netdev_run(void)
+{
+    struct ofpbuf packet;
+    struct xf_netdev *xf;
+
+    ofpbuf_init(&packet, XF_NETDEV_HEADROOM + max_mtu);
+    LIST_FOR_EACH (xf, struct xf_netdev, node, &xf_netdev_list) {
+        struct xf_netdev_port *port;
+
+        LIST_FOR_EACH (port, struct xf_netdev_port, node, &xf->port_list) {
+            int error;
+
+            /* Reset packet contents. */
+            packet.data = (char*)packet.base + XF_NETDEV_HEADROOM;
+            packet.size = 0;
+
+            error = netdev_recv(port->netdev, &packet);
+            if (!error) {
+                xf_netdev_port_input(xf, port, &packet);
+            } else if (error != EAGAIN) {
+                struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+                VLOG_ERR_RL(&rl, "error receiving data from %s: %s",
+                            netdev_get_name(port->netdev), strerror(error));
+            }
+        }
+    }
+    ofpbuf_uninit(&packet);
+}
+
+static void
+xf_netdev_wait(void)
+{
+    struct xf_netdev *xf;
+
+    LIST_FOR_EACH (xf, struct xf_netdev, node, &xf_netdev_list) {
+        struct xf_netdev_port *port;
+        LIST_FOR_EACH (port, struct xf_netdev_port, node, &xf->port_list) {
+            netdev_recv_wait(port->netdev);
+        }
+    }
+}
+
+
+/* Modify or add a 802.1Q header in 'packet' according to 'a'. */
+static void
+xf_netdev_set_dl_tci(struct ofpbuf *packet, struct xflow_key *key,
+                     const struct xflow_action_dl_tci *a)
+{
+    struct vlan_eth_header *veh;
+
+    if (key->dl_tci) {
+        veh = packet->l2;
+        veh->veth_tci = (veh->veth_tci & ~a->mask) | a->tci;
+    } else {
+        /* Insert new 802.1Q header. */
+        struct eth_header *eh = packet->l2;
+        struct vlan_eth_header tmp;
+        memcpy(tmp.veth_dst, eh->eth_dst, ETH_ADDR_LEN);
+        memcpy(tmp.veth_src, eh->eth_src, ETH_ADDR_LEN);
+        tmp.veth_type = htons(ETH_TYPE_VLAN);
+        tmp.veth_tci = htons(a->tci);
+        tmp.veth_next_type = eh->eth_type;
+
+        veh = ofpbuf_push_uninit(packet, VLAN_HEADER_LEN);
+        memcpy(veh, &tmp, sizeof tmp);
+        packet->l2 = (char*)packet->l2 - VLAN_HEADER_LEN;
+    }
+
+    key->dl_tci = veh->veth_tci | htons(XFLOW_TCI_PRESENT);
+}
+
+static void
+xf_netdev_strip_vlan(struct ofpbuf *packet, struct xflow_key *key)
+{
+    struct vlan_eth_header *veh = packet->l2;
+    if (veh->veth_type == htons(ETH_TYPE_VLAN)) {
+        struct eth_header tmp;
+
+        memcpy(tmp.eth_dst, veh->veth_dst, ETH_ADDR_LEN);
+        memcpy(tmp.eth_src, veh->veth_src, ETH_ADDR_LEN);
+        tmp.eth_type = veh->veth_next_type;
+
+        packet->size -= VLAN_HEADER_LEN;
+        packet->data = (char*)packet->data + VLAN_HEADER_LEN;
+        packet->l2 = (char*)packet->l2 + VLAN_HEADER_LEN;
+        memcpy(packet->data, &tmp, sizeof tmp);
+
+        key->dl_tci = htons(0);
+    }
+}
+
+static void
+xf_netdev_set_dl_src(struct ofpbuf *packet, struct xflow_key *key,
+                     const uint8_t dl_addr[ETH_ADDR_LEN])
+{
+    struct eth_header *eh = packet->l2;
+    memcpy(eh->eth_src, dl_addr, sizeof eh->eth_src);
+    memcpy(key->dl_src, dl_addr, sizeof key->dl_src);
+}
+
+static void
+xf_netdev_set_dl_dst(struct ofpbuf *packet, struct xflow_key *key,
+                     const uint8_t dl_addr[ETH_ADDR_LEN])
+{
+    struct eth_header *eh = packet->l2;
+    memcpy(eh->eth_dst, dl_addr, sizeof eh->eth_dst);
+    memcpy(key->dl_dst, dl_addr, sizeof key->dl_dst);
+}
+
+static void
+xf_netdev_set_nw_addr(struct ofpbuf *packet, struct xflow_key *key,
+                      const struct xflow_action_nw_addr *a)
+{
+    if (key->dl_type == htons(ETH_TYPE_IP)) {
+        struct ip_header *nh = packet->l3;
+        uint32_t *field;
+
+        field = a->type == XFLOWAT_SET_NW_SRC ? &nh->ip_src : &nh->ip_dst;
+        if (key->nw_proto == IP_TYPE_TCP) {
+            struct tcp_header *th = packet->l4;
+            th->tcp_csum = recalc_csum32(th->tcp_csum, *field, a->nw_addr);
+        } else if (key->nw_proto == IP_TYPE_UDP) {
+            struct udp_header *uh = packet->l4;
+            if (uh->udp_csum) {
+                uh->udp_csum = recalc_csum32(uh->udp_csum, *field, a->nw_addr);
+                if (!uh->udp_csum) {
+                    uh->udp_csum = 0xffff;
+                }
+            }
+        }
+        nh->ip_csum = recalc_csum32(nh->ip_csum, *field, a->nw_addr);
+        *field = a->nw_addr;
+
+        if (a->type == XFLOWAT_SET_NW_SRC) {
+            key->nw_src = a->type;
+        } else {
+            key->nw_dst = a->type;
+        }
+    }
+}
+
+static void
+xf_netdev_set_nw_tos(struct ofpbuf *packet, struct xflow_key *key,
+                     const struct xflow_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 | (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;
+        key->nw_tos = a->nw_tos;
+    }
+}
+
+static void
+xf_netdev_set_tp_port(struct ofpbuf *packet, struct xflow_key *key,
+                      const struct xflow_action_tp_port *a)
+{
+    if (key->dl_type == htons(ETH_TYPE_IP)) {
+        uint16_t *field;
+        if (key->nw_proto == IPPROTO_TCP) {
+            struct tcp_header *th = packet->l4;
+            field = a->type == XFLOWAT_SET_TP_SRC ? &th->tcp_src : &th->tcp_dst;
+            th->tcp_csum = recalc_csum16(th->tcp_csum, *field, a->tp_port);
+            *field = a->tp_port;
+        } else if (key->nw_proto == IPPROTO_UDP) {
+            struct udp_header *uh = packet->l4;
+            field = a->type == XFLOWAT_SET_TP_SRC ? &uh->udp_src : &uh->udp_dst;
+            uh->udp_csum = recalc_csum16(uh->udp_csum, *field, a->tp_port);
+            *field = a->tp_port;
+        } else {
+            return;
+        }
+
+        if (a->type == XFLOWAT_SET_TP_SRC) {
+            key->tp_src = a->tp_port;
+        } else {
+            key->tp_dst = a->tp_port;
+        }
+    }
+}
+
+static void
+xf_netdev_output_port(struct xf_netdev *xf, struct ofpbuf *packet,
+                      uint16_t out_port)
+{
+    struct xf_netdev_port *p = xf->ports[out_port];
+    if (p) {
+        netdev_send(p->netdev, packet);
+    }
+}
+
+static void
+xf_netdev_output_group(struct xf_netdev *xf, uint16_t group, uint16_t in_port,
+                       struct ofpbuf *packet)
+{
+    struct xflow_port_group *g = &xf->groups[group];
+    int i;
+
+    for (i = 0; i < g->n_ports; i++) {
+        uint16_t out_port = g->ports[i];
+        if (out_port != in_port) {
+            xf_netdev_output_port(xf, packet, out_port);
+        }
+    }
+}
+
+static int
+xf_netdev_output_control(struct xf_netdev *xf, const struct ofpbuf *packet,
+                         int queue_no, int port_no, uint32_t arg)
+{
+    struct ovs_queue *q = &xf->queues[queue_no];
+    struct xflow_msg *header;
+    struct ofpbuf *msg;
+    size_t msg_size;
+
+    if (q->n >= MAX_QUEUE_LEN) {
+        xf->n_lost++;
+        return ENOBUFS;
+    }
+
+    msg_size = sizeof *header + packet->size;
+    msg = ofpbuf_new(msg_size + XFIF_RECV_MSG_PADDING);
+    header = ofpbuf_put_uninit(msg, sizeof *header);
+    ofpbuf_reserve(msg, XFIF_RECV_MSG_PADDING);
+    header->type = queue_no;
+    header->length = msg_size;
+    header->port = port_no;
+    header->arg = arg;
+    ofpbuf_put(msg, packet->data, packet->size);
+    queue_push_tail(q, msg);
+
+    return 0;
+}
+
+static int
+xf_netdev_execute_actions(struct xf_netdev *xf,
+                          struct ofpbuf *packet, struct xflow_key *key,
+                          const union xflow_action *actions, int n_actions)
+{
+    int i;
+    for (i = 0; i < n_actions; i++) {
+        const union xflow_action *a = &actions[i];
+
+        switch (a->type) {
+        case XFLOWAT_OUTPUT:
+            xf_netdev_output_port(xf, packet, a->output.port);
+            break;
+
+        case XFLOWAT_OUTPUT_GROUP:
+            xf_netdev_output_group(xf, a->output_group.group, key->in_port,
+                                   packet);
+            break;
+
+        case XFLOWAT_CONTROLLER:
+            xf_netdev_output_control(xf, packet, _XFLOWL_ACTION_NR,
+                                     key->in_port, a->controller.arg);
+            break;
+
+        case XFLOWAT_SET_DL_TCI:
+            xf_netdev_set_dl_tci(packet, key, &a->dl_tci);
+            break;
+
+        case XFLOWAT_STRIP_VLAN:
+            xf_netdev_strip_vlan(packet, key);
+            break;
+
+        case XFLOWAT_SET_DL_SRC:
+            xf_netdev_set_dl_src(packet, key, a->dl_addr.dl_addr);
+            break;
+
+        case XFLOWAT_SET_DL_DST:
+            xf_netdev_set_dl_dst(packet, key, a->dl_addr.dl_addr);
+            break;
+
+        case XFLOWAT_SET_NW_SRC:
+        case XFLOWAT_SET_NW_DST:
+            xf_netdev_set_nw_addr(packet, key, &a->nw_addr);
+            break;
+
+        case XFLOWAT_SET_NW_TOS:
+            xf_netdev_set_nw_tos(packet, key, &a->nw_tos);
+            break;
+
+        case XFLOWAT_SET_TP_SRC:
+        case XFLOWAT_SET_TP_DST:
+            xf_netdev_set_tp_port(packet, key, &a->tp_port);
+            break;
+        }
+    }
+    return 0;
+}
+
+const struct xfif_class xfif_netdev_class = {
+    "netdev",
+    xf_netdev_run,
+    xf_netdev_wait,
+    NULL,                       /* enumerate */
+    xfif_netdev_open,
+    xfif_netdev_close,
+    NULL,                       /* get_all_names */
+    xfif_netdev_destroy,
+    xfif_netdev_get_stats,
+    xfif_netdev_get_drop_frags,
+    xfif_netdev_set_drop_frags,
+    xfif_netdev_port_add,
+    xfif_netdev_port_del,
+    xfif_netdev_port_query_by_number,
+    xfif_netdev_port_query_by_name,
+    xfif_netdev_port_list,
+    xfif_netdev_port_poll,
+    xfif_netdev_port_poll_wait,
+    xfif_netdev_port_group_get,
+    xfif_netdev_port_group_set,
+    xfif_netdev_flow_get,
+    xfif_netdev_flow_put,
+    xfif_netdev_flow_del,
+    xfif_netdev_flow_flush,
+    xfif_netdev_flow_list,
+    xfif_netdev_execute,
+    xfif_netdev_recv_get_mask,
+    xfif_netdev_recv_set_mask,
+    NULL,                       /* get_sflow_probability */
+    NULL,                       /* set_sflow_probability */
+    xfif_netdev_recv,
+    xfif_netdev_recv_wait,
+};
similarity index 58%
rename from lib/dpif-provider.h
rename to lib/xfif-provider.h
index 33663ff..3b42797 100644 (file)
  * limitations under the License.
  */
 
-#ifndef DPIF_PROVIDER_H
-#define DPIF_PROVIDER_H 1
+#ifndef XFIF_PROVIDER_H
+#define XFIF_PROVIDER_H 1
 
-/* Provider interface to dpifs, which provide an interface to an Open vSwitch
+/* Provider interface to xfifs, which provide an interface to an Open vSwitch
  * datapath. */
 
 #include <assert.h>
 #include "openflow/openflow.h"
-#include "dpif.h"
+#include "xfif.h"
 #include "util.h"
 
 #ifdef  __cplusplus
@@ -31,23 +31,23 @@ extern "C" {
 
 /* Open vSwitch datapath interface.
  *
- * This structure should be treated as opaque by dpif implementations. */
-struct dpif {
-    const struct dpif_class *dpif_class;
+ * This structure should be treated as opaque by xfif implementations. */
+struct xfif {
+    const struct xfif_class *xfif_class;
     char *base_name;
     char *full_name;
     uint8_t netflow_engine_type;
     uint8_t netflow_engine_id;
 };
 
-void dpif_init(struct dpif *, const struct dpif_class *, const char *name,
+void xfif_init(struct xfif *, const struct xfif_class *, const char *name,
                uint8_t netflow_engine_type, uint8_t netflow_engine_id);
-void dpif_uninit(struct dpif *dpif, bool close);
+void xfif_uninit(struct xfif *xfif, bool close);
 
-static inline void dpif_assert_class(const struct dpif *dpif,
-                                     const struct dpif_class *dpif_class)
+static inline void xfif_assert_class(const struct xfif *xfif,
+                                     const struct xfif_class *xfif_class)
 {
-    assert(dpif->dpif_class == dpif_class);
+    assert(xfif->xfif_class == xfif_class);
 }
 
 /* Datapath interface class structure, to be defined by each implementation of
@@ -56,18 +56,19 @@ static inline void dpif_assert_class(const struct dpif *dpif,
  * These functions return 0 if successful or a positive errno value on failure,
  * except where otherwise noted.
  *
- * These functions are expected to execute synchronously, that is, to block as
- * necessary to obtain a result.  Thus, they may not return EAGAIN or
- * EWOULDBLOCK or EINPROGRESS.  We may relax this requirement in the future if
- * and when we encounter performance problems. */
-struct dpif_class {
-    /* Type of dpif in this class, e.g. "system", "netdev", etc.
+ * Most of these functions are expected to execute synchronously, that is, to
+ * block as necessary to obtain a result.  Thus, these functions may return
+ * EAGAIN (or EWOULDBLOCK or EINPROGRESS) only where the function descriptions
+ * explicitly say those errors are a possibility.  We may relax this
+ * requirement in the future if and when we encounter performance problems. */
+struct xfif_class {
+    /* Type of xfif in this class, e.g. "system", "netdev", etc.
      *
      * One of the providers should supply a "system" type, since this is
-     * the type assumed if no type is specified when opening a dpif. */
+     * the type assumed if no type is specified when opening a xfif. */
     const char *type;
 
-    /* Performs periodic work needed by dpifs of this class, if any is
+    /* Performs periodic work needed by xfifs of this class, if any is
      * necessary. */
     void (*run)(void);
 
@@ -76,7 +77,7 @@ struct dpif_class {
     void (*wait)(void);
 
     /* Enumerates the names of all known created datapaths, if possible, into
-     * 'all_dps'.  The caller has already initialized 'all_dps' and other dpif
+     * 'all_dps'.  The caller has already initialized 'all_dps' and other xfif
      * classes might already have added names to it.
      *
      * This is used by the vswitch at startup, so that it can delete any
@@ -86,20 +87,20 @@ struct dpif_class {
      * case this function may be a null pointer. */
     int (*enumerate)(struct svec *all_dps);
 
-    /* Attempts to open an existing dpif called 'name', if 'create' is false,
-     * or to open an existing dpif or create a new one, if 'create' is true.
-     * 'type' corresponds to the 'type' field used in the dpif_class
+    /* Attempts to open an existing xfif called 'name', if 'create' is false,
+     * or to open an existing xfif or create a new one, if 'create' is true.
+     * 'type' corresponds to the 'type' field used in the xfif_class
      * structure.
      *
-     * If successful, stores a pointer to the new dpif in '*dpifp'.  On failure
-     * there are no requirements on what is stored in '*dpifp'. */
+     * If successful, stores a pointer to the new xfif in '*xfifp'.  On failure
+     * there are no requirements on what is stored in '*xfifp'. */
     int (*open)(const char *name, const char *type, bool create,
-                struct dpif **dpifp);
+                struct xfif **xfifp);
 
-    /* Closes 'dpif' and frees associated memory. */
-    void (*close)(struct dpif *dpif);
+    /* Closes 'xfif' and frees associated memory. */
+    void (*close)(struct xfif *xfif);
 
-    /* Enumerates all names that may be used to open 'dpif' into 'all_names'.
+    /* Enumerates all names that may be used to open 'xfif' into 'all_names'.
      * The Linux datapath, for example, supports opening a datapath both by
      * number, e.g. "dp0", and by the name of the datapath's local port.  For
      * some datapaths, this might be an infinite set (e.g. in a file name,
@@ -114,55 +115,55 @@ struct dpif_class {
      * function may be a null pointer.
      *
      * This is used by the vswitch at startup, */
-    int (*get_all_names)(const struct dpif *dpif, struct svec *all_names);
+    int (*get_all_names)(const struct xfif *xfif, struct svec *all_names);
 
-    /* Attempts to destroy the dpif underlying 'dpif'.
+    /* Attempts to destroy the xfif underlying 'xfif'.
      *
-     * If successful, 'dpif' will not be used again except as an argument for
+     * If successful, 'xfif' will not be used again except as an argument for
      * the 'close' member function. */
-    int (*destroy)(struct dpif *dpif);
+    int (*destroy)(struct xfif *xfif);
 
-    /* Retrieves statistics for 'dpif' into 'stats'. */
-    int (*get_stats)(const struct dpif *dpif, struct odp_stats *stats);
+    /* Retrieves statistics for 'xfif' into 'stats'. */
+    int (*get_stats)(const struct xfif *xfif, struct xflow_stats *stats);
 
-    /* Retrieves 'dpif''s current treatment of IP fragments into '*drop_frags':
+    /* Retrieves 'xfif''s current treatment of IP fragments into '*drop_frags':
      * true indicates that fragments are dropped, false indicates that
      * fragments are treated in the same way as other IP packets (except that
      * the L4 header cannot be read). */
-    int (*get_drop_frags)(const struct dpif *dpif, bool *drop_frags);
+    int (*get_drop_frags)(const struct xfif *xfif, bool *drop_frags);
 
-    /* Changes 'dpif''s treatment of IP fragments to 'drop_frags', whose
+    /* Changes 'xfif''s treatment of IP fragments to 'drop_frags', whose
      * meaning is the same as for the get_drop_frags member function. */
-    int (*set_drop_frags)(struct dpif *dpif, bool drop_frags);
+    int (*set_drop_frags)(struct xfif *xfif, bool drop_frags);
 
-    /* Creates a new port in 'dpif' connected to network device 'devname'.
-     * 'flags' is a set of ODP_PORT_* flags.  If successful, sets '*port_no'
+    /* Creates a new port in 'xfif' connected to network device 'devname'.
+     * 'flags' is a set of XFLOW_PORT_* flags.  If successful, sets '*port_no'
      * to the new port's port number. */
-    int (*port_add)(struct dpif *dpif, const char *devname, uint16_t flags,
+    int (*port_add)(struct xfif *xfif, const char *devname, uint16_t flags,
                     uint16_t *port_no);
 
-    /* Removes port numbered 'port_no' from 'dpif'. */
-    int (*port_del)(struct dpif *dpif, uint16_t port_no);
+    /* Removes port numbered 'port_no' from 'xfif'. */
+    int (*port_del)(struct xfif *xfif, uint16_t port_no);
 
-    /* Queries 'dpif' for a port with the given 'port_no' or 'devname'.  Stores
+    /* Queries 'xfif' for a port with the given 'port_no' or 'devname'.  Stores
      * information about the port into '*port' if successful. */
-    int (*port_query_by_number)(const struct dpif *dpif, uint16_t port_no,
-                                struct odp_port *port);
-    int (*port_query_by_name)(const struct dpif *dpif, const char *devname,
-                              struct odp_port *port);
+    int (*port_query_by_number)(const struct xfif *xfif, uint16_t port_no,
+                                struct xflow_port *port);
+    int (*port_query_by_name)(const struct xfif *xfif, const char *devname,
+                              struct xflow_port *port);
 
-    /* Stores in 'ports' information about up to 'n' ports attached to 'dpif',
-     * in no particular order.  Returns the number of ports attached to 'dpif'
+    /* Stores in 'ports' information about up to 'n' ports attached to 'xfif',
+     * in no particular order.  Returns the number of ports attached to 'xfif'
      * (not the number stored), if successful, otherwise a negative errno
      * value. */
-    int (*port_list)(const struct dpif *dpif, struct odp_port *ports, int n);
+    int (*port_list)(const struct xfif *xfif, struct xflow_port *ports, int n);
 
-    /* Polls for changes in the set of ports in 'dpif'.  If the set of ports in
-     * 'dpif' has changed, then this function should do one of the
+    /* Polls for changes in the set of ports in 'xfif'.  If the set of ports in
+     * 'xfif' has changed, then this function should do one of the
      * following:
      *
      * - Preferably: store the name of the device that was added to or deleted
-     *   from 'dpif' in '*devnamep' and return 0.  The caller is responsible
+     *   from 'xfif' in '*devnamep' and return 0.  The caller is responsible
      *   for freeing '*devnamep' (with free()) when it no longer needs it.
      *
      * - Alternatively: return ENOBUFS, without indicating the device that was
@@ -172,32 +173,32 @@ struct dpif_class {
      * indicating a device that was not actually added or deleted or returns
      * ENOBUFS without any change, are acceptable.
      *
-     * If the set of ports in 'dpif' has not changed, returns EAGAIN.  May also
+     * If the set of ports in 'xfif' has not changed, returns EAGAIN.  May also
      * return other positive errno values to indicate that something has gone
      * wrong. */
-    int (*port_poll)(const struct dpif *dpif, char **devnamep);
+    int (*port_poll)(const struct xfif *xfif, char **devnamep);
 
     /* Arranges for the poll loop to wake up when 'port_poll' will return a
      * value other than EAGAIN. */
-    void (*port_poll_wait)(const struct dpif *dpif);
+    void (*port_poll_wait)(const struct xfif *xfif);
 
     /* Stores in 'ports' the port numbers of up to 'n' ports that belong to
-     * 'group' in 'dpif'.  Returns the number of ports in 'group' (not the
+     * 'group' in 'xfif'.  Returns the number of ports in 'group' (not the
      * number stored), if successful, otherwise a negative errno value. */
-    int (*port_group_get)(const struct dpif *dpif, int group,
+    int (*port_group_get)(const struct xfif *xfif, int group,
                           uint16_t ports[], int n);
 
-    /* Changes port group 'group' in 'dpif' to consist of the 'n' ports whose
+    /* Changes port group 'group' in 'xfif' to consist of the 'n' ports whose
      * numbers are given in 'ports'.
      *
      * Use the get_stats member function to obtain the number of supported port
      * groups. */
-    int (*port_group_set)(struct dpif *dpif, int group,
+    int (*port_group_set)(struct xfif *xfif, int group,
                           const uint16_t ports[], int n);
 
     /* For each flow 'flow' in the 'n' flows in 'flows':
      *
-     * - If a flow matching 'flow->key' exists in 'dpif':
+     * - If a flow matching 'flow->key' exists in 'xfif':
      *
      *     Stores 0 into 'flow->stats.error' and stores statistics for the flow
      *     into 'flow->stats'.
@@ -212,7 +213,7 @@ struct dpif_class {
      *
      * - Flow-specific errors are indicated by a positive errno value in
      *   'flow->stats.error'.  In particular, ENOENT indicates that no flow
-     *   matching 'flow->key' exists in 'dpif'.  When an error value is stored,
+     *   matching 'flow->key' exists in 'xfif'.  When an error value is stored,
      *   the contents of 'flow->key' are preserved but other members of 'flow'
      *   should be treated as indeterminate.
      *
@@ -222,113 +223,114 @@ struct dpif_class {
      * this update occurred, in which the caller must not depend on any
      * elements in 'flows' being updated or not updated.
      */
-    int (*flow_get)(const struct dpif *dpif, struct odp_flow flows[], int n);
+    int (*flow_get)(const struct xfif *xfif, struct xflow_flow flows[], int n);
 
-    /* Adds or modifies a flow in 'dpif' as specified in 'put':
+    /* Adds or modifies a flow in 'xfif' as specified in 'put':
      *
-     * - If the flow specified in 'put->flow' does not exist in 'dpif', then
-     *   behavior depends on whether ODPPF_CREATE is specified in 'put->flags':
+     * - If the flow specified in 'put->flow' does not exist in 'xfif', then
+     *   behavior depends on whether XFLOWPF_CREATE is specified in 'put->flags':
      *   if it is, the flow will be added, otherwise the operation will fail
      *   with ENOENT.
      *
-     * - Otherwise, the flow specified in 'put->flow' does exist in 'dpif'.
-     *   Behavior in this case depends on whether ODPPF_MODIFY is specified in
+     * - Otherwise, the flow specified in 'put->flow' does exist in 'xfif'.
+     *   Behavior in this case depends on whether XFLOWPF_MODIFY is specified in
      *   'put->flags': if it is, the flow's actions will be updated, otherwise
      *   the operation will fail with EEXIST.  If the flow's actions are
-     *   updated, then its statistics will be zeroed if ODPPF_ZERO_STATS is set
+     *   updated, then its statistics will be zeroed if XFLOWPF_ZERO_STATS is set
      *   in 'put->flags', left as-is otherwise.
      */
-    int (*flow_put)(struct dpif *dpif, struct odp_flow_put *put);
+    int (*flow_put)(struct xfif *xfif, struct xflow_flow_put *put);
 
-    /* Deletes a flow matching 'flow->key' from 'dpif' or returns ENOENT if
-     * 'dpif' does not contain such a flow.
+    /* Deletes a flow matching 'flow->key' from 'xfif' or returns ENOENT if
+     * 'xfif' does not contain such a flow.
      *
      * If successful, updates 'flow->stats', 'flow->n_actions', and
      * 'flow->actions' as described in more detail under the flow_get member
      * function below. */
-    int (*flow_del)(struct dpif *dpif, struct odp_flow *flow);
+    int (*flow_del)(struct xfif *xfif, struct xflow_flow *flow);
 
-    /* Deletes all flows from 'dpif' and clears all of its queues of received
+    /* Deletes all flows from 'xfif' and clears all of its queues of received
      * packets. */
-    int (*flow_flush)(struct dpif *dpif);
+    int (*flow_flush)(struct xfif *xfif);
 
-    /* Stores up to 'n' flows in 'dpif' into 'flows', updating their statistics
+    /* Stores up to 'n' flows in 'xfif' into 'flows', updating their statistics
      * and actions as described under the flow_get member function.  If
-     * successful, returns the number of flows actually present in 'dpif',
-     * which might be greater than the number stored (if 'dpif' has more than
+     * successful, returns the number of flows actually present in 'xfif',
+     * which might be greater than the number stored (if 'xfif' has more than
      * 'n' flows).  On failure, returns a negative errno value. */
-    int (*flow_list)(const struct dpif *dpif, struct odp_flow flows[], int n);
+    int (*flow_list)(const struct xfif *xfif,
+                     struct xflow_flow flows[], int n);
 
     /* Performs the 'n_actions' actions in 'actions' on the Ethernet frame
      * specified in 'packet'.
      *
      * Pretends that the frame was originally received on the port numbered
-     * 'in_port'.  This affects only ODPAT_OUTPUT_GROUP actions, which will not
-     * send a packet out their input port.  Specify the number of an unused
+     * 'in_port'.  This affects only XFLOWAT_OUTPUT_GROUP actions, which will
+     * not send a packet out their input port.  Specify the number of an unused
      * port (e.g. UINT16_MAX is currently always unused) to avoid this
      * behavior. */
-    int (*execute)(struct dpif *dpif, uint16_t in_port,
-                   const union odp_action actions[], int n_actions,
+    int (*execute)(struct xfif *xfif, uint16_t in_port,
+                   const union xflow_action actions[], int n_actions,
                    const struct ofpbuf *packet);
 
-    /* Retrieves 'dpif''s "listen mask" into '*listen_mask'.  Each ODPL_* bit
-     * set in '*listen_mask' indicates the 'dpif' will receive messages of the
+    /* Retrieves 'xfif''s "listen mask" into '*listen_mask'.  Each XFLOWL_* bit
+     * set in '*listen_mask' indicates the 'xfif' will receive messages of the
      * corresponding type when it calls the recv member function. */
-    int (*recv_get_mask)(const struct dpif *dpif, int *listen_mask);
+    int (*recv_get_mask)(const struct xfif *xfif, int *listen_mask);
 
-    /* Sets 'dpif''s "listen mask" to 'listen_mask'.  Each ODPL_* bit set in
-     * 'listen_mask' indicates the 'dpif' will receive messages of the
+    /* Sets 'xfif''s "listen mask" to 'listen_mask'.  Each XFLOWL_* bit set in
+     * 'listen_mask' indicates the 'xfif' will receive messages of the
      * corresponding type when it calls the recv member function. */
-    int (*recv_set_mask)(struct dpif *dpif, int listen_mask);
+    int (*recv_set_mask)(struct xfif *xfif, int listen_mask);
 
-    /* Retrieves 'dpif''s sFlow sampling probability into '*probability'.
+    /* Retrieves 'xfif''s sFlow sampling probability into '*probability'.
      * Return value is 0 or a positive errno value.  EOPNOTSUPP indicates that
      * the datapath does not support sFlow, as does a null pointer.
      *
      * '*probability' is expressed as the number of packets out of UINT_MAX to
      * sample, e.g. probability/UINT_MAX is the probability of sampling a given
      * packet. */
-    int (*get_sflow_probability)(const struct dpif *dpif,
+    int (*get_sflow_probability)(const struct xfif *xfif,
                                  uint32_t *probability);
 
-    /* Sets 'dpif''s sFlow sampling probability to 'probability'.  Return value
+    /* Sets 'xfif''s sFlow sampling probability to 'probability'.  Return value
      * is 0 or a positive errno value.  EOPNOTSUPP indicates that the datapath
      * does not support sFlow, as does a null pointer.
      *
      * 'probability' is expressed as the number of packets out of UINT_MAX to
      * sample, e.g. probability/UINT_MAX is the probability of sampling a given
      * packet. */
-    int (*set_sflow_probability)(struct dpif *dpif, uint32_t probability);
+    int (*set_sflow_probability)(struct xfif *xfif, uint32_t probability);
 
-    /* Attempts to receive a message from 'dpif'.  If successful, stores the
+    /* Attempts to receive a message from 'xfif'.  If successful, stores the
      * message into '*packetp'.  The message, if one is received, must begin
-     * with 'struct odp_msg' as a header, and must have at least
-     * DPIF_RECV_MSG_PADDING bytes of headroom (allocated using
+     * with 'struct xflow_msg' as a header, and must have at least
+     * XFIF_RECV_MSG_PADDING bytes of headroom (allocated using
      * e.g. ofpbuf_reserve()).  Only messages of the types selected with the
      * set_listen_mask member function should be received.
      *
      * This function must not block.  If no message is ready to be received
      * when it is called, it should return EAGAIN without blocking. */
-    int (*recv)(struct dpif *dpif, struct ofpbuf **packetp);
+    int (*recv)(struct xfif *xfif, struct ofpbuf **packetp);
 
-    /* Arranges for the poll loop to wake up when 'dpif' has a message queued
+    /* Arranges for the poll loop to wake up when 'xfif' has a message queued
      * to be received with the recv member function. */
-    void (*recv_wait)(struct dpif *dpif);
+    void (*recv_wait)(struct xfif *xfif);
 };
 
 /* Minimum number of bytes of headroom for a packet returned by the 'recv'
- * member function (see above).  This headroom allows "struct odp_msg" to be
+ * member function (see above).  This headroom allows "struct xflow_msg" to be
  * replaced by "struct ofp_packet_in" without copying the buffer. */
-#define DPIF_RECV_MSG_PADDING (sizeof(struct ofp_packet_in) \
-                               - sizeof(struct odp_msg))
-BUILD_ASSERT_DECL(sizeof(struct ofp_packet_in) > sizeof(struct odp_msg));
-BUILD_ASSERT_DECL(DPIF_RECV_MSG_PADDING % 4 == 0);
+#define XFIF_RECV_MSG_PADDING (sizeof(struct ofp_packet_in) \
+                               - sizeof(struct xflow_msg))
+BUILD_ASSERT_DECL(sizeof(struct ofp_packet_in) > sizeof(struct xflow_msg));
+BUILD_ASSERT_DECL(XFIF_RECV_MSG_PADDING % 4 == 0);
 
-extern const struct dpif_class dpif_linux_class;
-extern const struct dpif_class dpif_netdev_class;
+extern const struct xfif_class xfif_linux_class;
+extern const struct xfif_class xfif_netdev_class;
 
 #ifdef  __cplusplus
 }
 #endif
 
-#endif /* dpif-provider.h */
+#endif /* xfif-provider.h */
similarity index 58%
rename from lib/dpif.c
rename to lib/xfif.c
index 097b38d..1f18f4c 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 #include <config.h>
-#include "dpif-provider.h"
+#include "xfif-provider.h"
 
 #include <assert.h>
 #include <ctype.h>
@@ -28,7 +28,7 @@
 #include "dynamic-string.h"
 #include "flow.h"
 #include "netlink.h"
-#include "odp-util.h"
+#include "xflow-util.h"
 #include "ofp-print.h"
 #include "ofpbuf.h"
 #include "packets.h"
 #include "valgrind.h"
 
 #include "vlog.h"
-#define THIS_MODULE VLM_dpif
+#define THIS_MODULE VLM_xfif
 
-static const struct dpif_class *base_dpif_classes[] = {
-    &dpif_linux_class,
-    &dpif_netdev_class,
+static const struct xfif_class *base_xfif_classes[] = {
+    &xfif_linux_class,
+    &xfif_netdev_class,
 };
 
-struct registered_dpif_class {
-    struct dpif_class dpif_class;
+struct registered_xfif_class {
+    struct xfif_class xfif_class;
     int refcount;
 };
-static struct shash dpif_classes = SHASH_INITIALIZER(&dpif_classes);
+static struct shash xfif_classes = SHASH_INITIALIZER(&xfif_classes);
 
 /* Rate limit for individual messages going to or from the datapath, output at
  * DBG level.  This is very high because, if these are enabled, it is because
  * we really need to see them. */
 static struct vlog_rate_limit dpmsg_rl = VLOG_RATE_LIMIT_INIT(600, 600);
 
-/* Not really much point in logging many dpif errors. */
+/* Not really much point in logging many xfif errors. */
 static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5);
 
-static void log_operation(const struct dpif *, const char *operation,
+static void log_operation(const struct xfif *, const char *operation,
                           int error);
-static void log_flow_operation(const struct dpif *, const char *operation,
-                               int error, struct odp_flow *flow);
-static void log_flow_put(struct dpif *, int error,
-                         const struct odp_flow_put *);
+static void log_flow_operation(const struct xfif *, const char *operation,
+                               int error, struct xflow_flow *flow);
+static void log_flow_put(struct xfif *, int error,
+                         const struct xflow_flow_put *);
 static bool should_log_flow_message(int error);
-static void check_rw_odp_flow(struct odp_flow *);
+static void check_rw_xflow_flow(struct xflow_flow *);
 
 static void
-dp_initialize(void)
+xf_initialize(void)
 {
     static int status = -1;
 
@@ -78,77 +78,77 @@ dp_initialize(void)
         int i;
 
         status = 0;
-        for (i = 0; i < ARRAY_SIZE(base_dpif_classes); i++) {
-            dp_register_provider(base_dpif_classes[i]);
+        for (i = 0; i < ARRAY_SIZE(base_xfif_classes); i++) {
+            xf_register_provider(base_xfif_classes[i]);
         }
     }
 }
 
-/* Performs periodic work needed by all the various kinds of dpifs.
+/* Performs periodic work needed by all the various kinds of xfifs.
  *
- * If your program opens any dpifs, it must call both this function and
+ * If your program opens any xfifs, it must call both this function and
  * netdev_run() within its main poll loop. */
 void
-dp_run(void)
+xf_run(void)
 {
     struct shash_node *node;
-    SHASH_FOR_EACH(node, &dpif_classes) {
-        const struct registered_dpif_class *registered_class = node->data;
-        if (registered_class->dpif_class.run) {
-            registered_class->dpif_class.run();
+    SHASH_FOR_EACH(node, &xfif_classes) {
+        const struct registered_xfif_class *registered_class = node->data;
+        if (registered_class->xfif_class.run) {
+            registered_class->xfif_class.run();
         }
     }
 }
 
-/* Arranges for poll_block() to wake up when dp_run() needs to be called.
+/* Arranges for poll_block() to wake up when xf_run() needs to be called.
  *
- * If your program opens any dpifs, it must call both this function and
+ * If your program opens any xfifs, it must call both this function and
  * netdev_wait() within its main poll loop. */
 void
-dp_wait(void)
+xf_wait(void)
 {
     struct shash_node *node;
-    SHASH_FOR_EACH(node, &dpif_classes) {
-        const struct registered_dpif_class *registered_class = node->data;
-        if (registered_class->dpif_class.wait) {
-            registered_class->dpif_class.wait();
+    SHASH_FOR_EACH(node, &xfif_classes) {
+        const struct registered_xfif_class *registered_class = node->data;
+        if (registered_class->xfif_class.wait) {
+            registered_class->xfif_class.wait();
         }
     }
 }
 
 /* Registers a new datapath provider.  After successful registration, new
- * datapaths of that type can be opened using dpif_open(). */
+ * datapaths of that type can be opened using xfif_open(). */
 int
-dp_register_provider(const struct dpif_class *new_class)
+xf_register_provider(const struct xfif_class *new_class)
 {
-    struct registered_dpif_class *registered_class;
+    struct registered_xfif_class *registered_class;
 
-    if (shash_find(&dpif_classes, new_class->type)) {
+    if (shash_find(&xfif_classes, new_class->type)) {
         VLOG_WARN("attempted to register duplicate datapath provider: %s",
                   new_class->type);
         return EEXIST;
     }
 
     registered_class = xmalloc(sizeof *registered_class);
-    memcpy(&registered_class->dpif_class, new_class,
-           sizeof registered_class->dpif_class);
+    memcpy(&registered_class->xfif_class, new_class,
+           sizeof registered_class->xfif_class);
     registered_class->refcount = 0;
 
-    shash_add(&dpif_classes, new_class->type, registered_class);
+    shash_add(&xfif_classes, new_class->type, registered_class);
 
     return 0;
 }
 
 /* Unregisters a datapath provider.  'type' must have been previously
- * registered and not currently be in use by any dpifs.  After unregistration
- * new datapaths of that type cannot be opened using dpif_open(). */
+ * registered and not currently be in use by any xfifs.  After unregistration
+ * new datapaths of that type cannot be opened using xfif_open(). */
 int
-dp_unregister_provider(const char *type)
+xf_unregister_provider(const char *type)
 {
     struct shash_node *node;
-    struct registered_dpif_class *registered_class;
+    struct registered_xfif_class *registered_class;
 
-    node = shash_find(&dpif_classes, type);
+    node = shash_find(&xfif_classes, type);
     if (!node) {
         VLOG_WARN("attempted to unregister a datapath provider that is not "
                   "registered: %s", type);
@@ -161,7 +161,7 @@ dp_unregister_provider(const char *type)
         return EBUSY;
     }
 
-    shash_delete(&dpif_classes, node);
+    shash_delete(&xfif_classes, node);
     free(registered_class);
 
     return 0;
@@ -170,16 +170,16 @@ dp_unregister_provider(const char *type)
 /* Clears 'types' and enumerates the types of all currently registered datapath
  * providers into it.  The caller must first initialize the svec. */
 void
-dp_enumerate_types(struct svec *types)
+xf_enumerate_types(struct svec *types)
 {
     struct shash_node *node;
 
-    dp_initialize();
+    xf_initialize();
     svec_clear(types);
 
-    SHASH_FOR_EACH(node, &dpif_classes) {
-        const struct registered_dpif_class *registered_class = node->data;
-        svec_add(types, registered_class->dpif_class.type);
+    SHASH_FOR_EACH(node, &xfif_classes) {
+        const struct registered_xfif_class *registered_class = node->data;
+        svec_add(types, registered_class->xfif_class.type);
     }
 }
 
@@ -190,26 +190,26 @@ dp_enumerate_types(struct svec *types)
  * Some kinds of datapaths might not be practically enumerable.  This is not
  * considered an error. */
 int
-dp_enumerate_names(const char *type, struct svec *names)
+xf_enumerate_names(const char *type, struct svec *names)
 {
-    const struct registered_dpif_class *registered_class;
-    const struct dpif_class *dpif_class;
+    const struct registered_xfif_class *registered_class;
+    const struct xfif_class *xfif_class;
     int error;
 
-    dp_initialize();
+    xf_initialize();
     svec_clear(names);
 
-    registered_class = shash_find_data(&dpif_classes, type);
+    registered_class = shash_find_data(&xfif_classes, type);
     if (!registered_class) {
         VLOG_WARN("could not enumerate unknown type: %s", type);
         return EAFNOSUPPORT;
     }
 
-    dpif_class = &registered_class->dpif_class;
-    error = dpif_class->enumerate ? dpif_class->enumerate(names) : 0;
+    xfif_class = &registered_class->xfif_class;
+    error = xfif_class->enumerate ? xfif_class->enumerate(names) : 0;
 
     if (error) {
-        VLOG_WARN("failed to enumerate %s datapaths: %s", dpif_class->type,
+        VLOG_WARN("failed to enumerate %s datapaths: %s", xfif_class->type,
                    strerror(error));
     }
 
@@ -219,7 +219,7 @@ dp_enumerate_names(const char *type, struct svec *names)
 /* Parses 'datapath name', which is of the form type@name into its
  * component pieces.  'name' and 'type' must be freed by the caller. */
 void
-dp_parse_name(const char *datapath_name_, char **name, char **type)
+xf_parse_name(const char *datapath_name_, char **name, char **type)
 {
     char *datapath_name = xstrdup(datapath_name_);
     char *separator;
@@ -236,19 +236,19 @@ dp_parse_name(const char *datapath_name_, char **name, char **type)
 }
 
 static int
-do_open(const char *name, const char *type, bool create, struct dpif **dpifp)
+do_open(const char *name, const char *type, bool create, struct xfif **xfifp)
 {
-    struct dpif *dpif = NULL;
+    struct xfif *xfif = NULL;
     int error;
-    struct registered_dpif_class *registered_class;
+    struct registered_xfif_class *registered_class;
 
-    dp_initialize();
+    xf_initialize();
 
     if (!type || *type == '\0') {
         type = "system";
     }
 
-    registered_class = shash_find_data(&dpif_classes, type);
+    registered_class = shash_find_data(&xfif_classes, type);
     if (!registered_class) {
         VLOG_WARN("could not create datapath %s of unknown type %s", name,
                   type);
@@ -256,13 +256,13 @@ do_open(const char *name, const char *type, bool create, struct dpif **dpifp)
         goto exit;
     }
 
-    error = registered_class->dpif_class.open(name, type, create, &dpif);
+    error = registered_class->xfif_class.open(name, type, create, &xfif);
     if (!error) {
         registered_class->refcount++;
     }
 
 exit:
-    *dpifp = error ? NULL : dpif;
+    *xfifp = error ? NULL : xfif;
     return error;
 }
 
@@ -270,37 +270,37 @@ exit:
  * if no datapath with 'name' and 'type' exists.  'type' may be either NULL or
  * the empty string to specify the default system type.  Returns 0 if
  * successful, otherwise a positive errno value.  On success stores a pointer
- * to the datapath in '*dpifp', otherwise a null pointer. */
+ * to the datapath in '*xfifp', otherwise a null pointer. */
 int
-dpif_open(const char *name, const char *type, struct dpif **dpifp)
+xfif_open(const char *name, const char *type, struct xfif **xfifp)
 {
-    return do_open(name, type, false, dpifp);
+    return do_open(name, type, false, xfifp);
 }
 
 /* Tries to create and open a new datapath with the given 'name' and 'type'.
  * 'type' may be either NULL or the empty string to specify the default system
  * type.  Will fail if a datapath with 'name' and 'type' already exists.
  * Returns 0 if successful, otherwise a positive errno value.  On success
- * stores a pointer to the datapath in '*dpifp', otherwise a null pointer. */
+ * stores a pointer to the datapath in '*xfifp', otherwise a null pointer. */
 int
-dpif_create(const char *name, const char *type, struct dpif **dpifp)
+xfif_create(const char *name, const char *type, struct xfif **xfifp)
 {
-    return do_open(name, type, true, dpifp);
+    return do_open(name, type, true, xfifp);
 }
 
 /* Tries to open a datapath with the given 'name' and 'type', creating it if it
  * does not exist.  'type' may be either NULL or the empty string to specify
  * the default system type.  Returns 0 if successful, otherwise a positive
- * errno value. On success stores a pointer to the datapath in '*dpifp',
+ * errno value. On success stores a pointer to the datapath in '*xfifp',
  * otherwise a null pointer. */
 int
-dpif_create_and_open(const char *name, const char *type, struct dpif **dpifp)
+xfif_create_and_open(const char *name, const char *type, struct xfif **xfifp)
 {
     int error;
 
-    error = dpif_create(name, type, dpifp);
+    error = xfif_create(name, type, xfifp);
     if (error == EEXIST || error == EBUSY) {
-        error = dpif_open(name, type, dpifp);
+        error = xfif_open(name, type, xfifp);
         if (error) {
             VLOG_WARN("datapath %s already exists but cannot be opened: %s",
                       name, strerror(error));
@@ -311,41 +311,41 @@ dpif_create_and_open(const char *name, const char *type, struct dpif **dpifp)
     return error;
 }
 
-/* Closes and frees the connection to 'dpif'.  Does not destroy the datapath
- * itself; call dpif_delete() first, instead, if that is desirable. */
+/* Closes and frees the connection to 'xfif'.  Does not destroy the datapath
+ * itself; call xfif_delete() first, instead, if that is desirable. */
 void
-dpif_close(struct dpif *dpif)
+xfif_close(struct xfif *xfif)
 {
-    if (dpif) {
-        struct registered_dpif_class *registered_class;
+    if (xfif) {
+        struct registered_xfif_class *registered_class;
 
-        registered_class = shash_find_data(&dpif_classes, 
-                dpif->dpif_class->type);
+        registered_class = shash_find_data(&xfif_classes, 
+                xfif->xfif_class->type);
         assert(registered_class);
         assert(registered_class->refcount);
 
         registered_class->refcount--;
-        dpif_uninit(dpif, true);
+        xfif_uninit(xfif, true);
     }
 }
 
-/* Returns the name of datapath 'dpif' prefixed with the type
+/* Returns the name of datapath 'xfif' prefixed with the type
  * (for use in log messages). */
 const char *
-dpif_name(const struct dpif *dpif)
+xfif_name(const struct xfif *xfif)
 {
-    return dpif->full_name;
+    return xfif->full_name;
 }
 
-/* Returns the name of datapath 'dpif' without the type
+/* Returns the name of datapath 'xfif' without the type
  * (for use in device names). */
 const char *
-dpif_base_name(const struct dpif *dpif)
+xfif_base_name(const struct xfif *xfif)
 {
-    return dpif->base_name;
+    return xfif->base_name;
 }
 
-/* Enumerates all names that may be used to open 'dpif' into 'all_names'.  The
+/* Enumerates all names that may be used to open 'xfif' into 'all_names'.  The
  * Linux datapath, for example, supports opening a datapath both by number,
  * e.g. "dp0", and by the name of the datapath's local port.  For some
  * datapaths, this might be an infinite set (e.g. in a file name, slashes may
@@ -355,98 +355,98 @@ dpif_base_name(const struct dpif *dpif)
  * The caller must already have initialized 'all_names'.  Any existing names in
  * 'all_names' will not be disturbed. */
 int
-dpif_get_all_names(const struct dpif *dpif, struct svec *all_names)
+xfif_get_all_names(const struct xfif *xfif, struct svec *all_names)
 {
-    if (dpif->dpif_class->get_all_names) {
-        int error = dpif->dpif_class->get_all_names(dpif, all_names);
+    if (xfif->xfif_class->get_all_names) {
+        int error = xfif->xfif_class->get_all_names(xfif, all_names);
         if (error) {
             VLOG_WARN_RL(&error_rl,
                          "failed to retrieve names for datpath %s: %s",
-                         dpif_name(dpif), strerror(error));
+                         xfif_name(xfif), strerror(error));
         }
         return error;
     } else {
-        svec_add(all_names, dpif_base_name(dpif));
+        svec_add(all_names, xfif_base_name(xfif));
         return 0;
     }
 }
 
-/* Destroys the datapath that 'dpif' is connected to, first removing all of its
- * ports.  After calling this function, it does not make sense to pass 'dpif'
- * to any functions other than dpif_name() or dpif_close(). */
+/* Destroys the datapath that 'xfif' is connected to, first removing all of its
+ * ports.  After calling this function, it does not make sense to pass 'xfif'
+ * to any functions other than xfif_name() or xfif_close(). */
 int
-dpif_delete(struct dpif *dpif)
+xfif_delete(struct xfif *xfif)
 {
     int error;
 
-    COVERAGE_INC(dpif_destroy);
+    COVERAGE_INC(xfif_destroy);
 
-    error = dpif->dpif_class->destroy(dpif);
-    log_operation(dpif, "delete", error);
+    error = xfif->xfif_class->destroy(xfif);
+    log_operation(xfif, "delete", error);
     return error;
 }
 
-/* Retrieves statistics for 'dpif' into 'stats'.  Returns 0 if successful,
+/* Retrieves statistics for 'xfif' into 'stats'.  Returns 0 if successful,
  * otherwise a positive errno value. */
 int
-dpif_get_dp_stats(const struct dpif *dpif, struct odp_stats *stats)
+xfif_get_xf_stats(const struct xfif *xfif, struct xflow_stats *stats)
 {
-    int error = dpif->dpif_class->get_stats(dpif, stats);
+    int error = xfif->xfif_class->get_stats(xfif, stats);
     if (error) {
         memset(stats, 0, sizeof *stats);
     }
-    log_operation(dpif, "get_stats", error);
+    log_operation(xfif, "get_stats", error);
     return error;
 }
 
-/* Retrieves the current IP fragment handling policy for 'dpif' into
+/* Retrieves the current IP fragment handling policy for 'xfif' into
  * '*drop_frags': true indicates that fragments are dropped, false indicates
  * that fragments are treated in the same way as other IP packets (except that
  * the L4 header cannot be read).  Returns 0 if successful, otherwise a
  * positive errno value. */
 int
-dpif_get_drop_frags(const struct dpif *dpif, bool *drop_frags)
+xfif_get_drop_frags(const struct xfif *xfif, bool *drop_frags)
 {
-    int error = dpif->dpif_class->get_drop_frags(dpif, drop_frags);
+    int error = xfif->xfif_class->get_drop_frags(xfif, drop_frags);
     if (error) {
         *drop_frags = false;
     }
-    log_operation(dpif, "get_drop_frags", error);
+    log_operation(xfif, "get_drop_frags", error);
     return error;
 }
 
-/* Changes 'dpif''s treatment of IP fragments to 'drop_frags', whose meaning is
+/* Changes 'xfif''s treatment of IP fragments to 'drop_frags', whose meaning is
  * the same as for the get_drop_frags member function.  Returns 0 if
  * successful, otherwise a positive errno value. */
 int
-dpif_set_drop_frags(struct dpif *dpif, bool drop_frags)
+xfif_set_drop_frags(struct xfif *xfif, bool drop_frags)
 {
-    int error = dpif->dpif_class->set_drop_frags(dpif, drop_frags);
-    log_operation(dpif, "set_drop_frags", error);
+    int error = xfif->xfif_class->set_drop_frags(xfif, drop_frags);
+    log_operation(xfif, "set_drop_frags", error);
     return error;
 }
 
-/* Attempts to add 'devname' as a port on 'dpif', given the combination of
- * ODP_PORT_* flags in 'flags'.  If successful, returns 0 and sets '*port_nop'
+/* Attempts to add 'devname' as a port on 'xfif', given the combination of
+ * XFLOW_PORT_* flags in 'flags'.  If successful, returns 0 and sets '*port_nop'
  * to the new port's port number (if 'port_nop' is non-null).  On failure,
  * returns a positive errno value and sets '*port_nop' to UINT16_MAX (if
  * 'port_nop' is non-null). */
 int
-dpif_port_add(struct dpif *dpif, const char *devname, uint16_t flags,
+xfif_port_add(struct xfif *xfif, const char *devname, uint16_t flags,
               uint16_t *port_nop)
 {
     uint16_t port_no;
     int error;
 
-    COVERAGE_INC(dpif_port_add);
+    COVERAGE_INC(xfif_port_add);
 
-    error = dpif->dpif_class->port_add(dpif, devname, flags, &port_no);
+    error = xfif->xfif_class->port_add(xfif, devname, flags, &port_no);
     if (!error) {
         VLOG_DBG_RL(&dpmsg_rl, "%s: added %s as port %"PRIu16,
-                    dpif_name(dpif), devname, port_no);
+                    xfif_name(xfif), devname, port_no);
     } else {
         VLOG_WARN_RL(&error_rl, "%s: failed to add %s as port: %s",
-                     dpif_name(dpif), devname, strerror(error));
+                     xfif_name(xfif), devname, strerror(error));
         port_no = UINT16_MAX;
     }
     if (port_nop) {
@@ -455,76 +455,76 @@ dpif_port_add(struct dpif *dpif, const char *devname, uint16_t flags,
     return error;
 }
 
-/* Attempts to remove 'dpif''s port number 'port_no'.  Returns 0 if successful,
+/* Attempts to remove 'xfif''s port number 'port_no'.  Returns 0 if successful,
  * otherwise a positive errno value. */
 int
-dpif_port_del(struct dpif *dpif, uint16_t port_no)
+xfif_port_del(struct xfif *xfif, uint16_t port_no)
 {
     int error;
 
-    COVERAGE_INC(dpif_port_del);
+    COVERAGE_INC(xfif_port_del);
 
-    error = dpif->dpif_class->port_del(dpif, port_no);
-    log_operation(dpif, "port_del", error);
+    error = xfif->xfif_class->port_del(xfif, port_no);
+    log_operation(xfif, "port_del", error);
     return error;
 }
 
-/* Looks up port number 'port_no' in 'dpif'.  On success, returns 0 and
+/* Looks up port number 'port_no' in 'xfif'.  On success, returns 0 and
  * initializes '*port' appropriately; on failure, returns a positive errno
  * value. */
 int
-dpif_port_query_by_number(const struct dpif *dpif, uint16_t port_no,
-                          struct odp_port *port)
+xfif_port_query_by_number(const struct xfif *xfif, uint16_t port_no,
+                          struct xflow_port *port)
 {
-    int error = dpif->dpif_class->port_query_by_number(dpif, port_no, port);
+    int error = xfif->xfif_class->port_query_by_number(xfif, port_no, port);
     if (!error) {
         VLOG_DBG_RL(&dpmsg_rl, "%s: port %"PRIu16" is device %s",
-                    dpif_name(dpif), port_no, port->devname);
+                    xfif_name(xfif), port_no, port->devname);
     } else {
         memset(port, 0, sizeof *port);
         VLOG_WARN_RL(&error_rl, "%s: failed to query port %"PRIu16": %s",
-                     dpif_name(dpif), port_no, strerror(error));
+                     xfif_name(xfif), port_no, strerror(error));
     }
     return error;
 }
 
-/* Looks up port named 'devname' in 'dpif'.  On success, returns 0 and
+/* Looks up port named 'devname' in 'xfif'.  On success, returns 0 and
  * initializes '*port' appropriately; on failure, returns a positive errno
  * value. */
 int
-dpif_port_query_by_name(const struct dpif *dpif, const char *devname,
-                        struct odp_port *port)
+xfif_port_query_by_name(const struct xfif *xfif, const char *devname,
+                        struct xflow_port *port)
 {
-    int error = dpif->dpif_class->port_query_by_name(dpif, devname, port);
+    int error = xfif->xfif_class->port_query_by_name(xfif, devname, port);
     if (!error) {
         VLOG_DBG_RL(&dpmsg_rl, "%s: device %s is on port %"PRIu16,
-                    dpif_name(dpif), devname, port->port);
+                    xfif_name(xfif), devname, port->port);
     } else {
         memset(port, 0, sizeof *port);
 
         /* Log level is DBG here because all the current callers are interested
-         * in whether 'dpif' actually has a port 'devname', so that it's not an
+         * in whether 'xfif' actually has a port 'devname', so that it's not an
          * issue worth logging if it doesn't. */
         VLOG_DBG_RL(&error_rl, "%s: failed to query port %s: %s",
-                    dpif_name(dpif), devname, strerror(error));
+                    xfif_name(xfif), devname, strerror(error));
     }
     return error;
 }
 
-/* Looks up port number 'port_no' in 'dpif'.  On success, returns 0 and copies
+/* Looks up port number 'port_no' in 'xfif'.  On success, returns 0 and copies
  * the port's name into the 'name_size' bytes in 'name', ensuring that the
  * result is null-terminated.  On failure, returns a positive errno value and
  * makes 'name' the empty string. */
 int
-dpif_port_get_name(struct dpif *dpif, uint16_t port_no,
+xfif_port_get_name(struct xfif *xfif, uint16_t port_no,
                    char *name, size_t name_size)
 {
-    struct odp_port port;
+    struct xflow_port port;
     int error;
 
     assert(name_size > 0);
 
-    error = dpif_port_query_by_number(dpif, port_no, &port);
+    error = xfif_port_query_by_number(xfif, port_no, &port);
     if (!error) {
         ovs_strlcpy(name, port.devname, name_size);
     } else {
@@ -533,7 +533,7 @@ dpif_port_get_name(struct dpif *dpif, uint16_t port_no,
     return error;
 }
 
-/* Obtains a list of all the ports in 'dpif'.
+/* Obtains a list of all the ports in 'xfif'.
  *
  * If successful, returns 0 and sets '*portsp' to point to an array of
  * appropriately initialized port structures and '*n_portsp' to the number of
@@ -543,24 +543,24 @@ dpif_port_get_name(struct dpif *dpif, uint16_t port_no,
  * On failure, returns a positive errno value and sets '*portsp' to NULL and
  * '*n_portsp' to 0. */
 int
-dpif_port_list(const struct dpif *dpif,
-               struct odp_port **portsp, size_t *n_portsp)
+xfif_port_list(const struct xfif *xfif,
+               struct xflow_port **portsp, size_t *n_portsp)
 {
-    struct odp_port *ports;
+    struct xflow_port *ports;
     size_t n_ports = 0;
     int error;
 
     for (;;) {
-        struct odp_stats stats;
+        struct xflow_stats stats;
         int retval;
 
-        error = dpif_get_dp_stats(dpif, &stats);
+        error = xfif_get_xf_stats(xfif, &stats);
         if (error) {
             goto exit;
         }
 
         ports = xcalloc(stats.n_ports, sizeof *ports);
-        retval = dpif->dpif_class->port_list(dpif, ports, stats.n_ports);
+        retval = xfif->xfif_class->port_list(xfif, ports, stats.n_ports);
         if (retval < 0) {
             /* Hard error. */
             error = -retval;
@@ -585,14 +585,14 @@ exit:
         *portsp = ports;
         *n_portsp = n_ports;
     }
-    log_operation(dpif, "port_list", error);
+    log_operation(xfif, "port_list", error);
     return error;
 }
 
-/* Polls for changes in the set of ports in 'dpif'.  If the set of ports in
- * 'dpif' has changed, this function does one of the following:
+/* Polls for changes in the set of ports in 'xfif'.  If the set of ports in
+ * 'xfif' has changed, this function does one of the following:
  *
- * - Stores the name of the device that was added to or deleted from 'dpif' in
+ * - Stores the name of the device that was added to or deleted from 'xfif' in
  *   '*devnamep' and returns 0.  The caller is responsible for freeing
  *   '*devnamep' (with free()) when it no longer needs it.
  *
@@ -602,38 +602,38 @@ exit:
  * '*devnamep' names a device that was not actually added or deleted or it
  * returns ENOBUFS without any change.
  *
- * Returns EAGAIN if the set of ports in 'dpif' has not changed.  May also
+ * Returns EAGAIN if the set of ports in 'xfif' has not changed.  May also
  * return other positive errno values to indicate that something has gone
  * wrong. */
 int
-dpif_port_poll(const struct dpif *dpif, char **devnamep)
+xfif_port_poll(const struct xfif *xfif, char **devnamep)
 {
-    int error = dpif->dpif_class->port_poll(dpif, devnamep);
+    int error = xfif->xfif_class->port_poll(xfif, devnamep);
     if (error) {
         *devnamep = NULL;
     }
     return error;
 }
 
-/* Arranges for the poll loop to wake up when port_poll(dpif) will return a
+/* Arranges for the poll loop to wake up when port_poll(xfif) will return a
  * value other than EAGAIN. */
 void
-dpif_port_poll_wait(const struct dpif *dpif)
+xfif_port_poll_wait(const struct xfif *xfif)
 {
-    dpif->dpif_class->port_poll_wait(dpif);
+    xfif->xfif_class->port_poll_wait(xfif);
 }
 
-/* Retrieves a list of the port numbers in port group 'group' in 'dpif'.
+/* Retrieves a list of the port numbers in port group 'group' in 'xfif'.
  *
  * On success, returns 0 and points '*ports' to a newly allocated array of
- * integers, each of which is a 'dpif' port number for a port in
+ * integers, each of which is a 'xfif' port number for a port in
  * 'group'.  Stores the number of elements in the array in '*n_ports'.  The
  * caller is responsible for freeing '*ports' by calling free().
  *
  * On failure, returns a positive errno value and sets '*ports' to NULL and
  * '*n_ports' to 0. */
 int
-dpif_port_group_get(const struct dpif *dpif, uint16_t group,
+xfif_port_group_get(const struct xfif *xfif, uint16_t group,
                     uint16_t **ports, size_t *n_ports)
 {
     int error;
@@ -641,7 +641,7 @@ dpif_port_group_get(const struct dpif *dpif, uint16_t group,
     *ports = NULL;
     *n_ports = 0;
     for (;;) {
-        int retval = dpif->dpif_class->port_group_get(dpif, group,
+        int retval = xfif->xfif_class->port_group_get(xfif, group,
                                                       *ports, *n_ports);
         if (retval < 0) {
             /* Hard error. */
@@ -663,45 +663,45 @@ dpif_port_group_get(const struct dpif *dpif, uint16_t group,
             *n_ports = retval;
         }
     }
-    log_operation(dpif, "port_group_get", error);
+    log_operation(xfif, "port_group_get", error);
     return error;
 }
 
-/* Updates port group 'group' in 'dpif', making it contain the 'n_ports' ports
- * whose 'dpif' port numbers are given in 'n_ports'.  Returns 0 if
+/* Updates port group 'group' in 'xfif', making it contain the 'n_ports' ports
+ * whose 'xfif' port numbers are given in 'n_ports'.  Returns 0 if
  * successful, otherwise a positive errno value.
  *
  * Behavior is undefined if the values in ports[] are not unique. */
 int
-dpif_port_group_set(struct dpif *dpif, uint16_t group,
+xfif_port_group_set(struct xfif *xfif, uint16_t group,
                     const uint16_t ports[], size_t n_ports)
 {
     int error;
 
-    COVERAGE_INC(dpif_port_group_set);
+    COVERAGE_INC(xfif_port_group_set);
 
-    error = dpif->dpif_class->port_group_set(dpif, group, ports, n_ports);
-    log_operation(dpif, "port_group_set", error);
+    error = xfif->xfif_class->port_group_set(xfif, group, ports, n_ports);
+    log_operation(xfif, "port_group_set", error);
     return error;
 }
 
-/* Deletes all flows from 'dpif'.  Returns 0 if successful, otherwise a
+/* Deletes all flows from 'xfif'.  Returns 0 if successful, otherwise a
  * positive errno value.  */
 int
-dpif_flow_flush(struct dpif *dpif)
+xfif_flow_flush(struct xfif *xfif)
 {
     int error;
 
-    COVERAGE_INC(dpif_flow_flush);
+    COVERAGE_INC(xfif_flow_flush);
 
-    error = dpif->dpif_class->flow_flush(dpif);
-    log_operation(dpif, "flow_flush", error);
+    error = xfif->xfif_class->flow_flush(xfif);
+    log_operation(xfif, "flow_flush", error);
     return error;
 }
 
-/* Queries 'dpif' for a flow entry matching 'flow->key'.
+/* Queries 'xfif' for a flow entry matching 'flow->key'.
  *
- * If a flow matching 'flow->key' exists in 'dpif', stores statistics for the
+ * If a flow matching 'flow->key' exists in 'xfif', stores statistics for the
  * flow into 'flow->stats'.  If 'flow->n_actions' is zero, then 'flow->actions'
  * is ignored.  If 'flow->n_actions' is nonzero, then 'flow->actions' should
  * point to an array of the specified number of actions.  At most that many of
@@ -710,17 +710,17 @@ dpif_flow_flush(struct dpif *dpif)
  * be greater than the number stored if the flow has more actions than space
  * available in the array.
  *
- * If no flow matching 'flow->key' exists in 'dpif', returns ENOENT.  On other
+ * If no flow matching 'flow->key' exists in 'xfif', returns ENOENT.  On other
  * failure, returns a positive errno value. */
 int
-dpif_flow_get(const struct dpif *dpif, struct odp_flow *flow)
+xfif_flow_get(const struct xfif *xfif, struct xflow_flow *flow)
 {
     int error;
 
-    COVERAGE_INC(dpif_flow_get);
+    COVERAGE_INC(xfif_flow_get);
 
-    check_rw_odp_flow(flow);
-    error = dpif->dpif_class->flow_get(dpif, flow, 1);
+    check_rw_xflow_flow(flow);
+    error = xfif->xfif_class->flow_get(xfif, flow, 1);
     if (!error) {
         error = flow->stats.error;
     }
@@ -730,14 +730,14 @@ dpif_flow_get(const struct dpif *dpif, struct odp_flow *flow)
         flow->n_actions = 0;
     }
     if (should_log_flow_message(error)) {
-        log_flow_operation(dpif, "flow_get", error, flow);
+        log_flow_operation(xfif, "flow_get", error, flow);
     }
     return error;
 }
 
 /* For each flow 'flow' in the 'n' flows in 'flows':
  *
- * - If a flow matching 'flow->key' exists in 'dpif':
+ * - If a flow matching 'flow->key' exists in 'xfif':
  *
  *     Stores 0 into 'flow->stats.error' and stores statistics for the flow
  *     into 'flow->stats'.
@@ -752,7 +752,7 @@ dpif_flow_get(const struct dpif *dpif, struct odp_flow *flow)
  *
  * - Flow-specific errors are indicated by a positive errno value in
  *   'flow->stats.error'.  In particular, ENOENT indicates that no flow
- *   matching 'flow->key' exists in 'dpif'.  When an error value is stored, the
+ *   matching 'flow->key' exists in 'xfif'.  When an error value is stored, the
  *   contents of 'flow->key' are preserved but other members of 'flow' should
  *   be treated as indeterminate.
  *
@@ -763,89 +763,89 @@ dpif_flow_get(const struct dpif *dpif, struct odp_flow *flow)
  * 'flows' being updated or not updated.
  */
 int
-dpif_flow_get_multiple(const struct dpif *dpif,
-                       struct odp_flow flows[], size_t n)
+xfif_flow_get_multiple(const struct xfif *xfif,
+                       struct xflow_flow flows[], size_t n)
 {
     int error;
     size_t i;
 
-    COVERAGE_ADD(dpif_flow_get, n);
+    COVERAGE_ADD(xfif_flow_get, n);
 
     for (i = 0; i < n; i++) {
-        check_rw_odp_flow(&flows[i]);
+        check_rw_xflow_flow(&flows[i]);
     }
 
-    error = dpif->dpif_class->flow_get(dpif, flows, n);
-    log_operation(dpif, "flow_get_multiple", error);
+    error = xfif->xfif_class->flow_get(xfif, flows, n);
+    log_operation(xfif, "flow_get_multiple", error);
     return error;
 }
 
-/* Adds or modifies a flow in 'dpif' as specified in 'put':
+/* Adds or modifies a flow in 'xfif' as specified in 'put':
  *
- * - If the flow specified in 'put->flow' does not exist in 'dpif', then
- *   behavior depends on whether ODPPF_CREATE is specified in 'put->flags': if
+ * - If the flow specified in 'put->flow' does not exist in 'xfif', then
+ *   behavior depends on whether XFLOWPF_CREATE is specified in 'put->flags': if
  *   it is, the flow will be added, otherwise the operation will fail with
  *   ENOENT.
  *
- * - Otherwise, the flow specified in 'put->flow' does exist in 'dpif'.
- *   Behavior in this case depends on whether ODPPF_MODIFY is specified in
+ * - Otherwise, the flow specified in 'put->flow' does exist in 'xfif'.
+ *   Behavior in this case depends on whether XFLOWPF_MODIFY is specified in
  *   'put->flags': if it is, the flow's actions will be updated, otherwise the
  *   operation will fail with EEXIST.  If the flow's actions are updated, then
- *   its statistics will be zeroed if ODPPF_ZERO_STATS is set in 'put->flags',
+ *   its statistics will be zeroed if XFLOWPF_ZERO_STATS is set in 'put->flags',
  *   left as-is otherwise.
  *
  * Returns 0 if successful, otherwise a positive errno value.
  */
 int
-dpif_flow_put(struct dpif *dpif, struct odp_flow_put *put)
+xfif_flow_put(struct xfif *xfif, struct xflow_flow_put *put)
 {
     int error;
 
-    COVERAGE_INC(dpif_flow_put);
+    COVERAGE_INC(xfif_flow_put);
 
-    error = dpif->dpif_class->flow_put(dpif, put);
+    error = xfif->xfif_class->flow_put(xfif, put);
     if (should_log_flow_message(error)) {
-        log_flow_put(dpif, error, put);
+        log_flow_put(xfif, error, put);
     }
     return error;
 }
 
-/* Deletes a flow matching 'flow->key' from 'dpif' or returns ENOENT if 'dpif'
+/* Deletes a flow matching 'flow->key' from 'xfif' or returns ENOENT if 'xfif'
  * does not contain such a flow.
  *
  * If successful, updates 'flow->stats', 'flow->n_actions', and 'flow->actions'
- * as described for dpif_flow_get(). */
+ * as described for xfif_flow_get(). */
 int
-dpif_flow_del(struct dpif *dpif, struct odp_flow *flow)
+xfif_flow_del(struct xfif *xfif, struct xflow_flow *flow)
 {
     int error;
 
-    COVERAGE_INC(dpif_flow_del);
+    COVERAGE_INC(xfif_flow_del);
 
-    check_rw_odp_flow(flow);
+    check_rw_xflow_flow(flow);
     memset(&flow->stats, 0, sizeof flow->stats);
 
-    error = dpif->dpif_class->flow_del(dpif, flow);
+    error = xfif->xfif_class->flow_del(xfif, flow);
     if (should_log_flow_message(error)) {
-        log_flow_operation(dpif, "delete flow", error, flow);
+        log_flow_operation(xfif, "delete flow", error, flow);
     }
     return error;
 }
 
-/* Stores up to 'n' flows in 'dpif' into 'flows', including their statistics
+/* Stores up to 'n' flows in 'xfif' into 'flows', including their statistics
  * but not including any information about their actions.  If successful,
  * returns 0 and sets '*n_out' to the number of flows actually present in
- * 'dpif', which might be greater than the number stored (if 'dpif' has more
+ * 'xfif', which might be greater than the number stored (if 'xfif' has more
  * than 'n' flows).  On failure, returns a negative errno value and sets
  * '*n_out' to 0. */
 int
-dpif_flow_list(const struct dpif *dpif, struct odp_flow flows[], size_t n,
+xfif_flow_list(const struct xfif *xfif, struct xflow_flow flows[], size_t n,
                size_t *n_out)
 {
     uint32_t i;
     int retval;
 
-    COVERAGE_INC(dpif_flow_query_list);
+    COVERAGE_INC(xfif_flow_query_list);
     if (RUNNING_ON_VALGRIND) {
         memset(flows, 0, n * sizeof *flows);
     } else {
@@ -854,22 +854,22 @@ dpif_flow_list(const struct dpif *dpif, struct odp_flow flows[], size_t n,
             flows[i].n_actions = 0;
         }
     }
-    retval = dpif->dpif_class->flow_list(dpif, flows, n);
+    retval = xfif->xfif_class->flow_list(xfif, flows, n);
     if (retval < 0) {
         *n_out = 0;
         VLOG_WARN_RL(&error_rl, "%s: flow list failed (%s)",
-                     dpif_name(dpif), strerror(-retval));
+                     xfif_name(xfif), strerror(-retval));
         return -retval;
     } else {
-        COVERAGE_ADD(dpif_flow_query_list_n, retval);
+        COVERAGE_ADD(xfif_flow_query_list_n, retval);
         *n_out = MIN(n, retval);
         VLOG_DBG_RL(&dpmsg_rl, "%s: listed %zu flows (of %d)",
-                    dpif_name(dpif), *n_out, retval);
+                    xfif_name(xfif), *n_out, retval);
         return 0;
     }
 }
 
-/* Retrieves all of the flows in 'dpif'.
+/* Retrieves all of the flows in 'xfif'.
  *
  * If successful, returns 0 and stores in '*flowsp' a pointer to a newly
  * allocated array of flows, including their statistics but not including any
@@ -880,24 +880,24 @@ dpif_flow_list(const struct dpif *dpif, struct odp_flow flows[], size_t n,
  * On failure, returns a positive errno value and sets '*flowsp' to NULL and
  * '*np' to 0. */
 int
-dpif_flow_list_all(const struct dpif *dpif,
-                   struct odp_flow **flowsp, size_t *np)
+xfif_flow_list_all(const struct xfif *xfif,
+                   struct xflow_flow **flowsp, size_t *np)
 {
-    struct odp_stats stats;
-    struct odp_flow *flows;
+    struct xflow_stats stats;
+    struct xflow_flow *flows;
     size_t n_flows;
     int error;
 
     *flowsp = NULL;
     *np = 0;
 
-    error = dpif_get_dp_stats(dpif, &stats);
+    error = xfif_get_xf_stats(xfif, &stats);
     if (error) {
         return error;
     }
 
     flows = xmalloc(sizeof *flows * stats.n_flows);
-    error = dpif_flow_list(dpif, flows, stats.n_flows, &n_flows);
+    error = xfif_flow_list(xfif, flows, stats.n_flows, &n_flows);
     if (error) {
         free(flows);
         return error;
@@ -906,32 +906,32 @@ dpif_flow_list_all(const struct dpif *dpif,
     if (stats.n_flows != n_flows) {
         VLOG_WARN_RL(&error_rl, "%s: datapath stats reported %"PRIu32" "
                      "flows but flow listing reported %zu",
-                     dpif_name(dpif), stats.n_flows, n_flows);
+                     xfif_name(xfif), stats.n_flows, n_flows);
     }
     *flowsp = flows;
     *np = n_flows;
     return 0;
 }
 
-/* Causes 'dpif' to perform the 'n_actions' actions in 'actions' on the
+/* Causes 'xfif' to perform the 'n_actions' actions in 'actions' on the
  * Ethernet frame specified in 'packet'.
  *
  * Pretends that the frame was originally received on the port numbered
- * 'in_port'.  This affects only ODPAT_OUTPUT_GROUP actions, which will not
+ * 'in_port'.  This affects only XFLOWAT_OUTPUT_GROUP actions, which will not
  * send a packet out their input port.  Specify the number of an unused port
  * (e.g. UINT16_MAX is currently always unused) to avoid this behavior.
  *
  * Returns 0 if successful, otherwise a positive errno value. */
 int
-dpif_execute(struct dpif *dpif, uint16_t in_port,
-             const union odp_action actions[], size_t n_actions,
+xfif_execute(struct xfif *xfif, uint16_t in_port,
+             const union xflow_action actions[], size_t n_actions,
              const struct ofpbuf *buf)
 {
     int error;
 
-    COVERAGE_INC(dpif_execute);
+    COVERAGE_INC(xfif_execute);
     if (n_actions > 0) {
-        error = dpif->dpif_class->execute(dpif, in_port, actions,
+        error = xfif->xfif_class->execute(xfif, in_port, actions,
                                           n_actions, buf);
     } else {
         error = 0;
@@ -940,8 +940,8 @@ dpif_execute(struct dpif *dpif, uint16_t in_port,
     if (!(error ? VLOG_DROP_WARN(&error_rl) : VLOG_DROP_DBG(&dpmsg_rl))) {
         struct ds ds = DS_EMPTY_INITIALIZER;
         char *packet = ofp_packet_to_string(buf->data, buf->size, buf->size);
-        ds_put_format(&ds, "%s: execute ", dpif_name(dpif));
-        format_odp_actions(&ds, actions, n_actions);
+        ds_put_format(&ds, "%s: execute ", xfif_name(xfif));
+        format_xflow_actions(&ds, actions, n_actions);
         if (error) {
             ds_put_format(&ds, " failed (%s)", strerror(error));
         }
@@ -953,28 +953,28 @@ dpif_execute(struct dpif *dpif, uint16_t in_port,
     return error;
 }
 
-/* Retrieves 'dpif''s "listen mask" into '*listen_mask'.  Each ODPL_* bit set
- * in '*listen_mask' indicates that dpif_recv() will receive messages of that
+/* Retrieves 'xfif''s "listen mask" into '*listen_mask'.  Each XFLOWL_* bit set
+ * in '*listen_mask' indicates that xfif_recv() will receive messages of that
  * type.  Returns 0 if successful, otherwise a positive errno value. */
 int
-dpif_recv_get_mask(const struct dpif *dpif, int *listen_mask)
+xfif_recv_get_mask(const struct xfif *xfif, int *listen_mask)
 {
-    int error = dpif->dpif_class->recv_get_mask(dpif, listen_mask);
+    int error = xfif->xfif_class->recv_get_mask(xfif, listen_mask);
     if (error) {
         *listen_mask = 0;
     }
-    log_operation(dpif, "recv_get_mask", error);
+    log_operation(xfif, "recv_get_mask", error);
     return error;
 }
 
-/* Sets 'dpif''s "listen mask" to 'listen_mask'.  Each ODPL_* bit set in
- * '*listen_mask' requests that dpif_recv() receive messages of that type.
+/* Sets 'xfif''s "listen mask" to 'listen_mask'.  Each XFLOWL_* bit set in
+ * '*listen_mask' requests that xfif_recv() receive messages of that type.
  * Returns 0 if successful, otherwise a positive errno value. */
 int
-dpif_recv_set_mask(struct dpif *dpif, int listen_mask)
+xfif_recv_set_mask(struct xfif *xfif, int listen_mask)
 {
-    int error = dpif->dpif_class->recv_set_mask(dpif, listen_mask);
-    log_operation(dpif, "recv_set_mask", error);
+    int error = xfif->xfif_class->recv_set_mask(xfif, listen_mask);
+    log_operation(xfif, "recv_set_mask", error);
     return error;
 }
 
@@ -983,17 +983,17 @@ dpif_recv_set_mask(struct dpif *dpif, int listen_mask)
  * the probability of sampling a given packet.
  *
  * Returns 0 if successful, otherwise a positive errno value.  EOPNOTSUPP
- * indicates that 'dpif' does not support sFlow sampling. */
+ * indicates that 'xfif' does not support sFlow sampling. */
 int
-dpif_get_sflow_probability(const struct dpif *dpif, uint32_t *probability)
+xfif_get_sflow_probability(const struct xfif *xfif, uint32_t *probability)
 {
-    int error = (dpif->dpif_class->get_sflow_probability
-                 ? dpif->dpif_class->get_sflow_probability(dpif, probability)
+    int error = (xfif->xfif_class->get_sflow_probability
+                 ? xfif->xfif_class->get_sflow_probability(xfif, probability)
                  : EOPNOTSUPP);
     if (error) {
         *probability = 0;
     }
-    log_operation(dpif, "get_sflow_probability", error);
+    log_operation(xfif, "get_sflow_probability", error);
     return error;
 }
 
@@ -1002,44 +1002,44 @@ dpif_get_sflow_probability(const struct dpif *dpif, uint32_t *probability)
  * the probability of sampling a given packet.
  *
  * Returns 0 if successful, otherwise a positive errno value.  EOPNOTSUPP
- * indicates that 'dpif' does not support sFlow sampling. */
+ * indicates that 'xfif' does not support sFlow sampling. */
 int
-dpif_set_sflow_probability(struct dpif *dpif, uint32_t probability)
+xfif_set_sflow_probability(struct xfif *xfif, uint32_t probability)
 {
-    int error = (dpif->dpif_class->set_sflow_probability
-                 ? dpif->dpif_class->set_sflow_probability(dpif, probability)
+    int error = (xfif->xfif_class->set_sflow_probability
+                 ? xfif->xfif_class->set_sflow_probability(xfif, probability)
                  : EOPNOTSUPP);
-    log_operation(dpif, "set_sflow_probability", error);
+    log_operation(xfif, "set_sflow_probability", error);
     return error;
 }
 
-/* Attempts to receive a message from 'dpif'.  If successful, stores the
+/* Attempts to receive a message from 'xfif'.  If successful, stores the
  * message into '*packetp'.  The message, if one is received, will begin with
- * 'struct odp_msg' as a header, and will have at least DPIF_RECV_MSG_PADDING
+ * 'struct xflow_msg' as a header, and will have at least XFIF_RECV_MSG_PADDING
  * bytes of headroom.  Only messages of the types selected with
- * dpif_set_listen_mask() will ordinarily be received (but if a message type is
+ * xfif_set_listen_mask() will ordinarily be received (but if a message type is
  * enabled and then later disabled, some stragglers might pop up).
  *
  * Returns 0 if successful, otherwise a positive errno value.  Returns EAGAIN
  * if no message is immediately available. */
 int
-dpif_recv(struct dpif *dpif, struct ofpbuf **packetp)
+xfif_recv(struct xfif *xfif, struct ofpbuf **packetp)
 {
-    int error = dpif->dpif_class->recv(dpif, packetp);
+    int error = xfif->xfif_class->recv(xfif, packetp);
     if (!error) {
         struct ofpbuf *buf = *packetp;
 
-        assert(ofpbuf_headroom(buf) >= DPIF_RECV_MSG_PADDING);
+        assert(ofpbuf_headroom(buf) >= XFIF_RECV_MSG_PADDING);
         if (VLOG_IS_DBG_ENABLED()) {
-            struct odp_msg *msg = buf->data;
+            struct xflow_msg *msg = buf->data;
             void *payload = msg + 1;
             size_t payload_len = buf->size - sizeof *msg;
             char *s = ofp_packet_to_string(payload, payload_len, payload_len);
             VLOG_DBG_RL(&dpmsg_rl, "%s: received %s message of length "
-                        "%zu on port %"PRIu16": %s", dpif_name(dpif),
-                        (msg->type == _ODPL_MISS_NR ? "miss"
-                         : msg->type == _ODPL_ACTION_NR ? "action"
-                         : msg->type == _ODPL_SFLOW_NR ? "sFlow"
+                        "%zu on port %"PRIu16": %s", xfif_name(xfif),
+                        (msg->type == _XFLOWL_MISS_NR ? "miss"
+                         : msg->type == _XFLOWL_ACTION_NR ? "action"
+                         : msg->type == _XFLOWL_SFLOW_NR ? "sFlow"
                          : "<unknown>"),
                         payload_len, msg->port, s);
             free(s);
@@ -1050,25 +1050,25 @@ dpif_recv(struct dpif *dpif, struct ofpbuf **packetp)
     return error;
 }
 
-/* Discards all messages that would otherwise be received by dpif_recv() on
- * 'dpif'.  Returns 0 if successful, otherwise a positive errno value. */
+/* Discards all messages that would otherwise be received by xfif_recv() on
+ * 'xfif'.  Returns 0 if successful, otherwise a positive errno value. */
 int
-dpif_recv_purge(struct dpif *dpif)
+xfif_recv_purge(struct xfif *xfif)
 {
-    struct odp_stats stats;
+    struct xflow_stats stats;
     unsigned int i;
     int error;
 
-    COVERAGE_INC(dpif_purge);
+    COVERAGE_INC(xfif_purge);
 
-    error = dpif_get_dp_stats(dpif, &stats);
+    error = xfif_get_xf_stats(xfif, &stats);
     if (error) {
         return error;
     }
 
     for (i = 0; i < stats.max_miss_queue + stats.max_action_queue + stats.max_sflow_queue; i++) {
         struct ofpbuf *buf;
-        error = dpif_recv(dpif, &buf);
+        error = xfif_recv(xfif, &buf);
         if (error) {
             return error == EAGAIN ? 0 : error;
         }
@@ -1077,50 +1077,50 @@ dpif_recv_purge(struct dpif *dpif)
     return 0;
 }
 
-/* Arranges for the poll loop to wake up when 'dpif' has a message queued to be
- * received with dpif_recv(). */
+/* Arranges for the poll loop to wake up when 'xfif' has a message queued to be
+ * received with xfif_recv(). */
 void
-dpif_recv_wait(struct dpif *dpif)
+xfif_recv_wait(struct xfif *xfif)
 {
-    dpif->dpif_class->recv_wait(dpif);
+    xfif->xfif_class->recv_wait(xfif);
 }
 
-/* Obtains the NetFlow engine type and engine ID for 'dpif' into '*engine_type'
+/* Obtains the NetFlow engine type and engine ID for 'xfif' into '*engine_type'
  * and '*engine_id', respectively. */
 void
-dpif_get_netflow_ids(const struct dpif *dpif,
+xfif_get_netflow_ids(const struct xfif *xfif,
                      uint8_t *engine_type, uint8_t *engine_id)
 {
-    *engine_type = dpif->netflow_engine_type;
-    *engine_id = dpif->netflow_engine_id;
+    *engine_type = xfif->netflow_engine_type;
+    *engine_id = xfif->netflow_engine_id;
 }
 \f
 void
-dpif_init(struct dpif *dpif, const struct dpif_class *dpif_class,
+xfif_init(struct xfif *xfif, const struct xfif_class *xfif_class,
           const char *name,
           uint8_t netflow_engine_type, uint8_t netflow_engine_id)
 {
-    dpif->dpif_class = dpif_class;
-    dpif->base_name = xstrdup(name);
-    dpif->full_name = xasprintf("%s@%s", dpif_class->type, name);
-    dpif->netflow_engine_type = netflow_engine_type;
-    dpif->netflow_engine_id = netflow_engine_id;
+    xfif->xfif_class = xfif_class;
+    xfif->base_name = xstrdup(name);
+    xfif->full_name = xasprintf("%s@%s", xfif_class->type, name);
+    xfif->netflow_engine_type = netflow_engine_type;
+    xfif->netflow_engine_id = netflow_engine_id;
 }
 
 /* Undoes the results of initialization.
  *
- * Normally this function only needs to be called from dpif_close().
+ * Normally this function only needs to be called from xfif_close().
  * However, it may be called by providers due to an error on opening
- * that occurs after initialization.  It this case dpif_close() would
+ * that occurs after initialization.  In this case xfif_close() would
  * never be called. */
 void
-dpif_uninit(struct dpif *dpif, bool close)
+xfif_uninit(struct xfif *xfif, bool close)
 {
-    char *base_name = dpif->base_name;
-    char *full_name = dpif->full_name;
+    char *base_name = xfif->base_name;
+    char *full_name = xfif->full_name;
 
     if (close) {
-        dpif->dpif_class->close(dpif);
+        xfif->xfif_class->close(xfif);
     }
 
     free(base_name);
@@ -1128,13 +1128,13 @@ dpif_uninit(struct dpif *dpif, bool close)
 }
 \f
 static void
-log_operation(const struct dpif *dpif, const char *operation, int error)
+log_operation(const struct xfif *xfif, const char *operation, int error)
 {
     if (!error) {
-        VLOG_DBG_RL(&dpmsg_rl, "%s: %s success", dpif_name(dpif), operation);
+        VLOG_DBG_RL(&dpmsg_rl, "%s: %s success", xfif_name(xfif), operation);
     } else {
         VLOG_WARN_RL(&error_rl, "%s: %s failed (%s)",
-                     dpif_name(dpif), operation, strerror(error));
+                     xfif_name(xfif), operation, strerror(error));
     }
 }
 
@@ -1152,12 +1152,13 @@ should_log_flow_message(int error)
 }
 
 static void
-log_flow_message(const struct dpif *dpif, int error, const char *operation,
-                 const flow_t *flow, const struct odp_flow_stats *stats,
-                 const union odp_action *actions, size_t n_actions)
+log_flow_message(const struct xfif *xfif, int error, const char *operation,
+                 const struct xflow_key *flow,
+                 const struct xflow_flow_stats *stats,
+                 const union xflow_action *actions, size_t n_actions)
 {
     struct ds ds = DS_EMPTY_INITIALIZER;
-    ds_put_format(&ds, "%s: ", dpif_name(dpif));
+    ds_put_format(&ds, "%s: ", xfif_name(xfif));
     if (error) {
         ds_put_cstr(&ds, "failed to ");
     }
@@ -1165,58 +1166,58 @@ log_flow_message(const struct dpif *dpif, int error, const char *operation,
     if (error) {
         ds_put_format(&ds, "(%s) ", strerror(error));
     }
-    flow_format(&ds, flow);
+    format_xflow_key(&ds, flow);
     if (stats) {
         ds_put_cstr(&ds, ", ");
-        format_odp_flow_stats(&ds, stats);
+        format_xflow_flow_stats(&ds, stats);
     }
     if (actions || n_actions) {
         ds_put_cstr(&ds, ", actions:");
-        format_odp_actions(&ds, actions, n_actions);
+        format_xflow_actions(&ds, actions, n_actions);
     }
     vlog(THIS_MODULE, flow_message_log_level(error), "%s", ds_cstr(&ds));
     ds_destroy(&ds);
 }
 
 static void
-log_flow_operation(const struct dpif *dpif, const char *operation, int error,
-                   struct odp_flow *flow)
+log_flow_operation(const struct xfif *xfif, const char *operation, int error,
+                   struct xflow_flow *flow)
 {
     if (error) {
         flow->n_actions = 0;
     }
-    log_flow_message(dpif, error, operation, &flow->key,
+    log_flow_message(xfif, error, operation, &flow->key,
                      !error ? &flow->stats : NULL,
                      flow->actions, flow->n_actions);
 }
 
 static void
-log_flow_put(struct dpif *dpif, int error, const struct odp_flow_put *put)
+log_flow_put(struct xfif *xfif, int error, const struct xflow_flow_put *put)
 {
-    enum { ODPPF_ALL = ODPPF_CREATE | ODPPF_MODIFY | ODPPF_ZERO_STATS };
+    enum { XFLOWPF_ALL = XFLOWPF_CREATE | XFLOWPF_MODIFY | XFLOWPF_ZERO_STATS };
     struct ds s;
 
     ds_init(&s);
     ds_put_cstr(&s, "put");
-    if (put->flags & ODPPF_CREATE) {
+    if (put->flags & XFLOWPF_CREATE) {
         ds_put_cstr(&s, "[create]");
     }
-    if (put->flags & ODPPF_MODIFY) {
+    if (put->flags & XFLOWPF_MODIFY) {
         ds_put_cstr(&s, "[modify]");
     }
-    if (put->flags & ODPPF_ZERO_STATS) {
+    if (put->flags & XFLOWPF_ZERO_STATS) {
         ds_put_cstr(&s, "[zero]");
     }
-    if (put->flags & ~ODPPF_ALL) {
-        ds_put_format(&s, "[%x]", put->flags & ~ODPPF_ALL);
+    if (put->flags & ~XFLOWPF_ALL) {
+        ds_put_format(&s, "[%x]", put->flags & ~XFLOWPF_ALL);
     }
-    log_flow_message(dpif, error, ds_cstr(&s), &put->flow.key,
+    log_flow_message(xfif, error, ds_cstr(&s), &put->flow.key,
                      !error ? &put->flow.stats : NULL,
                      put->flow.actions, put->flow.n_actions);
     ds_destroy(&s);
 }
 
-/* There is a tendency to construct odp_flow objects on the stack and to
+/* There is a tendency to construct xflow_flow objects on the stack and to
  * forget to properly initialize their "actions" and "n_actions" members.
  * When this happens, we get memory corruption because the kernel
  * writes through the random pointer that is in the "actions" member.
@@ -1233,7 +1234,7 @@ log_flow_put(struct dpif *dpif, int error, const struct odp_flow_put *put)
  *        "actions" or "n_actions" was not initialized.
  */
 static void
-check_rw_odp_flow(struct odp_flow *flow)
+check_rw_xflow_flow(struct xflow_flow *flow)
 {
     if (flow->n_actions) {
         memset(&flow->actions[0], 0xcc, sizeof flow->actions[0]);
diff --git a/lib/xfif.h b/lib/xfif.h
new file mode 100644 (file)
index 0000000..4059c8c
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef XFIF_H
+#define XFIF_H 1
+
+#include "openvswitch/xflow.h"
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+struct xfif;
+struct ofpbuf;
+struct svec;
+struct xfif_class;
+
+void xf_run(void);
+void xf_wait(void);
+
+int xf_register_provider(const struct xfif_class *);
+int xf_unregister_provider(const char *type);
+void xf_enumerate_types(struct svec *types);
+
+int xf_enumerate_names(const char *type, struct svec *names);
+void xf_parse_name(const char *datapath_name, char **name, char **type);
+
+int xfif_open(const char *name, const char *type, struct xfif **);
+int xfif_create(const char *name, const char *type, struct xfif **);
+int xfif_create_and_open(const char *name, const char *type, struct xfif **);
+void xfif_close(struct xfif *);
+
+const char *xfif_name(const struct xfif *);
+const char *xfif_base_name(const struct xfif *);
+int xfif_get_all_names(const struct xfif *, struct svec *);
+
+int xfif_delete(struct xfif *);
+
+int xfif_get_xf_stats(const struct xfif *, struct xflow_stats *);
+int xfif_get_drop_frags(const struct xfif *, bool *drop_frags);
+int xfif_set_drop_frags(struct xfif *, bool drop_frags);
+
+int xfif_port_add(struct xfif *, const char *devname, uint16_t flags,
+                  uint16_t *port_no);
+int xfif_port_del(struct xfif *, uint16_t port_no);
+int xfif_port_query_by_number(const struct xfif *, uint16_t port_no,
+                              struct xflow_port *);
+int xfif_port_query_by_name(const struct xfif *, const char *devname,
+                            struct xflow_port *);
+int xfif_port_get_name(struct xfif *, uint16_t port_no,
+                       char *name, size_t name_size);
+int xfif_port_list(const struct xfif *, struct xflow_port **, size_t *n_ports);
+
+int xfif_port_poll(const struct xfif *, char **devnamep);
+void xfif_port_poll_wait(const struct xfif *);
+
+int xfif_port_group_get(const struct xfif *, uint16_t group,
+                        uint16_t **ports, size_t *n_ports);
+int xfif_port_group_set(struct xfif *, uint16_t group,
+                        const uint16_t ports[], size_t n_ports);
+
+int xfif_flow_flush(struct xfif *);
+int xfif_flow_put(struct xfif *, struct xflow_flow_put *);
+int xfif_flow_del(struct xfif *, struct xflow_flow *);
+int xfif_flow_get(const struct xfif *, struct xflow_flow *);
+int xfif_flow_get_multiple(const struct xfif *, struct xflow_flow[], size_t n);
+int xfif_flow_list(const struct xfif *, struct xflow_flow[], size_t n,
+                   size_t *n_out);
+int xfif_flow_list_all(const struct xfif *,
+                       struct xflow_flow **flowsp, size_t *np);
+
+int xfif_execute(struct xfif *, uint16_t in_port,
+                 const union xflow_action[], size_t n_actions,
+                 const struct ofpbuf *);
+
+int xfif_recv_get_mask(const struct xfif *, int *listen_mask);
+int xfif_recv_set_mask(struct xfif *, int listen_mask);
+int xfif_get_sflow_probability(const struct xfif *, uint32_t *probability);
+int xfif_set_sflow_probability(struct xfif *, uint32_t probability);
+int xfif_recv(struct xfif *, struct ofpbuf **);
+int xfif_recv_purge(struct xfif *);
+void xfif_recv_wait(struct xfif *);
+
+void xfif_get_netflow_ids(const struct xfif *,
+                          uint8_t *engine_type, uint8_t *engine_id);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* xfif.h */
similarity index 100%
rename from lib/dpif.man
rename to lib/xfif.man
diff --git a/lib/xflow-util.c b/lib/xflow-util.c
new file mode 100644 (file)
index 0000000..b6d2d13
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "xflow-util.h"
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include "coverage.h"
+#include "dynamic-string.h"
+#include "flow.h"
+#include "packets.h"
+#include "timeval.h"
+#include "util.h"
+
+union xflow_action *
+xflow_actions_add(struct xflow_actions *actions, uint16_t type)
+{
+    union xflow_action *a;
+    if (actions->n_actions < MAX_XFLOW_ACTIONS) {
+        a = &actions->actions[actions->n_actions++];
+    } else {
+        COVERAGE_INC(xflow_overflow);
+        actions->n_actions = MAX_XFLOW_ACTIONS + 1;
+        a = &actions->actions[MAX_XFLOW_ACTIONS - 1];
+    }
+    memset(a, 0, sizeof *a);
+    a->type = type;
+    return a;
+}
+
+void
+format_xflow_key(struct ds *ds, const struct xflow_key *key)
+{
+    ds_put_format(ds, "tunnel%"PRIx32":in_port%04x",
+                  key->tun_id, key->in_port);
+    if (key->dl_tci) {
+        ds_put_format(ds, ":vlan%"PRIu16":pcp%d",
+                      vlan_tci_to_vid(key->dl_tci),
+                      vlan_tci_to_pcp(key->dl_tci));
+    }
+    ds_put_format(ds, " mac"ETH_ADDR_FMT"->"ETH_ADDR_FMT" type%04x "
+                  "proto%"PRId8" tos%"PRIu8" ip"IP_FMT"->"IP_FMT" port%d->%d",
+                  ETH_ADDR_ARGS(key->dl_src), ETH_ADDR_ARGS(key->dl_dst),
+                  ntohs(key->dl_type), key->nw_proto, key->nw_tos,
+                  IP_ARGS(&key->nw_src), IP_ARGS(&key->nw_dst),
+                  ntohs(key->tp_src), ntohs(key->tp_dst));
+}
+
+void
+format_xflow_action(struct ds *ds, const union xflow_action *a)
+{
+    switch (a->type) {
+    case XFLOWAT_OUTPUT:
+        ds_put_format(ds, "%"PRIu16, a->output.port);
+        break;
+    case XFLOWAT_OUTPUT_GROUP:
+        ds_put_format(ds, "g%"PRIu16, a->output_group.group);
+        break;
+    case XFLOWAT_CONTROLLER:
+        ds_put_format(ds, "ctl(%"PRIu32")", a->controller.arg);
+        break;
+    case XFLOWAT_SET_TUNNEL:
+        ds_put_format(ds, "set_tunnel(0x%08"PRIx32")", ntohl(a->tunnel.tun_id));
+        break;
+    case XFLOWAT_SET_DL_TCI:
+        ds_put_format(ds, "set_tci(%04"PRIx16",mask=%04"PRIx16")",
+                      ntohs(a->dl_tci.tci), ntohs(a->dl_tci.mask));
+        break;
+    case XFLOWAT_STRIP_VLAN:
+        ds_put_format(ds, "strip_vlan");
+        break;
+    case XFLOWAT_SET_DL_SRC:
+        ds_put_format(ds, "set_dl_src("ETH_ADDR_FMT")",
+               ETH_ADDR_ARGS(a->dl_addr.dl_addr));
+        break;
+    case XFLOWAT_SET_DL_DST:
+        ds_put_format(ds, "set_dl_dst("ETH_ADDR_FMT")",
+               ETH_ADDR_ARGS(a->dl_addr.dl_addr));
+        break;
+    case XFLOWAT_SET_NW_SRC:
+        ds_put_format(ds, "set_nw_src("IP_FMT")",
+                      IP_ARGS(&a->nw_addr.nw_addr));
+        break;
+    case XFLOWAT_SET_NW_DST:
+        ds_put_format(ds, "set_nw_dst("IP_FMT")",
+                      IP_ARGS(&a->nw_addr.nw_addr));
+        break;
+    case XFLOWAT_SET_NW_TOS:
+        ds_put_format(ds, "set_nw_tos(%"PRIu8")", a->nw_tos.nw_tos);
+        break;
+    case XFLOWAT_SET_TP_SRC:
+        ds_put_format(ds, "set_tp_src(%"PRIu16")", ntohs(a->tp_port.tp_port));
+        break;
+    case XFLOWAT_SET_TP_DST:
+        ds_put_format(ds, "set_tp_dst(%"PRIu16")", ntohs(a->tp_port.tp_port));
+        break;
+    default:
+        ds_put_format(ds, "***bad action 0x%"PRIx16"***", a->type);
+        break;
+    }
+}
+
+void
+format_xflow_actions(struct ds *ds, const union xflow_action *actions,
+                   size_t n_actions)
+{
+    size_t i;
+    for (i = 0; i < n_actions; i++) {
+        if (i) {
+            ds_put_char(ds, ',');
+        }
+        format_xflow_action(ds, &actions[i]);
+    }
+    if (!n_actions) {
+        ds_put_cstr(ds, "drop");
+    }
+}
+
+void
+format_xflow_flow_stats(struct ds *ds, const struct xflow_flow_stats *s)
+{
+    ds_put_format(ds, "packets:%llu, bytes:%llu, used:",
+                  (unsigned long long int) s->n_packets,
+                  (unsigned long long int) s->n_bytes);
+    if (s->used_sec) {
+        long long int used = s->used_sec * 1000 + s->used_nsec / 1000000;
+        ds_put_format(ds, "%.3fs", (time_msec() - used) / 1000.0);
+    } else {
+        ds_put_format(ds, "never");
+    }
+}
+
+void
+format_xflow_flow(struct ds *ds, const struct xflow_flow *f)
+{
+    format_xflow_key(ds, &f->key);
+    ds_put_cstr(ds, ", ");
+    format_xflow_flow_stats(ds, &f->stats);
+    ds_put_cstr(ds, ", actions:");
+    format_xflow_actions(ds, f->actions, f->n_actions);
+}
+\f
+void
+xflow_key_from_flow(struct xflow_key *key, const struct flow *flow)
+{
+    key->tun_id = flow->tun_id;
+    key->nw_src = flow->nw_src;
+    key->nw_dst = flow->nw_dst;
+    key->in_port = ofp_port_to_xflow_port(flow->in_port);
+    if (flow->dl_vlan == htons(OFP_VLAN_NONE)) {
+        key->dl_tci = htons(0);
+    } else {
+        uint16_t vid = flow->dl_vlan & htons(VLAN_VID_MASK);
+        uint16_t pcp = htons((flow->dl_vlan_pcp << VLAN_PCP_SHIFT)
+                             & VLAN_PCP_MASK);
+        key->dl_tci = vid | pcp | htons(XFLOW_TCI_PRESENT);
+    }
+    key->dl_type = flow->dl_type;
+    key->tp_src = flow->tp_src;
+    key->tp_dst = flow->tp_dst;
+    memcpy(key->dl_src, flow->dl_src, ETH_ALEN);
+    memcpy(key->dl_dst, flow->dl_dst, ETH_ALEN);
+    key->nw_proto = flow->nw_proto;
+    key->nw_tos = flow->nw_tos;
+}
+
+void
+xflow_key_to_flow(const struct xflow_key *key, struct flow *flow)
+{
+    flow->wildcards = 0;
+    flow->priority = 0xffff;
+    flow->tun_id = key->tun_id;
+    flow->nw_src = key->nw_src;
+    flow->nw_dst = key->nw_dst;
+    flow->in_port = xflow_port_to_ofp_port(key->in_port);
+    if (key->dl_tci) {
+        flow->dl_vlan = htons(vlan_tci_to_vid(key->dl_tci));
+        flow->dl_vlan_pcp = vlan_tci_to_pcp(key->dl_tci);
+    } else {
+        flow->dl_vlan = htons(OFP_VLAN_NONE);
+        flow->dl_vlan_pcp = 0;
+    }
+    flow->dl_type = key->dl_type;
+    flow->tp_src = key->tp_src;
+    flow->tp_dst = key->tp_dst;
+    memcpy(flow->dl_src, key->dl_src, ETH_ALEN);
+    memcpy(flow->dl_dst, key->dl_dst, ETH_ALEN);
+    flow->nw_proto = key->nw_proto;
+    flow->nw_tos = key->nw_tos;
+}
diff --git a/lib/xflow-util.h b/lib/xflow-util.h
new file mode 100644 (file)
index 0000000..55da492
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef XFLOW_UTIL_H
+#define XFLOW_UTIL_H 1
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "hash.h"
+#include "openflow/openflow.h"
+#include "openvswitch/xflow.h"
+
+struct ds;
+struct flow;
+
+/* The kernel datapaths limits actions to those that fit in a single page of
+ * memory, so there is no point in allocating more than that.  */
+enum { MAX_XFLOW_ACTIONS = 4096 / sizeof(union xflow_action) };
+
+struct xflow_actions {
+    size_t n_actions;
+    union xflow_action actions[MAX_XFLOW_ACTIONS];
+};
+
+static inline void
+xflow_actions_init(struct xflow_actions *actions)
+{
+    actions->n_actions = 0;
+}
+
+union xflow_action *xflow_actions_add(struct xflow_actions *actions, uint16_t type);
+
+static inline bool
+xflow_actions_overflow(const struct xflow_actions *actions)
+{
+    return actions->n_actions > MAX_XFLOW_ACTIONS;
+}
+
+static inline uint16_t
+ofp_port_to_xflow_port(uint16_t ofp_port)
+{
+    switch (ofp_port) {
+    case OFPP_LOCAL:
+        return XFLOWP_LOCAL;
+    case OFPP_NONE:
+        return XFLOWP_NONE;
+    default:
+        return ofp_port;
+    }
+}
+
+static inline uint16_t
+xflow_port_to_ofp_port(uint16_t xflow_port)
+{
+    switch (xflow_port) {
+    case XFLOWP_LOCAL:
+        return OFPP_LOCAL;
+    case XFLOWP_NONE:
+        return OFPP_NONE;
+    default:
+        return xflow_port;
+    }
+}
+
+void format_xflow_key(struct ds *, const struct xflow_key *);
+void format_xflow_action(struct ds *, const union xflow_action *);
+void format_xflow_actions(struct ds *, const union xflow_action *actions,
+                        size_t n_actions);
+void format_xflow_flow_stats(struct ds *, const struct xflow_flow_stats *);
+void format_xflow_flow(struct ds *, const struct xflow_flow *);
+
+void xflow_key_from_flow(struct xflow_key *, const struct flow *);
+void xflow_key_to_flow(const struct xflow_key *, struct flow *);
+
+static inline bool
+xflow_key_equal(const struct xflow_key *a, const struct xflow_key *b)
+{
+    return !memcmp(a, b, sizeof *a);
+}
+
+static inline size_t
+xflow_key_hash(const struct xflow_key *flow, uint32_t basis)
+{
+    BUILD_ASSERT_DECL(!(sizeof *flow % sizeof(uint32_t)));
+    return hash_words((const uint32_t *) flow,
+                      sizeof *flow / sizeof(uint32_t), basis);
+}
+
+#endif /* xflow-util.h */
index 0c99b49..4adbdc7 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2009 Nicira Networks, Inc.
+# Copyright (C) 2009, 2010 Nicira Networks, Inc.
 #
 # Copying and distribution of this file, with or without modification,
 # are permitted in any medium without royalty provided the copyright
@@ -26,4 +26,8 @@ ofproto_libofproto_a_SOURCES = \
        ofproto/pinsched.c \
        ofproto/pinsched.h \
        ofproto/status.c \
-       ofproto/status.h
+       ofproto/status.h \
+       ofproto/wdp-provider.h \
+       ofproto/wdp-xflow.c \
+       ofproto/wdp.c \
+       ofproto/wdp.h
index 2044ea5..3a4b1eb 100644 (file)
 #include <string.h>
 #include "dhcp-client.h"
 #include "dhcp.h"
-#include "dpif.h"
 #include "netdev.h"
 #include "openflow/openflow.h"
 #include "packets.h"
 #include "status.h"
 #include "stream-ssl.h"
+#include "wdp.h"
+#include "xfif.h"
 
 #define THIS_MODULE VLM_discovery
 #include "vlog.h"
@@ -95,11 +96,11 @@ discovery_status_cb(struct status_reply *sr, void *d_)
 
 int
 discovery_create(const char *re, bool update_resolv_conf,
-                 struct dpif *dpif, struct switch_status *ss,
+                 struct wdp *wdp, struct switch_status *ss,
                  struct discovery **discoveryp)
 {
     struct discovery *d;
-    char local_name[IF_NAMESIZE];
+    char *local_name;
     int error;
 
     d = xzalloc(sizeof *d);
@@ -112,14 +113,14 @@ discovery_create(const char *re, bool update_resolv_conf,
     d->update_resolv_conf = update_resolv_conf;
 
     /* Initialize DHCP client. */
-    error = dpif_port_get_name(dpif, ODPP_LOCAL,
-                               local_name, sizeof local_name);
+    error = wdp_port_get_name(wdp, OFPP_LOCAL, &local_name);
     if (error) {
         VLOG_ERR("failed to query datapath local port: %s", strerror(error));
         goto error_regfree;
     }
     error = dhclient_create(local_name, modify_dhcp_request,
                             validate_dhcp_offer, d, &d->dhcp);
+    free(local_name);
     if (error) {
         VLOG_ERR("failed to initialize DHCP client: %s", strerror(error));
         goto error_regfree;
index 2288ff6..63960e9 100644 (file)
 
 #include <stdbool.h>
 
-struct dpif;
 struct discovery;
 struct settings;
 struct switch_status;
+struct wdp;
 
 int discovery_create(const char *accept_controller_re, bool update_resolv_conf,
-                     struct dpif *, struct switch_status *,
+                     struct wdp *, struct switch_status *,
                      struct discovery **);
 void discovery_destroy(struct discovery *);
 bool discovery_get_update_resolv_conf(const struct discovery *);
index a79c5b2..d19893b 100644 (file)
@@ -20,7 +20,6 @@
 #include <stdlib.h>
 #include "flow.h"
 #include "mac-learning.h"
-#include "odp-util.h"
 #include "ofpbuf.h"
 #include "ofproto.h"
 #include "pktbuf.h"
@@ -263,7 +262,9 @@ fail_open_recover(struct fail_open *fo)
         fo->next_bogus_packet_in = LLONG_MAX;
 
         memset(&flow, 0, sizeof flow);
-        ofproto_delete_flow(fo->ofproto, &flow, OVSFW_ALL, FAIL_OPEN_PRIORITY);
+        flow.wildcards = OVSFW_ALL;
+        flow.priority = FAIL_OPEN_PRIORITY;
+        ofproto_delete_flow(fo->ofproto, &flow);
     }
 }
 
@@ -291,8 +292,9 @@ fail_open_flushed(struct fail_open *fo)
         action.output.len = htons(sizeof action);
         action.output.port = htons(OFPP_NORMAL);
         memset(&flow, 0, sizeof flow);
-        ofproto_add_flow(fo->ofproto, &flow, OVSFW_ALL, FAIL_OPEN_PRIORITY,
-                         &action, 1, 0);
+        flow.wildcards = OVSFW_ALL;
+        flow.priority = FAIL_OPEN_PRIORITY;
+        ofproto_add_flow(fo->ofproto, &flow, &action, 1, 0);
     }
 }
 
index bf90273..076c71a 100644 (file)
 #include <string.h>
 #include <stdlib.h>
 #include "dhcp.h"
-#include "dpif.h"
 #include "flow.h"
 #include "netdev.h"
-#include "odp-util.h"
 #include "ofproto.h"
 #include "ofpbuf.h"
 #include "openflow/openflow.h"
@@ -34,6 +32,7 @@
 #include "poll-loop.h"
 #include "status.h"
 #include "timeval.h"
+#include "wdp.h"
 
 #define THIS_MODULE VLM_in_band
 #include "vlog.h"
@@ -224,8 +223,6 @@ enum {
 
 struct in_band_rule {
     flow_t flow;
-    uint32_t wildcards;
-    unsigned int priority;
 };
 
 /* Track one remote IP and next hop information. */
@@ -392,141 +389,76 @@ in_band_status_cb(struct status_reply *sr, void *in_band_)
     }
 }
 
-/* Returns true if 'packet' should be sent to the local port regardless
- * of the flow table. */ 
-bool
-in_band_msg_in_hook(struct in_band *in_band, const flow_t *flow, 
-                    const struct ofpbuf *packet)
-{
-    if (!in_band) {
-        return false;
-    }
-
-    /* Regardless of how the flow table is configured, we want to be
-     * able to see replies to our DHCP requests. */
-    if (flow->dl_type == htons(ETH_TYPE_IP)
-            && flow->nw_proto == IP_TYPE_UDP
-            && flow->tp_src == htons(DHCP_SERVER_PORT)
-            && flow->tp_dst == htons(DHCP_CLIENT_PORT)
-            && packet->l7) {
-        struct dhcp_header *dhcp;
-
-        dhcp = ofpbuf_at(packet, (char *)packet->l7 - (char *)packet->data,
-                         sizeof *dhcp);
-        if (!dhcp) {
-            return false;
-        }
-
-        refresh_local(in_band);
-        if (!eth_addr_is_zero(in_band->local_mac)
-            && eth_addr_equals(dhcp->chaddr, in_band->local_mac)) {
-            return true;
-        }
-    }
-
-    return false;
-}
-
-/* Returns true if the rule that would match 'flow' with 'actions' is 
- * allowed to be set up in the datapath. */
-bool
-in_band_rule_check(struct in_band *in_band, const flow_t *flow,
-                   const struct odp_actions *actions)
-{
-    if (!in_band) {
-        return true;
-    }
-
-    /* Don't allow flows that would prevent DHCP replies from being seen
-     * by the local port. */
-    if (flow->dl_type == htons(ETH_TYPE_IP)
-            && flow->nw_proto == IP_TYPE_UDP
-            && flow->tp_src == htons(DHCP_SERVER_PORT) 
-            && flow->tp_dst == htons(DHCP_CLIENT_PORT)) {
-        int i;
-
-        for (i=0; i<actions->n_actions; i++) {
-            if (actions->actions[i].output.type == ODPAT_OUTPUT 
-                    && actions->actions[i].output.port == ODPP_LOCAL) {
-                return true;
-            }   
-        }
-        return false;
-    }
-
-    return true;
-}
-
 static void
 init_rule(struct in_band_rule *rule, unsigned int priority)
 {
-    rule->wildcards = OVSFW_ALL;
-    rule->priority = priority;
-
-    /* Not strictly necessary but seems cleaner. */
+    /* Clearing the flow is not strictly necessary but it seems cleaner. */
     memset(&rule->flow, 0, sizeof rule->flow);
+
+    rule->flow.wildcards = OVSFW_ALL;
+    rule->flow.priority = priority;
 }
 
 static void
-set_in_port(struct in_band_rule *rule, uint16_t odp_port)
+set_in_port(struct in_band_rule *rule, uint16_t ofp_port)
 {
-    rule->wildcards &= ~OFPFW_IN_PORT;
-    rule->flow.in_port = odp_port;
+    rule->flow.wildcards &= ~OFPFW_IN_PORT;
+    rule->flow.in_port = ofp_port;
 }
 
 static void
 set_dl_type(struct in_band_rule *rule, uint16_t dl_type)
 {
-    rule->wildcards &= ~OFPFW_DL_TYPE;
+    rule->flow.wildcards &= ~OFPFW_DL_TYPE;
     rule->flow.dl_type = dl_type;
 }
 
 static void
 set_dl_src(struct in_band_rule *rule, const uint8_t dl_src[ETH_ADDR_LEN])
 {
-    rule->wildcards &= ~OFPFW_DL_SRC;
+    rule->flow.wildcards &= ~OFPFW_DL_SRC;
     memcpy(rule->flow.dl_src, dl_src, ETH_ADDR_LEN);
 }
 
 static void
 set_dl_dst(struct in_band_rule *rule, const uint8_t dl_dst[ETH_ADDR_LEN])
 {
-    rule->wildcards &= ~OFPFW_DL_DST;
+    rule->flow.wildcards &= ~OFPFW_DL_DST;
     memcpy(rule->flow.dl_dst, dl_dst, ETH_ADDR_LEN);
 }
 
 static void
 set_tp_src(struct in_band_rule *rule, uint16_t tp_src)
 {
-    rule->wildcards &= ~OFPFW_TP_SRC;
+    rule->flow.wildcards &= ~OFPFW_TP_SRC;
     rule->flow.tp_src = tp_src;
 }
 
 static void
 set_tp_dst(struct in_band_rule *rule, uint16_t tp_dst)
 {
-    rule->wildcards &= ~OFPFW_TP_DST;
+    rule->flow.wildcards &= ~OFPFW_TP_DST;
     rule->flow.tp_dst = tp_dst;
 }
 
 static void
 set_nw_proto(struct in_band_rule *rule, uint8_t nw_proto)
 {
-    rule->wildcards &= ~OFPFW_NW_PROTO;
+    rule->flow.wildcards &= ~OFPFW_NW_PROTO;
     rule->flow.nw_proto = nw_proto;
 }
 
 static void
 set_nw_src(struct in_band_rule *rule, const struct in_addr nw_src)
 {
-    rule->wildcards &= ~OFPFW_NW_SRC_MASK;
+    rule->flow.wildcards &= ~OFPFW_NW_SRC_MASK;
     rule->flow.nw_src = nw_src.s_addr;
 }
 
 static void
 set_nw_dst(struct in_band_rule *rule, const struct in_addr nw_dst)
 {
-    rule->wildcards &= ~OFPFW_NW_DST_MASK;
+    rule->flow.wildcards &= ~OFPFW_NW_DST_MASK;
     rule->flow.nw_dst = nw_dst.s_addr;
 }
 
@@ -540,7 +472,7 @@ make_rules(struct in_band *ib,
     if (!eth_addr_is_zero(ib->installed_local_mac)) {
         /* (a) Allow DHCP requests sent from the local port. */
         init_rule(&rule, IBR_FROM_LOCAL_DHCP);
-        set_in_port(&rule, ODPP_LOCAL);
+        set_in_port(&rule, OFPP_LOCAL);
         set_dl_type(&rule, htons(ETH_TYPE_IP));
         set_dl_src(&rule, ib->installed_local_mac);
         set_nw_proto(&rule, IP_TYPE_UDP);
@@ -635,8 +567,7 @@ make_rules(struct in_band *ib,
 static void
 drop_rule(struct in_band *ib, const struct in_band_rule *rule)
 {
-    ofproto_delete_flow(ib->ofproto, &rule->flow,
-                        rule->wildcards, rule->priority);
+    ofproto_delete_flow(ib->ofproto, &rule->flow);
 }
 
 /* Drops from the flow table all of the flows set up by 'ib', then clears out
@@ -669,8 +600,7 @@ add_rule(struct in_band *ib, const struct in_band_rule *rule)
     action.output.len = htons(sizeof action);
     action.output.port = htons(OFPP_NORMAL);
     action.output.max_len = htons(0);
-    ofproto_add_flow(ib->ofproto, &rule->flow, rule->wildcards,
-                     rule->priority, &action, 1, 0);
+    ofproto_add_flow(ib->ofproto, &rule->flow, &action, 1, 0);
 }
 
 /* Inserts flows into the flow table for the current state of 'ib'. */
@@ -764,16 +694,15 @@ in_band_flushed(struct in_band *in_band)
 }
 
 int
-in_band_create(struct ofproto *ofproto, struct dpif *dpif,
+in_band_create(struct ofproto *ofproto, struct wdp *wdp,
                struct switch_status *ss, struct in_band **in_bandp)
 {
     struct in_band *in_band;
-    char local_name[IF_NAMESIZE];
     struct netdev *local_netdev;
+    char *local_name;
     int error;
 
-    error = dpif_port_get_name(dpif, ODPP_LOCAL,
-                               local_name, sizeof local_name);
+    error = wdp_port_get_name(wdp, OFPP_LOCAL, &local_name);
     if (error) {
         VLOG_ERR("failed to initialize in-band control: cannot get name "
                  "of datapath local port (%s)", strerror(error));
@@ -784,8 +713,10 @@ in_band_create(struct ofproto *ofproto, struct dpif *dpif,
     if (error) {
         VLOG_ERR("failed to initialize in-band control: cannot open "
                  "datapath local port %s (%s)", local_name, strerror(error));
+        free(local_name);
         return error;
     }
+    free(local_name);
 
     in_band = xzalloc(sizeof *in_band);
     in_band->ofproto = ofproto;
index 5122e4c..5572466 100644 (file)
 
 #include "flow.h"
 
-struct dpif;
 struct in_band;
-struct odp_actions;
+struct xflow_actions;
 struct ofproto;
 struct rconn;
 struct settings;
 struct switch_status;
+struct wdp;
 
-int in_band_create(struct ofproto *, struct dpif *, struct switch_status *,
+int in_band_create(struct ofproto *, struct wdp *, struct switch_status *,
                    struct in_band **);
 void in_band_destroy(struct in_band *);
 
@@ -40,7 +40,7 @@ void in_band_wait(struct in_band *);
 bool in_band_msg_in_hook(struct in_band *, const flow_t *, 
                          const struct ofpbuf *packet);
 bool in_band_rule_check(struct in_band *, const flow_t *,
-                        const struct odp_actions *);
+                        const struct xflow_actions *);
 void in_band_flushed(struct in_band *);
 
 #endif /* in-band.h */
index 60baf0e..8cedfe9 100644 (file)
 #include <inttypes.h>
 #include <stdlib.h>
 #include "collectors.h"
-#include "dpif.h"
 #include "compiler.h"
 #include "netdev.h"
 #include "ofpbuf.h"
 #include "ofproto.h"
+#include "packets.h"
 #include "poll-loop.h"
 #include "port-array.h"
 #include "sflow_api.h"
 #include "socket-util.h"
 #include "timeval.h"
+#include "wdp.h"
+#include "xfif.h"
 
 #define THIS_MODULE VLM_sflow
 #include "vlog.h"
@@ -44,10 +46,10 @@ struct ofproto_sflow {
     struct collectors *collectors;
     SFLAgent *sflow_agent;
     struct ofproto_sflow_options *options;
-    struct dpif *dpif;
+    struct wdp *wdp;
     time_t next_tick;
     size_t n_flood, n_all;
-    struct port_array ports;    /* Indexed by ODP port number. */
+    struct port_array ports;    /* Indexed by XFLOW port number. */
 };
 
 #define RECEIVER_INDEX 1
@@ -249,7 +251,7 @@ ofproto_sflow_clear(struct ofproto_sflow *os)
     os->options = NULL;
 
     /* Turn off sampling to save CPU cycles. */
-    dpif_set_sflow_probability(os->dpif, 0);
+    wdp_set_sflow_probability(os->wdp, 0);
 }
 
 bool
@@ -259,12 +261,12 @@ ofproto_sflow_is_enabled(const struct ofproto_sflow *os)
 }
 
 struct ofproto_sflow *
-ofproto_sflow_create(struct dpif *dpif)
+ofproto_sflow_create(struct wdp *wdp)
 {
     struct ofproto_sflow *os;
 
     os = xcalloc(1, sizeof *os);
-    os->dpif = dpif;
+    os->wdp = wdp;
     os->next_tick = time_now() + 1;
     port_array_init(&os->ports);
     return os;
@@ -275,11 +277,11 @@ ofproto_sflow_destroy(struct ofproto_sflow *os)
 {
     if (os) {
         struct ofproto_sflow_port *osp;
-        unsigned int odp_port;
+        unsigned int xflow_port;
 
         ofproto_sflow_clear(os);
-        PORT_ARRAY_FOR_EACH (osp, &os->ports, odp_port) {
-            ofproto_sflow_del_port(os, odp_port);
+        PORT_ARRAY_FOR_EACH (osp, &os->ports, xflow_port) {
+            ofproto_sflow_del_port(os, xflow_port);
         }
         port_array_destroy(&os->ports);
         free(os);
@@ -288,13 +290,13 @@ ofproto_sflow_destroy(struct ofproto_sflow *os)
 
 static void
 ofproto_sflow_add_poller(struct ofproto_sflow *os,
-                         struct ofproto_sflow_port *osp, uint16_t odp_port)
+                         struct ofproto_sflow_port *osp, uint16_t xflow_port)
 {
     SFLPoller *poller = sfl_agent_addPoller(os->sflow_agent, &osp->dsi, os,
                                             sflow_agent_get_counters);
     sfl_poller_set_sFlowCpInterval(poller, os->options->polling_interval);
     sfl_poller_set_sFlowCpReceiver(poller, RECEIVER_INDEX);
-    sfl_poller_set_bridgePort(poller, odp_port);
+    sfl_poller_set_bridgePort(poller, xflow_port);
 }
 
 static void
@@ -308,7 +310,7 @@ ofproto_sflow_add_sampler(struct ofproto_sflow *os,
 }
 
 void
-ofproto_sflow_add_port(struct ofproto_sflow *os, uint16_t odp_port,
+ofproto_sflow_add_port(struct ofproto_sflow *os, uint16_t xflow_port,
                        const char *netdev_name)
 {
     struct ofproto_sflow_port *osp;
@@ -316,7 +318,7 @@ ofproto_sflow_add_port(struct ofproto_sflow *os, uint16_t odp_port,
     uint32_t ifindex;
     int error;
 
-    ofproto_sflow_del_port(os, odp_port);
+    ofproto_sflow_del_port(os, xflow_port);
 
     /* Open network device. */
     error = netdev_open_default(netdev_name, &netdev);
@@ -331,22 +333,22 @@ ofproto_sflow_add_port(struct ofproto_sflow *os, uint16_t odp_port,
     osp->netdev = netdev;
     ifindex = netdev_get_ifindex(netdev);
     if (ifindex <= 0) {
-        ifindex = (os->sflow_agent->subId << 16) + odp_port;
+        ifindex = (os->sflow_agent->subId << 16) + xflow_port;
     }
     SFL_DS_SET(osp->dsi, 0, ifindex, 0);
-    port_array_set(&os->ports, odp_port, osp);
+    port_array_set(&os->ports, xflow_port, osp);
 
     /* Add poller and sampler. */
     if (os->sflow_agent) {
-        ofproto_sflow_add_poller(os, osp, odp_port);
+        ofproto_sflow_add_poller(os, osp, xflow_port);
         ofproto_sflow_add_sampler(os, osp);
     }
 }
 
 void
-ofproto_sflow_del_port(struct ofproto_sflow *os, uint16_t odp_port)
+ofproto_sflow_del_port(struct ofproto_sflow *os, uint16_t xflow_port)
 {
-    struct ofproto_sflow_port *osp = port_array_get(&os->ports, odp_port);
+    struct ofproto_sflow_port *osp = port_array_get(&os->ports, xflow_port);
     if (osp) {
         if (os->sflow_agent) {
             sfl_agent_removePoller(os->sflow_agent, &osp->dsi);
@@ -354,7 +356,7 @@ ofproto_sflow_del_port(struct ofproto_sflow *os, uint16_t odp_port)
         }
         netdev_close(osp->netdev);
         free(osp);
-        port_array_set(&os->ports, odp_port, NULL);
+        port_array_set(&os->ports, xflow_port, NULL);
     }
 }
 
@@ -365,7 +367,7 @@ ofproto_sflow_set_options(struct ofproto_sflow *os,
     struct ofproto_sflow_port *osp;
     bool options_changed;
     SFLReceiver *receiver;
-    unsigned int odp_port;
+    unsigned int xflow_port;
     SFLAddress agentIP;
     time_t now;
 
@@ -432,48 +434,48 @@ ofproto_sflow_set_options(struct ofproto_sflow *os,
     sfl_receiver_set_sFlowRcvrTimeout(receiver, 0xffffffff);
 
     /* Set the sampling_rate down in the datapath. */
-    dpif_set_sflow_probability(os->dpif,
-                               MAX(1, UINT32_MAX / options->sampling_rate));
+    wdp_set_sflow_probability(os->wdp,
+                              MAX(1, UINT32_MAX / options->sampling_rate));
 
     /* Add samplers and pollers for the currently known ports. */
-    PORT_ARRAY_FOR_EACH (osp, &os->ports, odp_port) {
-        ofproto_sflow_add_poller(os, osp, odp_port);
+    PORT_ARRAY_FOR_EACH (osp, &os->ports, xflow_port) {
+        ofproto_sflow_add_poller(os, osp, xflow_port);
         ofproto_sflow_add_sampler(os, osp);
     }
 }
 
 static int
-ofproto_sflow_odp_port_to_ifindex(const struct ofproto_sflow *os,
-                                  uint16_t odp_port)
+ofproto_sflow_xflow_port_to_ifindex(const struct ofproto_sflow *os,
+                                  uint16_t xflow_port)
 {
-    struct ofproto_sflow_port *osp = port_array_get(&os->ports, odp_port);
+    struct ofproto_sflow_port *osp = port_array_get(&os->ports, xflow_port);
     return osp ? SFL_DS_INDEX(osp->dsi) : 0;
 }
 
 void
-ofproto_sflow_received(struct ofproto_sflow *os, struct odp_msg *msg)
+ofproto_sflow_received(struct ofproto_sflow *os, struct xflow_msg *msg)
 {
     SFL_FLOW_SAMPLE_TYPE fs;
     SFLFlow_sample_element hdrElem;
     SFLSampled_header *header;
     SFLFlow_sample_element switchElem;
     SFLSampler *sampler;
-    const struct odp_sflow_sample_header *hdr;
-    const union odp_action *actions;
+    const struct xflow_sflow_sample_header *hdr;
+    const union xflow_action *actions;
     struct ofpbuf payload;
     size_t n_actions, n_outputs;
     size_t min_size;
     flow_t flow;
     size_t i;
 
-    /* Get odp_sflow_sample_header. */
+    /* Get xflow_sflow_sample_header. */
     min_size = sizeof *msg + sizeof *hdr;
     if (min_size > msg->length) {
         VLOG_WARN_RL(&rl, "sFlow packet too small (%"PRIu32" < %zu)",
                      msg->length, min_size);
         return;
     }
-    hdr = (const struct odp_sflow_sample_header *) (msg + 1);
+    hdr = (const struct xflow_sflow_sample_header *) (msg + 1);
 
     /* Get actions. */
     n_actions = hdr->n_actions;
@@ -489,16 +491,16 @@ ofproto_sflow_received(struct ofproto_sflow *os, struct odp_msg *msg)
                      n_actions, msg->length, min_size);
         return;
     }
-    actions = (const union odp_action *) (hdr + 1);
+    actions = (const union xflow_action *) (hdr + 1);
 
     /* Get packet payload and extract flow. */
-    payload.data = (union odp_action *) (actions + n_actions);
+    payload.data = (union xflow_action *) (actions + n_actions);
     payload.size = msg->length - min_size;
     flow_extract(&payload, 0, msg->port, &flow);
 
     /* Build a flow sample */
     memset(&fs, 0, sizeof fs);
-    fs.input = ofproto_sflow_odp_port_to_ifindex(os, msg->port);
+    fs.input = ofproto_sflow_xflow_port_to_ifindex(os, msg->port);
     fs.output = 0;              /* Filled in correctly below. */
     fs.sample_pool = hdr->sample_pool;
 
@@ -539,26 +541,29 @@ ofproto_sflow_received(struct ofproto_sflow *os, struct odp_msg *msg)
     /* Figure out the output ports. */
     n_outputs = 0;
     for (i = 0; i < n_actions; i++) {
-        const union odp_action *a = &actions[i];
+        const union xflow_action *a = &actions[i];
 
         switch (a->type) {
-        case ODPAT_OUTPUT:
-            fs.output = ofproto_sflow_odp_port_to_ifindex(os, a->output.port);
+        case XFLOWAT_OUTPUT:
+            fs.output = ofproto_sflow_xflow_port_to_ifindex(os, a->output.port);
             n_outputs++;
             break;
 
-        case ODPAT_OUTPUT_GROUP:
+        case XFLOWAT_OUTPUT_GROUP:
+#if 0
             n_outputs += (a->output_group.group == DP_GROUP_FLOOD ? os->n_flood
                           : a->output_group.group == DP_GROUP_ALL ? os->n_all
                           : 0);
+#endif
             break;
 
-        case ODPAT_SET_VLAN_VID:
-            switchElem.flowType.sw.dst_vlan = ntohs(a->vlan_vid.vlan_vid);
-            break;
-
-        case ODPAT_SET_VLAN_PCP:
-            switchElem.flowType.sw.dst_priority = a->vlan_pcp.vlan_pcp;
+        case XFLOWAT_SET_DL_TCI:
+            if (a->dl_tci.mask & htons(VLAN_VID_MASK)) {
+                switchElem.flowType.sw.dst_vlan = vlan_tci_to_vid(a->dl_tci.tci);
+            }
+            if (a->dl_tci.mask & htons(VLAN_PCP_MASK)) {
+                switchElem.flowType.sw.dst_priority = vlan_tci_to_pcp(a->dl_tci.tci);
+            }
             break;
 
         default:
index ec86d11..492de22 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009 InMon Corp.
+ * Copyright (c) 2009, 2010 InMon Corp.
  * Copyright (c) 2009 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
 #include <stdint.h>
 #include "svec.h"
 
-struct dpif;
-struct odp_msg;
 struct ofproto_sflow_options;
+struct wdp;
+struct xflow_msg;
 
-struct ofproto_sflow *ofproto_sflow_create(struct dpif *);
+struct ofproto_sflow *ofproto_sflow_create(struct wdp *);
 void ofproto_sflow_destroy(struct ofproto_sflow *);
 void ofproto_sflow_set_options(struct ofproto_sflow *,
                                const struct ofproto_sflow_options *);
 void ofproto_sflow_clear(struct ofproto_sflow *);
 bool ofproto_sflow_is_enabled(const struct ofproto_sflow *);
 
-void ofproto_sflow_add_port(struct ofproto_sflow *, uint16_t odp_port,
+void ofproto_sflow_add_port(struct ofproto_sflow *, uint16_t xflow_port,
                             const char *netdev_name);
-void ofproto_sflow_del_port(struct ofproto_sflow *, uint16_t odp_port);
+void ofproto_sflow_del_port(struct ofproto_sflow *, uint16_t xflow_port);
 void ofproto_sflow_set_group_sizes(struct ofproto_sflow *,
                                    size_t n_flood, size_t n_all);
 
 void ofproto_sflow_run(struct ofproto_sflow *);
 void ofproto_sflow_wait(struct ofproto_sflow *);
 
-void ofproto_sflow_received(struct ofproto_sflow *, struct odp_msg *);
+void ofproto_sflow_received(struct ofproto_sflow *, struct xflow_msg *);
 
 #endif /* ofproto/ofproto-sflow.h */
index 4197787..2b26d67 100644 (file)
 #include "classifier.h"
 #include "coverage.h"
 #include "discovery.h"
-#include "dpif.h"
 #include "dynamic-string.h"
 #include "fail-open.h"
 #include "in-band.h"
 #include "mac-learning.h"
 #include "netdev.h"
 #include "netflow.h"
-#include "odp-util.h"
 #include "ofp-print.h"
 #include "ofproto-sflow.h"
 #include "ofpbuf.h"
 #include "openflow/nicira-ext.h"
 #include "openflow/openflow.h"
-#include "openvswitch/datapath-protocol.h"
+#include "openvswitch/xflow.h"
 #include "packets.h"
 #include "pinsched.h"
 #include "pktbuf.h"
@@ -55,6 +53,8 @@
 #include "timeval.h"
 #include "unixctl.h"
 #include "vconn.h"
+#include "wdp.h"
+#include "xfif.h"
 #include "xtoxll.h"
 
 #define THIS_MODULE VLM_ofproto
@@ -67,104 +67,40 @@ enum {
     TABLEID_CLASSIFIER = 1
 };
 
-struct ofport {
-    struct netdev *netdev;
-    struct ofp_phy_port opp;    /* In host byte order. */
-};
-
-static void ofport_free(struct ofport *);
-static void hton_ofp_phy_port(struct ofp_phy_port *);
-
-static int xlate_actions(const union ofp_action *in, size_t n_in,
-                         const flow_t *flow, struct ofproto *ofproto,
-                         const struct ofpbuf *packet,
-                         struct odp_actions *out, tag_type *tags,
-                         bool *may_set_up_flow, uint16_t *nf_output_iface);
-
-struct rule {
-    struct cls_rule cr;
-
+struct ofproto_rule {
     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. */
-    uint64_t byte_count;        /* Number of bytes received. */
-    uint64_t accounted_bytes;   /* Number of bytes passed to account_cb. */
     tag_type tags;              /* Tags (set only by hooks). */
-    struct netflow_flow nf_flow; /* Per-flow NetFlow tracking data. */
+};
 
-    /* If 'super' is non-NULL, this rule is a subrule, that is, it is an
-     * exact-match rule (having cr.wc.wildcards of 0) generated from the
-     * wildcard rule 'super'.  In this case, 'list' is an element of the
-     * super-rule's list.
-     *
-     * If 'super' is NULL, this rule is a super-rule, and 'list' is the head of
-     * a list of subrules.  A super-rule with no wildcards (where
-     * cr.wc.wildcards is 0) will never have any subrules. */
-    struct rule *super;
-    struct list list;
+static struct ofproto_rule *
+ofproto_rule_cast(const struct wdp_rule *wdp_rule)
+{
+    return wdp_rule->client_data;
+}
 
-    /* OpenFlow actions.
-     *
-     * 'n_actions' is the number of elements in the 'actions' array.  A single
-     * action may take up more more than one element's worth of space.
-     *
-     * A subrule has no actions (it uses the super-rule's actions). */
-    int n_actions;
-    union ofp_action *actions;
+static void
+ofproto_rule_init(struct wdp_rule *wdp_rule)
+{
+    wdp_rule->client_data = xzalloc(sizeof(struct ofproto_rule));
+}
 
-    /* Datapath actions.
-     *
-     * A super-rule with wildcard fields never has ODP actions (since the
-     * datapath only supports exact-match flows). */
-    bool installed;             /* Installed in datapath? */
-    bool may_install;           /* True ordinarily; false if actions must
-                                 * be reassessed for every packet. */
-    int n_odp_actions;
-    union odp_action *odp_actions;
-};
 
 static inline bool
-rule_is_hidden(const struct rule *rule)
+rule_is_hidden(const struct wdp_rule *rule)
 {
-    /* Subrules are merely an implementation detail, so hide them from the
-     * controller. */
-    if (rule->super != NULL) {
-        return true;
-    }
-
     /* Rules with priority higher than UINT16_MAX are set up by ofproto itself
      * (e.g. by in-band control) and are intentionally hidden from the
      * controller. */
-    if (rule->cr.priority > UINT16_MAX) {
+    if (rule->cr.flow.priority > UINT16_MAX) {
         return true;
     }
 
     return false;
 }
 
-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,
-                                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 *);
-static void rule_insert(struct ofproto *, struct rule *,
-                        struct ofpbuf *packet, uint16_t in_port);
-static void rule_remove(struct ofproto *, struct rule *);
-static bool rule_make_actions(struct ofproto *, struct rule *,
-                              const struct ofpbuf *packet);
-static void rule_install(struct ofproto *, struct rule *,
-                         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);
+static void delete_flow(struct ofproto *, struct wdp_rule *, uint8_t reason);
 
 /* ofproto supports two kinds of OpenFlow connections:
  *
@@ -210,13 +146,13 @@ struct ofconn {
 
 /* We use OFPR_NO_MATCH and OFPR_ACTION as indexes into struct ofconn's
  * "schedulers" array.  Their values are 0 and 1, and their meanings and values
- * coincide with _ODPL_MISS_NR and _ODPL_ACTION_NR, so this is convenient.  In
+ * coincide with WDP_CHAN_MISS and WDP_CHAN_ACTION, so this is convenient.  In
  * case anything ever changes, check their values here.  */
 #define N_SCHEDULERS 2
 BUILD_ASSERT_DECL(OFPR_NO_MATCH == 0);
-BUILD_ASSERT_DECL(OFPR_NO_MATCH == _ODPL_MISS_NR);
+BUILD_ASSERT_DECL(OFPR_NO_MATCH == WDP_CHAN_MISS);
 BUILD_ASSERT_DECL(OFPR_ACTION == 1);
-BUILD_ASSERT_DECL(OFPR_ACTION == _ODPL_ACTION_NR);
+BUILD_ASSERT_DECL(OFPR_ACTION == WDP_CHAN_ACTION);
 
 static struct ofconn *ofconn_create(struct ofproto *, struct rconn *,
                                     enum ofconn_type);
@@ -228,8 +164,8 @@ static bool ofconn_receives_async_msgs(const struct ofconn *);
 static void queue_tx(struct ofpbuf *msg, const struct ofconn *ofconn,
                      struct rconn_packet_counter *counter);
 
-static void send_packet_in(struct ofproto *, struct ofpbuf *odp_msg);
-static void do_send_packet_in(struct ofpbuf *odp_msg, void *ofconn);
+static void send_packet_in(struct ofproto *, struct wdp_packet *);
+static void do_send_packet_in(struct wdp_packet *, void *ofconn);
 
 struct ofproto {
     /* Settings. */
@@ -242,11 +178,7 @@ struct ofproto {
     char *dp_desc;              /* Datapath description. */
 
     /* Datapath. */
-    struct dpif *dpif;
-    struct netdev_monitor *netdev_monitor;
-    struct port_array ports;    /* Index is ODP port nr; ofport->opp.port_no is
-                                 * OFP port nr. */
-    struct shash port_by_name;
+    struct wdp *wdp;
     uint32_t max_ports;
 
     /* Configuration. */
@@ -254,6 +186,7 @@ struct ofproto {
     struct fail_open *fail_open;
     struct netflow *netflow;
     struct ofproto_sflow *sflow;
+    bool tun_id_from_cookie;
 
     /* In-band control. */
     struct in_band *in_band;
@@ -261,13 +194,6 @@ struct ofproto {
     struct sockaddr_in *extra_in_band_remotes;
     size_t n_extra_remotes;
 
-    /* Flow table. */
-    struct classifier cls;
-    bool need_revalidate;
-    long long int next_expiration;
-    struct tag_set revalidate_set;
-    bool tun_id_from_cookie;
-
     /* OpenFlow connections. */
     struct hmap controllers;   /* Controller "struct ofconn"s. */
     struct list all_conns;     /* Contains "struct ofconn"s. */
@@ -291,59 +217,47 @@ static const struct ofhooks default_ofhooks;
 static uint64_t pick_datapath_id(const struct ofproto *);
 static uint64_t pick_fallback_dpid(void);
 
-static void update_used(struct ofproto *);
-static void update_stats(struct ofproto *, struct rule *,
-                         const struct odp_flow_stats *);
-static void expire_rule(struct cls_rule *, void *ofproto);
-static void active_timeout(struct ofproto *ofproto, struct rule *rule);
-static bool revalidate_rule(struct ofproto *p, struct rule *rule);
-static void revalidate_cb(struct cls_rule *rule_, void *p_);
-
-static void handle_odp_msg(struct ofproto *, struct ofpbuf *);
+static void handle_wdp_packet(struct ofproto *, struct wdp_packet *);
 
 static void handle_openflow(struct ofconn *, struct ofproto *,
                             struct ofpbuf *);
 
-static void refresh_port_groups(struct ofproto *);
-
-static void update_port(struct ofproto *, const char *devname);
-static int init_ports(struct ofproto *);
-static void reinit_ports(struct ofproto *);
-
 int
 ofproto_create(const char *datapath, const char *datapath_type,
                const struct ofhooks *ofhooks, void *aux,
                struct ofproto **ofprotop)
 {
-    struct odp_stats stats;
+    struct wdp_stats stats;
     struct ofproto *p;
-    struct dpif *dpif;
+    struct wdp *wdp;
     int error;
 
     *ofprotop = NULL;
 
     /* Connect to datapath and start listening for messages. */
-    error = dpif_open(datapath, datapath_type, &dpif);
+    error = wdp_open(datapath, datapath_type, &wdp);
     if (error) {
         VLOG_ERR("failed to open datapath %s: %s", datapath, strerror(error));
         return error;
     }
-    error = dpif_get_dp_stats(dpif, &stats);
+    error = wdp_get_wdp_stats(wdp, &stats);
     if (error) {
         VLOG_ERR("failed to obtain stats for datapath %s: %s",
                  datapath, strerror(error));
-        dpif_close(dpif);
+        wdp_close(wdp);
         return error;
     }
-    error = dpif_recv_set_mask(dpif, ODPL_MISS | ODPL_ACTION | ODPL_SFLOW);
+    error = wdp_recv_set_mask(wdp, ((1 << WDP_CHAN_MISS)
+                                    | (1 << WDP_CHAN_ACTION)
+                                    | (1 << WDP_CHAN_SFLOW)));
     if (error) {
         VLOG_ERR("failed to listen on datapath %s: %s",
                  datapath, strerror(error));
-        dpif_close(dpif);
+        wdp_close(wdp);
         return error;
     }
-    dpif_flow_flush(dpif);
-    dpif_recv_purge(dpif);
+    wdp_flow_flush(wdp);
+    wdp_recv_purge(wdp);
 
     /* Initialize settings. */
     p = xzalloc(sizeof *p);
@@ -356,10 +270,7 @@ ofproto_create(const char *datapath, const char *datapath_type,
     p->dp_desc = xstrdup(DEFAULT_DP_DESC);
 
     /* Initialize datapath. */
-    p->dpif = dpif;
-    p->netdev_monitor = netdev_monitor_create();
-    port_array_init(&p->ports);
-    shash_init(&p->port_by_name);
+    p->wdp = wdp;
     p->max_ports = stats.max_ports;
 
     /* Initialize submodules. */
@@ -369,12 +280,6 @@ ofproto_create(const char *datapath, const char *datapath_type,
     p->netflow = NULL;
     p->sflow = NULL;
 
-    /* Initialize flow table. */
-    classifier_init(&p->cls);
-    p->need_revalidate = false;
-    p->next_expiration = time_msec() + 1000;
-    tag_set_init(&p->revalidate_set);
-
     /* Initialize OpenFlow connections. */
     list_init(&p->all_conns);
     hmap_init(&p->controllers);
@@ -443,7 +348,7 @@ add_controller(struct ofproto *ofproto, const struct ofproto_controller *c)
 
     if (is_discovery_controller(c)) {
         int error = discovery_create(c->accept_re, c->update_resolv_conf,
-                                     ofproto->dpif, ofproto->switch_status,
+                                     ofproto->wdp, ofproto->switch_status,
                                      &discovery);
         if (error) {
             return;
@@ -565,7 +470,7 @@ update_in_band_remotes(struct ofproto *ofproto)
      * even before we know any remote addresses. */
     if (n_addrs || discovery) {
         if (!ofproto->in_band) {
-            in_band_create(ofproto, ofproto->dpif, ofproto->switch_status,
+            in_band_create(ofproto, ofproto->wdp, ofproto->switch_status,
                            &ofproto->in_band);
         }
         in_band_set_remotes(ofproto->in_band, addrs, n_addrs);
@@ -818,15 +723,8 @@ ofproto_set_sflow(struct ofproto *ofproto,
     struct ofproto_sflow *os = ofproto->sflow;
     if (oso) {
         if (!os) {
-            struct ofport *ofport;
-            unsigned int odp_port;
-
-            os = ofproto->sflow = ofproto_sflow_create(ofproto->dpif);
-            refresh_port_groups(ofproto);
-            PORT_ARRAY_FOR_EACH (ofport, &ofproto->ports, odp_port) {
-                ofproto_sflow_add_port(os, odp_port,
-                                       netdev_get_name(ofport->netdev));
-            }
+            os = ofproto->sflow = ofproto_sflow_create(ofproto->wdp);
+            /* XXX ofport */
         }
         ofproto_sflow_set_options(os, oso);
     } else {
@@ -883,8 +781,6 @@ void
 ofproto_destroy(struct ofproto *p)
 {
     struct ofconn *ofconn, *next_ofconn;
-    struct ofport *ofport;
-    unsigned int port_no;
     size_t i;
 
     if (!p) {
@@ -900,7 +796,6 @@ ofproto_destroy(struct ofproto *p)
     free(p->extra_in_band_remotes);
 
     ofproto_flush_flows(p);
-    classifier_destroy(&p->cls);
 
     LIST_FOR_EACH_SAFE (ofconn, next_ofconn, struct ofconn, node,
                         &p->all_conns) {
@@ -908,12 +803,7 @@ ofproto_destroy(struct ofproto *p)
     }
     hmap_destroy(&p->controllers);
 
-    dpif_close(p->dpif);
-    netdev_monitor_destroy(p->netdev_monitor);
-    PORT_ARRAY_FOR_EACH (ofport, &p->ports, port_no) {
-        ofport_free(ofport);
-    }
-    shash_destroy(&p->port_by_name);
+    wdp_close(p->wdp);
 
     switch_status_destroy(p->switch_status);
     netflow_destroy(p->netflow);
@@ -937,8 +827,6 @@ ofproto_destroy(struct ofproto *p)
     free(p->serial_desc);
     free(p->dp_desc);
 
-    port_array_destroy(&p->ports);
-
     free(p);
 }
 
@@ -952,17 +840,6 @@ ofproto_run(struct ofproto *p)
     return error;
 }
 
-static void
-process_port_change(struct ofproto *ofproto, int error, char *devname)
-{
-    if (error == ENOBUFS) {
-        reinit_ports(ofproto);
-    } else if (!error) {
-        update_port(ofproto, devname);
-        free(devname);
-    }
-}
-
 /* Returns a "preference level" for snooping 'ofconn'.  A higher return value
  * means that 'ofconn' is more interesting for monitoring than a lower return
  * value. */
@@ -1010,19 +887,13 @@ int
 ofproto_run1(struct ofproto *p)
 {
     struct ofconn *ofconn, *next_ofconn;
-    char *devname;
-    int error;
     int i;
 
-    if (shash_is_empty(&p->port_by_name)) {
-        init_ports(p);
-    }
-
     for (i = 0; i < 50; i++) {
-        struct ofpbuf *buf;
+        struct wdp_packet packet;
         int error;
 
-        error = dpif_recv(p->dpif, &buf);
+        error = wdp_recv(p->wdp, &packet);
         if (error) {
             if (error == ENODEV) {
                 /* Someone destroyed the datapath behind our back.  The caller
@@ -1030,21 +901,13 @@ ofproto_run1(struct ofproto *p)
                  * spin from here on out. */
                 static struct vlog_rate_limit rl2 = VLOG_RATE_LIMIT_INIT(1, 5);
                 VLOG_ERR_RL(&rl2, "%s: datapath was destroyed externally",
-                            dpif_name(p->dpif));
+                            wdp_name(p->wdp));
                 return ENODEV;
             }
             break;
         }
 
-        handle_odp_msg(p, buf);
-    }
-
-    while ((error = dpif_port_poll(p->dpif, &devname)) != EAGAIN) {
-        process_port_change(p, error, devname);
-    }
-    while ((error = netdev_monitor_poll(p->netdev_monitor,
-                                        &devname)) != EAGAIN) {
-        process_port_change(p, error, devname);
+        handle_wdp_packet(p, xmemdup(&packet, sizeof packet));
     }
 
     if (p->in_band) {
@@ -1090,22 +953,6 @@ ofproto_run1(struct ofproto *p)
         }
     }
 
-    if (time_msec() >= p->next_expiration) {
-        COVERAGE_INC(ofproto_expiration);
-        p->next_expiration = time_msec() + 1000;
-        update_used(p);
-
-        classifier_for_each(&p->cls, CLS_INC_ALL, expire_rule, p);
-
-        /* Let the hook know that we're at a stable point: all outstanding data
-         * in existing flows has been accounted to the account_cb.  Thus, the
-         * hook can now reasonably do operations that depend on having accurate
-         * flow volume accounting (currently, that's just bond rebalancing). */
-        if (p->ofhooks->account_checkpoint_cb) {
-            p->ofhooks->account_checkpoint_cb(p->aux);
-        }
-    }
-
     if (p->netflow) {
         netflow_run(p->netflow);
     }
@@ -1124,21 +971,8 @@ struct revalidate_cbdata {
 };
 
 int
-ofproto_run2(struct ofproto *p, bool revalidate_all)
+ofproto_run2(struct ofproto *p OVS_UNUSED, bool revalidate_all OVS_UNUSED)
 {
-    if (p->need_revalidate || revalidate_all
-        || !tag_set_is_empty(&p->revalidate_set)) {
-        struct revalidate_cbdata cbdata;
-        cbdata.ofproto = p;
-        cbdata.revalidate_all = revalidate_all;
-        cbdata.revalidate_subrules = p->need_revalidate;
-        cbdata.revalidate_set = p->revalidate_set;
-        tag_set_init(&p->revalidate_set);
-        COVERAGE_INC(ofproto_revalidate);
-        classifier_for_each(&p->cls, CLS_INC_EXACT, revalidate_cb, &cbdata);
-        p->need_revalidate = false;
-    }
-
     return 0;
 }
 
@@ -1148,9 +982,8 @@ ofproto_wait(struct ofproto *p)
     struct ofconn *ofconn;
     size_t i;
 
-    dpif_recv_wait(p->dpif);
-    dpif_port_poll_wait(p->dpif);
-    netdev_monitor_poll_wait(p->netdev_monitor);
+    wdp_recv_wait(p->wdp);
+    wdp_port_poll_wait(p->wdp);
     LIST_FOR_EACH (ofconn, struct ofconn, node, &p->all_conns) {
         ofconn_wait(ofconn);
     }
@@ -1164,16 +997,6 @@ ofproto_wait(struct ofproto *p)
     if (p->sflow) {
         ofproto_sflow_wait(p->sflow);
     }
-    if (!tag_set_is_empty(&p->revalidate_set)) {
-        poll_immediate_wake();
-    }
-    if (p->need_revalidate) {
-        /* Shouldn't happen, but if it does just go around again. */
-        VLOG_DBG_RL(&rl, "need revalidate in ofproto_wait_cb()");
-        poll_immediate_wake();
-    } else if (p->next_expiration != LLONG_MAX) {
-        poll_timer_wait(p->next_expiration - time_msec());
-    }
     for (i = 0; i < p->n_listeners; i++) {
         pvconn_wait(p->listeners[i]);
     }
@@ -1183,15 +1006,9 @@ ofproto_wait(struct ofproto *p)
 }
 
 void
-ofproto_revalidate(struct ofproto *ofproto, tag_type tag)
+ofproto_revalidate(struct ofproto *ofproto OVS_UNUSED, tag_type tag OVS_UNUSED)
 {
-    tag_set_add(&ofproto->revalidate_set, tag);
-}
-
-struct tag_set *
-ofproto_get_revalidate_set(struct ofproto *ofproto)
-{
-    return &ofproto->revalidate_set;
+    //XXX tag_set_add(&ofproto->revalidate_set, tag);
 }
 
 bool
@@ -1205,71 +1022,46 @@ ofproto_send_packet(struct ofproto *p, const flow_t *flow,
                     const union ofp_action *actions, size_t n_actions,
                     const struct ofpbuf *packet)
 {
-    struct odp_actions odp_actions;
-    int error;
-
-    error = xlate_actions(actions, n_actions, flow, p, packet, &odp_actions,
-                          NULL, NULL, NULL);
-    if (error) {
-        return error;
-    }
-
-    /* XXX Should we translate the dpif_execute() errno value into an OpenFlow
+    /* XXX Should we translate the wdp_execute() errno value into an OpenFlow
      * error code? */
-    dpif_execute(p->dpif, flow->in_port, odp_actions.actions,
-                 odp_actions.n_actions, packet);
+    wdp_execute(p->wdp, flow->in_port, actions, n_actions, packet);
     return 0;
 }
 
 void
-ofproto_add_flow(struct ofproto *p,
-                 const flow_t *flow, uint32_t wildcards, unsigned int priority,
+ofproto_add_flow(struct ofproto *p, const flow_t *flow,
                  const union ofp_action *actions, size_t n_actions,
                  int idle_timeout)
 {
-    struct rule *rule;
-    rule = rule_create(p, NULL, actions, n_actions,
-                       idle_timeout >= 0 ? idle_timeout : 5 /* XXX */, 
-                       0, 0, false);
-    cls_rule_from_flow(flow, wildcards, priority, &rule->cr);
-    rule_insert(p, rule, NULL, 0);
-}
+    struct wdp_flow_put put;
+    struct wdp_rule *rule;
 
-void
-ofproto_delete_flow(struct ofproto *ofproto, const flow_t *flow,
-                    uint32_t wildcards, unsigned int priority)
-{
-    struct rule *rule;
+    put.flags = WDP_PUT_CREATE | WDP_PUT_MODIFY | WDP_PUT_ALL;
+    put.flow = flow;
+    put.actions = actions;
+    put.n_actions = n_actions;
+    put.idle_timeout = idle_timeout;
+    put.hard_timeout = 0;
 
-    rule = rule_from_cls_rule(classifier_find_rule_exactly(&ofproto->cls,
-                                                           flow, wildcards,
-                                                           priority));
-    if (rule) {
-        rule_remove(ofproto, rule);
+    if (!wdp_flow_put(p->wdp, &put, NULL, &rule)) {
+        ofproto_rule_init(rule);
     }
 }
 
-static void
-destroy_rule(struct cls_rule *rule_, void *ofproto_)
+void
+ofproto_delete_flow(struct ofproto *ofproto, const flow_t *flow)
 {
-    struct rule *rule = rule_from_cls_rule(rule_);
-    struct ofproto *ofproto = ofproto_;
-
-    /* Mark the flow as not installed, even though it might really be
-     * installed, so that rule_remove() doesn't bother trying to uninstall it.
-     * There is no point in uninstalling it individually since we are about to
-     * blow away all the flows with dpif_flow_flush(). */
-    rule->installed = false;
-
-    rule_remove(ofproto, rule);
+    struct wdp_rule *rule = wdp_flow_get(ofproto->wdp, flow);
+    if (rule) {
+        delete_flow(ofproto, rule, OFPRR_DELETE);
+    }
 }
 
 void
 ofproto_flush_flows(struct ofproto *ofproto)
 {
     COVERAGE_INC(ofproto_flush);
-    classifier_for_each(&ofproto->cls, CLS_INC_ALL, destroy_rule, ofproto);
-    dpif_flow_flush(ofproto->dpif);
+    wdp_flow_flush(ofproto->wdp);
     if (ofproto->in_band) {
         in_band_flushed(ofproto->in_band);
     }
@@ -1278,305 +1070,6 @@ ofproto_flush_flows(struct ofproto *ofproto)
     }
 }
 \f
-static void
-reinit_ports(struct ofproto *p)
-{
-    struct svec devnames;
-    struct ofport *ofport;
-    unsigned int port_no;
-    struct odp_port *odp_ports;
-    size_t n_odp_ports;
-    size_t i;
-
-    svec_init(&devnames);
-    PORT_ARRAY_FOR_EACH (ofport, &p->ports, port_no) {
-        svec_add (&devnames, (char *) ofport->opp.name);
-    }
-    dpif_port_list(p->dpif, &odp_ports, &n_odp_ports);
-    for (i = 0; i < n_odp_ports; i++) {
-        svec_add (&devnames, odp_ports[i].devname);
-    }
-    free(odp_ports);
-
-    svec_sort_unique(&devnames);
-    for (i = 0; i < devnames.n; i++) {
-        update_port(p, devnames.names[i]);
-    }
-    svec_destroy(&devnames);
-}
-
-static size_t
-refresh_port_group(struct ofproto *p, unsigned int group)
-{
-    uint16_t *ports;
-    size_t n_ports;
-    struct ofport *port;
-    unsigned int port_no;
-
-    assert(group == DP_GROUP_ALL || group == DP_GROUP_FLOOD);
-
-    ports = xmalloc(port_array_count(&p->ports) * sizeof *ports);
-    n_ports = 0;
-    PORT_ARRAY_FOR_EACH (port, &p->ports, port_no) {
-        if (group == DP_GROUP_ALL || !(port->opp.config & OFPPC_NO_FLOOD)) {
-            ports[n_ports++] = port_no;
-        }
-    }
-    dpif_port_group_set(p->dpif, group, ports, n_ports);
-    free(ports);
-
-    return n_ports;
-}
-
-static void
-refresh_port_groups(struct ofproto *p)
-{
-    size_t n_flood = refresh_port_group(p, DP_GROUP_FLOOD);
-    size_t n_all = refresh_port_group(p, DP_GROUP_ALL);
-    if (p->sflow) {
-        ofproto_sflow_set_group_sizes(p->sflow, n_flood, n_all);
-    }
-}
-
-static struct ofport *
-make_ofport(const struct odp_port *odp_port)
-{
-    struct netdev_options netdev_options;
-    enum netdev_flags flags;
-    struct ofport *ofport;
-    struct netdev *netdev;
-    bool carrier;
-    int error;
-
-    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)",
-                     odp_port->devname, odp_port->port,
-                     odp_port->devname, strerror(error));
-        return NULL;
-    }
-
-    ofport = xmalloc(sizeof *ofport);
-    ofport->netdev = netdev;
-    ofport->opp.port_no = odp_port_to_ofp_port(odp_port->port);
-    netdev_get_etheraddr(netdev, ofport->opp.hw_addr);
-    memcpy(ofport->opp.name, odp_port->devname,
-           MIN(sizeof ofport->opp.name, sizeof odp_port->devname));
-    ofport->opp.name[sizeof ofport->opp.name - 1] = '\0';
-
-    netdev_get_flags(netdev, &flags);
-    ofport->opp.config = flags & NETDEV_UP ? 0 : OFPPC_PORT_DOWN;
-
-    netdev_get_carrier(netdev, &carrier);
-    ofport->opp.state = carrier ? 0 : OFPPS_LINK_DOWN;
-
-    netdev_get_features(netdev,
-                        &ofport->opp.curr, &ofport->opp.advertised,
-                        &ofport->opp.supported, &ofport->opp.peer);
-    return ofport;
-}
-
-static bool
-ofport_conflicts(const struct ofproto *p, const struct odp_port *odp_port)
-{
-    if (port_array_get(&p->ports, odp_port->port)) {
-        VLOG_WARN_RL(&rl, "ignoring duplicate port %"PRIu16" in datapath",
-                     odp_port->port);
-        return true;
-    } else if (shash_find(&p->port_by_name, odp_port->devname)) {
-        VLOG_WARN_RL(&rl, "ignoring duplicate device %s in datapath",
-                     odp_port->devname);
-        return true;
-    } else {
-        return false;
-    }
-}
-
-static int
-ofport_equal(const struct ofport *a_, const struct ofport *b_)
-{
-    const struct ofp_phy_port *a = &a_->opp;
-    const struct ofp_phy_port *b = &b_->opp;
-
-    BUILD_ASSERT_DECL(sizeof *a == 48); /* Detect ofp_phy_port changes. */
-    return (a->port_no == b->port_no
-            && !memcmp(a->hw_addr, b->hw_addr, sizeof a->hw_addr)
-            && !strcmp((char *) a->name, (char *) b->name)
-            && a->state == b->state
-            && a->config == b->config
-            && a->curr == b->curr
-            && a->advertised == b->advertised
-            && a->supported == b->supported
-            && a->peer == b->peer);
-}
-
-static void
-send_port_status(struct ofproto *p, const struct ofport *ofport,
-                 uint8_t reason)
-{
-    /* XXX Should limit the number of queued port status change messages. */
-    struct ofconn *ofconn;
-    LIST_FOR_EACH (ofconn, struct ofconn, node, &p->all_conns) {
-        struct ofp_port_status *ops;
-        struct ofpbuf *b;
-
-        if (!ofconn_receives_async_msgs(ofconn)) {
-            continue;
-        }
-
-        ops = make_openflow_xid(sizeof *ops, OFPT_PORT_STATUS, 0, &b);
-        ops->reason = reason;
-        ops->desc = ofport->opp;
-        hton_ofp_phy_port(&ops->desc);
-        queue_tx(b, ofconn, NULL);
-    }
-    if (p->ofhooks->port_changed_cb) {
-        p->ofhooks->port_changed_cb(reason, &ofport->opp, p->aux);
-    }
-}
-
-static void
-ofport_install(struct ofproto *p, struct ofport *ofport)
-{
-    uint16_t odp_port = ofp_port_to_odp_port(ofport->opp.port_no);
-    const char *netdev_name = (const char *) ofport->opp.name;
-
-    netdev_monitor_add(p->netdev_monitor, ofport->netdev);
-    port_array_set(&p->ports, odp_port, ofport);
-    shash_add(&p->port_by_name, netdev_name, ofport);
-    if (p->sflow) {
-        ofproto_sflow_add_port(p->sflow, odp_port, netdev_name);
-    }
-}
-
-static void
-ofport_remove(struct ofproto *p, struct ofport *ofport)
-{
-    uint16_t odp_port = ofp_port_to_odp_port(ofport->opp.port_no);
-
-    netdev_monitor_remove(p->netdev_monitor, ofport->netdev);
-    port_array_set(&p->ports, odp_port, NULL);
-    shash_delete(&p->port_by_name,
-                 shash_find(&p->port_by_name, (char *) ofport->opp.name));
-    if (p->sflow) {
-        ofproto_sflow_del_port(p->sflow, odp_port);
-    }
-}
-
-static void
-ofport_free(struct ofport *ofport)
-{
-    if (ofport) {
-        netdev_close(ofport->netdev);
-        free(ofport);
-    }
-}
-
-static void
-update_port(struct ofproto *p, const char *devname)
-{
-    struct odp_port odp_port;
-    struct ofport *old_ofport;
-    struct ofport *new_ofport;
-    int error;
-
-    COVERAGE_INC(ofproto_update_port);
-
-    /* Query the datapath for port information. */
-    error = dpif_port_query_by_name(p->dpif, devname, &odp_port);
-
-    /* Find the old ofport. */
-    old_ofport = shash_find_data(&p->port_by_name, devname);
-    if (!error) {
-        if (!old_ofport) {
-            /* There's no port named 'devname' but there might be a port with
-             * the same port number.  This could happen if a port is deleted
-             * and then a new one added in its place very quickly, or if a port
-             * is renamed.  In the former case we want to send an OFPPR_DELETE
-             * and an OFPPR_ADD, and in the latter case we want to send a
-             * single OFPPR_MODIFY.  We can distinguish the cases by comparing
-             * the old port's ifindex against the new port, or perhaps less
-             * reliably but more portably by comparing the old port's MAC
-             * against the new port's MAC.  However, this code isn't that smart
-             * and always sends an OFPPR_MODIFY (XXX). */
-            old_ofport = port_array_get(&p->ports, odp_port.port);
-        }
-    } else if (error != ENOENT && error != ENODEV) {
-        VLOG_WARN_RL(&rl, "dpif_port_query_by_name returned unexpected error "
-                     "%s", strerror(error));
-        return;
-    }
-
-    /* Create a new ofport. */
-    new_ofport = !error ? make_ofport(&odp_port) : NULL;
-
-    /* Eliminate a few pathological cases. */
-    if (!old_ofport && !new_ofport) {
-        return;
-    } else if (old_ofport && new_ofport) {
-        /* Most of the 'config' bits are OpenFlow soft state, but
-         * OFPPC_PORT_DOWN is maintained the kernel.  So transfer the OpenFlow
-         * bits from old_ofport.  (make_ofport() only sets OFPPC_PORT_DOWN and
-         * leaves the other bits 0.)  */
-        new_ofport->opp.config |= old_ofport->opp.config & ~OFPPC_PORT_DOWN;
-
-        if (ofport_equal(old_ofport, new_ofport)) {
-            /* False alarm--no change. */
-            ofport_free(new_ofport);
-            return;
-        }
-    }
-
-    /* Now deal with the normal cases. */
-    if (old_ofport) {
-        ofport_remove(p, old_ofport);
-    }
-    if (new_ofport) {
-        ofport_install(p, new_ofport);
-    }
-    send_port_status(p, new_ofport ? new_ofport : old_ofport,
-                     (!old_ofport ? OFPPR_ADD
-                      : !new_ofport ? OFPPR_DELETE
-                      : OFPPR_MODIFY));
-    ofport_free(old_ofport);
-
-    /* Update port groups. */
-    refresh_port_groups(p);
-}
-
-static int
-init_ports(struct ofproto *p)
-{
-    struct odp_port *ports;
-    size_t n_ports;
-    size_t i;
-    int error;
-
-    error = dpif_port_list(p->dpif, &ports, &n_ports);
-    if (error) {
-        return error;
-    }
-
-    for (i = 0; i < n_ports; i++) {
-        const struct odp_port *odp_port = &ports[i];
-        if (!ofport_conflicts(p, odp_port)) {
-            struct ofport *ofport = make_ofport(odp_port);
-            if (ofport) {
-                ofport_install(p, ofport);
-            }
-        }
-    }
-    free(ports);
-    refresh_port_groups(p);
-    return 0;
-}
-\f
 static struct ofconn *
 ofconn_create(struct ofproto *p, struct rconn *rconn, enum ofconn_type type)
 {
@@ -1692,72 +1185,8 @@ ofconn_receives_async_msgs(const struct ofconn *ofconn)
     }
 }
 \f
-/* Caller is responsible for initializing the 'cr' member of the returned
- * rule. */
-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,
-            uint64_t flow_cookie, bool send_flow_removed)
-{
-    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);
-    } else {
-        list_init(&rule->list);
-    }
-    rule->n_actions = n_actions;
-    rule->actions = xmemdup(actions, n_actions * sizeof *actions);
-    netflow_flow_clear(&rule->nf_flow);
-    netflow_flow_update_time(ofproto->netflow, &rule->nf_flow, rule->created);
-
-    return rule;
-}
-
-static struct rule *
-rule_from_cls_rule(const struct cls_rule *cls_rule)
-{
-    return cls_rule ? CONTAINER_OF(cls_rule, struct rule, cr) : NULL;
-}
-
-static void
-rule_free(struct rule *rule)
-{
-    free(rule->actions);
-    free(rule->odp_actions);
-    free(rule);
-}
-
-/* Destroys 'rule'.  If 'rule' is a subrule, also removes it from its
- * super-rule's list of subrules.  If 'rule' is a super-rule, also iterates
- * through all of its subrules and revalidates them, destroying any that no
- * longer has a super-rule (which is probably all of them).
- *
- * Before calling this function, the caller must make have removed 'rule' from
- * the classifier.  If 'rule' is an exact-match rule, the caller is also
- * responsible for ensuring that it has been uninstalled from the datapath. */
-static void
-rule_destroy(struct ofproto *ofproto, struct rule *rule)
-{
-    if (!rule->super) {
-        struct rule *subrule, *next;
-        LIST_FOR_EACH_SAFE (subrule, next, struct rule, list, &rule->list) {
-            revalidate_rule(ofproto, subrule);
-        }
-    } else {
-        list_remove(&rule->list);
-    }
-    rule_free(rule);
-}
-
 static bool
-rule_has_out_port(const struct rule *rule, uint16_t out_port)
+rule_has_out_port(const struct wdp_rule *rule, uint16_t out_port)
 {
     const union ofp_action *oa;
     struct actions_iterator i;
@@ -1773,311 +1202,6 @@ rule_has_out_port(const struct rule *rule, uint16_t out_port)
     }
     return false;
 }
-
-/* Executes the actions indicated by 'rule' on 'packet', which is in flow
- * 'flow' and is considered to have arrived on ODP port 'in_port'.
- *
- * The flow that 'packet' actually contains does not need to actually match
- * 'rule'; the actions in 'rule' will be applied to it either way.  Likewise,
- * the packet and byte counters for 'rule' will be credited for the packet sent
- * out whether or not the packet actually matches 'rule'.
- *
- * If 'rule' is an exact-match rule and 'flow' actually equals the rule's flow,
- * the caller must already have accurately composed ODP actions for it given
- * 'packet' using rule_make_actions().  If 'rule' is a wildcard rule, or if
- * 'rule' is an exact-match rule but 'flow' is not the rule's flow, then this
- * function will compose a set of ODP actions based on 'rule''s OpenFlow
- * actions and apply them to 'packet'. */
-static void
-rule_execute(struct ofproto *ofproto, struct rule *rule,
-             struct ofpbuf *packet, const flow_t *flow)
-{
-    const union odp_action *actions;
-    size_t n_actions;
-    struct odp_actions a;
-
-    /* Grab or compose the ODP actions.
-     *
-     * The special case for an exact-match 'rule' where 'flow' is not the
-     * rule's flow is important to avoid, e.g., sending a packet out its input
-     * port simply because the ODP actions were composed for the wrong
-     * scenario. */
-    if (rule->cr.wc.wildcards || !flow_equal(flow, &rule->cr.flow)) {
-        struct rule *super = rule->super ? rule->super : rule;
-        if (xlate_actions(super->actions, super->n_actions, flow, ofproto,
-                          packet, &a, NULL, 0, NULL)) {
-            return;
-        }
-        actions = a.actions;
-        n_actions = a.n_actions;
-    } else {
-        actions = rule->odp_actions;
-        n_actions = rule->n_odp_actions;
-    }
-
-    /* Execute the ODP actions. */
-    if (!dpif_execute(ofproto->dpif, flow->in_port,
-                      actions, n_actions, packet)) {
-        struct odp_flow_stats stats;
-        flow_extract_stats(flow, packet, &stats);
-        update_stats(ofproto, rule, &stats);
-        rule->used = time_msec();
-        netflow_flow_update_time(ofproto->netflow, &rule->nf_flow, rule->used);
-    }
-}
-
-static void
-rule_insert(struct ofproto *p, struct rule *rule, struct ofpbuf *packet,
-            uint16_t in_port)
-{
-    struct rule *displaced_rule;
-
-    /* Insert the rule in the classifier. */
-    displaced_rule = rule_from_cls_rule(classifier_insert(&p->cls, &rule->cr));
-    if (!rule->cr.wc.wildcards) {
-        rule_make_actions(p, rule, packet);
-    }
-
-    /* Send the packet and credit it to the rule. */
-    if (packet) {
-        flow_t flow;
-        flow_extract(packet, 0, in_port, &flow);
-        rule_execute(p, rule, packet, &flow);
-    }
-
-    /* Install the rule in the datapath only after sending the packet, to
-     * avoid packet reordering.  */
-    if (rule->cr.wc.wildcards) {
-        COVERAGE_INC(ofproto_add_wc_flow);
-        p->need_revalidate = true;
-    } else {
-        rule_install(p, rule, displaced_rule);
-    }
-
-    /* Free the rule that was displaced, if any. */
-    if (displaced_rule) {
-        rule_destroy(p, displaced_rule);
-    }
-}
-
-static struct rule *
-rule_create_subrule(struct ofproto *ofproto, struct rule *rule,
-                    const flow_t *flow)
-{
-    struct rule *subrule = rule_create(ofproto, rule, NULL, 0,
-                                       rule->idle_timeout, rule->hard_timeout,
-                                       0, false);
-    COVERAGE_INC(ofproto_subrule_create);
-    cls_rule_from_flow(flow, 0, (rule->cr.priority <= UINT16_MAX ? UINT16_MAX
-                        : rule->cr.priority), &subrule->cr);
-    classifier_insert_exact(&ofproto->cls, &subrule->cr);
-
-    return subrule;
-}
-
-static void
-rule_remove(struct ofproto *ofproto, struct rule *rule)
-{
-    if (rule->cr.wc.wildcards) {
-        COVERAGE_INC(ofproto_del_wc_flow);
-        ofproto->need_revalidate = true;
-    } else {
-        rule_uninstall(ofproto, rule);
-    }
-    classifier_remove(&ofproto->cls, &rule->cr);
-    rule_destroy(ofproto, rule);
-}
-
-/* Returns true if the actions changed, false otherwise. */
-static bool
-rule_make_actions(struct ofproto *p, struct rule *rule,
-                  const struct ofpbuf *packet)
-{
-    const struct rule *super;
-    struct odp_actions a;
-    size_t actions_len;
-
-    assert(!rule->cr.wc.wildcards);
-
-    super = rule->super ? rule->super : rule;
-    rule->tags = 0;
-    xlate_actions(super->actions, super->n_actions, &rule->cr.flow, p,
-                  packet, &a, &rule->tags, &rule->may_install,
-                  &rule->nf_flow.output_iface);
-
-    actions_len = a.n_actions * sizeof *a.actions;
-    if (rule->n_odp_actions != a.n_actions
-        || memcmp(rule->odp_actions, a.actions, actions_len)) {
-        COVERAGE_INC(ofproto_odp_unchanged);
-        free(rule->odp_actions);
-        rule->n_odp_actions = a.n_actions;
-        rule->odp_actions = xmemdup(a.actions, actions_len);
-        return true;
-    } else {
-        return false;
-    }
-}
-
-static int
-do_put_flow(struct ofproto *ofproto, struct rule *rule, int flags,
-            struct odp_flow_put *put)
-{
-    memset(&put->flow.stats, 0, sizeof put->flow.stats);
-    put->flow.key = rule->cr.flow;
-    put->flow.actions = rule->odp_actions;
-    put->flow.n_actions = rule->n_odp_actions;
-    put->flow.flags = 0;
-    put->flags = flags;
-    return dpif_flow_put(ofproto->dpif, put);
-}
-
-static void
-rule_install(struct ofproto *p, struct rule *rule, struct rule *displaced_rule)
-{
-    assert(!rule->cr.wc.wildcards);
-
-    if (rule->may_install) {
-        struct odp_flow_put put;
-        if (!do_put_flow(p, rule,
-                         ODPPF_CREATE | ODPPF_MODIFY | ODPPF_ZERO_STATS,
-                         &put)) {
-            rule->installed = true;
-            if (displaced_rule) {
-                update_stats(p, displaced_rule, &put.flow.stats);
-                rule_post_uninstall(p, displaced_rule);
-            }
-        }
-    } else if (displaced_rule) {
-        rule_uninstall(p, displaced_rule);
-    }
-}
-
-static void
-rule_reinstall(struct ofproto *ofproto, struct rule *rule)
-{
-    if (rule->installed) {
-        struct odp_flow_put put;
-        COVERAGE_INC(ofproto_dp_missed);
-        do_put_flow(ofproto, rule, ODPPF_CREATE | ODPPF_MODIFY, &put);
-    } else {
-        rule_install(ofproto, rule, NULL);
-    }
-}
-
-static void
-rule_update_actions(struct ofproto *ofproto, struct rule *rule)
-{
-    bool actions_changed;
-    uint16_t new_out_iface, old_out_iface;
-
-    old_out_iface = rule->nf_flow.output_iface;
-    actions_changed = rule_make_actions(ofproto, rule, NULL);
-
-    if (rule->may_install) {
-        if (rule->installed) {
-            if (actions_changed) {
-                struct odp_flow_put put;
-                do_put_flow(ofproto, rule, ODPPF_CREATE | ODPPF_MODIFY
-                                           | ODPPF_ZERO_STATS, &put);
-                update_stats(ofproto, rule, &put.flow.stats);
-
-                /* Temporarily set the old output iface so that NetFlow
-                 * messages have the correct output interface for the old
-                 * stats. */
-                new_out_iface = rule->nf_flow.output_iface;
-                rule->nf_flow.output_iface = old_out_iface;
-                rule_post_uninstall(ofproto, rule);
-                rule->nf_flow.output_iface = new_out_iface;
-            }
-        } else {
-            rule_install(ofproto, rule, NULL);
-        }
-    } else {
-        rule_uninstall(ofproto, rule);
-    }
-}
-
-static void
-rule_account(struct ofproto *ofproto, struct rule *rule, uint64_t extra_bytes)
-{
-    uint64_t total_bytes = rule->byte_count + extra_bytes;
-
-    if (ofproto->ofhooks->account_flow_cb
-        && total_bytes > rule->accounted_bytes)
-    {
-        ofproto->ofhooks->account_flow_cb(
-            &rule->cr.flow, rule->odp_actions, rule->n_odp_actions,
-            total_bytes - rule->accounted_bytes, ofproto->aux);
-        rule->accounted_bytes = total_bytes;
-    }
-}
-
-static void
-rule_uninstall(struct ofproto *p, struct rule *rule)
-{
-    assert(!rule->cr.wc.wildcards);
-    if (rule->installed) {
-        struct odp_flow odp_flow;
-
-        odp_flow.key = rule->cr.flow;
-        odp_flow.actions = NULL;
-        odp_flow.n_actions = 0;
-        odp_flow.flags = 0;
-        if (!dpif_flow_del(p->dpif, &odp_flow)) {
-            update_stats(p, rule, &odp_flow.stats);
-        }
-        rule->installed = false;
-
-        rule_post_uninstall(p, rule);
-    }
-}
-
-static bool
-is_controller_rule(struct rule *rule)
-{
-    /* If the only action is send to the controller then don't report
-     * NetFlow expiration messages since it is just part of the control
-     * logic for the network and not real traffic. */
-
-    if (rule && rule->super) {
-        struct rule *super = rule->super;
-
-        return super->n_actions == 1 &&
-               super->actions[0].type == htons(OFPAT_OUTPUT) &&
-               super->actions[0].output.port == htons(OFPP_CONTROLLER);
-    }
-
-    return false;
-}
-
-static void
-rule_post_uninstall(struct ofproto *ofproto, struct rule *rule)
-{
-    struct rule *super = rule->super;
-
-    rule_account(ofproto, rule, 0);
-
-    if (ofproto->netflow && !is_controller_rule(rule)) {
-        struct ofexpired expired;
-        expired.flow = rule->cr.flow;
-        expired.packet_count = rule->packet_count;
-        expired.byte_count = rule->byte_count;
-        expired.used = rule->used;
-        netflow_expire(ofproto->netflow, &rule->nf_flow, &expired);
-    }
-    if (super) {
-        super->packet_count += rule->packet_count;
-        super->byte_count += rule->byte_count;
-
-        /* Reset counters to prevent double counting if the rule ever gets
-         * reinstalled. */
-        rule->packet_count = 0;
-        rule->byte_count = 0;
-        rule->accounted_bytes = 0;
-
-        netflow_flow_clear(&rule->nf_flow);
-    }
-}
 \f
 static void
 queue_tx(struct ofpbuf *msg, const struct ofconn *ofconn,
@@ -2119,440 +1243,95 @@ send_error_oh(const struct ofconn *ofconn, const struct ofp_header *oh,
     send_error(ofconn, oh, error, oh, MIN(oh_length, 64));
 }
 
-static void
-hton_ofp_phy_port(struct ofp_phy_port *opp)
-{
-    opp->port_no = htons(opp->port_no);
-    opp->config = htonl(opp->config);
-    opp->state = htonl(opp->state);
-    opp->curr = htonl(opp->curr);
-    opp->advertised = htonl(opp->advertised);
-    opp->supported = htonl(opp->supported);
-    opp->peer = htonl(opp->peer);
-}
-
 static int
 handle_echo_request(struct ofconn *ofconn, struct ofp_header *oh)
 {
     struct ofp_header *rq = oh;
-    queue_tx(make_echo_reply(rq), ofconn, ofconn->reply_counter);
-    return 0;
-}
-
-static int
-handle_features_request(struct ofproto *p, struct ofconn *ofconn,
-                        struct ofp_header *oh)
-{
-    struct ofp_switch_features *osf;
-    struct ofpbuf *buf;
-    unsigned int port_no;
-    struct ofport *port;
-
-    osf = make_openflow_xid(sizeof *osf, OFPT_FEATURES_REPLY, oh->xid, &buf);
-    osf->datapath_id = htonll(p->datapath_id);
-    osf->n_buffers = htonl(pktbuf_capacity());
-    osf->n_tables = 2;
-    osf->capabilities = htonl(OFPC_FLOW_STATS | OFPC_TABLE_STATS |
-                              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_STRIP_VLAN) |
-                         (1u << OFPAT_SET_DL_SRC) |
-                         (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));
-
-    PORT_ARRAY_FOR_EACH (port, &p->ports, port_no) {
-        hton_ofp_phy_port(ofpbuf_put(buf, &port->opp, sizeof port->opp));
-    }
-
-    queue_tx(buf, ofconn, ofconn->reply_counter);
-    return 0;
-}
-
-static int
-handle_get_config_request(struct ofproto *p, struct ofconn *ofconn,
-                          struct ofp_header *oh)
-{
-    struct ofpbuf *buf;
-    struct ofp_switch_config *osc;
-    uint16_t flags;
-    bool drop_frags;
-
-    /* Figure out flags. */
-    dpif_get_drop_frags(p->dpif, &drop_frags);
-    flags = drop_frags ? OFPC_FRAG_DROP : OFPC_FRAG_NORMAL;
-
-    /* Send reply. */
-    osc = make_openflow_xid(sizeof *osc, OFPT_GET_CONFIG_REPLY, oh->xid, &buf);
-    osc->flags = htons(flags);
-    osc->miss_send_len = htons(ofconn->miss_send_len);
-    queue_tx(buf, ofconn, ofconn->reply_counter);
-
-    return 0;
-}
-
-static int
-handle_set_config(struct ofproto *p, struct ofconn *ofconn,
-                  struct ofp_switch_config *osc)
-{
-    uint16_t flags;
-    int error;
-
-    error = check_ofp_message(&osc->header, OFPT_SET_CONFIG, sizeof *osc);
-    if (error) {
-        return error;
-    }
-    flags = ntohs(osc->flags);
-
-    if (ofconn->type == OFCONN_CONTROLLER && ofconn->role != NX_ROLE_SLAVE) {
-        switch (flags & OFPC_FRAG_MASK) {
-        case OFPC_FRAG_NORMAL:
-            dpif_set_drop_frags(p->dpif, false);
-            break;
-        case OFPC_FRAG_DROP:
-            dpif_set_drop_frags(p->dpif, true);
-            break;
-        default:
-            VLOG_WARN_RL(&rl, "requested bad fragment mode (flags=%"PRIx16")",
-                         osc->flags);
-            break;
-        }
-    }
-
-    ofconn->miss_send_len = ntohs(osc->miss_send_len);
-
-    return 0;
-}
-
-static void
-add_output_group_action(struct odp_actions *actions, uint16_t group,
-                        uint16_t *nf_output_iface)
-{
-    odp_actions_add(actions, ODPAT_OUTPUT_GROUP)->output_group.group = group;
-
-    if (group == DP_GROUP_ALL || group == DP_GROUP_FLOOD) {
-        *nf_output_iface = NF_OUT_FLOOD;
-    }
-}
-
-static void
-add_controller_action(struct odp_actions *actions,
-                      const struct ofp_action_output *oao)
-{
-    union odp_action *a = odp_actions_add(actions, ODPAT_CONTROLLER);
-    a->controller.arg = ntohs(oao->max_len);
-}
-
-struct action_xlate_ctx {
-    /* Input. */
-    flow_t flow;                /* Flow to which these actions correspond. */
-    int recurse;                /* Recursion level, via xlate_table_action. */
-    struct ofproto *ofproto;
-    const struct ofpbuf *packet; /* The packet corresponding to 'flow', or a
-                                  * null pointer if we are revalidating
-                                  * without a packet to refer to. */
-
-    /* Output. */
-    struct odp_actions *out;    /* Datapath actions. */
-    tag_type *tags;             /* Tags associated with OFPP_NORMAL actions. */
-    bool may_set_up_flow;       /* True ordinarily; false if the actions must
-                                 * be reassessed for every packet. */
-    uint16_t nf_output_iface;   /* Output interface index for NetFlow. */
-};
-
-static void do_xlate_actions(const union ofp_action *in, size_t n_in,
-                             struct action_xlate_ctx *ctx);
-
-static void
-add_output_action(struct action_xlate_ctx *ctx, uint16_t port)
-{
-    const struct ofport *ofport = port_array_get(&ctx->ofproto->ports, port);
-
-    if (ofport) {
-        if (ofport->opp.config & OFPPC_NO_FWD) {
-            /* Forwarding disabled on port. */
-            return;
-        }
-    } else {
-        /*
-         * We don't have an ofport record for this port, but it doesn't hurt to
-         * allow forwarding to it anyhow.  Maybe such a port will appear later
-         * and we're pre-populating the flow table.
-         */
-    }
-
-    odp_actions_add(ctx->out, ODPAT_OUTPUT)->output.port = port;
-    ctx->nf_output_iface = port;
-}
-
-static struct rule *
-lookup_valid_rule(struct ofproto *ofproto, const flow_t *flow)
-{
-    struct rule *rule;
-    rule = rule_from_cls_rule(classifier_lookup(&ofproto->cls, flow));
-
-    /* The rule we found might not be valid, since we could be in need of
-     * revalidation.  If it is not valid, don't return it. */
-    if (rule
-        && rule->super
-        && ofproto->need_revalidate
-        && !revalidate_rule(ofproto, rule)) {
-        COVERAGE_INC(ofproto_invalidated);
-        return NULL;
-    }
-
-    return rule;
-}
-
-static void
-xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port)
-{
-    if (!ctx->recurse) {
-        uint16_t old_in_port;
-        struct rule *rule;
-
-        /* Look up a flow with 'in_port' as the input port.  Then restore the
-         * original input port (otherwise OFPP_NORMAL and OFPP_IN_PORT will
-         * have surprising behavior). */
-        old_in_port = ctx->flow.in_port;
-        ctx->flow.in_port = in_port;
-        rule = lookup_valid_rule(ctx->ofproto, &ctx->flow);
-        ctx->flow.in_port = old_in_port;
-
-        if (rule) {
-            if (rule->super) {
-                rule = rule->super;
-            }
-
-            ctx->recurse++;
-            do_xlate_actions(rule->actions, rule->n_actions, ctx);
-            ctx->recurse--;
-        }
-    }
-}
-
-static void
-xlate_output_action(struct action_xlate_ctx *ctx,
-                    const struct ofp_action_output *oao)
-{
-    uint16_t odp_port;
-    uint16_t prev_nf_output_iface = ctx->nf_output_iface;
-
-    ctx->nf_output_iface = NF_OUT_DROP;
-
-    switch (ntohs(oao->port)) {
-    case OFPP_IN_PORT:
-        add_output_action(ctx, ctx->flow.in_port);
-        break;
-    case OFPP_TABLE:
-        xlate_table_action(ctx, ctx->flow.in_port);
-        break;
-    case OFPP_NORMAL:
-        if (!ctx->ofproto->ofhooks->normal_cb(&ctx->flow, ctx->packet,
-                                              ctx->out, ctx->tags,
-                                              &ctx->nf_output_iface,
-                                              ctx->ofproto->aux)) {
-            COVERAGE_INC(ofproto_uninstallable);
-            ctx->may_set_up_flow = false;
-        }
-        break;
-    case OFPP_FLOOD:
-        add_output_group_action(ctx->out, DP_GROUP_FLOOD,
-                                &ctx->nf_output_iface);
-        break;
-    case OFPP_ALL:
-        add_output_group_action(ctx->out, DP_GROUP_ALL, &ctx->nf_output_iface);
-        break;
-    case OFPP_CONTROLLER:
-        add_controller_action(ctx->out, oao);
-        break;
-    case OFPP_LOCAL:
-        add_output_action(ctx, ODPP_LOCAL);
-        break;
-    default:
-        odp_port = ofp_port_to_odp_port(ntohs(oao->port));
-        if (odp_port != ctx->flow.in_port) {
-            add_output_action(ctx, odp_port);
-        }
-        break;
-    }
-
-    if (prev_nf_output_iface == NF_OUT_FLOOD) {
-        ctx->nf_output_iface = NF_OUT_FLOOD;
-    } else if (ctx->nf_output_iface == NF_OUT_DROP) {
-        ctx->nf_output_iface = prev_nf_output_iface;
-    } else if (prev_nf_output_iface != NF_OUT_DROP &&
-               ctx->nf_output_iface != NF_OUT_FLOOD) {
-        ctx->nf_output_iface = NF_OUT_MULTI;
-    }
-}
-
-static void
-xlate_nicira_action(struct action_xlate_ctx *ctx,
-                    const struct nx_action_header *nah)
-{
-    const struct nx_action_resubmit *nar;
-    const struct nx_action_set_tunnel *nast;
-    union odp_action *oa;
-    int subtype = ntohs(nah->subtype);
-
-    assert(nah->vendor == htonl(NX_VENDOR_ID));
-    switch (subtype) {
-    case NXAST_RESUBMIT:
-        nar = (const struct nx_action_resubmit *) nah;
-        xlate_table_action(ctx, ofp_port_to_odp_port(ntohs(nar->in_port)));
-        break;
-
-    case NXAST_SET_TUNNEL:
-        nast = (const struct nx_action_set_tunnel *) nah;
-        oa = odp_actions_add(ctx->out, ODPAT_SET_TUNNEL);
-        ctx->flow.tun_id = oa->tunnel.tun_id = nast->tun_id;
-        break;
-
-    /* If you add a new action here that modifies flow data, don't forget to
-     * update the flow key in ctx->flow in the same key. */
-
-    default:
-        VLOG_DBG_RL(&rl, "unknown Nicira action type %"PRIu16, subtype);
-        break;
-    }
+    queue_tx(make_echo_reply(rq), ofconn, ofconn->reply_counter);
+    return 0;
 }
 
-static void
-do_xlate_actions(const union ofp_action *in, size_t n_in,
-                 struct action_xlate_ctx *ctx)
+static int
+handle_features_request(struct ofproto *p, struct ofconn *ofconn,
+                        struct ofp_header *oh)
 {
-    struct actions_iterator iter;
-    const union ofp_action *ia;
-    const struct ofport *port;
-
-    port = port_array_get(&ctx->ofproto->ports, ctx->flow.in_port);
-    if (port && port->opp.config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) &&
-        port->opp.config & (eth_addr_equals(ctx->flow.dl_dst, stp_eth_addr)
-                            ? OFPPC_NO_RECV_STP : OFPPC_NO_RECV)) {
-        /* Drop this flow. */
-        return;
-    }
+    struct ofpbuf *features;
+    int error;
 
-    for (ia = actions_first(&iter, in, n_in); ia; ia = actions_next(&iter)) {
-        uint16_t type = ntohs(ia->type);
-        union odp_action *oa;
+    error = wdp_get_features(p->wdp, &features);
+    if (!error) {
+        struct ofp_switch_features *osf = features->data;
 
-        switch (type) {
-        case OFPAT_OUTPUT:
-            xlate_output_action(ctx, &ia->output);
-            break;
+        update_openflow_length(features);
+        osf->header.version = OFP_VERSION;
+        osf->header.type = OFPT_FEATURES_REPLY;
+        osf->header.xid = oh->xid;
 
-        case OFPAT_SET_VLAN_VID:
-            oa = odp_actions_add(ctx->out, ODPAT_SET_VLAN_VID);
-            ctx->flow.dl_vlan = oa->vlan_vid.vlan_vid = ia->vlan_vid.vlan_vid;
-            break;
+        osf->datapath_id = htonll(p->datapath_id);
+        osf->n_buffers = htonl(pktbuf_capacity());
+        memset(osf->pad, 0, sizeof osf->pad);
 
-        case OFPAT_SET_VLAN_PCP:
-            oa = odp_actions_add(ctx->out, ODPAT_SET_VLAN_PCP);
-            ctx->flow.dl_vlan_pcp = oa->vlan_pcp.vlan_pcp = ia->vlan_pcp.vlan_pcp;
-            break;
+        /* Turn on capabilities implemented by ofproto. */
+        osf->capabilities |= htonl(OFPC_FLOW_STATS | OFPC_TABLE_STATS |
+                                   OFPC_PORT_STATS);
 
-        case OFPAT_STRIP_VLAN:
-            odp_actions_add(ctx->out, ODPAT_STRIP_VLAN);
-            ctx->flow.dl_vlan = OFP_VLAN_NONE;
-            ctx->flow.dl_vlan_pcp = 0;
-            break;
+        queue_tx(features, ofconn, ofconn->reply_counter);
+    }
+    return error;
+}
 
-        case OFPAT_SET_DL_SRC:
-            oa = odp_actions_add(ctx->out, ODPAT_SET_DL_SRC);
-            memcpy(oa->dl_addr.dl_addr,
-                   ((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
-            memcpy(ctx->flow.dl_src,
-                   ((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
-            break;
+static int
+handle_get_config_request(struct ofproto *p, struct ofconn *ofconn,
+                          struct ofp_header *oh)
+{
+    struct ofpbuf *buf;
+    struct ofp_switch_config *osc;
+    uint16_t flags;
+    bool drop_frags;
 
-        case OFPAT_SET_DL_DST:
-            oa = odp_actions_add(ctx->out, ODPAT_SET_DL_DST);
-            memcpy(oa->dl_addr.dl_addr,
-                   ((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
-            memcpy(ctx->flow.dl_dst,
-                   ((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
-            break;
+    /* Figure out flags. */
+    wdp_get_drop_frags(p->wdp, &drop_frags);
+    flags = drop_frags ? OFPC_FRAG_DROP : OFPC_FRAG_NORMAL;
 
-        case OFPAT_SET_NW_SRC:
-            oa = odp_actions_add(ctx->out, ODPAT_SET_NW_SRC);
-            ctx->flow.nw_src = oa->nw_addr.nw_addr = ia->nw_addr.nw_addr;
-            break;
+    /* Send reply. */
+    osc = make_openflow_xid(sizeof *osc, OFPT_GET_CONFIG_REPLY, oh->xid, &buf);
+    osc->flags = htons(flags);
+    osc->miss_send_len = htons(ofconn->miss_send_len);
+    queue_tx(buf, ofconn, ofconn->reply_counter);
 
-        case OFPAT_SET_NW_DST:
-            oa = odp_actions_add(ctx->out, ODPAT_SET_NW_DST);
-            ctx->flow.nw_dst = oa->nw_addr.nw_addr = ia->nw_addr.nw_addr;
-            break;
+    return 0;
+}
 
-        case OFPAT_SET_NW_TOS:
-            oa = odp_actions_add(ctx->out, ODPAT_SET_NW_TOS);
-            ctx->flow.nw_tos = oa->nw_tos.nw_tos = ia->nw_tos.nw_tos;
-            break;
+static int
+handle_set_config(struct ofproto *p, struct ofconn *ofconn,
+                  struct ofp_switch_config *osc)
+{
+    uint16_t flags;
+    int error;
 
-        case OFPAT_SET_TP_SRC:
-            oa = odp_actions_add(ctx->out, ODPAT_SET_TP_SRC);
-            ctx->flow.tp_src = oa->tp_port.tp_port = ia->tp_port.tp_port;
-            break;
+    error = check_ofp_message(&osc->header, OFPT_SET_CONFIG, sizeof *osc);
+    if (error) {
+        return error;
+    }
+    flags = ntohs(osc->flags);
 
-        case OFPAT_SET_TP_DST:
-            oa = odp_actions_add(ctx->out, ODPAT_SET_TP_DST);
-            ctx->flow.tp_dst = oa->tp_port.tp_port = ia->tp_port.tp_port;
+    if (ofconn->type == OFCONN_CONTROLLER && ofconn->role != NX_ROLE_SLAVE) {
+        switch (flags & OFPC_FRAG_MASK) {
+        case OFPC_FRAG_NORMAL:
+            wdp_set_drop_frags(p->wdp, false);
             break;
-
-        case OFPAT_VENDOR:
-            xlate_nicira_action(ctx, (const struct nx_action_header *) ia);
+        case OFPC_FRAG_DROP:
+            wdp_set_drop_frags(p->wdp, true);
             break;
-
         default:
-            VLOG_DBG_RL(&rl, "unknown action type %"PRIu16, type);
+            VLOG_WARN_RL(&rl, "requested bad fragment mode (flags=%"PRIx16")",
+                         osc->flags);
             break;
         }
     }
-}
 
-static int
-xlate_actions(const union ofp_action *in, size_t n_in,
-              const flow_t *flow, struct ofproto *ofproto,
-              const struct ofpbuf *packet,
-              struct odp_actions *out, tag_type *tags, bool *may_set_up_flow,
-              uint16_t *nf_output_iface)
-{
-    tag_type no_tags = 0;
-    struct action_xlate_ctx ctx;
-    COVERAGE_INC(ofproto_ofp2odp);
-    odp_actions_init(out);
-    ctx.flow = *flow;
-    ctx.recurse = 0;
-    ctx.ofproto = ofproto;
-    ctx.packet = packet;
-    ctx.out = out;
-    ctx.tags = tags ? tags : &no_tags;
-    ctx.may_set_up_flow = true;
-    ctx.nf_output_iface = NF_OUT_DROP;
-    do_xlate_actions(in, n_in, &ctx);
-
-    /* Check with in-band control to see if we're allowed to set up this
-     * flow. */
-    if (!in_band_rule_check(ofproto->in_band, flow, out)) {
-        ctx.may_set_up_flow = false;
-    }
-
-    if (may_set_up_flow) {
-        *may_set_up_flow = ctx.may_set_up_flow;
-    }
-    if (nf_output_iface) {
-        *nf_output_iface = ctx.nf_output_iface;
-    }
-    if (odp_actions_overflow(out)) {
-        odp_actions_init(out);
-        return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_TOO_MANY);
-    }
+    ofconn->miss_send_len = ntohs(osc->miss_send_len);
+
     return 0;
 }
 
@@ -2585,7 +1364,7 @@ handle_packet_out(struct ofproto *p, struct ofconn *ofconn,
 {
     struct ofp_packet_out *opo;
     struct ofpbuf payload, *buffer;
-    struct odp_actions actions;
+    struct ofp_action_header *actions;
     int n_actions;
     uint16_t in_port;
     flow_t flow;
@@ -2601,6 +1380,7 @@ handle_packet_out(struct ofproto *p, struct ofconn *ofconn,
         return error;
     }
     opo = (struct ofp_packet_out *) oh;
+    actions = opo->actions;
 
     COVERAGE_INC(ofproto_packet_out);
     if (opo->buffer_id != htonl(UINT32_MAX)) {
@@ -2614,54 +1394,20 @@ handle_packet_out(struct ofproto *p, struct ofconn *ofconn,
         buffer = NULL;
     }
 
-    flow_extract(&payload, 0, ofp_port_to_odp_port(ntohs(opo->in_port)), &flow);
-    error = xlate_actions((const union ofp_action *) opo->actions, n_actions,
-                          &flow, p, &payload, &actions, NULL, NULL, NULL);
-    if (error) {
-        return error;
-    }
-
-    dpif_execute(p->dpif, flow.in_port, actions.actions, actions.n_actions,
-                 &payload);
+    flow_extract(&payload, 0, ntohs(opo->in_port), &flow);
+    wdp_execute(p->wdp, flow.in_port, (const union ofp_action *) actions,
+                n_actions, &payload);
     ofpbuf_delete(buffer);
 
     return 0;
 }
 
-static void
-update_port_config(struct ofproto *p, struct ofport *port,
-                   uint32_t config, uint32_t mask)
-{
-    mask &= config ^ port->opp.config;
-    if (mask & OFPPC_PORT_DOWN) {
-        if (config & OFPPC_PORT_DOWN) {
-            netdev_turn_flags_off(port->netdev, NETDEV_UP, true);
-        } else {
-            netdev_turn_flags_on(port->netdev, NETDEV_UP, true);
-        }
-    }
-#define REVALIDATE_BITS (OFPPC_NO_RECV | OFPPC_NO_RECV_STP | OFPPC_NO_FWD)
-    if (mask & REVALIDATE_BITS) {
-        COVERAGE_INC(ofproto_costly_flags);
-        port->opp.config ^= mask & REVALIDATE_BITS;
-        p->need_revalidate = true;
-    }
-#undef REVALIDATE_BITS
-    if (mask & OFPPC_NO_FLOOD) {
-        port->opp.config ^= OFPPC_NO_FLOOD;
-        refresh_port_groups(p);
-    }
-    if (mask & OFPPC_NO_PACKET_IN) {
-        port->opp.config ^= OFPPC_NO_PACKET_IN;
-    }
-}
-
 static int
 handle_port_mod(struct ofproto *p, struct ofconn *ofconn,
                 struct ofp_header *oh)
 {
     const struct ofp_port_mod *opm;
-    struct ofport *port;
+    struct wdp_port port;
     int error;
 
     error = reject_slave_controller(ofconn, oh);
@@ -2674,19 +1420,29 @@ handle_port_mod(struct ofproto *p, struct ofconn *ofconn,
     }
     opm = (struct ofp_port_mod *) oh;
 
-    port = port_array_get(&p->ports,
-                          ofp_port_to_odp_port(ntohs(opm->port_no)));
-    if (!port) {
-        return ofp_mkerr(OFPET_PORT_MOD_FAILED, OFPPMFC_BAD_PORT);
-    } else if (memcmp(port->opp.hw_addr, opm->hw_addr, OFP_ETH_ALEN)) {
-        return ofp_mkerr(OFPET_PORT_MOD_FAILED, OFPPMFC_BAD_HW_ADDR);
+    if (wdp_port_query_by_number(p->wdp, ntohs(opm->port_no), &port)) {
+        error = ofp_mkerr(OFPET_PORT_MOD_FAILED, OFPPMFC_BAD_PORT);
+    } else if (memcmp(port.opp.hw_addr, opm->hw_addr, OFP_ETH_ALEN)) {
+        error = ofp_mkerr(OFPET_PORT_MOD_FAILED, OFPPMFC_BAD_HW_ADDR);
     } else {
-        update_port_config(p, port, ntohl(opm->config), ntohl(opm->mask));
+        uint32_t mask, new_config;
+
+        mask = ntohl(opm->mask) & (OFPPC_PORT_DOWN | OFPPC_NO_STP
+                                   | OFPPC_NO_RECV | OFPPC_NO_RECV_STP
+                                   | OFPPC_NO_FLOOD | OFPPC_NO_FWD
+                                   | OFPPC_NO_PACKET_IN);
+        new_config = (port.opp.config & ~mask) | (ntohl(opm->config) & mask);
+        if (new_config != port.opp.config) {
+            wdp_port_set_config(p->wdp, ntohs(opm->port_no), new_config);
+        }
         if (opm->advertise) {
-            netdev_set_advertisements(port->netdev, ntohl(opm->advertise));
+            netdev_set_advertisements(port.netdev, ntohl(opm->advertise));
         }
+        error = 0;
     }
-    return 0;
+    wdp_port_free(&port);
+
+    return error;
 }
 
 static struct ofpbuf *
@@ -2742,46 +1498,28 @@ handle_desc_stats_request(struct ofproto *p, struct ofconn *ofconn,
     return 0;
 }
 
-static void
-count_subrules(struct cls_rule *cls_rule, void *n_subrules_)
-{
-    struct rule *rule = rule_from_cls_rule(cls_rule);
-    int *n_subrules = n_subrules_;
-
-    if (rule->super) {
-        (*n_subrules)++;
-    }
-}
-
 static int
 handle_table_stats_request(struct ofproto *p, struct ofconn *ofconn,
                            struct ofp_stats_request *request)
 {
     struct ofp_table_stats *ots;
     struct ofpbuf *msg;
-    struct odp_stats dpstats;
-    int n_exact, n_subrules, n_wild;
+    struct wdp_stats dpstats;
 
     msg = start_stats_reply(request, sizeof *ots * 2);
 
-    /* Count rules of various kinds. */
-    n_subrules = 0;
-    classifier_for_each(&p->cls, CLS_INC_EXACT, count_subrules, &n_subrules);
-    n_exact = classifier_count_exact(&p->cls) - n_subrules;
-    n_wild = classifier_count(&p->cls) - classifier_count_exact(&p->cls);
+    wdp_get_wdp_stats(p->wdp, &dpstats);
 
     /* Hash table. */
-    dpif_get_dp_stats(p->dpif, &dpstats);
     ots = append_stats_reply(sizeof *ots, ofconn, &msg);
     memset(ots, 0, sizeof *ots);
     ots->table_id = TABLEID_HASH;
     strcpy(ots->name, "hash");
     ots->wildcards = htonl(0);
-    ots->max_entries = htonl(dpstats.max_capacity);
-    ots->active_count = htonl(n_exact);
-    ots->lookup_count = htonll(dpstats.n_frags + dpstats.n_hit +
-                               dpstats.n_missed);
-    ots->matched_count = htonll(dpstats.n_hit); /* XXX */
+    ots->max_entries = htonl(dpstats.exact.max_capacity);
+    ots->active_count = htonl(dpstats.exact.n_flows);
+    ots->lookup_count = htonll(dpstats.exact.n_hit + dpstats.exact.n_missed);
+    ots->matched_count = htonll(dpstats.exact.n_hit);
 
     /* Classifier table. */
     ots = append_stats_reply(sizeof *ots, ofconn, &msg);
@@ -2790,17 +1528,17 @@ handle_table_stats_request(struct ofproto *p, struct ofconn *ofconn,
     strcpy(ots->name, "classifier");
     ots->wildcards = p->tun_id_from_cookie ? htonl(OVSFW_ALL)
                                            : htonl(OFPFW_ALL);
-    ots->max_entries = htonl(65536);
-    ots->active_count = htonl(n_wild);
-    ots->lookup_count = htonll(0);              /* XXX */
-    ots->matched_count = htonll(0);             /* XXX */
+    ots->max_entries = htonl(dpstats.wild.max_capacity);
+    ots->active_count = htonl(dpstats.wild.n_flows);
+    ots->lookup_count = htonll(dpstats.wild.n_hit + dpstats.wild.n_missed);
+    ots->matched_count = htonll(dpstats.wild.n_hit);
 
     queue_tx(msg, ofconn, ofconn->reply_counter);
     return 0;
 }
 
 static void
-append_port_stat(struct ofport *port, uint16_t port_no, struct ofconn *ofconn, 
+append_port_stat(struct wdp_port *port, struct ofconn *ofconn,
                  struct ofpbuf **msgp)
 {
     struct netdev_stats stats;
@@ -2812,7 +1550,7 @@ append_port_stat(struct ofport *port, uint16_t port_no, struct ofconn *ofconn,
     netdev_get_stats(port->netdev, &stats);
 
     ops = append_stats_reply(sizeof *ops, ofconn, msgp);
-    ops->port_no = htons(odp_port_to_ofp_port(port_no));
+    ops->port_no = htons(port->opp.port_no);
     memset(ops->pad, 0, sizeof ops->pad);
     ops->rx_packets = htonll(stats.rx_packets);
     ops->tx_packets = htonll(stats.tx_packets);
@@ -2836,8 +1574,6 @@ handle_port_stats_request(struct ofproto *p, struct ofconn *ofconn,
     struct ofp_port_stats_request *psr;
     struct ofp_port_stats *ops;
     struct ofpbuf *msg;
-    struct ofport *port;
-    unsigned int port_no;
 
     if (arg_size != sizeof *psr) {
         return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
@@ -2846,15 +1582,22 @@ handle_port_stats_request(struct ofproto *p, struct ofconn *ofconn,
 
     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);
+        struct wdp_port port;
+
+        if (!wdp_port_query_by_number(p->wdp, ntohs(psr->port_no), &port)) {
+            append_port_stat(&port, ofconn, &msg);
+            wdp_port_free(&port);
         }
     } else {
-        PORT_ARRAY_FOR_EACH (port, &p->ports, port_no) {
-            append_port_stat(port, port_no, ofconn, &msg);
+        struct wdp_port *ports;
+        size_t n_ports;
+        size_t i;
+
+        wdp_port_list(p->wdp, &ports, &n_ports);
+        for (i = 0; i < n_ports; i++) {
+            append_port_stat(&ports[i], ofconn, &msg);
         }
+        wdp_port_array_free(ports, n_ports);
     }
 
     queue_tx(msg, ofconn, ofconn->reply_counter);
@@ -2872,60 +1615,23 @@ struct flow_stats_cbdata {
  * '*packet_countp' and '*byte_countp'.  If 'rule' is a wildcarded rule, the
  * returned statistic include statistics for all of 'rule''s subrules. */
 static void
-query_stats(struct ofproto *p, struct rule *rule,
+query_stats(struct ofproto *p, struct wdp_rule *rule,
             uint64_t *packet_countp, uint64_t *byte_countp)
 {
-    uint64_t packet_count, byte_count;
-    struct rule *subrule;
-    struct odp_flow *odp_flows;
-    size_t n_odp_flows;
-
-    /* Start from historical data for 'rule' itself that are no longer tracked
-     * by the datapath.  This counts, for example, subrules that have
-     * expired. */
-    packet_count = rule->packet_count;
-    byte_count = rule->byte_count;
-
-    /* Prepare to ask the datapath for statistics on 'rule', or if it is
-     * wildcarded then on all of its subrules.
-     *
-     * Also, add any statistics that are not tracked by the datapath for each
-     * subrule.  This includes, for example, statistics for packets that were
-     * executed "by hand" by ofproto via dpif_execute() but must be accounted
-     * to a flow. */
-    n_odp_flows = rule->cr.wc.wildcards ? list_size(&rule->list) : 1;
-    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) {
-            odp_flows[i++].key = subrule->cr.flow;
-            packet_count += subrule->packet_count;
-            byte_count += subrule->byte_count;
-        }
-    } else {
-        odp_flows[0].key = rule->cr.flow;
-    }
+    struct wdp_flow_stats stats;
 
-    /* Fetch up-to-date statistics from the datapath and add them in. */
-    if (!dpif_flow_get_multiple(p->dpif, odp_flows, n_odp_flows)) {
-        size_t i;
-        for (i = 0; i < n_odp_flows; i++) {
-            struct odp_flow *odp_flow = &odp_flows[i];
-            packet_count += odp_flow->stats.n_packets;
-            byte_count += odp_flow->stats.n_bytes;
-        }
+    if (!wdp_flow_get_stats(p->wdp, rule, &stats)) {
+        *packet_countp = stats.n_packets;
+        *byte_countp = stats.n_bytes;
+    } else {
+        *packet_countp = 0;
+        *byte_countp = 0;
     }
-    free(odp_flows);
-
-    /* Return the stats to the caller. */
-    *packet_countp = packet_count;
-    *byte_countp = byte_count;
 }
 
 static void
-flow_stats_cb(struct cls_rule *rule_, void *cbdata_)
+flow_stats_cb(struct wdp_rule *rule, void *cbdata_)
 {
-    struct rule *rule = rule_from_cls_rule(rule_);
     struct flow_stats_cbdata *cbdata = cbdata_;
     struct ofp_flow_stats *ofs;
     uint64_t packet_count, byte_count;
@@ -2934,7 +1640,8 @@ flow_stats_cb(struct cls_rule *rule_, void *cbdata_)
     uint32_t sec = tdiff / 1000;
     uint32_t msec = tdiff - (sec * 1000);
 
-    if (rule_is_hidden(rule) || !rule_has_out_port(rule, cbdata->out_port)) {
+    if (rule_is_hidden(rule)
+        || !rule_has_out_port(rule, cbdata->out_port)) {
         return;
     }
 
@@ -2945,14 +1652,14 @@ flow_stats_cb(struct cls_rule *rule_, void *cbdata_)
 
     ofs = append_stats_reply(len, cbdata->ofconn, &cbdata->msg);
     ofs->length = htons(len);
-    ofs->table_id = rule->cr.wc.wildcards ? TABLEID_CLASSIFIER : TABLEID_HASH;
+    ofs->table_id = rule->cr.flow.wildcards ? TABLEID_CLASSIFIER : TABLEID_HASH;
     ofs->pad = 0;
-    flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards,
-                  cbdata->ofproto->tun_id_from_cookie, &ofs->match);
+    flow_to_match(&rule->cr.flow, cbdata->ofproto->tun_id_from_cookie,
+                  &ofs->match);
     ofs->duration_sec = htonl(sec);
     ofs->duration_nsec = htonl(msec * 1000000);
-    ofs->cookie = rule->flow_cookie;
-    ofs->priority = htons(rule->cr.priority);
+    ofs->cookie = ofproto_rule_cast(rule)->flow_cookie;
+    ofs->priority = htons(rule->cr.flow.priority);
     ofs->idle_timeout = htons(rule->idle_timeout);
     ofs->hard_timeout = htons(rule->hard_timeout);
     memset(ofs->pad2, 0, sizeof ofs->pad2);
@@ -2977,7 +1684,7 @@ handle_flow_stats_request(struct ofproto *p, struct ofconn *ofconn,
 {
     struct ofp_flow_stats_request *fsr;
     struct flow_stats_cbdata cbdata;
-    struct cls_rule target;
+    flow_t target;
 
     if (arg_size != sizeof *fsr) {
         return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
@@ -2989,10 +1696,10 @@ handle_flow_stats_request(struct ofproto *p, struct ofconn *ofconn,
     cbdata.ofconn = ofconn;
     cbdata.out_port = fsr->out_port;
     cbdata.msg = start_stats_reply(osr, 1024);
-    cls_rule_from_match(&fsr->match, 0, false, 0, &target);
-    classifier_for_each_match(&p->cls, &target,
-                              table_id_to_include(fsr->table_id),
-                              flow_stats_cb, &cbdata);
+    flow_from_match(&fsr->match, 0, false, 0, &target);
+    wdp_flow_for_each_match(p->wdp, &target,
+                            table_id_to_include(fsr->table_id),
+                            flow_stats_cb, &cbdata);
     queue_tx(cbdata.msg, ofconn, ofconn->reply_counter);
     return 0;
 }
@@ -3003,27 +1710,21 @@ struct flow_stats_ds_cbdata {
 };
 
 static void
-flow_stats_ds_cb(struct cls_rule *rule_, void *cbdata_)
+flow_stats_ds_cb(struct wdp_rule *rule, void *cbdata_)
 {
-    struct rule *rule = rule_from_cls_rule(rule_);
     struct flow_stats_ds_cbdata *cbdata = cbdata_;
     struct ds *results = cbdata->results;
     struct ofp_match match;
     uint64_t packet_count, byte_count;
     size_t act_len = sizeof *rule->actions * rule->n_actions;
 
-    /* Don't report on subrules. */
-    if (rule->super != NULL) {
-        return;
-    }
-
     query_stats(cbdata->ofproto, rule, &packet_count, &byte_count);
-    flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards,
-                  cbdata->ofproto->tun_id_from_cookie, &match);
+    flow_to_match(&rule->cr.flow, cbdata->ofproto->tun_id_from_cookie,
+                  &match);
 
     ds_put_format(results, "duration=%llds, ",
                   (time_msec() - rule->created) / 1000);
-    ds_put_format(results, "priority=%u, ", rule->cr.priority);
+    ds_put_format(results, "priority=%u, ", rule->cr.flow.priority);
     ds_put_format(results, "n_packets=%"PRIu64", ", packet_count);
     ds_put_format(results, "n_bytes=%"PRIu64", ", byte_count);
     ofp_print_match(results, &match, true);
@@ -3036,9 +1737,9 @@ flow_stats_ds_cb(struct cls_rule *rule_, void *cbdata_)
 void
 ofproto_get_all_flows(struct ofproto *p, struct ds *results)
 {
-    struct ofp_match match;
-    struct cls_rule target;
     struct flow_stats_ds_cbdata cbdata;
+    struct ofp_match match;
+    flow_t target;
 
     memset(&match, 0, sizeof match);
     match.wildcards = htonl(OVSFW_ALL);
@@ -3046,9 +1747,9 @@ ofproto_get_all_flows(struct ofproto *p, struct ds *results)
     cbdata.ofproto = p;
     cbdata.results = results;
 
-    cls_rule_from_match(&match, 0, false, 0, &target);
-    classifier_for_each_match(&p->cls, &target, CLS_INC_ALL,
-                              flow_stats_ds_cb, &cbdata);
+    flow_from_match(&match, 0, false, 0, &target);
+    wdp_flow_for_each_match(p->wdp, &target, CLS_INC_ALL,
+                            flow_stats_ds_cb, &cbdata);
 }
 
 struct aggregate_stats_cbdata {
@@ -3060,9 +1761,8 @@ struct aggregate_stats_cbdata {
 };
 
 static void
-aggregate_stats_cb(struct cls_rule *rule_, void *cbdata_)
+aggregate_stats_cb(struct wdp_rule *rule, void *cbdata_)
 {
-    struct rule *rule = rule_from_cls_rule(rule_);
     struct aggregate_stats_cbdata *cbdata = cbdata_;
     uint64_t packet_count, byte_count;
 
@@ -3085,8 +1785,8 @@ handle_aggregate_stats_request(struct ofproto *p, struct ofconn *ofconn,
     struct ofp_aggregate_stats_request *asr;
     struct ofp_aggregate_stats_reply *reply;
     struct aggregate_stats_cbdata cbdata;
-    struct cls_rule target;
     struct ofpbuf *msg;
+    flow_t target;
 
     if (arg_size != sizeof *asr) {
         return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
@@ -3099,10 +1799,10 @@ handle_aggregate_stats_request(struct ofproto *p, struct ofconn *ofconn,
     cbdata.packet_count = 0;
     cbdata.byte_count = 0;
     cbdata.n_flows = 0;
-    cls_rule_from_match(&asr->match, 0, false, 0, &target);
-    classifier_for_each_match(&p->cls, &target,
-                              table_id_to_include(asr->table_id),
-                              aggregate_stats_cb, &cbdata);
+    flow_from_match(&asr->match, 0, false, 0, &target);
+    wdp_flow_for_each_match(p->wdp, &target,
+                            table_id_to_include(asr->table_id),
+                            aggregate_stats_cb, &cbdata);
 
     msg = start_stats_reply(osr, sizeof *reply);
     reply = append_stats_reply(sizeof *reply, ofconn, &msg);
@@ -3152,39 +1852,6 @@ handle_stats_request(struct ofproto *p, struct ofconn *ofconn,
     }
 }
 
-static long long int
-msec_from_nsec(uint64_t sec, uint32_t nsec)
-{
-    return !sec ? 0 : sec * 1000 + nsec / 1000000;
-}
-
-static void
-update_time(struct ofproto *ofproto, struct rule *rule,
-            const struct odp_flow_stats *stats)
-{
-    long long int used = msec_from_nsec(stats->used_sec, stats->used_nsec);
-    if (used > rule->used) {
-        rule->used = used;
-        if (rule->super && used > rule->super->used) {
-            rule->super->used = used;
-        }
-        netflow_flow_update_time(ofproto->netflow, &rule->nf_flow, used);
-    }
-}
-
-static void
-update_stats(struct ofproto *ofproto, struct rule *rule,
-             const struct odp_flow_stats *stats)
-{
-    if (stats->n_packets) {
-        update_time(ofproto, rule, stats);
-        rule->packet_count += stats->n_packets;
-        rule->byte_count += stats->n_bytes;
-        netflow_flow_update_flags(&rule->nf_flow, stats->ip_tos,
-                                  stats->tcp_flags);
-    }
-}
-
 /* Implements OFPFC_ADD and the cases for OFPFC_MODIFY and OFPFC_MODIFY_STRICT
  * in which no matching flow already exists in the flow table.
  *
@@ -3198,64 +1865,61 @@ static int
 add_flow(struct ofproto *p, struct ofconn *ofconn,
          const struct ofp_flow_mod *ofm, size_t n_actions)
 {
+    struct wdp_rule *rule;
+    struct wdp_flow_put put;
     struct ofpbuf *packet;
-    struct rule *rule;
     uint16_t in_port;
+    flow_t flow;
     int error;
 
-    if (ofm->flags & htons(OFPFF_CHECK_OVERLAP)) {
-        flow_t flow;
-        uint32_t wildcards;
-
-        flow_from_match(&ofm->match, p->tun_id_from_cookie, ofm->cookie,
-                        &flow, &wildcards);
-        if (classifier_rule_overlaps(&p->cls, &flow, wildcards,
-                                     ntohs(ofm->priority))) {
-            return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_OVERLAP);
-        }
+    flow_from_match(&ofm->match, ntohs(ofm->priority), p->tun_id_from_cookie,
+                    ofm->cookie, &flow);
+    if (ofm->flags & htons(OFPFF_CHECK_OVERLAP)
+        && wdp_flow_overlaps(p->wdp, &flow)) {
+        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),  ofm->cookie,
-                       ofm->flags & htons(OFPFF_SEND_FLOW_REM));
-    cls_rule_from_match(&ofm->match, ntohs(ofm->priority),
-                        p->tun_id_from_cookie, ofm->cookie, &rule->cr);
+    put.flags = WDP_PUT_CREATE | WDP_PUT_MODIFY | WDP_PUT_ALL;
+    put.flow = &flow;
+    put.actions = (const union ofp_action *) ofm->actions;
+    put.n_actions = n_actions;
+    put.idle_timeout = ntohs(ofm->idle_timeout);
+    put.hard_timeout = ntohs(ofm->hard_timeout);
+    error = wdp_flow_put(p->wdp, &put, NULL, &rule);
+    if (error) {
+        /* XXX wdp_flow_put should return OpenFlow error code. */
+        return error;
+    }
+    ofproto_rule_init(rule);
 
-    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;
+        if (!error) {
+            wdp_flow_inject(p->wdp, rule, in_port, packet);
+            ofpbuf_delete(packet);
+        }
     }
 
-    rule_insert(p, rule, packet, in_port);
-    ofpbuf_delete(packet);
-    return error;
+    return 0;
 }
 
-static struct rule *
+static struct wdp_rule *
 find_flow_strict(struct ofproto *p, const struct ofp_flow_mod *ofm)
 {
-    uint32_t wildcards;
     flow_t flow;
 
-    flow_from_match(&ofm->match, p->tun_id_from_cookie, ofm->cookie,
-                    &flow, &wildcards);
-    return rule_from_cls_rule(classifier_find_rule_exactly(
-                                  &p->cls, &flow, wildcards,
-                                  ntohs(ofm->priority)));
+    flow_from_match(&ofm->match, ntohs(ofm->priority),
+                    p->tun_id_from_cookie, ofm->cookie, &flow);
+    return wdp_flow_get(p->wdp, &flow);
 }
 
 static int
 send_buffered_packet(struct ofproto *ofproto, struct ofconn *ofconn,
-                     struct rule *rule, const struct ofp_flow_mod *ofm)
+                     struct wdp_rule *rule, const struct ofp_flow_mod *ofm)
 {
     struct ofpbuf *packet;
     uint16_t in_port;
-    flow_t flow;
     int error;
 
     if (ofm->buffer_id == htonl(UINT32_MAX)) {
@@ -3268,8 +1932,7 @@ send_buffered_packet(struct ofproto *ofproto, struct ofconn *ofconn,
         return error;
     }
 
-    flow_extract(packet, 0, in_port, &flow);
-    rule_execute(ofproto, rule, packet, &flow);
+    wdp_flow_inject(ofproto->wdp, rule, in_port, packet);
     ofpbuf_delete(packet);
 
     return 0;
@@ -3281,12 +1944,12 @@ struct modify_flows_cbdata {
     struct ofproto *ofproto;
     const struct ofp_flow_mod *ofm;
     size_t n_actions;
-    struct rule *match;
+    struct wdp_rule *match;
 };
 
 static int modify_flow(struct ofproto *, const struct ofp_flow_mod *,
-                       size_t n_actions, struct rule *);
-static void modify_flows_cb(struct cls_rule *, void *cbdata_);
+                       size_t n_actions, struct wdp_rule *);
+static void modify_flows_cb(struct wdp_rule *, void *cbdata_);
 
 /* Implements OFPFC_MODIFY.  Returns 0 on success or an OpenFlow error code as
  * encoded by ofp_mkerr() on failure.
@@ -3298,18 +1961,18 @@ modify_flows_loose(struct ofproto *p, struct ofconn *ofconn,
                    const struct ofp_flow_mod *ofm, size_t n_actions)
 {
     struct modify_flows_cbdata cbdata;
-    struct cls_rule target;
+    flow_t target;
 
     cbdata.ofproto = p;
     cbdata.ofm = ofm;
     cbdata.n_actions = n_actions;
     cbdata.match = NULL;
 
-    cls_rule_from_match(&ofm->match, 0, p->tun_id_from_cookie, ofm->cookie,
-                        &target);
+    flow_from_match(&ofm->match, 0, p->tun_id_from_cookie, ofm->cookie,
+                    &target);
 
-    classifier_for_each_match(&p->cls, &target, CLS_INC_ALL,
-                              modify_flows_cb, &cbdata);
+    wdp_flow_for_each_match(p->wdp, &target, CLS_INC_ALL,
+                            modify_flows_cb, &cbdata);
     if (cbdata.match) {
         /* This credits the packet to whichever flow happened to happened to
          * match last.  That's weird.  Maybe we should do a lookup for the
@@ -3330,7 +1993,7 @@ static int
 modify_flow_strict(struct ofproto *p, struct ofconn *ofconn,
                    struct ofp_flow_mod *ofm, size_t n_actions)
 {
-    struct rule *rule = find_flow_strict(p, ofm);
+    struct wdp_rule *rule = find_flow_strict(p, ofm);
     if (rule && !rule_is_hidden(rule)) {
         modify_flow(p, ofm, n_actions, rule);
         return send_buffered_packet(p, ofconn, rule, ofm);
@@ -3341,9 +2004,8 @@ modify_flow_strict(struct ofproto *p, struct ofconn *ofconn,
 
 /* Callback for modify_flows_loose(). */
 static void
-modify_flows_cb(struct cls_rule *rule_, void *cbdata_)
+modify_flows_cb(struct wdp_rule *rule, void *cbdata_)
 {
-    struct rule *rule = rule_from_cls_rule(rule_);
     struct modify_flows_cbdata *cbdata = cbdata_;
 
     if (!rule_is_hidden(rule)) {
@@ -3358,33 +2020,27 @@ modify_flows_cb(struct cls_rule *rule_, void *cbdata_)
  * ofp_action[] structures). */
 static int
 modify_flow(struct ofproto *p, const struct ofp_flow_mod *ofm,
-            size_t n_actions, struct rule *rule)
+            size_t n_actions, struct wdp_rule *rule)
 {
-    size_t actions_len = n_actions * sizeof *rule->actions;
+    const struct ofp_action_header *actions = ofm->actions;
+    struct ofproto_rule *ofproto_rule = ofproto_rule_cast(rule);
+    struct wdp_flow_put put;
 
-    rule->flow_cookie = ofm->cookie;
+    ofproto_rule->flow_cookie = ofm->cookie;
 
     /* If the actions are the same, do nothing. */
     if (n_actions == rule->n_actions
-        && !memcmp(ofm->actions, rule->actions, actions_len))
+        && !memcmp(ofm->actions, rule->actions, sizeof *actions * n_actions))
     {
         return 0;
     }
 
-    /* Replace actions. */
-    free(rule->actions);
-    rule->actions = xmemdup(ofm->actions, actions_len);
-    rule->n_actions = n_actions;
-
-    /* Make sure that the datapath gets updated properly. */
-    if (rule->cr.wc.wildcards) {
-        COVERAGE_INC(ofproto_mod_wc_flow);
-        p->need_revalidate = true;
-    } else {
-        rule_update_actions(p, rule);
-    }
-
-    return 0;
+    put.flags = WDP_PUT_MODIFY | WDP_PUT_ACTIONS;
+    put.flow = &rule->cr.flow;
+    put.actions = (const union ofp_action *) actions;
+    put.n_actions = n_actions;
+    put.idle_timeout = put.hard_timeout = 0;
+    return wdp_flow_put(p->wdp, &put, NULL, NULL);
 }
 \f
 /* OFPFC_DELETE implementation. */
@@ -3394,44 +2050,44 @@ struct delete_flows_cbdata {
     uint16_t out_port;
 };
 
-static void delete_flows_cb(struct cls_rule *, void *cbdata_);
-static void delete_flow(struct ofproto *, struct rule *, uint16_t out_port);
+static void delete_flows_cb(struct wdp_rule *, void *cbdata_);
+static void delete_flow_core(struct ofproto *, struct wdp_rule *,
+                             uint16_t out_port);
 
 /* Implements OFPFC_DELETE. */
 static void
 delete_flows_loose(struct ofproto *p, const struct ofp_flow_mod *ofm)
 {
     struct delete_flows_cbdata cbdata;
-    struct cls_rule target;
+    flow_t target;
 
     cbdata.ofproto = p;
     cbdata.out_port = ofm->out_port;
 
-    cls_rule_from_match(&ofm->match, 0, p->tun_id_from_cookie, ofm->cookie,
-                        &target);
+    flow_from_match(&ofm->match, 0, p->tun_id_from_cookie, ofm->cookie,
+                    &target);
 
-    classifier_for_each_match(&p->cls, &target, CLS_INC_ALL,
-                              delete_flows_cb, &cbdata);
+    wdp_flow_for_each_match(p->wdp, &target, CLS_INC_ALL,
+                            delete_flows_cb, &cbdata);
 }
 
 /* Implements OFPFC_DELETE_STRICT. */
 static void
 delete_flow_strict(struct ofproto *p, struct ofp_flow_mod *ofm)
 {
-    struct rule *rule = find_flow_strict(p, ofm);
+    struct wdp_rule *rule = find_flow_strict(p, ofm);
     if (rule) {
-        delete_flow(p, rule, ofm->out_port);
+        delete_flow_core(p, rule, ofm->out_port);
     }
 }
 
 /* Callback for delete_flows_loose(). */
 static void
-delete_flows_cb(struct cls_rule *rule_, void *cbdata_)
+delete_flows_cb(struct wdp_rule *rule, void *cbdata_)
 {
-    struct rule *rule = rule_from_cls_rule(rule_);
     struct delete_flows_cbdata *cbdata = cbdata_;
 
-    delete_flow(cbdata->ofproto, rule, cbdata->out_port);
+    delete_flow_core(cbdata->ofproto, rule, cbdata->out_port);
 }
 
 /* Implements core of OFPFC_DELETE and OFPFC_DELETE_STRICT where 'rule' has
@@ -3443,7 +2099,7 @@ delete_flows_cb(struct cls_rule *rule_, void *cbdata_)
  * 'out_port' is htons(OFPP_NONE) or if 'rule' actually outputs to the
  * specified 'out_port'. */
 static void
-delete_flow(struct ofproto *p, struct rule *rule, uint16_t out_port)
+delete_flow_core(struct ofproto *p, struct wdp_rule *rule, uint16_t out_port)
 {
     if (rule_is_hidden(rule)) {
         return;
@@ -3453,8 +2109,7 @@ delete_flow(struct ofproto *p, struct rule *rule, uint16_t out_port)
         return;
     }
 
-    send_flow_removed(p, rule, time_msec(), OFPRR_DELETE);
-    rule_remove(p, rule);
+    delete_flow(p, rule, OFPRR_DELETE);
 }
 \f
 static int
@@ -3495,10 +2150,10 @@ handle_flow_mod(struct ofproto *p, struct ofconn *ofconn,
 
     switch (ntohs(ofm->command)) {
     case OFPFC_ADD:
-        return add_flow(p, ofconn, ofm, n_actions);
+        return modify_flows_loose(p, ofconn, ofm, n_actions);
 
     case OFPFC_MODIFY:
-        return modify_flows_loose(p, ofconn, ofm, n_actions);
+        return modify_flow_strict(p, ofconn, ofm, n_actions);
 
     case OFPFC_MODIFY_STRICT:
         return modify_flow_strict(p, ofconn, ofm, n_actions);
@@ -3703,41 +2358,28 @@ handle_openflow(struct ofconn *ofconn, struct ofproto *p,
 }
 \f
 static void
-handle_odp_miss_msg(struct ofproto *p, struct ofpbuf *packet)
+handle_flow_miss(struct ofproto *p, struct wdp_packet *packet)
 {
-    struct odp_msg *msg = packet->data;
-    struct rule *rule;
-    struct ofpbuf payload;
+    struct wdp_rule *rule;
     flow_t flow;
 
-    payload.data = msg + 1;
-    payload.size = msg->length - sizeof *msg;
-    flow_extract(&payload, msg->arg, msg->port, &flow);
-
-    /* Check with in-band control to see if this packet should be sent
-     * to the local port regardless of the flow table. */
-    if (in_band_msg_in_hook(p->in_band, &flow, &payload)) {
-        union odp_action action;
-
-        memset(&action, 0, sizeof(action));
-        action.output.type = ODPAT_OUTPUT;
-        action.output.port = ODPP_LOCAL;
-        dpif_execute(p->dpif, flow.in_port, &action, 1, &payload);
-    }
-
-    rule = lookup_valid_rule(p, &flow);
+    flow_extract(packet->payload, packet->tun_id, packet->in_port, &flow);
+    rule = wdp_flow_match(p->wdp, &flow);
     if (!rule) {
         /* Don't send a packet-in if OFPPC_NO_PACKET_IN asserted. */
-        struct ofport *port = port_array_get(&p->ports, msg->port);
-        if (port) {
-            if (port->opp.config & OFPPC_NO_PACKET_IN) {
+        struct wdp_port port;
+
+        if (!wdp_port_query_by_number(p->wdp, packet->in_port, &port)) {
+            bool no_packet_in = (port.opp.config & OFPPC_NO_PACKET_IN) != 0;
+            wdp_port_free(&port);
+            if (no_packet_in) {
                 COVERAGE_INC(ofproto_no_packet_in);
-                /* XXX install 'drop' flow entry */
-                ofpbuf_delete(packet);
+                wdp_packet_destroy(packet);
                 return;
             }
         } else {
-            VLOG_WARN_RL(&rl, "packet-in on unknown port %"PRIu16, msg->port);
+            VLOG_WARN_RL(&rl, "packet-in on unknown port %"PRIu16,
+                         packet->in_port);
         }
 
         COVERAGE_INC(ofproto_packet_in);
@@ -3745,24 +2387,9 @@ handle_odp_miss_msg(struct ofproto *p, struct ofpbuf *packet)
         return;
     }
 
-    if (rule->cr.wc.wildcards) {
-        rule = rule_create_subrule(p, rule, &flow);
-        rule_make_actions(p, rule, packet);
-    } else {
-        if (!rule->may_install) {
-            /* The rule is not installable, that is, we need to process every
-             * packet, so process the current packet and set its actions into
-             * 'subrule'. */
-            rule_make_actions(p, rule, packet);
-        } else {
-            /* XXX revalidate rule if it needs it */
-        }
-    }
-
-    rule_execute(p, rule, &payload, &flow);
-    rule_reinstall(p, rule);
+    wdp_flow_inject(p->wdp, rule, packet->in_port, packet->payload);
 
-    if (rule->super && rule->super->cr.priority == FAIL_OPEN_PRIORITY) {
+    if (rule->cr.flow.priority == FAIL_OPEN_PRIORITY) {
         /*
          * Extra-special case for fail-open mode.
          *
@@ -3775,273 +2402,120 @@ handle_odp_miss_msg(struct ofproto *p, struct ofpbuf *packet)
          */
         send_packet_in(p, packet);
     } else {
-        ofpbuf_delete(packet);
+        wdp_packet_destroy(packet);
     }
 }
 
 static void
-handle_odp_msg(struct ofproto *p, struct ofpbuf *packet)
+handle_wdp_packet(struct ofproto *p, struct wdp_packet *packet)
 {
-    struct odp_msg *msg = packet->data;
-
-    switch (msg->type) {
-    case _ODPL_ACTION_NR:
+    switch (packet->channel) {
+    case WDP_CHAN_ACTION:
         COVERAGE_INC(ofproto_ctlr_action);
         send_packet_in(p, packet);
         break;
 
-    case _ODPL_SFLOW_NR:
-        if (p->sflow) {
-            ofproto_sflow_received(p->sflow, msg);
-        }
-        ofpbuf_delete(packet);
+    case WDP_CHAN_SFLOW:
+        /* XXX */
+        wdp_packet_destroy(packet);
         break;
 
-    case _ODPL_MISS_NR:
-        handle_odp_miss_msg(p, packet);
+    case WDP_CHAN_MISS:
+        handle_flow_miss(p, packet);
         break;
 
+    case WDP_N_CHANS:
     default:
-        VLOG_WARN_RL(&rl, "received ODP message of unexpected type %"PRIu32,
-                     msg->type);
+        wdp_packet_destroy(packet);
+        VLOG_WARN_RL(&rl, "received message on unexpected channel %d",
+                     (int) packet->channel);
         break;
     }
 }
 \f
-static void
-revalidate_cb(struct cls_rule *sub_, void *cbdata_)
-{
-    struct rule *sub = rule_from_cls_rule(sub_);
-    struct revalidate_cbdata *cbdata = cbdata_;
-
-    if (cbdata->revalidate_all
-        || (cbdata->revalidate_subrules && sub->super)
-        || (tag_set_intersects(&cbdata->revalidate_set, sub->tags))) {
-        revalidate_rule(cbdata->ofproto, sub);
-    }
-}
-
-static bool
-revalidate_rule(struct ofproto *p, struct rule *rule)
-{
-    const flow_t *flow = &rule->cr.flow;
-
-    COVERAGE_INC(ofproto_revalidate_rule);
-    if (rule->super) {
-        struct rule *super;
-        super = rule_from_cls_rule(classifier_lookup_wild(&p->cls, flow));
-        if (!super) {
-            rule_remove(p, rule);
-            return false;
-        } else if (super != rule->super) {
-            COVERAGE_INC(ofproto_revalidate_moved);
-            list_remove(&rule->list);
-            list_push_back(&super->list, &rule->list);
-            rule->super = super;
-            rule->hard_timeout = super->hard_timeout;
-            rule->idle_timeout = super->idle_timeout;
-            rule->created = super->created;
-            rule->used = 0;
-        }
-    }
-
-    rule_update_actions(p, rule);
-    return true;
-}
-
 static struct ofpbuf *
-compose_flow_removed(struct ofproto *p, const struct rule *rule,
-                     long long int now, uint8_t reason)
+compose_flow_removed(struct ofproto *p, const struct wdp_rule *rule,
+                     uint8_t reason)
 {
-    struct ofp_flow_removed *ofr;
-    struct ofpbuf *buf;
-    long long int tdiff = now - rule->created;
+    long long int tdiff = time_msec() - rule->created;
     uint32_t sec = tdiff / 1000;
     uint32_t msec = tdiff - (sec * 1000);
+    struct ofp_flow_removed *ofr;
+    struct ofpbuf *buf;
 
     ofr = make_openflow(sizeof *ofr, OFPT_FLOW_REMOVED, &buf);
-    flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, p->tun_id_from_cookie,
-                  &ofr->match);
-    ofr->cookie = rule->flow_cookie;
-    ofr->priority = htons(rule->cr.priority);
+    flow_to_match(&rule->cr.flow, p->tun_id_from_cookie, &ofr->match);
+    ofr->cookie = ofproto_rule_cast(rule)->flow_cookie;
+    ofr->priority = htons(rule->cr.flow.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
-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)
+delete_flow(struct ofproto *p, struct wdp_rule *rule, uint8_t reason)
 {
-    struct ofconn *ofconn;
-    struct ofconn *prev;
-    struct ofpbuf *buf = NULL;
-
     /* We limit the maximum number of queued flow expirations it by accounting
      * them under the counter for replies.  That works because preventing
      * OpenFlow requests from being processed also prevents new flows from
      * being added (and expiring).  (It also prevents processing OpenFlow
      * requests that would not add new flows, so it is imperfect.) */
 
-    prev = NULL;
-    LIST_FOR_EACH (ofconn, struct ofconn, node, &p->all_conns) {
-        if (rule->send_flow_removed && rconn_is_connected(ofconn->rconn)
-            && ofconn_receives_async_msgs(ofconn)) {
-            if (prev) {
-                queue_tx(ofpbuf_clone(buf), prev, prev->reply_counter);
-            } else {
-                buf = compose_flow_removed(p, rule, now, reason);
-            }
-            prev = ofconn;
-        }
-    }
-    if (prev) {
-        queue_tx(buf, prev, prev->reply_counter);
-    }
-}
-
+    struct ofproto_rule *ofproto_rule = ofproto_rule_cast(rule);
+    struct wdp_flow_stats stats;
+    struct ofpbuf *buf;
 
-static void
-expire_rule(struct cls_rule *cls_rule, void *p_)
-{
-    struct ofproto *p = p_;
-    struct rule *rule = rule_from_cls_rule(cls_rule);
-    long long int hard_expire, idle_expire, expire, now;
-
-    hard_expire = (rule->hard_timeout
-                   ? rule->created + rule->hard_timeout * 1000
-                   : LLONG_MAX);
-    idle_expire = (rule->idle_timeout
-                   && (rule->super || list_is_empty(&rule->list))
-                   ? rule->used + rule->idle_timeout * 1000
-                   : LLONG_MAX);
-    expire = MIN(hard_expire, idle_expire);
-
-    now = time_msec();
-    if (now < expire) {
-        if (rule->installed && now >= rule->used + 5000) {
-            uninstall_idle_flow(p, rule);
-        } else if (!rule->cr.wc.wildcards) {
-            active_timeout(p, rule);
-        }
+    if (ofproto_rule->send_flow_removed) {
+        /* Compose most of the ofp_flow_removed before 'rule' is destroyed. */
+        buf = compose_flow_removed(p, rule, reason);
+    } else {
+        buf = NULL;
+    }
 
+    if (wdp_flow_delete(p->wdp, rule, &stats)) {
         return;
     }
 
-    COVERAGE_INC(ofproto_expired);
-
-    /* Update stats.  This code will be a no-op if the rule expired
-     * due to an idle timeout. */
-    if (rule->cr.wc.wildcards) {
-        struct rule *subrule, *next;
-        LIST_FOR_EACH_SAFE (subrule, next, struct rule, list, &rule->list) {
-            rule_remove(p, subrule);
-        }
-    } else {
-        rule_uninstall(p, rule);
-    }
+    if (buf) {
+        struct ofp_flow_removed *ofr;
+        struct ofconn *prev = NULL;
+        struct ofconn *ofconn;
 
-    if (!rule_is_hidden(rule)) {
-        send_flow_removed(p, rule, now,
-                          (now >= hard_expire
-                           ? OFPRR_HARD_TIMEOUT : OFPRR_IDLE_TIMEOUT));
-    }
-    rule_remove(p, rule);
-}
+        /* Compose the parts of the ofp_flow_removed that require stats. */
+        ofr = buf->data;
+        ofr->packet_count = htonll(stats.n_packets);
+        ofr->byte_count = htonll(stats.n_bytes);
 
-static void
-active_timeout(struct ofproto *ofproto, struct rule *rule)
-{
-    if (ofproto->netflow && !is_controller_rule(rule) &&
-        netflow_active_timeout_expired(ofproto->netflow, &rule->nf_flow)) {
-        struct ofexpired expired;
-        struct odp_flow odp_flow;
-
-        /* Get updated flow stats. */
-        memset(&odp_flow, 0, sizeof odp_flow);
-        if (rule->installed) {
-            odp_flow.key = rule->cr.flow;
-            odp_flow.flags = ODPFF_ZERO_TCP_FLAGS;
-            dpif_flow_get(ofproto->dpif, &odp_flow);
-
-            if (odp_flow.stats.n_packets) {
-                update_time(ofproto, rule, &odp_flow.stats);
-                netflow_flow_update_flags(&rule->nf_flow, odp_flow.stats.ip_tos,
-                                          odp_flow.stats.tcp_flags);
+        LIST_FOR_EACH (ofconn, struct ofconn, node, &p->all_conns) {
+            if (rconn_is_connected(ofconn->rconn)) {
+                if (prev) {
+                    queue_tx(ofpbuf_clone(buf), prev, prev->reply_counter);
+                }
+                prev = ofconn;
             }
         }
-
-        expired.flow = rule->cr.flow;
-        expired.packet_count = rule->packet_count +
-                               odp_flow.stats.n_packets;
-        expired.byte_count = rule->byte_count + odp_flow.stats.n_bytes;
-        expired.used = rule->used;
-
-        netflow_expire(ofproto->netflow, &rule->nf_flow, &expired);
-
-        /* Schedule us to send the accumulated records once we have
-         * collected all of them. */
-        poll_immediate_wake();
-    }
-}
-
-static void
-update_used(struct ofproto *p)
-{
-    struct odp_flow *flows;
-    size_t n_flows;
-    size_t i;
-    int error;
-
-    error = dpif_flow_list_all(p->dpif, &flows, &n_flows);
-    if (error) {
-        return;
-    }
-
-    for (i = 0; i < n_flows; i++) {
-        struct odp_flow *f = &flows[i];
-        struct rule *rule;
-
-        rule = rule_from_cls_rule(
-            classifier_find_rule_exactly(&p->cls, &f->key, 0, UINT16_MAX));
-        if (!rule || !rule->installed) {
-            COVERAGE_INC(ofproto_unexpected_rule);
-            dpif_flow_del(p->dpif, f);
-            continue;
+        if (prev) {
+            queue_tx(buf, prev, prev->reply_counter);
+        } else {
+            ofpbuf_delete(buf);
         }
-
-        update_time(p, rule, &f->stats);
-        rule_account(p, rule, f->stats.n_bytes);
     }
-    free(flows);
+    free(ofproto_rule);
 }
 
 /* pinsched callback for sending 'packet' on 'ofconn'. */
 static void
-do_send_packet_in(struct ofpbuf *packet, void *ofconn_)
+do_send_packet_in(struct wdp_packet *packet, void *ofconn_)
 {
     struct ofconn *ofconn = ofconn_;
 
-    rconn_send_with_limit(ofconn->rconn, packet,
+    rconn_send_with_limit(ofconn->rconn, packet->payload,
                           ofconn->packet_in_counter, 100);
+    packet->payload = NULL;
+    wdp_packet_destroy(packet);
 }
 
 /* Takes 'packet', which has been converted with do_convert_to_packet_in(), and
@@ -4054,12 +2528,11 @@ do_send_packet_in(struct ofpbuf *packet, void *ofconn_)
  * If 'clone' is true, the caller retains ownership of 'packet'.  Otherwise,
  * ownership is transferred to this function. */
 static void
-schedule_packet_in(struct ofconn *ofconn, struct ofpbuf *packet, int max_len,
-                   bool clone)
+schedule_packet_in(struct ofconn *ofconn, struct wdp_packet *packet,
+                   int max_len, bool clone)
 {
     struct ofproto *ofproto = ofconn->ofproto;
-    struct ofp_packet_in *opi = packet->data;
-    uint16_t in_port = ofp_port_to_odp_port(ntohs(opi->in_port));
+    struct ofp_packet_in *opi = packet->payload->data;
     int send_len, trim_size;
     uint32_t buffer_id;
 
@@ -4073,8 +2546,9 @@ schedule_packet_in(struct ofconn *ofconn, struct ofpbuf *packet, int max_len,
     } else {
         struct ofpbuf payload;
         payload.data = opi->data;
-        payload.size = packet->size - offsetof(struct ofp_packet_in, data);
-        buffer_id = pktbuf_save(ofconn->pktbuf, &payload, in_port);
+        payload.size = (packet->payload->size
+                        - offsetof(struct ofp_packet_in, data));
+        buffer_id = pktbuf_save(ofconn->pktbuf, &payload, packet->in_port);
     }
 
     /* Figure out how much of the packet to send. */
@@ -4087,26 +2561,25 @@ schedule_packet_in(struct ofconn *ofconn, struct ofpbuf *packet, int max_len,
     /* Adjust packet length and clone if necessary. */
     trim_size = offsetof(struct ofp_packet_in, data) + send_len;
     if (clone) {
-        packet = ofpbuf_clone_data(packet->data, trim_size);
-        opi = packet->data;
+        packet = wdp_packet_clone(packet, trim_size);
+        opi = packet->payload->data;
     } else {
-        packet->size = trim_size;
+        packet->payload->size = trim_size;
     }
 
     /* Update packet headers. */
     opi->buffer_id = htonl(buffer_id);
-    update_openflow_length(packet);
+    update_openflow_length(packet->payload);
 
     /* Hand over to packet scheduler.  It might immediately call into
      * do_send_packet_in() or it might buffer it for a while (until a later
      * call to pinsched_run()). */
-    pinsched_send(ofconn->schedulers[opi->reason], in_port,
+    pinsched_send(ofconn->schedulers[opi->reason], packet->in_port,
                   packet, do_send_packet_in, ofconn);
 }
 
-/* Replace struct odp_msg header in 'packet' by equivalent struct
- * ofp_packet_in.  The odp_msg must have sufficient headroom to do so (e.g. as
- * returned by dpif_recv()).
+/* Converts 'packet->payload' to a struct ofp_packet_in.  It must have
+ * sufficient headroom to do so (e.g. as returned by dpif_recv()).
  *
  * The conversion is not complete: the caller still needs to trim any unneeded
  * payload off the end of the buffer, set the length in the OpenFlow header,
@@ -4116,48 +2589,37 @@ schedule_packet_in(struct ofconn *ofconn, struct ofpbuf *packet, int max_len,
  * Returns the maximum number of bytes of the packet that should be sent to
  * the controller (INT_MAX if no limit). */
 static int
-do_convert_to_packet_in(struct ofpbuf *packet)
+do_convert_to_packet_in(struct wdp_packet *packet)
 {
-    struct odp_msg *msg = packet->data;
+    uint16_t total_len = packet->payload->size;
     struct ofp_packet_in *opi;
-    uint8_t reason;
-    uint16_t total_len;
-    uint16_t in_port;
-    int max_len;
-
-    /* Extract relevant header fields */
-    if (msg->type == _ODPL_ACTION_NR) {
-        reason = OFPR_ACTION;
-        max_len = msg->arg;
-    } else {
-        reason = OFPR_NO_MATCH;
-        max_len = INT_MAX;
-    }
-    total_len = msg->length - sizeof *msg;
-    in_port = odp_port_to_ofp_port(msg->port);
 
     /* Repurpose packet buffer by overwriting header. */
-    ofpbuf_pull(packet, sizeof(struct odp_msg));
-    opi = ofpbuf_push_zeros(packet, offsetof(struct ofp_packet_in, data));
+    opi = ofpbuf_push_zeros(packet->payload,
+                            offsetof(struct ofp_packet_in, data));
     opi->header.version = OFP_VERSION;
     opi->header.type = OFPT_PACKET_IN;
     opi->total_len = htons(total_len);
-    opi->in_port = htons(in_port);
-    opi->reason = reason;
-
-    return max_len;
+    opi->in_port = htons(packet->in_port);
+    if (packet->channel == WDP_CHAN_MISS) {
+        opi->reason = OFPR_NO_MATCH;
+        return INT_MAX;
+    } else {
+        opi->reason = OFPR_ACTION;
+        return packet->send_len;
+    }
 }
 
-/* Given 'packet' containing an odp_msg of type _ODPL_ACTION_NR or
- * _ODPL_MISS_NR, sends an OFPT_PACKET_IN message to each OpenFlow controller
- * as necessary according to their individual configurations.
+/* Given 'packet' with channel WDP_CHAN_ACTION or WDP_CHAN_MISS, sends an
+ * OFPT_PACKET_IN message to each OpenFlow controller as necessary according to
+ * their individual configurations.
  *
- * 'packet' must have sufficient headroom to convert it into a struct
+ * 'packet->payload' must have sufficient headroom to convert it into a struct
  * ofp_packet_in (e.g. as returned by dpif_recv()).
  *
  * Takes ownership of 'packet'. */
 static void
-send_packet_in(struct ofproto *ofproto, struct ofpbuf *packet)
+send_packet_in(struct ofproto *ofproto, struct wdp_packet *packet)
 {
     struct ofconn *ofconn, *prev;
     int max_len;
@@ -4176,27 +2638,29 @@ send_packet_in(struct ofproto *ofproto, struct ofpbuf *packet)
     if (prev) {
         schedule_packet_in(prev, packet, max_len, false);
     } else {
-        ofpbuf_delete(packet);
+        wdp_packet_destroy(packet);
     }
 }
 
 static uint64_t
 pick_datapath_id(const struct ofproto *ofproto)
 {
-    const struct ofport *port;
+    struct wdp_port port;
 
-    port = port_array_get(&ofproto->ports, ODPP_LOCAL);
-    if (port) {
+    if (!wdp_port_query_by_number(ofproto->wdp, OFPP_LOCAL, &port)) {
         uint8_t ea[ETH_ADDR_LEN];
         int error;
 
-        error = netdev_get_etheraddr(port->netdev, ea);
+        error = netdev_get_etheraddr(port.netdev, ea);
         if (!error) {
+            wdp_port_free(&port);
             return eth_addr_to_uint64(ea);
         }
         VLOG_WARN("could not get MAC address for %s (%s)",
-                  netdev_get_name(port->netdev), strerror(error));
+                  netdev_get_name(port.netdev), strerror(error));
+        wdp_port_free(&port);
     }
+
     return ofproto->fallback_dpid;
 }
 
@@ -4207,51 +2671,3 @@ pick_fallback_dpid(void)
     eth_addr_nicira_random(ea);
     return eth_addr_to_uint64(ea);
 }
-\f
-static bool
-default_normal_ofhook_cb(const flow_t *flow, const struct ofpbuf *packet,
-                         struct odp_actions *actions, tag_type *tags,
-                         uint16_t *nf_output_iface, void *ofproto_)
-{
-    struct ofproto *ofproto = ofproto_;
-    int out_port;
-
-    /* Drop frames for reserved multicast addresses. */
-    if (eth_addr_is_reserved(flow->dl_dst)) {
-        return true;
-    }
-
-    /* Learn source MAC (but don't try to learn from revalidation). */
-    if (packet != NULL) {
-        tag_type rev_tag = mac_learning_learn(ofproto->ml, flow->dl_src,
-                                              0, flow->in_port);
-        if (rev_tag) {
-            /* The log messages here could actually be useful in debugging,
-             * so keep the rate limit relatively high. */
-            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
-            VLOG_DBG_RL(&rl, "learned that "ETH_ADDR_FMT" is on port %"PRIu16,
-                        ETH_ADDR_ARGS(flow->dl_src), flow->in_port);
-            ofproto_revalidate(ofproto, rev_tag);
-        }
-    }
-
-    /* Determine output port. */
-    out_port = mac_learning_lookup_tag(ofproto->ml, flow->dl_dst, 0, tags);
-    if (out_port < 0) {
-        add_output_group_action(actions, DP_GROUP_FLOOD, nf_output_iface);
-    } else if (out_port != flow->in_port) {
-        odp_actions_add(actions, ODPAT_OUTPUT)->output.port = out_port;
-        *nf_output_iface = out_port;
-    } else {
-        /* Drop. */
-    }
-
-    return true;
-}
-
-static const struct ofhooks default_ofhooks = {
-    NULL,
-    default_normal_ofhook_cb,
-    NULL,
-    NULL
-};
index c3d71e8..c537b20 100644 (file)
 extern "C" {
 #endif
 
-struct odp_actions;
+struct xflow_actions;
 struct ofhooks;
 struct ofproto;
 struct svec;
 
-enum {
-    DP_GROUP_FLOOD = 0,
-    DP_GROUP_ALL = 1
-};
-
 struct ofexpired {
     flow_t flow;
     uint64_t packet_count;      /* Packets from subrules. */
@@ -128,12 +123,10 @@ void ofproto_get_all_flows(struct ofproto *p, struct ds *);
 int ofproto_send_packet(struct ofproto *, const flow_t *,
                         const union ofp_action *, size_t n_actions,
                         const struct ofpbuf *);
-void ofproto_add_flow(struct ofproto *, const flow_t *, uint32_t wildcards,
-                      unsigned int priority,
+void ofproto_add_flow(struct ofproto *, const flow_t *,
                       const union ofp_action *, size_t n_actions,
                       int idle_timeout);
-void ofproto_delete_flow(struct ofproto *, const flow_t *, uint32_t wildcards,
-                         unsigned int priority);
+void ofproto_delete_flow(struct ofproto *, const flow_t *);
 void ofproto_flush_flows(struct ofproto *);
 
 /* Hooks for ovs-vswitchd. */
@@ -141,9 +134,9 @@ struct ofhooks {
     void (*port_changed_cb)(enum ofp_port_reason, const struct ofp_phy_port *,
                             void *aux);
     bool (*normal_cb)(const flow_t *, const struct ofpbuf *packet,
-                      struct odp_actions *, tag_type *,
+                      struct xflow_actions *, tag_type *,
                       uint16_t *nf_output_iface, void *aux);
-    void (*account_flow_cb)(const flow_t *, const union odp_action *,
+    void (*account_flow_cb)(const flow_t *, const union xflow_action *,
                             size_t n_actions, unsigned long long int n_bytes,
                             void *aux);
     void (*account_checkpoint_cb)(void *aux);
index 6af2bb6..f6a453a 100644 (file)
 #include <arpa/inet.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include "list.h"
 #include "ofpbuf.h"
 #include "openflow/openflow.h"
 #include "poll-loop.h"
 #include "port-array.h"
-#include "queue.h"
 #include "random.h"
 #include "rconn.h"
 #include "status.h"
 #include "timeval.h"
 #include "vconn.h"
+#include "wdp.h"
+
+struct wdp_packet_queue {
+    struct list list;
+    int n;
+};
 
 struct pinsched {
     /* Client-supplied parameters. */
@@ -38,7 +44,7 @@ struct pinsched {
     int burst_limit;          /* Maximum token bucket size, in packets. */
 
     /* One queue per physical port. */
-    struct port_array queues;   /* Array of "struct ovs_queue *". */
+    struct port_array queues;   /* Array of "struct wdp_packet_queue". */
     int n_queued;               /* Sum over queues[*].n. */
     unsigned int last_tx_port;  /* Last port checked in round-robin. */
 
@@ -63,12 +69,15 @@ struct pinsched {
     struct status_category *ss_cat;
 };
 
-static struct ofpbuf *
-dequeue_packet(struct pinsched *ps, struct ovs_queue *q,
+static struct wdp_packet *
+dequeue_packet(struct pinsched *ps, struct wdp_packet_queue *q,
                unsigned int port_no)
 {
-    struct ofpbuf *packet = queue_pop_head(q);
-    if (!q->n) {
+    struct wdp_packet *packet;
+
+    packet = CONTAINER_OF(list_pop_front(&q->list), struct wdp_packet, list);
+    q->n--;
+    if (list_is_empty(&q->list)) {
         free(q);
         port_array_set(&ps->queues, port_no, NULL);
     }
@@ -80,11 +89,11 @@ dequeue_packet(struct pinsched *ps, struct ovs_queue *q,
 static void
 drop_packet(struct pinsched *ps)
 {
-    struct ovs_queue *longest;  /* Queue currently selected as longest. */
-    int n_longest;              /* # of queues of same length as 'longest'. */
+    struct wdp_packet_queue *longest;
+    int n_longest;
     unsigned int longest_port_no;
     unsigned int port_no;
-    struct ovs_queue *q;
+    struct wdp_packet_queue *q;
 
     ps->n_queue_dropped++;
 
@@ -108,14 +117,16 @@ drop_packet(struct pinsched *ps)
     }
 
     /* FIXME: do we want to pop the tail instead? */
-    ofpbuf_delete(dequeue_packet(ps, longest, longest_port_no));
+    wdp_packet_destroy(dequeue_packet(ps, longest, longest_port_no));
 }
 
 /* Remove and return the next packet to transmit (in round-robin order). */
-static struct ofpbuf *
+static struct wdp_packet *
 get_tx_packet(struct pinsched *ps)
 {
-    struct ovs_queue *q = port_array_next(&ps->queues, &ps->last_tx_port);
+    struct wdp_packet_queue *q;
+
+    q = port_array_next(&ps->queues, &ps->last_tx_port);
     if (!q) {
         q = port_array_first(&ps->queues, &ps->last_tx_port);
     }
@@ -150,7 +161,7 @@ get_token(struct pinsched *ps)
 
 void
 pinsched_send(struct pinsched *ps, uint16_t port_no,
-              struct ofpbuf *packet, pinsched_tx_cb *cb, void *aux)
+              struct wdp_packet *packet, pinsched_tx_cb *cb, void *aux)
 {
     if (!ps) {
         cb(packet, aux);
@@ -161,13 +172,13 @@ pinsched_send(struct pinsched *ps, uint16_t port_no,
         cb(packet, aux);
     } else {
         /* Otherwise queue it up for the periodic callback to drain out. */
-        struct ovs_queue *q;
+        struct wdp_packet_queue *q;
 
-        /* We are called with a buffer obtained from dpif_recv() that has much
+        /* We are called with a buffer obtained from xfif_recv() that has much
          * more allocated space than actual content most of the time.  Since
          * we're going to store the packet for some time, free up that
          * otherwise wasted space. */
-        ofpbuf_trim(packet);
+        ofpbuf_trim(packet->payload);
 
         if (ps->n_queued >= ps->burst_limit) {
             drop_packet(ps);
@@ -175,10 +186,12 @@ pinsched_send(struct pinsched *ps, uint16_t port_no,
         q = port_array_get(&ps->queues, port_no);
         if (!q) {
             q = xmalloc(sizeof *q);
-            queue_init(q);
+            list_init(&q->list);
+            q->n = 0;
             port_array_set(&ps->queues, port_no, q);
         }
-        queue_push_tail(q, packet);
+        list_push_back(&q->list, &packet->list);
+        q->n++;
         ps->n_queued++;
         ps->n_limited++;
     }
index 17e3db1..0bbdbe0 100644 (file)
 
 struct ofpbuf;
 struct switch_status;
+struct wdp_packet;
 
-typedef void pinsched_tx_cb(struct ofpbuf *, void *aux);
+typedef void pinsched_tx_cb(struct wdp_packet *, void *aux);
 struct pinsched *pinsched_create(int rate_limit, int burst_limit,
                                  struct switch_status *);
 void pinsched_get_limits(const struct pinsched *,
                          int *rate_limit, int *burst_limit);
 void pinsched_set_limits(struct pinsched *, int rate_limit, int burst_limit);
 void pinsched_destroy(struct pinsched *);
-void pinsched_send(struct pinsched *, uint16_t port_no, struct ofpbuf *,
+void pinsched_send(struct pinsched *, uint16_t port_no, struct wdp_packet *,
                    pinsched_tx_cb *, void *aux);
 void pinsched_run(struct pinsched *, pinsched_tx_cb *, void *aux);
 void pinsched_wait(struct pinsched *);
index c103c7f..e4c5c72 100644 (file)
@@ -20,6 +20,7 @@
 #include <stdlib.h>
 #include "coverage.h"
 #include "ofpbuf.h"
+#include "openflow/openflow.h"
 #include "timeval.h"
 #include "util.h"
 #include "vconn.h"
@@ -151,7 +152,7 @@ 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 UINT16_max in '*in_port'.
+ * NULL in '*bufferp' and OFPP_NONE in '*in_port'.
  *
  * On failure, stores NULL in in '*bufferp' and UINT16_MAX in '*in_port'. */
 int
@@ -194,7 +195,7 @@ pktbuf_retrieve(struct pktbuf *pb, uint32_t id, struct ofpbuf **bufferp,
         error = 0;
     }
     *bufferp = NULL;
-    *in_port = UINT16_MAX;
+    *in_port = OFPP_NONE;
     return error;
 }
 
diff --git a/ofproto/wdp-provider.h b/ofproto/wdp-provider.h
new file mode 100644 (file)
index 0000000..4efb383
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 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.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WDP_PROVIDER_H
+#define WDP_PROVIDER_H 1
+
+/* Provider interface to wdps, which provide an interface to an Open vSwitch
+ * datapath. */
+
+#include <assert.h>
+#include "util.h"
+#include "wdp.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+static inline struct wdp_rule *
+wdp_rule_cast(const struct cls_rule *cls_rule)
+{
+    return cls_rule ? CONTAINER_OF(cls_rule, struct wdp_rule, cr) : NULL;
+}
+
+/* Open vSwitch datapath interface.
+ *
+ * This structure should be treated as opaque by wdp implementations. */
+struct wdp {
+    const struct wdp_class *wdp_class;
+    char *base_name;
+    char *full_name;
+    uint8_t netflow_engine_type;
+    uint8_t netflow_engine_id;
+};
+
+void wdp_init(struct wdp *, const struct wdp_class *, const char *name,
+              uint8_t netflow_engine_type, uint8_t netflow_engine_id);
+void wdp_uninit(struct wdp *wdp, bool close);
+
+static inline void wdp_assert_class(const struct wdp *wdp,
+                                    const struct wdp_class *wdp_class)
+{
+    assert(wdp->wdp_class == wdp_class);
+}
+
+/* Datapath interface class structure, to be defined by each implementation of
+ * a datapath interface.
+ *
+ * These functions return 0 if successful or a positive errno value on failure,
+ * except where otherwise noted.
+ *
+ * Most of these functions are expected to execute synchronously, that is, to
+ * block as necessary to obtain a result.  Thus, these functions may return
+ * EAGAIN (or EWOULDBLOCK or EINPROGRESS) only where the function descriptions
+ * explicitly say those errors are a possibility.  We may relax this
+ * requirement in the future if and when we encounter performance problems. */
+struct wdp_class {
+    /* Type of wdp in this class, e.g. "system", "netdev", etc.
+     *
+     * One of the providers should supply a "system" type, since this is
+     * the type assumed if no type is specified when opening a wdp. */
+    const char *type;
+
+    /* Performs periodic work needed by wdps of this class, if any is
+     * necessary. */
+    void (*run)(void);
+
+    /* Arranges for poll_block() to wake up if the "run" member function needs
+     * to be called. */
+    void (*wait)(void);
+
+    /* Enumerates the names of all known created datapaths for 'wdp_class',
+     * if possible, into 'all_wdps'.  The caller has already initialized
+     * 'all_wdps' and other wdp classes might already have added names to it.
+     *
+     * This is used by the vswitch at startup, so that it can delete any
+     * datapaths that are not configured.
+     *
+     * Some kinds of datapaths might not be practically enumerable, in which
+     * case this function may be a null pointer. */
+    int (*enumerate)(const struct wdp_class *wdp_class,
+                     struct svec *all_wdps);
+
+    /* Attempts to open an existing wdp of class 'wdp_class' called 'name',
+     * if 'create' is false, or to open an existing wdp or create a new one,
+     * if 'create' is true.
+     *
+     * If successful, stores a pointer to the new wdp in '*wdpp'.  On
+     * failure there are no requirements on what is stored in '*wdpp'. */
+    int (*open)(const struct wdp_class *wdp_class, const char *name,
+                bool create, struct wdp **wdpp);
+
+    /* Closes 'wdp' and frees associated memory. */
+    void (*close)(struct wdp *wdp);
+
+    /* Enumerates all names that may be used to open 'wdp' into 'all_names'.
+     * The Linux datapath, for example, supports opening a datapath both by
+     * number, e.g. "wdp0", and by the name of the datapath's local port.  For
+     * some datapaths, this might be an infinite set (e.g. in a file name,
+     * slashes may be duplicated any number of times), in which case only the
+     * names most likely to be used should be enumerated.
+     *
+     * The caller has already initialized 'all_names' and might already have
+     * added some names to it.  This function should not disturb any existing
+     * names in 'all_names'.
+     *
+     * If a datapath class does not support multiple names for a datapath, this
+     * function may be a null pointer.
+     *
+     * This is used by the vswitch at startup, */
+    int (*get_all_names)(const struct wdp *wdp, struct svec *all_names);
+
+    /* Attempts to destroy the wdp underlying 'wdp'.
+     *
+     * If successful, 'wdp' will not be used again except as an argument for
+     * the 'close' member function. */
+    int (*destroy)(struct wdp *wdp);
+
+    /* Creates a "struct ofp_switch_features" for 'wdp' and stores it in
+     * '*featuresp'.  The caller is responsible for freeing '*featuresp' (with
+     * ofpbuf_delete()) when it is no longer needed. */
+    int (*get_features)(const struct wdp *wdp, struct ofpbuf **featuresp);
+
+    /* Retrieves statistics for 'wdp' into 'stats'. */
+    int (*get_stats)(const struct wdp *wdp, struct wdp_stats *stats);
+
+    /* Retrieves 'wdp''s current treatment of IP fragments into '*drop_frags':
+     * true indicates that fragments are dropped, false indicates that
+     * fragments are treated in the same way as other IP packets (except that
+     * the L4 header cannot be read). */
+    int (*get_drop_frags)(const struct wdp *wdp, bool *drop_frags);
+
+    /* Changes 'wdp''s treatment of IP fragments to 'drop_frags', whose meaning
+     * is the same as for the get_drop_frags member function.  EOPNOTSUPP
+     * indicates that the datapath does not support changing the fragment
+     * dropping policy, as does a null pointer. */
+    int (*set_drop_frags)(struct wdp *wdp, bool drop_frags);
+
+    /* Creates a new port in 'wdp' connected to network device 'devname'.  If
+     * 'internal' is true, creates the port as an internal port.  If
+     * successful, sets '*port_nop' to the new port's port number.
+     *
+     * Possible error return values include:
+     *
+     *   - ENODEV: No device named 'devname' exists (if 'internal' is false).
+     *
+     *   - EEXIST: A device named 'devname' already exists (if 'internal' is
+     *     true).
+     *
+     *   - EINVAL: Device 'devname' is not supported as part of a datapath
+     *     (e.g. it is not an Ethernet device), or 'devname' is too long for a
+     *     network device name (if 'internal' is true)
+     *
+     *   - EFBIG: The datapath already has as many ports as it can support.
+     *
+     *   - EOPNOTSUPP: 'wdp' has a fixed set of ports.
+     *
+     * A null pointer is equivalent to returning EOPNOTSUPP.
+     */
+    int (*port_add)(struct wdp *wdp, const char *devname,
+                    bool internal, uint16_t *port_nop);
+
+    /* Removes port numbered 'port_no' from 'wdp'.
+     *
+     * Possible error return values include:
+     *
+     *   - EINVAL: 'port_no' is outside the valid range, or this particular
+     *     port is not removable (e.g. it is the local port).
+     *
+     *   - ENOENT: 'wdp' currently has no port numbered 'port_no'.
+     *
+     *   - EOPNOTSUPP: 'wdp' has a fixed set of ports.
+     *
+     * A null pointer is equivalent to returning EOPNOTSUPP.
+     */
+    int (*port_del)(struct wdp *wdp, uint16_t port_no);
+
+    /* Looks up a port in 'wdp' by name or number.  On success, returns 0 and
+     * initializes '*portp'.  On failure, returns a positive errno value.
+     *
+     * The caller takes ownership of everything in '*portp' and will eventually
+     * free it with, e.g., wdp_port_free(). */
+    int (*port_query_by_number)(const struct wdp *wdp, uint16_t port_no,
+                                struct wdp_port *portp);
+    int (*port_query_by_name)(const struct wdp *wdp, const char *devname,
+                              struct wdp_port *portp);
+
+    /* Obtains a list of all the ports in 'wdp'.  Sets '*portsp' to point to an
+     * array of port structures and '*n_portsp' to the number of ports in the
+     * array.
+     *
+     * The caller takes ownership of '*portsp' and all of the ports in it and
+     * is responsible for freeing the ports and the array with, e.g.,
+     * wdp_port_array_free(). */
+    int (*port_list)(const struct wdp *wdp, struct wdp_port **portsp,
+                     size_t *n_portsp);
+
+    int (*port_set_config)(struct wdp *wdp, uint16_t port_no,
+                           uint32_t config);
+
+    /* Polls for changes in the set of ports in 'wdp'.  If the set of ports
+     * in 'wdp' has changed, then this function should do one of the
+     * following:
+     *
+     * - Preferably: store the name of the device that was added to or deleted
+     *   from 'wdp' in '*devnamep' and return 0.  The caller is responsible
+     *   for freeing '*devnamep' (with free()) when it no longer needs it.
+     *
+     * - Alternatively: return ENOBUFS, without indicating the device that was
+     *   added or deleted.
+     *
+     * Occasional 'false positives', in which the function returns 0 while
+     * indicating a device that was not actually added or deleted or returns
+     * ENOBUFS without any change, are acceptable.
+     *
+     * If the set of ports in 'wdp' has not changed, returns EAGAIN.  May
+     * also return other positive errno values to indicate that something has
+     * gone wrong.
+     *
+     * If 'wdp' has a fixed set of ports, this function may be null, which is
+     * equivalent to always returning EAGAIN.
+     */
+    int (*port_poll)(const struct wdp *wdp, char **devnamep);
+
+    /* Arranges for the poll loop to wake up when 'port_poll' will return a
+     * value other than EAGAIN.
+     *
+     * If 'wdp' has a fixed set of ports, this function may be null. */
+    void (*port_poll_wait)(const struct wdp *wdp);
+
+    /* If 'wdp' contains a flow exactly equal to 'flow', returns that flow.
+     * Otherwise returns null. */
+    struct wdp_rule *(*flow_get)(const struct wdp *wdp,
+                                 const flow_t *flow);
+
+    /* If 'wdp' contains one or more flows that match 'flow', returns the
+     * highest-priority matching flow.  If there is more than one
+     * highest-priority match, picks one of them in an arbitrary fashion.
+     * Otherwise returns null.
+     *
+     * Ignores 'flow->priority' and 'flow->wildcards'. */
+    struct wdp_rule *(*flow_match)(const struct wdp *wdp,
+                                   const flow_t *flow);
+
+    /* Iterates through all of the flows in 'wdp''s flow table, passing each
+     * flow that matches the specified search criteria to 'callback' along with
+     * 'aux'.
+     *
+     * Flows are filtered out in two ways.  First, based on 'include':
+     * Exact-match flows are excluded unless CLS_INC_EXACT is in 'include'.
+     * Wildcarded flows are excluded unless CLS_INC_WILD is in 'include'.
+     *
+     * Flows are also filtered out based on 'target': on a field-by-field
+     * basis, a flow is included if 'target' wildcards that field or if the
+     * flow and 'target' both have the same exact value for the field.  A flow
+     * is excluded if any field does not match based on these criteria.
+     *
+     * Ignores 'target->priority'.
+     *
+     * 'callback' is allowed to delete the rule that is passed as its argument.
+     * It may modify any flow in 'wdp', e.g. changing their actions.
+     * 'callback' must not delete flows from 'wdp' other than its argument
+     * flow, nor may it insert new flows into 'wdp'. */
+    void (*flow_for_each_match)(const struct wdp *wdp, const flow_t *flow,
+                                int include,
+                                wdp_flow_cb_func *callback, void *aux);
+
+    /* Retrieves flow statistics for 'rule', which must be in 'wdp''s flow
+     * table, and stores them into '*stats'.  Returns 0 if successful,
+     * otherwise a positive errno value. */
+    int (*flow_get_stats)(const struct wdp *wdp,
+                          const struct wdp_rule *rule,
+                          struct wdp_flow_stats *stats);
+
+    /* Searches 'wdp''s flow table for a flow that overlaps 'flow'.  Two flow
+     * entries overlap if they have the same priority and a single packet may
+     * match both.
+     *
+     * This is intended for implementing OpenFlow's OFPFF_CHECK_OVERLAP
+     * feature. */
+    bool (*flow_overlaps)(const struct wdp *wdp, const flow_t *flow);
+
+    /* Adds or modifies a flow in 'wdp' as specified in 'put':
+     *
+     *   - If a rule with the same priority, wildcards, and values for fields
+     *     that are not wildcarded specified in 'put->flow' does not already
+     *     exist in 'wdp', then behavior depends on whether WDP_PUT_CREATE is
+     *     specified in 'put->flags': if it is, the flow will be added,
+     *     otherwise the operation will fail with ENOENT.
+     *
+     *     The new flow's actions and timeouts are set from the values in
+     *     'put'.
+     *
+     *   - Otherwise, the flow specified in 'put->flow' does exist in 'wdp'.
+     *     Behavior in this case depends on whether WDP_PUT_MODIFY is specified
+     *     in 'put->flags': if it is, the flow will be updated, otherwise the
+     *     operation will fail with EEXIST.  The exact updates depend on the
+     *     remaining flags in 'put->flags':
+     *
+     *       . If WDP_PUT_COUNTERS is set, packet counters, byte counters, TCP
+     *         flags, and IP TOS values are set to 0.
+     *
+     *       . If WDP_PUT_ACTIONS is set, the actions are replaced by the
+     *         'put->n_actions' actions in 'put->actions'.
+     *
+     *       . If WDP_PUT_INSERTED is set, the flow's insertion time is updated
+     *         to the current time.  (Timeouts are relative to a flow's
+     *         insertion time so this affects their interpretation.)
+     *
+     *       . If WDP_PUT_TIMEOUTS is set, the flow's idle and hard timeouts
+     *         are updated from 'put->idle_timeout' and 'put->hard_timeout',
+     *         respectively.
+     *
+     * Returns 0 if successful, otherwise a positive errno value.  If
+     * successful:
+     *
+     *   - If 'old_stats' is nonnull, then 'old_stats' is filled with the
+     *     flow's stats as they existed just before the update, or it is zeroed
+     *     if the flow is newly created.
+     *
+     *   - If 'rulep' is nonnull, then it is set to the newly created rule.
+     *
+     * Some error return values have specific meanings:
+     *
+     *   - ENOENT: Flow does not exist and WDP_PUT_CREATE not specified.
+     *
+     *   - EEXIST: Flow exists and WDP_PUT_MODIFY not specified.
+     *
+     *   - ENOBUFS: Flow table full.
+     *
+     *   - EINVAL: Flow table cannot accept flow of this form.
+     */
+    int (*flow_put)(struct wdp *wdp, const struct wdp_flow_put *put,
+                    struct wdp_flow_stats *old_stats,
+                    struct wdp_rule **rulep);
+
+    /* Deletes 'rule' from 'wdp'.  Returns 0 if successful, otherwise a
+     * positive errno value.
+     *
+     * If successful and 'final_stats' is non-null, stores the flow's
+     * statistics just before it is deleted into '*final_stats'. */
+    int (*flow_delete)(struct wdp *wdp, struct wdp_rule *rule,
+                       struct wdp_flow_stats *final_stats);
+
+    /* Deletes all flows from 'wdp' and clears all of its queues of received
+     * packets. */
+    int (*flow_flush)(struct wdp *wdp);
+
+    /* Performs the actions for 'rule' on the Ethernet frame specified in
+     * 'packet'.  Pretends that the frame was originally received on the port
+     * numbered 'in_port'.  Packets and bytes sent should be credited to
+     * 'rule'. */
+    int (*flow_inject)(struct wdp *wdp, struct wdp_rule *rule,
+                       uint16_t in_port, const struct ofpbuf *packet);
+
+    /* Performs the 'n_actions' actions in 'actions' on the Ethernet frame
+     * specified in 'packet'.  Pretends that the frame was originally received
+     * on the port numbered 'in_port'. */
+    int (*execute)(struct wdp *wdp, uint16_t in_port,
+                   const union ofp_action actions[], int n_actions,
+                   const struct ofpbuf *packet);
+
+    /* Retrieves 'wdp''s "listen mask" into '*listen_mask'.  Each bit set in
+     * '*listen_mask' indicates the 'wdp' will receive messages of the
+     * corresponding WDP_CHAN_* when it calls the recv member function. */
+    int (*recv_get_mask)(const struct wdp *wdp, int *listen_mask);
+
+    /* Sets 'wdp''s "listen mask" to 'listen_mask'.  Each bit set in
+     * 'listen_mask' indicates the 'wdp' will receive messages of the
+     * corresponding WDP_CHAN_* type when it calls the recv member function. */
+    int (*recv_set_mask)(struct wdp *wdp, int listen_mask);
+
+    /* Retrieves 'wdp''s sFlow sampling probability into '*probability'.
+     * Return value is 0 or a positive errno value.  EOPNOTSUPP indicates that
+     * the datapath does not support sFlow, as does a null pointer.
+     *
+     * '*probability' is expressed as the number of packets out of UINT_MAX to
+     * sample, e.g. probability/UINT_MAX is the probability of sampling a given
+     * packet. */
+    int (*get_sflow_probability)(const struct wdp *wdp,
+                                 uint32_t *probability);
+
+    /* Sets 'wdp''s sFlow sampling probability to 'probability'.  Return value
+     * is 0 or a positive errno value.  EOPNOTSUPP indicates that the datapath
+     * does not support sFlow, as does a null pointer.
+     *
+     * 'probability' is expressed as the number of packets out of UINT_MAX to
+     * sample, e.g. probability/UINT_MAX is the probability of sampling a given
+     * packet. */
+    int (*set_sflow_probability)(struct wdp *wdp, uint32_t probability);
+
+    /* Attempts to receive a message from 'wdp'.  If successful, stores the
+     * message into '*packet'.  Only messages of the types selected with the
+     * recv_set_mask member function should be received.
+     *
+     * This function must not block.  If no message is ready to be received
+     * when it is called, it should return EAGAIN without blocking. */
+    int (*recv)(struct wdp *wdp, struct wdp_packet *packet);
+
+    /* Arranges for the poll loop to wake up when 'wdp' has a message queued
+     * to be received with the recv member function. */
+    void (*recv_wait)(struct wdp *wdp);
+};
+
+extern const struct wdp_class wdp_linux_class;
+extern const struct wdp_class wdp_netdev_class;
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* wdp-provider.h */
diff --git a/ofproto/wdp-xflow.c b/ofproto/wdp-xflow.c
new file mode 100644 (file)
index 0000000..3e4edeb
--- /dev/null
@@ -0,0 +1,2285 @@
+/*
+ * Copyright (c) 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.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include "wdp-xflow.h"
+
+#include <errno.h>
+#include <inttypes.h>
+
+#include "coverage.h"
+#include "dhcp.h"
+#include "netdev.h"
+#include "netflow.h"
+#include "ofpbuf.h"
+#include "openflow/nicira-ext.h"
+#include "openflow/openflow.h"
+#include "packets.h"
+#include "poll-loop.h"
+#include "port-array.h"
+#include "shash.h"
+#include "stp.h"
+#include "svec.h"
+#include "timeval.h"
+#include "util.h"
+#include "vconn.h"
+#include "wdp-provider.h"
+#include "xfif.h"
+#include "xflow-util.h"
+#include "xtoxll.h"
+
+#define THIS_MODULE VLM_wdp_xflow
+#include "vlog.h"
+
+static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+\f
+/* Maximum numbers of rules. */
+#define WX_MAX_WILD     65536   /* Wildcarded rules. */
+#define WX_MAX_EXACT    1048576 /* Exact-match rules. */
+
+struct wx {
+    struct list list_node;
+    struct wdp wdp;
+    struct xfif *xfif;
+    struct classifier cls;
+    struct netdev_monitor *netdev_monitor;
+    struct port_array ports;    /* Index is ODP port nr; wdp_port->opp.port_no
+                                 * is OFP port nr. */
+    struct shash port_by_name;
+    bool need_revalidate;
+    long long int next_expiration;
+};
+
+static struct list all_wx = LIST_INITIALIZER(&all_wx);
+
+static int wx_port_init(struct wx *);
+static void wx_port_run(struct wx *);
+static void wx_port_refresh_groups(struct wx *);
+
+enum {
+    WX_GROUP_FLOOD = 0,
+    WX_GROUP_ALL = 1
+};
+
+static struct wx *
+wx_cast(const struct wdp *wdp)
+{
+    return CONTAINER_OF(wdp, struct wx, wdp);
+}
+
+static int
+wx_xlate_actions(struct wx *, const union ofp_action *, size_t n,
+                 const flow_t *flow, const struct ofpbuf *packet,
+                 struct xflow_actions *out, bool *may_set_up_flow);
+\f
+struct wx_rule {
+    struct wdp_rule wr;
+
+    uint64_t packet_count;      /* Number of packets received. */
+    uint64_t byte_count;        /* Number of bytes received. */
+    uint64_t accounted_bytes;   /* Number of bytes passed to account_cb. */
+    long long int used;         /* Last-used time (0 if never used). */
+
+    /* If 'super' is non-NULL, this rule is a subrule, that is, it is an
+     * exact-match rule (having cr.wc.wildcards of 0) generated from the
+     * wildcard rule 'super'.  In this case, 'list' is an element of the
+     * super-rule's list.
+     *
+     * If 'super' is NULL, this rule is a super-rule, and 'list' is the head of
+     * a list of subrules.  A super-rule with no wildcards (where
+     * cr.wc.wildcards is 0) will never have any subrules. */
+    struct wx_rule *super;
+    struct list list;
+
+    /* Datapath actions.
+     *
+     * A super-rule with wildcard fields never has XFLOW actions (since the
+     * datapath only supports exact-match flows). */
+    bool installed;             /* Installed in datapath? */
+    bool may_install;           /* True ordinarily; false if actions must
+                                 * be reassessed for every packet. */
+    int n_xflow_actions;
+    union xflow_action *xflow_actions;
+};
+
+static void wx_rule_destroy(struct wx *, struct wx_rule *);
+static void wx_rule_update_actions(struct wx *, struct wx_rule *);
+static void wx_rule_execute(struct wx *, struct wx_rule *,
+                            struct ofpbuf *packet, const flow_t *);
+static bool wx_rule_make_actions(struct wx *, struct wx_rule *,
+                                 const struct ofpbuf *packet);
+static void wx_rule_install(struct wx *, struct wx_rule *,
+                            struct wx_rule *displaced_rule);
+
+static struct wx_rule *
+wx_rule_cast(const struct cls_rule *cls_rule)
+{
+    return cls_rule ? CONTAINER_OF(cls_rule, struct wx_rule, wr.cr) : NULL;
+}
+
+/* Returns true if 'rule' is merely an implementation detail that should be
+ * hidden from the client. */
+static inline bool
+wx_rule_is_hidden(const struct wx_rule *rule)
+{
+    return rule->super != NULL;
+}
+
+static void
+wx_rule_free(struct wx_rule *rule)
+{
+    wdp_rule_uninit(&rule->wr);
+    free(rule->xflow_actions);
+    free(rule);
+}
+
+static void
+wx_rule_account(struct wx *wx OVS_UNUSED, struct wx_rule *rule OVS_UNUSED,
+                uint64_t extra_bytes OVS_UNUSED)
+{
+    /* XXX call account_cb hook */
+}
+
+static void
+wx_rule_post_uninstall(struct wx *wx, struct wx_rule *rule)
+{
+    struct wx_rule *super = rule->super;
+
+    wx_rule_account(wx, rule, 0);
+
+    /* XXX netflow expiration */
+
+    if (super) {
+        super->packet_count += rule->packet_count;
+        super->byte_count += rule->byte_count;
+
+        /* Reset counters to prevent double counting if the rule ever gets
+         * reinstalled. */
+        rule->packet_count = 0;
+        rule->byte_count = 0;
+        rule->accounted_bytes = 0;
+
+        //XXX netflow_flow_clear(&rule->nf_flow);
+    }
+}
+
+static long long int
+xflow_flow_stats_to_msec(const struct xflow_flow_stats *stats)
+{
+    return (stats->used_sec
+            ? stats->used_sec * 1000 + stats->used_nsec / 1000000
+            : 0);
+}
+
+static void
+wx_rule_update_time(struct wx *wx OVS_UNUSED, struct wx_rule *rule,
+                    const struct xflow_flow_stats *stats)
+{
+    long long int used = xflow_flow_stats_to_msec(stats);
+    if (used > rule->used) {
+        rule->used = used;
+        if (rule->super && used > rule->super->used) {
+            rule->super->used = used;
+        }
+        //XXX netflow_flow_update_time(ofproto->netflow, &rule->nf_flow, used);
+    }
+}
+
+static void
+wx_rule_update_stats(struct wx *wx, struct wx_rule *rule,
+                     const struct xflow_flow_stats *stats)
+{
+    if (stats->n_packets) {
+        wx_rule_update_time(wx, rule, stats);
+        rule->packet_count += stats->n_packets;
+        rule->byte_count += stats->n_bytes;
+        /* XXX netflow_flow_update_flags(&rule->nf_flow, stats->ip_tos,
+           stats->tcp_flags); */
+    }
+}
+
+static void
+wx_rule_uninstall(struct wx *wx, struct wx_rule *rule)
+{
+    assert(!rule->wr.cr.flow.wildcards);
+    if (rule->installed) {
+        struct xflow_flow xflow_flow;
+
+        xflow_key_from_flow(&xflow_flow.key, &rule->wr.cr.flow);
+        xflow_flow.actions = NULL;
+        xflow_flow.n_actions = 0;
+        xflow_flow.flags = 0;
+        if (!xfif_flow_del(wx->xfif, &xflow_flow)) {
+            wx_rule_update_stats(wx, rule, &xflow_flow.stats);
+        }
+        rule->installed = false;
+
+        wx_rule_post_uninstall(wx, rule);
+    }
+}
+
+#if 0
+static bool
+is_controller_rule(struct wx_rule *rule)
+{
+    /* If the only action is send to the controller then don't report
+     * NetFlow expiration messages since it is just part of the control
+     * logic for the network and not real traffic. */
+
+    if (rule && rule->super) {
+        struct wdp_rule *super = &rule->super->wr;
+
+        return super->n_actions == 1 &&
+            super->actions[0].type == htons(OFPAT_OUTPUT) &&
+            super->actions[0].output.port == htons(OFPP_CONTROLLER);
+    }
+
+    return false;
+}
+#endif
+
+static void
+wx_rule_remove(struct wx *wx, struct wx_rule *rule)
+{
+    if (rule->wr.cr.flow.wildcards) {
+        COVERAGE_INC(wx_del_wc_flow);
+        wx->need_revalidate = true;
+    } else {
+        wx_rule_uninstall(wx, rule);
+    }
+    classifier_remove(&wx->cls, &rule->wr.cr);
+    wx_rule_destroy(wx, rule);
+}
+
+static bool
+wx_rule_revalidate(struct wx *wx, struct wx_rule *rule)
+{
+    const flow_t *flow = &rule->wr.cr.flow;
+
+    COVERAGE_INC(wx_rule_revalidate);
+    if (rule->super) {
+        struct wx_rule *super;
+        super = wx_rule_cast(classifier_lookup_wild(&wx->cls, flow));
+        if (!super) {
+            wx_rule_remove(wx, rule);
+            return false;
+        } else if (super != rule->super) {
+            COVERAGE_INC(wx_revalidate_moved);
+            list_remove(&rule->list);
+            list_push_back(&super->list, &rule->list);
+            rule->super = super;
+            rule->wr.hard_timeout = super->wr.hard_timeout;
+            rule->wr.idle_timeout = super->wr.idle_timeout;
+            rule->wr.created = super->wr.created;
+            rule->used = 0;
+        }
+    }
+
+    wx_rule_update_actions(wx, rule);
+    return true;
+}
+
+/* Destroys 'rule'.  If 'rule' is a subrule, also removes it from its
+ * super-rule's list of subrules.  If 'rule' is a super-rule, also iterates
+ * through all of its subrules and revalidates them, destroying any that no
+ * longer has a super-rule (which is probably all of them).
+ *
+ * Before calling this function, the caller must make have removed 'rule' from
+ * the classifier.  If 'rule' is an exact-match rule, the caller is also
+ * responsible for ensuring that it has been uninstalled from the datapath. */
+static void
+wx_rule_destroy(struct wx *wx, struct wx_rule *rule)
+{
+    if (!rule->super) {
+        struct wx_rule *subrule, *next;
+        LIST_FOR_EACH_SAFE (subrule, next, struct wx_rule, list, &rule->list) {
+            wx_rule_revalidate(wx, subrule);
+        }
+    } else {
+        list_remove(&rule->list);
+    }
+    wx_rule_free(rule);
+}
+
+#if 0
+static bool
+wx_rule_has_out_port(const struct wx_rule *rule, uint16_t out_port)
+{
+    const union ofp_action *oa;
+    struct actions_iterator i;
+
+    if (out_port == htons(OFPP_NONE)) {
+        return true;
+    }
+    for (oa = actions_first(&i, rule->wr.actions,
+                            rule->wr.n_actions);
+         oa;
+         oa = actions_next(&i)) {
+        if (oa->type == htons(OFPAT_OUTPUT) && oa->output.port == out_port) {
+            return true;
+        }
+    }
+    return false;
+}
+#endif
+
+/* Caller is responsible for initializing the 'cr' member of the returned
+ * rule. */
+static struct wx_rule *
+wx_rule_create(struct wx_rule *super,
+               const union ofp_action *actions, size_t n_actions,
+               uint16_t idle_timeout, uint16_t hard_timeout)
+{
+    struct wx_rule *rule = xzalloc(sizeof *rule);
+    wdp_rule_init(&rule->wr, actions, n_actions);
+    rule->wr.idle_timeout = idle_timeout;
+    rule->wr.hard_timeout = hard_timeout;
+    rule->used = rule->wr.created;
+    rule->super = super;
+    if (super) {
+        list_push_back(&super->list, &rule->list);
+    } else {
+        list_init(&rule->list);
+    }
+#if 0
+    netflow_flow_clear(&rule->nf_flow);
+    netflow_flow_update_time(ofproto->netflow, &rule->nf_flow, rule->created);
+#endif
+
+    return rule;
+}
+
+/* Executes the actions indicated by 'rule' on 'packet', which is in flow
+ * 'flow' and is considered to have arrived on XFLOW port 'in_port'.
+ *
+ * The flow that 'packet' actually contains does not need to actually match
+ * 'rule'; the actions in 'rule' will be applied to it either way.  Likewise,
+ * the packet and byte counters for 'rule' will be credited for the packet sent
+ * out whether or not the packet actually matches 'rule'.
+ *
+ * If 'rule' is an exact-match rule and 'flow' actually equals the rule's flow,
+ * the caller must already have accurately composed XFLOW actions for it given
+ * 'packet' using rule_make_actions().  If 'rule' is a wildcard rule, or if
+ * 'rule' is an exact-match rule but 'flow' is not the rule's flow, then this
+ * function will compose a set of XFLOW actions based on 'rule''s OpenFlow
+ * actions and apply them to 'packet'. */
+static void
+wx_rule_execute(struct wx *wx, struct wx_rule *rule,
+                struct ofpbuf *packet, const flow_t *flow)
+{
+    const union xflow_action *actions;
+    size_t n_actions;
+    struct xflow_actions a;
+
+    /* Grab or compose the XFLOW actions.
+     *
+     * The special case for an exact-match 'rule' where 'flow' is not the
+     * rule's flow is important to avoid, e.g., sending a packet out its input
+     * port simply because the XFLOW actions were composed for the wrong
+     * scenario. */
+    if (rule->wr.cr.flow.wildcards
+        || !flow_equal(flow, &rule->wr.cr.flow))
+    {
+        struct wx_rule *super = rule->super ? rule->super : rule;
+        if (wx_xlate_actions(wx, super->wr.actions, super->wr.n_actions, flow,
+                             packet, &a, NULL)) {
+            return;
+        }
+        actions = a.actions;
+        n_actions = a.n_actions;
+    } else {
+        actions = rule->xflow_actions;
+        n_actions = rule->n_xflow_actions;
+    }
+
+    /* Execute the XFLOW actions. */
+    if (!xfif_execute(wx->xfif, flow->in_port,
+                      actions, n_actions, packet)) {
+        struct xflow_flow_stats stats;
+        flow_extract_stats(flow, packet, &stats);
+        wx_rule_update_stats(wx, rule, &stats);
+        rule->used = time_msec();
+        //XXX netflow_flow_update_time(wx->netflow, &rule->nf_flow, rule->used);
+    }
+}
+
+static void
+wx_rule_insert(struct wx *wx, struct wx_rule *rule, struct ofpbuf *packet,
+               uint16_t in_port)
+{
+    struct wx_rule *displaced_rule;
+
+    /* Insert the rule in the classifier. */
+    displaced_rule = wx_rule_cast(classifier_insert(&wx->cls, &rule->wr.cr));
+    if (!rule->wr.cr.flow.wildcards) {
+        wx_rule_make_actions(wx, rule, packet);
+    }
+
+    /* Send the packet and credit it to the rule. */
+    if (packet) {
+        flow_t flow;
+        flow_extract(packet, 0, in_port, &flow);
+        wx_rule_execute(wx, rule, packet, &flow);
+    }
+
+    /* Install the rule in the datapath only after sending the packet, to
+     * avoid packet reordering.  */
+    if (rule->wr.cr.flow.wildcards) {
+        COVERAGE_INC(wx_add_wc_flow);
+        wx->need_revalidate = true;
+    } else {
+        wx_rule_install(wx, rule, displaced_rule);
+    }
+
+    /* Free the rule that was displaced, if any. */
+    if (displaced_rule) {
+        rule->wr.client_data = displaced_rule->wr.client_data;
+        wx_rule_destroy(wx, displaced_rule);
+    }
+}
+
+static struct wx_rule *
+wx_rule_create_subrule(struct wx *wx, struct wx_rule *rule, const flow_t *flow)
+{
+    struct wx_rule *subrule;
+
+    subrule = wx_rule_create(rule, NULL, 0,
+                             rule->wr.idle_timeout,
+                             rule->wr.hard_timeout);
+    COVERAGE_INC(wx_subrule_create);
+    cls_rule_from_flow(flow, &subrule->wr.cr);
+    classifier_insert_exact(&wx->cls, &subrule->wr.cr);
+
+    return subrule;
+}
+
+/* Returns true if the actions changed, false otherwise. */
+static bool
+wx_rule_make_actions(struct wx *wx, struct wx_rule *rule,
+                     const struct ofpbuf *packet)
+{
+    const struct wx_rule *super;
+    struct xflow_actions a;
+    size_t actions_len;
+
+    assert(!rule->wr.cr.flow.wildcards);
+
+    super = rule->super ? rule->super : rule;
+    wx_xlate_actions(wx, super->wr.actions, super->wr.n_actions,
+                     &rule->wr.cr.flow, packet, &a, &rule->may_install);
+
+    actions_len = a.n_actions * sizeof *a.actions;
+    if (rule->n_xflow_actions != a.n_actions
+        || memcmp(rule->xflow_actions, a.actions, actions_len)) {
+        COVERAGE_INC(wx_xflow_unchanged);
+        free(rule->xflow_actions);
+        rule->n_xflow_actions = a.n_actions;
+        rule->xflow_actions = xmemdup(a.actions, actions_len);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static int
+do_put_flow(struct wx *wx, struct wx_rule *rule, int flags,
+            struct xflow_flow_put *put)
+{
+    memset(&put->flow.stats, 0, sizeof put->flow.stats);
+    xflow_key_from_flow(&put->flow.key, &rule->wr.cr.flow);
+    put->flow.actions = rule->xflow_actions;
+    put->flow.n_actions = rule->n_xflow_actions;
+    put->flow.flags = 0;
+    put->flags = flags;
+    return xfif_flow_put(wx->xfif, put);
+}
+
+static void
+wx_rule_install(struct wx *wx, struct wx_rule *rule, struct wx_rule *displaced_rule)
+{
+    assert(!rule->wr.cr.flow.wildcards);
+
+    if (rule->may_install) {
+        struct xflow_flow_put put;
+        if (!do_put_flow(wx, rule,
+                         XFLOWPF_CREATE | XFLOWPF_MODIFY | XFLOWPF_ZERO_STATS,
+                         &put)) {
+            rule->installed = true;
+            if (displaced_rule) {
+                wx_rule_update_stats(wx, displaced_rule, &put.flow.stats);
+                wx_rule_post_uninstall(wx, displaced_rule);
+            }
+        }
+    } else if (displaced_rule) {
+        wx_rule_uninstall(wx, displaced_rule);
+    }
+}
+
+static void
+wx_rule_reinstall(struct wx *wx, struct wx_rule *rule)
+{
+    if (rule->installed) {
+        struct xflow_flow_put put;
+        COVERAGE_INC(wx_dp_missed);
+        do_put_flow(wx, rule, XFLOWPF_CREATE | XFLOWPF_MODIFY, &put);
+    } else {
+        wx_rule_install(wx, rule, NULL);
+    }
+}
+
+static void
+wx_rule_update_actions(struct wx *wx, struct wx_rule *rule)
+{
+    bool actions_changed;
+#if 0
+    uint16_t new_out_iface, old_out_iface;
+
+    old_out_iface = rule->nf_flow.output_iface;
+#endif
+    actions_changed = wx_rule_make_actions(wx, rule, NULL);
+
+    if (rule->may_install) {
+        if (rule->installed) {
+            if (actions_changed) {
+                struct xflow_flow_put put;
+                do_put_flow(wx, rule, XFLOWPF_CREATE | XFLOWPF_MODIFY
+                            | XFLOWPF_ZERO_STATS, &put);
+                wx_rule_update_stats(wx, rule, &put.flow.stats);
+#if 0
+                /* Temporarily set the old output iface so that NetFlow
+                 * messages have the correct output interface for the old
+                 * stats. */
+                new_out_iface = rule->nf_flow.output_iface;
+                rule->nf_flow.output_iface = old_out_iface;
+#endif
+                wx_rule_post_uninstall(wx, rule);
+                //rule->nf_flow.output_iface = new_out_iface;
+            }
+        } else {
+            wx_rule_install(wx, rule, NULL);
+        }
+    } else {
+        wx_rule_uninstall(wx, rule);
+    }
+}
+\f
+static void
+add_output_group_action(struct xflow_actions *actions, uint16_t group,
+                        uint16_t *nf_output_iface)
+{
+    xflow_actions_add(actions, XFLOWAT_OUTPUT_GROUP)->output_group.group = group;
+
+    if (group == WX_GROUP_ALL || group == WX_GROUP_FLOOD) {
+        *nf_output_iface = NF_OUT_FLOOD;
+    }
+}
+
+static void
+add_controller_action(struct xflow_actions *actions,
+                      const struct ofp_action_output *oao)
+{
+    union xflow_action *a = xflow_actions_add(actions, XFLOWAT_CONTROLLER);
+    a->controller.arg = ntohs(oao->max_len);
+}
+
+struct wx_xlate_ctx {
+    /* Input. */
+    flow_t flow;                /* Flow to which these actions correspond. */
+    int recurse;                /* Recursion level, via xlate_table_action. */
+    struct wx *wx;
+    const struct ofpbuf *packet; /* The packet corresponding to 'flow', or a
+                                  * null pointer if we are revalidating
+                                  * without a packet to refer to. */
+
+    /* Output. */
+    struct xflow_actions *out;    /* Datapath actions. */
+    //tag_type *tags;             /* Tags associated with OFPP_NORMAL actions. */
+    bool may_set_up_flow;       /* True ordinarily; false if the actions must
+                                 * be reassessed for every packet. */
+    uint16_t nf_output_iface;   /* Output interface index for NetFlow. */
+};
+
+static void do_xlate_actions(const union ofp_action *in, size_t n_in,
+                             struct wx_xlate_ctx *ctx);
+
+static void
+add_output_action(struct wx_xlate_ctx *ctx, uint16_t port)
+{
+    const struct wdp_port *wdp_port = port_array_get(&ctx->wx->ports, port);
+
+    if (wdp_port) {
+        if (wdp_port->opp.config & OFPPC_NO_FWD) {
+            /* Forwarding disabled on port. */
+            return;
+        }
+    } else {
+        /*
+         * We don't have an ofport record for this port, but it doesn't hurt to
+         * allow forwarding to it anyhow.  Maybe such a port will appear later
+         * and we're pre-populating the flow table.
+         */
+    }
+
+    xflow_actions_add(ctx->out, XFLOWAT_OUTPUT)->output.port = port;
+    //ctx->nf_output_iface = port;
+}
+
+static struct wx_rule *
+wx_rule_lookup_valid(struct wx *wx, const flow_t *flow)
+{
+    struct wx_rule *rule = wx_rule_cast(classifier_lookup(&wx->cls, flow));
+
+    /* The rule we found might not be valid, since we could be in need of
+     * revalidation.  If it is not valid, don't return it. */
+    if (rule
+        && rule->super
+        && wx->need_revalidate
+        && !wx_rule_revalidate(wx, rule)) {
+        COVERAGE_INC(wx_invalidated);
+        return NULL;
+    }
+
+    return rule;
+}
+
+static void
+xlate_table_action(struct wx_xlate_ctx *ctx, uint16_t in_port)
+{
+    if (!ctx->recurse) {
+        uint16_t old_in_port;
+        struct wx_rule *rule;
+
+        /* Look up a flow with 'in_port' as the input port.  Then restore the
+         * original input port (otherwise OFPP_NORMAL and OFPP_IN_PORT will
+         * have surprising behavior). */
+        old_in_port = ctx->flow.in_port;
+        ctx->flow.in_port = in_port;
+        rule = wx_rule_lookup_valid(ctx->wx, &ctx->flow);
+        ctx->flow.in_port = old_in_port;
+
+        if (rule) {
+            if (rule->super) {
+                rule = rule->super;
+            }
+
+            ctx->recurse++;
+            do_xlate_actions(rule->wr.actions, rule->wr.n_actions, ctx);
+            ctx->recurse--;
+        }
+    }
+}
+
+static void
+xlate_output_action(struct wx_xlate_ctx *ctx,
+                    const struct ofp_action_output *oao)
+{
+    uint16_t xflow_port;
+    uint16_t prev_nf_output_iface = ctx->nf_output_iface;
+
+    ctx->nf_output_iface = NF_OUT_DROP;
+
+    switch (ntohs(oao->port)) {
+    case OFPP_IN_PORT:
+        add_output_action(ctx, ctx->flow.in_port);
+        break;
+    case OFPP_TABLE:
+        xlate_table_action(ctx, ctx->flow.in_port);
+        break;
+    case OFPP_NORMAL:
+#if 0
+        if (!ctx->wx->ofhooks->normal_cb(ctx->flow, ctx->packet,
+                                         ctx->out, ctx->tags,
+                                         &ctx->nf_output_iface,
+                                         ctx->wx->aux)) {
+            COVERAGE_INC(wx_uninstallable);
+            ctx->may_set_up_flow = false;
+        }
+        break;
+#else
+        /* fall through to flood for now */
+#endif
+    case OFPP_FLOOD:
+        add_output_group_action(ctx->out, WX_GROUP_FLOOD,
+                                &ctx->nf_output_iface);
+        break;
+    case OFPP_ALL:
+        add_output_group_action(ctx->out, WX_GROUP_ALL, &ctx->nf_output_iface);
+        break;
+    case OFPP_CONTROLLER:
+        add_controller_action(ctx->out, oao);
+        break;
+    case OFPP_LOCAL:
+        add_output_action(ctx, XFLOWP_LOCAL);
+        break;
+    default:
+        xflow_port = ofp_port_to_xflow_port(ntohs(oao->port));
+        if (xflow_port != ctx->flow.in_port) {
+            add_output_action(ctx, xflow_port);
+        }
+        break;
+    }
+
+    if (prev_nf_output_iface == NF_OUT_FLOOD) {
+        ctx->nf_output_iface = NF_OUT_FLOOD;
+    } else if (ctx->nf_output_iface == NF_OUT_DROP) {
+        ctx->nf_output_iface = prev_nf_output_iface;
+    } else if (prev_nf_output_iface != NF_OUT_DROP &&
+               ctx->nf_output_iface != NF_OUT_FLOOD) {
+        ctx->nf_output_iface = NF_OUT_MULTI;
+    }
+}
+
+static void
+xlate_nicira_action(struct wx_xlate_ctx *ctx,
+                    const struct nx_action_header *nah)
+{
+    const struct nx_action_resubmit *nar;
+    const struct nx_action_set_tunnel *nast;
+    union xflow_action *oa;
+    int subtype = ntohs(nah->subtype);
+
+    assert(nah->vendor == htonl(NX_VENDOR_ID));
+    switch (subtype) {
+    case NXAST_RESUBMIT:
+        nar = (const struct nx_action_resubmit *) nah;
+        xlate_table_action(ctx, ofp_port_to_xflow_port(ntohs(nar->in_port)));
+        break;
+
+    case NXAST_SET_TUNNEL:
+        nast = (const struct nx_action_set_tunnel *) nah;
+        oa = xflow_actions_add(ctx->out, XFLOWAT_SET_TUNNEL);
+        ctx->flow.tun_id = oa->tunnel.tun_id = nast->tun_id;
+        break;
+
+    /* If you add a new action here that modifies flow data, don't forget to
+     * update the flow key in ctx->flow in the same key. */
+
+    default:
+        VLOG_DBG_RL(&rl, "unknown Nicira action type %"PRIu16, subtype);
+        break;
+    }
+}
+
+static void
+do_xlate_actions(const union ofp_action *in, size_t n_in,
+                 struct wx_xlate_ctx *ctx)
+{
+    struct actions_iterator iter;
+    const union ofp_action *ia;
+    const struct wdp_port *port;
+
+    port = port_array_get(&ctx->wx->ports, ctx->flow.in_port);
+    if (port && port->opp.config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) &&
+        port->opp.config & (eth_addr_equals(ctx->flow.dl_dst, stp_eth_addr)
+                            ? OFPPC_NO_RECV_STP : OFPPC_NO_RECV)) {
+        /* Drop this flow. */
+        return;
+    }
+
+    for (ia = actions_first(&iter, in, n_in); ia; ia = actions_next(&iter)) {
+        uint16_t type = ntohs(ia->type);
+        union xflow_action *oa;
+
+        switch (type) {
+        case OFPAT_OUTPUT:
+            xlate_output_action(ctx, &ia->output);
+            break;
+
+        case OFPAT_SET_VLAN_VID:
+            oa = xflow_actions_add(ctx->out, XFLOWAT_SET_DL_TCI);
+            oa->dl_tci.tci = ia->vlan_vid.vlan_vid & htons(VLAN_VID_MASK);
+            oa->dl_tci.mask = htons(VLAN_VID_MASK);
+            ctx->flow.dl_vlan = ia->vlan_vid.vlan_vid;
+            break;
+
+        case OFPAT_SET_VLAN_PCP:
+            oa = xflow_actions_add(ctx->out, XFLOWAT_SET_DL_TCI);
+            oa->dl_tci.tci = htons((ia->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT)
+                                   & VLAN_PCP_MASK);
+            oa->dl_tci.mask = htons(VLAN_PCP_MASK);
+
+            if (ctx->flow.dl_vlan == htons(OFP_VLAN_NONE)) {
+                ctx->flow.dl_vlan = htons(0);
+            }
+            ctx->flow.dl_vlan_pcp = ia->vlan_pcp.vlan_pcp;
+            break;
+
+        case OFPAT_STRIP_VLAN:
+            xflow_actions_add(ctx->out, XFLOWAT_STRIP_VLAN);
+            ctx->flow.dl_vlan = htons(OFP_VLAN_NONE);
+            ctx->flow.dl_vlan_pcp = 0;
+            break;
+
+        case OFPAT_SET_DL_SRC:
+            oa = xflow_actions_add(ctx->out, XFLOWAT_SET_DL_SRC);
+            memcpy(oa->dl_addr.dl_addr,
+                   ((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
+            memcpy(ctx->flow.dl_src,
+                   ((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
+            break;
+
+        case OFPAT_SET_DL_DST:
+            oa = xflow_actions_add(ctx->out, XFLOWAT_SET_DL_DST);
+            memcpy(oa->dl_addr.dl_addr,
+                   ((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
+            memcpy(ctx->flow.dl_dst,
+                   ((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
+            break;
+
+        case OFPAT_SET_NW_SRC:
+            oa = xflow_actions_add(ctx->out, XFLOWAT_SET_NW_SRC);
+            ctx->flow.nw_src = oa->nw_addr.nw_addr = ia->nw_addr.nw_addr;
+            break;
+
+        case OFPAT_SET_NW_DST:
+            oa = xflow_actions_add(ctx->out, XFLOWAT_SET_NW_DST);
+            ctx->flow.nw_dst = oa->nw_addr.nw_addr = ia->nw_addr.nw_addr;
+            break;
+
+        case OFPAT_SET_NW_TOS:
+            oa = xflow_actions_add(ctx->out, XFLOWAT_SET_NW_TOS);
+            ctx->flow.nw_tos = oa->nw_tos.nw_tos = ia->nw_tos.nw_tos;
+            break;
+
+        case OFPAT_SET_TP_SRC:
+            oa = xflow_actions_add(ctx->out, XFLOWAT_SET_TP_SRC);
+            ctx->flow.tp_src = oa->tp_port.tp_port = ia->tp_port.tp_port;
+            break;
+
+        case OFPAT_SET_TP_DST:
+            oa = xflow_actions_add(ctx->out, XFLOWAT_SET_TP_DST);
+            ctx->flow.tp_dst = oa->tp_port.tp_port = ia->tp_port.tp_port;
+            break;
+
+        case OFPAT_VENDOR:
+            xlate_nicira_action(ctx, (const struct nx_action_header *) ia);
+            break;
+
+        default:
+            VLOG_DBG_RL(&rl, "unknown action type %"PRIu16, type);
+            break;
+        }
+    }
+}
+
+/* Returns true if 'flow' and 'actions' may be set up as a flow in the kernel.
+ * This is true most of the time, but we don't allow flows that would prevent
+ * DHCP replies from being seen by the local port to be set up in the
+ * kernel.
+ *
+ * We only need this, strictly speaking, when in-band control is turned on. */
+static bool
+wx_may_set_up(const flow_t *flow, const struct xflow_actions *actions)
+{
+    if (flow->dl_type == htons(ETH_TYPE_IP)
+        && flow->nw_proto == IP_TYPE_UDP
+        && flow->tp_src == htons(DHCP_SERVER_PORT)
+        && flow->tp_dst == htons(DHCP_CLIENT_PORT)) {
+        int i;
+
+        for (i = 0; i < actions->n_actions; i++) {
+            const struct xflow_action_output *oao = &actions->actions[i].output;
+            if (oao->type == XFLOWAT_OUTPUT && oao->port == XFLOWP_LOCAL) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    return true;
+}
+
+static int
+wx_xlate_actions(struct wx *wx, const union ofp_action *in, size_t n_in,
+                 const flow_t *flow, const struct ofpbuf *packet,
+                 struct xflow_actions *out, bool *may_set_up_flow)
+{
+    //tag_type no_tags = 0;
+    struct wx_xlate_ctx ctx;
+    COVERAGE_INC(wx_ofp2xflow);
+    xflow_actions_init(out);
+    ctx.flow = *flow;
+    ctx.recurse = 0;
+    ctx.wx = wx;
+    ctx.packet = packet;
+    ctx.out = out;
+    //ctx.tags = tags ? tags : &no_tags;
+    ctx.may_set_up_flow = true;
+    ctx.nf_output_iface = NF_OUT_DROP;
+    do_xlate_actions(in, n_in, &ctx);
+
+    if (may_set_up_flow) {
+        *may_set_up_flow = ctx.may_set_up_flow && wx_may_set_up(flow, out);
+    }
+#if 0
+    if (nf_output_iface) {
+        *nf_output_iface = ctx.nf_output_iface;
+    }
+#endif
+    if (xflow_actions_overflow(out)) {
+        xflow_actions_init(out);
+        return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_TOO_MANY);
+    }
+    return 0;
+}
+\f
+static void
+update_used(struct wx *wx)
+{
+    struct xflow_flow *flows;
+    size_t n_flows;
+    size_t i;
+    int error;
+
+    error = xfif_flow_list_all(wx->xfif, &flows, &n_flows);
+    if (error) {
+        return;
+    }
+
+    for (i = 0; i < n_flows; i++) {
+        struct xflow_flow *f = &flows[i];
+        struct wx_rule *rule;
+        flow_t flow;
+
+        xflow_key_to_flow(&f->key, &flow);
+        rule = wx_rule_cast(classifier_find_rule_exactly(&wx->cls, &flow));
+        if (!rule || !rule->installed) {
+            COVERAGE_INC(wx_unexpected_rule);
+            xfif_flow_del(wx->xfif, f);
+            continue;
+        }
+
+        wx_rule_update_time(wx, rule, &f->stats);
+        wx_rule_account(wx, rule, f->stats.n_bytes);
+    }
+    free(flows);
+}
+
+static void
+uninstall_idle_flow(struct wx *wx, struct wx_rule *rule)
+{
+    assert(rule->installed);
+    assert(!rule->wr.cr.flow.wildcards);
+
+    if (rule->super) {
+        wx_rule_remove(wx, rule);
+    } else {
+        wx_rule_uninstall(wx, rule);
+    }
+}
+
+static void
+expire_rule(struct cls_rule *cls_rule, void *wx_)
+{
+    struct wx *wx = wx_;
+    struct wx_rule *rule = wx_rule_cast(cls_rule);
+    long long int hard_expire, idle_expire, expire, now;
+
+    hard_expire = (rule->wr.hard_timeout
+                   ? rule->wr.created + rule->wr.hard_timeout * 1000
+                   : LLONG_MAX);
+    idle_expire = (rule->wr.idle_timeout
+                   && (rule->super || list_is_empty(&rule->list))
+                   ? rule->used + rule->wr.idle_timeout * 1000
+                   : LLONG_MAX);
+    expire = MIN(hard_expire, idle_expire);
+
+    now = time_msec();
+    if (now < expire) {
+        if (rule->installed && now >= rule->used + 5000) {
+            uninstall_idle_flow(wx, rule);
+        } else if (!rule->wr.cr.flow.wildcards) {
+            //XXX active_timeout(wx, rule);
+        }
+
+        return;
+    }
+
+    COVERAGE_INC(wx_expired);
+
+    /* Update stats.  This code will be a no-op if the rule expired
+     * due to an idle timeout. */
+    if (rule->wr.cr.flow.wildcards) {
+        struct wx_rule *subrule, *next;
+        LIST_FOR_EACH_SAFE (subrule, next, struct wx_rule, list, &rule->list) {
+            wx_rule_remove(wx, subrule);
+        }
+    } else {
+        wx_rule_uninstall(wx, rule);
+    }
+
+#if 0                           /* XXX */
+    if (!wx_rule_is_hidden(rule)) {
+        send_flow_removed(wx, rule, now,
+                          (now >= hard_expire
+                           ? OFPRR_HARD_TIMEOUT : OFPRR_IDLE_TIMEOUT));
+    }
+#endif
+    wx_rule_remove(wx, rule);
+}
+
+struct revalidate_cbdata {
+    struct wx *wx;
+    bool revalidate_all;        /* Revalidate all exact-match rules? */
+    bool revalidate_subrules;   /* Revalidate all exact-match subrules? */
+    //struct tag_set revalidate_set; /* Set of tags to revalidate. */
+};
+
+static bool
+revalidate_rule(struct wx *wx, struct wx_rule *rule)
+{
+    const flow_t *flow = &rule->wr.cr.flow;
+
+    COVERAGE_INC(wx_revalidate_rule);
+    if (rule->super) {
+        struct wx_rule *super;
+        super = wx_rule_cast(classifier_lookup_wild(&wx->cls, flow));
+        if (!super) {
+            wx_rule_remove(wx, rule);
+            return false;
+        } else if (super != rule->super) {
+            COVERAGE_INC(wx_revalidate_moved);
+            list_remove(&rule->list);
+            list_push_back(&super->list, &rule->list);
+            rule->super = super;
+            rule->wr.hard_timeout = super->wr.hard_timeout;
+            rule->wr.idle_timeout = super->wr.idle_timeout;
+            rule->wr.created = super->wr.created;
+            rule->used = 0;
+        }
+    }
+
+    wx_rule_update_actions(wx, rule);
+    return true;
+}
+
+static void
+revalidate_cb(struct cls_rule *sub_, void *cbdata_)
+{
+    struct wx_rule *sub = wx_rule_cast(sub_);
+    struct revalidate_cbdata *cbdata = cbdata_;
+
+    if (cbdata->revalidate_all
+        || (cbdata->revalidate_subrules && sub->super)
+        /*|| (tag_set_intersects(&cbdata->revalidate_set, sub->tags))*/) {
+        revalidate_rule(cbdata->wx, sub);
+    }
+}
+
+static void
+wx_run_one(struct wx *wx)
+{
+    wx_port_run(wx);
+
+    if (time_msec() >= wx->next_expiration) {
+        COVERAGE_INC(wx_expiration);
+        wx->next_expiration = time_msec() + 1000;
+        update_used(wx);
+
+        classifier_for_each(&wx->cls, CLS_INC_ALL, expire_rule, wx);
+
+        /* XXX account_checkpoint_cb */
+    }
+
+    if (wx->need_revalidate /*|| !tag_set_is_empty(&p->revalidate_set)*/) {
+        struct revalidate_cbdata cbdata;
+        cbdata.wx = wx;
+        cbdata.revalidate_all = false;
+        cbdata.revalidate_subrules = wx->need_revalidate;
+        //cbdata.revalidate_set = wx->revalidate_set;
+        //tag_set_init(&wx->revalidate_set);
+        COVERAGE_INC(wx_revalidate);
+        classifier_for_each(&wx->cls, CLS_INC_EXACT, revalidate_cb, &cbdata);
+        wx->need_revalidate = false;
+    }
+}
+
+static void
+wx_run(void)
+{
+    struct wx *wx;
+
+    LIST_FOR_EACH (wx, struct wx, list_node, &all_wx) {
+        wx_run_one(wx);
+    }
+    xf_run();
+}
+
+static void
+wx_wait_one(struct wx *wx)
+{
+    xfif_port_poll_wait(wx->xfif);
+    netdev_monitor_poll_wait(wx->netdev_monitor);
+    if (wx->need_revalidate /*|| !tag_set_is_empty(&p->revalidate_set)*/) {
+        poll_immediate_wake();
+    } else if (wx->next_expiration != LLONG_MAX) {
+        poll_timer_wait(wx->next_expiration - time_msec());
+    }
+}
+
+static void
+wx_wait(void)
+{
+    struct wx *wx;
+
+    LIST_FOR_EACH (wx, struct wx, list_node, &all_wx) {
+        wx_wait_one(wx);
+    }
+    xf_wait();
+}
+\f
+static int wx_flow_flush(struct wdp *);
+
+static int
+wx_enumerate(const struct wdp_class *wdp_class, struct svec *all_wdps)
+{
+    struct svec names = SVEC_EMPTY_INITIALIZER;
+    int error = xf_enumerate_names(wdp_class->type, &names);
+    svec_move(all_wdps, &names);
+    return error;
+}
+
+static int
+wx_open(const struct wdp_class *wdp_class, const char *name, bool create,
+        struct wdp **wdpp)
+{
+    struct xfif *xfif;
+    int error;
+
+    error = (create
+             ? xfif_create_and_open(name, wdp_class->type, &xfif)
+             : xfif_open(name, wdp_class->type, &xfif));
+    if (!error) {
+        struct wx *wx;
+
+        wx = xzalloc(sizeof *wx);
+        list_push_back(&all_wx, &wx->list_node);
+        wdp_init(&wx->wdp, wdp_class, name, 0, 0);
+        wx->xfif = xfif;
+        classifier_init(&wx->cls);
+        wx->netdev_monitor = netdev_monitor_create();
+        port_array_init(&wx->ports);
+        shash_init(&wx->port_by_name);
+        wx->next_expiration = time_msec() + 1000;
+
+        wx_port_init(wx);
+
+        *wdpp = &wx->wdp;
+    }
+
+    return error;
+}
+
+static void
+wx_close(struct wdp *wdp)
+{
+    struct wx *wx = wx_cast(wdp);
+
+    wx_flow_flush(wdp);
+    xfif_close(wx->xfif);
+    classifier_destroy(&wx->cls);
+    netdev_monitor_destroy(wx->netdev_monitor);
+    list_remove(&wx->list_node);
+    free(wx);
+}
+
+static int
+wx_get_all_names(const struct wdp *wdp, struct svec *all_names)
+{
+    struct wx *wx = wx_cast(wdp);
+
+    return xfif_get_all_names(wx->xfif, all_names);
+}
+
+static int
+wx_destroy(struct wdp *wdp)
+{
+    struct wx *wx = wx_cast(wdp);
+
+    return xfif_delete(wx->xfif);
+}
+
+static void
+hton_ofp_phy_port(struct ofp_phy_port *opp)
+{
+    opp->port_no = htons(opp->port_no);
+    opp->config = htonl(opp->config);
+    opp->state = htonl(opp->state);
+    opp->curr = htonl(opp->curr);
+    opp->advertised = htonl(opp->advertised);
+    opp->supported = htonl(opp->supported);
+    opp->peer = htonl(opp->peer);
+}
+
+static int
+wx_get_features(const struct wdp *wdp, struct ofpbuf **featuresp)
+{
+    struct wx *wx = wx_cast(wdp);
+    struct ofp_switch_features *osf;
+    struct ofpbuf *buf;
+    unsigned int port_no;
+    struct wdp_port *port;
+
+    buf = ofpbuf_new(sizeof *osf);
+    osf = ofpbuf_put_zeros(buf, sizeof *osf);
+    osf->n_tables = 2;
+    osf->capabilities = htonl(OFPC_ARP_MATCH_IP);
+    osf->actions = htonl((1u << OFPAT_OUTPUT) |
+                         (1u << OFPAT_SET_VLAN_VID) |
+                         (1u << OFPAT_SET_VLAN_PCP) |
+                         (1u << OFPAT_STRIP_VLAN) |
+                         (1u << OFPAT_SET_DL_SRC) |
+                         (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));
+
+    PORT_ARRAY_FOR_EACH (port, &wx->ports, port_no) {
+        hton_ofp_phy_port(ofpbuf_put(buf, &port->opp, sizeof port->opp));
+    }
+
+    *featuresp = buf;
+    return 0;
+}
+
+static void
+count_subrules(struct cls_rule *cls_rule, void *n_subrules_)
+{
+    struct wx_rule *rule = wx_rule_cast(cls_rule);
+    int *n_subrules = n_subrules_;
+
+    if (rule->super) {
+        (*n_subrules)++;
+    }
+}
+
+static int
+wx_get_stats(const struct wdp *wdp, struct wdp_stats *stats)
+{
+    struct wx *wx = wx_cast(wdp);
+    struct xflow_stats xflow_stats;
+    int n_subrules;
+    int error;
+
+    error = xfif_get_xf_stats(wx->xfif, &xflow_stats);
+
+    n_subrules = 0;
+    classifier_for_each(&wx->cls, CLS_INC_EXACT, count_subrules, &n_subrules);
+
+    stats->exact.n_flows = classifier_count_exact(&wx->cls) - n_subrules;
+    stats->exact.cur_capacity = xflow_stats.cur_capacity;
+    stats->exact.max_capacity = MIN(WX_MAX_EXACT, xflow_stats.max_capacity);
+    stats->exact.n_hit = xflow_stats.n_hit;
+    stats->exact.n_missed = xflow_stats.n_missed;
+    stats->exact.n_lost = xflow_stats.n_lost;
+
+    stats->wild.n_flows = classifier_count_wild(&wx->cls);
+    stats->wild.cur_capacity = WX_MAX_WILD;
+    stats->wild.max_capacity = WX_MAX_WILD;
+    stats->wild.n_hit = 0;      /* XXX */
+    stats->wild.n_missed = 0;   /* XXX */
+    stats->wild.n_lost = 0;     /* XXX */
+
+    stats->n_ports = xflow_stats.n_ports;
+    stats->max_ports = xflow_stats.max_ports;
+
+    stats->n_frags = xflow_stats.n_frags;
+
+    stats->max_miss_queue = xflow_stats.max_miss_queue;
+    stats->max_action_queue = xflow_stats.max_action_queue;
+    stats->max_sflow_queue = xflow_stats.max_sflow_queue;
+
+    return error;
+}
+
+static int
+wx_get_drop_frags(const struct wdp *wdp, bool *drop_frags)
+{
+    struct wx *wx = wx_cast(wdp);
+
+    return xfif_get_drop_frags(wx->xfif, drop_frags);
+}
+
+static int
+wx_set_drop_frags(struct wdp *wdp, bool drop_frags)
+{
+    struct wx *wx = wx_cast(wdp);
+
+    return xfif_set_drop_frags(wx->xfif, drop_frags);
+}
+
+static int
+wx_port_add(struct wdp *wdp, const char *devname,
+            bool internal, uint16_t *port_no)
+{
+    struct wx *wx = wx_cast(wdp);
+    uint16_t xflow_flags = internal ? XFLOW_PORT_INTERNAL : 0;
+    return xfif_port_add(wx->xfif, devname, xflow_flags, port_no);
+}
+
+static int
+wx_port_del(struct wdp *wdp, uint16_t port_no)
+{
+    struct wx *wx = wx_cast(wdp);
+
+    return xfif_port_del(wx->xfif, port_no);
+}
+
+static int
+wx_answer_port_query(const struct wdp_port *port, struct wdp_port *portp)
+{
+    if (port) {
+        wdp_port_copy(portp, port);
+        return 0;
+    } else {
+        return ENOENT;
+    }
+}
+
+static int
+wx_port_query_by_number(const struct wdp *wdp, uint16_t port_no,
+                        struct wdp_port *portp)
+{
+    struct wx *wx = wx_cast(wdp);
+    const struct wdp_port *port;
+
+    port = port_array_get(&wx->ports, ofp_port_to_xflow_port(port_no));
+    return wx_answer_port_query(port, portp);
+}
+
+static int
+wx_port_query_by_name(const struct wdp *wdp, const char *devname,
+                      struct wdp_port *portp)
+{
+    struct wx *wx = wx_cast(wdp);
+
+    return wx_answer_port_query(shash_find_data(&wx->port_by_name, devname),
+                                portp);
+}
+
+static int
+wx_port_set_config(struct wdp *wdp, uint16_t port_no, uint32_t config)
+{
+    struct wx *wx = wx_cast(wdp);
+    struct wdp_port *port;
+    uint32_t changes;
+
+    port = port_array_get(&wx->ports, ofp_port_to_xflow_port(port_no));
+    if (!port) {
+        return ENOENT;
+    }
+    changes = config ^ port->opp.config;
+
+    if (changes & OFPPC_PORT_DOWN) {
+        int error;
+        if (config & OFPPC_PORT_DOWN) {
+            error = netdev_turn_flags_off(port->netdev, NETDEV_UP, true);
+        } else {
+            error = netdev_turn_flags_on(port->netdev, NETDEV_UP, true);
+        }
+        if (!error) {
+            port->opp.config ^= OFPPC_PORT_DOWN;
+        }
+    }
+
+#define REVALIDATE_BITS (OFPPC_NO_RECV | OFPPC_NO_RECV_STP | OFPPC_NO_FWD)
+    if (changes & REVALIDATE_BITS) {
+        COVERAGE_INC(wx_costly_flags);
+        port->opp.config ^= changes & REVALIDATE_BITS;
+        wx->need_revalidate = true;
+    }
+#undef REVALIDATE_BITS
+
+    if (changes & OFPPC_NO_FLOOD) {
+        port->opp.config ^= OFPPC_NO_FLOOD;
+        wx_port_refresh_groups(wx);
+    }
+
+    if (changes & OFPPC_NO_PACKET_IN) {
+        port->opp.config ^= OFPPC_NO_PACKET_IN;
+    }
+
+    return 0;
+}
+
+static int
+wx_port_list(const struct wdp *wdp, struct wdp_port **portsp, size_t *n_portsp)
+{
+    struct wx *wx = wx_cast(wdp);
+    struct wdp_port *ports, *port;
+    unsigned int port_no;
+    size_t n_ports, i;
+
+    *n_portsp = n_ports = port_array_count(&wx->ports);
+    *portsp = ports = xmalloc(n_ports * sizeof *ports);
+    i = 0;
+    PORT_ARRAY_FOR_EACH (port, &wx->ports, port_no) {
+        wdp_port_copy(&ports[i++], port);
+    }
+    assert(i == n_ports);
+
+    return 0;
+}
+
+static int
+wx_port_poll(const struct wdp *wdp, char **devnamep)
+{
+    struct wx *wx = wx_cast(wdp);
+
+    return xfif_port_poll(wx->xfif, devnamep);
+}
+
+static void
+wx_port_poll_wait(const struct wdp *wdp)
+{
+    struct wx *wx = wx_cast(wdp);
+
+    xfif_port_poll_wait(wx->xfif);
+}
+
+static struct wdp_rule *
+wx_flow_get(const struct wdp *wdp, const flow_t *flow)
+{
+    struct wx *wx = wx_cast(wdp);
+    struct wx_rule *rule;
+
+    rule = wx_rule_cast(classifier_find_rule_exactly(&wx->cls, flow));
+    return rule && !wx_rule_is_hidden(rule) ? &rule->wr : NULL;
+}
+
+static struct wdp_rule *
+wx_flow_match(const struct wdp *wdp, const flow_t *flow)
+{
+    struct wx *wx = wx_cast(wdp);
+    struct wx_rule *rule;
+
+    rule = wx_rule_cast(classifier_lookup(&wx->cls, flow));
+    if (rule) {
+        if (wx_rule_is_hidden(rule)) {
+            rule = rule->super;
+        }
+        return &rule->wr;
+    } else {
+        return NULL;
+    }
+}
+
+struct wx_for_each_thunk_aux {
+    wdp_flow_cb_func *client_callback;
+    void *client_aux;
+};
+
+static void
+wx_for_each_thunk(struct cls_rule *cls_rule, void *aux_)
+{
+    struct wx_for_each_thunk_aux *aux = aux_;
+    struct wx_rule *rule = wx_rule_cast(cls_rule);
+
+    if (!wx_rule_is_hidden(rule)) {
+        aux->client_callback(&rule->wr, aux->client_aux);
+    }
+}
+
+static void
+wx_flow_for_each_match(const struct wdp *wdp, const flow_t *target,
+                       int include,
+                       wdp_flow_cb_func *client_callback, void *client_aux)
+{
+    struct wx *wx = wx_cast(wdp);
+    struct wx_for_each_thunk_aux aux;
+
+    aux.client_callback = client_callback;
+    aux.client_aux = client_aux;
+    classifier_for_each_match(&wx->cls, target, include,
+                              wx_for_each_thunk, &aux);
+}
+
+/* Obtains statistic counters for 'rule' within 'wx' and stores them into
+ * '*stats'.  If 'rule' is a wildcarded rule, the returned statistic include
+ * statistics for all of 'rule''s subrules. */
+static void
+query_stats(struct wx *wx, struct wx_rule *rule, struct wdp_flow_stats *stats)
+{
+    struct wx_rule *subrule;
+    struct xflow_flow *xflow_flows;
+    size_t n_xflow_flows;
+
+    /* Start from historical data for 'rule' itself that are no longer tracked
+     * by the datapath.  This counts, for example, subrules that have
+     * expired. */
+    stats->n_packets = rule->packet_count;
+    stats->n_bytes = rule->byte_count;
+    stats->inserted = rule->wr.created;
+    stats->used = LLONG_MIN;
+    stats->tcp_flags = 0;
+    stats->ip_tos = 0;
+
+    /* Prepare to ask the datapath for statistics on 'rule', or if it is
+     * wildcarded then on all of its subrules.
+     *
+     * Also, add any statistics that are not tracked by the datapath for each
+     * subrule.  This includes, for example, statistics for packets that were
+     * executed "by hand" by ofproto via xfif_execute() but must be accounted
+     * to a flow. */
+    n_xflow_flows = rule->wr.cr.flow.wildcards ? list_size(&rule->list) : 1;
+    xflow_flows = xzalloc(n_xflow_flows * sizeof *xflow_flows);
+    if (rule->wr.cr.flow.wildcards) {
+        size_t i = 0;
+        LIST_FOR_EACH (subrule, struct wx_rule, list, &rule->list) {
+            xflow_key_from_flow(&xflow_flows[i++].key, &subrule->wr.cr.flow);
+            stats->n_packets += subrule->packet_count;
+            stats->n_bytes += subrule->byte_count;
+        }
+    } else {
+        xflow_key_from_flow(&xflow_flows[0].key, &rule->wr.cr.flow);
+    }
+
+    /* Fetch up-to-date statistics from the datapath and add them in. */
+    if (!xfif_flow_get_multiple(wx->xfif, xflow_flows, n_xflow_flows)) {
+        size_t i;
+        for (i = 0; i < n_xflow_flows; i++) {
+            struct xflow_flow *xflow_flow = &xflow_flows[i];
+            long long int used;
+
+            stats->n_packets += xflow_flow->stats.n_packets;
+            stats->n_bytes += xflow_flow->stats.n_bytes;
+            used = xflow_flow_stats_to_msec(&xflow_flow->stats);
+            if (used > stats->used) {
+                stats->used = used;
+                if (xflow_flow->key.dl_type == htons(ETH_TYPE_IP)
+                    && xflow_flow->key.nw_proto == IP_TYPE_TCP) {
+                    stats->ip_tos = xflow_flow->stats.ip_tos;
+                }
+            }
+            stats->tcp_flags |= xflow_flow->stats.tcp_flags;
+        }
+    }
+    free(xflow_flows);
+}
+
+static int
+wx_flow_get_stats(const struct wdp *wdp,
+                  const struct wdp_rule *wdp_rule,
+                  struct wdp_flow_stats *stats)
+{
+    struct wx *wx = wx_cast(wdp);
+    struct wx_rule *rule = wx_rule_cast(&wdp_rule->cr);
+
+    query_stats(wx, rule, stats);
+    return 0;
+}
+
+static bool
+wx_flow_overlaps(const struct wdp *wdp, const flow_t *flow)
+{
+    struct wx *wx = wx_cast(wdp);
+
+    /* XXX overlap with a subrule? */
+    return classifier_rule_overlaps(&wx->cls, flow);
+}
+
+static int
+wx_flow_put(struct wdp *wdp, const struct wdp_flow_put *put,
+            struct wdp_flow_stats *old_stats, struct wdp_rule **rulep)
+{
+    struct wx *wx = wx_cast(wdp);
+    struct wx_rule *rule;
+
+    rule = wx_rule_cast(classifier_find_rule_exactly(&wx->cls, put->flow));
+    if (rule && wx_rule_is_hidden(rule)) {
+        rule = NULL;
+    }
+
+    if (rule) {
+        if (!(put->flags & WDP_PUT_MODIFY)) {
+            return EEXIST;
+        }
+    } else {
+        if (!(put->flags & WDP_PUT_CREATE)) {
+            return EINVAL;
+        }
+        if ((put->flow->wildcards
+             ? classifier_count_wild(&wx->cls) >= WX_MAX_WILD
+             : classifier_count_exact(&wx->cls) >= WX_MAX_EXACT)) {
+            /* XXX subrules should not count against exact-match limit */
+            return ENOBUFS;
+        }
+    }
+
+    rule = wx_rule_create(NULL, put->actions, put->n_actions,
+                          put->idle_timeout, put->hard_timeout);
+    cls_rule_from_flow(put->flow, &rule->wr.cr);
+    wx_rule_insert(wx, rule, NULL, 0);
+
+    if (old_stats) {
+        /* XXX */
+        memset(old_stats, 0, sizeof *old_stats);
+    }
+    if (rulep) {
+        *rulep = &rule->wr;
+    }
+
+    return 0;
+}
+
+static int
+wx_flow_delete(struct wdp *wdp, struct wdp_rule *wdp_rule,
+               struct wdp_flow_stats *final_stats)
+{
+    struct wx *wx = wx_cast(wdp);
+    struct wx_rule *rule = wx_rule_cast(&wdp_rule->cr);
+
+    wx_rule_remove(wx, rule);
+    if (final_stats) {
+        memset(final_stats, 0, sizeof *final_stats); /* XXX */
+    }
+    return 0;
+}
+
+static void
+wx_flush_rule(struct cls_rule *cls_rule, void *wx_)
+{
+    struct wx_rule *rule = wx_rule_cast(cls_rule);
+    struct wx *wx = wx_;
+
+    /* Mark the flow as not installed, even though it might really be
+     * installed, so that wx_rule_remove() doesn't bother trying to uninstall
+     * it.  There is no point in uninstalling it individually since we are
+     * about to blow away all the flows with xfif_flow_flush(). */
+    rule->installed = false;
+
+    wx_rule_remove(wx, rule);
+}
+
+static int
+wx_flow_flush(struct wdp *wdp)
+{
+    struct wx *wx = wx_cast(wdp);
+
+    COVERAGE_INC(wx_flow_flush);
+    classifier_for_each(&wx->cls, CLS_INC_ALL, wx_flush_rule, wx);
+    xfif_flow_flush(wx->xfif);
+    return 0;
+}
+
+static int
+wx_execute(struct wdp *wdp, uint16_t in_port,
+           const union ofp_action actions[], int n_actions,
+           const struct ofpbuf *packet)
+{
+    struct wx *wx = wx_cast(wdp);
+    struct xflow_actions xflow_actions;
+    flow_t flow;
+    int error;
+
+    flow_extract((struct ofpbuf *) packet, 0, in_port, &flow);
+    error = wx_xlate_actions(wx, actions, n_actions, &flow, packet,
+                             &xflow_actions, NULL);
+    if (error) {
+        return error;
+    }
+    xfif_execute(wx->xfif, ofp_port_to_xflow_port(in_port),
+                 xflow_actions.actions, xflow_actions.n_actions, packet);
+    return 0;
+}
+
+static int
+wx_flow_inject(struct wdp *wdp, struct wdp_rule *wdp_rule,
+               uint16_t in_port, const struct ofpbuf *packet)
+{
+    struct wx_rule *rule = wx_rule_cast(&wdp_rule->cr);
+    int error;
+
+    error = wx_execute(wdp, in_port, rule->wr.actions, rule->wr.n_actions,
+                       packet);
+    if (!error) {
+        rule->packet_count++;
+        rule->byte_count += packet->size;
+        rule->used = time_msec();
+    }
+    return error;
+}
+
+static int
+wx_recv_get_mask(const struct wdp *wdp, int *listen_mask)
+{
+    struct wx *wx = wx_cast(wdp);
+    int xflow_listen_mask;
+    int error;
+
+    error = xfif_recv_get_mask(wx->xfif, &xflow_listen_mask);
+    if (!error) {
+        *listen_mask = 0;
+        if (xflow_listen_mask & XFLOWL_MISS) {
+            *listen_mask |= 1 << WDP_CHAN_MISS;
+        }
+        if (xflow_listen_mask & XFLOWL_ACTION) {
+            *listen_mask |= 1 << WDP_CHAN_ACTION;
+        }
+        if (xflow_listen_mask & XFLOWL_SFLOW) {
+            *listen_mask |= 1 << WDP_CHAN_SFLOW;
+        }
+    }
+    return error;
+}
+
+static int
+wx_recv_set_mask(struct wdp *wdp, int listen_mask)
+{
+    struct wx *wx = wx_cast(wdp);
+    int xflow_listen_mask;
+
+    xflow_listen_mask = 0;
+    if (listen_mask & (1 << WDP_CHAN_MISS)) {
+        xflow_listen_mask |= XFLOWL_MISS;
+    }
+    if (listen_mask & (1 << WDP_CHAN_ACTION)) {
+        xflow_listen_mask |= XFLOWL_ACTION;
+    }
+    if (listen_mask & (1 << WDP_CHAN_SFLOW)) {
+        xflow_listen_mask |= XFLOWL_SFLOW;
+    }
+
+    return xfif_recv_set_mask(wx->xfif, xflow_listen_mask);
+}
+
+static int
+wx_get_sflow_probability(const struct wdp *wdp, uint32_t *probability)
+{
+    struct wx *wx = wx_cast(wdp);
+
+    return xfif_get_sflow_probability(wx->xfif, probability);
+}
+
+static int
+wx_set_sflow_probability(struct wdp *wdp, uint32_t probability)
+{
+    struct wx *wx = wx_cast(wdp);
+
+    return xfif_set_sflow_probability(wx->xfif, probability);
+}
+
+static int
+wx_translate_xflow_msg(struct xflow_msg *msg, struct ofpbuf *payload,
+                       struct wdp_packet *packet)
+{
+    packet->in_port = xflow_port_to_ofp_port(msg->port);
+    packet->send_len = 0;
+    packet->tun_id = 0;
+
+    switch (msg->type) {
+    case _XFLOWL_MISS_NR:
+        packet->channel = WDP_CHAN_MISS;
+        packet->payload = payload;
+        packet->tun_id = msg->arg;
+        return 0;
+
+    case _XFLOWL_ACTION_NR:
+        packet->channel = WDP_CHAN_ACTION;
+        packet->payload = payload;
+        packet->send_len = msg->arg;
+        return 0;
+
+    case _XFLOWL_SFLOW_NR:
+        /* XXX */
+        ofpbuf_delete(payload);
+        return ENOSYS;
+
+    default:
+        VLOG_WARN_RL(&rl, "received XFLOW message of unexpected type %"PRIu32,
+                     msg->type);
+        ofpbuf_delete(payload);
+        return ENOSYS;
+    }
+}
+
+static const uint8_t *
+get_local_mac(const struct wx *wx)
+{
+    const struct wdp_port *port = port_array_get(&wx->ports, XFLOWP_LOCAL);
+    return port ? port->opp.hw_addr : NULL;
+}
+
+/* Returns true if 'packet' is a DHCP reply to the local port.  Such a reply
+ * should be sent to the local port regardless of the flow table.
+ *
+ * We only need this, strictly speaking, when in-band control is turned on. */
+static bool
+wx_is_local_dhcp_reply(const struct wx *wx,
+                       const flow_t *flow, const struct ofpbuf *packet)
+{
+    if (flow->dl_type == htons(ETH_TYPE_IP)
+        && flow->nw_proto == IP_TYPE_UDP
+        && flow->tp_src == htons(DHCP_SERVER_PORT)
+        && flow->tp_dst == htons(DHCP_CLIENT_PORT)
+        && packet->l7)
+    {
+        const uint8_t *local_mac = get_local_mac(wx);
+        struct dhcp_header *dhcp = ofpbuf_at(
+            packet, (char *)packet->l7 - (char *)packet->data, sizeof *dhcp);
+        return dhcp && local_mac && eth_addr_equals(dhcp->chaddr, local_mac);
+    }
+
+    return false;
+}
+
+static bool
+wx_explode_rule(struct wx *wx, struct xflow_msg *msg, struct ofpbuf *payload)
+{
+    struct wx_rule *rule;
+    flow_t flow;
+
+    flow_extract(payload, 0, xflow_port_to_ofp_port(msg->port), &flow);
+
+    if (wx_is_local_dhcp_reply(wx, &flow, payload)) {
+        union xflow_action action;
+
+        memset(&action, 0, sizeof(action));
+        action.output.type = XFLOWAT_OUTPUT;
+        action.output.port = XFLOWP_LOCAL;
+        xfif_execute(wx->xfif, msg->port, &action, 1, payload);
+    }
+
+    rule = wx_rule_lookup_valid(wx, &flow);
+    if (!rule) {
+        return false;
+    }
+
+    if (rule->wr.cr.flow.wildcards) {
+        rule = wx_rule_create_subrule(wx, rule, &flow);
+        wx_rule_make_actions(wx, rule, payload);
+    } else {
+        if (!rule->may_install) {
+            /* The rule is not installable, that is, we need to process every
+             * packet, so process the current packet and set its actions into
+             * 'subrule'. */
+            wx_rule_make_actions(wx, rule, payload);
+        } else {
+            /* XXX revalidate rule if it needs it */
+        }
+    }
+
+    wx_rule_execute(wx, rule, payload, &flow);
+    wx_rule_reinstall(wx, rule);
+
+    return true;
+}
+
+static int
+wx_recv(struct wdp *wdp, struct wdp_packet *packet)
+{
+    struct wx *wx = wx_cast(wdp);
+    int i;
+
+    /* XXX need to avoid 50*50 potential cost for caller. */
+    for (i = 0; i < 50; i++) {
+        struct xflow_msg *msg;
+        struct ofpbuf *buf;
+        int error;
+
+        error = xfif_recv(wx->xfif, &buf);
+        if (error) {
+            return error;
+        }
+
+        msg = ofpbuf_pull(buf, sizeof *msg);
+        if (msg->type != _XFLOWL_MISS_NR || !wx_explode_rule(wx, msg, buf)) {
+            return wx_translate_xflow_msg(msg, buf, packet);
+        }
+        ofpbuf_delete(buf);
+    }
+    return EAGAIN;
+}
+
+static void
+wx_recv_wait(struct wdp *wdp)
+{
+    struct wx *wx = wx_cast(wdp);
+
+    xfif_recv_wait(wx->xfif);
+}
+\f
+static void wx_port_update(struct wx *, const char *devname);
+static void wx_port_reinit(struct wx *);
+
+static void
+wx_port_process_change(struct wx *wx, int error, char *devname)
+{
+    if (error == ENOBUFS) {
+        wx_port_reinit(wx);
+    } else if (!error) {
+        wx_port_update(wx, devname);
+        free(devname);
+    }
+}
+
+static void
+wx_port_run(struct wx *wx)
+{
+    char *devname;
+    int error;
+
+    while ((error = xfif_port_poll(wx->xfif, &devname)) != EAGAIN) {
+        wx_port_process_change(wx, error, devname);
+    }
+    while ((error = netdev_monitor_poll(wx->netdev_monitor,
+                                        &devname)) != EAGAIN) {
+        wx_port_process_change(wx, error, devname);
+    }
+}
+
+static size_t
+wx_port_refresh_group(struct wx *wx, unsigned int group)
+{
+    uint16_t *ports;
+    size_t n_ports;
+    struct wdp_port *port;
+    unsigned int port_no;
+
+    assert(group == WX_GROUP_ALL || group == WX_GROUP_FLOOD);
+
+    ports = xmalloc(port_array_count(&wx->ports) * sizeof *ports);
+    n_ports = 0;
+    PORT_ARRAY_FOR_EACH (port, &wx->ports, port_no) {
+        if (group == WX_GROUP_ALL || !(port->opp.config & OFPPC_NO_FLOOD)) {
+            ports[n_ports++] = port_no;
+        }
+    }
+    xfif_port_group_set(wx->xfif, group, ports, n_ports);
+    free(ports);
+
+    return n_ports;
+}
+
+static void
+wx_port_refresh_groups(struct wx *wx)
+{
+    wx_port_refresh_group(wx, WX_GROUP_FLOOD);
+    wx_port_refresh_group(wx, WX_GROUP_ALL);
+}
+
+static void
+wx_port_reinit(struct wx *wx)
+{
+    struct svec devnames;
+    struct wdp_port *wdp_port;
+    unsigned int port_no;
+    struct xflow_port *xflow_ports;
+    size_t n_xflow_ports;
+    size_t i;
+
+    svec_init(&devnames);
+    PORT_ARRAY_FOR_EACH (wdp_port, &wx->ports, port_no) {
+        svec_add (&devnames, (char *) wdp_port->opp.name);
+    }
+    xfif_port_list(wx->xfif, &xflow_ports, &n_xflow_ports);
+    for (i = 0; i < n_xflow_ports; i++) {
+        svec_add(&devnames, xflow_ports[i].devname);
+    }
+    free(xflow_ports);
+
+    svec_sort_unique(&devnames);
+    for (i = 0; i < devnames.n; i++) {
+        wx_port_update(wx, devnames.names[i]);
+    }
+    svec_destroy(&devnames);
+
+    wx_port_refresh_groups(wx);
+}
+
+static struct wdp_port *
+make_wdp_port(const struct xflow_port *xflow_port)
+{
+    struct netdev_options netdev_options;
+    enum netdev_flags flags;
+    struct wdp_port *wdp_port;
+    struct netdev *netdev;
+    bool carrier;
+    int error;
+
+    memset(&netdev_options, 0, sizeof netdev_options);
+    netdev_options.name = xflow_port->devname;
+    netdev_options.ethertype = NETDEV_ETH_TYPE_NONE;
+    netdev_options.may_create = true;
+    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)",
+                     xflow_port->devname, xflow_port->port,
+                     xflow_port->devname, strerror(error));
+        return NULL;
+    }
+
+    wdp_port = xmalloc(sizeof *wdp_port);
+    wdp_port->netdev = netdev;
+    wdp_port->opp.port_no = xflow_port_to_ofp_port(xflow_port->port);
+    netdev_get_etheraddr(netdev, wdp_port->opp.hw_addr);
+    strncpy((char *) wdp_port->opp.name, xflow_port->devname,
+            sizeof wdp_port->opp.name);
+    wdp_port->opp.name[sizeof wdp_port->opp.name - 1] = '\0';
+
+    netdev_get_flags(netdev, &flags);
+    wdp_port->opp.config = flags & NETDEV_UP ? 0 : OFPPC_PORT_DOWN;
+
+    netdev_get_carrier(netdev, &carrier);
+    wdp_port->opp.state = carrier ? 0 : OFPPS_LINK_DOWN;
+
+    netdev_get_features(netdev,
+                        &wdp_port->opp.curr, &wdp_port->opp.advertised,
+                        &wdp_port->opp.supported, &wdp_port->opp.peer);
+
+    wdp_port->devname = xstrdup(xflow_port->devname);
+    wdp_port->internal = (xflow_port->flags & XFLOW_PORT_INTERNAL) != 0;
+    return wdp_port;
+}
+
+static bool
+wx_port_conflicts(const struct wx *wx, const struct xflow_port *xflow_port)
+{
+    if (port_array_get(&wx->ports, xflow_port->port)) {
+        VLOG_WARN_RL(&rl, "ignoring duplicate port %"PRIu16" in datapath",
+                     xflow_port->port);
+        return true;
+    } else if (shash_find(&wx->port_by_name, xflow_port->devname)) {
+        VLOG_WARN_RL(&rl, "ignoring duplicate device %s in datapath",
+                     xflow_port->devname);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static int
+wdp_port_equal(const struct wdp_port *a_, const struct wdp_port *b_)
+{
+    const struct ofp_phy_port *a = &a_->opp;
+    const struct ofp_phy_port *b = &b_->opp;
+
+    BUILD_ASSERT_DECL(sizeof *a == 48); /* Detect ofp_phy_port changes. */
+    return (a->port_no == b->port_no
+            && !memcmp(a->hw_addr, b->hw_addr, sizeof a->hw_addr)
+            && !strcmp((char *) a->name, (char *) b->name)
+            && a->state == b->state
+            && a->config == b->config
+            && a->curr == b->curr
+            && a->advertised == b->advertised
+            && a->supported == b->supported
+            && a->peer == b->peer);
+}
+
+static void
+wx_port_install(struct wx *wx, struct wdp_port *wdp_port)
+{
+    uint16_t xflow_port = ofp_port_to_xflow_port(wdp_port->opp.port_no);
+    const char *netdev_name = (const char *) wdp_port->opp.name;
+
+    netdev_monitor_add(wx->netdev_monitor, wdp_port->netdev);
+    port_array_set(&wx->ports, xflow_port, wdp_port);
+    shash_add(&wx->port_by_name, netdev_name, wdp_port);
+}
+
+static void
+wx_port_remove(struct wx *wx, struct wdp_port *wdp_port)
+{
+    uint16_t xflow_port = ofp_port_to_xflow_port(wdp_port->opp.port_no);
+
+    netdev_monitor_remove(wx->netdev_monitor, wdp_port->netdev);
+    port_array_set(&wx->ports, xflow_port, NULL);
+    shash_delete(&wx->port_by_name,
+                 shash_find(&wx->port_by_name, (char *) wdp_port->opp.name));
+}
+
+static void
+wx_port_free(struct wdp_port *wdp_port)
+{
+    if (wdp_port) {
+        netdev_close(wdp_port->netdev);
+        free(wdp_port);
+    }
+}
+
+static void
+wx_port_update(struct wx *wx, const char *devname)
+{
+    struct xflow_port xflow_port;
+    struct wdp_port *old_wdp_port;
+    struct wdp_port *new_wdp_port;
+    int error;
+
+    COVERAGE_INC(wx_update_port);
+
+    /* Query the datapath for port information. */
+    error = xfif_port_query_by_name(wx->xfif, devname, &xflow_port);
+
+    /* Find the old wdp_port. */
+    old_wdp_port = shash_find_data(&wx->port_by_name, devname);
+    if (!error) {
+        if (!old_wdp_port) {
+            /* There's no port named 'devname' but there might be a port with
+             * the same port number.  This could happen if a port is deleted
+             * and then a new one added in its place very quickly, or if a port
+             * is renamed.  In the former case we want to send an OFPPR_DELETE
+             * and an OFPPR_ADD, and in the latter case we want to send a
+             * single OFPPR_MODIFY.  We can distinguish the cases by comparing
+             * the old port's ifindex against the new port, or perhaps less
+             * reliably but more portably by comparing the old port's MAC
+             * against the new port's MAC.  However, this code isn't that smart
+             * and always sends an OFPPR_MODIFY (XXX). */
+            old_wdp_port = port_array_get(&wx->ports, xflow_port.port);
+        }
+    } else if (error != ENOENT && error != ENODEV) {
+        VLOG_WARN_RL(&rl, "xfif_port_query_by_name returned unexpected error "
+                     "%s", strerror(error));
+        return;
+    }
+
+    /* Create a new wdp_port. */
+    new_wdp_port = !error ? make_wdp_port(&xflow_port) : NULL;
+
+    /* Eliminate a few pathological cases. */
+    if (!old_wdp_port && !new_wdp_port) {
+        return;
+    } else if (old_wdp_port && new_wdp_port) {
+        /* Most of the 'config' bits are OpenFlow soft state, but
+         * OFPPC_PORT_DOWN is maintained by the kernel.  So transfer the
+         * OpenFlow bits from old_wdp_port.  (make_wdp_port() only sets
+         * OFPPC_PORT_DOWN and leaves the other bits 0.)  */
+        new_wdp_port->opp.config |= old_wdp_port->opp.config & ~OFPPC_PORT_DOWN;
+
+        if (wdp_port_equal(old_wdp_port, new_wdp_port)) {
+            /* False alarm--no change. */
+            wx_port_free(new_wdp_port);
+            return;
+        }
+    }
+
+    /* Now deal with the normal cases. */
+    if (old_wdp_port) {
+        wx_port_remove(wx, old_wdp_port);
+    }
+    if (new_wdp_port) {
+        wx_port_install(wx, new_wdp_port);
+    }
+    wx_port_free(old_wdp_port);
+}
+
+static int
+wx_port_init(struct wx *wx)
+{
+    struct xflow_port *ports;
+    size_t n_ports;
+    size_t i;
+    int error;
+
+    error = xfif_port_list(wx->xfif, &ports, &n_ports);
+    if (error) {
+        return error;
+    }
+
+    for (i = 0; i < n_ports; i++) {
+        const struct xflow_port *xflow_port = &ports[i];
+        if (!wx_port_conflicts(wx, xflow_port)) {
+            struct wdp_port *wdp_port = make_wdp_port(xflow_port);
+            if (wdp_port) {
+                wx_port_install(wx, wdp_port);
+            }
+        }
+    }
+    free(ports);
+    wx_port_refresh_groups(wx);
+    return 0;
+}
+\f
+void
+wdp_xflow_register(void)
+{
+    static const struct wdp_class wdp_xflow_class = {
+        NULL,                   /* name */
+        wx_run,
+        wx_wait,
+        wx_enumerate,
+        wx_open,
+        wx_close,
+        wx_get_all_names,
+        wx_destroy,
+        wx_get_features,
+        wx_get_stats,
+        wx_get_drop_frags,
+        wx_set_drop_frags,
+        wx_port_add,
+        wx_port_del,
+        wx_port_query_by_number,
+        wx_port_query_by_name,
+        wx_port_list,
+        wx_port_set_config,
+        wx_port_poll,
+        wx_port_poll_wait,
+        wx_flow_get,
+        wx_flow_match,
+        wx_flow_for_each_match,
+        wx_flow_get_stats,
+        wx_flow_overlaps,
+        wx_flow_put,
+        wx_flow_delete,
+        wx_flow_flush,
+        wx_flow_inject,
+        wx_execute,
+        wx_recv_get_mask,
+        wx_recv_set_mask,
+        wx_get_sflow_probability,
+        wx_set_sflow_probability,
+        wx_recv,
+        wx_recv_wait,
+    };
+
+    static bool inited = false;
+
+    struct svec types;
+    const char *type;
+    bool registered;
+    int i;
+
+    if (inited) {
+        return;
+    }
+    inited = true;
+
+    svec_init(&types);
+    xf_enumerate_types(&types);
+
+    registered = false;
+    SVEC_FOR_EACH (i, type, &types) {
+        struct wdp_class *class;
+
+        class = xmalloc(sizeof *class);
+        *class = wdp_xflow_class;
+        class->type = xstrdup(type);
+        if (registered) {
+            class->run = NULL;
+            class->wait = NULL;
+        }
+        if (!wdp_register_provider(class)) {
+            registered = true;
+        }
+    }
+
+    svec_destroy(&types);
+}
diff --git a/ofproto/wdp-xflow.h b/ofproto/wdp-xflow.h
new file mode 100644 (file)
index 0000000..ad71c49
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 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.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WDP_XFLOW_H
+#define WDP_XFLOW_H 1
+
+void wdp_xflow_register(void);
+
+#endif /* ofproto/wdp-xflow.h */
diff --git a/ofproto/wdp.c b/ofproto/wdp.c
new file mode 100644 (file)
index 0000000..7e04110
--- /dev/null
@@ -0,0 +1,1048 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "wdp-provider.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "coverage.h"
+#include "dynamic-string.h"
+#include "flow.h"
+#include "netdev.h"
+#include "netlink.h"
+#include "ofp-print.h"
+#include "ofpbuf.h"
+#include "packets.h"
+#include "poll-loop.h"
+#include "shash.h"
+#include "svec.h"
+#include "timeval.h"
+#include "util.h"
+#include "valgrind.h"
+#include "wdp-xflow.h"
+
+#include "vlog.h"
+#define THIS_MODULE VLM_wdp
+\f
+/* wdp_rule */
+
+/* Initializes a new 'struct wdp_rule', copying in the 'n_actions' elements of
+ * 'actions'.
+ *
+ * The caller is responsible for initializing 'rule->cr'. */
+void
+wdp_rule_init(struct wdp_rule *rule, const union ofp_action *actions,
+              size_t n_actions)
+{
+    rule->actions = xmemdup(actions, n_actions * sizeof *actions);
+    rule->n_actions = n_actions;
+    rule->created = time_msec();
+    rule->idle_timeout = 0;
+    rule->hard_timeout = 0;
+    rule->client_data = NULL;
+}
+
+/* Frees the data in 'rule'. */
+void
+wdp_rule_uninit(struct wdp_rule *rule)
+{
+    free(rule->actions);
+}
+\f
+/* wdp */
+
+static const struct wdp_class *base_wdp_classes[] = {
+    /* XXX none yet */
+};
+
+struct registered_wdp_class {
+    const struct wdp_class *wdp_class;
+    int refcount;
+};
+
+static struct shash wdp_classes = SHASH_INITIALIZER(&wdp_classes);
+
+/* Rate limit for individual messages going to or from the datapath, output at
+ * DBG level.  This is very high because, if these are enabled, it is because
+ * we really need to see them. */
+static struct vlog_rate_limit wdpmsg_rl = VLOG_RATE_LIMIT_INIT(600, 600);
+
+/* Not really much point in logging many wdp errors. */
+static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(9999, 5);
+
+static void log_operation(const struct wdp *, const char *operation,
+                          int error);
+
+static void
+wdp_initialize(void)
+{
+    static int status = -1;
+
+    if (status < 0) {
+        int i;
+
+        status = 0;
+        for (i = 0; i < ARRAY_SIZE(base_wdp_classes); i++) {
+            wdp_register_provider(base_wdp_classes[i]);
+        }
+        wdp_xflow_register();
+    }
+}
+
+/* Performs periodic work needed by all the various kinds of wdps.
+ *
+ * If your program opens any wdps, it must call both this function and
+ * netdev_run() within its main poll loop. */
+void
+wdp_run(void)
+{
+    struct shash_node *node;
+    SHASH_FOR_EACH (node, &wdp_classes) {
+        const struct registered_wdp_class *registered_class = node->data;
+        if (registered_class->wdp_class->run) {
+            registered_class->wdp_class->run();
+        }
+    }
+}
+
+/* Arranges for poll_block() to wake up when wdp_run() needs to be called.
+ *
+ * If your program opens any wdps, it must call both this function and
+ * netdev_wait() within its main poll loop. */
+void
+wdp_wait(void)
+{
+    struct shash_node *node;
+    SHASH_FOR_EACH(node, &wdp_classes) {
+        const struct registered_wdp_class *registered_class = node->data;
+        if (registered_class->wdp_class->wait) {
+            registered_class->wdp_class->wait();
+        }
+    }
+}
+
+/* Registers a new datapath provider.  After successful registration, new
+ * datapaths of that type can be opened using wdp_open(). */
+int
+wdp_register_provider(const struct wdp_class *new_class)
+{
+    struct registered_wdp_class *registered_class;
+
+    if (shash_find(&wdp_classes, new_class->type)) {
+        VLOG_WARN("attempted to register duplicate datapath provider: %s",
+                  new_class->type);
+        return EEXIST;
+    }
+
+    registered_class = xmalloc(sizeof *registered_class);
+    registered_class->wdp_class = new_class;
+    registered_class->refcount = 0;
+
+    shash_add(&wdp_classes, new_class->type, registered_class);
+
+    return 0;
+}
+
+/* Unregisters a datapath provider.  'type' must have been previously
+ * registered and not currently be in use by any wdps.  After unregistration
+ * new datapaths of that type cannot be opened using wdp_open(). */
+int
+wdp_unregister_provider(const char *type)
+{
+    struct shash_node *node;
+    struct registered_wdp_class *registered_class;
+
+    node = shash_find(&wdp_classes, type);
+    if (!node) {
+        VLOG_WARN("attempted to unregister a datapath provider that is not "
+                  "registered: %s", type);
+        return EAFNOSUPPORT;
+    }
+
+    registered_class = node->data;
+    if (registered_class->refcount) {
+        VLOG_WARN("attempted to unregister in use datapath provider: %s",
+                  type);
+        return EBUSY;
+    }
+
+    shash_delete(&wdp_classes, node);
+    free(registered_class);
+
+    return 0;
+}
+
+/* Clears 'types' and enumerates the types of all currently registered wdp
+ * providers into it.  The caller must first initialize the svec. */
+void
+wdp_enumerate_types(struct svec *types)
+{
+    struct shash_node *node;
+
+    wdp_initialize();
+    svec_clear(types);
+
+    SHASH_FOR_EACH (node, &wdp_classes) {
+        const struct registered_wdp_class *registered_class = node->data;
+        svec_add(types, registered_class->wdp_class->type);
+    }
+}
+
+/* Clears 'names' and enumerates the names of all known created datapaths
+ * with the given 'type'.  The caller must first initialize the svec. Returns 0
+ * if successful, otherwise a positive errno value.
+ *
+ * Some kinds of datapaths might not be practically enumerable.  This is not
+ * considered an error. */
+int
+wdp_enumerate_names(const char *type, struct svec *names)
+{
+    const struct registered_wdp_class *registered_class;
+    const struct wdp_class *wdp_class;
+    int error;
+
+    wdp_initialize();
+    svec_clear(names);
+
+    registered_class = shash_find_data(&wdp_classes, type);
+    if (!registered_class) {
+        VLOG_WARN("could not enumerate unknown type: %s", type);
+        return EAFNOSUPPORT;
+    }
+
+    wdp_class = registered_class->wdp_class;
+    error = (wdp_class->enumerate
+             ? wdp_class->enumerate(wdp_class, names)
+             : 0);
+
+    if (error) {
+        VLOG_WARN("failed to enumerate %s datapaths: %s", wdp_class->type,
+                  strerror(error));
+    }
+
+    return error;
+}
+
+/* Parses 'datapath_name', which is of the form type@name, into its
+ * component pieces.  'name' and 'type' must be freed by the caller. */
+void
+wdp_parse_name(const char *datapath_name_, char **name, char **type)
+{
+    char *datapath_name = xstrdup(datapath_name_);
+    char *separator;
+
+    separator = strchr(datapath_name, '@');
+    if (separator) {
+        *separator = '\0';
+        *type = datapath_name;
+        *name = xstrdup(separator + 1);
+    } else {
+        *name = datapath_name;
+        *type = NULL;
+    }
+}
+
+static int
+do_open(const char *name, const char *type, bool create, struct wdp **wdpp)
+{
+    struct wdp *wdp = NULL;
+    int error;
+    struct registered_wdp_class *registered_class;
+
+    wdp_initialize();
+
+    if (!type || *type == '\0') {
+        type = "system";
+    }
+
+    registered_class = shash_find_data(&wdp_classes, type);
+    if (!registered_class) {
+        VLOG_WARN("could not create datapath %s of unknown type %s", name,
+                  type);
+        error = EAFNOSUPPORT;
+        goto exit;
+    }
+
+    error = registered_class->wdp_class->open(registered_class->wdp_class,
+                                              name, create, &wdp);
+    if (!error) {
+        registered_class->refcount++;
+    }
+
+exit:
+    *wdpp = error ? NULL : wdp;
+    return error;
+}
+
+/* Tries to open an existing datapath named 'name' and type 'type'.  Will fail
+ * if no datapath with 'name' and 'type' exists.  'type' may be either NULL or
+ * the empty string to specify the default system type.  Returns 0 if
+ * successful, otherwise a positive errno value.  On success stores a pointer
+ * to the datapath in '*wdpp', otherwise a null pointer. */
+int
+wdp_open(const char *name, const char *type, struct wdp **wdpp)
+{
+    return do_open(name, type, false, wdpp);
+}
+
+/* Tries to create and open a new datapath with the given 'name' and 'type'.
+ * 'type' may be either NULL or the empty string to specify the default system
+ * type.  Will fail if a datapath with 'name' and 'type' already exists.
+ * Returns 0 if successful, otherwise a positive errno value.  On success
+ * stores a pointer to the datapath in '*wdpp', otherwise a null pointer. */
+int
+wdp_create(const char *name, const char *type, struct wdp **wdpp)
+{
+    return do_open(name, type, true, wdpp);
+}
+
+/* Tries to open a datapath with the given 'name' and 'type', creating it if it
+ * does not exist.  'type' may be either NULL or the empty string to specify
+ * the default system type.  Returns 0 if successful, otherwise a positive
+ * errno value. On success stores a pointer to the datapath in '*wdpp',
+ * otherwise a null pointer. */
+int
+wdp_create_and_open(const char *name, const char *type, struct wdp **wdpp)
+{
+    int error;
+
+    error = wdp_create(name, type, wdpp);
+    if (error == EEXIST || error == EBUSY) {
+        error = wdp_open(name, type, wdpp);
+        if (error) {
+            VLOG_WARN("datapath %s already exists but cannot be opened: %s",
+                      name, strerror(error));
+        }
+    } else if (error) {
+        VLOG_WARN("failed to create datapath %s: %s", name, strerror(error));
+    }
+    return error;
+}
+
+/* Closes and frees the connection to 'wdp'.  Does not destroy the wdp
+ * itself; call wdp_delete() first, instead, if that is desirable. */
+void
+wdp_close(struct wdp *wdp)
+{
+    if (wdp) {
+        struct registered_wdp_class *registered_class;
+
+        registered_class = shash_find_data(&wdp_classes, 
+                                           wdp->wdp_class->type);
+        assert(registered_class);
+        assert(registered_class->refcount);
+
+        registered_class->refcount--;
+        wdp_uninit(wdp, true);
+    }
+}
+
+/* Returns the name of datapath 'wdp' prefixed with the type
+ * (for use in log messages). */
+const char *
+wdp_name(const struct wdp *wdp)
+{
+    return wdp->full_name;
+}
+
+/* Returns the name of datapath 'wdp' without the type
+ * (for use in device names). */
+const char *
+wdp_base_name(const struct wdp *wdp)
+{
+    return wdp->base_name;
+}
+
+/* Enumerates all names that may be used to open 'wdp' into 'all_names'.  The
+ * Linux datapath, for example, supports opening a datapath both by number,
+ * e.g. "wdp0", and by the name of the datapath's local port.  For some
+ * datapaths, this might be an infinite set (e.g. in a file name, slashes may
+ * be duplicated any number of times), in which case only the names most likely
+ * to be used will be enumerated.
+ *
+ * The caller must already have initialized 'all_names'.  Any existing names in
+ * 'all_names' will not be disturbed. */
+int
+wdp_get_all_names(const struct wdp *wdp, struct svec *all_names)
+{
+    if (wdp->wdp_class->get_all_names) {
+        int error = wdp->wdp_class->get_all_names(wdp, all_names);
+        if (error) {
+            VLOG_WARN_RL(&error_rl,
+                         "failed to retrieve names for datpath %s: %s",
+                         wdp_name(wdp), strerror(error));
+        }
+        return error;
+    } else {
+        svec_add(all_names, wdp_base_name(wdp));
+        return 0;
+    }
+}
+
+/* Destroys the datapath that 'wdp' is connected to, first removing all of
+ * its ports.  After calling this function, it does not make sense to pass
+ * 'wdp' to any functions other than wdp_name() or wdp_close(). */
+int
+wdp_delete(struct wdp *wdp)
+{
+    int error;
+
+    COVERAGE_INC(wdp_destroy);
+
+    error = wdp->wdp_class->destroy(wdp);
+    log_operation(wdp, "delete", error);
+    return error;
+}
+
+/* Obtains the set of features supported by 'wdp'.
+ *
+ * If successful, returns 0 and stores in '*featuresp' a newly allocated
+ * "struct ofp_switch_features" that describes the features and ports supported
+ * by 'wdp'.  The caller is responsible for initializing the header,
+ * datapath_id, and n_buffers members of the returned "struct
+ * ofp_switch_features".  The caller must free the returned buffer (with
+ * ofpbuf_delete()) when it is no longer needed.
+ *
+ * On error, returns an OpenFlow error code (as constructed by ofp_mkerr()) and
+ * sets '*featuresp' to NULL. */
+int
+wdp_get_features(const struct wdp *wdp, struct ofpbuf **featuresp)
+{
+    int error = wdp->wdp_class->get_features(wdp, featuresp);
+    if (error) {
+        *featuresp = NULL;
+    }
+    return error;
+}
+
+/* Retrieves statistics for 'wdp' into 'stats'.  Returns 0 if successful,
+ * otherwise a positive errno value.  On error, clears 'stats' to
+ * all-bits-zero. */
+int
+wdp_get_wdp_stats(const struct wdp *wdp, struct wdp_stats *stats)
+{
+    int error = wdp->wdp_class->get_stats(wdp, stats);
+    if (error) {
+        memset(stats, 0, sizeof *stats);
+    }
+    log_operation(wdp, "get_stats", error);
+    return error;
+}
+
+/* Retrieves the current IP fragment handling policy for 'wdp' into
+ * '*drop_frags': true indicates that fragments are dropped, false indicates
+ * that fragments are treated in the same way as other IP packets (except that
+ * the L4 header cannot be read).  Returns 0 if successful, otherwise a
+ * positive errno value. */
+int
+wdp_get_drop_frags(const struct wdp *wdp, bool *drop_frags)
+{
+    int error = wdp->wdp_class->get_drop_frags(wdp, drop_frags);
+    if (error) {
+        *drop_frags = false;
+    }
+    log_operation(wdp, "get_drop_frags", error);
+    return error;
+}
+
+/* Changes 'wdp''s treatment of IP fragments to 'drop_frags', whose meaning is
+ * the same as for the get_drop_frags member function.  Returns 0 if
+ * successful, otherwise a positive errno value.  EOPNOTSUPP indicates that
+ * 'wdp''s fragment dropping policy is not configurable. */
+int
+wdp_set_drop_frags(struct wdp *wdp, bool drop_frags)
+{
+    int error;
+    error = (wdp->wdp_class->set_drop_frags
+             ? wdp->wdp_class->set_drop_frags(wdp, drop_frags)
+             : EOPNOTSUPP);
+    log_operation(wdp, "set_drop_frags", error);
+    return error;
+}
+
+/* Clears the contents of 'port'. */
+void
+wdp_port_clear(struct wdp_port *port)
+{
+    memset(port, 0, sizeof *port);
+}
+
+/* Makes a deep copy of 'old' in 'port'.  The caller may free 'port''s data
+ * with wdp_port_free(). */
+void
+wdp_port_copy(struct wdp_port *port, const struct wdp_port *old)
+{
+    port->netdev = old->netdev ? netdev_reopen(old->netdev) : NULL;
+    port->opp = old->opp;
+    port->devname = old->devname ? xstrdup(old->devname) : NULL;
+    port->internal = old->internal;
+}
+
+/* Frees the data that 'port' points to (but not 'port' itself). */
+void
+wdp_port_free(struct wdp_port *port)
+{
+    if (port) {
+        netdev_close(port->netdev);
+        free(port->devname);
+    }
+}
+
+/* Frees the data that each of the 'n' ports in 'ports' points to, and then
+ * frees 'ports' itself. */
+void
+wdp_port_array_free(struct wdp_port *ports, size_t n)
+{
+    size_t i;
+
+    for (i = 0; i < n; i++) {
+        wdp_port_free(&ports[i]);
+    }
+    free(ports);
+}
+
+/* Attempts to add 'devname' as a port on 'wdp':
+ *
+ *   - If 'internal' is true, attempts to create a new internal port (a virtual
+ *     port implemented in software) by that name.
+ *
+ *   - If 'internal' is false, 'devname' must name an existing network device.
+ *
+ * If successful, returns 0 and sets '*port_nop' to the new port's OpenFlow
+ * port number (if 'port_nop' is non-null).  On failure, returns a positive
+ * errno value and sets '*port_nop' to OFPP_NONE (if 'port_nop' is non-null).
+ *
+ * Some wildcarded datapaths might have fixed sets of ports.  For these
+ * datapaths this function will always fail.
+ *
+ * Possible error return values include:
+ *
+ *   - ENODEV: No device named 'devname' exists (if 'internal' is false).
+ *
+ *   - EEXIST: A device named 'devname' already exists (if 'internal' is true).
+ *
+ *   - EINVAL: Device 'devname' is not supported as part of a datapath (e.g. it
+ *     is not an Ethernet device), or 'devname' is too long for a network
+ *     device name (if 'internal' is true)
+ *
+ *   - EFBIG: The datapath already has as many ports as it can support.
+ *
+ *   - EOPNOTSUPP: 'wdp' has a fixed set of ports.
+ */
+int
+wdp_port_add(struct wdp *wdp, const char *devname,
+             bool internal, uint16_t *port_nop)
+{
+    uint16_t port_no;
+    int error;
+
+    COVERAGE_INC(wdp_port_add);
+
+    error = (wdp->wdp_class->port_add
+             ? wdp->wdp_class->port_add(wdp, devname, internal, &port_no)
+             : EOPNOTSUPP);
+    if (!error) {
+        VLOG_DBG_RL(&wdpmsg_rl, "%s: added %s as port %"PRIu16,
+                    wdp_name(wdp), devname, port_no);
+    } else {
+        VLOG_WARN_RL(&error_rl, "%s: failed to add %s as port: %s",
+                     wdp_name(wdp), devname, strerror(error));
+        port_no = OFPP_NONE;
+    }
+    if (port_nop) {
+        *port_nop = port_no;
+    }
+    return error;
+}
+
+/* Attempts to remove 'wdp''s port numbered 'port_no'.  Returns 0 if
+ * successful, otherwise a positive errno value.
+ *
+ * Some wildcarded datapaths might have fixed sets of ports.  For these
+ * datapaths this function will always fail.
+ *
+ * Possible error return values include:
+ *
+ *   - EINVAL: 'port_no' is outside the valid range, or this particular port is
+ *     not removable (e.g. it is the local port).
+ *
+ *   - ENOENT: 'wdp' currently has no port numbered 'port_no'.
+ *
+ *   - EOPNOTSUPP: 'wdp' has a fixed set of ports.
+ */
+int
+wdp_port_del(struct wdp *wdp, uint16_t port_no)
+{
+    int error;
+
+    COVERAGE_INC(wdp_port_del);
+
+    error = (wdp->wdp_class->port_del
+             ? wdp->wdp_class->port_del(wdp, port_no)
+             : EOPNOTSUPP);
+    log_operation(wdp, "port_del", error);
+    return error;
+}
+
+/* Looks up port number 'port_no' in 'wdp'.  On success, returns 0 and
+ * initializes 'port' with port details.  On failure, returns a positive errno
+ * value and clears the contents of 'port' (with wdp_port_clear()).
+ *
+ * The caller must not modify or free the returned wdp_port.  Calling
+ * wdp_run() or wdp_port_poll() may free the returned wdp_port.
+ *
+ * Possible error return values include:
+ *
+ *   - EINVAL: 'port_no' is outside the valid range.
+ *
+ *   - ENOENT: 'wdp' currently has no port numbered 'port_no'.
+ */
+int
+wdp_port_query_by_number(const struct wdp *wdp, uint16_t port_no,
+                         struct wdp_port *port)
+{
+    int error;
+
+    error = wdp->wdp_class->port_query_by_number(wdp, port_no, port);
+    if (!error) {
+        VLOG_DBG_RL(&wdpmsg_rl, "%s: port %"PRIu16" is device %s",
+                    wdp_name(wdp), port_no, port->devname);
+    } else {
+        wdp_port_clear(port);
+        VLOG_WARN_RL(&error_rl, "%s: failed to query port %"PRIu16": %s",
+                     wdp_name(wdp), port_no, strerror(error));
+    }
+    return error;
+}
+
+/* Same as wdp_port_query_by_number() except that it look for a port named
+ * 'devname' in 'wdp'.
+ *
+ * Possible error return values include:
+ *
+ *   - ENODEV: No device named 'devname' exists.
+ *
+ *   - ENOENT: 'devname' exists but it is not attached as a port on 'wdp'.
+ */
+int
+wdp_port_query_by_name(const struct wdp *wdp, const char *devname,
+                       struct wdp_port *port)
+{
+    int error = wdp->wdp_class->port_query_by_name(wdp, devname, port);
+    if (!error) {
+        VLOG_DBG_RL(&wdpmsg_rl, "%s: device %s is on port %"PRIu16,
+                    wdp_name(wdp), devname, port->opp.port_no);
+    } else {
+        wdp_port_clear(port);
+
+        /* Log level is DBG here because all the current callers are interested
+         * in whether 'wdp' actually has a port 'devname', so that it's not
+         * an issue worth logging if it doesn't. */
+        VLOG_DBG_RL(&error_rl, "%s: failed to query port %s: %s",
+                    wdp_name(wdp), devname, strerror(error));
+    }
+    return error;
+}
+
+/* Looks up port number 'port_no' in 'wdp'.  On success, returns 0 and stores
+ * a copy of the port's name in '*namep'.  On failure, returns a positive errno
+ * value and stores NULL in '*namep'.
+ *
+ * Error return values are the same as for wdp_port_query_by_name().
+ *
+ * The caller is responsible for freeing '*namep' (with free()). */
+int
+wdp_port_get_name(struct wdp *wdp, uint16_t port_no, char **namep)
+{
+    struct wdp_port port;
+    int error;
+
+    error = wdp_port_query_by_number(wdp, port_no, &port);
+    *namep = port.devname;
+    port.devname = NULL;
+    wdp_port_free(&port);
+
+    return error;
+}
+
+/* Obtains a list of all the ports in 'wdp', in no particular order.
+ *
+ * If successful, returns 0 and sets '*portsp' to point to an array of struct
+ * wdp_port and '*n_portsp' to the number of pointers in the array.  On
+ * failure, returns a positive errno value and sets '*portsp' to NULL and
+ * '*n_portsp' to 0.
+ *
+ * The caller is responsible for freeing '*portsp' and the individual wdp_port
+ * structures, e.g. with wdp_port_array_free().  */
+int
+wdp_port_list(const struct wdp *wdp,
+              struct wdp_port **portsp, size_t *n_portsp)
+{
+    int error;
+
+    error = wdp->wdp_class->port_list(wdp, portsp, n_portsp);
+    if (error) {
+        *portsp = NULL;
+        *n_portsp = 0;
+    }
+    log_operation(wdp, "port_list", error);
+    return error;
+}
+
+int
+wdp_port_set_config(struct wdp *wdp, uint16_t port_no, uint32_t config)
+{
+    return wdp->wdp_class->port_set_config(wdp, port_no, config);
+}
+
+/* Polls for changes in the set of ports in 'wdp'.  If the set of ports in
+ * 'wdp' has changed, this function does one of the following:
+ *
+ * - Stores the name of the device that was added to or deleted from 'wdp' in
+ *   '*devnamep' and returns 0.  The caller is responsible for freeing
+ *   '*devnamep' (with free()) when it no longer needs it.
+ *
+ * - Returns ENOBUFS and sets '*devnamep' to NULL.
+ *
+ * This function may also return 'false positives', where it returns 0 and
+ * '*devnamep' names a device that was not actually added or deleted or it
+ * returns ENOBUFS without any change.
+ *
+ * Returns EAGAIN if the set of ports in 'wdp' has not changed.  May also
+ * return other positive errno values to indicate that something has gone
+ * wrong. */
+int
+wdp_port_poll(const struct wdp *wdp, char **devnamep)
+{
+    int error = (wdp->wdp_class->port_poll
+                 ? wdp->wdp_class->port_poll(wdp, devnamep)
+                 : EAGAIN);
+    if (error) {
+        *devnamep = NULL;
+    }
+    return error;
+}
+
+/* Arranges for the poll loop to wake up when port_poll(wdp) will return a
+ * value other than EAGAIN. */
+void
+wdp_port_poll_wait(const struct wdp *wdp)
+{
+    if (wdp->wdp_class->port_poll_wait) {
+        wdp->wdp_class->port_poll_wait(wdp);
+    }
+}
+
+/* Deletes all flows from 'wdp'.  Returns 0 if successful, otherwise a
+ * positive errno value.  */
+int
+wdp_flow_flush(struct wdp *wdp)
+{
+    int error;
+
+    COVERAGE_INC(wdp_flow_flush);
+
+    error = wdp->wdp_class->flow_flush(wdp);
+    log_operation(wdp, "flow_flush", error);
+    return error;
+}
+
+struct wdp_rule *
+wdp_flow_get(struct wdp *wdp, const flow_t *flow)
+{
+    return wdp->wdp_class->flow_get(wdp, flow);
+}
+
+struct wdp_rule *
+wdp_flow_match(struct wdp *wdp, const flow_t *flow)
+{
+    return wdp->wdp_class->flow_match(wdp, flow);
+}
+
+void
+wdp_flow_for_each_match(const struct wdp *wdp, const flow_t *target,
+                        int include, wdp_flow_cb_func *callback, void *aux)
+{
+    wdp->wdp_class->flow_for_each_match(wdp, target, include,
+                                        callback, aux); 
+}
+
+int
+wdp_flow_get_stats(const struct wdp *wdp, const struct wdp_rule *rule,
+                   struct wdp_flow_stats *stats)
+{
+    int error = wdp->wdp_class->flow_get_stats(wdp, rule, stats);
+    if (error) {
+        memset(stats, 0, sizeof *stats);
+    }
+    return error;
+}
+
+bool
+wdp_flow_overlaps(const struct wdp *wdp, const flow_t *flow)
+{
+    return wdp->wdp_class->flow_overlaps(wdp, flow);
+}
+
+int
+wdp_flow_put(struct wdp *wdp, struct wdp_flow_put *put,
+             struct wdp_flow_stats *old_stats, struct wdp_rule **rulep)
+{
+    int error = wdp->wdp_class->flow_put(wdp, put, old_stats, rulep);
+    if (error) {
+        if (old_stats) {
+            memset(old_stats, 0, sizeof *old_stats);
+        }
+        if (rulep) {
+            *rulep = NULL;
+        }
+    }
+    return error;
+}
+
+int
+wdp_flow_delete(struct wdp *wdp, struct wdp_rule *rule,
+                struct wdp_flow_stats *final_stats)
+{
+    int error = wdp->wdp_class->flow_delete(wdp, rule, final_stats);
+    if (error && final_stats) {
+        memset(final_stats, 0, sizeof *final_stats);
+    }
+    return error;
+}
+
+int
+wdp_flow_inject(struct wdp *wdp, struct wdp_rule *rule,
+                uint16_t in_port, const struct ofpbuf *packet)
+{
+    return wdp->wdp_class->flow_inject(wdp, rule, in_port, packet);
+}
+
+int
+wdp_execute(struct wdp *wdp, uint16_t in_port,
+            const union ofp_action actions[], size_t n_actions,
+            const struct ofpbuf *buf)
+{
+    int error;
+
+    COVERAGE_INC(wdp_execute);
+    if (n_actions > 0) {
+        error = wdp->wdp_class->execute(wdp, in_port, actions,
+                                        n_actions, buf);
+    } else {
+        error = 0;
+    }
+    return error;
+}
+
+/* Retrieves 'wdp''s "listen mask" into '*listen_mask'.  Each bit set in
+ * '*listen_mask' indicates that wdp_recv() will receive messages of the
+ * corresponding WDP_CHAN_* type.  Returns 0 if successful, otherwise a
+ * positive errno value. */
+int
+wdp_recv_get_mask(const struct wdp *wdp, int *listen_mask)
+{
+    int error = wdp->wdp_class->recv_get_mask(wdp, listen_mask);
+    if (error) {
+        *listen_mask = 0;
+    }
+    log_operation(wdp, "recv_get_mask", error);
+    return error;
+}
+
+/* Sets 'wdp''s "listen mask" to 'listen_mask'.  Each bit set in
+ * '*listen_mask' requests that wdp_recv() receive messages of the
+ * corresponding WDP_CHAN_* type.  Returns 0 if successful, otherwise a
+ * positive errno value. */
+int
+wdp_recv_set_mask(struct wdp *wdp, int listen_mask)
+{
+    int error = wdp->wdp_class->recv_set_mask(wdp, listen_mask);
+    log_operation(wdp, "recv_set_mask", error);
+    return error;
+}
+
+/* Retrieve the sFlow sampling probability.  '*probability' is expressed as the
+ * number of packets out of UINT_MAX to sample, e.g. probability/UINT_MAX is
+ * the probability of sampling a given packet.
+ *
+ * Returns 0 if successful, otherwise a positive errno value.  EOPNOTSUPP
+ * indicates that 'wdp' does not support sFlow sampling. */
+int
+wdp_get_sflow_probability(const struct wdp *wdp, uint32_t *probability)
+{
+    int error = (wdp->wdp_class->get_sflow_probability
+                 ? wdp->wdp_class->get_sflow_probability(wdp, probability)
+                 : EOPNOTSUPP);
+    if (error) {
+        *probability = 0;
+    }
+    log_operation(wdp, "get_sflow_probability", error);
+    return error;
+}
+
+/* Set the sFlow sampling probability.  'probability' is expressed as the
+ * number of packets out of UINT_MAX to sample, e.g. probability/UINT_MAX is
+ * the probability of sampling a given packet.
+ *
+ * Returns 0 if successful, otherwise a positive errno value.  EOPNOTSUPP
+ * indicates that 'wdp' does not support sFlow sampling. */
+int
+wdp_set_sflow_probability(struct wdp *wdp, uint32_t probability)
+{
+    int error = (wdp->wdp_class->set_sflow_probability
+                 ? wdp->wdp_class->set_sflow_probability(wdp, probability)
+                 : EOPNOTSUPP);
+    log_operation(wdp, "set_sflow_probability", error);
+    return error;
+}
+
+/* Attempts to receive a message from 'wdp'.  If successful, stores the
+ * message into '*packetp'.  Only messages of the types selected with
+ * wdp_set_listen_mask() will ordinarily be received (but if a message type
+ * is enabled and then later disabled, some stragglers might pop up).
+ *
+ * Returns 0 if successful, otherwise a positive errno value.  Returns EAGAIN
+ * if no message is immediately available. */
+int
+wdp_recv(struct wdp *wdp, struct wdp_packet *packet)
+{
+    int error = wdp->wdp_class->recv(wdp, packet);
+    if (!error) {
+        /* XXX vlog_dbg received packet */
+    } else {
+        memset(packet, 0, sizeof *packet);
+        packet->channel = -1;
+    }
+    return error;
+}
+
+/* Discards all messages that would otherwise be received by wdp_recv() on
+ * 'wdp'.  Returns 0 if successful, otherwise a positive errno value. */
+int
+wdp_recv_purge(struct wdp *wdp)
+{
+    struct wdp_stats stats;
+    unsigned int i;
+    int error;
+
+    COVERAGE_INC(wdp_purge);
+
+    error = wdp_get_wdp_stats(wdp, &stats);
+    if (error) {
+        return error;
+    }
+
+    for (i = 0; i < stats.max_miss_queue + stats.max_action_queue + stats.max_sflow_queue; i++) {
+        struct wdp_packet packet;
+
+        error = wdp_recv(wdp, &packet);
+        if (error) {
+            return error == EAGAIN ? 0 : error;
+        }
+        ofpbuf_delete(packet.payload);
+    }
+    return 0;
+}
+
+/* Arranges for the poll loop to wake up when 'wdp' has a message queued to be
+ * received with wdp_recv(). */
+void
+wdp_recv_wait(struct wdp *wdp)
+{
+    wdp->wdp_class->recv_wait(wdp);
+}
+
+/* Obtains the NetFlow engine type and engine ID for 'wdp' into '*engine_type'
+ * and '*engine_id', respectively. */
+void
+wdp_get_netflow_ids(const struct wdp *wdp,
+                    uint8_t *engine_type, uint8_t *engine_id)
+{
+    *engine_type = wdp->netflow_engine_type;
+    *engine_id = wdp->netflow_engine_id;
+}
+\f
+/* Returns a copy of 'old'.  The packet's payload, if any, is copied as well,
+ * but if it is longer than 'trim' bytes it is truncated to that length. */
+struct wdp_packet *
+wdp_packet_clone(const struct wdp_packet *old, size_t trim)
+{
+    struct wdp_packet *new = xmemdup(old, sizeof *old);
+    if (old->payload) {
+        new->payload = ofpbuf_clone_data(old->payload->data,
+                                         MIN(trim, old->payload->size));
+    }
+    return new;
+}
+
+void
+wdp_packet_destroy(struct wdp_packet *packet)
+{
+    if (packet) {
+        ofpbuf_delete(packet->payload);
+        free(packet);
+    }
+}
+
+void
+wdp_init(struct wdp *wdp, const struct wdp_class *wdp_class,
+         const char *name,
+         uint8_t netflow_engine_type, uint8_t netflow_engine_id)
+{
+    wdp->wdp_class = wdp_class;
+    wdp->base_name = xstrdup(name);
+    wdp->full_name = xasprintf("%s@%s", wdp_class->type, name);
+    wdp->netflow_engine_type = netflow_engine_type;
+    wdp->netflow_engine_id = netflow_engine_id;
+}
+
+/* Undoes the results of initialization.
+ *
+ * Normally this function only needs to be called from wdp_close().
+ * However, it may be called by providers due to an error on opening
+ * that occurs after initialization.  It this case wdp_close() would
+ * never be called. */
+void
+wdp_uninit(struct wdp *wdp, bool close)
+{
+    char *base_name = wdp->base_name;
+    char *full_name = wdp->full_name;
+
+    if (close) {
+        wdp->wdp_class->close(wdp);
+    }
+
+    free(base_name);
+    free(full_name);
+}
+\f
+static void
+log_operation(const struct wdp *wdp, const char *operation, int error)
+{
+    if (!error) {
+        VLOG_DBG_RL(&wdpmsg_rl, "%s: %s success", wdp_name(wdp), operation);
+    } else {
+        VLOG_WARN_RL(&error_rl, "%s: %s failed (%s)",
+                     wdp_name(wdp), operation, strerror(error));
+    }
+}
diff --git a/ofproto/wdp.h b/ofproto/wdp.h
new file mode 100644 (file)
index 0000000..0b90bd4
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 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.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WDP_H
+#define WDP_H 1
+
+#include "classifier.h"
+#include "list.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+struct ofpbuf;
+struct svec;
+struct wdp;
+struct wdp_class;
+union ofp_action;
+
+struct wdp_table_stats {
+    /* Flows. */
+    unsigned int n_flows;       /* Number of flows in table. */
+    unsigned int cur_capacity;  /* Current flow table capacity. */
+    unsigned int max_capacity;  /* Maximum expansion of flow table capacity. */
+
+    /* Lookups. */
+    unsigned long long int n_hit;    /* Number of flow table matches. */
+    unsigned long long int n_missed; /* Number of flow table misses. */
+    unsigned long long int n_lost;   /* Misses dropped due to buffer limits. */
+};
+
+struct wdp_stats {
+    struct wdp_table_stats exact;
+    struct wdp_table_stats wild;
+
+    /* Ports. */
+    unsigned int n_ports;       /* Current number of ports. */
+    unsigned int max_ports;     /* Maximum supported number of ports. */
+
+    /* Lookups. */
+    unsigned long long int n_frags;  /* Number of dropped IP fragments. */
+
+    /* Queues. */
+    unsigned int max_miss_queue;   /* Max length of WDP_CHAN_MISS queue. */
+    unsigned int max_action_queue; /* Max length of WDP_CHAN_ACTION queue. */
+    unsigned int max_sflow_queue;  /* Max length of WDP_CHAN_SFLOW queue. */
+};
+
+struct wdp_rule {
+    struct cls_rule cr;
+
+    long long int created;      /* Time created, in ms since the epoch. */
+    uint16_t idle_timeout;      /* In seconds from time of last use. */
+    uint16_t hard_timeout;      /* In seconds from time of creation. */
+
+    /* OpenFlow actions.
+     *
+     * 'n_actions' is the number of elements in the 'actions' array.  A single
+     * action may take up more more than one element's worth of space.
+     *
+     * A subrule has no actions (it uses the super-rule's actions). */
+    union ofp_action *actions;  /* OpenFlow actions. */
+    int n_actions;              /* Number of elements in 'actions' array. */
+
+    void *client_data;
+};
+
+void wdp_rule_init(struct wdp_rule *, const union ofp_action *actions,
+                     size_t n_actions);
+void wdp_rule_uninit(struct wdp_rule *);
+\f
+void wdp_run(void);
+void wdp_wait(void);
+
+int wdp_register_provider(const struct wdp_class *);
+int wdp_unregister_provider(const char *type);
+void wdp_enumerate_types(struct svec *types);
+
+int wdp_enumerate_names(const char *type, struct svec *names);
+void wdp_parse_name(const char *datapath_name, char **name, char **type);
+
+void wdp_run_expiration(struct wdp *);
+void wdp_run_revalidation(struct wdp *, bool revalidate_all);
+
+int wdp_open(const char *name, const char *type, struct wdp **);
+int wdp_create(const char *name, const char *type, struct wdp **);
+int wdp_create_and_open(const char *name, const char *type, struct wdp **);
+void wdp_close(struct wdp *);
+
+const char *wdp_name(const struct wdp *);
+const char *wdp_base_name(const struct wdp *);
+int wdp_get_all_names(const struct wdp *, struct svec *);
+
+int wdp_delete(struct wdp *);
+
+int wdp_get_features(const struct wdp *, struct ofpbuf **featuresp);
+int wdp_get_wdp_stats(const struct wdp *, struct wdp_stats *);
+
+int wdp_get_drop_frags(const struct wdp *, bool *drop_frags);
+int wdp_set_drop_frags(struct wdp *, bool drop_frags);
+
+struct wdp_port {
+    struct netdev *netdev;
+    struct ofp_phy_port opp;    /* In *host* byte order. */
+    char *devname;              /* Network device name. */
+    bool internal;
+};
+void wdp_port_clear(struct wdp_port *);
+void wdp_port_copy(struct wdp_port *, const struct wdp_port *);
+void wdp_port_free(struct wdp_port *);
+void wdp_port_array_free(struct wdp_port *, size_t n);
+
+int wdp_port_add(struct wdp *, const char *devname, bool internal,
+                   uint16_t *port_no);
+int wdp_port_del(struct wdp *, uint16_t port_no);
+int wdp_port_query_by_number(const struct wdp *, uint16_t port_no,
+                             struct wdp_port *);
+int wdp_port_query_by_name(const struct wdp *, const char *devname,
+                           struct wdp_port *);
+int wdp_port_get_name(struct wdp *, uint16_t port_no, char **namep);
+int wdp_port_list(const struct wdp *, struct wdp_port **, size_t *n_ports);
+
+int wdp_port_set_config(struct wdp *, uint16_t port_no, uint32_t config);
+
+int wdp_port_poll(const struct wdp *, char **devnamep);
+void wdp_port_poll_wait(const struct wdp *);
+
+int wdp_flow_flush(struct wdp *);
+
+struct wdp_flow_stats {
+    unsigned long long int n_packets; /* Number of matched packets. */
+    unsigned long long int n_bytes;   /* Number of matched bytes. */
+    long long int inserted;           /* Time inserted into flow table. */
+    long long int used;               /* Time last used. */
+    uint8_t tcp_flags;                /* Bitwise-OR of TCP flags seen. */
+    uint8_t ip_tos;                   /* IP TOS for most recent packet. */
+};
+
+/* Finding and inspecting flows. */
+struct wdp_rule *wdp_flow_get(struct wdp *, const flow_t *);
+struct wdp_rule *wdp_flow_match(struct wdp *, const flow_t *);
+
+typedef void wdp_flow_cb_func(struct wdp_rule *, void *aux);
+void wdp_flow_for_each_match(const struct wdp *, const flow_t *,
+                               int include, wdp_flow_cb_func *, void *aux);
+
+int wdp_flow_get_stats(const struct wdp *, const struct wdp_rule *,
+                         struct wdp_flow_stats *);
+bool wdp_flow_overlaps(const struct wdp *, const flow_t *);
+
+/* Modifying flows. */
+enum wdp_flow_put_flags {
+    /* At least one of these flags should be set. */
+    WDP_PUT_CREATE = 1 << 0,    /* Allow creating a new flow. */
+    WDP_PUT_MODIFY = 1 << 1,    /* Allow modifying an existing flow. */
+
+    /* Options used only for modifying existing flows. */
+    WDP_PUT_COUNTERS = 1 << 2,  /* Clear counters, TCP flags, IP TOS, used. */
+    WDP_PUT_ACTIONS = 1 << 3,   /* Update actions. */
+    WDP_PUT_INSERTED = 1 << 4,  /* Update 'inserted' to current time. */
+    WDP_PUT_TIMEOUTS = 1 << 5,  /* Update 'idle_timeout' and 'hard_timeout'. */
+    WDP_PUT_ALL = (WDP_PUT_COUNTERS | WDP_PUT_ACTIONS
+                   | WDP_PUT_INSERTED | WDP_PUT_TIMEOUTS)
+};
+
+struct wdp_flow_put {
+    enum wdp_flow_put_flags flags;
+
+    const flow_t *flow;
+
+    const union ofp_action *actions;
+    size_t n_actions;
+
+    unsigned short int idle_timeout;
+    unsigned short int hard_timeout;
+};
+
+int wdp_flow_put(struct wdp *, struct wdp_flow_put *,
+                   struct wdp_flow_stats *old_stats,
+                   struct wdp_rule **rulep);
+int wdp_flow_delete(struct wdp *, struct wdp_rule *,
+                      struct wdp_flow_stats *final_stats);
+
+/* Sending packets in flows. */
+int wdp_flow_inject(struct wdp *, struct wdp_rule *,
+                      uint16_t in_port, const struct ofpbuf *);
+int wdp_execute(struct wdp *, uint16_t in_port,
+                  const union ofp_action[], size_t n_actions,
+                  const struct ofpbuf *);
+
+/* Receiving packets that miss the flow table. */
+enum wdp_channel {
+    WDP_CHAN_MISS,              /* Packet missed in flow table. */
+    WDP_CHAN_ACTION,            /* Packet output to OFPP_CONTROLLER. */
+    WDP_CHAN_SFLOW,             /* sFlow samples. */
+    WDP_N_CHANS
+};
+
+struct wdp_packet {
+    struct list list;
+    enum wdp_channel channel;
+    uint32_t tun_id;
+    uint16_t in_port;
+    int send_len;
+    struct ofpbuf *payload;
+};
+
+struct wdp_packet *wdp_packet_clone(const struct wdp_packet *, size_t);
+void wdp_packet_destroy(struct wdp_packet *);
+
+int wdp_recv_get_mask(const struct wdp *, int *listen_mask);
+int wdp_recv_set_mask(struct wdp *, int listen_mask);
+int wdp_get_sflow_probability(const struct wdp *, uint32_t *probability);
+int wdp_set_sflow_probability(struct wdp *, uint32_t probability);
+int wdp_recv(struct wdp *, struct wdp_packet *);
+int wdp_recv_purge(struct wdp *);
+void wdp_recv_wait(struct wdp *);
+
+void wdp_get_netflow_ids(const struct wdp *,
+                           uint8_t *engine_type, uint8_t *engine_id);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* wdp.h */
index ebf2a01..639a23e 100644 (file)
@@ -8,6 +8,7 @@ TESTSUITE_AT = \
        tests/testsuite.at \
        tests/ovsdb-macros.at \
        tests/library.at \
+       tests/classifier.at \
        tests/check-structs.at \
        tests/daemon.at \
        tests/vconn.at \
@@ -170,7 +171,9 @@ tests_test_aes128_SOURCES = tests/test-aes128.c
 tests_test_aes128_LDADD = lib/libopenvswitch.a
 
 noinst_PROGRAMS += tests/test-classifier
-tests_test_classifier_SOURCES = tests/test-classifier.c
+tests_test_classifier_SOURCES = \
+       tests/test-classifier.c \
+       tests/test-command-line.c
 tests_test_classifier_LDADD = lib/libopenvswitch.a
 
 noinst_PROGRAMS += tests/test-csum
diff --git a/tests/classifier.at b/tests/classifier.at
new file mode 100644 (file)
index 0000000..a03ed45
--- /dev/null
@@ -0,0 +1,18 @@
+AT_BANNER([classifier unit tests])
+
+m4_define([CHECK_CLASSIFIER],
+  [AT_SETUP([m4_translit([$1], [-], [ ])])
+   AT_KEYWORDS([classifier $2])
+   AT_CHECK([test-classifier $1])
+   AT_CLEANUP])
+
+CHECK_CLASSIFIER([empty])
+CHECK_CLASSIFIER([destroy-null])
+CHECK_CLASSIFIER([single-rule], [slow])
+CHECK_CLASSIFIER([rule-replacement], [slow])
+CHECK_CLASSIFIER([two-rules-in-one-bucket])
+CHECK_CLASSIFIER([two-rules-in-one-table])
+CHECK_CLASSIFIER([two-rules-in-different-tables])
+CHECK_CLASSIFIER([many-rules-in-one-bucket], [slow])
+CHECK_CLASSIFIER([many-rules-in-one-table], [slow])
+CHECK_CLASSIFIER([many-rules-in-different-tables], [slow])
index 0e408f0..f9f97f1 100644 (file)
@@ -10,11 +10,6 @@ AT_SETUP([test TCP/IP checksumming])
 AT_CHECK([test-csum], [0], [ignore])
 AT_CLEANUP
 
-AT_SETUP([test flow classifier])
-AT_KEYWORDS([slow])
-AT_CHECK([test-classifier], [0], [ignore])
-AT_CLEANUP
-
 AT_SETUP([test hash functions])
 AT_CHECK([test-hash], [0], [ignore])
 AT_CLEANUP
index c831559..b9032cf 100644 (file)
 #include "classifier.h"
 #include <errno.h>
 #include <limits.h>
+#include "command-line.h"
 #include "flow.h"
 #include <limits.h>
 #include "packets.h"
+#include "test-command-line.h"
 
 #undef NDEBUG
 #include <assert.h>
@@ -84,7 +86,7 @@ tcls_count_exact(const struct tcls *tcls)
 
     n_exact = 0;
     for (i = 0; i < tcls->n_rules; i++) {
-        n_exact += tcls->rules[i]->cls_rule.wc.wildcards == 0;
+        n_exact += tcls->rules[i]->cls_rule.flow.wildcards == 0;
     }
     return n_exact;
 }
@@ -100,18 +102,18 @@ tcls_insert(struct tcls *tcls, const struct test_rule *rule)
 {
     size_t i;
 
-    assert(rule->cls_rule.wc.wildcards || rule->cls_rule.priority == UINT_MAX);
+    assert(rule->cls_rule.flow.wildcards || rule->cls_rule.flow.priority == UINT_MAX);
     for (i = 0; i < tcls->n_rules; i++) {
         const struct cls_rule *pos = &tcls->rules[i]->cls_rule;
-        if (pos->priority == rule->cls_rule.priority
-            && pos->wc.wildcards == rule->cls_rule.wc.wildcards
+        if (pos->flow.priority == rule->cls_rule.flow.priority
+            && pos->flow.wildcards == rule->cls_rule.flow.wildcards
             && flow_equal(&pos->flow, &rule->cls_rule.flow)) {
             /* Exact match.
              * XXX flow_equal should ignore wildcarded fields */
             free(tcls->rules[i]);
             tcls->rules[i] = xmemdup(rule, sizeof *rule);
             return tcls->rules[i];
-        } else if (pos->priority < rule->cls_rule.priority) {
+        } else if (pos->flow.priority < rule->cls_rule.flow.priority) {
             break;
         }
     }
@@ -165,18 +167,18 @@ match(const struct cls_rule *wild, const flow_t *fixed)
         void *wild_field = (char *) &wild->flow + f->ofs;
         void *fixed_field = (char *) fixed + f->ofs;
 
-        if ((wild->wc.wildcards & f->wildcards) == f->wildcards ||
+        if ((wild->flow.wildcards & f->wildcards) == f->wildcards ||
             !memcmp(wild_field, fixed_field, f->len)) {
             /* Definite match. */
             continue;
         }
 
-        if (wild->wc.wildcards & f->wildcards) {
+        if (wild->flow.wildcards & f->wildcards) {
             uint32_t test = read_uint32(wild_field);
             uint32_t ip = read_uint32(fixed_field);
             int shift = (f_idx == CLS_F_IDX_NW_SRC
                          ? OFPFW_NW_SRC_SHIFT : OFPFW_NW_DST_SHIFT);
-            uint32_t mask = flow_nw_bits_to_mask(wild->wc.wildcards, shift);
+            uint32_t mask = flow_nw_bits_to_mask(wild->flow.wildcards, shift);
             if (!((test ^ ip) & mask)) {
                 continue;
             }
@@ -194,7 +196,7 @@ tcls_lookup(const struct tcls *cls, const flow_t *flow, int include)
 
     for (i = 0; i < cls->n_rules; i++) {
         struct test_rule *pos = cls->rules[i];
-        uint32_t wildcards = pos->cls_rule.wc.wildcards;
+        uint32_t wildcards = pos->cls_rule.flow.wildcards;
         if (include & (wildcards ? CLS_INC_WILD : CLS_INC_EXACT)
             && match(&pos->cls_rule, flow)) {
             return &pos->cls_rule;
@@ -212,7 +214,7 @@ tcls_delete_matches(struct tcls *cls,
 
     for (i = 0; i < cls->n_rules; ) {
         struct test_rule *pos = cls->rules[i];
-        uint32_t wildcards = pos->cls_rule.wc.wildcards;
+        uint32_t wildcards = pos->cls_rule.flow.wildcards;
         if (include & (wildcards ? CLS_INC_WILD : CLS_INC_EXACT)
             && match(target, &pos->cls_rule.flow)) {
             tcls_remove(cls, pos);
@@ -380,7 +382,6 @@ compare_classifiers(struct classifier *cls, struct tcls *tcls)
                ETH_ADDR_LEN);
         flow.nw_proto = nw_proto_values[get_value(&x, N_NW_PROTO_VALUES)];
         flow.nw_tos = nw_tos_values[get_value(&x, N_NW_TOS_VALUES)];
-        memset(flow.reserved, 0, sizeof flow.reserved);
 
         for (include = 1; include <= 3; include++) {
             cr0 = lookup_with_include_bits(cls, &flow, include);
@@ -391,10 +392,10 @@ compare_classifiers(struct classifier *cls, struct tcls *tcls)
                 const struct test_rule *tr1 = test_rule_from_cls_rule(cr1);
 
                 assert(flow_equal(&cr0->flow, &cr1->flow));
-                assert(cr0->wc.wildcards == cr1->wc.wildcards);
-                assert(cr0->priority == cr1->priority);
-                /* Skip nw_src_mask and nw_dst_mask, because they are derived
-                 * members whose values are used only for optimization. */
+                assert(cr0->flow.wildcards == cr1->flow.wildcards);
+                assert(cr0->flow.priority == cr1->flow.priority);
+                /* Skip nw_src_mask, nw_dst_mask, and dl_tci_mask, because they
+                 * are derived members used only for optimization. */
                 assert(tr0->aux == tr1->aux);
             }
         }
@@ -453,15 +454,14 @@ make_rule(int wc_fields, unsigned int priority, int value_pat)
 {
     const struct cls_field *f;
     struct test_rule *rule;
-    uint32_t wildcards;
     flow_t flow;
 
-    wildcards = 0;
     memset(&flow, 0, sizeof flow);
+    flow.priority = priority;
     for (f = &cls_fields[0]; f < &cls_fields[CLS_N_FIELDS]; f++) {
         int f_idx = f - cls_fields;
         if (wc_fields & (1u << f_idx)) {
-            wildcards |= f->wildcards;
+            flow.wildcards |= f->wildcards;
         } else {
             int value_idx = (value_pat & (1u << f_idx)) != 0;
             memcpy((char *) &flow + f->ofs, values[f_idx][value_idx], f->len);
@@ -469,8 +469,7 @@ make_rule(int wc_fields, unsigned int priority, int value_pat)
     }
 
     rule = xzalloc(sizeof *rule);
-    cls_rule_from_flow(&flow, wildcards, !wildcards ? UINT_MAX : priority,
-                       &rule->cls_rule);
+    cls_rule_from_flow(&flow, &rule->cls_rule);
     return rule;
 }
 
@@ -487,7 +486,7 @@ shuffle(unsigned int *p, size_t n)
 \f
 /* Tests an empty classifier. */
 static void
-test_empty(void)
+test_empty(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     struct classifier cls;
     struct tcls tcls;
@@ -503,14 +502,14 @@ test_empty(void)
 
 /* Destroys a null classifier. */
 static void
-test_destroy_null(void)
+test_destroy_null(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     classifier_destroy(NULL);
 }
 
 /* Tests classification with one rule at a time. */
 static void
-test_single_rule(void)
+test_single_rule(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     unsigned int wc_fields;     /* Hilarious. */
 
@@ -548,7 +547,7 @@ test_single_rule(void)
 
 /* Tests replacing one rule by another. */
 static void
-test_rule_replacement(void)
+test_rule_replacement(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     unsigned int wc_fields;
 
@@ -599,7 +598,7 @@ random_wcf_in_table(int table, int seed)
 /* Tests classification with two rules at a time that fall into the same
  * bucket. */
 static void
-test_two_rules_in_one_bucket(void)
+test_two_rules_in_one_bucket(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     int table, rel_pri, wcf_pat, value_pat;
 
@@ -688,7 +687,7 @@ test_two_rules_in_one_bucket(void)
 /* Tests classification with two rules at a time that fall into the same
  * table but different buckets. */
 static void
-test_two_rules_in_one_table(void)
+test_two_rules_in_one_table(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     int table, rel_pri, wcf_pat;
 
@@ -764,7 +763,7 @@ test_two_rules_in_one_table(void)
 /* Tests classification with two rules at a time that fall into different
  * tables. */
 static void
-test_two_rules_in_different_tables(void)
+test_two_rules_in_different_tables(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     int table1, table2, rel_pri, wcf_pat;
 
@@ -833,7 +832,7 @@ test_two_rules_in_different_tables(void)
 /* Tests classification with many rules at a time that fall into the same
  * bucket but have unique priorities (and various wildcards). */
 static void
-test_many_rules_in_one_bucket(void)
+test_many_rules_in_one_bucket(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     enum { MAX_RULES = 50 };
     int iteration, table;
@@ -877,7 +876,7 @@ test_many_rules_in_one_bucket(void)
 /* Tests classification with many rules at a time that fall into the same
  * table but random buckets. */
 static void
-test_many_rules_in_one_table(void)
+test_many_rules_in_one_table(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     enum { MAX_RULES = 50 };
     int iteration, table;
@@ -920,7 +919,8 @@ test_many_rules_in_one_table(void)
 /* Tests classification with many rules at a time that fall into random buckets
  * in random tables. */
 static void
-test_many_rules_in_different_tables(void)
+test_many_rules_in_different_tables(int argc OVS_UNUSED,
+                                    char *argv[] OVS_UNUSED)
 {
     enum { MAX_RULES = 50 };
     int iteration;
@@ -957,44 +957,43 @@ test_many_rules_in_different_tables(void)
             struct test_rule *rule = xmemdup(tcls.rules[rand() % tcls.n_rules],
                                              sizeof(struct test_rule));
             int include = rand() % 2 ? CLS_INC_WILD : CLS_INC_EXACT;
-            include |= (rule->cls_rule.wc.wildcards
+            include |= (rule->cls_rule.flow.wildcards
                         ? CLS_INC_WILD : CLS_INC_EXACT);
-            classifier_for_each_match(&cls, &rule->cls_rule, include,
+            classifier_for_each_match(&cls, &rule->cls_rule.flow, include,
                                       free_rule, &cls);
             tcls_delete_matches(&tcls, &rule->cls_rule, include);
             compare_classifiers(&cls, &tcls);
             free(rule);
         }
-        putchar('.');
-        fflush(stdout);
 
         destroy_classifier(&cls);
         tcls_destroy(&tcls);
     }
 }
 \f
-static void
-run_test(void (*function)(void))
-{
-    function();
-    putchar('.');
-    fflush(stdout);
-}
-
 int
-main(void)
-{
+main(int argc, char *argv[])
+{
+    static const struct command all_commands[] = {
+        { "empty", 0, 0, test_empty },
+        { "destroy-null", 0, 0, test_destroy_null },
+        { "single-rule", 0, 0, test_single_rule },
+        { "rule-replacement", 0, 0, test_rule_replacement },
+        { "two-rules-in-one-bucket", 0, 0, test_two_rules_in_one_bucket },
+        { "two-rules-in-one-table", 0, 0, test_two_rules_in_one_table },
+        { "two-rules-in-different-tables", 0, 0,
+          test_two_rules_in_different_tables },
+        { "many-rules-in-one-bucket", 0, 0,
+          test_many_rules_in_one_bucket },
+        { "many-rules-in-one-table", 0, 0, test_many_rules_in_one_table },
+        { "many-rules-in-different-tables", 0, 0,
+          test_many_rules_in_different_tables },
+        { NULL, 0, 0, NULL },
+    };
+
+    set_program_name(argv[0]);
     init_values();
-    run_test(test_empty);
-    run_test(test_destroy_null);
-    run_test(test_single_rule);
-    run_test(test_rule_replacement);
-    run_test(test_two_rules_in_one_bucket);
-    run_test(test_two_rules_in_one_table);
-    run_test(test_two_rules_in_different_tables);
-    run_test(test_many_rules_in_one_bucket);
-    run_test(test_many_rules_in_one_table);
-    run_test(test_many_rules_in_different_tables);
-    putchar('\n');
+    parse_test_options(argc, argv, all_commands);
+    run_command(argc - 1, argv + 1, all_commands);
     return 0;
 }
diff --git a/tests/test-command-line.c b/tests/test-command-line.c
new file mode 100644 (file)
index 0000000..369828f
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 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.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "test-command-line.h"
+#include <getopt.h>
+#include <limits.h>
+#include <stdlib.h>
+#include "command-line.h"
+#include "timeval.h"
+#include "util.h"
+#include "vlog.h"
+
+static void
+test_usage(const struct command commands[])
+{
+    const struct command *p;
+
+    printf("%s: an Open vSwitch test utility\n"
+           "usage: %s [OPTIONS] COMMAND [ARG...]\n\n"
+           "Valid commands:\n" ,
+           program_name, program_name);
+
+    for (p = commands; p->name; p++) {
+        int i;
+
+        printf("  %s", p->name);
+        for (i = 0; i < p->min_args; i++) {
+            printf(" ARG%d", i + 1);
+        }
+        if (p->max_args == INT_MAX) {
+            printf(" [ARG...]");
+        } else if (p->max_args > p->min_args) {
+            for (i = p->min_args; i < p->max_args; i++) {
+                putchar(' ');
+                if (i == p->min_args) {
+                    putchar('[');
+                }
+                printf("ARG%d", i + 1);
+            }
+            putchar(']');
+        }
+        putchar('\n');
+    }
+    vlog_usage();
+    printf("\nOther options:\n"
+           "  -t, --timeout=SECS          give up after SECS seconds\n"
+           "  -h, --help                  display this help message\n");
+    exit(EXIT_SUCCESS);
+}
+
+/* Parses options for test programs that don't have any special needs.
+ * Prints --help output based on 'commands'. */
+void
+parse_test_options(int argc, char *argv[],
+                   const struct command commands[])
+{
+    static struct option long_options[] = {
+        {"timeout", required_argument, 0, 't'},
+        {"verbose", optional_argument, 0, 'v'},
+        {"help", no_argument, 0, 'h'},
+        {0, 0, 0, 0},
+    };
+    char *short_options = long_options_to_short_options(long_options);
+
+    for (;;) {
+        unsigned long int timeout;
+        int c;
+
+        c = getopt_long(argc, argv, short_options, long_options, NULL);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+        case 't':
+            timeout = strtoul(optarg, NULL, 10);
+            if (timeout <= 0) {
+                ovs_fatal(0, "value %s on -t or --timeout is not at least 1",
+                          optarg);
+            } else {
+                time_alarm(timeout);
+            }
+            break;
+
+        case 'h':
+            test_usage(commands);
+
+        case 'v':
+            vlog_set_verbosity(optarg);
+            break;
+
+        case '?':
+            exit(EXIT_FAILURE);
+
+        default:
+            abort();
+        }
+    }
+    free(short_options);
+}
+
diff --git a/tests/test-command-line.h b/tests/test-command-line.h
new file mode 100644 (file)
index 0000000..908ff76
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 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.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TEST_COMMAND_LINE_H
+#define TEST_COMMAND_LINE_H 1
+
+/* Utilities for command-line parsing for test utilities. */
+
+#include "compiler.h"
+
+struct command;
+
+void parse_test_options(int argc, char *argv[], const struct command *);
+
+#endif /* command-line.h */
index 424dd7b..a9d1f0a 100644 (file)
@@ -68,7 +68,7 @@ main(int argc OVS_UNUSED, char *argv[])
         }
 
         flow_extract(packet, 0, 1, &flow);
-        flow_to_match(&flow, 0, false, &extracted_match);
+        flow_to_match(&flow, false, &extracted_match);
 
         if (memcmp(&expected_match, &extracted_match, sizeof expected_match)) {
             char *exp_s = ofp_match_to_string(&expected_match, 2);
index f4e80ca..5699e3c 100644 (file)
@@ -38,6 +38,7 @@ m4_define([OVS_WAIT_WHILE], [OVS_WAIT([if $1; then :; else exit 0; fi], [$2])])
 m4_include([tests/ovsdb-macros.at])
 
 m4_include([tests/library.at])
+m4_include([tests/classifier.at])
 m4_include([tests/check-structs.at])
 m4_include([tests/daemon.at])
 m4_include([tests/vconn.at])
index 752a447..7977080 100644 (file)
@@ -29,7 +29,7 @@ Do not use \fBovs\-dpctl\fR commands to modify datapaths if
 Most \fBovs\-dpctl\fR commands that work with datapaths take an argument
 that specifies the name of the datapath, in one of the following
 forms:
-.so lib/dpif.man
+.so lib/xfif.man
 .PP
 The following commands manage datapaths.
 .
index ecfb306..c4937a3 100644 (file)
 #include "command-line.h"
 #include "compiler.h"
 #include "dirs.h"
-#include "dpif.h"
 #include "dynamic-string.h"
 #include "netdev.h"
-#include "odp-util.h"
+#include "xflow-util.h"
 #include "svec.h"
 #include "timeval.h"
 #include "util.h"
+#include "xfif.h"
 
 #include "vlog.h"
 #define THIS_MODULE VLM_dpctl
@@ -177,17 +177,17 @@ static int if_up(const char *netdev_name)
 }
 
 static int
-parsed_dpif_open(const char *arg_, bool create, struct dpif **dpifp)
+parsed_xfif_open(const char *arg_, bool create, struct xfif **xfifp)
 {
     int result;
     char *name, *type;
 
-    dp_parse_name(arg_, &name, &type);
+    xf_parse_name(arg_, &name, &type);
 
     if (create) {
-        result = dpif_create(name, type, dpifp);
+        result = xfif_create(name, type, xfifp);
     } else {
-        result = dpif_open(name, type, dpifp);
+        result = xfif_open(name, type, xfifp);
     }
 
     free(name);
@@ -198,9 +198,9 @@ parsed_dpif_open(const char *arg_, bool create, struct dpif **dpifp)
 static void
 do_add_dp(int argc OVS_UNUSED, char *argv[])
 {
-    struct dpif *dpif;
-    run(parsed_dpif_open(argv[1], true, &dpif), "add_dp");
-    dpif_close(dpif);
+    struct xfif *xfif;
+    run(parsed_xfif_open(argv[1], true, &xfif), "add_dp");
+    xfif_close(xfif);
     if (argc > 2) {
         do_add_if(argc, argv);
     }
@@ -209,24 +209,24 @@ do_add_dp(int argc OVS_UNUSED, char *argv[])
 static void
 do_del_dp(int argc OVS_UNUSED, char *argv[])
 {
-    struct dpif *dpif;
-    run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
-    run(dpif_delete(dpif), "del_dp");
-    dpif_close(dpif);
+    struct xfif *xfif;
+    run(parsed_xfif_open(argv[1], false, &xfif), "opening datapath");
+    run(xfif_delete(xfif), "del_dp");
+    xfif_close(xfif);
 }
 
 static int
 compare_ports(const void *a_, const void *b_)
 {
-    const struct odp_port *a = a_;
-    const struct odp_port *b = b_;
+    const struct xflow_port *a = a_;
+    const struct xflow_port *b = b_;
     return a->port < b->port ? -1 : a->port > b->port;
 }
 
 static void
-query_ports(struct dpif *dpif, struct odp_port **ports, size_t *n_ports)
+query_ports(struct xfif *xfif, struct xflow_port **ports, size_t *n_ports)
 {
-    run(dpif_port_list(dpif, ports, n_ports), "listing ports");
+    run(xfif_port_list(xfif, ports, n_ports), "listing ports");
     qsort(*ports, *n_ports, sizeof **ports, compare_ports);
 }
 
@@ -234,10 +234,10 @@ static void
 do_add_if(int argc OVS_UNUSED, char *argv[])
 {
     bool failure = false;
-    struct dpif *dpif;
+    struct xfif *xfif;
     int i;
 
-    run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
+    run(parsed_xfif_open(argv[1], false, &xfif), "opening datapath");
     for (i = 2; i < argc; i++) {
         char *save_ptr = NULL;
         char *devname, *suboptions;
@@ -264,7 +264,7 @@ do_add_if(int argc OVS_UNUSED, char *argv[])
 
                 switch (getsubopt(&suboptions, options, &value)) {
                 case AP_INTERNAL:
-                    flags |= ODP_PORT_INTERNAL;
+                    flags |= XFLOW_PORT_INTERNAL;
                     break;
 
                 default:
@@ -274,7 +274,7 @@ do_add_if(int argc OVS_UNUSED, char *argv[])
             }
         }
 
-        error = dpif_port_add(dpif, devname, flags, NULL);
+        error = xfif_port_add(xfif, devname, flags, NULL);
         if (error) {
             ovs_error(error, "adding %s to %s failed", devname, argv[1]);
             failure = true;
@@ -282,20 +282,20 @@ do_add_if(int argc OVS_UNUSED, char *argv[])
             failure = true;
         }
     }
-    dpif_close(dpif);
+    xfif_close(xfif);
     if (failure) {
         exit(EXIT_FAILURE);
     }
 }
 
 static bool
-get_port_number(struct dpif *dpif, const char *name, uint16_t *port)
+get_port_number(struct xfif *xfif, const char *name, uint16_t *port)
 {
-    struct odp_port *ports;
+    struct xflow_port *ports;
     size_t n_ports;
     size_t i;
 
-    query_ports(dpif, &ports, &n_ports);
+    query_ports(xfif, &ports, &n_ports);
     for (i = 0; i < n_ports; i++) {
         if (!strcmp(name, ports[i].devname)) {
             *port = ports[i].port;
@@ -312,10 +312,10 @@ static void
 do_del_if(int argc OVS_UNUSED, char *argv[])
 {
     bool failure = false;
-    struct dpif *dpif;
+    struct xfif *xfif;
     int i;
 
-    run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
+    run(parsed_xfif_open(argv[1], false, &xfif), "opening datapath");
     for (i = 2; i < argc; i++) {
         const char *name = argv[i];
         uint16_t port;
@@ -323,33 +323,33 @@ do_del_if(int argc OVS_UNUSED, char *argv[])
 
         if (!name[strspn(name, "0123456789")]) {
             port = atoi(name);
-        } else if (!get_port_number(dpif, name, &port)) {
+        } else if (!get_port_number(xfif, name, &port)) {
             failure = true;
             continue;
         }
 
-        error = dpif_port_del(dpif, port);
+        error = xfif_port_del(xfif, port);
         if (error) {
             ovs_error(error, "deleting port %s from %s failed", name, argv[1]);
             failure = true;
         }
     }
-    dpif_close(dpif);
+    xfif_close(xfif);
     if (failure) {
         exit(EXIT_FAILURE);
     }
 }
 
 static void
-show_dpif(struct dpif *dpif)
+show_xfif(struct xfif *xfif)
 {
-    struct odp_port *ports;
-    struct odp_stats stats;
+    struct xflow_port *ports;
+    struct xflow_stats stats;
     size_t n_ports;
     size_t i;
 
-    printf("%s:\n", dpif_name(dpif));
-    if (!dpif_get_dp_stats(dpif, &stats)) {
+    printf("%s:\n", xfif_name(xfif));
+    if (!xfif_get_xf_stats(xfif, &stats)) {
         printf("\tflows: cur:%"PRIu32", soft-max:%"PRIu32", "
                "hard-max:%"PRIu32"\n",
                stats.n_flows, stats.cur_capacity, stats.max_capacity);
@@ -364,16 +364,16 @@ show_dpif(struct dpif *dpif)
         printf("\tqueues: max-miss:%"PRIu16", max-action:%"PRIu16"\n",
                stats.max_miss_queue, stats.max_action_queue);
     }
-    query_ports(dpif, &ports, &n_ports);
+    query_ports(xfif, &ports, &n_ports);
     for (i = 0; i < n_ports; i++) {
         printf("\tport %u: %s", ports[i].port, ports[i].devname);
-        if (ports[i].flags & ODP_PORT_INTERNAL) {
+        if (ports[i].flags & XFLOW_PORT_INTERNAL) {
             printf(" (internal)");
         }
         printf("\n");
     }
     free(ports);
-    dpif_close(dpif);
+    xfif_close(xfif);
 }
 
 static void
@@ -384,12 +384,12 @@ do_show(int argc, char *argv[])
         int i;
         for (i = 1; i < argc; i++) {
             const char *name = argv[i];
-            struct dpif *dpif;
+            struct xfif *xfif;
             int error;
 
-            error = parsed_dpif_open(name, false, &dpif);
+            error = parsed_xfif_open(name, false, &xfif);
             if (!error) {
-                show_dpif(dpif);
+                show_xfif(xfif);
             } else {
                 ovs_error(error, "opening datapath %s failed", name);
                 failure = true;
@@ -397,15 +397,15 @@ do_show(int argc, char *argv[])
         }
     } else {
         unsigned int i;
-        for (i = 0; i < ODP_MAX; i++) {
+        for (i = 0; i < XFLOW_MAX; i++) {
             char name[128];
-            struct dpif *dpif;
+            struct xfif *xfif;
             int error;
 
             sprintf(name, "dp%u", i);
-            error = parsed_dpif_open(name, false, &dpif);
+            error = parsed_xfif_open(name, false, &xfif);
             if (!error) {
-                show_dpif(dpif);
+                show_xfif(xfif);
             } else if (error != ENODEV) {
                 ovs_error(error, "opening datapath %s failed", name);
                 failure = true;
@@ -420,34 +420,34 @@ do_show(int argc, char *argv[])
 static void
 do_dump_dps(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
-    struct svec dpif_names, dpif_types;
+    struct svec xfif_names, xfif_types;
     unsigned int i;
     int error = 0;
 
-    svec_init(&dpif_names);
-    svec_init(&dpif_types);
-    dp_enumerate_types(&dpif_types);
+    svec_init(&xfif_names);
+    svec_init(&xfif_types);
+    xf_enumerate_types(&xfif_types);
 
-    for (i = 0; i < dpif_types.n; i++) {
+    for (i = 0; i < xfif_types.n; i++) {
         unsigned int j;
         int retval;
 
-        retval = dp_enumerate_names(dpif_types.names[i], &dpif_names);
+        retval = xf_enumerate_names(xfif_types.names[i], &xfif_names);
         if (retval) {
             error = retval;
         }
 
-        for (j = 0; j < dpif_names.n; j++) {
-            struct dpif *dpif;
-            if (!dpif_open(dpif_names.names[j], dpif_types.names[i], &dpif)) {
-                printf("%s\n", dpif_name(dpif));
-                dpif_close(dpif);
+        for (j = 0; j < xfif_names.n; j++) {
+            struct xfif *xfif;
+            if (!xfif_open(xfif_names.names[j], xfif_types.names[i], &xfif)) {
+                printf("%s\n", xfif_name(xfif));
+                xfif_close(xfif);
             }
         }
     }
 
-    svec_destroy(&dpif_names);
-    svec_destroy(&dpif_types);
+    svec_destroy(&xfif_names);
+    svec_destroy(&xfif_types);
     if (error) {
         exit(EXIT_FAILURE);
     }
@@ -456,57 +456,58 @@ do_dump_dps(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 static void
 do_dump_flows(int argc OVS_UNUSED, char *argv[])
 {
-    struct odp_flow *flows;
-    struct dpif *dpif;
+    struct xflow_flow *flows;
+    struct xfif *xfif;
     size_t n_flows;
     struct ds ds;
     size_t i;
 
-    run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
-    run(dpif_flow_list_all(dpif, &flows, &n_flows), "listing all flows");
+    run(parsed_xfif_open(argv[1], false, &xfif), "opening datapath");
+    run(xfif_flow_list_all(xfif, &flows, &n_flows), "listing all flows");
 
     ds_init(&ds);
     for (i = 0; i < n_flows; i++) {
-        struct odp_flow *f = &flows[i];
-        enum { MAX_ACTIONS = 4096 / sizeof(union odp_action) };
-        union odp_action actions[MAX_ACTIONS];
+        struct xflow_flow *f = &flows[i];
+        enum { MAX_ACTIONS = 4096 / sizeof(union xflow_action) };
+        union xflow_action actions[MAX_ACTIONS];
 
         f->actions = actions;
         f->n_actions = MAX_ACTIONS;
-        if (!dpif_flow_get(dpif, f)) {
+        if (!xfif_flow_get(xfif, f)) {
+
             ds_clear(&ds);
-            format_odp_flow(&ds, f);
+            format_xflow_flow(&ds, f);
             printf("%s\n", ds_cstr(&ds));
         }
     }
     ds_destroy(&ds);
-    dpif_close(dpif);
+    xfif_close(xfif);
 }
 
 static void
 do_del_flows(int argc OVS_UNUSED, char *argv[])
 {
-    struct dpif *dpif;
+    struct xfif *xfif;
 
-    run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
-    run(dpif_flow_flush(dpif), "deleting all flows");
-    dpif_close(dpif);
+    run(parsed_xfif_open(argv[1], false, &xfif), "opening datapath");
+    run(xfif_flow_flush(xfif), "deleting all flows");
+    xfif_close(xfif);
 }
 
 static void
 do_dump_groups(int argc OVS_UNUSED, char *argv[])
 {
-    struct odp_stats stats;
-    struct dpif *dpif;
+    struct xflow_stats stats;
+    struct xfif *xfif;
     unsigned int i;
 
-    run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
-    run(dpif_get_dp_stats(dpif, &stats), "get datapath stats");
+    run(parsed_xfif_open(argv[1], false, &xfif), "opening datapath");
+    run(xfif_get_xf_stats(xfif, &stats), "get datapath stats");
     for (i = 0; i < stats.max_groups; i++) {
         uint16_t *ports;
         size_t n_ports;
 
-        if (!dpif_port_group_get(dpif, i, &ports, &n_ports) && n_ports) {
+        if (!xfif_port_group_get(xfif, i, &ports, &n_ports) && n_ports) {
             size_t j;
 
             printf("group %u:", i);
@@ -517,7 +518,7 @@ do_dump_groups(int argc OVS_UNUSED, char *argv[])
         }
         free(ports);
     }
-    dpif_close(dpif);
+    xfif_close(xfif);
 }
 
 static void
index 1a0c936..fbccdcb 100644 (file)
 #include "command-line.h"
 #include "compiler.h"
 #include "dirs.h"
-#include "dpif.h"
 #include "dynamic-string.h"
 #include "netdev.h"
 #include "netlink.h"
-#include "odp-util.h"
+#include "xflow-util.h"
 #include "ofp-print.h"
 #include "ofpbuf.h"
 #include "openflow/nicira-ext.h"
@@ -48,6 +47,7 @@
 #include "timeval.h"
 #include "util.h"
 #include "vconn.h"
+#include "xfif.h"
 #include "xtoxll.h"
 
 #include "vlog.h"
@@ -217,12 +217,12 @@ static void
 open_vconn__(const char *name, const char *default_suffix,
              struct vconn **vconnp)
 {
-    struct dpif *dpif;
+    struct xfif *xfif;
     struct stat s;
     char *bridge_path, *datapath_name, *datapath_type;
 
     bridge_path = xasprintf("%s/%s.%s", ovs_rundir, name, default_suffix);
-    dp_parse_name(name, &datapath_name, &datapath_type);
+    xf_parse_name(name, &datapath_name, &datapath_type);
 
     if (strstr(name, ":")) {
         run(vconn_open_block(name, OFP_VERSION, vconnp),
@@ -231,19 +231,19 @@ open_vconn__(const char *name, const char *default_suffix,
         open_vconn_socket(name, vconnp);
     } else if (!stat(bridge_path, &s) && S_ISSOCK(s.st_mode)) {
         open_vconn_socket(bridge_path, vconnp);
-    } else if (!dpif_open(datapath_name, datapath_type, &dpif)) {
-        char dpif_name[IF_NAMESIZE + 1];
+    } else if (!xfif_open(datapath_name, datapath_type, &xfif)) {
+        char xfif_name[IF_NAMESIZE + 1];
         char *socket_name;
 
-        run(dpif_port_get_name(dpif, ODPP_LOCAL, dpif_name, sizeof dpif_name),
-            "obtaining name of %s", dpif_name);
-        dpif_close(dpif);
-        if (strcmp(dpif_name, name)) {
-            VLOG_INFO("datapath %s is named %s", name, dpif_name);
+        run(xfif_port_get_name(xfif, XFLOWP_LOCAL, xfif_name, sizeof xfif_name),
+            "obtaining name of %s", xfif_name);
+        xfif_close(xfif);
+        if (strcmp(xfif_name, name)) {
+            VLOG_INFO("datapath %s is named %s", name, xfif_name);
         }
 
         socket_name = xasprintf("%s/%s.%s",
-                                ovs_rundir, dpif_name, default_suffix);
+                                ovs_rundir, xfif_name, default_suffix);
         if (stat(socket_name, &s)) {
             ovs_fatal(errno, "cannot connect to %s: stat failed on %s",
                       name, socket_name);
index e50a4a7..c9fd2ab 100644 (file)
@@ -16,7 +16,7 @@ OpenFlow controllers over TCP or SSL.
 The mandatory \fIdatapath\fR argument argument specifies the local datapath
 to relay.  It takes one of the following forms:
 .
-.so lib/dpif.man
+.so lib/xfif.man
 .
 .PP
 The optional \fIcontroller\fR arguments specify how to connect to
index e84a399..8e5b4d5 100644 (file)
 #include "compiler.h"
 #include "daemon.h"
 #include "dirs.h"
-#include "dpif.h"
 #include "leak-checker.h"
 #include "list.h"
 #include "netdev.h"
 #include "ofpbuf.h"
 #include "ofproto/ofproto.h"
+#include "ofproto/wdp.h"
 #include "openflow/openflow.h"
 #include "packets.h"
 #include "poll-loop.h"
@@ -44,6 +44,7 @@
 #include "unixctl.h"
 #include "util.h"
 #include "vconn.h"
+#include "xfif.h"
 
 #include "vlog.h"
 #define THIS_MODULE VLM_openflowd
@@ -91,7 +92,7 @@ main(int argc, char *argv[])
     struct ofproto *ofproto;
     struct ofsettings s;
     int error;
-    struct dpif *dpif;
+    struct xfif *xfif;
     struct netflow_options nf_options;
 
     proctitle_init(argc, argv);
@@ -113,7 +114,7 @@ main(int argc, char *argv[])
     VLOG_INFO("Open vSwitch version %s", VERSION BUILDNR);
     VLOG_INFO("OpenFlow protocol version 0x%02x", OFP_VERSION);
 
-    error = dpif_create_and_open(s.dp_name, s.dp_type, &dpif);
+    error = xfif_create_and_open(s.dp_name, s.dp_type, &xfif);
     if (error) {
         ovs_fatal(error, "could not create datapath");
     }
@@ -130,7 +131,7 @@ main(int argc, char *argv[])
                 ovs_fatal(error, "failed to open %s as a device", port);
             }
 
-            error = dpif_port_add(dpif, port, 0, NULL);
+            error = xfif_port_add(xfif, port, 0, NULL);
             if (error) {
                 ovs_fatal(error, "failed to add %s as a port", port);
             }
@@ -182,17 +183,17 @@ main(int argc, char *argv[])
             ovs_fatal(error, "unrecoverable datapath error");
         }
         unixctl_server_run(unixctl);
-        dp_run();
+        wdp_run();
         netdev_run();
 
         ofproto_wait(ofproto);
         unixctl_server_wait(unixctl);
-        dp_wait();
+        wdp_wait();
         netdev_wait();
         poll_block();
     }
 
-    dpif_close(dpif);
+    xfif_close(xfif);
 
     return 0;
 }
@@ -475,7 +476,7 @@ parse_options(int argc, char *argv[], struct ofsettings *s)
     }
 
     /* Local vconns. */
-    dp_parse_name(argv[0], &s->dp_name, &s->dp_type);
+    xf_parse_name(argv[0], &s->dp_name, &s->dp_type);
 
     /* Controllers. */
     s->n_controllers = argc > 1 ? argc - 1 : 1;
index 354d4d8..373e41c 100644 (file)
@@ -32,7 +32,6 @@
 #include "bitmap.h"
 #include "coverage.h"
 #include "dirs.h"
-#include "dpif.h"
 #include "dynamic-string.h"
 #include "flow.h"
 #include "hash.h"
@@ -40,7 +39,7 @@
 #include "list.h"
 #include "mac-learning.h"
 #include "netdev.h"
-#include "odp-util.h"
+#include "xflow-util.h"
 #include "ofp-print.h"
 #include "ofpbuf.h"
 #include "ofproto/netflow.h"
@@ -61,6 +60,7 @@
 #include "vconn.h"
 #include "vswitchd/vswitch-idl.h"
 #include "xenserver.h"
+#include "xfif.h"
 #include "xtoxll.h"
 #include "sflow_api.h"
 
@@ -69,7 +69,7 @@
 
 struct dst {
     uint16_t vlan;
-    uint16_t dp_ifidx;
+    uint16_t xf_ifidx;
 };
 
 struct iface {
@@ -82,7 +82,7 @@ struct iface {
 
     /* These members are valid only after bridge_reconfigure() causes them to
      * be initialized.*/
-    int dp_ifidx;               /* Index within kernel datapath. */
+    int xf_ifidx;               /* Index within kernel datapath. */
     struct netdev *netdev;      /* Network device. */
     bool enabled;               /* May be chosen for flows? */
 
@@ -171,7 +171,7 @@ struct bridge {
     char *dp_desc;              /* Datapath description. */
 
     /* Kernel datapath information. */
-    struct dpif *dpif;          /* Datapath. */
+    struct xfif *xfif;          /* Datapath. */
     struct port_array ifaces;   /* Indexed by kernel datapath port number. */
 
     /* Bridge ports. */
@@ -243,8 +243,8 @@ static void port_del_ifaces(struct port *, const struct ovsrec_port *);
 static void port_destroy(struct port *);
 static struct port *port_lookup(const struct bridge *, const char *name);
 static struct iface *port_lookup_iface(const struct port *, const char *name);
-static struct port *port_from_dp_ifidx(const struct bridge *,
-                                       uint16_t dp_ifidx);
+static struct port *port_from_xf_ifidx(const struct bridge *,
+                                       uint16_t xf_ifidx);
 static void port_update_bond_compat(struct port *);
 static void port_update_vlan_compat(struct port *);
 static void port_update_bonding(struct port *);
@@ -259,8 +259,8 @@ static struct iface *iface_create(struct port *port,
                                   const struct ovsrec_interface *if_cfg);
 static void iface_destroy(struct iface *);
 static struct iface *iface_lookup(const struct bridge *, const char *name);
-static struct iface *iface_from_dp_ifidx(const struct bridge *,
-                                         uint16_t dp_ifidx);
+static struct iface *iface_from_xf_ifidx(const struct bridge *,
+                                         uint16_t xf_ifidx);
 static bool iface_is_internal(const struct bridge *, const char *name);
 static void iface_set_mac(struct iface *);
 
@@ -283,11 +283,11 @@ bridge_get_ifaces(struct svec *svec)
 
             for (j = 0; j < port->n_ifaces; j++) {
                 struct iface *iface = port->ifaces[j];
-                if (iface->dp_ifidx < 0) {
+                if (iface->xf_ifidx < 0) {
                     VLOG_ERR("%s interface not in datapath %s, ignoring",
-                             iface->name, dpif_name(br->dpif));
+                             iface->name, xfif_name(br->xfif));
                 } else {
-                    if (iface->dp_ifidx != ODPP_LOCAL) {
+                    if (iface->xf_ifidx != XFLOWP_LOCAL) {
                         svec_add(svec, iface->name);
                     }
                 }
@@ -300,7 +300,7 @@ void
 bridge_init(const struct ovsrec_open_vswitch *cfg)
 {
     struct svec bridge_names;
-    struct svec dpif_names, dpif_types;
+    struct svec xfif_names, xfif_types;
     size_t i;
 
     unixctl_command_register("fdb/show", bridge_unixctl_fdb_show, NULL);
@@ -311,39 +311,39 @@ bridge_init(const struct ovsrec_open_vswitch *cfg)
     }
     svec_sort(&bridge_names);
 
-    svec_init(&dpif_names);
-    svec_init(&dpif_types);
-    dp_enumerate_types(&dpif_types);
-    for (i = 0; i < dpif_types.n; i++) {
-        struct dpif *dpif;
+    svec_init(&xfif_names);
+    svec_init(&xfif_types);
+    xf_enumerate_types(&xfif_types);
+    for (i = 0; i < xfif_types.n; i++) {
+        struct xfif *xfif;
         int retval;
         size_t j;
 
-        dp_enumerate_names(dpif_types.names[i], &dpif_names);
+        xf_enumerate_names(xfif_types.names[i], &xfif_names);
 
-        for (j = 0; j < dpif_names.n; j++) {
-            retval = dpif_open(dpif_names.names[j], dpif_types.names[i], &dpif);
+        for (j = 0; j < xfif_names.n; j++) {
+            retval = xfif_open(xfif_names.names[j], xfif_types.names[i], &xfif);
             if (!retval) {
                 struct svec all_names;
                 size_t k;
 
                 svec_init(&all_names);
-                dpif_get_all_names(dpif, &all_names);
+                xfif_get_all_names(xfif, &all_names);
                 for (k = 0; k < all_names.n; k++) {
                     if (svec_contains(&bridge_names, all_names.names[k])) {
                         goto found;
                     }
                 }
-                dpif_delete(dpif);
+                xfif_delete(xfif);
             found:
                 svec_destroy(&all_names);
-                dpif_close(dpif);
+                xfif_close(xfif);
             }
         }
     }
     svec_destroy(&bridge_names);
-    svec_destroy(&dpif_names);
-    svec_destroy(&dpif_types);
+    svec_destroy(&xfif_names);
+    svec_destroy(&xfif_types);
 
     unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows,
                              NULL);
@@ -396,6 +396,7 @@ set_up_iface(const struct ovsrec_interface *iface_cfg, struct iface *iface,
         netdev_options.args = &options;
         netdev_options.ethertype = NETDEV_ETH_TYPE_NONE;
         netdev_options.may_create = true;
+        netdev_options.may_open = true;
         if (iface_is_internal(iface->port->bridge, iface_cfg->name)) {
             netdev_options.may_open = true;
         }
@@ -455,17 +456,17 @@ check_iface_netdev(struct bridge *br OVS_UNUSED, struct iface *iface,
 }
 
 static bool
-check_iface_dp_ifidx(struct bridge *br, struct iface *iface,
+check_iface_xf_ifidx(struct bridge *br, struct iface *iface,
                      void *aux OVS_UNUSED)
 {
-    if (iface->dp_ifidx >= 0) {
+    if (iface->xf_ifidx >= 0) {
         VLOG_DBG("%s has interface %s on port %d",
-                 dpif_name(br->dpif),
-                 iface->name, iface->dp_ifidx);
+                 xfif_name(br->xfif),
+                 iface->name, iface->xf_ifidx);
         return true;
     } else {
         VLOG_ERR("%s interface not in %s, dropping",
-                 iface->name, dpif_name(br->dpif));
+                 iface->name, xfif_name(br->xfif));
         return false;
     }
 }
@@ -481,7 +482,7 @@ set_iface_properties(struct bridge *br OVS_UNUSED, struct iface *iface,
 
     /* Set MAC address of internal interfaces other than the local
      * interface. */
-    if (iface->dp_ifidx != ODPP_LOCAL
+    if (iface->xf_ifidx != XFLOWP_LOCAL
         && iface_is_internal(br, iface->name)) {
         iface_set_mac(iface);
     }
@@ -632,43 +633,43 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
      * that port already belongs to a different datapath, so we must do all
      * port deletions before any port additions. */
     LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
-        struct odp_port *dpif_ports;
-        size_t n_dpif_ports;
+        struct xflow_port *xfif_ports;
+        size_t n_xfif_ports;
         struct shash want_ifaces;
 
-        dpif_port_list(br->dpif, &dpif_ports, &n_dpif_ports);
+        xfif_port_list(br->xfif, &xfif_ports, &n_xfif_ports);
         bridge_get_all_ifaces(br, &want_ifaces);
-        for (i = 0; i < n_dpif_ports; i++) {
-            const struct odp_port *p = &dpif_ports[i];
+        for (i = 0; i < n_xfif_ports; i++) {
+            const struct xflow_port *p = &xfif_ports[i];
             if (!shash_find(&want_ifaces, p->devname)
                 && strcmp(p->devname, br->name)) {
-                int retval = dpif_port_del(br->dpif, p->port);
+                int retval = xfif_port_del(br->xfif, p->port);
                 if (retval) {
                     VLOG_ERR("failed to remove %s interface from %s: %s",
-                             p->devname, dpif_name(br->dpif),
+                             p->devname, xfif_name(br->xfif),
                              strerror(retval));
                 }
             }
         }
         shash_destroy(&want_ifaces);
-        free(dpif_ports);
+        free(xfif_ports);
     }
     LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
-        struct odp_port *dpif_ports;
-        size_t n_dpif_ports;
+        struct xflow_port *xfif_ports;
+        size_t n_xfif_ports;
         struct shash cur_ifaces, want_ifaces;
         struct shash_node *node;
 
         /* Get the set of interfaces currently in this datapath. */
-        dpif_port_list(br->dpif, &dpif_ports, &n_dpif_ports);
+        xfif_port_list(br->xfif, &xfif_ports, &n_xfif_ports);
         shash_init(&cur_ifaces);
-        for (i = 0; i < n_dpif_ports; i++) {
-            const char *name = dpif_ports[i].devname;
+        for (i = 0; i < n_xfif_ports; i++) {
+            const char *name = xfif_ports[i].devname;
             if (!shash_find(&cur_ifaces, name)) {
                 shash_add(&cur_ifaces, name, NULL);
             }
         }
-        free(dpif_ports);
+        free(xfif_ports);
 
         /* Get the set of interfaces we want on this datapath. */
         bridge_get_all_ifaces(br, &want_ifaces);
@@ -689,15 +690,15 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
 
                 /* Add to datapath. */
                 internal = iface_is_internal(br, if_name);
-                error = dpif_port_add(br->dpif, if_name,
-                                      internal ? ODP_PORT_INTERNAL : 0, NULL);
+                error = xfif_port_add(br->xfif, if_name,
+                                      internal ? XFLOW_PORT_INTERNAL : 0, NULL);
                 if (error == EFBIG) {
                     VLOG_ERR("ran out of valid port numbers on %s",
-                             dpif_name(br->dpif));
+                             xfif_name(br->xfif));
                     break;
                 } else if (error) {
                     VLOG_ERR("failed to add %s interface to %s: %s",
-                             if_name, dpif_name(br->dpif), strerror(error));
+                             if_name, xfif_name(br->xfif), strerror(error));
                 }
             }
         }
@@ -715,7 +716,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
         bridge_fetch_dp_ifaces(br);
 
         iterate_and_prune_ifaces(br, check_iface_netdev, NULL);
-        iterate_and_prune_ifaces(br, check_iface_dp_ifidx, NULL);
+        iterate_and_prune_ifaces(br, check_iface_xf_ifidx, NULL);
 
         /* Pick local port hardware address, datapath ID. */
         bridge_pick_local_hw_addr(br, ea, &hw_addr_iface);
@@ -744,7 +745,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
 
             memset(&opts, 0, sizeof opts);
 
-            dpif_get_netflow_ids(br->dpif, &opts.engine_type, &opts.engine_id);
+            xfif_get_netflow_ids(br->xfif, &opts.engine_type, &opts.engine_id);
             if (nf_cfg->engine_type) {
                 opts.engine_type = *nf_cfg->engine_type;
             }
@@ -835,7 +836,7 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
         /* Update the controller and related settings.  It would be more
          * straightforward to call this from bridge_reconfigure_one(), but we
          * can't do it there for two reasons.  First, and most importantly, at
-         * that point we don't know the dp_ifidx of any interfaces that have
+         * that point we don't know the xf_ifidx of any interfaces that have
          * been added to the bridge (because we haven't actually added them to
          * the datapath).  Second, at that point we haven't set the datapath ID
          * yet; when a controller is configured, resetting the datapath ID will
@@ -951,7 +952,7 @@ bridge_pick_local_hw_addr(struct bridge *br, uint8_t ea[ETH_ADDR_LEN],
 
             /* The local port doesn't count (since we're trying to choose its
              * MAC address anyway). */
-            if (iface->dp_ifidx == ODPP_LOCAL) {
+            if (iface->xf_ifidx == XFLOWP_LOCAL) {
                 continue;
             }
 
@@ -1125,7 +1126,7 @@ bridge_flush(struct bridge *br)
     mac_learning_flush(br->ml);
 }
 
-/* Returns the 'br' interface for the ODPP_LOCAL port, or null if 'br' has no
+/* Returns the 'br' interface for the XFLOWP_LOCAL port, or null if 'br' has no
  * such interface. */
 static struct iface *
 bridge_get_local_iface(struct bridge *br)
@@ -1136,7 +1137,7 @@ bridge_get_local_iface(struct bridge *br)
         struct port *port = br->ports[i];
         for (j = 0; j < port->n_ifaces; j++) {
             struct iface *iface = port->ifaces[j];
-            if (iface->dp_ifidx == ODPP_LOCAL) {
+            if (iface->xf_ifidx == XFLOWP_LOCAL) {
                 return iface;
             }
         }
@@ -1166,7 +1167,7 @@ bridge_unixctl_fdb_show(struct unixctl_conn *conn,
             continue;
         }
         ds_put_format(&ds, "%5d  %4d  "ETH_ADDR_FMT"  %3d\n",
-                      br->ports[e->port]->ifaces[0]->dp_ifidx,
+                      br->ports[e->port]->ifaces[0]->xf_ifidx,
                       e->vlan, ETH_ADDR_ARGS(e->mac), mac_entry_age(e));
     }
     unixctl_command_reply(conn, 200, ds_cstr(&ds));
@@ -1183,21 +1184,21 @@ bridge_create(const struct ovsrec_bridge *br_cfg)
     assert(!bridge_lookup(br_cfg->name));
     br = xzalloc(sizeof *br);
 
-    error = dpif_create_and_open(br_cfg->name, br_cfg->datapath_type,
-                                 &br->dpif);
+    error = xfif_create_and_open(br_cfg->name, br_cfg->datapath_type,
+                                 &br->xfif);
     if (error) {
         free(br);
         return NULL;
     }
-    dpif_flow_flush(br->dpif);
+    xfif_flow_flush(br->xfif);
 
     error = ofproto_create(br_cfg->name, br_cfg->datapath_type, &bridge_ofhooks,
                            br, &br->ofproto);
     if (error) {
         VLOG_ERR("failed to create switch %s: %s", br_cfg->name,
                  strerror(error));
-        dpif_delete(br->dpif);
-        dpif_close(br->dpif);
+        xfif_delete(br->xfif);
+        xfif_close(br->xfif);
         free(br);
         return NULL;
     }
@@ -1217,7 +1218,7 @@ bridge_create(const struct ovsrec_bridge *br_cfg)
 
     list_push_back(&all_bridges, &br->node);
 
-    VLOG_INFO("created bridge %s on %s", br->name, dpif_name(br->dpif));
+    VLOG_INFO("created bridge %s on %s", br->name, xfif_name(br->xfif));
 
     return br;
 }
@@ -1232,12 +1233,12 @@ bridge_destroy(struct bridge *br)
             port_destroy(br->ports[br->n_ports - 1]);
         }
         list_remove(&br->node);
-        error = dpif_delete(br->dpif);
+        error = xfif_delete(br->xfif);
         if (error && error != ENOENT) {
             VLOG_ERR("failed to delete %s: %s",
-                     dpif_name(br->dpif), strerror(error));
+                     xfif_name(br->xfif), strerror(error));
         }
-        dpif_close(br->dpif);
+        xfif_close(br->xfif);
         ofproto_destroy(br->ofproto);
         mac_learning_destroy(br->ml);
         port_array_destroy(&br->ifaces);
@@ -1307,7 +1308,7 @@ bridge_run_one(struct bridge *br)
         return error;
     }
 
-    mac_learning_run(br->ml, ofproto_get_revalidate_set(br->ofproto));
+    //XXX mac_learning_run(br->ml, ofproto_get_revalidate_set(br->ofproto));
     bond_run(br);
 
     error = ofproto_run2(br->ofproto, br->flush);
@@ -1446,7 +1447,7 @@ bridge_reconfigure_one(const struct ovsrec_open_vswitch *ovs_cfg,
         char local_name[IF_NAMESIZE];
         int error;
 
-        error = dpif_port_get_name(br->dpif, ODPP_LOCAL,
+        error = xfif_port_get_name(br->xfif, XFLOWP_LOCAL,
                                    local_name, sizeof local_name);
         if (!error && !shash_find(&new_ports, local_name)) {
             VLOG_WARN("bridge %s: controller specified but no local port "
@@ -1595,7 +1596,8 @@ bridge_reconfigure_remotes(const struct ovsrec_open_vswitch *ovs_cfg,
         action.output.len = htons(sizeof action);
         action.output.port = htons(OFPP_NORMAL);
         memset(&flow, 0, sizeof flow);
-        ofproto_add_flow(br->ofproto, &flow, OVSFW_ALL, 0, &action, 1, 0);
+        flow.wildcards = OVSFW_ALL;
+        ofproto_add_flow(br->ofproto, &flow, &action, 1, 0);
     } else {
         struct ofproto_controller *ocs;
         size_t i;
@@ -1690,16 +1692,16 @@ bridge_get_all_ifaces(const struct bridge *br, struct shash *ifaces)
 /* For robustness, in case the administrator moves around datapath ports behind
  * our back, we re-check all the datapath port numbers here.
  *
- * This function will set the 'dp_ifidx' members of interfaces that have
+ * This function will set the 'xf_ifidx' members of interfaces that have
  * disappeared to -1, so only call this function from a context where those
  * 'struct iface's will be removed from the bridge.  Otherwise, the -1
- * 'dp_ifidx'es will cause trouble later when we try to send them to the
+ * 'xf_ifidx'es will cause trouble later when we try to send them to the
  * datapath, which doesn't support UINT16_MAX+1 ports. */
 static void
 bridge_fetch_dp_ifaces(struct bridge *br)
 {
-    struct odp_port *dpif_ports;
-    size_t n_dpif_ports;
+    struct xflow_port *xfif_ports;
+    size_t n_xfif_ports;
     size_t i, j;
 
     /* Reset all interface numbers. */
@@ -1707,36 +1709,36 @@ bridge_fetch_dp_ifaces(struct bridge *br)
         struct port *port = br->ports[i];
         for (j = 0; j < port->n_ifaces; j++) {
             struct iface *iface = port->ifaces[j];
-            iface->dp_ifidx = -1;
+            iface->xf_ifidx = -1;
         }
     }
     port_array_clear(&br->ifaces);
 
-    dpif_port_list(br->dpif, &dpif_ports, &n_dpif_ports);
-    for (i = 0; i < n_dpif_ports; i++) {
-        struct odp_port *p = &dpif_ports[i];
+    xfif_port_list(br->xfif, &xfif_ports, &n_xfif_ports);
+    for (i = 0; i < n_xfif_ports; i++) {
+        struct xflow_port *p = &xfif_ports[i];
         struct iface *iface = iface_lookup(br, p->devname);
         if (iface) {
-            if (iface->dp_ifidx >= 0) {
+            if (iface->xf_ifidx >= 0) {
                 VLOG_WARN("%s reported interface %s twice",
-                          dpif_name(br->dpif), p->devname);
-            } else if (iface_from_dp_ifidx(br, p->port)) {
+                          xfif_name(br->xfif), p->devname);
+            } else if (iface_from_xf_ifidx(br, p->port)) {
                 VLOG_WARN("%s reported interface %"PRIu16" twice",
-                          dpif_name(br->dpif), p->port);
+                          xfif_name(br->xfif), p->port);
             } else {
                 port_array_set(&br->ifaces, p->port, iface);
-                iface->dp_ifidx = p->port;
+                iface->xf_ifidx = p->port;
             }
 
             if (iface->cfg) {
-                int64_t ofport = (iface->dp_ifidx >= 0
-                                  ? odp_port_to_ofp_port(iface->dp_ifidx)
+                int64_t ofport = (iface->xf_ifidx >= 0
+                                  ? xflow_port_to_ofp_port(iface->xf_ifidx)
                                   : -1);
                 ovsrec_interface_set_ofport(iface->cfg, &ofport, 1);
             }
         }
     }
-    free(dpif_ports);
+    free(xfif_ports);
 }
 \f
 /* Bridge packet processing functions. */
@@ -1785,7 +1787,7 @@ bond_choose_iface(const struct port *port)
 
 static bool
 choose_output_iface(const struct port *port, const uint8_t *dl_src,
-                    uint16_t *dp_ifidx, tag_type *tags)
+                    uint16_t *xf_ifidx, tag_type *tags)
 {
     struct iface *iface;
 
@@ -1809,7 +1811,7 @@ choose_output_iface(const struct port *port, const uint8_t *dl_src,
         *tags |= e->iface_tag;
         iface = port->ifaces[e->iface_idx];
     }
-    *dp_ifidx = iface->dp_ifidx;
+    *xf_ifidx = iface->xf_ifidx;
     *tags |= iface->tag;        /* Currently only used for bonding. */
     return true;
 }
@@ -2003,7 +2005,7 @@ set_dst(struct dst *p, const flow_t *flow,
     p->vlan = (out_port->vlan >= 0 ? OFP_VLAN_NONE
               : in_port->vlan >= 0 ? in_port->vlan
               : ntohs(flow->dl_vlan));
-    return choose_output_iface(out_port, flow->dl_src, &p->dp_ifidx, tags);
+    return choose_output_iface(out_port, flow->dl_src, &p->xf_ifidx, tags);
 }
 
 static void
@@ -2064,7 +2066,7 @@ dst_is_duplicate(const struct dst *dsts, size_t n_dsts,
 {
     size_t i;
     for (i = 0; i < n_dsts; i++) {
-        if (dsts[i].vlan == test->vlan && dsts[i].dp_ifidx == test->dp_ifidx) {
+        if (dsts[i].vlan == test->vlan && dsts[i].xf_ifidx == test->xf_ifidx) {
             return true;
         }
     }
@@ -2094,7 +2096,7 @@ compose_dsts(const struct bridge *br, const flow_t *flow, uint16_t vlan,
     size_t i;
 
     if (out_port == FLOOD_PORT) {
-        /* XXX use ODP_FLOOD if no vlans or bonding. */
+        /* XXX use XFLOW_FLOOD if no vlans or bonding. */
         /* XXX even better, define each VLAN as a datapath port group */
         for (i = 0; i < br->n_ports; i++) {
             struct port *port = br->ports[i];
@@ -2107,7 +2109,7 @@ compose_dsts(const struct bridge *br, const flow_t *flow, uint16_t vlan,
         }
         *nf_output_iface = NF_OUT_FLOOD;
     } else if (out_port && set_dst(dst, flow, in_port, out_port, tags)) {
-        *nf_output_iface = dst->dp_ifidx;
+        *nf_output_iface = dst->xf_ifidx;
         mirrors |= out_port->dst_mirrors;
         dst++;
     }
@@ -2165,7 +2167,7 @@ static void OVS_UNUSED
 print_dsts(const struct dst *dsts, size_t n)
 {
     for (; n--; dsts++) {
-        printf(">p%"PRIu16, dsts->dp_ifidx);
+        printf(">p%"PRIu16, dsts->xf_ifidx);
         if (dsts->vlan != OFP_VLAN_NONE) {
             printf("v%"PRIu16, dsts->vlan);
         }
@@ -2175,7 +2177,7 @@ print_dsts(const struct dst *dsts, size_t n)
 static void
 compose_actions(struct bridge *br, const flow_t *flow, uint16_t vlan,
                 const struct port *in_port, const struct port *out_port,
-                tag_type *tags, struct odp_actions *actions,
+                tag_type *tags, struct xflow_actions *actions,
                 uint16_t *nf_output_iface)
 {
     struct dst dsts[DP_MAX_PORTS * (MAX_MIRRORS + 1)];
@@ -2188,18 +2190,19 @@ compose_actions(struct bridge *br, const flow_t *flow, uint16_t vlan,
 
     cur_vlan = ntohs(flow->dl_vlan);
     for (p = dsts; p < &dsts[n_dsts]; p++) {
-        union odp_action *a;
+        union xflow_action *a;
         if (p->vlan != cur_vlan) {
             if (p->vlan == OFP_VLAN_NONE) {
-                odp_actions_add(actions, ODPAT_STRIP_VLAN);
+                xflow_actions_add(actions, XFLOWAT_STRIP_VLAN);
             } else {
-                a = odp_actions_add(actions, ODPAT_SET_VLAN_VID);
-                a->vlan_vid.vlan_vid = htons(p->vlan);
+                a = xflow_actions_add(actions, XFLOWAT_SET_DL_TCI);
+                a->dl_tci.tci = htons(p->vlan & VLAN_VID_MASK);
+                a->dl_tci.mask = htons(VLAN_VID_MASK);
             }
             cur_vlan = p->vlan;
         }
-        a = odp_actions_add(actions, ODPAT_OUTPUT);
-        a->output.port = p->dp_ifidx;
+        a = xflow_actions_add(actions, XFLOWAT_OUTPUT);
+        a->output.port = p->xf_ifidx;
     }
 }
 
@@ -2305,7 +2308,7 @@ is_admissible(struct bridge *br, const flow_t *flow, bool have_packet,
     int vlan;
 
     /* Find the interface and port structure for the received packet. */
-    in_iface = iface_from_dp_ifidx(br, flow->in_port);
+    in_iface = iface_from_xf_ifidx(br, flow->in_port);
     if (!in_iface) {
         /* No interface?  Something fishy... */
         if (have_packet) {
@@ -2382,7 +2385,7 @@ is_admissible(struct bridge *br, const flow_t *flow, bool have_packet,
  * not at all, if 'packet' was NULL. */
 static bool
 process_flow(struct bridge *br, const flow_t *flow,
-             const struct ofpbuf *packet, struct odp_actions *actions,
+             const struct ofpbuf *packet, struct xflow_actions *actions,
              tag_type *tags, uint16_t *nf_output_iface)
 {
     struct port *in_port;
@@ -2441,7 +2444,7 @@ bridge_port_changed_ofhook_cb(enum ofp_port_reason reason,
     struct iface *iface;
     struct port *port;
 
-    iface = iface_from_dp_ifidx(br, ofp_port_to_odp_port(opp->port_no));
+    iface = iface_from_xf_ifidx(br, ofp_port_to_xflow_port(opp->port_no));
     if (!iface) {
         return;
     }
@@ -2469,7 +2472,7 @@ bridge_port_changed_ofhook_cb(enum ofp_port_reason reason,
 
 static bool
 bridge_normal_ofhook_cb(const flow_t *flow, const struct ofpbuf *packet,
-                        struct odp_actions *actions, tag_type *tags,
+                        struct xflow_actions *actions, tag_type *tags,
                         uint16_t *nf_output_iface, void *br_)
 {
     struct bridge *br = br_;
@@ -2480,12 +2483,12 @@ bridge_normal_ofhook_cb(const flow_t *flow, const struct ofpbuf *packet,
 
 static void
 bridge_account_flow_ofhook_cb(const flow_t *flow,
-                              const union odp_action *actions,
+                              const union xflow_action *actions,
                               size_t n_actions, unsigned long long int n_bytes,
                               void *br_)
 {
     struct bridge *br = br_;
-    const union odp_action *a;
+    const union xflow_action *a;
     struct port *in_port;
     tag_type tags = 0;
     int vlan;
@@ -2502,8 +2505,8 @@ bridge_account_flow_ofhook_cb(const flow_t *flow,
     }
 
     for (a = actions; a < &actions[n_actions]; a++) {
-        if (a->type == ODPAT_OUTPUT) {
-            struct port *out_port = port_from_dp_ifidx(br, a->output.port);
+        if (a->type == XFLOWAT_OUTPUT) {
+            struct port *out_port = port_from_xf_ifidx(br, a->output.port);
             if (out_port && out_port->n_ifaces >= 2) {
                 struct bond_entry *e = lookup_bond_entry(out_port,
                                                          flow->dl_src);
@@ -2856,13 +2859,13 @@ bond_send_learning_packets(struct port *port)
     error = n_packets = n_errors = 0;
     LIST_FOR_EACH (e, struct mac_entry, lru_node, &br->ml->lrus) {
         union ofp_action actions[2], *a;
-        uint16_t dp_ifidx;
+        uint16_t xf_ifidx;
         tag_type tags = 0;
         flow_t flow;
         int retval;
 
         if (e->port == port->port_idx
-            || !choose_output_iface(port, e->mac, &dp_ifidx, &tags)) {
+            || !choose_output_iface(port, e->mac, &xf_ifidx, &tags)) {
             continue;
         }
 
@@ -2877,14 +2880,14 @@ bond_send_learning_packets(struct port *port)
         }
         a->output.type = htons(OFPAT_OUTPUT);
         a->output.len = htons(sizeof *a);
-        a->output.port = htons(odp_port_to_ofp_port(dp_ifidx));
+        a->output.port = htons(xflow_port_to_ofp_port(xf_ifidx));
         a++;
 
         /* Send packet. */
         n_packets++;
         compose_benign_packet(&packet, "Open vSwitch Bond Failover", 0xf177,
                               e->mac);
-        flow_extract(&packet, 0, ODPP_NONE, &flow);
+        flow_extract(&packet, 0, XFLOWP_NONE, &flow);
         retval = ofproto_send_packet(br->ofproto, &flow, actions, a - actions,
                                      &packet);
         if (retval) {
@@ -3007,12 +3010,12 @@ bond_unixctl_show(struct unixctl_conn *conn,
             /* MACs. */
             LIST_FOR_EACH (me, struct mac_entry, lru_node,
                            &port->bridge->ml->lrus) {
-                uint16_t dp_ifidx;
+                uint16_t xf_ifidx;
                 tag_type tags = 0;
                 if (bond_hash(me->mac) == hash
                     && me->port != port->port_idx
-                    && choose_output_iface(port, me->mac, &dp_ifidx, &tags)
-                    && dp_ifidx == iface->dp_ifidx)
+                    && choose_output_iface(port, me->mac, &xf_ifidx, &tags)
+                    && xf_ifidx == iface->xf_ifidx)
                 {
                     ds_put_format(&ds, "\t\t"ETH_ADDR_FMT"\n",
                                   ETH_ADDR_ARGS(me->mac));
@@ -3429,9 +3432,9 @@ port_destroy(struct port *port)
 }
 
 static struct port *
-port_from_dp_ifidx(const struct bridge *br, uint16_t dp_ifidx)
+port_from_xf_ifidx(const struct bridge *br, uint16_t xf_ifidx)
 {
-    struct iface *iface = iface_from_dp_ifidx(br, dp_ifidx);
+    struct iface *iface = iface_from_xf_ifidx(br, xf_ifidx);
     return iface ? iface->port : NULL;
 }
 
@@ -3607,7 +3610,7 @@ iface_create(struct port *port, const struct ovsrec_interface *if_cfg)
     iface->port = port;
     iface->port_ifidx = port->n_ifaces;
     iface->name = xstrdup(name);
-    iface->dp_ifidx = -1;
+    iface->xf_ifidx = -1;
     iface->tag = tag_create_random();
     iface->delay_expires = LLONG_MAX;
     iface->netdev = NULL;
@@ -3656,8 +3659,8 @@ iface_destroy(struct iface *iface)
 
         shash_find_and_delete_assert(&br->iface_by_name, iface->name);
 
-        if (iface->dp_ifidx >= 0) {
-            port_array_set(&br->ifaces, iface->dp_ifidx, NULL);
+        if (iface->xf_ifidx >= 0) {
+            port_array_set(&br->ifaces, iface->xf_ifidx, NULL);
         }
 
         del = port->ifaces[iface->port_ifidx] = port->ifaces[--port->n_ifaces];
@@ -3685,14 +3688,14 @@ iface_lookup(const struct bridge *br, const char *name)
 }
 
 static struct iface *
-iface_from_dp_ifidx(const struct bridge *br, uint16_t dp_ifidx)
+iface_from_xf_ifidx(const struct bridge *br, uint16_t xf_ifidx)
 {
-    return port_array_get(&br->ifaces, dp_ifidx);
+    return port_array_get(&br->ifaces, xf_ifidx);
 }
 
 /* Returns true if 'iface' is the name of an "internal" interface on bridge
  * 'br', that is, an interface that is entirely simulated within the datapath.
- * The local port (ODPP_LOCAL) is always an internal interface.  Other local
+ * The local port (XFLOWP_LOCAL) is always an internal interface.  Other local
  * interfaces are created by setting "iface.<iface>.internal = true".
  *
  * In addition, we have a kluge-y feature that creates an internal port with
@@ -3733,7 +3736,7 @@ iface_set_mac(struct iface *iface)
         if (eth_addr_is_multicast(ea)) {
             VLOG_ERR("interface %s: cannot set MAC to multicast address",
                      iface->name);
-        } else if (iface->dp_ifidx == ODPP_LOCAL) {
+        } else if (iface->xf_ifidx == XFLOWP_LOCAL) {
             VLOG_ERR("ignoring iface.%s.mac; use bridge.%s.mac instead",
                      iface->name, iface->name);
         } else {
index 6478156..69adc44 100644 (file)
@@ -30,9 +30,9 @@
 #include "command-line.h"
 #include "compiler.h"
 #include "daemon.h"
-#include "dpif.h"
 #include "leak-checker.h"
 #include "netdev.h"
+#include "ofproto/wdp.h"
 #include "ovsdb-idl.h"
 #include "poll-loop.h"
 #include "proc-net-compat.h"
@@ -46,6 +46,7 @@
 #include "util.h"
 #include "vconn.h"
 #include "vswitchd/vswitch-idl.h"
+#include "xfif.h"
 
 #include "vlog.h"
 #define THIS_MODULE VLM_vswitchd
@@ -121,7 +122,7 @@ main(int argc, char *argv[])
             }
         }
         unixctl_server_run(unixctl);
-        dp_run();
+        wdp_run();
         netdev_run();
 
         signal_wait(sighup);
@@ -130,7 +131,7 @@ main(int argc, char *argv[])
         }
         ovsdb_idl_wait(idl);
         unixctl_server_wait(unixctl);
-        dp_wait();
+        wdp_wait();
         netdev_wait();
         poll_block();
     }