openflow: Remove OFPG11_*
[cascardo/ovs.git] / ofproto / ofproto-dpif-xlate.c
index 8a208a4..1738394 100644 (file)
@@ -205,7 +205,9 @@ struct xlate_ctx {
     uint32_t orig_skb_priority; /* Priority when packet arrived. */
     uint32_t sflow_n_outputs;   /* Number of output ports. */
     odp_port_t sflow_odp_port;  /* Output port for composing sFlow action. */
+    ofp_port_t nf_output_iface; /* Output interface index for NetFlow. */
     bool exit;                  /* No further actions should be processed. */
+    mirror_mask_t mirrors;      /* Bitmap of associated mirrors. */
 
    /* These are used for non-bond recirculation.  The recirculation IDs are
     * stored in xout and must be associated with a datapath flow (ukey),
@@ -298,6 +300,11 @@ struct xlate_ctx {
      * the MPLS label stack that was originally present. */
     bool was_mpls;
 
+    /* True if conntrack has been performed on this packet during processing
+     * on the current bridge. This is used to determine whether conntrack
+     * state from the datapath should be honored after recirculation. */
+    bool conntracked;
+
     /* OpenFlow 1.1+ action set.
      *
      * 'action_set' accumulates "struct ofpact"s added by OFPACT_WRITE_ACTIONS.
@@ -309,6 +316,7 @@ struct xlate_ctx {
 };
 
 static void xlate_action_set(struct xlate_ctx *ctx);
+static void xlate_commit_actions(struct xlate_ctx *ctx);
 
 static void
 ctx_trigger_recirculation(struct xlate_ctx *ctx)
@@ -528,6 +536,18 @@ xlate_report(struct xlate_ctx *ctx, const char *format, ...)
     }
 }
 
+static inline void
+xlate_report_actions(struct xlate_ctx *ctx, const char *title,
+                     const struct ofpact *ofpacts, size_t ofpacts_len)
+{
+    if (OVS_UNLIKELY(ctx->xin->report_hook)) {
+        struct ds s = DS_EMPTY_INITIALIZER;
+        ofpacts_format(ofpacts, ofpacts_len, &s);
+        xlate_report(ctx, "%s: %s", title, ds_cstr(&s));
+        ds_destroy(&s);
+    }
+}
+
 static void
 xlate_xbridge_init(struct xlate_cfg *xcfg, struct xbridge *xbridge)
 {
@@ -1528,74 +1548,61 @@ lookup_input_bundle(const struct xbridge *xbridge, ofp_port_t in_port,
 }
 
 static void
-add_mirror_actions(struct xlate_ctx *ctx, const struct flow *orig_flow)
+mirror_packet(struct xlate_ctx *ctx, struct xbundle *xbundle,
+              mirror_mask_t mirrors)
 {
-    const struct xbridge *xbridge = ctx->xbridge;
-    mirror_mask_t mirrors;
-    struct xbundle *in_xbundle;
-    uint16_t vlan;
-    uint16_t vid;
-
-    mirrors = ctx->xout->mirrors;
-    ctx->xout->mirrors = 0;
-
-    in_xbundle = lookup_input_bundle(xbridge, orig_flow->in_port.ofp_port,
-                                     ctx->xin->packet != NULL, NULL);
-    if (!in_xbundle) {
+    bool warn = ctx->xin->packet != NULL;
+    uint16_t vid = vlan_tci_to_vid(ctx->xin->flow.vlan_tci);
+    if (!input_vid_is_valid(vid, xbundle, warn)) {
         return;
     }
-    mirrors |= xbundle_mirror_src(xbridge, in_xbundle);
+    uint16_t vlan = input_vid_to_vlan(xbundle, vid);
 
-    /* Drop frames on bundles reserved for mirroring. */
-    if (xbundle_mirror_out(xbridge, in_xbundle)) {
-        if (ctx->xin->packet != NULL) {
-            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
-            VLOG_WARN_RL(&rl, "bridge %s: dropping packet received on port "
-                         "%s, which is reserved exclusively for mirroring",
-                         ctx->xbridge->name, in_xbundle->name);
-        }
-        ofpbuf_clear(ctx->odp_actions);
-        return;
-    }
+    const struct xbridge *xbridge = ctx->xbridge;
 
-    /* Check VLAN. */
-    vid = vlan_tci_to_vid(orig_flow->vlan_tci);
-    if (!input_vid_is_valid(vid, in_xbundle, ctx->xin->packet != NULL)) {
+    /* Don't mirror to destinations that we've already mirrored to. */
+    mirrors &= ~ctx->mirrors;
+    if (!mirrors) {
         return;
     }
-    vlan = input_vid_to_vlan(in_xbundle, vid);
 
-    if (!mirrors) {
-        return;
+    /* Record these mirrors so that we don't mirror to them again. */
+    ctx->mirrors |= mirrors;
+
+    if (ctx->xin->resubmit_stats) {
+        mirror_update_stats(xbridge->mbridge, mirrors,
+                            ctx->xin->resubmit_stats->n_packets,
+                            ctx->xin->resubmit_stats->n_bytes);
     }
+    if (ctx->xin->xcache) {
+        struct xc_entry *entry;
 
-    /* Restore the original packet before adding the mirror actions. */
-    ctx->xin->flow = *orig_flow;
+        entry = xlate_cache_add_entry(ctx->xin->xcache, XC_MIRROR);
+        entry->u.mirror.mbridge = mbridge_ref(xbridge->mbridge);
+        entry->u.mirror.mirrors = mirrors;
+    }
 
     while (mirrors) {
+        const unsigned long *vlans;
         mirror_mask_t dup_mirrors;
         struct ofbundle *out;
-        const unsigned long *vlans;
-        bool vlan_mirrored;
-        bool has_mirror;
         int out_vlan;
 
-        has_mirror = mirror_get(xbridge->mbridge, raw_ctz(mirrors),
-                                &vlans, &dup_mirrors, &out, &out_vlan);
+        bool has_mirror = mirror_get(xbridge->mbridge, raw_ctz(mirrors),
+                                     &vlans, &dup_mirrors, &out, &out_vlan);
         ovs_assert(has_mirror);
 
         if (vlans) {
             ctx->wc->masks.vlan_tci |= htons(VLAN_CFI | VLAN_VID_MASK);
         }
-        vlan_mirrored = !vlans || bitmap_is_set(vlans, vlan);
 
-        if (!vlan_mirrored) {
+        if (vlans && !bitmap_is_set(vlans, vlan)) {
             mirrors = zero_rightmost_1bit(mirrors);
             continue;
         }
 
         mirrors &= ~dup_mirrors;
-        ctx->xout->mirrors |= dup_mirrors;
+        ctx->mirrors |= dup_mirrors;
         if (out) {
             struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
             struct xbundle *out_xbundle = xbundle_lookup(xcfg, out);
@@ -1603,7 +1610,7 @@ add_mirror_actions(struct xlate_ctx *ctx, const struct flow *orig_flow)
                 output_normal(ctx, out_xbundle, vlan);
             }
         } else if (vlan != out_vlan
-                   && !eth_addr_is_reserved(orig_flow->dl_dst)) {
+                   && !eth_addr_is_reserved(ctx->xin->flow.dl_dst)) {
             struct xbundle *xbundle;
 
             LIST_FOR_EACH (xbundle, list_node, &xbridge->xbundles) {
@@ -1616,6 +1623,20 @@ add_mirror_actions(struct xlate_ctx *ctx, const struct flow *orig_flow)
     }
 }
 
+static void
+mirror_ingress_packet(struct xlate_ctx *ctx)
+{
+    if (mbridge_has_mirrors(ctx->xbridge->mbridge)) {
+        bool warn = ctx->xin->packet != NULL;
+        struct xbundle *xbundle = lookup_input_bundle(
+            ctx->xbridge, ctx->xin->flow.in_port.ofp_port, warn, NULL);
+        if (xbundle) {
+            mirror_packet(ctx, xbundle,
+                          xbundle_mirror_src(ctx->xbridge, xbundle));
+        }
+    }
+}
+
 /* Given 'vid', the VID obtained from the 802.1Q header that was received as
  * part of a packet (specify 0 if there was no 802.1Q header), and 'in_xbundle',
  * the bundle on which the packet was received, returns the VLAN to which the
@@ -2244,7 +2265,7 @@ xlate_normal_flood(struct xlate_ctx *ctx, struct xbundle *in_xbundle,
             output_normal(ctx, xbundle, vlan);
         }
     }
-    ctx->xout->nf_output_iface = NF_OUT_FLOOD;
+    ctx->nf_output_iface = NF_OUT_FLOOD;
 }
 
 static void
@@ -2259,8 +2280,6 @@ xlate_normal(struct xlate_ctx *ctx)
     uint16_t vlan;
     uint16_t vid;
 
-    ctx->xout->has_normal = true;
-
     memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src);
     memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
     wc->masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI);
@@ -2647,7 +2666,7 @@ tnl_route_lookup_flow(const struct flow *oflow,
     struct xlate_cfg *xcfg;
     ovs_be32 gw;
 
-    if (!ovs_router_lookup(oflow->tunnel.ip_dst, out_dev, &gw)) {
+    if (!ovs_router_lookup4(oflow->tunnel.ip_dst, out_dev, &gw)) {
         return -ENOENT;
     }
 
@@ -2676,35 +2695,36 @@ tnl_route_lookup_flow(const struct flow *oflow,
 }
 
 static int
-xlate_flood_packet(struct xbridge *xbridge, struct dp_packet *packet)
+compose_table_xlate(struct xlate_ctx *ctx, const struct xport *out_dev,
+                    struct dp_packet *packet)
 {
+    struct xbridge *xbridge = out_dev->xbridge;
     struct ofpact_output output;
     struct flow flow;
 
     ofpact_init(&output.ofpact, OFPACT_OUTPUT, sizeof output);
-    /* Use OFPP_NONE as the in_port to avoid special packet processing. */
     flow_extract(packet, &flow);
-    flow.in_port.ofp_port = OFPP_NONE;
-    output.port = OFPP_FLOOD;
+    flow.in_port.ofp_port = out_dev->ofp_port;
+    output.port = OFPP_TABLE;
     output.max_len = 0;
 
-    return ofproto_dpif_execute_actions(xbridge->ofproto, &flow, NULL,
-                                        &output.ofpact, sizeof output,
-                                        packet);
+    return ofproto_dpif_execute_actions__(xbridge->ofproto, &flow, NULL,
+                                          &output.ofpact, sizeof output,
+                                          ctx->recurse, ctx->resubmits, packet);
 }
 
 static void
-tnl_send_arp_request(const struct xport *out_dev, const uint8_t eth_src[ETH_ADDR_LEN],
+tnl_send_arp_request(struct xlate_ctx *ctx, const struct xport *out_dev,
+                     const struct eth_addr eth_src,
                      ovs_be32 ip_src, ovs_be32 ip_dst)
 {
-    struct xbridge *xbridge = out_dev->xbridge;
     struct dp_packet packet;
 
     dp_packet_init(&packet, 0);
     compose_arp(&packet, ARP_OP_REQUEST,
                 eth_src, eth_addr_zero, true, ip_src, ip_dst);
 
-    xlate_flood_packet(xbridge, &packet);
+    compose_table_xlate(ctx, out_dev, &packet);
     dp_packet_uninit(&packet);
 }
 
@@ -2715,8 +2735,8 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport,
     struct ovs_action_push_tnl tnl_push_data;
     struct xport *out_dev = NULL;
     ovs_be32 s_ip, d_ip = 0;
-    uint8_t smac[ETH_ADDR_LEN];
-    uint8_t dmac[ETH_ADDR_LEN];
+    struct eth_addr smac;
+    struct eth_addr dmac;
     int err;
 
     err = tnl_route_lookup_flow(flow, &d_ip, &out_dev);
@@ -2728,7 +2748,7 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport,
                  IP_ARGS(d_ip), netdev_get_name(out_dev->netdev));
 
     /* Use mac addr of bridge port of the peer. */
-    err = netdev_get_etheraddr(out_dev->netdev, smac);
+    err = netdev_get_etheraddr(out_dev->netdev, &smac);
     if (err) {
         xlate_report(ctx, "tunnel output device lacks Ethernet address");
         return err;
@@ -2740,12 +2760,12 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport,
         return err;
     }
 
-    err = tnl_arp_lookup(out_dev->xbridge->name, d_ip, dmac);
+    err = tnl_arp_lookup(out_dev->xbridge->name, d_ip, &dmac);
     if (err) {
         xlate_report(ctx, "ARP cache miss for "IP_FMT" on bridge %s, "
                      "sending ARP request",
                      IP_ARGS(d_ip), out_dev->xbridge->name);
-        tnl_send_arp_request(out_dev, smac, s_ip, d_ip);
+        tnl_send_arp_request(ctx, out_dev, smac, s_ip, d_ip);
         return err;
     }
     if (ctx->xin->xcache) {
@@ -2772,6 +2792,25 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport,
     return 0;
 }
 
+static void
+xlate_commit_actions(struct xlate_ctx *ctx)
+{
+    bool use_masked = ctx->xbridge->support.masked_set_action;
+
+    ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
+                                          ctx->odp_actions, ctx->wc,
+                                          use_masked);
+}
+
+static void
+clear_conntrack(struct flow *flow)
+{
+    flow->ct_state = 0;
+    flow->ct_zone = 0;
+    flow->ct_mark = 0;
+    memset(&flow->ct_label, 0, sizeof flow->ct_label);
+}
+
 static void
 compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
                         const struct xlate_bond_recirc *xr, bool check_stp)
@@ -2789,7 +2828,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
 
     /* If 'struct flow' gets additional metadata, we'll need to zero it out
      * before traversing a patch port. */
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 33);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 34);
     memset(&flow_tnl, 0, sizeof flow_tnl);
 
     if (!xport) {
@@ -2824,14 +2863,10 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
         }
     }
 
-    if (mbridge_has_mirrors(ctx->xbridge->mbridge) && xport->xbundle) {
-        ctx->xout->mirrors |= xbundle_mirror_dst(xport->xbundle->xbridge,
-                                                 xport->xbundle);
-    }
-
     if (xport->peer) {
         const struct xport *peer = xport->peer;
         struct flow old_flow = ctx->xin->flow;
+        bool old_conntrack = ctx->conntracked;
         bool old_was_mpls = ctx->was_mpls;
         cls_version_t old_version = ctx->tables_version;
         struct ofpbuf old_stack = ctx->stack;
@@ -2847,6 +2882,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
         memset(&flow->tunnel, 0, sizeof flow->tunnel);
         memset(flow->regs, 0, sizeof flow->regs);
         flow->actset_output = OFPP_UNSET;
+        ctx->conntracked = false;
+        clear_conntrack(flow);
 
         /* The bridge is now known so obtain its table version. */
         ctx->tables_version
@@ -2871,10 +2908,10 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
                  * the learning action look at the packet, then drop it. */
                 struct flow old_base_flow = ctx->base_flow;
                 size_t old_size = ctx->odp_actions->size;
-                mirror_mask_t old_mirrors = ctx->xout->mirrors;
+                mirror_mask_t old_mirrors = ctx->mirrors;
 
                 xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true);
-                ctx->xout->mirrors = old_mirrors;
+                ctx->mirrors = old_mirrors;
                 ctx->base_flow = old_base_flow;
                 ctx->odp_actions->size = old_size;
 
@@ -2901,6 +2938,10 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
          * bridge. */
         ctx->was_mpls = old_was_mpls;
 
+        /* The peer bridge's conntrack execution should have no effect on the
+         * original bridge. */
+        ctx->conntracked = old_conntrack;
+
         /* The fact that the peer bridge exits (for any reason) does not mean
          * that the original bridge should exit.  Specifically, if the peer
          * bridge recirculates (which typically modifies the packet), the
@@ -2989,11 +3030,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
     }
 
     if (out_port != ODPP_NONE) {
-        bool use_masked = ctx->xbridge->support.masked_set_action;
-
-        ctx->xout->slow |= commit_odp_actions(flow, &ctx->base_flow,
-                                              ctx->odp_actions,
-                                              wc, use_masked);
+        xlate_commit_actions(ctx);
 
         if (xr) {
             struct ovs_action_hash *act_hash;
@@ -3041,7 +3078,13 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
 
         ctx->sflow_odp_port = odp_port;
         ctx->sflow_n_outputs++;
-        ctx->xout->nf_output_iface = ofp_port;
+        ctx->nf_output_iface = ofp_port;
+    }
+
+    if (mbridge_has_mirrors(ctx->xbridge->mbridge) && xport->xbundle) {
+        mirror_packet(ctx, xport->xbundle,
+                      xbundle_mirror_dst(xport->xbundle->xbridge,
+                                         xport->xbundle));
     }
 
  out:
@@ -3119,7 +3162,6 @@ xlate_table_action(struct xlate_ctx *ctx, ofp_port_t in_port, uint8_t table_id,
         rule = rule_dpif_lookup_from_table(ctx->xbridge->ofproto,
                                            ctx->tables_version,
                                            &ctx->xin->flow, ctx->xin->wc,
-                                           ctx->xin->xcache != NULL,
                                            ctx->xin->resubmit_stats,
                                            &ctx->table_id, in_port,
                                            may_packet_in, honor_table_miss);
@@ -3138,6 +3180,7 @@ xlate_table_action(struct xlate_ctx *ctx, ofp_port_t in_port, uint8_t table_id,
 
                 entry = xlate_cache_add_entry(ctx->xin->xcache, XC_RULE);
                 entry->u.rule = rule;
+                rule_dpif_ref(rule);
             }
             xlate_recursively(ctx, rule);
         }
@@ -3312,6 +3355,11 @@ xlate_hash_fields_select_group(struct xlate_ctx *ctx, struct group_dpif *group)
             }
             basis = hash_bytes(&value, mf->n_bytes, basis);
 
+            /* For tunnels, hash in whether the field is present. */
+            if (mf_is_tun_metadata(mf)) {
+                basis = hash_boolean(mf_is_set(mf, &ctx->xin->flow), basis);
+            }
+
             mf_mask_field(mf, &ctx->wc->masks);
         }
     }
@@ -3428,7 +3476,7 @@ flood_packets(struct xlate_ctx *ctx, bool all)
         }
     }
 
-    ctx->xout->nf_output_iface = NF_OUT_FLOOD;
+    ctx->nf_output_iface = NF_OUT_FLOOD;
 }
 
 static void
@@ -3438,7 +3486,6 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
 {
     struct ofproto_packet_in *pin;
     struct dp_packet *packet;
-    bool use_masked;
 
     ctx->xout->slow |= SLOW_CONTROLLER;
     if (!ctx->xin->packet) {
@@ -3447,10 +3494,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
 
     packet = dp_packet_clone(ctx->xin->packet);
 
-    use_masked = ctx->xbridge->support.masked_set_action;
-    ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
-                                          ctx->odp_actions,
-                                          ctx->wc, use_masked);
+    xlate_commit_actions(ctx);
 
     odp_execute_actions(NULL, &packet, 1, false,
                         ctx->odp_actions->data, ctx->odp_actions->size, NULL);
@@ -3486,31 +3530,34 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
     dp_packet_delete(packet);
 }
 
-/* Called only when ctx->recirc_action_offset is set. */
 static void
-compose_recirculate_action(struct xlate_ctx *ctx)
+compose_recirculate_action__(struct xlate_ctx *ctx, uint8_t table)
 {
     struct recirc_metadata md;
-    bool use_masked;
     uint32_t id;
 
-    use_masked = ctx->xbridge->support.masked_set_action;
-    ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
-                                          ctx->odp_actions,
-                                          ctx->wc, use_masked);
-
     recirc_metadata_from_flow(&md, &ctx->xin->flow);
 
     ovs_assert(ctx->recirc_action_offset >= 0);
 
+    struct recirc_state state = {
+        .table_id = table,
+        .ofproto = ctx->xbridge->ofproto,
+        .metadata = md,
+        .stack = &ctx->stack,
+        .mirrors = ctx->mirrors,
+        .conntracked = ctx->conntracked,
+        .action_set_len = ctx->recirc_action_offset,
+        .ofpacts_len = ctx->action_set.size,
+        .ofpacts = ctx->action_set.data,
+    };
+
     /* Only allocate recirculation ID if we have a packet. */
     if (ctx->xin->packet) {
         /* Allocate a unique recirc id for the given metadata state in the
          * flow.  The life-cycle of this recirc id is managed by associating it
          * with the udpif key ('ukey') created for each new datapath flow. */
-        id = recirc_alloc_id_ctx(ctx->xbridge->ofproto, 0, &md, &ctx->stack,
-                                 ctx->recirc_action_offset,
-                                 ctx->action_set.size, ctx->action_set.data);
+        id = recirc_alloc_id_ctx(&state);
         if (!id) {
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
             VLOG_ERR_RL(&rl, "Failed to allocate recirculation id");
@@ -3520,12 +3567,12 @@ compose_recirculate_action(struct xlate_ctx *ctx)
     } else {
         /* Look up an existing recirc id for the given metadata state in the
          * flow.  No new reference is taken, as the ID is RCU protected and is
-         * only required temporarily for verification. */
-        id = recirc_find_id(ctx->xbridge->ofproto, 0, &md, &ctx->stack,
-                            ctx->recirc_action_offset,
-                            ctx->action_set.size, ctx->action_set.data);
-        /* We let zero 'id' to be used in the RECIRC action below, which will
-         * fail all revalidations as zero is not a valid recirculation ID. */
+         * only required temporarily for verification.
+         *
+         * This might fail and return 0.  We let zero 'id' to be used in the
+         * RECIRC action below, which will fail all revalidations as zero is
+         * not a valid recirculation ID. */
+        id = recirc_find_id(&state);
     }
 
     nl_msg_put_u32(ctx->odp_actions, OVS_ACTION_ATTR_RECIRC, id);
@@ -3536,6 +3583,25 @@ compose_recirculate_action(struct xlate_ctx *ctx)
     ctx->last_unroll_offset = -1;
 }
 
+/* Called only when ctx->recirc_action_offset is set. */
+static void
+compose_recirculate_action(struct xlate_ctx *ctx)
+{
+    xlate_commit_actions(ctx);
+    compose_recirculate_action__(ctx, 0);
+}
+
+/* Fork the pipeline here. The current packet will continue processing the
+ * current action list. A clone of the current packet will recirculate, skip
+ * the remainder of the current action list and asynchronously resume pipeline
+ * processing in 'table' with the current metadata and action set. */
+static void
+compose_recirculate_and_fork(struct xlate_ctx *ctx, uint8_t table)
+{
+    ctx->recirc_action_offset = ctx->action_set.size;
+    compose_recirculate_action__(ctx, table);
+}
+
 static void
 compose_mpls_push_action(struct xlate_ctx *ctx, struct ofpact_push_mpls *mpls)
 {
@@ -3546,11 +3612,7 @@ compose_mpls_push_action(struct xlate_ctx *ctx, struct ofpact_push_mpls *mpls)
 
     n = flow_count_mpls_labels(flow, ctx->wc);
     if (!n) {
-        bool use_masked = ctx->xbridge->support.masked_set_action;
-
-        ctx->xout->slow |= commit_odp_actions(flow, &ctx->base_flow,
-                                              ctx->odp_actions,
-                                              ctx->wc, use_masked);
+        xlate_commit_actions(ctx);
     } else if (n >= FLOW_MAX_MPLS_LABELS) {
         if (ctx->xin->packet != NULL) {
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
@@ -3668,9 +3730,9 @@ static void
 xlate_output_action(struct xlate_ctx *ctx,
                     ofp_port_t port, uint16_t max_len, bool may_packet_in)
 {
-    ofp_port_t prev_nf_output_iface = ctx->xout->nf_output_iface;
+    ofp_port_t prev_nf_output_iface = ctx->nf_output_iface;
 
-    ctx->xout->nf_output_iface = NF_OUT_DROP;
+    ctx->nf_output_iface = NF_OUT_DROP;
 
     switch (port) {
     case OFPP_IN_PORT:
@@ -3709,12 +3771,12 @@ xlate_output_action(struct xlate_ctx *ctx,
     }
 
     if (prev_nf_output_iface == NF_OUT_FLOOD) {
-        ctx->xout->nf_output_iface = NF_OUT_FLOOD;
-    } else if (ctx->xout->nf_output_iface == NF_OUT_DROP) {
-        ctx->xout->nf_output_iface = prev_nf_output_iface;
+        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->xout->nf_output_iface != NF_OUT_FLOOD) {
-        ctx->xout->nf_output_iface = NF_OUT_MULTI;
+               ctx->nf_output_iface != NF_OUT_FLOOD) {
+        ctx->nf_output_iface = NF_OUT_MULTI;
     }
 }
 
@@ -3764,10 +3826,10 @@ xlate_enqueue_action(struct xlate_ctx *ctx,
     ctx->xin->flow.skb_priority = flow_priority;
 
     /* Update NetFlow output port. */
-    if (ctx->xout->nf_output_iface == NF_OUT_DROP) {
-        ctx->xout->nf_output_iface = ofp_port;
-    } else if (ctx->xout->nf_output_iface != NF_OUT_FLOOD) {
-        ctx->xout->nf_output_iface = NF_OUT_MULTI;
+    if (ctx->nf_output_iface == NF_OUT_DROP) {
+        ctx->nf_output_iface = ofp_port;
+    } else if (ctx->nf_output_iface != NF_OUT_FLOOD) {
+        ctx->nf_output_iface = NF_OUT_MULTI;
     }
 }
 
@@ -3834,7 +3896,6 @@ xlate_learn_action__(struct xlate_ctx *ctx, const struct ofpact_learn *learn,
 static void
 xlate_learn_action(struct xlate_ctx *ctx, const struct ofpact_learn *learn)
 {
-    ctx->xout->has_learn = true;
     learn_mask(learn, ctx->wc);
 
     if (ctx->xin->xcache) {
@@ -3893,7 +3954,6 @@ xlate_sample_action(struct xlate_ctx *ctx,
     /* Scale the probability from 16-bit to 32-bit while representing
      * the same percentage. */
     uint32_t probability = (os->probability << 16) | os->probability;
-    bool use_masked;
 
     if (!ctx->xbridge->support.variable_length_userdata) {
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
@@ -3904,10 +3964,7 @@ xlate_sample_action(struct xlate_ctx *ctx,
         return;
     }
 
-    use_masked = ctx->xbridge->support.masked_set_action;
-    ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
-                                          ctx->odp_actions,
-                                          ctx->wc, use_masked);
+    xlate_commit_actions(ctx);
 
     union user_action_cookie cookie = {
         .flow_sample = {
@@ -4077,6 +4134,8 @@ recirc_unroll_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
         case OFPACT_WRITE_ACTIONS:
         case OFPACT_METER:
         case OFPACT_SAMPLE:
+        case OFPACT_DEBUG_RECIRC:
+        case OFPACT_CT:
             break;
 
             /* These need not be copied for restoration. */
@@ -4099,6 +4158,102 @@ recirc_unroll_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
         CHECK_MPLS_RECIRCULATION();       \
     }
 
+static void
+put_ct_mark(const struct flow *flow, struct flow *base_flow,
+            struct ofpbuf *odp_actions, struct flow_wildcards *wc)
+{
+    struct {
+        uint32_t key;
+        uint32_t mask;
+    } odp_attr;
+
+    odp_attr.key = flow->ct_mark;
+    odp_attr.mask = wc->masks.ct_mark;
+
+    if (odp_attr.mask && odp_attr.key != base_flow->ct_mark) {
+        nl_msg_put_unspec(odp_actions, OVS_CT_ATTR_MARK, &odp_attr,
+                          sizeof(odp_attr));
+    }
+}
+
+static void
+put_ct_label(const struct flow *flow, struct flow *base_flow,
+             struct ofpbuf *odp_actions, struct flow_wildcards *wc)
+{
+    if (!ovs_u128_is_zero(&wc->masks.ct_label)
+        && !ovs_u128_equals(&flow->ct_label, &base_flow->ct_label)) {
+        struct {
+            ovs_u128 key;
+            ovs_u128 mask;
+        } *odp_ct_label;
+
+        odp_ct_label = nl_msg_put_unspec_uninit(odp_actions,
+                                                OVS_CT_ATTR_LABELS,
+                                                sizeof(*odp_ct_label));
+        odp_ct_label->key = flow->ct_label;
+        odp_ct_label->mask = wc->masks.ct_label;
+    }
+}
+
+static void
+put_ct_helper(struct ofpbuf *odp_actions, struct ofpact_conntrack *ofc)
+{
+    if (ofc->alg) {
+        if (ofc->alg == IPPORT_FTP) {
+            nl_msg_put_string(odp_actions, OVS_CT_ATTR_HELPER, "ftp");
+        } else {
+            VLOG_WARN("Cannot serialize ct_helper %d\n", ofc->alg);
+        }
+    }
+}
+
+static void
+compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc)
+{
+    ovs_u128 old_ct_label = ctx->base_flow.ct_label;
+    uint32_t old_ct_mark = ctx->base_flow.ct_mark;
+    size_t ct_offset;
+    uint16_t zone;
+
+    /* Ensure that any prior actions are applied before composing the new
+     * conntrack action. */
+    xlate_commit_actions(ctx);
+
+    /* Process nested actions first, to populate the key. */
+    do_xlate_actions(ofc->actions, ofpact_ct_get_action_len(ofc), ctx);
+
+    if (ofc->zone_src.field) {
+        zone = mf_get_subfield(&ofc->zone_src, &ctx->xin->flow);
+    } else {
+        zone = ofc->zone_imm;
+    }
+
+    ct_offset = nl_msg_start_nested(ctx->odp_actions, OVS_ACTION_ATTR_CT);
+    if (ofc->flags & NX_CT_F_COMMIT) {
+        nl_msg_put_flag(ctx->odp_actions, OVS_CT_ATTR_COMMIT);
+    }
+    nl_msg_put_u16(ctx->odp_actions, OVS_CT_ATTR_ZONE, zone);
+    put_ct_mark(&ctx->xin->flow, &ctx->base_flow, ctx->odp_actions, ctx->wc);
+    put_ct_label(&ctx->xin->flow, &ctx->base_flow, ctx->odp_actions, ctx->wc);
+    put_ct_helper(ctx->odp_actions, ofc);
+    nl_msg_end_nested(ctx->odp_actions, ct_offset);
+
+    /* Restore the original ct fields in the key. These should only be exposed
+     * after recirculation to another table. */
+    ctx->base_flow.ct_mark = old_ct_mark;
+    ctx->base_flow.ct_label = old_ct_label;
+
+    if (ofc->recirc_table == NX_CT_RECIRC_NONE) {
+        /* If we do not recirculate as part of this action, hide the results of
+         * connection tracking from subsequent recirculations. */
+        ctx->conntracked = false;
+    } else {
+        /* Use ct_* fields from datapath during recirculation upcall. */
+        ctx->conntracked = true;
+        compose_recirculate_and_fork(ctx, ofc->recirc_table);
+    }
+}
+
 static void
 do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
                  struct xlate_ctx *ctx)
@@ -4109,6 +4264,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
 
     if (ovs_native_tunneling_is_on(ctx->xbridge->ofproto)) {
         tnl_arp_snoop(flow, wc, ctx->xbridge->name);
+        tnl_nd_snoop(flow, wc, ctx->xbridge->name);
     }
     /* dl_type already in the mask, not set below. */
 
@@ -4188,13 +4344,13 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             break;
 
         case OFPACT_SET_ETH_SRC:
-            memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src);
-            memcpy(flow->dl_src, ofpact_get_SET_ETH_SRC(a)->mac, ETH_ADDR_LEN);
+            WC_MASK_FIELD(wc, dl_src);
+            flow->dl_src = ofpact_get_SET_ETH_SRC(a)->mac;
             break;
 
         case OFPACT_SET_ETH_DST:
-            memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
-            memcpy(flow->dl_dst, ofpact_get_SET_ETH_DST(a)->mac, ETH_ADDR_LEN);
+            WC_MASK_FIELD(wc, dl_dst);
+            flow->dl_dst = ofpact_get_SET_ETH_DST(a)->mac;
             break;
 
         case OFPACT_SET_IPV4_SRC:
@@ -4302,9 +4458,9 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
                        && !eth_type_mpls(flow->dl_type)) {
                 break;
             }
-            /* A flow may wildcard nw_frag.  Do nothing if setting a trasport
+            /* A flow may wildcard nw_frag.  Do nothing if setting a transport
              * header field on a packet that does not have them. */
-            mf_mask_field_and_prereqs(mf, &wc->masks);
+            mf_mask_field_and_prereqs(mf, wc);
             if (mf_are_prereqs_ok(mf, flow)) {
                 mf_set_flow_value_masked(mf, &set_field->value,
                                          &set_field->mask, flow);
@@ -4422,7 +4578,6 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
         case OFPACT_FIN_TIMEOUT:
             CHECK_MPLS_RECIRCULATION();
             memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
-            ctx->xout->has_fin_timeout = true;
             xlate_fin_timeout(ctx, ofpact_get_FIN_TIMEOUT(a));
             break;
 
@@ -4463,6 +4618,16 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
         case OFPACT_SAMPLE:
             xlate_sample_action(ctx, ofpact_get_SAMPLE(a));
             break;
+
+        case OFPACT_CT:
+            CHECK_MPLS_RECIRCULATION();
+            compose_conntrack_action(ctx, ofpact_get_CT(a));
+            break;
+
+        case OFPACT_DEBUG_RECIRC:
+            ctx_trigger_recirculation(ctx);
+            a = ofpact_next(a);
+            break;
         }
 
         /* Check if need to store this and the remaining actions for later
@@ -4498,6 +4663,8 @@ xlate_in_init(struct xlate_in *xin, struct ofproto_dpif *ofproto,
     xin->resubmit_hook = NULL;
     xin->report_hook = NULL;
     xin->resubmit_stats = NULL;
+    xin->recurse = 0;
+    xin->resubmits = 0;
     xin->wc = wc;
     xin->odp_actions = odp_actions;
 
@@ -4601,7 +4768,7 @@ netdev_max_backlog(void)
 
         stream = fopen(filename, "r");
         if (!stream) {
-            VLOG_WARN("%s: open failed (%s)", filename, ovs_strerror(errno));
+            VLOG_INFO("%s: open failed (%s)", filename, ovs_strerror(errno));
         } else {
             if (fscanf(stream, "%d", &n) != 1) {
                 VLOG_WARN("%s: read error", filename);
@@ -4662,16 +4829,16 @@ xlate_wc_init(struct xlate_ctx *ctx)
     flow_wildcards_init_catchall(ctx->wc);
 
     /* Some fields we consider to always be examined. */
-    memset(&ctx->wc->masks.in_port, 0xff, sizeof ctx->wc->masks.in_port);
-    memset(&ctx->wc->masks.dl_type, 0xff, sizeof ctx->wc->masks.dl_type);
+    WC_MASK_FIELD(ctx->wc, in_port);
+    WC_MASK_FIELD(ctx->wc, dl_type);
     if (is_ip_any(&ctx->xin->flow)) {
-        ctx->wc->masks.nw_frag |= FLOW_NW_FRAG_MASK;
+        WC_MASK_FIELD_MASK(ctx->wc, nw_frag, FLOW_NW_FRAG_MASK);
     }
 
     if (ctx->xbridge->support.odp.recirc) {
         /* Always exactly match recirc_id when datapath supports
          * recirculation.  */
-        ctx->wc->masks.recirc_id = UINT32_MAX;
+        WC_MASK_FIELD(ctx->wc, recirc_id);
     }
 
     if (ctx->xbridge->netflow) {
@@ -4718,11 +4885,6 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
     *xout = (struct xlate_out) {
         .slow = 0,
         .fail_open = false,
-        .has_learn = false,
-        .has_normal = false,
-        .has_fin_timeout = false,
-        .nf_output_iface = NF_OUT_DROP,
-        .mirrors = 0,
         .n_recircs = 0,
     };
 
@@ -4750,8 +4912,8 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
         .wc = xin->wc ? xin->wc : &scratch_wc,
         .odp_actions = xin->odp_actions ? xin->odp_actions : &scratch_actions,
 
-        .recurse = 0,
-        .resubmits = 0,
+        .recurse = xin->recurse,
+        .resubmits = xin->resubmits,
         .in_group = false,
         .in_action_set = false,
 
@@ -4760,12 +4922,15 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
         .orig_skb_priority = flow->skb_priority,
         .sflow_n_outputs = 0,
         .sflow_odp_port = 0,
+        .nf_output_iface = NF_OUT_DROP,
         .exit = false,
+        .mirrors = 0,
 
         .recirc_action_offset = -1,
         .last_unroll_offset = -1,
 
         .was_mpls = false,
+        .conntracked = false,
 
         .action_set_has_group = false,
         .action_set = OFPBUF_STUB_INITIALIZER(action_set_stub),
@@ -4798,36 +4963,33 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
         xlate_wc_init(&ctx);
     }
 
-    struct xport *in_port;
-
     COVERAGE_INC(xlate_actions);
 
-    /* The in_port of the original packet before recirculation. */
-    in_port = get_ofp_port(xbridge, flow->in_port.ofp_port);
-
     if (xin->recirc) {
-        const struct recirc_id_node *recirc = xin->recirc;
+        const struct recirc_state *state = &xin->recirc->state;
+
+        xlate_report(&ctx, "Restoring state post-recirculation:");
 
         if (xin->ofpacts_len > 0 || ctx.rule) {
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+            const char *conflict = xin->ofpacts_len ? "actions" : "rule";
 
-            VLOG_WARN_RL(&rl, "Recirculation conflict (%s)!",
-                         xin->ofpacts_len > 0
-                         ? "actions"
-                         : "rule");
+            VLOG_WARN_RL(&rl, "Recirculation conflict (%s)!", conflict);
+            xlate_report(&ctx, "- Recirculation conflict (%s)!", conflict);
             goto exit;
         }
 
         /* Set the bridge for post-recirculation processing if needed. */
-        if (ctx.xbridge->ofproto != recirc->ofproto) {
+        if (ctx.xbridge->ofproto != state->ofproto) {
             struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
-            const struct xbridge *new_bridge = xbridge_lookup(xcfg,
-                                                              recirc->ofproto);
+            const struct xbridge *new_bridge
+                = xbridge_lookup(xcfg, state->ofproto);
 
             if (OVS_UNLIKELY(!new_bridge)) {
                 /* Drop the packet if the bridge cannot be found. */
                 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
                 VLOG_WARN_RL(&rl, "Recirculation bridge no longer exists.");
+                xlate_report(&ctx, "- Recirculation bridge no longer exists.");
                 goto exit;
             }
             ctx.xbridge = new_bridge;
@@ -4835,26 +4997,36 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
 
         /* Set the post-recirculation table id.  Note: A table lookup is done
          * only if there are no post-recirculation actions. */
-        ctx.table_id = recirc->table_id;
+        ctx.table_id = state->table_id;
+        xlate_report(&ctx, "- Resuming from table %"PRIu8, ctx.table_id);
+
+        if (!state->conntracked) {
+            clear_conntrack(flow);
+        }
 
         /* Restore pipeline metadata. May change flow's in_port and other
          * metadata to the values that existed when recirculation was
          * triggered. */
-        recirc_metadata_to_flow(&recirc->metadata, flow);
+        recirc_metadata_to_flow(&state->metadata, flow);
 
         /* Restore stack, if any. */
-        if (recirc->stack) {
-            ofpbuf_put(&ctx.stack, recirc->stack->data, recirc->stack->size);
+        if (state->stack) {
+            ofpbuf_put(&ctx.stack, state->stack->data, state->stack->size);
         }
 
+        /* Restore mirror state. */
+        ctx.mirrors = state->mirrors;
+
         /* Restore action set, if any. */
-        if (recirc->action_set_len) {
+        if (state->action_set_len) {
             const struct ofpact *a;
 
-            ofpbuf_put(&ctx.action_set, recirc->ofpacts,
-                       recirc->action_set_len);
+            xlate_report_actions(&ctx, "- Restoring action set",
+                                 state->ofpacts, state->action_set_len);
+
+            ofpbuf_put(&ctx.action_set, state->ofpacts, state->action_set_len);
 
-            OFPACT_FOR_EACH(a, recirc->ofpacts, recirc->action_set_len) {
+            OFPACT_FOR_EACH(a, state->ofpacts, state->action_set_len) {
                 if (a->type == OFPACT_GROUP) {
                     ctx.action_set_has_group = true;
                     break;
@@ -4864,10 +5036,13 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
 
         /* Restore recirculation actions.  If there are no actions, processing
          * will start with a lookup in the table set above. */
-        if (recirc->ofpacts_len > recirc->action_set_len) {
-            xin->ofpacts_len = recirc->ofpacts_len - recirc->action_set_len;
-            xin->ofpacts = recirc->ofpacts +
-                recirc->action_set_len / sizeof *recirc->ofpacts;
+        if (state->ofpacts_len > state->action_set_len) {
+            xin->ofpacts_len = state->ofpacts_len - state->action_set_len;
+            xin->ofpacts = state->ofpacts +
+                state->action_set_len / sizeof *state->ofpacts;
+
+            xlate_report_actions(&ctx, "- Restoring actions",
+                                 xin->ofpacts, xin->ofpacts_len);
         }
     } else if (OVS_UNLIKELY(flow->recirc_id)) {
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
@@ -4882,7 +5057,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
     if (!xin->ofpacts && !ctx.rule) {
         ctx.rule = rule_dpif_lookup_from_table(
             ctx.xbridge->ofproto, ctx.tables_version, flow, xin->wc,
-            ctx.xin->xcache != NULL, ctx.xin->resubmit_stats, &ctx.table_id,
+            ctx.xin->resubmit_stats, &ctx.table_id,
             flow->in_port.ofp_port, true, true);
         if (ctx.xin->resubmit_stats) {
             rule_dpif_credit_stats(ctx.rule, ctx.xin->resubmit_stats);
@@ -4892,6 +5067,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
 
             entry = xlate_cache_add_entry(ctx.xin->xcache, XC_RULE);
             entry->u.rule = ctx.rule;
+            rule_dpif_ref(ctx.rule);
         }
 
         if (OVS_UNLIKELY(ctx.xin->resubmit_hook)) {
@@ -4900,12 +5076,10 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
     }
     xout->fail_open = ctx.rule && rule_dpif_is_fail_open(ctx.rule);
 
-    struct flow orig_flow;
-    if (mbridge_has_mirrors(xbridge->mbridge)) {
-        /* Do this conditionally because the copy is expensive enough that it
-         * shows up in profiles. */
-        orig_flow = *flow;
-    }
+    /* Get the proximate input port of the packet.  (If xin->recirc,
+     * flow->in_port is the ultimate input port of the packet.) */
+    struct xport *in_port = get_ofp_port(xbridge,
+                                         ctx.base_flow.in_port.ofp_port);
 
     /* Tunnel stats only for non-recirculated packets. */
     if (!xin->recirc && in_port && in_port->is_tunnel) {
@@ -4924,9 +5098,20 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
         }
     }
 
-    /* Do not perform special processing on recirculated packets,
-     * as recirculated packets are not really received by the bridge. */
-    if (xin->recirc || !process_special(&ctx, in_port)) {
+    if (!xin->recirc && process_special(&ctx, in_port)) {
+        /* process_special() did all the processing for this packet.
+         *
+         * We do not perform special processing on recirculated packets, as
+         * recirculated packets are not really received by the bridge.*/
+    } else if (in_port && in_port->xbundle
+               && xbundle_mirror_out(xbridge, in_port->xbundle)) {
+        if (ctx.xin->packet != NULL) {
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+            VLOG_WARN_RL(&rl, "bridge %s: dropping packet received on port "
+                         "%s, which is reserved exclusively for mirroring",
+                         ctx.xbridge->name, in_port->xbundle->name);
+        }
+    } else {
         /* Sampling is done only for packets really received by the bridge. */
         unsigned int user_cookie_offset = 0;
         if (!xin->recirc) {
@@ -4953,6 +5138,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
                 OVS_NOT_REACHED();
             }
 
+            mirror_ingress_packet(&ctx);
             do_xlate_actions(ofpacts, ofpacts_len, &ctx);
 
             /* We've let OFPP_NORMAL and the learning action look at the
@@ -4992,11 +5178,6 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
         if (user_cookie_offset) {
             fix_sflow_action(&ctx, user_cookie_offset);
         }
-        /* Only mirror fully processed packets. */
-        if (!exit_recirculates(&ctx)
-            && mbridge_has_mirrors(xbridge->mbridge)) {
-            add_mirror_actions(&ctx, &orig_flow);
-        }
     }
 
     if (nl_attr_oversized(ctx.odp_actions->size)) {
@@ -5011,29 +5192,13 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
         ctx.xout->slow |= SLOW_ACTION;
     }
 
-    /* Update mirror stats only for packets really received by the bridge. */
-    if (!xin->recirc && mbridge_has_mirrors(xbridge->mbridge)) {
-        if (ctx.xin->resubmit_stats) {
-            mirror_update_stats(xbridge->mbridge, xout->mirrors,
-                                ctx.xin->resubmit_stats->n_packets,
-                                ctx.xin->resubmit_stats->n_bytes);
-        }
-        if (ctx.xin->xcache) {
-            struct xc_entry *entry;
-
-            entry = xlate_cache_add_entry(ctx.xin->xcache, XC_MIRROR);
-            entry->u.mirror.mbridge = mbridge_ref(xbridge->mbridge);
-            entry->u.mirror.mirrors = xout->mirrors;
-        }
-    }
-
     /* Do netflow only for packets really received by the bridge and not sent
      * to the controller.  We consider packets sent to the controller to be
      * part of the control plane rather than the data plane. */
     if (!xin->recirc && xbridge->netflow && !(xout->slow & SLOW_CONTROLLER)) {
         if (ctx.xin->resubmit_stats) {
             netflow_flow_update(xbridge->netflow, flow,
-                                xout->nf_output_iface,
+                                ctx.nf_output_iface,
                                 ctx.xin->resubmit_stats);
         }
         if (ctx.xin->xcache) {
@@ -5042,7 +5207,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
             entry = xlate_cache_add_entry(ctx.xin->xcache, XC_NETFLOW);
             entry->u.nf.netflow = netflow_ref(xbridge->netflow);
             entry->u.nf.flow = xmemdup(flow, sizeof *flow);
-            entry->u.nf.iface = xout->nf_output_iface;
+            entry->u.nf.iface = ctx.nf_output_iface;
         }
     }
 
@@ -5147,7 +5312,7 @@ xlate_push_stats(struct xlate_cache *xcache,
 {
     struct xc_entry *entry;
     struct ofpbuf entries = xcache->entries;
-    uint8_t dmac[ETH_ADDR_LEN];
+    struct eth_addr dmac;
 
     if (!stats->n_packets) {
         return;
@@ -5191,7 +5356,8 @@ xlate_push_stats(struct xlate_cache *xcache,
             break;
         case XC_TNL_ARP:
             /* Lookup arp to avoid arp timeout. */
-            tnl_arp_lookup(entry->u.tnl_arp_cache.br_name, entry->u.tnl_arp_cache.d_ip, dmac);
+            tnl_arp_lookup(entry->u.tnl_arp_cache.br_name,
+                           entry->u.tnl_arp_cache.d_ip, &dmac);
             break;
         default:
             OVS_NOT_REACHED();