- ofpbuf_clear(odp_actions);
- ofpbuf_reserve(odp_actions, NL_A_U32_SIZE);
-
- ctx->odp_actions = odp_actions;
- ctx->tags = 0;
- ctx->slow = 0;
- ctx->has_learn = false;
- ctx->has_normal = false;
- ctx->has_fin_timeout = false;
- ctx->nf_output_iface = NF_OUT_DROP;
- ctx->mirrors = 0;
- ctx->recurse = 0;
- ctx->max_resubmit_trigger = false;
- ctx->orig_skb_priority = ctx->flow.skb_priority;
- ctx->table_id = 0;
- ctx->exit = false;
-
- ofpbuf_use_stub(&ctx->stack, ctx->init_stack, sizeof ctx->init_stack);
-
- if (ctx->ofproto->has_mirrors || hit_resubmit_limit) {
+ /* Flow initialization rules:
+ * - 'base_flow' must match the kernel's view of the packet at the
+ * time that action processing starts. 'flow' represents any
+ * transformations we wish to make through actions.
+ * - By default 'base_flow' and 'flow' are the same since the input
+ * packet matches the output before any actions are applied.
+ * - When using VLAN splinters, 'base_flow''s VLAN is set to the value
+ * of the received packet as seen by the kernel. If we later output
+ * to another device without any modifications this will cause us to
+ * insert a new tag since the original one was stripped off by the
+ * VLAN device.
+ * - Tunnel metadata as received is retained in 'flow'. This allows
+ * tunnel metadata matching also in later tables.
+ * Since a kernel action for setting the tunnel metadata will only be
+ * generated with actual tunnel output, changing the tunnel metadata
+ * values in 'flow' (such as tun_id) will only have effect with a later
+ * tunnel output action.
+ * - Tunnel 'base_flow' is completely cleared since that is what the
+ * kernel does. If we wish to maintain the original values an action
+ * needs to be generated. */
+
+ ctx.xin = xin;
+ ctx.xout = xout;
+
+ ctx.ofproto = xin->ofproto;
+ ctx.rule = xin->rule;
+
+ ctx.base_flow = ctx.xin->flow;
+ ctx.base_flow.vlan_tci = xin->initial_vals.vlan_tci;
+ memset(&ctx.base_flow.tunnel, 0, sizeof ctx.base_flow.tunnel);
+ ctx.orig_tunnel_ip_dst = ctx.xin->flow.tunnel.ip_dst;
+
+ ctx.xout->tags = 0;
+ ctx.xout->slow = 0;
+ ctx.xout->has_learn = false;
+ ctx.xout->has_normal = false;
+ ctx.xout->has_fin_timeout = false;
+ ctx.xout->nf_output_iface = NF_OUT_DROP;
+ ctx.xout->mirrors = 0;
+
+ ofpbuf_use_stub(&ctx.xout->odp_actions, ctx.xout->odp_actions_stub,
+ sizeof ctx.xout->odp_actions_stub);
+ ofpbuf_reserve(&ctx.xout->odp_actions, NL_A_U32_SIZE);
+
+ ctx.recurse = 0;
+ ctx.max_resubmit_trigger = false;
+ ctx.orig_skb_priority = ctx.xin->flow.skb_priority;
+ ctx.table_id = 0;
+ ctx.exit = false;
+
+ if (xin->ofpacts) {
+ ofpacts = xin->ofpacts;
+ ofpacts_len = xin->ofpacts_len;
+ } else if (xin->rule) {
+ ofpacts = xin->rule->up.ofpacts;
+ ofpacts_len = xin->rule->up.ofpacts_len;
+ } else {
+ NOT_REACHED();
+ }
+
+ ofpbuf_use_stub(&ctx.stack, ctx.init_stack, sizeof ctx.init_stack);
+
+ if (ctx.ofproto->has_mirrors || hit_resubmit_limit) {