From: Ethan Jackson Date: Mon, 13 May 2013 18:18:21 +0000 (-0700) Subject: ofproto-dpif: Revamp xlate_actions() interface. X-Git-Tag: sliver-openvswitch-1.10.90-3~6^2~192 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=bbafd73bebaa7c045ecbd6ff885230ea24be0dcb;p=sliver-openvswitch.git ofproto-dpif: Revamp xlate_actions() interface. This patch implements a new interface to xlate_actions which, aside from being simpler and more intuitive, achieves several goals. It pulls all of xlate_actions() results into a single structure which will be easier to cache and pass around in future. And it shields xlate_ctx from the rest of the code, making it possible to factor xlate_actions() in the future (hopefully). Signed-off-by: Ethan Jackson --- diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 0bde8c4d6..386434d1e 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -208,31 +208,44 @@ static int set_stp_port(struct ofport *, static bool ofbundle_includes_vlan(const struct ofbundle *, uint16_t vlan); -struct xlate_ctx { - /* xlate_ctx_init() initializes these members. */ +struct xlate_ctx; + +/* Initial values of fields of the packet that may be changed during + * flow processing and needed later. */ +struct initial_vals { + /* This is the value of vlan_tci in the packet as actually received from + * dpif. This is the same as the facet's flow.vlan_tci unless the packet + * was received via a VLAN splinter. In that case, this value is 0 + * (because the packet as actually received from the dpif had no 802.1Q + * tag) but the facet's flow.vlan_tci is set to the VLAN that the splinter + * represents. + * + * This member should be removed when the VLAN splinters feature is no + * longer needed. */ + ovs_be16 vlan_tci; +}; + +struct xlate_out { + tag_type tags; /* Tags associated with actions. */ + enum slow_path_reason slow; /* 0 if fast path may be used. */ + bool has_learn; /* Actions include NXAST_LEARN? */ + bool has_normal; /* Actions output to OFPP_NORMAL? */ + bool has_fin_timeout; /* Actions include NXAST_FIN_TIMEOUT? */ + uint16_t nf_output_iface; /* Output interface index for NetFlow. */ + mirror_mask_t mirrors; /* Bitmap of associated mirrors. */ + + uint64_t odp_actions_stub[256 / 8]; + struct ofpbuf odp_actions; +}; - /* The ofproto. */ +struct xlate_in { struct ofproto_dpif *ofproto; /* Flow to which the OpenFlow actions apply. xlate_actions() will modify * this flow when actions change header fields. */ struct flow flow; - /* Flow at the last commit. */ - struct flow base_flow; - - /* Tunnel IP destination address as received. This is stored separately - * as the base_flow.tunnel is cleared on init to reflect the datapath - * behavior. Used to make sure not to send tunneled output to ourselves, - * which might lead to an infinite loop. This could happen easily - * if a tunnel is marked as 'ip_remote=flow', and the flow does not - * actually set the tun_dst field. */ - ovs_be32 orig_tunnel_ip_dst; - - /* stack for the push and pop actions. - * Each stack element is of the type "union mf_subvalue". */ - struct ofpbuf stack; - union mf_subvalue init_stack[1024 / sizeof(union mf_subvalue)]; + struct initial_vals initial_vals; /* The packet corresponding to 'flow', or a null pointer if we are * revalidating without a packet to refer to. */ @@ -246,9 +259,13 @@ struct xlate_ctx { * not if we are just revalidating. */ bool may_learn; - /* The rule that we are currently translating, or NULL. */ + /* The rule initiating translation or NULL. */ struct rule_dpif *rule; + /* The actions to translate. If 'rule' is not NULL, these may be NULL. */ + const struct ofpact *ofpacts; + size_t ofpacts_len; + /* Union of the set of TCP flags seen so far in this flow. (Used only by * NXAST_FIN_TIMEOUT. Set to zero to avoid updating updating rules' * timeouts.) */ @@ -262,7 +279,7 @@ struct xlate_ctx { * resubmit or OFPP_TABLE action didn't find a matching rule. * * This is normally null so the client has to set it manually after - * calling xlate_ctx_init(). */ + * calling xlate_in_init(). */ void (*resubmit_hook)(struct xlate_ctx *, struct rule_dpif *rule); /* If nonnull, flow translation calls this function to report some @@ -274,23 +291,35 @@ struct xlate_ctx { * rule reached through a resubmit or OFPP_TABLE action. * * This is normally null so the client has to set it manually after - * calling xlate_ctx_init(). */ + * calling xlate_in_init(). */ const struct dpif_flow_stats *resubmit_stats; +}; -/* xlate_actions() initializes and uses these members. The client might want - * to look at them after it returns. */ +/* Context used by xlate_actions() and its callees. */ +struct xlate_ctx { + struct xlate_in *xin; + struct xlate_out *xout; - struct ofpbuf *odp_actions; /* Datapath actions. */ - tag_type tags; /* Tags associated with actions. */ - enum slow_path_reason slow; /* 0 if fast path may be used. */ - bool has_learn; /* Actions include NXAST_LEARN? */ - bool has_normal; /* Actions output to OFPP_NORMAL? */ - bool has_fin_timeout; /* Actions include NXAST_FIN_TIMEOUT? */ - uint16_t nf_output_iface; /* Output interface index for NetFlow. */ - mirror_mask_t mirrors; /* Bitmap of associated mirrors. */ + struct ofproto_dpif *ofproto; + + /* Flow at the last commit. */ + struct flow base_flow; -/* xlate_actions() initializes and uses these members, but the client has no - * reason to look at them. */ + /* Tunnel IP destination address as received. This is stored separately + * as the base_flow.tunnel is cleared on init to reflect the datapath + * behavior. Used to make sure not to send tunneled output to ourselves, + * which might lead to an infinite loop. This could happen easily + * if a tunnel is marked as 'ip_remote=flow', and the flow does not + * actually set the tun_dst field. */ + ovs_be32 orig_tunnel_ip_dst; + + /* Stack for the push and pop actions. Each stack element is of type + * "union mf_subvalue". */ + union mf_subvalue init_stack[1024 / sizeof(union mf_subvalue)]; + struct ofpbuf stack; + + /* The rule that we are currently translating, or NULL. */ + struct rule_dpif *rule; int recurse; /* Recursion level, via xlate_table_action. */ bool max_resubmit_trigger; /* Recursed too deeply during translation. */ @@ -302,31 +331,17 @@ struct xlate_ctx { bool exit; /* No further actions should be processed. */ }; -/* Initial values of fields of the packet that may be changed during - * flow processing and needed later. */ -struct initial_vals { - /* This is the value of vlan_tci in the packet as actually received from - * dpif. This is the same as the facet's flow.vlan_tci unless the packet - * was received via a VLAN splinter. In that case, this value is 0 - * (because the packet as actually received from the dpif had no 802.1Q - * tag) but the facet's flow.vlan_tci is set to the VLAN that the splinter - * represents. - * - * This member should be removed when the VLAN splinters feature is no - * longer needed. */ - ovs_be16 vlan_tci; -}; +static void xlate_in_init(struct xlate_in *, struct ofproto_dpif *, + const struct flow *, const struct initial_vals *, + struct rule_dpif *, uint8_t tcp_flags, + const struct ofpbuf *); + +static void xlate_out_uninit(struct xlate_out *); + +static void xlate_actions(struct xlate_in *, struct xlate_out *); + +static void xlate_actions_for_side_effects(struct xlate_in *); -static void xlate_ctx_init(struct xlate_ctx *, struct ofproto_dpif *, - const struct flow *, - const struct initial_vals *initial_vals, - struct rule_dpif *, uint8_t tcp_flags, - const struct ofpbuf *); -static void xlate_actions(struct xlate_ctx *, const struct ofpact *ofpacts, - size_t ofpacts_len, struct ofpbuf *odp_actions); -static void xlate_actions_for_side_effects(struct xlate_ctx *, - const struct ofpact *ofpacts, - size_t ofpacts_len); static void xlate_table_action(struct xlate_ctx *, uint16_t in_port, uint8_t table_id, bool may_packet_in); @@ -465,21 +480,11 @@ struct facet { struct netflow_flow nf_flow; /* Per-flow NetFlow tracking data. */ uint8_t tcp_flags; /* TCP flags seen for this 'rule'. */ - bool has_learn; /* Actions include NXAST_LEARN? */ - bool has_normal; /* Actions output to OFPP_NORMAL? */ - bool has_fin_timeout; /* Actions include NXAST_FIN_TIMEOUT? */ - tag_type tags; /* Tags that would require revalidation. */ - mirror_mask_t mirrors; /* Bitmap of dependent mirrors. */ - - /* Datapath actions. */ - struct ofpbuf odp_actions; - uint64_t odp_actions_stub[256 / 8]; + struct xlate_out xout; /* Initial values of the packet that may be needed later. */ struct initial_vals initial_vals; - enum slow_path_reason slow; /* 0 if fast path may be used. */ - /* Storage for a single subfacet, to reduce malloc() time and space * overhead. (A facet always has at least one subfacet and in the common * case has exactly one subfacet. However, 'one_subfacet' may not @@ -1014,7 +1019,7 @@ type_run(const char *type) HMAP_FOR_EACH_SAFE (facet, next, hmap_node, &ofproto->facets) { if (need_revalidate - || tag_set_intersects(&revalidate_set, facet->tags)) { + || tag_set_intersects(&revalidate_set, facet->xout.tags)) { facet_revalidate(facet); run_fast_rl(); } @@ -1605,7 +1610,7 @@ run(struct ofproto *ofproto_) facet = CONTAINER_OF(hmap_random_node(&ofproto->facets), struct facet, hmap_node); if (!tag_set_intersects(&ofproto->backer->revalidate_set, - facet->tags)) { + facet->xout.tags)) { if (!facet_check_consistency(facet)) { ofproto->backer->need_revalidate = REV_INCONSISTENCY; } @@ -3493,8 +3498,10 @@ struct flow_miss { struct flow_miss_op { struct dpif_op dpif_op; - void *garbage; /* Pointer to pass to free(), NULL if none. */ - uint64_t stub[1024 / 8]; /* Temporary buffer. */ + + uint64_t slow_stub[128 / 8]; /* Buffer for compose_slow_path() */ + struct xlate_out xout; + bool xout_garbage; /* 'xout' needs to be uninitialized? */ }; /* Sends an OFPT_PACKET_IN message for 'packet' of type OFPR_NO_MATCH to each @@ -3587,7 +3594,7 @@ init_flow_miss_execute_op(struct flow_miss *miss, struct ofpbuf *packet, eth_pop_vlan(packet); } - op->garbage = NULL; + op->xout_garbage = false; op->dpif_op.type = DPIF_OP_EXECUTE; op->dpif_op.u.execute.key = miss->key; op->dpif_op.u.execute.key_len = miss->key_len; @@ -3653,40 +3660,36 @@ handle_flow_miss_without_facet(struct flow_miss *miss, { struct rule_dpif *rule = rule_dpif_lookup(miss->ofproto, &miss->flow); long long int now = time_msec(); - struct xlate_ctx ctx; struct ofpbuf *packet; + struct xlate_in xin; LIST_FOR_EACH (packet, list_node, &miss->packets) { struct flow_miss_op *op = &ops[*n_ops]; struct dpif_flow_stats stats; - struct ofpbuf odp_actions; COVERAGE_INC(facet_suppress); handle_flow_miss_common(rule, packet, &miss->flow); - ofpbuf_use_stub(&odp_actions, op->stub, sizeof op->stub); - dpif_flow_stats_extract(&miss->flow, packet, now, &stats); rule_credit_stats(rule, &stats); - xlate_ctx_init(&ctx, miss->ofproto, &miss->flow, &miss->initial_vals, - rule, stats.tcp_flags, packet); - ctx.resubmit_stats = &stats; - xlate_actions(&ctx, rule->up.ofpacts, rule->up.ofpacts_len, - &odp_actions); + xlate_in_init(&xin, miss->ofproto, &miss->flow, &miss->initial_vals, + rule, stats.tcp_flags, packet); + xin.resubmit_stats = &stats; + xlate_actions(&xin, &op->xout); - if (odp_actions.size) { + if (op->xout.odp_actions.size) { struct dpif_execute *execute = &op->dpif_op.u.execute; init_flow_miss_execute_op(miss, packet, op); - execute->actions = odp_actions.data; - execute->actions_len = odp_actions.size; - op->garbage = ofpbuf_get_uninit_pointer(&odp_actions); + execute->actions = op->xout.odp_actions.data; + execute->actions_len = op->xout.odp_actions.size; + op->xout_garbage = true; (*n_ops)++; } else { - ofpbuf_uninit(&odp_actions); + xlate_out_uninit(&op->xout); } } } @@ -3711,7 +3714,7 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet, struct ofpbuf *packet; subfacet = subfacet_create(facet, miss, now); - want_path = subfacet->facet->slow ? SF_SLOW_PATH : SF_FAST_PATH; + want_path = subfacet->facet->xout.slow ? SF_SLOW_PATH : SF_FAST_PATH; LIST_FOR_EACH (packet, list_node, &miss->packets) { struct flow_miss_op *op = &ops[*n_ops]; @@ -3720,23 +3723,22 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet, handle_flow_miss_common(facet->rule, packet, &miss->flow); if (want_path != SF_FAST_PATH) { - struct xlate_ctx ctx; + struct xlate_in xin; - xlate_ctx_init(&ctx, ofproto, &facet->flow, &facet->initial_vals, - facet->rule, 0, packet); - xlate_actions_for_side_effects(&ctx, facet->rule->up.ofpacts, - facet->rule->up.ofpacts_len); + xlate_in_init(&xin, ofproto, &facet->flow, &facet->initial_vals, + facet->rule, 0, packet); + xlate_actions_for_side_effects(&xin); } dpif_flow_stats_extract(&facet->flow, packet, now, &stats); subfacet_update_stats(subfacet, &stats); - if (facet->odp_actions.size) { + if (facet->xout.odp_actions.size) { struct dpif_execute *execute = &op->dpif_op.u.execute; init_flow_miss_execute_op(miss, packet, op); - execute->actions = facet->odp_actions.data, - execute->actions_len = facet->odp_actions.size; + execute->actions = facet->xout.odp_actions.data, + execute->actions_len = facet->xout.odp_actions.size; (*n_ops)++; } } @@ -3747,17 +3749,17 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet, subfacet->path = want_path; - op->garbage = NULL; + op->xout_garbage = false; op->dpif_op.type = DPIF_OP_FLOW_PUT; put->flags = DPIF_FP_CREATE | DPIF_FP_MODIFY; put->key = miss->key; put->key_len = miss->key_len; if (want_path == SF_FAST_PATH) { - put->actions = facet->odp_actions.data; - put->actions_len = facet->odp_actions.size; + put->actions = facet->xout.odp_actions.data; + put->actions_len = facet->xout.odp_actions.size; } else { - compose_slow_path(ofproto, &facet->flow, facet->slow, - op->stub, sizeof op->stub, + compose_slow_path(ofproto, &facet->flow, facet->xout.slow, + op->slow_stub, sizeof op->slow_stub, &put->actions, &put->actions_len); } put->stats = NULL; @@ -4049,7 +4051,9 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls, /* Free memory. */ for (i = 0; i < n_ops; i++) { - free(flow_miss_ops[i].garbage); + if (flow_miss_ops[i].xout_garbage) { + xlate_out_uninit(&flow_miss_ops[i].xout); + } } hmap_destroy(&todo); } @@ -4538,8 +4542,8 @@ expire_subfacets(struct ofproto_dpif *ofproto, int dp_max_idle) &ofproto->subfacets) { long long int cutoff; - cutoff = (subfacet->facet->slow & (SLOW_CFM | SLOW_BFD | SLOW_LACP - | SLOW_STP) + cutoff = (subfacet->facet->xout.slow & (SLOW_CFM | SLOW_BFD | SLOW_LACP + | SLOW_STP) ? special_cutoff : normal_cutoff); if (subfacet->used < cutoff) { @@ -4613,7 +4617,7 @@ static struct facet * facet_create(const struct flow_miss *miss, uint32_t hash) { struct ofproto_dpif *ofproto = miss->ofproto; - struct xlate_ctx ctx; + struct xlate_in xin; struct facet *facet; facet = xzalloc(sizeof *facet); @@ -4629,20 +4633,11 @@ facet_create(const struct flow_miss *miss, uint32_t hash) netflow_flow_init(&facet->nf_flow); netflow_flow_update_time(ofproto->netflow, &facet->nf_flow, facet->used); - ofpbuf_use_stub(&facet->odp_actions, &facet->odp_actions_stub, - sizeof facet->odp_actions_stub); - xlate_ctx_init(&ctx, ofproto, &facet->flow, &facet->initial_vals, - facet->rule, 0, NULL); - ctx.may_learn = true; - xlate_actions(&ctx, facet->rule->up.ofpacts, facet->rule->up.ofpacts_len, - &facet->odp_actions); - facet->tags = ctx.tags; - facet->has_learn = ctx.has_learn; - facet->has_normal = ctx.has_normal; - facet->has_fin_timeout = ctx.has_fin_timeout; - facet->nf_flow.output_iface = ctx.nf_output_iface; - facet->mirrors = ctx.mirrors; - facet->slow = ctx.slow; + xlate_in_init(&xin, ofproto, &facet->flow, &facet->initial_vals, + facet->rule, 0, NULL); + xin.may_learn = true; + xlate_actions(&xin, &facet->xout); + facet->nf_flow.output_iface = facet->xout.nf_output_iface; return facet; } @@ -4651,7 +4646,7 @@ static void facet_free(struct facet *facet) { if (facet) { - ofpbuf_uninit(&facet->odp_actions); + xlate_out_uninit(&facet->xout); free(facet); } } @@ -4720,26 +4715,25 @@ facet_learn(struct facet *facet) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto); long long int now = time_msec(); - struct xlate_ctx ctx; + struct xlate_in xin; - if (!facet->has_fin_timeout && now < facet->learn_rl) { + if (!facet->xout.has_fin_timeout && now < facet->learn_rl) { return; } facet->learn_rl = now + 500; - if (!facet->has_learn - && !facet->has_normal - && (!facet->has_fin_timeout + if (!facet->xout.has_learn + && !facet->xout.has_normal + && (!facet->xout.has_fin_timeout || !(facet->tcp_flags & (TCP_FIN | TCP_RST)))) { return; } - xlate_ctx_init(&ctx, ofproto, &facet->flow, &facet->initial_vals, - facet->rule, facet->tcp_flags, NULL); - ctx.may_learn = true; - xlate_actions_for_side_effects(&ctx, facet->rule->up.ofpacts, - facet->rule->up.ofpacts_len); + xlate_in_init(&xin, ofproto, &facet->flow, &facet->initial_vals, + facet->rule, facet->tcp_flags, NULL); + xin.may_learn = true; + xlate_actions_for_side_effects(&xin); } static void @@ -4751,7 +4745,7 @@ facet_account(struct facet *facet) ovs_be16 vlan_tci; uint64_t n_bytes; - if (!facet->has_normal || !ofproto->has_bonded_bundles) { + if (!facet->xout.has_normal || !ofproto->has_bonded_bundles) { return; } n_bytes = facet->byte_count - facet->accounted_bytes; @@ -4765,8 +4759,8 @@ facet_account(struct facet *facet) * We use the actions from an arbitrary subfacet because they should all * be equally valid for our purpose. */ vlan_tci = facet->flow.vlan_tci; - NL_ATTR_FOR_EACH_UNSAFE (a, left, facet->odp_actions.data, - facet->odp_actions.size) { + NL_ATTR_FOR_EACH_UNSAFE (a, left, facet->xout.odp_actions.data, + facet->xout.odp_actions.size) { const struct ovs_action_push_vlan *vlan; struct ofport_dpif *port; @@ -4887,8 +4881,11 @@ facet_lookup_valid(struct ofproto_dpif *ofproto, const struct flow *flow, if (facet && (ofproto->backer->need_revalidate || tag_set_intersects(&ofproto->backer->revalidate_set, - facet->tags)) + facet->xout.tags)) && !facet_revalidate(facet)) { + facet_revalidate(facet); + + /* facet_revalidate() may have destroyed 'facet'. */ facet = facet_find(ofproto, flow, hash); } @@ -4902,10 +4899,9 @@ facet_check_consistency(struct facet *facet) struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto); - uint64_t odp_actions_stub[1024 / 8]; - struct ofpbuf odp_actions; + struct xlate_out xout; + struct xlate_in xin; - struct xlate_ctx ctx; struct rule_dpif *rule; bool ok; @@ -4930,35 +4926,35 @@ facet_check_consistency(struct facet *facet) } /* Check the datapath actions for consistency. */ - ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub); - xlate_ctx_init(&ctx, ofproto, &facet->flow, &facet->initial_vals, rule, 0, - NULL); - xlate_actions(&ctx, rule->up.ofpacts, rule->up.ofpacts_len, &odp_actions); + xlate_in_init(&xin, ofproto, &facet->flow, &facet->initial_vals, rule, + 0, NULL); + xlate_actions(&xin, &xout); - ok = ofpbuf_equal(&facet->odp_actions, &odp_actions) - && facet->slow == ctx.slow; + ok = ofpbuf_equal(&facet->xout.odp_actions, &xout.odp_actions) + && facet->xout.slow == xout.slow; if (!ok && !VLOG_DROP_WARN(&rl)) { struct ds s = DS_EMPTY_INITIALIZER; flow_format(&s, &facet->flow); ds_put_cstr(&s, ": inconsistency in facet"); - if (!ofpbuf_equal(&facet->odp_actions, &odp_actions)) { + if (!ofpbuf_equal(&facet->xout.odp_actions, &xout.odp_actions)) { ds_put_cstr(&s, " (actions were: "); - format_odp_actions(&s, facet->odp_actions.data, - facet->odp_actions.size); + format_odp_actions(&s, facet->xout.odp_actions.data, + facet->xout.odp_actions.size); ds_put_cstr(&s, ") (correct actions: "); - format_odp_actions(&s, odp_actions.data, odp_actions.size); + format_odp_actions(&s, xout.odp_actions.data, + xout.odp_actions.size); ds_put_cstr(&s, ")"); } - if (facet->slow != ctx.slow) { - ds_put_format(&s, " slow path incorrect. should be %d", ctx.slow); + if (facet->xout.slow != xout.slow) { + ds_put_format(&s, " slow path incorrect. should be %d", xout.slow); } ds_destroy(&s); } - ofpbuf_uninit(&odp_actions); + xlate_out_uninit(&xout); return ok; } @@ -4979,13 +4975,10 @@ static bool facet_revalidate(struct facet *facet) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto); - - uint64_t odp_actions_stub[1024 / 8]; - struct ofpbuf odp_actions; - struct rule_dpif *new_rule; struct subfacet *subfacet; - struct xlate_ctx ctx; + struct xlate_out xout; + struct xlate_in xin; COVERAGE_INC(facet_revalidate); @@ -5015,45 +5008,45 @@ facet_revalidate(struct facet *facet) * We do not modify any 'facet' state yet, because we might need to, e.g., * emit a NetFlow expiration and, if so, we need to have the old state * around to properly compose it. */ - ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub); - xlate_ctx_init(&ctx, ofproto, &facet->flow, &facet->initial_vals, new_rule, - 0, NULL); - xlate_actions(&ctx, new_rule->up.ofpacts, new_rule->up.ofpacts_len, - &odp_actions); + xlate_in_init(&xin, ofproto, &facet->flow, &facet->initial_vals, new_rule, + 0, NULL); + xlate_actions(&xin, &xout); /* A facet's slow path reason should only change under dramatic * circumstances. Rather than try to update everything, it's simpler to * remove the facet and start over. */ - if (facet->slow != ctx.slow) { + if (facet->xout.slow != xout.slow) { facet_remove(facet); - ofpbuf_uninit(&odp_actions); + xlate_out_uninit(&xout); return false; } - if (!ofpbuf_equal(&facet->odp_actions, &odp_actions)) { + if (!ofpbuf_equal(&facet->xout.odp_actions, &xout.odp_actions)) { LIST_FOR_EACH(subfacet, list_node, &facet->subfacets) { if (subfacet->path == SF_FAST_PATH) { struct dpif_flow_stats stats; - subfacet_install(subfacet, &odp_actions, &stats); + subfacet_install(subfacet, &xout.odp_actions, &stats); subfacet_update_stats(subfacet, &stats); } } facet_flush_stats(facet); - ofpbuf_clear(&facet->odp_actions); - ofpbuf_put(&facet->odp_actions, odp_actions.data, odp_actions.size); + ofpbuf_clear(&facet->xout.odp_actions); + ofpbuf_put(&facet->xout.odp_actions, xout.odp_actions.data, + xout.odp_actions.size); } /* Update 'facet' now that we've taken care of all the old state. */ - facet->tags = ctx.tags; - facet->slow = ctx.slow; - facet->nf_flow.output_iface = ctx.nf_output_iface; - facet->has_learn = ctx.has_learn; - facet->has_normal = ctx.has_normal; - facet->has_fin_timeout = ctx.has_fin_timeout; - facet->mirrors = ctx.mirrors; + facet->xout.tags = xout.tags; + facet->xout.slow = xout.slow; + facet->xout.has_learn = xout.has_learn; + facet->xout.has_normal = xout.has_normal; + facet->xout.has_fin_timeout = xout.has_fin_timeout; + facet->xout.nf_output_iface = xout.nf_output_iface; + facet->xout.mirrors = xout.mirrors; + facet->nf_flow.output_iface = facet->xout.nf_output_iface; if (facet->rule != new_rule) { COVERAGE_INC(facet_changed_rule); @@ -5064,7 +5057,7 @@ facet_revalidate(struct facet *facet) facet->prev_used = facet->used; } - ofpbuf_uninit(&odp_actions); + xlate_out_uninit(&xout); return true; } @@ -5114,7 +5107,8 @@ facet_push_stats(struct facet *facet) flow_push_stats(facet, &stats); update_mirror_stats(ofproto_dpif_cast(facet->rule->up.ofproto), - facet->mirrors, stats.n_packets, stats.n_bytes); + facet->xout.mirrors, stats.n_packets, + stats.n_bytes); } } @@ -5163,15 +5157,14 @@ flow_push_stats(struct facet *facet, const struct dpif_flow_stats *stats) { struct rule_dpif *rule = facet->rule; struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto); - struct xlate_ctx ctx; + struct xlate_in xin; ofproto_rule_update_used(&rule->up, stats->used); - xlate_ctx_init(&ctx, ofproto, &facet->flow, &facet->initial_vals, rule, 0, - NULL); - ctx.resubmit_stats = stats; - xlate_actions_for_side_effects(&ctx, rule->up.ofpacts, - rule->up.ofpacts_len); + xlate_in_init(&xin, ofproto, &facet->flow, &facet->initial_vals, rule, + 0, NULL); + xin.resubmit_stats = stats; + xlate_actions_for_side_effects(&xin); } /* Subfacets. */ @@ -5318,7 +5311,7 @@ subfacet_install(struct subfacet *subfacet, const struct ofpbuf *odp_actions, { struct facet *facet = subfacet->facet; struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto); - enum subfacet_path path = facet->slow ? SF_SLOW_PATH : SF_FAST_PATH; + enum subfacet_path path = facet->xout.slow ? SF_SLOW_PATH : SF_FAST_PATH; const struct nlattr *actions = odp_actions->data; size_t actions_len = odp_actions->size; @@ -5332,7 +5325,7 @@ subfacet_install(struct subfacet *subfacet, const struct ofpbuf *odp_actions, } if (path == SF_SLOW_PATH) { - compose_slow_path(ofproto, &facet->flow, facet->slow, + compose_slow_path(ofproto, &facet->flow, facet->xout.slow, slow_path_stub, sizeof slow_path_stub, &actions, &actions_len); } @@ -5598,24 +5591,22 @@ rule_dpif_execute(struct rule_dpif *rule, const struct flow *flow, struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto); struct initial_vals initial_vals; struct dpif_flow_stats stats; - struct xlate_ctx ctx; - uint64_t odp_actions_stub[1024 / 8]; - struct ofpbuf odp_actions; + struct xlate_out xout; + struct xlate_in xin; dpif_flow_stats_extract(flow, packet, time_msec(), &stats); rule_credit_stats(rule, &stats); initial_vals.vlan_tci = flow->vlan_tci; - ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub); - xlate_ctx_init(&ctx, ofproto, flow, &initial_vals, - rule, stats.tcp_flags, packet); - ctx.resubmit_stats = &stats; - xlate_actions(&ctx, rule->up.ofpacts, rule->up.ofpacts_len, &odp_actions); + xlate_in_init(&xin, ofproto, flow, &initial_vals, rule, stats.tcp_flags, + packet); + xin.resubmit_stats = &stats; + xlate_actions(&xin, &xout); - execute_odp_actions(ofproto, flow, odp_actions.data, - odp_actions.size, packet); + execute_odp_actions(ofproto, flow, xout.odp_actions.data, + xout.odp_actions.size, packet); - ofpbuf_uninit(&odp_actions); + xlate_out_uninit(&xout); } static enum ofperr @@ -5647,7 +5638,8 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet) struct dpif_flow_stats stats; struct odputil_keybuf keybuf; struct ofpact_output output; - struct xlate_ctx ctx; + struct xlate_out xout; + struct xlate_in xin; struct flow flow; int error; @@ -5664,15 +5656,17 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet) output.port = ofport->up.ofp_port; output.max_len = 0; - xlate_ctx_init(&ctx, ofproto, &flow, NULL, NULL, 0, packet); - ctx.resubmit_stats = &stats; - xlate_actions(&ctx, &output.ofpact, sizeof output, &odp_actions); + xlate_in_init(&xin, ofproto, &flow, NULL, NULL, 0, packet); + xin.ofpacts_len = sizeof output; + xin.ofpacts = &output.ofpact; + xin.resubmit_stats = &stats; + xlate_actions(&xin, &xout); error = dpif_execute(ofproto->backer->dpif, key.data, key.size, - odp_actions.data, odp_actions.size, + xout.odp_actions.data, xout.odp_actions.size, packet); - ofpbuf_uninit(&odp_actions); + xlate_out_uninit(&xout); if (error) { VLOG_WARN_RL(&rl, "%s: failed to send packet on port %s (%s)", @@ -5869,8 +5863,8 @@ static void add_sflow_action(struct xlate_ctx *ctx) { ctx->user_cookie_offset = compose_sflow_action(ctx->ofproto, - ctx->odp_actions, - &ctx->flow, OVSP_NONE); + &ctx->xout->odp_actions, + &ctx->xin->flow, OVSP_NONE); ctx->sflow_odp_port = 0; ctx->sflow_n_outputs = 0; } @@ -5880,7 +5874,8 @@ add_sflow_action(struct xlate_ctx *ctx) static void add_ipfix_action(struct xlate_ctx *ctx) { - compose_ipfix_action(ctx->ofproto, ctx->odp_actions, &ctx->flow); + compose_ipfix_action(ctx->ofproto, &ctx->xout->odp_actions, + &ctx->xin->flow); } /* Fix SAMPLE action according to data collected while composing ODP actions. @@ -5896,7 +5891,7 @@ fix_sflow_action(struct xlate_ctx *ctx) return; } - cookie = ofpbuf_at(ctx->odp_actions, ctx->user_cookie_offset, + cookie = ofpbuf_at(&ctx->xout->odp_actions, ctx->user_cookie_offset, sizeof cookie->sflow); ovs_assert(cookie->type == USER_ACTION_COOKIE_SFLOW); @@ -5932,7 +5927,7 @@ compose_output_action__(struct xlate_ctx *ctx, uint16_t ofp_port, if (netdev_vport_is_patch(ofport->up.netdev)) { struct ofport_dpif *peer = ofport_get_peer(ofport); - struct flow old_flow = ctx->flow; + struct flow old_flow = ctx->xin->flow; const struct ofproto_dpif *peer_ofproto; enum slow_path_reason special; struct ofport_dpif *in_port; @@ -5949,49 +5944,49 @@ compose_output_action__(struct xlate_ctx *ctx, uint16_t ofp_port, } ctx->ofproto = ofproto_dpif_cast(peer->up.ofproto); - ctx->flow.in_port = peer->up.ofp_port; - ctx->flow.metadata = htonll(0); - memset(&ctx->flow.tunnel, 0, sizeof ctx->flow.tunnel); - memset(ctx->flow.regs, 0, sizeof ctx->flow.regs); - - in_port = get_ofp_port(ctx->ofproto, ctx->flow.in_port); - special = process_special(ctx->ofproto, &ctx->flow, in_port, - ctx->packet); + ctx->xin->flow.in_port = peer->up.ofp_port; + ctx->xin->flow.metadata = htonll(0); + memset(&ctx->xin->flow.tunnel, 0, sizeof ctx->xin->flow.tunnel); + memset(ctx->xin->flow.regs, 0, sizeof ctx->xin->flow.regs); + + in_port = get_ofp_port(ctx->ofproto, ctx->xin->flow.in_port); + special = process_special(ctx->ofproto, &ctx->xin->flow, in_port, + ctx->xin->packet); if (special) { - ctx->slow = special; + ctx->xout->slow = special; } else if (!in_port || may_receive(in_port, ctx)) { if (!in_port || stp_forward_in_state(in_port->stp_state)) { - xlate_table_action(ctx, ctx->flow.in_port, 0, true); + xlate_table_action(ctx, ctx->xin->flow.in_port, 0, true); } else { /* Forwarding is disabled by STP. Let OFPP_NORMAL and 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; - xlate_table_action(ctx, ctx->flow.in_port, 0, true); + size_t old_size = ctx->xout->odp_actions.size; + xlate_table_action(ctx, ctx->xin->flow.in_port, 0, true); ctx->base_flow = old_base_flow; - ctx->odp_actions->size = old_size; + ctx->xout->odp_actions.size = old_size; } } - ctx->flow = old_flow; + ctx->xin->flow = old_flow; ctx->ofproto = ofproto_dpif_cast(ofport->up.ofproto); - if (ctx->resubmit_stats) { - netdev_vport_inc_tx(ofport->up.netdev, ctx->resubmit_stats); - netdev_vport_inc_rx(peer->up.netdev, ctx->resubmit_stats); + if (ctx->xin->resubmit_stats) { + netdev_vport_inc_tx(ofport->up.netdev, ctx->xin->resubmit_stats); + netdev_vport_inc_rx(peer->up.netdev, ctx->xin->resubmit_stats); } return; } - flow_vlan_tci = ctx->flow.vlan_tci; - flow_skb_mark = ctx->flow.skb_mark; - flow_nw_tos = ctx->flow.nw_tos; + flow_vlan_tci = ctx->xin->flow.vlan_tci; + flow_skb_mark = ctx->xin->flow.skb_mark; + flow_nw_tos = ctx->xin->flow.nw_tos; - pdscp = get_priority(ofport, ctx->flow.skb_priority); + pdscp = get_priority(ofport, ctx->xin->flow.skb_priority); if (pdscp) { - ctx->flow.nw_tos &= ~IP_DSCP_MASK; - ctx->flow.nw_tos |= pdscp->dscp; + ctx->xin->flow.nw_tos &= ~IP_DSCP_MASK; + ctx->xin->flow.nw_tos |= pdscp->dscp; } if (ofport->tnl_port) { @@ -5999,44 +5994,45 @@ compose_output_action__(struct xlate_ctx *ctx, uint16_t ofp_port, * the Logical (tunnel) Port are not visible for any further * matches, while explicit set actions on tunnel metadata are. */ - struct flow_tnl flow_tnl = ctx->flow.tunnel; - odp_port = tnl_port_send(ofport->tnl_port, &ctx->flow); + struct flow_tnl flow_tnl = ctx->xin->flow.tunnel; + odp_port = tnl_port_send(ofport->tnl_port, &ctx->xin->flow); if (odp_port == OVSP_NONE) { xlate_report(ctx, "Tunneling decided against output"); goto out; /* restore flow_nw_tos */ } - if (ctx->flow.tunnel.ip_dst == ctx->orig_tunnel_ip_dst) { + if (ctx->xin->flow.tunnel.ip_dst == ctx->orig_tunnel_ip_dst) { xlate_report(ctx, "Not tunneling to our own address"); goto out; /* restore flow_nw_tos */ } - if (ctx->resubmit_stats) { - netdev_vport_inc_tx(ofport->up.netdev, ctx->resubmit_stats); + if (ctx->xin->resubmit_stats) { + netdev_vport_inc_tx(ofport->up.netdev, ctx->xin->resubmit_stats); } out_port = odp_port; - commit_odp_tunnel_action(&ctx->flow, &ctx->base_flow, - ctx->odp_actions); - ctx->flow.tunnel = flow_tnl; /* Restore tunnel metadata */ + commit_odp_tunnel_action(&ctx->xin->flow, &ctx->base_flow, + &ctx->xout->odp_actions); + ctx->xin->flow.tunnel = flow_tnl; /* Restore tunnel metadata */ } else { odp_port = ofport->odp_port; out_port = vsp_realdev_to_vlandev(ctx->ofproto, odp_port, - ctx->flow.vlan_tci); + ctx->xin->flow.vlan_tci); if (out_port != odp_port) { - ctx->flow.vlan_tci = htons(0); + ctx->xin->flow.vlan_tci = htons(0); } - ctx->flow.skb_mark &= ~IPSEC_MARK; + ctx->xin->flow.skb_mark &= ~IPSEC_MARK; } - commit_odp_actions(&ctx->flow, &ctx->base_flow, ctx->odp_actions); - nl_msg_put_u32(ctx->odp_actions, OVS_ACTION_ATTR_OUTPUT, out_port); + commit_odp_actions(&ctx->xin->flow, &ctx->base_flow, + &ctx->xout->odp_actions); + nl_msg_put_u32(&ctx->xout->odp_actions, OVS_ACTION_ATTR_OUTPUT, out_port); ctx->sflow_odp_port = odp_port; ctx->sflow_n_outputs++; - ctx->nf_output_iface = ofp_port; + ctx->xout->nf_output_iface = ofp_port; /* Restore flow */ - ctx->flow.vlan_tci = flow_vlan_tci; - ctx->flow.skb_mark = flow_skb_mark; + ctx->xin->flow.vlan_tci = flow_vlan_tci; + ctx->xin->flow.skb_mark = flow_skb_mark; out: - ctx->flow.nw_tos = flow_nw_tos; + ctx->xin->flow.nw_tos = flow_nw_tos; } static void @@ -6054,11 +6050,11 @@ tag_the_flow(struct xlate_ctx *ctx, struct rule_dpif *rule) if (table_id > 0 && table_id < N_TABLES) { struct table_dpif *table = &ofproto->tables[table_id]; if (table->other_table) { - ctx->tags |= (rule && rule->tag - ? rule->tag - : rule_calculate_tag(&ctx->flow, - &table->other_table->mask, - table->basis)); + ctx->xout->tags |= (rule && rule->tag + ? rule->tag + : rule_calculate_tag(&ctx->xin->flow, + &table->other_table->mask, + table->basis)); } } } @@ -6068,8 +6064,8 @@ static struct rule_dpif * ctx_rule_hooks(struct xlate_ctx *ctx, struct rule_dpif *rule, bool may_packet_in) { - if (ctx->resubmit_hook) { - ctx->resubmit_hook(ctx, rule); + if (ctx->xin->resubmit_hook) { + ctx->xin->resubmit_hook(ctx, rule); } if (rule == NULL && may_packet_in) { /* XXX @@ -6079,10 +6075,10 @@ ctx_rule_hooks(struct xlate_ctx *ctx, struct rule_dpif *rule, * OFPTC_TABLE_MISS_DROP * When OF1.0, OFPTC_TABLE_MISS_CONTINUE is used. What to do? */ - rule = rule_dpif_miss_rule(ctx->ofproto, &ctx->flow); + rule = rule_dpif_miss_rule(ctx->ofproto, &ctx->xin->flow); } - if (rule && ctx->resubmit_stats) { - rule_credit_stats(rule, ctx->resubmit_stats); + if (rule && ctx->xin->resubmit_stats) { + rule_credit_stats(rule, ctx->xin->resubmit_stats); } return rule; } @@ -6093,20 +6089,20 @@ xlate_table_action(struct xlate_ctx *ctx, { if (ctx->recurse < MAX_RESUBMIT_RECURSION) { struct rule_dpif *rule; - uint16_t old_in_port = ctx->flow.in_port; + uint16_t old_in_port = ctx->xin->flow.in_port; uint8_t old_table_id = ctx->table_id; ctx->table_id = table_id; /* Look up a flow with 'in_port' as the input port. */ - ctx->flow.in_port = in_port; - rule = rule_dpif_lookup__(ctx->ofproto, &ctx->flow, table_id); + ctx->xin->flow.in_port = in_port; + rule = rule_dpif_lookup__(ctx->ofproto, &ctx->xin->flow, table_id); tag_the_flow(ctx, rule); /* Restore the original input port. Otherwise OFPP_NORMAL and * OFPP_IN_PORT will have surprising behavior. */ - ctx->flow.in_port = old_in_port; + ctx->xin->flow.in_port = old_in_port; rule = ctx_rule_hooks(ctx, rule, may_packet_in); @@ -6139,7 +6135,7 @@ xlate_ofpact_resubmit(struct xlate_ctx *ctx, in_port = resubmit->in_port; if (in_port == OFPP_IN_PORT) { - in_port = ctx->flow.in_port; + in_port = ctx->xin->flow.in_port; } table_id = resubmit->table_id; @@ -6158,7 +6154,7 @@ flood_packets(struct xlate_ctx *ctx, bool all) HMAP_FOR_EACH (ofport, up.hmap_node, &ctx->ofproto->up.ports) { uint16_t ofp_port = ofport->up.ofp_port; - if (ofp_port == ctx->flow.in_port) { + if (ofp_port == ctx->xin->flow.in_port) { continue; } @@ -6169,7 +6165,7 @@ flood_packets(struct xlate_ctx *ctx, bool all) } } - ctx->nf_output_iface = NF_OUT_FLOOD; + ctx->xout->nf_output_iface = NF_OUT_FLOOD; } static void @@ -6180,13 +6176,13 @@ execute_controller_action(struct xlate_ctx *ctx, int len, struct ofputil_packet_in pin; struct ofpbuf *packet; - ovs_assert(!ctx->slow || ctx->slow == SLOW_CONTROLLER); - ctx->slow = SLOW_CONTROLLER; - if (!ctx->packet) { + ovs_assert(!ctx->xout->slow || ctx->xout->slow == SLOW_CONTROLLER); + ctx->xout->slow = SLOW_CONTROLLER; + if (!ctx->xin->packet) { return; } - packet = ofpbuf_clone(ctx->packet); + packet = ofpbuf_clone(ctx->xin->packet); if (packet->l2 && packet->l3) { struct eth_header *eh; @@ -6195,36 +6191,37 @@ execute_controller_action(struct xlate_ctx *ctx, int len, eth_pop_vlan(packet); eh = packet->l2; - memcpy(eh->eth_src, ctx->flow.dl_src, sizeof eh->eth_src); - memcpy(eh->eth_dst, ctx->flow.dl_dst, sizeof eh->eth_dst); + memcpy(eh->eth_src, ctx->xin->flow.dl_src, sizeof eh->eth_src); + memcpy(eh->eth_dst, ctx->xin->flow.dl_dst, sizeof eh->eth_dst); - if (ctx->flow.vlan_tci & htons(VLAN_CFI)) { - eth_push_vlan(packet, ctx->flow.vlan_tci); + if (ctx->xin->flow.vlan_tci & htons(VLAN_CFI)) { + eth_push_vlan(packet, ctx->xin->flow.vlan_tci); } mpls_depth = eth_mpls_depth(packet); - if (mpls_depth < ctx->flow.mpls_depth) { - push_mpls(packet, ctx->flow.dl_type, ctx->flow.mpls_lse); - } else if (mpls_depth > ctx->flow.mpls_depth) { - pop_mpls(packet, ctx->flow.dl_type); + if (mpls_depth < ctx->xin->flow.mpls_depth) { + push_mpls(packet, ctx->xin->flow.dl_type, ctx->xin->flow.mpls_lse); + } else if (mpls_depth > ctx->xin->flow.mpls_depth) { + pop_mpls(packet, ctx->xin->flow.dl_type); } else if (mpls_depth) { - set_mpls_lse(packet, ctx->flow.mpls_lse); + set_mpls_lse(packet, ctx->xin->flow.mpls_lse); } if (packet->l4) { - if (ctx->flow.dl_type == htons(ETH_TYPE_IP)) { - packet_set_ipv4(packet, ctx->flow.nw_src, ctx->flow.nw_dst, - ctx->flow.nw_tos, ctx->flow.nw_ttl); + if (ctx->xin->flow.dl_type == htons(ETH_TYPE_IP)) { + packet_set_ipv4(packet, ctx->xin->flow.nw_src, + ctx->xin->flow.nw_dst, ctx->xin->flow.nw_tos, + ctx->xin->flow.nw_ttl); } if (packet->l7) { - if (ctx->flow.nw_proto == IPPROTO_TCP) { - packet_set_tcp_port(packet, ctx->flow.tp_src, - ctx->flow.tp_dst); - } else if (ctx->flow.nw_proto == IPPROTO_UDP) { - packet_set_udp_port(packet, ctx->flow.tp_src, - ctx->flow.tp_dst); + if (ctx->xin->flow.nw_proto == IPPROTO_TCP) { + packet_set_tcp_port(packet, ctx->xin->flow.tp_src, + ctx->xin->flow.tp_dst); + } else if (ctx->xin->flow.nw_proto == IPPROTO_UDP) { + packet_set_udp_port(packet, ctx->xin->flow.tp_src, + ctx->xin->flow.tp_dst); } } } @@ -6238,7 +6235,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len, pin.cookie = ctx->rule ? ctx->rule->up.flow_cookie : 0; pin.send_len = len; - flow_get_metadata(&ctx->flow, &pin.fmd); + flow_get_metadata(&ctx->xin->flow, &pin.fmd); connmgr_send_packet_in(ctx->ofproto->up.connmgr, &pin); ofpbuf_delete(packet); @@ -6250,36 +6247,36 @@ execute_mpls_push_action(struct xlate_ctx *ctx, ovs_be16 eth_type) ovs_assert(eth_type_mpls(eth_type)); if (ctx->base_flow.mpls_depth) { - ctx->flow.mpls_lse &= ~htonl(MPLS_BOS_MASK); - ctx->flow.mpls_depth++; + ctx->xin->flow.mpls_lse &= ~htonl(MPLS_BOS_MASK); + ctx->xin->flow.mpls_depth++; } else { ovs_be32 label; uint8_t tc, ttl; - if (ctx->flow.dl_type == htons(ETH_TYPE_IPV6)) { + if (ctx->xin->flow.dl_type == htons(ETH_TYPE_IPV6)) { label = htonl(0x2); /* IPV6 Explicit Null. */ } else { label = htonl(0x0); /* IPV4 Explicit Null. */ } - tc = (ctx->flow.nw_tos & IP_DSCP_MASK) >> 2; - ttl = ctx->flow.nw_ttl ? ctx->flow.nw_ttl : 0x40; - ctx->flow.mpls_lse = set_mpls_lse_values(ttl, tc, 1, label); - ctx->flow.mpls_depth = 1; + tc = (ctx->xin->flow.nw_tos & IP_DSCP_MASK) >> 2; + ttl = ctx->xin->flow.nw_ttl ? ctx->xin->flow.nw_ttl : 0x40; + ctx->xin->flow.mpls_lse = set_mpls_lse_values(ttl, tc, 1, label); + ctx->xin->flow.mpls_depth = 1; } - ctx->flow.dl_type = eth_type; + ctx->xin->flow.dl_type = eth_type; } static void execute_mpls_pop_action(struct xlate_ctx *ctx, ovs_be16 eth_type) { - ovs_assert(eth_type_mpls(ctx->flow.dl_type)); + ovs_assert(eth_type_mpls(ctx->xin->flow.dl_type)); ovs_assert(!eth_type_mpls(eth_type)); - if (ctx->flow.mpls_depth) { - ctx->flow.mpls_depth--; - ctx->flow.mpls_lse = htonl(0); - if (!ctx->flow.mpls_depth) { - ctx->flow.dl_type = eth_type; + if (ctx->xin->flow.mpls_depth) { + ctx->xin->flow.mpls_depth--; + ctx->xin->flow.mpls_lse = htonl(0); + if (!ctx->xin->flow.mpls_depth) { + ctx->xin->flow.dl_type = eth_type; } } } @@ -6287,13 +6284,13 @@ execute_mpls_pop_action(struct xlate_ctx *ctx, ovs_be16 eth_type) static bool compose_dec_ttl(struct xlate_ctx *ctx, struct ofpact_cnt_ids *ids) { - if (ctx->flow.dl_type != htons(ETH_TYPE_IP) && - ctx->flow.dl_type != htons(ETH_TYPE_IPV6)) { + if (ctx->xin->flow.dl_type != htons(ETH_TYPE_IP) && + ctx->xin->flow.dl_type != htons(ETH_TYPE_IPV6)) { return false; } - if (ctx->flow.nw_ttl > 1) { - ctx->flow.nw_ttl--; + if (ctx->xin->flow.nw_ttl > 1) { + ctx->xin->flow.nw_ttl--; return false; } else { size_t i; @@ -6311,26 +6308,26 @@ compose_dec_ttl(struct xlate_ctx *ctx, struct ofpact_cnt_ids *ids) static bool execute_set_mpls_ttl_action(struct xlate_ctx *ctx, uint8_t ttl) { - if (!eth_type_mpls(ctx->flow.dl_type)) { + if (!eth_type_mpls(ctx->xin->flow.dl_type)) { return true; } - set_mpls_lse_ttl(&ctx->flow.mpls_lse, ttl); + set_mpls_lse_ttl(&ctx->xin->flow.mpls_lse, ttl); return false; } static bool execute_dec_mpls_ttl_action(struct xlate_ctx *ctx) { - uint8_t ttl = mpls_lse_to_ttl(ctx->flow.mpls_lse); + uint8_t ttl = mpls_lse_to_ttl(ctx->xin->flow.mpls_lse); - if (!eth_type_mpls(ctx->flow.dl_type)) { + if (!eth_type_mpls(ctx->xin->flow.dl_type)) { return false; } if (ttl > 1) { ttl--; - set_mpls_lse_ttl(&ctx->flow.mpls_lse, ttl); + set_mpls_lse_ttl(&ctx->xin->flow.mpls_lse, ttl); return false; } else { execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0); @@ -6344,16 +6341,16 @@ static void xlate_output_action(struct xlate_ctx *ctx, uint16_t port, uint16_t max_len, bool may_packet_in) { - uint16_t prev_nf_output_iface = ctx->nf_output_iface; + uint16_t prev_nf_output_iface = ctx->xout->nf_output_iface; - ctx->nf_output_iface = NF_OUT_DROP; + ctx->xout->nf_output_iface = NF_OUT_DROP; switch (port) { case OFPP_IN_PORT: - compose_output_action(ctx, ctx->flow.in_port); + compose_output_action(ctx, ctx->xin->flow.in_port); break; case OFPP_TABLE: - xlate_table_action(ctx, ctx->flow.in_port, 0, may_packet_in); + xlate_table_action(ctx, ctx->xin->flow.in_port, 0, may_packet_in); break; case OFPP_NORMAL: xlate_normal(ctx); @@ -6371,7 +6368,7 @@ xlate_output_action(struct xlate_ctx *ctx, break; case OFPP_LOCAL: default: - if (port != ctx->flow.in_port) { + if (port != ctx->xin->flow.in_port) { compose_output_action(ctx, port); } else { xlate_report(ctx, "skipping output to input port"); @@ -6380,12 +6377,12 @@ xlate_output_action(struct xlate_ctx *ctx, } if (prev_nf_output_iface == NF_OUT_FLOOD) { - ctx->nf_output_iface = NF_OUT_FLOOD; - } else if (ctx->nf_output_iface == NF_OUT_DROP) { - ctx->nf_output_iface = prev_nf_output_iface; + 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; } else if (prev_nf_output_iface != NF_OUT_DROP && - ctx->nf_output_iface != NF_OUT_FLOOD) { - ctx->nf_output_iface = NF_OUT_MULTI; + ctx->xout->nf_output_iface != NF_OUT_FLOOD) { + ctx->xout->nf_output_iface = NF_OUT_MULTI; } } @@ -6393,7 +6390,7 @@ static void xlate_output_reg_action(struct xlate_ctx *ctx, const struct ofpact_output_reg *or) { - uint64_t port = mf_get_subfield(&or->src, &ctx->flow); + uint64_t port = mf_get_subfield(&or->src, &ctx->xin->flow); if (port <= UINT16_MAX) { xlate_output_action(ctx, port, or->max_len, false); } @@ -6419,22 +6416,22 @@ xlate_enqueue_action(struct xlate_ctx *ctx, /* Check output port. */ if (ofp_port == OFPP_IN_PORT) { - ofp_port = ctx->flow.in_port; - } else if (ofp_port == ctx->flow.in_port) { + ofp_port = ctx->xin->flow.in_port; + } else if (ofp_port == ctx->xin->flow.in_port) { return; } /* Add datapath actions. */ - flow_priority = ctx->flow.skb_priority; - ctx->flow.skb_priority = priority; + flow_priority = ctx->xin->flow.skb_priority; + ctx->xin->flow.skb_priority = priority; compose_output_action(ctx, ofp_port); - ctx->flow.skb_priority = flow_priority; + ctx->xin->flow.skb_priority = flow_priority; /* Update NetFlow output port. */ - 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; + 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; } } @@ -6445,7 +6442,7 @@ xlate_set_queue_action(struct xlate_ctx *ctx, uint32_t queue_id) if (!dpif_queue_to_priority(ctx->ofproto->backer->dpif, queue_id, &skb_priority)) { - ctx->flow.skb_priority = skb_priority; + ctx->xin->flow.skb_priority = skb_priority; } else { /* Couldn't translate queue to a priority. Nothing to do. A warning * has already been logged. */ @@ -6480,9 +6477,10 @@ xlate_bundle_action(struct xlate_ctx *ctx, { uint16_t port; - port = bundle_execute(bundle, &ctx->flow, slave_enabled_cb, ctx->ofproto); + port = bundle_execute(bundle, &ctx->xin->flow, slave_enabled_cb, + ctx->ofproto); if (bundle->dst.field) { - nxm_reg_load(&bundle->dst, port, &ctx->flow); + nxm_reg_load(&bundle->dst, port, &ctx->xin->flow); } else { xlate_output_action(ctx, port, 0, false); } @@ -6499,7 +6497,7 @@ xlate_learn_action(struct xlate_ctx *ctx, int error; ofpbuf_use_stack(&ofpacts, ofpacts_stub, sizeof ofpacts_stub); - learn_execute(learn, &ctx->flow, &fm, &ofpacts); + learn_execute(learn, &ctx->xin->flow, &fm, &ofpacts); error = ofproto_flow_mod(&ctx->ofproto->up, &fm); if (error && !VLOG_DROP_WARN(&rl)) { @@ -6524,7 +6522,7 @@ static void xlate_fin_timeout(struct xlate_ctx *ctx, const struct ofpact_fin_timeout *oft) { - if (ctx->tcp_flags & (TCP_FIN | TCP_RST) && ctx->rule) { + if (ctx->xin->tcp_flags & (TCP_FIN | TCP_RST) && ctx->rule) { struct rule_dpif *rule = ctx->rule; reduce_timeout(oft->fin_idle_timeout, &rule->up.idle_timeout); @@ -6541,18 +6539,20 @@ xlate_sample_action(struct xlate_ctx *ctx, * the same percentage. */ uint32_t probability = (os->probability << 16) | os->probability; - commit_odp_actions(&ctx->flow, &ctx->base_flow, ctx->odp_actions); + commit_odp_actions(&ctx->xin->flow, &ctx->base_flow, + &ctx->xout->odp_actions); compose_flow_sample_cookie(os->probability, os->collector_set_id, os->obs_domain_id, os->obs_point_id, &cookie); - compose_sample_action(ctx->ofproto, ctx->odp_actions, &ctx->flow, + compose_sample_action(ctx->ofproto, &ctx->xout->odp_actions, &ctx->xin->flow, probability, &cookie, sizeof cookie.flow_sample); } static bool may_receive(const struct ofport_dpif *port, struct xlate_ctx *ctx) { - if (port->up.pp.config & (eth_addr_equals(ctx->flow.dl_dst, eth_addr_stp) + if (port->up.pp.config & (eth_addr_equals(ctx->xin->flow.dl_dst, + eth_addr_stp) ? OFPUTIL_PC_NO_RECV_STP : OFPUTIL_PC_NO_RECV)) { return false; @@ -6574,14 +6574,14 @@ static bool tunnel_ecn_ok(struct xlate_ctx *ctx) { if (is_ip_any(&ctx->base_flow) - && (ctx->flow.tunnel.ip_tos & IP_ECN_MASK) == IP_ECN_CE) { + && (ctx->xin->flow.tunnel.ip_tos & IP_ECN_MASK) == IP_ECN_CE) { if ((ctx->base_flow.nw_tos & IP_ECN_MASK) == IP_ECN_NOT_ECT) { VLOG_WARN_RL(&rl, "dropping tunnel packet marked ECN CE" " but is not ECN capable"); return false; } else { /* Set the ECN CE value in the tunneled packet. */ - ctx->flow.nw_tos |= IP_ECN_CE; + ctx->xin->flow.nw_tos |= IP_ECN_CE; } } @@ -6628,66 +6628,69 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_SET_VLAN_VID: - ctx->flow.vlan_tci &= ~htons(VLAN_VID_MASK); - ctx->flow.vlan_tci |= (htons(ofpact_get_SET_VLAN_VID(a)->vlan_vid) - | htons(VLAN_CFI)); + ctx->xin->flow.vlan_tci &= ~htons(VLAN_VID_MASK); + ctx->xin->flow.vlan_tci |= + (htons(ofpact_get_SET_VLAN_VID(a)->vlan_vid) + | htons(VLAN_CFI)); break; case OFPACT_SET_VLAN_PCP: - ctx->flow.vlan_tci &= ~htons(VLAN_PCP_MASK); - ctx->flow.vlan_tci |= htons((ofpact_get_SET_VLAN_PCP(a)->vlan_pcp - << VLAN_PCP_SHIFT) - | VLAN_CFI); + ctx->xin->flow.vlan_tci &= ~htons(VLAN_PCP_MASK); + ctx->xin->flow.vlan_tci |= + htons((ofpact_get_SET_VLAN_PCP(a)->vlan_pcp << VLAN_PCP_SHIFT) + | VLAN_CFI); break; case OFPACT_STRIP_VLAN: - ctx->flow.vlan_tci = htons(0); + ctx->xin->flow.vlan_tci = htons(0); break; case OFPACT_PUSH_VLAN: /* XXX 802.1AD(QinQ) */ - ctx->flow.vlan_tci = htons(VLAN_CFI); + ctx->xin->flow.vlan_tci = htons(VLAN_CFI); break; case OFPACT_SET_ETH_SRC: - memcpy(ctx->flow.dl_src, ofpact_get_SET_ETH_SRC(a)->mac, + memcpy(ctx->xin->flow.dl_src, ofpact_get_SET_ETH_SRC(a)->mac, ETH_ADDR_LEN); break; case OFPACT_SET_ETH_DST: - memcpy(ctx->flow.dl_dst, ofpact_get_SET_ETH_DST(a)->mac, + memcpy(ctx->xin->flow.dl_dst, ofpact_get_SET_ETH_DST(a)->mac, ETH_ADDR_LEN); break; case OFPACT_SET_IPV4_SRC: - if (ctx->flow.dl_type == htons(ETH_TYPE_IP)) { - ctx->flow.nw_src = ofpact_get_SET_IPV4_SRC(a)->ipv4; + if (ctx->xin->flow.dl_type == htons(ETH_TYPE_IP)) { + ctx->xin->flow.nw_src = ofpact_get_SET_IPV4_SRC(a)->ipv4; } break; case OFPACT_SET_IPV4_DST: - if (ctx->flow.dl_type == htons(ETH_TYPE_IP)) { - ctx->flow.nw_dst = ofpact_get_SET_IPV4_DST(a)->ipv4; + if (ctx->xin->flow.dl_type == htons(ETH_TYPE_IP)) { + ctx->xin->flow.nw_dst = ofpact_get_SET_IPV4_DST(a)->ipv4; } break; case OFPACT_SET_IPV4_DSCP: /* OpenFlow 1.0 only supports IPv4. */ - if (ctx->flow.dl_type == htons(ETH_TYPE_IP)) { - ctx->flow.nw_tos &= ~IP_DSCP_MASK; - ctx->flow.nw_tos |= ofpact_get_SET_IPV4_DSCP(a)->dscp; + if (ctx->xin->flow.dl_type == htons(ETH_TYPE_IP)) { + ctx->xin->flow.nw_tos &= ~IP_DSCP_MASK; + ctx->xin->flow.nw_tos |= ofpact_get_SET_IPV4_DSCP(a)->dscp; } break; case OFPACT_SET_L4_SRC_PORT: - if (is_ip_any(&ctx->flow)) { - ctx->flow.tp_src = htons(ofpact_get_SET_L4_SRC_PORT(a)->port); + if (is_ip_any(&ctx->xin->flow)) { + ctx->xin->flow.tp_src = + htons(ofpact_get_SET_L4_SRC_PORT(a)->port); } break; case OFPACT_SET_L4_DST_PORT: - if (is_ip_any(&ctx->flow)) { - ctx->flow.tp_dst = htons(ofpact_get_SET_L4_DST_PORT(a)->port); + if (is_ip_any(&ctx->xin->flow)) { + ctx->xin->flow.tp_dst = + htons(ofpact_get_SET_L4_DST_PORT(a)->port); } break; @@ -6696,7 +6699,8 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_SET_TUNNEL: - ctx->flow.tunnel.tun_id = htonll(ofpact_get_SET_TUNNEL(a)->tun_id); + ctx->xin->flow.tunnel.tun_id = + htonll(ofpact_get_SET_TUNNEL(a)->tun_id); break; case OFPACT_SET_QUEUE: @@ -6704,24 +6708,24 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_POP_QUEUE: - ctx->flow.skb_priority = ctx->orig_skb_priority; + ctx->xin->flow.skb_priority = ctx->orig_skb_priority; break; case OFPACT_REG_MOVE: - nxm_execute_reg_move(ofpact_get_REG_MOVE(a), &ctx->flow); + nxm_execute_reg_move(ofpact_get_REG_MOVE(a), &ctx->xin->flow); break; case OFPACT_REG_LOAD: - nxm_execute_reg_load(ofpact_get_REG_LOAD(a), &ctx->flow); + nxm_execute_reg_load(ofpact_get_REG_LOAD(a), &ctx->xin->flow); break; case OFPACT_STACK_PUSH: - nxm_execute_stack_push(ofpact_get_STACK_PUSH(a), &ctx->flow, + nxm_execute_stack_push(ofpact_get_STACK_PUSH(a), &ctx->xin->flow, &ctx->stack); break; case OFPACT_STACK_POP: - nxm_execute_stack_pop(ofpact_get_STACK_POP(a), &ctx->flow, + nxm_execute_stack_pop(ofpact_get_STACK_POP(a), &ctx->xin->flow, &ctx->stack); break; @@ -6734,7 +6738,8 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_SET_MPLS_TTL: - if (execute_set_mpls_ttl_action(ctx, ofpact_get_SET_MPLS_TTL(a)->ttl)) { + if (execute_set_mpls_ttl_action(ctx, + ofpact_get_SET_MPLS_TTL(a)->ttl)) { goto out; } break; @@ -6756,7 +6761,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_MULTIPATH: - multipath_execute(ofpact_get_MULTIPATH(a), &ctx->flow); + multipath_execute(ofpact_get_MULTIPATH(a), &ctx->xin->flow); break; case OFPACT_BUNDLE: @@ -6769,8 +6774,8 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_LEARN: - ctx->has_learn = true; - if (ctx->may_learn) { + ctx->xout->has_learn = true; + if (ctx->xin->may_learn) { xlate_learn_action(ctx, ofpact_get_LEARN(a)); } break; @@ -6780,7 +6785,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_FIN_TIMEOUT: - ctx->has_fin_timeout = true; + ctx->xout->has_fin_timeout = true; xlate_fin_timeout(ctx, ofpact_get_FIN_TIMEOUT(a)); break; @@ -6794,8 +6799,8 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, case OFPACT_WRITE_METADATA: metadata = ofpact_get_WRITE_METADATA(a); - ctx->flow.metadata &= ~metadata->mask; - ctx->flow.metadata |= metadata->metadata & metadata->mask; + ctx->xin->flow.metadata &= ~metadata->mask; + ctx->xin->flow.metadata |= metadata->metadata & metadata->mask; break; case OFPACT_GOTO_TABLE: { @@ -6808,7 +6813,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, ctx->table_id = ogt->table_id; /* Look up a flow from the new table. */ - rule = rule_dpif_lookup__(ctx->ofproto, &ctx->flow, ctx->table_id); + rule = rule_dpif_lookup__(ctx->ofproto, &ctx->xin->flow, ctx->table_id); tag_the_flow(ctx, rule); @@ -6843,12 +6848,58 @@ out: } static void -xlate_ctx_init(struct xlate_ctx *ctx, struct ofproto_dpif *ofproto, - const struct flow *flow, - const struct initial_vals *initial_vals, - struct rule_dpif *rule, uint8_t tcp_flags, - const struct ofpbuf *packet) +xlate_in_init(struct xlate_in *xin, struct ofproto_dpif *ofproto, + const struct flow *flow, + const struct initial_vals *initial_vals, + struct rule_dpif *rule, uint8_t tcp_flags, + const struct ofpbuf *packet) +{ + xin->ofproto = ofproto; + xin->flow = *flow; + xin->packet = packet; + xin->may_learn = packet != NULL; + xin->rule = rule; + xin->ofpacts = NULL; + xin->ofpacts_len = 0; + xin->tcp_flags = tcp_flags; + xin->resubmit_hook = NULL; + xin->report_hook = NULL; + xin->resubmit_stats = NULL; + + if (initial_vals) { + xin->initial_vals = *initial_vals; + } else { + xin->initial_vals.vlan_tci = xin->flow.vlan_tci; + } +} + +static void +xlate_out_uninit(struct xlate_out *xout) { + if (xout) { + ofpbuf_uninit(&xout->odp_actions); + } +} + +/* Translates the 'ofpacts_len' bytes of "struct ofpacts" starting at 'ofpacts' + * into datapath actions in 'odp_actions', using 'ctx'. */ +static void +xlate_actions(struct xlate_in *xin, struct xlate_out *xout) +{ + /* Normally false. Set to true if we ever hit MAX_RESUBMIT_RECURSION, so + * that in the future we always keep a copy of the original flow for + * tracing purposes. */ + static bool hit_resubmit_limit; + + enum slow_path_reason special; + const struct ofpact *ofpacts; + struct ofport_dpif *in_port; + struct flow orig_flow; + struct xlate_ctx ctx; + size_t ofpacts_len; + + COVERAGE_INC(ofproto_dpif_xlate); + /* Flow initialization rules: * - 'base_flow' must match the kernel's view of the packet at the * time that action processing starts. 'flow' represents any @@ -6870,73 +6921,59 @@ xlate_ctx_init(struct xlate_ctx *ctx, struct ofproto_dpif *ofproto, * kernel does. If we wish to maintain the original values an action * needs to be generated. */ - ctx->ofproto = ofproto; - ctx->flow = *flow; - ctx->base_flow = ctx->flow; - memset(&ctx->base_flow.tunnel, 0, sizeof ctx->base_flow.tunnel); - ctx->orig_tunnel_ip_dst = flow->tunnel.ip_dst; - ctx->rule = rule; - ctx->packet = packet; - ctx->may_learn = packet != NULL; - ctx->tcp_flags = tcp_flags; - ctx->resubmit_hook = NULL; - ctx->report_hook = NULL; - ctx->resubmit_stats = NULL; - - if (initial_vals) { - ctx->base_flow.vlan_tci = initial_vals->vlan_tci; + 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(); } -} -/* Translates the 'ofpacts_len' bytes of "struct ofpacts" starting at 'ofpacts' - * into datapath actions in 'odp_actions', using 'ctx'. */ -static void -xlate_actions(struct xlate_ctx *ctx, - const struct ofpact *ofpacts, size_t ofpacts_len, - struct ofpbuf *odp_actions) -{ - /* Normally false. Set to true if we ever hit MAX_RESUBMIT_RECURSION, so - * that in the future we always keep a copy of the original flow for - * tracing purposes. */ - static bool hit_resubmit_limit; + ofpbuf_use_stub(&ctx.stack, ctx.init_stack, sizeof ctx.init_stack); - enum slow_path_reason special; - struct ofport_dpif *in_port; - struct flow orig_flow; - - COVERAGE_INC(ofproto_dpif_xlate); - - 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) { + if (ctx.ofproto->has_mirrors || hit_resubmit_limit) { /* Do this conditionally because the copy is expensive enough that it * shows up in profiles. */ - orig_flow = ctx->flow; + orig_flow = ctx.xin->flow; } - if (ctx->flow.nw_frag & FLOW_NW_FRAG_ANY) { - switch (ctx->ofproto->up.frag_handling) { + if (ctx.xin->flow.nw_frag & FLOW_NW_FRAG_ANY) { + switch (ctx.ofproto->up.frag_handling) { case OFPC_FRAG_NORMAL: /* We must pretend that transport ports are unavailable. */ - ctx->flow.tp_src = ctx->base_flow.tp_src = htons(0); - ctx->flow.tp_dst = ctx->base_flow.tp_dst = htons(0); + ctx.xin->flow.tp_src = ctx.base_flow.tp_src = htons(0); + ctx.xin->flow.tp_dst = ctx.base_flow.tp_dst = htons(0); break; case OFPC_FRAG_DROP: @@ -6954,33 +6991,34 @@ xlate_actions(struct xlate_ctx *ctx, } } - in_port = get_ofp_port(ctx->ofproto, ctx->flow.in_port); - special = process_special(ctx->ofproto, &ctx->flow, in_port, ctx->packet); + in_port = get_ofp_port(ctx.ofproto, ctx.xin->flow.in_port); + special = process_special(ctx.ofproto, &ctx.xin->flow, in_port, + ctx.xin->packet); if (special) { - ctx->slow = special; + ctx.xout->slow = special; } else { static struct vlog_rate_limit trace_rl = VLOG_RATE_LIMIT_INIT(1, 1); struct initial_vals initial_vals; size_t sample_actions_len; uint32_t local_odp_port; - initial_vals.vlan_tci = ctx->base_flow.vlan_tci; + initial_vals.vlan_tci = ctx.base_flow.vlan_tci; - add_sflow_action(ctx); - add_ipfix_action(ctx); - sample_actions_len = ctx->odp_actions->size; + add_sflow_action(&ctx); + add_ipfix_action(&ctx); + sample_actions_len = ctx.xout->odp_actions.size; - if (tunnel_ecn_ok(ctx) && (!in_port || may_receive(in_port, ctx))) { - do_xlate_actions(ofpacts, ofpacts_len, ctx); + if (tunnel_ecn_ok(&ctx) && (!in_port || may_receive(in_port, &ctx))) { + do_xlate_actions(ofpacts, ofpacts_len, &ctx); /* We've let OFPP_NORMAL and the learning action look at the * packet, so drop it now if forwarding is disabled. */ if (in_port && !stp_forward_in_state(in_port->stp_state)) { - ctx->odp_actions->size = sample_actions_len; + ctx.xout->odp_actions.size = sample_actions_len; } } - if (ctx->max_resubmit_trigger && !ctx->resubmit_hook) { + if (ctx.max_resubmit_trigger && !ctx.xin->resubmit_hook) { if (!hit_resubmit_limit) { /* We didn't record the original flow. Make sure we do from * now on. */ @@ -6988,7 +7026,7 @@ xlate_actions(struct xlate_ctx *ctx, } else if (!VLOG_DROP_ERR(&trace_rl)) { struct ds ds = DS_EMPTY_INITIALIZER; - ofproto_trace(ctx->ofproto, &orig_flow, ctx->packet, + ofproto_trace(ctx.ofproto, &orig_flow, ctx.xin->packet, &initial_vals, &ds); VLOG_ERR("Trace triggered by excessive resubmit " "recursion:\n%s", ds_cstr(&ds)); @@ -6996,42 +7034,38 @@ xlate_actions(struct xlate_ctx *ctx, } } - local_odp_port = ofp_port_to_odp_port(ctx->ofproto, OFPP_LOCAL); - if (!connmgr_must_output_local(ctx->ofproto->up.connmgr, &ctx->flow, + local_odp_port = ofp_port_to_odp_port(ctx.ofproto, OFPP_LOCAL); + if (!connmgr_must_output_local(ctx.ofproto->up.connmgr, &ctx.xin->flow, local_odp_port, - ctx->odp_actions->data, - ctx->odp_actions->size)) { - compose_output_action(ctx, OFPP_LOCAL); + ctx.xout->odp_actions.data, + ctx.xout->odp_actions.size)) { + compose_output_action(&ctx, OFPP_LOCAL); } - if (ctx->ofproto->has_mirrors) { - add_mirror_actions(ctx, &orig_flow); + if (ctx.ofproto->has_mirrors) { + add_mirror_actions(&ctx, &orig_flow); } - fix_sflow_action(ctx); + fix_sflow_action(&ctx); } - ofpbuf_uninit(&ctx->stack); + ofpbuf_uninit(&ctx.stack); } /* Translates the 'ofpacts_len' bytes of "struct ofpact"s starting at 'ofpacts' * into datapath actions, using 'ctx', and discards the datapath actions. */ static void -xlate_actions_for_side_effects(struct xlate_ctx *ctx, - const struct ofpact *ofpacts, - size_t ofpacts_len) +xlate_actions_for_side_effects(struct xlate_in *xin) { - uint64_t odp_actions_stub[1024 / 8]; - struct ofpbuf odp_actions; + struct xlate_out xout; - ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub); - xlate_actions(ctx, ofpacts, ofpacts_len, &odp_actions); - ofpbuf_uninit(&odp_actions); + xlate_actions(xin, &xout); + xlate_out_uninit(&xout); } static void xlate_report(struct xlate_ctx *ctx, const char *s) { - if (ctx->report_hook) { - ctx->report_hook(ctx, s); + if (ctx->xin->report_hook) { + ctx->xin->report_hook(ctx, s); } } @@ -7160,26 +7194,26 @@ output_normal(struct xlate_ctx *ctx, const struct ofbundle *out_bundle, if (!out_bundle->bond) { port = ofbundle_get_a_port(out_bundle); } else { - port = bond_choose_output_slave(out_bundle->bond, &ctx->flow, - vid, &ctx->tags); + port = bond_choose_output_slave(out_bundle->bond, &ctx->xin->flow, + vid, &ctx->xout->tags); if (!port) { /* No slaves enabled, so drop packet. */ return; } } - old_tci = ctx->flow.vlan_tci; + old_tci = ctx->xin->flow.vlan_tci; tci = htons(vid); if (tci || out_bundle->use_priority_tags) { - tci |= ctx->flow.vlan_tci & htons(VLAN_PCP_MASK); + tci |= ctx->xin->flow.vlan_tci & htons(VLAN_PCP_MASK); if (tci) { tci |= htons(VLAN_CFI); } } - ctx->flow.vlan_tci = tci; + ctx->xin->flow.vlan_tci = tci; compose_output_action(ctx, port->up.ofp_port); - ctx->flow.vlan_tci = old_tci; + ctx->xin->flow.vlan_tci = old_tci; } static int @@ -7228,7 +7262,7 @@ add_mirror_actions(struct xlate_ctx *ctx, const struct flow *orig_flow) size_t left; in_bundle = lookup_input_bundle(ctx->ofproto, orig_flow->in_port, - ctx->packet != NULL, NULL); + ctx->xin->packet != NULL, NULL); if (!in_bundle) { return; } @@ -7236,7 +7270,7 @@ add_mirror_actions(struct xlate_ctx *ctx, const struct flow *orig_flow) /* Drop frames on bundles reserved for mirroring. */ if (in_bundle->mirror_out) { - if (ctx->packet != NULL) { + 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", @@ -7247,15 +7281,15 @@ add_mirror_actions(struct xlate_ctx *ctx, const struct flow *orig_flow) /* Check VLAN. */ vid = vlan_tci_to_vid(orig_flow->vlan_tci); - if (!input_vid_is_valid(vid, in_bundle, ctx->packet != NULL)) { + if (!input_vid_is_valid(vid, in_bundle, ctx->xin->packet != NULL)) { return; } vlan = input_vid_to_vlan(in_bundle, vid); /* Look at the output ports to check for destination selections. */ - NL_ATTR_FOR_EACH (a, left, ctx->odp_actions->data, - ctx->odp_actions->size) { + NL_ATTR_FOR_EACH (a, left, ctx->xout->odp_actions.data, + ctx->xout->odp_actions.size) { enum ovs_action_attr type = nl_attr_type(a); struct ofport_dpif *ofport; @@ -7274,7 +7308,7 @@ add_mirror_actions(struct xlate_ctx *ctx, const struct flow *orig_flow) } /* Restore the original packet before adding the mirror actions. */ - ctx->flow = *orig_flow; + ctx->xin->flow = *orig_flow; while (mirrors) { struct ofmirror *m; @@ -7287,7 +7321,7 @@ add_mirror_actions(struct xlate_ctx *ctx, const struct flow *orig_flow) } mirrors &= ~m->dup_mirrors; - ctx->mirrors |= m->dup_mirrors; + ctx->xout->mirrors |= m->dup_mirrors; if (m->out) { output_normal(ctx, m->out, vlan); } else if (vlan != m->out_vlan @@ -7449,7 +7483,7 @@ is_admissible(struct xlate_ctx *ctx, struct ofport_dpif *in_port, uint16_t vlan) { struct ofproto_dpif *ofproto = ctx->ofproto; - struct flow *flow = &ctx->flow; + struct flow *flow = &ctx->xin->flow; struct ofbundle *in_bundle = in_port->bundle; /* Drop frames for reserved multicast addresses @@ -7463,7 +7497,7 @@ is_admissible(struct xlate_ctx *ctx, struct ofport_dpif *in_port, struct mac_entry *mac; switch (bond_check_admissibility(in_bundle->bond, in_port, - flow->dl_dst, &ctx->tags)) { + flow->dl_dst, &ctx->xout->tags)) { case BV_ACCEPT: break; @@ -7496,19 +7530,19 @@ xlate_normal(struct xlate_ctx *ctx) uint16_t vlan; uint16_t vid; - ctx->has_normal = true; + ctx->xout->has_normal = true; - in_bundle = lookup_input_bundle(ctx->ofproto, ctx->flow.in_port, - ctx->packet != NULL, &in_port); + in_bundle = lookup_input_bundle(ctx->ofproto, ctx->xin->flow.in_port, + ctx->xin->packet != NULL, &in_port); if (!in_bundle) { xlate_report(ctx, "no input bundle, dropping"); return; } /* Drop malformed frames. */ - if (ctx->flow.dl_type == htons(ETH_TYPE_VLAN) && - !(ctx->flow.vlan_tci & htons(VLAN_CFI))) { - if (ctx->packet != NULL) { + if (ctx->xin->flow.dl_type == htons(ETH_TYPE_VLAN) && + !(ctx->xin->flow.vlan_tci & htons(VLAN_CFI))) { + 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 with partial " "VLAN tag received on port %s", @@ -7520,7 +7554,7 @@ xlate_normal(struct xlate_ctx *ctx) /* Drop frames on bundles reserved for mirroring. */ if (in_bundle->mirror_out) { - if (ctx->packet != NULL) { + 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", @@ -7531,8 +7565,8 @@ xlate_normal(struct xlate_ctx *ctx) } /* Check VLAN. */ - vid = vlan_tci_to_vid(ctx->flow.vlan_tci); - if (!input_vid_is_valid(vid, in_bundle, ctx->packet != NULL)) { + vid = vlan_tci_to_vid(ctx->xin->flow.vlan_tci); + if (!input_vid_is_valid(vid, in_bundle, ctx->xin->packet != NULL)) { xlate_report(ctx, "disallowed VLAN VID for this input port, dropping"); return; } @@ -7544,13 +7578,13 @@ xlate_normal(struct xlate_ctx *ctx) } /* Learn source MAC. */ - if (ctx->may_learn) { - update_learning_table(ctx->ofproto, &ctx->flow, vlan, in_bundle); + if (ctx->xin->may_learn) { + update_learning_table(ctx->ofproto, &ctx->xin->flow, vlan, in_bundle); } /* Determine output bundle. */ - mac = mac_learning_lookup(ctx->ofproto->ml, ctx->flow.dl_dst, vlan, - &ctx->tags); + mac = mac_learning_lookup(ctx->ofproto->ml, ctx->xin->flow.dl_dst, vlan, + &ctx->xout->tags); if (mac) { if (mac->port.p != in_bundle) { xlate_report(ctx, "forwarding to learned port"); @@ -7570,7 +7604,7 @@ xlate_normal(struct xlate_ctx *ctx) output_normal(ctx, bundle, vlan); } } - ctx->nf_output_iface = NF_OUT_FLOOD; + ctx->xout->nf_output_iface = NF_OUT_FLOOD; } } @@ -7709,12 +7743,10 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet, struct initial_vals initial_vals; struct odputil_keybuf keybuf; struct dpif_flow_stats stats; - + struct xlate_out xout; + struct xlate_in xin; struct ofpbuf key; - struct xlate_ctx ctx; - uint64_t odp_actions_stub[1024 / 8]; - struct ofpbuf odp_actions; ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); odp_flow_key_from_flow(&key, flow, @@ -7723,16 +7755,16 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet, dpif_flow_stats_extract(flow, packet, time_msec(), &stats); initial_vals.vlan_tci = flow->vlan_tci; - xlate_ctx_init(&ctx, ofproto, flow, &initial_vals, NULL, - packet_get_tcp_flags(packet, flow), packet); - ctx.resubmit_stats = &stats; + xlate_in_init(&xin, ofproto, flow, &initial_vals, NULL, stats.tcp_flags, + packet); + xin.resubmit_stats = &stats; + xin.ofpacts_len = ofpacts_len; + xin.ofpacts = ofpacts; - ofpbuf_use_stub(&odp_actions, - odp_actions_stub, sizeof odp_actions_stub); - xlate_actions(&ctx, ofpacts, ofpacts_len, &odp_actions); + xlate_actions(&xin, &xout); dpif_execute(ofproto->backer->dpif, key.data, key.size, - odp_actions.data, odp_actions.size, packet); - ofpbuf_uninit(&odp_actions); + xout.odp_actions.data, xout.odp_actions.size, packet); + xlate_out_uninit(&xout); return 0; } @@ -7778,7 +7810,7 @@ send_active_timeout(struct ofproto_dpif *ofproto, struct facet *facet) if (subfacet->path == SF_FAST_PATH) { struct dpif_flow_stats stats; - subfacet_install(subfacet, &facet->odp_actions, &stats); + subfacet_install(subfacet, &facet->xout.odp_actions, &stats); subfacet_update_stats(subfacet, &stats); } } @@ -7864,7 +7896,8 @@ ofproto_unixctl_fdb_show(struct unixctl_conn *conn, int argc OVS_UNUSED, } struct trace_ctx { - struct xlate_ctx ctx; + struct xlate_out xout; + struct xlate_in xin; struct flow flow; struct ds *result; }; @@ -7892,15 +7925,15 @@ trace_format_rule(struct ds *result, uint8_t table_id, int level, static void trace_format_flow(struct ds *result, int level, const char *title, - struct trace_ctx *trace) + struct trace_ctx *trace) { ds_put_char_multiple(result, '\t', level); ds_put_format(result, "%s: ", title); - if (flow_equal(&trace->ctx.flow, &trace->flow)) { + if (flow_equal(&trace->xin.flow, &trace->flow)) { ds_put_cstr(result, "unchanged"); } else { - flow_format(result, &trace->ctx.flow); - trace->flow = trace->ctx.flow; + flow_format(result, &trace->xin.flow); + trace->flow = trace->xin.flow; } ds_put_char(result, '\n'); } @@ -7923,7 +7956,7 @@ static void trace_format_odp(struct ds *result, int level, const char *title, struct trace_ctx *trace) { - struct ofpbuf *odp_actions = trace->ctx.odp_actions; + struct ofpbuf *odp_actions = &trace->xout.odp_actions; ds_put_char_multiple(result, '\t', level); ds_put_format(result, "%s: ", title); @@ -7934,7 +7967,7 @@ trace_format_odp(struct ds *result, int level, const char *title, static void trace_resubmit(struct xlate_ctx *ctx, struct rule_dpif *rule) { - struct trace_ctx *trace = CONTAINER_OF(ctx, struct trace_ctx, ctx); + struct trace_ctx *trace = CONTAINER_OF(ctx->xin, struct trace_ctx, xin); struct ds *result = trace->result; ds_put_char(result, '\n'); @@ -7947,7 +7980,7 @@ trace_resubmit(struct xlate_ctx *ctx, struct rule_dpif *rule) static void trace_report(struct xlate_ctx *ctx, const char *s) { - struct trace_ctx *trace = CONTAINER_OF(ctx, struct trace_ctx, ctx); + struct trace_ctx *trace = CONTAINER_OF(ctx->xin, struct trace_ctx, xin); struct ds *result = trace->result; ds_put_char_multiple(result, '\t', ctx->recurse); @@ -8107,23 +8140,22 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow, trace.flow = *flow; ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub); - xlate_ctx_init(&trace.ctx, ofproto, flow, initial_vals, rule, - tcp_flags, packet); - trace.ctx.resubmit_hook = trace_resubmit; - trace.ctx.report_hook = trace_report; - xlate_actions(&trace.ctx, rule->up.ofpacts, rule->up.ofpacts_len, - &odp_actions); + xlate_in_init(&trace.xin, ofproto, flow, initial_vals, rule, tcp_flags, + packet); + trace.xin.resubmit_hook = trace_resubmit; + trace.xin.report_hook = trace_report; + xlate_actions(&trace.xin, &trace.xout); ds_put_char(ds, '\n'); trace_format_flow(ds, 0, "Final flow", &trace); ds_put_cstr(ds, "Datapath actions: "); - format_odp_actions(ds, odp_actions.data, odp_actions.size); - ofpbuf_uninit(&odp_actions); + format_odp_actions(ds, trace.xout.odp_actions.data, + trace.xout.odp_actions.size); - if (trace.ctx.slow) { + if (trace.xout.slow) { ds_put_cstr(ds, "\nThis flow is handled by the userspace " "slow path because it:"); - switch (trace.ctx.slow) { + switch (trace.xout.slow) { case SLOW_CFM: ds_put_cstr(ds, "\n\t- Consists of CFM packets."); break; @@ -8144,6 +8176,8 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow, NOT_REACHED(); } } + + xlate_out_uninit(&trace.xout); } } @@ -8421,18 +8455,18 @@ ofproto_unixctl_dpif_dump_flows(struct unixctl_conn *conn, } ds_put_cstr(&ds, ", actions:"); - if (facet->slow) { + if (facet->xout.slow) { uint64_t slow_path_stub[128 / 8]; const struct nlattr *actions; size_t actions_len; - compose_slow_path(ofproto, &facet->flow, facet->slow, + compose_slow_path(ofproto, &facet->flow, facet->xout.slow, slow_path_stub, sizeof slow_path_stub, &actions, &actions_len); format_odp_actions(&ds, actions, actions_len); } else { - format_odp_actions(&ds, facet->odp_actions.data, - facet->odp_actions.size); + format_odp_actions(&ds, facet->xout.odp_actions.data, + facet->xout.odp_actions.size); } ds_put_char(&ds, '\n'); }