Remove recursion from GOTO_TABLE processing in do_xlate_actions(). This allows packet processing pipelines built with goto table be longer and not interact with each other via the resubmit recursion limit.
Signed-off-by: Jarno Rajahalme <jarno.rajaha...@nsn.com> --- ofproto/ofproto-dpif.c | 112 +++++++++++++++++++++++++++++++----------------- tests/ofproto-dpif.at | 14 ++++++ 2 files changed, 87 insertions(+), 39 deletions(-) diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 89f5bf4..f720095 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -5816,61 +5816,73 @@ compose_output_action(struct action_xlate_ctx *ctx, uint16_t ofp_port) } static void +tag_the_flow(struct action_xlate_ctx *ctx, struct rule_dpif *rule) +{ + struct ofproto_dpif *ofproto = ctx->ofproto; + uint8_t table_id = ctx->table_id; + + 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)); + } + } +} + +/* Common rule processing in one place to avoid duplicating code. */ +static struct rule_dpif * +ctx_rule_hooks(struct action_xlate_ctx *ctx, struct rule_dpif *rule, + bool may_packet_in) +{ + if (ctx->resubmit_hook) { + ctx->resubmit_hook(ctx, rule); + } + if (rule == NULL && may_packet_in) { + /* XXX + * check if table configuration flags + * OFPTC_TABLE_MISS_CONTROLLER, default. + * OFPTC_TABLE_MISS_CONTINUE, + * 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); + } + if (rule && ctx->resubmit_stats) { + rule_credit_stats(rule, ctx->resubmit_stats); + } + return rule; +} + +static void xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port, uint8_t table_id, bool may_packet_in) { if (ctx->recurse < MAX_RESUBMIT_RECURSION) { - struct ofproto_dpif *ofproto = ctx->ofproto; struct rule_dpif *rule; - uint16_t old_in_port; - uint8_t old_table_id; + uint16_t old_in_port = ctx->flow.in_port; + uint8_t old_table_id = ctx->table_id; - old_table_id = ctx->table_id; ctx->table_id = table_id; /* Look up a flow with 'in_port' as the input port. */ - old_in_port = ctx->flow.in_port; ctx->flow.in_port = in_port; - rule = rule_dpif_lookup__(ofproto, &ctx->flow, table_id); - - /* Tag the flow. */ - 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)); - } - } + rule = rule_dpif_lookup__(ctx->ofproto, &ctx->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; - if (ctx->resubmit_hook) { - ctx->resubmit_hook(ctx, rule); - } - - if (rule == NULL && may_packet_in) { - /* XXX - * check if table configuration flags - * OFPTC_TABLE_MISS_CONTROLLER, default. - * OFPTC_TABLE_MISS_CONTINUE, - * OFPTC_TABLE_MISS_DROP - * When OF1.0, OFPTC_TABLE_MISS_CONTINUE is used. What to do? - */ - rule = rule_dpif_miss_rule(ofproto, &ctx->flow); - } + rule = ctx_rule_hooks(ctx, rule, may_packet_in); if (rule) { struct rule_dpif *old_rule = ctx->rule; - if (ctx->resubmit_stats) { - rule_credit_stats(rule, ctx->resubmit_stats); - } - ctx->recurse++; ctx->rule = rule; do_xlate_actions(rule->up.ofpacts, rule->up.ofpacts_len, ctx); @@ -6341,12 +6353,15 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, { bool was_evictable = true; const struct ofpact *a; + struct rule_dpif *orig_rule = ctx->rule; if (ctx->rule) { /* Don't let the rule we're working on get evicted underneath us. */ was_evictable = ctx->rule->up.evictable; ctx->rule->up.evictable = false; } + + do_xlate_actions_again: OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { struct ofpact_controller *controller; const struct ofpact_metadata *metadata; @@ -6536,17 +6551,36 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_GOTO_TABLE: { - /* XXX remove recursion */ - /* It is assumed that goto-table is last action */ + /* It is assumed that goto-table is the last action. */ struct ofpact_goto_table *ogt = ofpact_get_GOTO_TABLE(a); + struct rule_dpif *rule; + ovs_assert(ctx->table_id < ogt->table_id); - xlate_table_action(ctx, ctx->flow.in_port, ogt->table_id, true); + + 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); + + tag_the_flow(ctx, rule); + + rule = ctx_rule_hooks(ctx, rule, true); + + if (rule) { + ctx->rule = rule; + + /* Tail recursion removal. */ + ofpacts = rule->up.ofpacts; + ofpacts_len = rule->up.ofpacts_len; + goto do_xlate_actions_again; + } break; } } } out: + ctx->rule = orig_rule; if (ctx->rule) { ctx->rule->up.evictable = was_evictable; } diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 7915792..dcde4ea 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -20,6 +20,20 @@ AT_CHECK([tail -1 stdout], [0], OVS_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([ofproto-dpif - goto table]) +OVS_VSWITCHD_START +ADD_OF_PORTS([br0], [1], [10], [11]) +echo "table=0 in_port=1 actions=output(10),goto_table(1)" > flows.txt +for i in `seq 1 252`; do echo "table=$i actions=goto_table($(($i+1)))"; done >> flows.txt +echo "table=253 actions=output(11)" >> flows.txt +AT_CHECK([ovs-ofctl -O OpenFlow12 add-flows br0 flows.txt]) +AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0'], [0], [stdout]) +AT_CHECK([tail -1 stdout], [0], + [Datapath actions: 10,11 +]) +OVS_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([ofproto-dpif - registers]) OVS_VSWITCHD_START ADD_OF_PORTS([br0], [20], [21], [22], [33], [90]) -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev