datapath: Get packet metadata from userspace in odp_packet_cmd_execute().
[openvswitch] / ofproto / ofproto-dpif.c
index 3d9198464826b7c9d41af68f4683756fe49da2a9..c5fe2820dddeb6826200126867257e01f4f5df0a 100644 (file)
@@ -43,6 +43,7 @@
 #include "ofproto-sflow.h"
 #include "poll-loop.h"
 #include "timer.h"
+#include "unaligned.h"
 #include "unixctl.h"
 #include "vlan-bitmap.h"
 #include "vlog.h"
@@ -170,11 +171,6 @@ struct action_xlate_ctx {
      * calling action_xlate_ctx_init(). */
     void (*resubmit_hook)(struct action_xlate_ctx *, struct rule_dpif *);
 
-    /* If true, the speciality of 'flow' should be checked before executing
-     * its actions.  If special_cb returns false on 'flow' rendered
-     * uninstallable and no actions will be executed. */
-    bool check_special;
-
 /* xlate_actions() initializes and uses these members.  The client might want
  * to look at them after it returns. */
 
@@ -270,6 +266,7 @@ static void facet_update_time(struct ofproto_dpif *, struct facet *,
                               long long int used);
 static void facet_update_stats(struct ofproto_dpif *, struct facet *,
                                const struct dpif_flow_stats *);
+static void facet_reset_dp_stats(struct facet *, struct dpif_flow_stats *);
 static void facet_push_stats(struct facet *);
 static void facet_account(struct ofproto_dpif *, struct facet *,
                           uint64_t extra_bytes);
@@ -288,6 +285,7 @@ struct ofport_dpif {
     struct list bundle_node;    /* In struct ofbundle's "ports" list. */
     struct cfm *cfm;            /* Connectivity Fault Management, if any. */
     tag_type tag;               /* Tag associated with this port. */
+    uint32_t bond_stable_id;    /* stable_id to use as bond slave, or 0. */
 };
 
 static struct ofport_dpif *
@@ -299,14 +297,16 @@ ofport_dpif_cast(const struct ofport *ofport)
 
 static void port_run(struct ofport_dpif *);
 static void port_wait(struct ofport_dpif *);
-static int set_cfm(struct ofport *, const struct cfm *,
-                   const uint16_t *remote_mps, size_t n_remote_mps);
+static int set_cfm(struct ofport *, const struct cfm_settings *);
 
 struct ofproto_dpif {
     struct ofproto up;
     struct dpif *dpif;
     int max_ports;
 
+    /* Statistics. */
+    uint64_t n_matches;
+
     /* Bridging. */
     struct netflow *netflow;
     struct ofproto_sflow *sflow;
@@ -351,8 +351,7 @@ static void handle_upcall(struct ofproto_dpif *, struct dpif_upcall *);
 static int expire(struct ofproto_dpif *);
 
 /* Utilities. */
-static int send_packet(struct ofproto_dpif *,
-                       uint32_t odp_port, uint16_t vlan_tci,
+static int send_packet(struct ofproto_dpif *, uint32_t odp_port,
                        const struct ofpbuf *packet);
 
 /* Global variables. */
@@ -417,6 +416,7 @@ construct(struct ofproto *ofproto_)
     }
 
     ofproto->max_ports = dpif_get_max_ports(ofproto->dpif);
+    ofproto->n_matches = 0;
 
     error = dpif_recv_set_mask(ofproto->dpif,
                                ((1u << DPIF_UC_MISS) |
@@ -445,6 +445,10 @@ construct(struct ofproto *ofproto_)
     ofproto->need_revalidate = false;
     tag_set_init(&ofproto->revalidate_set);
 
+    ofproto->up.tables = xmalloc(sizeof *ofproto->up.tables);
+    classifier_init(&ofproto->up.tables[0]);
+    ofproto->up.n_tables = 1;
+
     ofproto_dpif_unixctl_init();
 
     return 0;
@@ -586,6 +590,39 @@ flush(struct ofproto *ofproto_)
     dpif_flow_flush(ofproto->dpif);
 }
 
+static void
+get_features(struct ofproto *ofproto_ OVS_UNUSED,
+             bool *arp_match_ip, uint32_t *actions)
+{
+    *arp_match_ip = true;
+    *actions = ((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) |
+                (1u << OFPAT_ENQUEUE));
+}
+
+static void
+get_tables(struct ofproto *ofproto_, struct ofp_table_stats *ots)
+{
+    struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+    struct odp_stats s;
+
+    strcpy(ots->name, "classifier");
+
+    dpif_get_dp_stats(ofproto->dpif, &s);
+    put_32aligned_be64(&ots->lookup_count, htonll(s.n_hit + s.n_missed));
+    put_32aligned_be64(&ots->matched_count,
+                       htonll(s.n_hit + ofproto->n_matches));
+}
+
 static int
 set_netflow(struct ofproto *ofproto_,
             const struct netflow_options *netflow_options)
@@ -644,7 +681,7 @@ port_destruct(struct ofport *port_)
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto);
 
     bundle_remove(port_);
-    set_cfm(port_, NULL, NULL, 0);
+    set_cfm(port_, NULL);
     if (ofproto->sflow) {
         ofproto_sflow_del_port(ofproto->sflow, port->odp_port);
     }
@@ -698,26 +735,19 @@ set_sflow(struct ofproto *ofproto_,
 }
 
 static int
-set_cfm(struct ofport *ofport_, const struct cfm *cfm,
-        const uint16_t *remote_mps, size_t n_remote_mps)
+set_cfm(struct ofport *ofport_, const struct cfm_settings *s)
 {
     struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
     int error;
 
-    if (!cfm) {
+    if (!s) {
         error = 0;
     } else {
         if (!ofport->cfm) {
-            ofport->cfm = cfm_create();
+            ofport->cfm = cfm_create(netdev_get_name(ofport->up.netdev));
         }
 
-        ofport->cfm->mpid = cfm->mpid;
-        ofport->cfm->interval = cfm->interval;
-        memcpy(ofport->cfm->maid, cfm->maid, CCM_MAID_LEN);
-
-        cfm_update_remote_mps(ofport->cfm, remote_mps, n_remote_mps);
-
-        if (cfm_configure(ofport->cfm)) {
+        if (cfm_configure(ofport->cfm, s)) {
             return 0;
         }
 
@@ -729,11 +759,11 @@ set_cfm(struct ofport *ofport_, const struct cfm *cfm,
 }
 
 static int
-get_cfm(struct ofport *ofport_, const struct cfm **cfmp)
+get_cfm_fault(const struct ofport *ofport_)
 {
     struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
-    *cfmp = ofport->cfm;
-    return 0;
+
+    return ofport->cfm ? cfm_get_fault(ofport->cfm) : -1;
 }
 \f
 /* Bundles. */
@@ -792,6 +822,8 @@ bundle_del_port(struct ofport_dpif *port)
 {
     struct ofbundle *bundle = port->bundle;
 
+    bundle->ofproto->need_revalidate = true;
+
     list_remove(&port->bundle_node);
     port->bundle = NULL;
 
@@ -812,7 +844,8 @@ bundle_del_port(struct ofport_dpif *port)
 
 static bool
 bundle_add_port(struct ofbundle *bundle, uint32_t ofp_port,
-                struct lacp_slave_settings *lacp)
+                struct lacp_slave_settings *lacp,
+                uint32_t bond_stable_id)
 {
     struct ofport_dpif *port;
 
@@ -822,6 +855,7 @@ bundle_add_port(struct ofbundle *bundle, uint32_t ofp_port,
     }
 
     if (port->bundle != bundle) {
+        bundle->ofproto->need_revalidate = true;
         if (port->bundle) {
             bundle_del_port(port);
         }
@@ -836,6 +870,8 @@ bundle_add_port(struct ofbundle *bundle, uint32_t ofp_port,
         lacp_slave_register(bundle->lacp, port, lacp);
     }
 
+    port->bond_stable_id = bond_stable_id;
+
     return true;
 }
 
@@ -939,7 +975,8 @@ bundle_set(struct ofproto *ofproto_, void *aux,
     ok = true;
     for (i = 0; i < s->n_slaves; i++) {
         if (!bundle_add_port(bundle, s->slaves[i],
-                             s->lacp ? &s->lacp_slaves[i] : NULL)) {
+                             s->lacp ? &s->lacp_slaves[i] : NULL,
+                             s->bond_stable_ids ? s->bond_stable_ids[i] : 0)) {
             ok = false;
         }
     }
@@ -948,7 +985,7 @@ bundle_set(struct ofproto *ofproto_, void *aux,
 
         LIST_FOR_EACH_SAFE (port, next_port, bundle_node, &bundle->ports) {
             for (i = 0; i < s->n_slaves; i++) {
-                if (s->slaves[i] == odp_port_to_ofp_port(port->odp_port)) {
+                if (s->slaves[i] == port->up.ofp_port) {
                     goto found;
                 }
             }
@@ -987,13 +1024,11 @@ bundle_set(struct ofproto *ofproto_, void *aux,
             }
         } else {
             bundle->bond = bond_create(s->bond);
+            ofproto->need_revalidate = true;
         }
 
         LIST_FOR_EACH (port, bundle_node, &bundle->ports) {
-            uint16_t stable_id = (bundle->lacp
-                                  ? lacp_slave_get_port_id(bundle->lacp, port)
-                                  : port->odp_port);
-            bond_slave_register(bundle->bond, port, stable_id,
+            bond_slave_register(bundle->bond, port, port->bond_stable_id,
                                 port->up.netdev);
         }
     } else {
@@ -1099,7 +1134,11 @@ bundle_run(struct ofbundle *bundle)
 
         LIST_FOR_EACH (port, bundle_node, &bundle->ports) {
             bool may_enable = lacp_slave_may_enable(bundle->lacp, port);
-            bond_slave_set_lacp_may_enable(bundle->bond, port, may_enable);
+
+            if (may_enable && port->cfm) {
+                may_enable = !cfm_get_fault(port->cfm);
+            }
+            bond_slave_set_may_enable(bundle->bond, port, may_enable);
         }
 
         bond_run(bundle->bond, &bundle->ofproto->revalidate_set,
@@ -1314,7 +1353,8 @@ is_mirror_output_bundle(struct ofproto *ofproto_, void *aux)
 static struct ofport_dpif *
 get_ofp_port(struct ofproto_dpif *ofproto, uint16_t ofp_port)
 {
-    return ofport_dpif_cast(ofproto_get_port(&ofproto->up, ofp_port));
+    struct ofport *ofport = ofproto_get_port(&ofproto->up, ofp_port);
+    return ofport ? ofport_dpif_cast(ofport) : NULL;
 }
 
 static struct ofport_dpif *
@@ -1340,14 +1380,11 @@ port_run(struct ofport_dpif *ofport)
 
         if (cfm_should_send_ccm(ofport->cfm)) {
             struct ofpbuf packet;
-            struct ccm *ccm;
 
             ofpbuf_init(&packet, 0);
-            ccm = eth_compose(&packet, eth_addr_ccm, ofport->up.opp.hw_addr,
-                              ETH_TYPE_CFM, sizeof *ccm);
-            cfm_compose_ccm(ofport->cfm, ccm);
+            cfm_compose_ccm(ofport->cfm, &packet, ofport->up.opp.hw_addr);
             send_packet(ofproto_dpif_cast(ofport->up.ofproto),
-                        ofport->odp_port, 0, &packet);
+                        ofport->odp_port, &packet);
             ofpbuf_uninit(&packet);
         }
     }
@@ -1508,19 +1545,19 @@ process_special(struct ofproto_dpif *ofproto, const struct flow *flow,
 {
     if (cfm_should_process_flow(flow)) {
         struct ofport_dpif *ofport = get_ofp_port(ofproto, flow->in_port);
-        if (ofport && ofport->cfm) {
+        if (packet && ofport && ofport->cfm) {
             cfm_process_heartbeat(ofport->cfm, packet);
         }
         return true;
     } else if (flow->dl_type == htons(ETH_TYPE_LACP)) {
         struct ofport_dpif *port = get_ofp_port(ofproto, flow->in_port);
-        if (port && port->bundle && port->bundle->lacp) {
+        if (packet && port && port->bundle && port->bundle->lacp) {
             const struct lacp_pdu *pdu = parse_lacp_packet(packet);
             if (pdu) {
                 lacp_process_pdu(port->bundle->lacp, port, pdu);
             }
-            return true;
         }
+        return true;
     }
     return false;
 }
@@ -1540,13 +1577,14 @@ handle_miss_upcall(struct ofproto_dpif *ofproto, struct dpif_upcall *upcall)
     /* Handle 802.1ag and LACP. */
     if (process_special(ofproto, &flow, upcall->packet)) {
         ofpbuf_delete(upcall->packet);
+        ofproto->n_matches++;
         return;
     }
 
     /* Check with in-band control to see if this packet should be sent
      * to the local port regardless of the flow table. */
     if (connmgr_msg_in_hook(ofproto->up.connmgr, &flow, upcall->packet)) {
-        send_packet(ofproto, OFPP_LOCAL, 0, upcall->packet);
+        send_packet(ofproto, ODPP_LOCAL, upcall->packet);
     }
 
     facet = facet_lookup_valid(ofproto, &flow);
@@ -1594,6 +1632,7 @@ handle_miss_upcall(struct ofproto_dpif *ofproto, struct dpif_upcall *upcall)
 
     facet_execute(ofproto, facet, upcall->packet);
     facet_install(ofproto, facet, false);
+    ofproto->n_matches++;
 }
 
 static void
@@ -1655,7 +1694,7 @@ expire(struct ofproto_dpif *ofproto)
     expire_facets(ofproto, dp_max_idle);
 
     /* Expire OpenFlow flows whose idle_timeout or hard_timeout has passed. */
-    cls_cursor_init(&cursor, &ofproto->up.cls, NULL);
+    cls_cursor_init(&cursor, &ofproto->up.tables[0], NULL);
     CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, up.cr, &cursor) {
         rule_expire(rule);
     }
@@ -1968,9 +2007,16 @@ execute_odp_actions(struct ofproto_dpif *ofproto, const struct flow *flow,
 
         return true;
     } else {
+        struct odputil_keybuf keybuf;
+        struct ofpbuf key;
         int error;
 
-        error = dpif_execute(ofproto->dpif, odp_actions, actions_len, packet);
+        ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
+        odp_flow_key_from_flow(&key, flow);
+
+        error = dpif_execute(ofproto->dpif, key.data, key.size,
+                             odp_actions, actions_len, packet);
+
         ofpbuf_delete(packet);
         return !error;
     }
@@ -2046,6 +2092,12 @@ facet_make_actions(struct ofproto_dpif *p, struct facet *facet,
     ofpbuf_delete(odp_actions);
 }
 
+/* Updates 'facet''s flow in the datapath setting its actions to 'actions_len'
+ * bytes of actions in 'actions'.  If 'stats' is non-null, statistics counters
+ * in the datapath will be zeroed and 'stats' will be updated with traffic new
+ * since 'facet' was last updated.
+ *
+ * Returns 0 if successful, otherwise a positive errno value.*/
 static int
 facet_put__(struct ofproto_dpif *ofproto, struct facet *facet,
             const struct nlattr *actions, size_t actions_len,
@@ -2054,19 +2106,24 @@ facet_put__(struct ofproto_dpif *ofproto, struct facet *facet,
     struct odputil_keybuf keybuf;
     enum dpif_flow_put_flags flags;
     struct ofpbuf key;
+    int ret;
 
     flags = DPIF_FP_CREATE | DPIF_FP_MODIFY;
     if (stats) {
         flags |= DPIF_FP_ZERO_STATS;
-        facet->dp_packet_count = 0;
-        facet->dp_byte_count = 0;
     }
 
     ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
     odp_flow_key_from_flow(&key, &facet->flow);
 
-    return dpif_flow_put(ofproto->dpif, flags, key.data, key.size,
-                         actions, actions_len, stats);
+    ret = dpif_flow_put(ofproto->dpif, flags, key.data, key.size,
+                        actions, actions_len, stats);
+
+    if (stats) {
+        facet_reset_dp_stats(facet, stats);
+    }
+
+    return ret;
 }
 
 /* If 'facet' is installable, inserts or re-inserts it into 'p''s datapath.  If
@@ -2084,6 +2141,12 @@ facet_install(struct ofproto_dpif *p, struct facet *facet, bool zero_stats)
     }
 }
 
+static int
+vlan_tci_to_openflow_vlan(ovs_be16 vlan_tci)
+{
+    return vlan_tci != htons(0) ? vlan_tci_to_vid(vlan_tci) : OFP_VLAN_NONE;
+}
+
 static void
 facet_account(struct ofproto_dpif *ofproto,
               struct facet *facet, uint64_t extra_bytes)
@@ -2093,6 +2156,7 @@ facet_account(struct ofproto_dpif *ofproto,
     const struct nlattr *a;
     tag_type dummy = 0;
     unsigned int left;
+    ovs_be16 vlan_tci;
     int vlan;
 
     total_bytes = facet->byte_count + extra_bytes;
@@ -2120,14 +2184,32 @@ facet_account(struct ofproto_dpif *ofproto,
     if (!ofproto->has_bonded_bundles) {
         return;
     }
+
+    /* This loop feeds byte counters to bond_account() for rebalancing to use
+     * as a basis.  We also need to track the actual VLAN on which the packet
+     * is going to be sent to ensure that it matches the one passed to
+     * bond_choose_output_slave().  (Otherwise, we will account to the wrong
+     * hash bucket.) */
+    vlan_tci = facet->flow.vlan_tci;
     NL_ATTR_FOR_EACH_UNSAFE (a, left, facet->actions, facet->actions_len) {
-        if (nl_attr_type(a) == ODP_ACTION_ATTR_OUTPUT) {
-            struct ofport_dpif *port;
+        struct ofport_dpif *port;
 
+        switch (nl_attr_type(a)) {
+        case ODP_ACTION_ATTR_OUTPUT:
             port = get_odp_port(ofproto, nl_attr_get_u32(a));
             if (port && port->bundle && port->bundle->bond) {
-                bond_account(port->bundle->bond, &facet->flow, vlan, n_bytes);
+                bond_account(port->bundle->bond, &facet->flow,
+                             vlan_tci_to_openflow_vlan(vlan_tci), n_bytes);
             }
+            break;
+
+        case ODP_ACTION_ATTR_STRIP_VLAN:
+            vlan_tci = htons(0);
+            break;
+
+        case ODP_ACTION_ATTR_SET_DL_TCI:
+            vlan_tci = nl_attr_get_be16(a);
+            break;
         }
     }
 }
@@ -2140,16 +2222,17 @@ facet_uninstall(struct ofproto_dpif *p, struct facet *facet)
         struct odputil_keybuf keybuf;
         struct dpif_flow_stats stats;
         struct ofpbuf key;
+        int error;
 
         ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
         odp_flow_key_from_flow(&key, &facet->flow);
 
-        if (!dpif_flow_del(p->dpif, key.data, key.size, &stats)) {
+        error = dpif_flow_del(p->dpif, key.data, key.size, &stats);
+        facet_reset_dp_stats(facet, &stats);
+        if (!error) {
             facet_update_stats(p, facet, &stats);
         }
         facet->installed = false;
-        facet->dp_packet_count = 0;
-        facet->dp_byte_count = 0;
     } else {
         assert(facet->dp_packet_count == 0);
         assert(facet->dp_byte_count == 0);
@@ -2168,6 +2251,24 @@ facet_is_controller_flow(struct facet *facet)
                                       htons(OFPP_CONTROLLER)));
 }
 
+/* Resets 'facet''s datapath statistics counters.  This should be called when
+ * 'facet''s statistics are cleared in the datapath.  If 'stats' is non-null,
+ * it should contain the statistics returned by dpif when 'facet' was reset in
+ * the datapath.  'stats' will be modified to only included statistics new
+ * since 'facet' was last updated. */
+static void
+facet_reset_dp_stats(struct facet *facet, struct dpif_flow_stats *stats)
+{
+    if (stats && facet->dp_packet_count <= stats->n_packets
+        && facet->dp_byte_count <= stats->n_bytes) {
+        stats->n_packets -= facet->dp_packet_count;
+        stats->n_bytes -= facet->dp_byte_count;
+    }
+
+    facet->dp_packet_count = 0;
+    facet->dp_byte_count = 0;
+}
+
 /* Folds all of 'facet''s statistics into its rule.  Also updates the
  * accounting ofhook and emits a NetFlow expiration if appropriate.  All of
  * 'facet''s statistics in the datapath should have been zeroed and folded into
@@ -2428,7 +2529,8 @@ static struct rule_dpif *
 rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow)
 {
     return rule_dpif_cast(rule_from_cls_rule(
-                              classifier_lookup(&ofproto->up.cls, flow)));
+                              classifier_lookup(&ofproto->up.tables[0],
+                                                flow)));
 }
 
 static struct rule *
@@ -2460,7 +2562,7 @@ rule_construct(struct rule *rule_)
     }
 
     old_rule = rule_dpif_cast(rule_from_cls_rule(classifier_find_rule_exactly(
-                                                     &ofproto->up.cls,
+                                                     &ofproto->up.tables[0],
                                                      &rule->up.cr)));
     if (old_rule) {
         ofproto_rule_destroy(&old_rule->up);
@@ -2470,7 +2572,7 @@ rule_construct(struct rule *rule_)
     rule->packet_count = 0;
     rule->byte_count = 0;
     list_init(&rule->facets);
-    classifier_insert(&ofproto->up.cls, &rule->up.cr);
+    classifier_insert(&ofproto->up.tables[0], &rule->up.cr);
 
     ofproto->need_revalidate = true;
 
@@ -2484,7 +2586,7 @@ rule_destruct(struct rule *rule_)
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
     struct facet *facet, *next_facet;
 
-    classifier_remove(&ofproto->up.cls, &rule->up.cr);
+    classifier_remove(&ofproto->up.tables[0], &rule->up.cr);
     LIST_FOR_EACH_SAFE (facet, next_facet, list_node, &rule->facets) {
         facet_revalidate(ofproto, facet);
     }
@@ -2570,25 +2672,26 @@ rule_modify_actions(struct rule *rule_,
     return error;
 }
 \f
-/* Sends 'packet' out of port 'odp_port' within 'ofproto'.  If 'vlan_tci' is
- * zero the packet will not have any 802.1Q hader; if it is nonzero, then the
- * packet will be sent with the VLAN TCI specified by 'vlan_tci & ~VLAN_CFI'.
- *
+/* Sends 'packet' out of port 'odp_port' within 'p'.
  * Returns 0 if successful, otherwise a positive errno value. */
 static int
-send_packet(struct ofproto_dpif *ofproto, uint32_t odp_port, uint16_t vlan_tci,
+send_packet(struct ofproto_dpif *ofproto, uint32_t odp_port,
             const struct ofpbuf *packet)
 {
-    struct ofpbuf odp_actions;
+    struct ofpbuf key, odp_actions;
+    struct odputil_keybuf keybuf;
+    struct flow flow;
     int error;
 
+    flow_extract((struct ofpbuf *) packet, 0, 0, &flow);
+    ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
+    odp_flow_key_from_flow(&key, &flow);
+
     ofpbuf_init(&odp_actions, 32);
-    if (vlan_tci != 0) {
-        nl_msg_put_u32(&odp_actions, ODP_ACTION_ATTR_SET_DL_TCI,
-                       ntohs(vlan_tci & ~VLAN_CFI));
-    }
     nl_msg_put_u32(&odp_actions, ODP_ACTION_ATTR_OUTPUT, odp_port);
-    error = dpif_execute(ofproto->dpif, odp_actions.data, odp_actions.size,
+    error = dpif_execute(ofproto->dpif,
+                         key.data, key.size,
+                         odp_actions.data, odp_actions.size,
                          packet);
     ofpbuf_uninit(&odp_actions);
 
@@ -3069,7 +3172,6 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx,
     ctx->flow = *flow;
     ctx->packet = packet;
     ctx->resubmit_hook = NULL;
-    ctx->check_special = true;
 }
 
 static struct ofpbuf *
@@ -3085,8 +3187,7 @@ xlate_actions(struct action_xlate_ctx *ctx,
     ctx->recurse = 0;
     ctx->last_pop_priority = -1;
 
-    if (ctx->check_special
-        && process_special(ctx->ofproto, &ctx->flow, ctx->packet)) {
+    if (process_special(ctx->ofproto, &ctx->flow, ctx->packet)) {
         ctx->may_set_up_flow = false;
     } else {
         do_xlate_actions(in, n_in, ctx);
@@ -3485,7 +3586,7 @@ is_admissible(struct ofproto_dpif *ofproto, const struct flow *flow,
 
     /* Find the port and bundle for the received packet. */
     in_port = get_ofp_port(ofproto, flow->in_port);
-    *in_bundlep = in_bundle = in_port->bundle;
+    *in_bundlep = in_bundle = in_port ? in_port->bundle : NULL;
     if (!in_port || !in_bundle) {
         /* No interface?  Something fishy... */
         if (have_packet) {
@@ -3635,13 +3736,18 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet,
     error = validate_actions(ofp_actions, n_ofp_actions, flow,
                              ofproto->max_ports);
     if (!error) {
+        struct odputil_keybuf keybuf;
         struct action_xlate_ctx ctx;
         struct ofpbuf *odp_actions;
+        struct ofpbuf key;
+
+        ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
+        odp_flow_key_from_flow(&key, flow);
 
         action_xlate_ctx_init(&ctx, ofproto, flow, packet);
         odp_actions = xlate_actions(&ctx, ofp_actions, n_ofp_actions);
-        dpif_execute(ofproto->dpif, odp_actions->data, odp_actions->size,
-                     packet);
+        dpif_execute(ofproto->dpif, key.data, key.size,
+                     odp_actions->data, odp_actions->size, packet);
         ofpbuf_delete(odp_actions);
     }
     return error;
@@ -3854,6 +3960,8 @@ const struct ofproto_class ofproto_dpif_class = {
     run,
     wait,
     flush,
+    get_features,
+    get_tables,
     port_alloc,
     port_construct,
     port_destruct,
@@ -3869,6 +3977,7 @@ const struct ofproto_class ofproto_dpif_class = {
     port_poll,
     port_poll_wait,
     port_is_lacp_current,
+    NULL,                       /* rule_choose_table */
     rule_alloc,
     rule_construct,
     rule_destruct,
@@ -3883,7 +3992,7 @@ const struct ofproto_class ofproto_dpif_class = {
     get_netflow_ids,
     set_sflow,
     set_cfm,
-    get_cfm,
+    get_cfm_fault,
     bundle_set,
     bundle_remove,
     mirror_set,