diff options
Diffstat (limited to 'ofproto')
-rw-r--r-- | ofproto/ofproto-dpif-xlate.c | 214 |
1 files changed, 133 insertions, 81 deletions
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 223313d4e..9e39a4ff7 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -507,11 +507,12 @@ static struct xlate_cfg *new_xcfg = NULL; static bool may_receive(const struct xport *, struct xlate_ctx *); static void do_xlate_actions(const struct ofpact *, size_t ofpacts_len, - struct xlate_ctx *); + struct xlate_ctx *, bool); static void xlate_normal(struct xlate_ctx *); static void xlate_table_action(struct xlate_ctx *, ofp_port_t in_port, uint8_t table_id, bool may_packet_in, - bool honor_table_miss, bool with_ct_orig); + bool honor_table_miss, bool with_ct_orig, + bool is_last_action); static bool input_vid_is_valid(const struct xlate_ctx *, uint16_t vid, struct xbundle *); static void xvlan_copy(struct xvlan *dst, const struct xvlan *src); @@ -536,7 +537,8 @@ struct xlate_bond_recirc { }; static void compose_output_action(struct xlate_ctx *, ofp_port_t ofp_port, - const struct xlate_bond_recirc *xr); + const struct xlate_bond_recirc *xr, + bool is_last_action); static struct xbridge *xbridge_lookup(struct xlate_cfg *, const struct ofproto_dpif *); @@ -2218,7 +2220,8 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle, memcpy(&old_vlans, &ctx->xin->flow.vlans, sizeof(old_vlans)); xvlan_put(&ctx->xin->flow, &out_xvlan); - compose_output_action(ctx, xport->ofp_port, use_recirc ? &xr : NULL); + compose_output_action(ctx, xport->ofp_port, use_recirc ? &xr : NULL, + false); memcpy(&ctx->xin->flow.vlans, &old_vlans, sizeof(old_vlans)); } @@ -3557,7 +3560,7 @@ apply_nested_clone_actions(struct xlate_ctx *ctx, const struct xport *in_dev, if (xport_stp_forward_state(out_dev) && xport_rstp_forward_state(out_dev)) { xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true, - false); + false, true); if (!ctx->freezing) { xlate_action_set(ctx); } @@ -3572,7 +3575,7 @@ apply_nested_clone_actions(struct xlate_ctx *ctx, const struct xport *in_dev, mirror_mask_t old_mirrors2 = ctx->mirrors; xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true, - false); + false, true); ctx->mirrors = old_mirrors2; ctx->base_flow = old_base_flow; ctx->odp_actions->size = old_size; @@ -3716,7 +3719,8 @@ terminate_native_tunnel(struct xlate_ctx *ctx, ofp_port_t ofp_port, static void compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, - const struct xlate_bond_recirc *xr, bool check_stp) + const struct xlate_bond_recirc *xr, bool check_stp, + bool is_last_action OVS_UNUSED) { const struct xport *xport = get_ofp_port(ctx->xbridge, ofp_port); struct flow_wildcards *wc = ctx->wc; @@ -3882,13 +3886,15 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, static void compose_output_action(struct xlate_ctx *ctx, ofp_port_t ofp_port, - const struct xlate_bond_recirc *xr) + const struct xlate_bond_recirc *xr, + bool is_last_action) { - compose_output_action__(ctx, ofp_port, xr, true); + compose_output_action__(ctx, ofp_port, xr, true, is_last_action); } static void -xlate_recursively(struct xlate_ctx *ctx, struct rule_dpif *rule, bool deepens) +xlate_recursively(struct xlate_ctx *ctx, struct rule_dpif *rule, + bool deepens, bool is_last_action) { struct rule_dpif *old_rule = ctx->rule; ovs_be64 old_cookie = ctx->rule_cookie; @@ -3904,7 +3910,8 @@ xlate_recursively(struct xlate_ctx *ctx, struct rule_dpif *rule, bool deepens) ctx->rule = rule; ctx->rule_cookie = rule->up.flow_cookie; actions = rule_get_actions(&rule->up); - do_xlate_actions(actions->ofpacts, actions->ofpacts_len, ctx); + do_xlate_actions(actions->ofpacts, actions->ofpacts_len, ctx, + is_last_action); ctx->rule_cookie = old_cookie; ctx->rule = old_rule; ctx->depth -= deepens; @@ -3979,7 +3986,7 @@ tuple_swap(struct flow *flow, struct flow_wildcards *wc) static void xlate_table_action(struct xlate_ctx *ctx, ofp_port_t in_port, uint8_t table_id, bool may_packet_in, bool honor_table_miss, - bool with_ct_orig) + bool with_ct_orig, bool is_last_action) { /* Check if we need to recirculate before matching in a table. */ if (ctx->was_mpls) { @@ -4030,7 +4037,8 @@ xlate_table_action(struct xlate_ctx *ctx, ofp_port_t in_port, uint8_t table_id, struct ovs_list *old_trace = ctx->xin->trace; xlate_report_table(ctx, rule, table_id); - xlate_recursively(ctx, rule, table_id <= old_table_id); + xlate_recursively(ctx, rule, table_id <= old_table_id, + is_last_action); ctx->xin->trace = old_trace; } @@ -4057,7 +4065,8 @@ xlate_group_stats(struct xlate_ctx *ctx, struct group_dpif *group, } static void -xlate_group_bucket(struct xlate_ctx *ctx, struct ofputil_bucket *bucket) +xlate_group_bucket(struct xlate_ctx *ctx, struct ofputil_bucket *bucket, + bool is_last_action) { uint64_t action_list_stub[1024 / 8]; struct ofpbuf action_list = OFPBUF_STUB_INITIALIZER(action_list_stub); @@ -4068,7 +4077,7 @@ xlate_group_bucket(struct xlate_ctx *ctx, struct ofputil_bucket *bucket) ofpacts_execute_action_set(&action_list, &action_set); ctx->depth++; - do_xlate_actions(action_list.data, action_list.size, ctx); + do_xlate_actions(action_list.data, action_list.size, ctx, is_last_action); ctx->depth--; ofpbuf_uninit(&action_list); @@ -4106,23 +4115,26 @@ xlate_group_bucket(struct xlate_ctx *ctx, struct ofputil_bucket *bucket) } static void -xlate_all_group(struct xlate_ctx *ctx, struct group_dpif *group) +xlate_all_group(struct xlate_ctx *ctx, struct group_dpif *group, + bool is_last_action) { struct ofputil_bucket *bucket; LIST_FOR_EACH (bucket, list_node, &group->up.buckets) { - xlate_group_bucket(ctx, bucket); + bool last = is_last_action && !bucket->list_node.next; + xlate_group_bucket(ctx, bucket, last); } xlate_group_stats(ctx, group, NULL); } static void -xlate_ff_group(struct xlate_ctx *ctx, struct group_dpif *group) +xlate_ff_group(struct xlate_ctx *ctx, struct group_dpif *group, + bool is_last_action) { struct ofputil_bucket *bucket; bucket = group_first_live_bucket(ctx, group, 0); if (bucket) { - xlate_group_bucket(ctx, bucket); + xlate_group_bucket(ctx, bucket, is_last_action); xlate_group_stats(ctx, group, bucket); } else if (ctx->xin->xcache) { ofproto_group_unref(&group->up); @@ -4130,7 +4142,8 @@ xlate_ff_group(struct xlate_ctx *ctx, struct group_dpif *group) } static void -xlate_default_select_group(struct xlate_ctx *ctx, struct group_dpif *group) +xlate_default_select_group(struct xlate_ctx *ctx, struct group_dpif *group, + bool is_last_action) { struct flow_wildcards *wc = ctx->wc; struct ofputil_bucket *bucket; @@ -4140,7 +4153,7 @@ xlate_default_select_group(struct xlate_ctx *ctx, struct group_dpif *group) flow_mask_hash_fields(&ctx->xin->flow, wc, NX_HASH_FIELDS_SYMMETRIC_L4); bucket = group_best_live_bucket(ctx, group, basis); if (bucket) { - xlate_group_bucket(ctx, bucket); + xlate_group_bucket(ctx, bucket, is_last_action); xlate_group_stats(ctx, group, bucket); } else if (ctx->xin->xcache) { ofproto_group_unref(&group->up); @@ -4148,7 +4161,8 @@ xlate_default_select_group(struct xlate_ctx *ctx, struct group_dpif *group) } static void -xlate_hash_fields_select_group(struct xlate_ctx *ctx, struct group_dpif *group) +xlate_hash_fields_select_group(struct xlate_ctx *ctx, struct group_dpif *group, + bool is_last_action) { const struct field_array *fields = &group->up.props.fields; const uint8_t *mask_values = fields->values; @@ -4186,7 +4200,7 @@ xlate_hash_fields_select_group(struct xlate_ctx *ctx, struct group_dpif *group) struct ofputil_bucket *bucket = group_best_live_bucket(ctx, group, basis); if (bucket) { - xlate_group_bucket(ctx, bucket); + xlate_group_bucket(ctx, bucket, is_last_action); xlate_group_stats(ctx, group, bucket); } else if (ctx->xin->xcache) { ofproto_group_unref(&group->up); @@ -4194,7 +4208,8 @@ xlate_hash_fields_select_group(struct xlate_ctx *ctx, struct group_dpif *group) } static void -xlate_dp_hash_select_group(struct xlate_ctx *ctx, struct group_dpif *group) +xlate_dp_hash_select_group(struct xlate_ctx *ctx, struct group_dpif *group, + bool is_last_action) { struct ofputil_bucket *bucket; @@ -4218,7 +4233,7 @@ xlate_dp_hash_select_group(struct xlate_ctx *ctx, struct group_dpif *group) ctx->wc->masks.dp_hash |= mask; bucket = group_best_live_bucket(ctx, group, basis); if (bucket) { - xlate_group_bucket(ctx, bucket); + xlate_group_bucket(ctx, bucket, is_last_action); xlate_group_stats(ctx, group, bucket); } } @@ -4226,7 +4241,8 @@ xlate_dp_hash_select_group(struct xlate_ctx *ctx, struct group_dpif *group) } static void -xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group) +xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group, + bool is_last_action) { const char *selection_method = group->up.props.selection_method; @@ -4238,11 +4254,11 @@ xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group) } if (selection_method[0] == '\0') { - xlate_default_select_group(ctx, group); + xlate_default_select_group(ctx, group, is_last_action); } else if (!strcasecmp("hash", selection_method)) { - xlate_hash_fields_select_group(ctx, group); + xlate_hash_fields_select_group(ctx, group, is_last_action); } else if (!strcasecmp("dp_hash", selection_method)) { - xlate_dp_hash_select_group(ctx, group); + xlate_dp_hash_select_group(ctx, group, is_last_action); } else { /* Parsing of groups should ensure this never happens */ OVS_NOT_REACHED(); @@ -4250,7 +4266,8 @@ xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group) } static void -xlate_group_action__(struct xlate_ctx *ctx, struct group_dpif *group) +xlate_group_action__(struct xlate_ctx *ctx, struct group_dpif *group, + bool is_last_action) { bool was_in_group = ctx->in_group; ctx->in_group = true; @@ -4258,13 +4275,13 @@ xlate_group_action__(struct xlate_ctx *ctx, struct group_dpif *group) switch (group->up.type) { case OFPGT11_ALL: case OFPGT11_INDIRECT: - xlate_all_group(ctx, group); + xlate_all_group(ctx, group, is_last_action); break; case OFPGT11_SELECT: - xlate_select_group(ctx, group); + xlate_select_group(ctx, group, is_last_action); break; case OFPGT11_FF: - xlate_ff_group(ctx, group); + xlate_ff_group(ctx, group, is_last_action); break; default: OVS_NOT_REACHED(); @@ -4274,7 +4291,8 @@ xlate_group_action__(struct xlate_ctx *ctx, struct group_dpif *group) } static bool -xlate_group_action(struct xlate_ctx *ctx, uint32_t group_id) +xlate_group_action(struct xlate_ctx *ctx, uint32_t group_id, + bool is_last_action) { if (xlate_resubmit_resource_check(ctx)) { struct group_dpif *group; @@ -4288,7 +4306,7 @@ xlate_group_action(struct xlate_ctx *ctx, uint32_t group_id) group_id); return true; } - xlate_group_action__(ctx, group); + xlate_group_action__(ctx, group, is_last_action); } return false; @@ -4296,7 +4314,8 @@ xlate_group_action(struct xlate_ctx *ctx, uint32_t group_id) static void xlate_ofpact_resubmit(struct xlate_ctx *ctx, - const struct ofpact_resubmit *resubmit) + const struct ofpact_resubmit *resubmit, + bool is_last_action) { ofp_port_t in_port; uint8_t table_id; @@ -4321,26 +4340,47 @@ xlate_ofpact_resubmit(struct xlate_ctx *ctx, } xlate_table_action(ctx, in_port, table_id, may_packet_in, - honor_table_miss, resubmit->with_ct_orig); + honor_table_miss, resubmit->with_ct_orig, + is_last_action); } static void -flood_packets(struct xlate_ctx *ctx, bool all) +flood_packet_to_port(struct xlate_ctx *ctx, const struct xport *xport, + bool all, bool is_last_action) { - const struct xport *xport; + if (!xport) { + return; + } + + if (all) { + compose_output_action__(ctx, xport->ofp_port, NULL, false, + is_last_action); + } else { + compose_output_action(ctx, xport->ofp_port, NULL, is_last_action); + } +} + +static void +flood_packets(struct xlate_ctx *ctx, bool all, bool is_last_action) +{ + const struct xport *xport, *last = NULL; + /* Use 'last' the keep track of the last output port. */ HMAP_FOR_EACH (xport, ofp_node, &ctx->xbridge->xports) { if (xport->ofp_port == ctx->xin->flow.in_port.ofp_port) { continue; } - if (all) { - compose_output_action__(ctx, xport->ofp_port, NULL, false); - } else if (!(xport->config & OFPUTIL_PC_NO_FLOOD)) { - compose_output_action(ctx, xport->ofp_port, NULL); + if (all || !(xport->config & OFPUTIL_PC_NO_FLOOD)) { + /* 'last' is not the last port, send a packet out, and + * update 'last'. */ + flood_packet_to_port(ctx, last, all, false); + last = xport; } } + /* Send the packet to the 'last' port. */ + flood_packet_to_port(ctx, last, all, is_last_action); ctx->nf_output_iface = NF_OUT_FLOOD; } @@ -4834,7 +4874,8 @@ compose_dec_mpls_ttl_action(struct xlate_ctx *ctx) static void xlate_output_action(struct xlate_ctx *ctx, - ofp_port_t port, uint16_t max_len, bool may_packet_in) + ofp_port_t port, uint16_t max_len, bool may_packet_in, + bool is_last_action) { ofp_port_t prev_nf_output_iface = ctx->nf_output_iface; @@ -4842,20 +4883,21 @@ xlate_output_action(struct xlate_ctx *ctx, switch (port) { case OFPP_IN_PORT: - compose_output_action(ctx, ctx->xin->flow.in_port.ofp_port, NULL); + compose_output_action(ctx, ctx->xin->flow.in_port.ofp_port, NULL, + is_last_action); break; case OFPP_TABLE: xlate_table_action(ctx, ctx->xin->flow.in_port.ofp_port, - 0, may_packet_in, true, false); + 0, may_packet_in, true, false, is_last_action); break; case OFPP_NORMAL: xlate_normal(ctx); break; case OFPP_FLOOD: - flood_packets(ctx, false); + flood_packets(ctx, false, is_last_action); break; case OFPP_ALL: - flood_packets(ctx, true); + flood_packets(ctx, true, is_last_action); break; case OFPP_CONTROLLER: execute_controller_action(ctx, max_len, @@ -4870,7 +4912,7 @@ xlate_output_action(struct xlate_ctx *ctx, case OFPP_LOCAL: default: if (port != ctx->xin->flow.in_port.ofp_port) { - compose_output_action(ctx, port, NULL); + compose_output_action(ctx, port, NULL, is_last_action); } else { xlate_report(ctx, OFT_WARN, "skipping output to input port"); } @@ -4889,7 +4931,8 @@ xlate_output_action(struct xlate_ctx *ctx, static void xlate_output_reg_action(struct xlate_ctx *ctx, - const struct ofpact_output_reg *or) + const struct ofpact_output_reg *or, + bool is_last_action) { uint64_t port = mf_get_subfield(&or->src, &ctx->xin->flow); if (port <= UINT16_MAX) { @@ -4899,7 +4942,8 @@ xlate_output_reg_action(struct xlate_ctx *ctx, memset(&value, 0xff, sizeof value); mf_write_subfield_flow(&or->src, &value, &ctx->wc->masks); - xlate_output_action(ctx, u16_to_ofp(port), or->max_len, false); + xlate_output_action(ctx, u16_to_ofp(port), or->max_len, false, + is_last_action); } else { xlate_report(ctx, OFT_WARN, "output port %"PRIu64" is out of range", port); @@ -4908,7 +4952,8 @@ xlate_output_reg_action(struct xlate_ctx *ctx, static void xlate_output_trunc_action(struct xlate_ctx *ctx, - ofp_port_t port, uint32_t max_len) + ofp_port_t port, uint32_t max_len, + bool is_last_action) { bool support_trunc = ctx->xbridge->support.trunc; struct ovs_action_trunc *trunc; @@ -4945,7 +4990,7 @@ xlate_output_trunc_action(struct xlate_ctx *ctx, OVS_ACTION_ATTR_TRUNC, sizeof *trunc); trunc->max_len = max_len; - xlate_output_action(ctx, port, max_len, false); + xlate_output_action(ctx, port, max_len, false, is_last_action); if (!support_trunc) { ctx->xout->slow |= SLOW_ACTION; } @@ -4958,7 +5003,8 @@ xlate_output_trunc_action(struct xlate_ctx *ctx, static void xlate_enqueue_action(struct xlate_ctx *ctx, - const struct ofpact_enqueue *enqueue) + const struct ofpact_enqueue *enqueue, + bool is_last_action) { ofp_port_t ofp_port = enqueue->port; uint32_t queue_id = enqueue->queue; @@ -4969,7 +5015,7 @@ xlate_enqueue_action(struct xlate_ctx *ctx, error = dpif_queue_to_priority(ctx->xbridge->dpif, queue_id, &priority); if (error) { /* Fall back to ordinary output action. */ - xlate_output_action(ctx, enqueue->port, 0, false); + xlate_output_action(ctx, enqueue->port, 0, false, is_last_action); return; } @@ -4983,7 +5029,7 @@ xlate_enqueue_action(struct xlate_ctx *ctx, /* Add datapath actions. */ flow_priority = ctx->xin->flow.skb_priority; ctx->xin->flow.skb_priority = priority; - compose_output_action(ctx, ofp_port, NULL); + compose_output_action(ctx, ofp_port, NULL, is_last_action); ctx->xin->flow.skb_priority = flow_priority; /* Update NetFlow output port. */ @@ -5031,7 +5077,8 @@ slave_enabled_cb(ofp_port_t ofp_port, void *xbridge_) static void xlate_bundle_action(struct xlate_ctx *ctx, - const struct ofpact_bundle *bundle) + const struct ofpact_bundle *bundle, + bool is_last_action) { ofp_port_t port; @@ -5041,7 +5088,7 @@ xlate_bundle_action(struct xlate_ctx *ctx, nxm_reg_load(&bundle->dst, ofp_to_u16(port), &ctx->xin->flow, ctx->wc); xlate_report_subfield(ctx, &bundle->dst); } else { - xlate_output_action(ctx, port, 0, false); + xlate_output_action(ctx, port, 0, false, is_last_action); } } @@ -5335,7 +5382,7 @@ reversible_actions(const struct ofpact *ofpacts, size_t ofpacts_len) static void clone_xlate_actions(const struct ofpact *actions, size_t actions_len, - struct xlate_ctx *ctx) + struct xlate_ctx *ctx, bool is_last_action) { struct ofpbuf old_stack = ctx->stack; union mf_subvalue new_stack[1024 / sizeof(union mf_subvalue)]; @@ -5350,9 +5397,9 @@ clone_xlate_actions(const struct ofpact *actions, size_t actions_len, size_t offset, ac_offset; struct flow old_flow = ctx->xin->flow; - if (reversible_actions(actions, actions_len)) { + if (reversible_actions(actions, actions_len) || is_last_action) { old_flow = ctx->xin->flow; - do_xlate_actions(actions, actions_len, ctx); + do_xlate_actions(actions, actions_len, ctx, is_last_action); if (ctx->freezing) { finish_freezing(ctx); } @@ -5373,7 +5420,7 @@ clone_xlate_actions(const struct ofpact *actions, size_t actions_len, if (ctx->xbridge->support.clone) { /* Use clone action */ /* Use clone action as datapath clone. */ offset = nl_msg_start_nested(ctx->odp_actions, OVS_ACTION_ATTR_CLONE); - do_xlate_actions(actions, actions_len, ctx); + do_xlate_actions(actions, actions_len, ctx, true); if (ctx->freezing) { finish_freezing(ctx); } @@ -5386,7 +5433,7 @@ clone_xlate_actions(const struct ofpact *actions, size_t actions_len, offset = nl_msg_start_nested(ctx->odp_actions, OVS_ACTION_ATTR_SAMPLE); ac_offset = nl_msg_start_nested(ctx->odp_actions, OVS_SAMPLE_ATTR_ACTIONS); - do_xlate_actions(actions, actions_len, ctx); + do_xlate_actions(actions, actions_len, ctx, true); if (ctx->freezing) { finish_freezing(ctx); } @@ -5425,11 +5472,12 @@ xlate_done: } static void -compose_clone(struct xlate_ctx *ctx, const struct ofpact_nest *oc) +compose_clone(struct xlate_ctx *ctx, const struct ofpact_nest *oc, + bool is_last_action) { size_t oc_actions_len = ofpact_nest_get_action_len(oc); - clone_xlate_actions(oc->actions, oc_actions_len, ctx); + clone_xlate_actions(oc->actions, oc_actions_len, ctx, is_last_action); } static void @@ -5511,7 +5559,7 @@ xlate_action_set(struct xlate_ctx *ctx) struct ovs_list *old_trace = ctx->xin->trace; ctx->xin->trace = xlate_report(ctx, OFT_TABLE, "--. Executing action set:"); - do_xlate_actions(action_list.data, action_list.size, ctx); + do_xlate_actions(action_list.data, action_list.size, ctx, true); ctx->xin->trace = old_trace; ctx->in_action_set = false; @@ -5735,7 +5783,8 @@ put_ct_nat(struct xlate_ctx *ctx) } static void -compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc) +compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc, + bool is_last_action) { ovs_u128 old_ct_label_mask = ctx->wc->masks.ct_label; uint32_t old_ct_mark_mask = ctx->wc->masks.ct_mark; @@ -5750,7 +5799,8 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc) ctx->ct_nat_action = NULL; ctx->wc->masks.ct_mark = 0; ctx->wc->masks.ct_label = OVS_U128_ZERO; - do_xlate_actions(ofc->actions, ofpact_ct_get_action_len(ofc), ctx); + do_xlate_actions(ofc->actions, ofpact_ct_get_action_len(ofc), ctx, + is_last_action); if (ofc->zone_src.field) { zone = mf_get_subfield(&ofc->zone_src, &ctx->xin->flow); @@ -6146,7 +6196,7 @@ xlate_ofpact_unroll_xlate(struct xlate_ctx *ctx, static void do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, - struct xlate_ctx *ctx) + struct xlate_ctx *ctx, bool is_last_action) { struct flow_wildcards *wc = ctx->wc; struct flow *flow = &ctx->xin->flow; @@ -6167,6 +6217,8 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, const struct ofpact_metadata *metadata; const struct ofpact_set_field *set_field; const struct mf_field *mf; + bool last = is_last_action && ofpact_last(a, ofpacts, ofpacts_len) + && ctx->action_set.size; if (ctx->error) { break; @@ -6194,11 +6246,11 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, switch (a->type) { case OFPACT_OUTPUT: xlate_output_action(ctx, ofpact_get_OUTPUT(a)->port, - ofpact_get_OUTPUT(a)->max_len, true); + ofpact_get_OUTPUT(a)->max_len, true, last); break; case OFPACT_GROUP: - if (xlate_group_action(ctx, ofpact_get_GROUP(a)->group_id)) { + if (xlate_group_action(ctx, ofpact_get_GROUP(a)->group_id, last)) { /* Group could not be found. */ /* XXX: Terminates action list translation, but does not @@ -6227,7 +6279,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, case OFPACT_ENQUEUE: memset(&wc->masks.skb_priority, 0xff, sizeof wc->masks.skb_priority); - xlate_enqueue_action(ctx, ofpact_get_ENQUEUE(a)); + xlate_enqueue_action(ctx, ofpact_get_ENQUEUE(a), last); break; case OFPACT_SET_VLAN_VID: @@ -6339,7 +6391,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, * to avoid that, only adding any actions that follow the resubmit * to the frozen actions. */ - xlate_ofpact_resubmit(ctx, ofpact_get_RESUBMIT(a)); + xlate_ofpact_resubmit(ctx, ofpact_get_RESUBMIT(a), last); continue; case OFPACT_SET_TUNNEL: @@ -6437,16 +6489,16 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_BUNDLE: - xlate_bundle_action(ctx, ofpact_get_BUNDLE(a)); + xlate_bundle_action(ctx, ofpact_get_BUNDLE(a), last); break; case OFPACT_OUTPUT_REG: - xlate_output_reg_action(ctx, ofpact_get_OUTPUT_REG(a)); + xlate_output_reg_action(ctx, ofpact_get_OUTPUT_REG(a), last); break; case OFPACT_OUTPUT_TRUNC: xlate_output_trunc_action(ctx, ofpact_get_OUTPUT_TRUNC(a)->port, - ofpact_get_OUTPUT_TRUNC(a)->max_len); + ofpact_get_OUTPUT_TRUNC(a)->max_len, last); break; case OFPACT_LEARN: @@ -6502,7 +6554,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, ovs_assert(ctx->table_id < ogt->table_id); xlate_table_action(ctx, ctx->xin->flow.in_port.ofp_port, - ogt->table_id, true, true, false); + ogt->table_id, true, true, false, last); break; } @@ -6511,7 +6563,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_CLONE: - compose_clone(ctx, ofpact_get_CLONE(a)); + compose_clone(ctx, ofpact_get_CLONE(a), last); break; case OFPACT_ENCAP: @@ -6531,7 +6583,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, } case OFPACT_CT: - compose_conntrack_action(ctx, ofpact_get_CT(a)); + compose_conntrack_action(ctx, ofpact_get_CT(a), last); break; case OFPACT_CT_CLEAR: @@ -7099,7 +7151,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) } mirror_ingress_packet(&ctx); - do_xlate_actions(ofpacts, ofpacts_len, &ctx); + do_xlate_actions(ofpacts, ofpacts_len, &ctx, true); if (ctx.error) { goto exit; } @@ -7127,7 +7179,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) && xbridge->has_in_band && in_band_must_output_to_local_port(flow) && !actions_output_to_local_port(&ctx)) { - compose_output_action(&ctx, OFPP_LOCAL, NULL); + compose_output_action(&ctx, OFPP_LOCAL, NULL, false); } if (user_cookie_offset) { |