dpif-netdev: Purge all ukeys when reconfigure pmd.
[cascardo/ovs.git] / ofproto / ofproto-dpif-xlate.c
index 2a91cfc..de5c9b1 100644 (file)
@@ -205,6 +205,7 @@ 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. */
 
@@ -529,6 +530,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)
 {
@@ -1529,68 +1542,55 @@ 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->mirrors;
-    ctx->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;
         }
@@ -1604,7 +1604,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) {
@@ -1617,6 +1617,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
@@ -2245,7 +2259,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
@@ -2260,8 +2274,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);
@@ -2695,7 +2707,8 @@ xlate_flood_packet(struct xbridge *xbridge, struct dp_packet *packet)
 }
 
 static void
-tnl_send_arp_request(const struct xport *out_dev, const uint8_t eth_src[ETH_ADDR_LEN],
+tnl_send_arp_request(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;
@@ -2716,8 +2729,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);
@@ -2729,7 +2742,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;
@@ -2741,7 +2754,7 @@ 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",
@@ -2825,11 +2838,6 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
         }
     }
 
-    if (mbridge_has_mirrors(ctx->xbridge->mbridge) && xport->xbundle) {
-        ctx->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;
@@ -3042,7 +3050,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:
@@ -3120,7 +3134,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);
@@ -3139,6 +3152,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);
         }
@@ -3313,6 +3327,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);
         }
     }
@@ -3429,7 +3448,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
@@ -3504,14 +3523,23 @@ compose_recirculate_action(struct xlate_ctx *ctx)
 
     ovs_assert(ctx->recirc_action_offset >= 0);
 
+    struct recirc_state state = {
+        .table_id = 0,
+        .ofproto = ctx->xbridge->ofproto,
+        .metadata = md,
+        .stack = &ctx->stack,
+        .mirrors = ctx->mirrors,
+        .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");
@@ -3521,12 +3549,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);
@@ -3669,9 +3697,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:
@@ -3710,12 +3738,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;
     }
 }
 
@@ -3765,10 +3793,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;
     }
 }
 
@@ -3835,7 +3863,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) {
@@ -4078,6 +4105,7 @@ 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:
             break;
 
             /* These need not be copied for restoration. */
@@ -4189,13 +4217,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:
@@ -4305,7 +4333,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             }
             /* A flow may wildcard nw_frag.  Do nothing if setting a trasport
              * 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);
@@ -4423,7 +4451,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;
 
@@ -4464,6 +4491,11 @@ 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_DEBUG_RECIRC:
+            ctx_trigger_recirculation(ctx);
+            a = ofpact_next(a);
+            break;
         }
 
         /* Check if need to store this and the remaining actions for later
@@ -4663,16 +4695,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) {
@@ -4719,10 +4751,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,
         .n_recircs = 0,
     };
 
@@ -4760,6 +4788,7 @@ 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,
 
@@ -4799,36 +4828,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;
@@ -4836,26 +4862,32 @@ 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);
 
         /* 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;
@@ -4865,10 +4897,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);
@@ -4883,7 +4918,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);
@@ -4893,6 +4928,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)) {
@@ -4901,12 +4937,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) {
@@ -4925,9 +4959,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) {
@@ -4954,6 +4999,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
@@ -4993,11 +5039,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)) {
@@ -5012,29 +5053,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, ctx.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 = ctx.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) {
@@ -5043,7 +5068,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;
         }
     }
 
@@ -5148,7 +5173,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;
@@ -5192,7 +5217,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();