Remove NXAST_DROP_SPOOFED_ARP action.
[sliver-openvswitch.git] / ofproto / ofproto-dpif.c
index d3cb92b..8088c68 100644 (file)
@@ -184,8 +184,9 @@ struct action_xlate_ctx {
  * reason to look at them. */
 
     int recurse;                /* Recursion level, via xlate_table_action. */
-    int last_pop_priority;      /* Offset in 'odp_actions' just past most
-                                 * recent ODP_ACTION_ATTR_SET_PRIORITY. */
+    uint32_t priority;          /* Current flow priority. 0 if none. */
+    struct flow base_flow;      /* Flow at the last commit. */
+    uint32_t base_priority;     /* Priority at the last commit. */
 };
 
 static void action_xlate_ctx_init(struct action_xlate_ctx *,
@@ -266,6 +267,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);
@@ -296,8 +298,7 @@ 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;
@@ -681,7 +682,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);
     }
@@ -735,26 +736,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;
         }
 
@@ -766,11 +760,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. */
@@ -1141,7 +1135,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,
@@ -1383,12 +1381,9 @@ 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, &packet);
             ofpbuf_uninit(&packet);
@@ -1551,19 +1546,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;
 }
@@ -2013,9 +2008,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;
     }
@@ -2091,6 +2093,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,
@@ -2099,19 +2107,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
@@ -2210,16 +2223,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);
@@ -2238,6 +2252,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
@@ -2647,12 +2679,20 @@ static int
 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);
     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);
 
@@ -2669,6 +2709,71 @@ static void do_xlate_actions(const union ofp_action *in, size_t n_in,
                              struct action_xlate_ctx *ctx);
 static bool xlate_normal(struct action_xlate_ctx *);
 
+static void
+commit_odp_actions(struct action_xlate_ctx *ctx)
+{
+    const struct flow *flow = &ctx->flow;
+    struct flow *base = &ctx->base_flow;
+    struct ofpbuf *odp_actions = ctx->odp_actions;
+
+    if (base->tun_id != flow->tun_id) {
+        nl_msg_put_be64(odp_actions, ODP_ACTION_ATTR_SET_TUNNEL, flow->tun_id);
+        base->tun_id = flow->tun_id;
+    }
+
+    if (base->nw_src != flow->nw_src) {
+        nl_msg_put_be32(odp_actions, ODP_ACTION_ATTR_SET_NW_SRC, flow->nw_src);
+        base->nw_src = flow->nw_src;
+    }
+
+    if (base->nw_dst != flow->nw_dst) {
+        nl_msg_put_be32(odp_actions, ODP_ACTION_ATTR_SET_NW_DST, flow->nw_dst);
+        base->nw_dst = flow->nw_dst;
+    }
+
+    if (base->vlan_tci != flow->vlan_tci) {
+        if (!(flow->vlan_tci & htons(VLAN_CFI))) {
+            nl_msg_put_flag(odp_actions, ODP_ACTION_ATTR_STRIP_VLAN);
+        } else {
+            nl_msg_put_be16(odp_actions, ODP_ACTION_ATTR_SET_DL_TCI,
+                            flow->vlan_tci & ~htons(VLAN_CFI));
+        }
+        base->vlan_tci = flow->vlan_tci;
+    }
+
+    if (base->tp_src != flow->tp_src) {
+        nl_msg_put_be16(odp_actions, ODP_ACTION_ATTR_SET_TP_SRC, flow->tp_src);
+        base->tp_src = flow->tp_src;
+    }
+
+    if (base->tp_dst != flow->tp_dst) {
+        nl_msg_put_be16(odp_actions, ODP_ACTION_ATTR_SET_TP_DST, flow->tp_dst);
+        base->tp_dst = flow->tp_dst;
+    }
+
+    if (!eth_addr_equals(base->dl_src, flow->dl_src)) {
+        nl_msg_put_unspec(odp_actions, ODP_ACTION_ATTR_SET_DL_SRC,
+                          flow->dl_src, ETH_ADDR_LEN);
+        memcpy(base->dl_src, flow->dl_src, ETH_ADDR_LEN);
+    }
+
+    if (!eth_addr_equals(base->dl_dst, flow->dl_dst)) {
+        nl_msg_put_unspec(odp_actions, ODP_ACTION_ATTR_SET_DL_DST,
+                          flow->dl_dst, ETH_ADDR_LEN);
+        memcpy(base->dl_dst, flow->dl_dst, ETH_ADDR_LEN);
+    }
+
+    if (ctx->base_priority != ctx->priority) {
+        if (ctx->priority) {
+            nl_msg_put_u32(odp_actions, ODP_ACTION_ATTR_SET_PRIORITY,
+                           ctx->priority);
+        } else {
+            nl_msg_put_flag(odp_actions, ODP_ACTION_ATTR_POP_PRIORITY);
+        }
+        ctx->base_priority = ctx->priority;
+    }
+}
+
 static void
 add_output_action(struct action_xlate_ctx *ctx, uint16_t ofp_port)
 {
@@ -2688,6 +2793,7 @@ add_output_action(struct action_xlate_ctx *ctx, uint16_t ofp_port)
          */
     }
 
+    commit_odp_actions(ctx);
     nl_msg_put_u32(ctx->odp_actions, ODP_ACTION_ATTR_OUTPUT, odp_port);
     ctx->nf_output_iface = ofp_port;
 }
@@ -2725,20 +2831,20 @@ xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port)
 }
 
 static void
-flood_packets(struct ofproto_dpif *ofproto,
-              uint16_t ofp_in_port, ovs_be32 mask,
-              uint16_t *nf_output_iface, struct ofpbuf *odp_actions)
+flood_packets(struct action_xlate_ctx *ctx, ovs_be32 mask)
 {
     struct ofport_dpif *ofport;
 
-    HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
+    commit_odp_actions(ctx);
+    HMAP_FOR_EACH (ofport, up.hmap_node, &ctx->ofproto->up.ports) {
         uint16_t ofp_port = ofport->up.ofp_port;
-        if (ofp_port != ofp_in_port && !(ofport->up.opp.config & mask)) {
-            nl_msg_put_u32(odp_actions, ODP_ACTION_ATTR_OUTPUT,
+        if (ofp_port != ctx->flow.in_port && !(ofport->up.opp.config & mask)) {
+            nl_msg_put_u32(ctx->odp_actions, ODP_ACTION_ATTR_OUTPUT,
                            ofport->odp_port);
         }
     }
-    *nf_output_iface = NF_OUT_FLOOD;
+
+    ctx->nf_output_iface = NF_OUT_FLOOD;
 }
 
 static void
@@ -2760,14 +2866,13 @@ xlate_output_action__(struct action_xlate_ctx *ctx,
         xlate_normal(ctx);
         break;
     case OFPP_FLOOD:
-        flood_packets(ctx->ofproto, ctx->flow.in_port, htonl(OFPPC_NO_FLOOD),
-                      &ctx->nf_output_iface, ctx->odp_actions);
+        flood_packets(ctx,  htonl(OFPPC_NO_FLOOD));
         break;
     case OFPP_ALL:
-        flood_packets(ctx->ofproto, ctx->flow.in_port, htonl(0),
-                      &ctx->nf_output_iface, ctx->odp_actions);
+        flood_packets(ctx, htonl(0));
         break;
     case OFPP_CONTROLLER:
+        commit_odp_actions(ctx);
         nl_msg_put_u64(ctx->odp_actions, ODP_ACTION_ATTR_CONTROLLER, max_len);
         break;
     case OFPP_LOCAL:
@@ -2797,34 +2902,12 @@ xlate_output_action(struct action_xlate_ctx *ctx,
     xlate_output_action__(ctx, ntohs(oao->port), ntohs(oao->max_len));
 }
 
-/* If the final ODP action in 'ctx' is "pop priority", drop it, as an
- * optimization, because we're going to add another action that sets the
- * priority immediately after, or because there are no actions following the
- * pop.  */
-static void
-remove_pop_action(struct action_xlate_ctx *ctx)
-{
-    if (ctx->odp_actions->size == ctx->last_pop_priority) {
-        ctx->odp_actions->size -= NLA_ALIGN(NLA_HDRLEN);
-        ctx->last_pop_priority = -1;
-    }
-}
-
-static void
-add_pop_action(struct action_xlate_ctx *ctx)
-{
-    if (ctx->odp_actions->size != ctx->last_pop_priority) {
-        nl_msg_put_flag(ctx->odp_actions, ODP_ACTION_ATTR_POP_PRIORITY);
-        ctx->last_pop_priority = ctx->odp_actions->size;
-    }
-}
-
 static void
 xlate_enqueue_action(struct action_xlate_ctx *ctx,
                      const struct ofp_action_enqueue *oae)
 {
     uint16_t ofp_port, odp_port;
-    uint32_t priority;
+    uint32_t ctx_priority, priority;
     int error;
 
     error = dpif_queue_to_priority(ctx->ofproto->dpif, ntohl(oae->queue_id),
@@ -2843,10 +2926,10 @@ xlate_enqueue_action(struct action_xlate_ctx *ctx,
     odp_port = ofp_port_to_odp_port(ofp_port);
 
     /* Add ODP actions. */
-    remove_pop_action(ctx);
-    nl_msg_put_u32(ctx->odp_actions, ODP_ACTION_ATTR_SET_PRIORITY, priority);
+    ctx_priority = ctx->priority;
+    ctx->priority = priority;
     add_output_action(ctx, odp_port);
-    add_pop_action(ctx);
+    ctx->priority = ctx_priority;
 
     /* Update NetFlow output port. */
     if (ctx->nf_output_iface == NF_OUT_DROP) {
@@ -2871,20 +2954,7 @@ xlate_set_queue_action(struct action_xlate_ctx *ctx,
         return;
     }
 
-    remove_pop_action(ctx);
-    nl_msg_put_u32(ctx->odp_actions, ODP_ACTION_ATTR_SET_PRIORITY, priority);
-}
-
-static void
-xlate_set_dl_tci(struct action_xlate_ctx *ctx)
-{
-    ovs_be16 tci = ctx->flow.vlan_tci;
-    if (!(tci & htons(VLAN_CFI))) {
-        nl_msg_put_flag(ctx->odp_actions, ODP_ACTION_ATTR_STRIP_VLAN);
-    } else {
-        nl_msg_put_be16(ctx->odp_actions, ODP_ACTION_ATTR_SET_DL_TCI,
-                        tci & ~htons(VLAN_CFI));
-    }
+    ctx->priority = priority;
 }
 
 struct xlate_reg_state {
@@ -2892,27 +2962,6 @@ struct xlate_reg_state {
     ovs_be64 tun_id;
 };
 
-static void
-save_reg_state(const struct action_xlate_ctx *ctx,
-               struct xlate_reg_state *state)
-{
-    state->vlan_tci = ctx->flow.vlan_tci;
-    state->tun_id = ctx->flow.tun_id;
-}
-
-static void
-update_reg_state(struct action_xlate_ctx *ctx,
-                 const struct xlate_reg_state *state)
-{
-    if (ctx->flow.vlan_tci != state->vlan_tci) {
-        xlate_set_dl_tci(ctx);
-    }
-    if (ctx->flow.tun_id != state->tun_id) {
-        nl_msg_put_be64(ctx->odp_actions,
-                        ODP_ACTION_ATTR_SET_TUNNEL, ctx->flow.tun_id);
-    }
-}
-
 static void
 xlate_autopath(struct action_xlate_ctx *ctx,
                const struct nx_action_autopath *naa)
@@ -2943,7 +2992,6 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
     const struct nx_action_multipath *nam;
     const struct nx_action_autopath *naa;
     enum nx_action_subtype subtype = ntohs(nah->subtype);
-    struct xlate_reg_state state;
     ovs_be64 tun_id;
 
     assert(nah->vendor == htonl(NX_VENDOR_ID));
@@ -2956,38 +3004,26 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
     case NXAST_SET_TUNNEL:
         nast = (const struct nx_action_set_tunnel *) nah;
         tun_id = htonll(ntohl(nast->tun_id));
-        nl_msg_put_be64(ctx->odp_actions, ODP_ACTION_ATTR_SET_TUNNEL, tun_id);
         ctx->flow.tun_id = tun_id;
         break;
 
-    case NXAST_DROP_SPOOFED_ARP:
-        if (ctx->flow.dl_type == htons(ETH_TYPE_ARP)) {
-            nl_msg_put_flag(ctx->odp_actions,
-                            ODP_ACTION_ATTR_DROP_SPOOFED_ARP);
-        }
-        break;
-
     case NXAST_SET_QUEUE:
         nasq = (const struct nx_action_set_queue *) nah;
         xlate_set_queue_action(ctx, nasq);
         break;
 
     case NXAST_POP_QUEUE:
-        add_pop_action(ctx);
+        ctx->priority = 0;
         break;
 
     case NXAST_REG_MOVE:
-        save_reg_state(ctx, &state);
         nxm_execute_reg_move((const struct nx_action_reg_move *) nah,
                              &ctx->flow);
-        update_reg_state(ctx, &state);
         break;
 
     case NXAST_REG_LOAD:
-        save_reg_state(ctx, &state);
         nxm_execute_reg_load((const struct nx_action_reg_load *) nah,
                              &ctx->flow);
-        update_reg_state(ctx, &state);
         break;
 
     case NXAST_NOTE:
@@ -2996,7 +3032,6 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
 
     case NXAST_SET_TUNNEL64:
         tun_id = ((const struct nx_action_set_tunnel64 *) nah)->tun_id;
-        nl_msg_put_be64(ctx->odp_actions, ODP_ACTION_ATTR_SET_TUNNEL, tun_id);
         ctx->flow.tun_id = tun_id;
         break;
 
@@ -3014,6 +3049,7 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
      * update the flow key in ctx->flow at the same time. */
 
     case NXAST_SNAT__OBSOLETE:
+    case NXAST_DROP_SPOOFED_ARP__OBSOLETE:
     default:
         VLOG_DBG_RL(&rl, "unknown Nicira action type %d", (int) subtype);
         break;
@@ -3050,62 +3086,45 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
         case OFPAT_SET_VLAN_VID:
             ctx->flow.vlan_tci &= ~htons(VLAN_VID_MASK);
             ctx->flow.vlan_tci |= ia->vlan_vid.vlan_vid | htons(VLAN_CFI);
-            xlate_set_dl_tci(ctx);
             break;
 
         case OFPAT_SET_VLAN_PCP:
             ctx->flow.vlan_tci &= ~htons(VLAN_PCP_MASK);
             ctx->flow.vlan_tci |= htons(
                 (ia->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT) | VLAN_CFI);
-            xlate_set_dl_tci(ctx);
             break;
 
         case OFPAT_STRIP_VLAN:
             ctx->flow.vlan_tci = htons(0);
-            xlate_set_dl_tci(ctx);
             break;
 
         case OFPAT_SET_DL_SRC:
             oada = ((struct ofp_action_dl_addr *) ia);
-            nl_msg_put_unspec(ctx->odp_actions, ODP_ACTION_ATTR_SET_DL_SRC,
-                              oada->dl_addr, ETH_ADDR_LEN);
             memcpy(ctx->flow.dl_src, oada->dl_addr, ETH_ADDR_LEN);
             break;
 
         case OFPAT_SET_DL_DST:
             oada = ((struct ofp_action_dl_addr *) ia);
-            nl_msg_put_unspec(ctx->odp_actions, ODP_ACTION_ATTR_SET_DL_DST,
-                              oada->dl_addr, ETH_ADDR_LEN);
             memcpy(ctx->flow.dl_dst, oada->dl_addr, ETH_ADDR_LEN);
             break;
 
         case OFPAT_SET_NW_SRC:
-            nl_msg_put_be32(ctx->odp_actions, ODP_ACTION_ATTR_SET_NW_SRC,
-                            ia->nw_addr.nw_addr);
             ctx->flow.nw_src = ia->nw_addr.nw_addr;
             break;
 
         case OFPAT_SET_NW_DST:
-            nl_msg_put_be32(ctx->odp_actions, ODP_ACTION_ATTR_SET_NW_DST,
-                            ia->nw_addr.nw_addr);
             ctx->flow.nw_dst = ia->nw_addr.nw_addr;
             break;
 
         case OFPAT_SET_NW_TOS:
-            nl_msg_put_u8(ctx->odp_actions, ODP_ACTION_ATTR_SET_NW_TOS,
-                          ia->nw_tos.nw_tos);
             ctx->flow.nw_tos = ia->nw_tos.nw_tos;
             break;
 
         case OFPAT_SET_TP_SRC:
-            nl_msg_put_be16(ctx->odp_actions, ODP_ACTION_ATTR_SET_TP_SRC,
-                            ia->tp_port.tp_port);
             ctx->flow.tp_src = ia->tp_port.tp_port;
             break;
 
         case OFPAT_SET_TP_DST:
-            nl_msg_put_be16(ctx->odp_actions, ODP_ACTION_ATTR_SET_TP_DST,
-                            ia->tp_port.tp_port);
             ctx->flow.tp_dst = ia->tp_port.tp_port;
             break;
 
@@ -3146,7 +3165,9 @@ xlate_actions(struct action_xlate_ctx *ctx,
     ctx->may_set_up_flow = true;
     ctx->nf_output_iface = NF_OUT_DROP;
     ctx->recurse = 0;
-    ctx->last_pop_priority = -1;
+    ctx->priority = 0;
+    ctx->base_priority = 0;
+    ctx->base_flow = ctx->flow;
 
     if (process_special(ctx->ofproto, &ctx->flow, ctx->packet)) {
         ctx->may_set_up_flow = false;
@@ -3154,8 +3175,6 @@ xlate_actions(struct action_xlate_ctx *ctx,
         do_xlate_actions(in, n_in, ctx);
     }
 
-    remove_pop_action(ctx);
-
     /* Check with in-band control to see if we're allowed to set up this
      * flow. */
     if (!connmgr_may_set_up_flow(ctx->ofproto->up.connmgr, &ctx->flow,
@@ -3697,13 +3716,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;
@@ -3933,6 +3957,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,
@@ -3947,7 +3972,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,