From: Jiawei Wang Date: Tue, 12 Jan 2021 10:29:16 +0000 (+0200) Subject: net/mlx5: support E-Switch mirroring and jump in one flow X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=6a951567c159;p=dpdk.git net/mlx5: support E-Switch mirroring and jump in one flow mlx5 E-Switch mirroring is implemented as multiple destination array in one steering table. The array currently supports only port ID as destination actions. This patch adds the jump action support to the array as one of destination. The packets can be mirrored to the port and jump to the next table in the same destination array allowing to continue handling in the new table. For example: set sample_actions 0 port_id id 1 / end flow create 0 ingress transfer pattern eth / end actions sample ratio 1 index 0 / jump group 1 / end flow create 1 ingress transfer group 1 pattern eth / end actions set_mac_dst mac_addr 00:aa:bb:cc:dd:ee / port_id id 2 / end The flow results all the matched ingress packets are mirrored to port id 1 and go to group 1. In the group 1, packets are modified with the destination mac and sent to port id 2. Signed-off-by: Jiawei Wang Acked-by: Viacheslav Ovsiienko --- diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst index f5034dcd18..54622b5329 100644 --- a/doc/guides/nics/mlx5.rst +++ b/doc/guides/nics/mlx5.rst @@ -101,6 +101,7 @@ Features - Matching on GTP extension header with raw encap/decap action. - Matching on Geneve TLV option header with raw encap/decap action. - RSS support in sample action. +- E-Switch mirroring and jump. Limitations ----------- diff --git a/doc/guides/rel_notes/release_21_02.rst b/doc/guides/rel_notes/release_21_02.rst index 31051ede08..79fe82f488 100644 --- a/doc/guides/rel_notes/release_21_02.rst +++ b/doc/guides/rel_notes/release_21_02.rst @@ -113,6 +113,7 @@ New Features * Introduced basic support on Windows. * Added GTP PDU session container matching and raw encap/decap. * Added support for RSS action in the sample sub-actions list. + * Added support for E-Switch mirroring and jump action in the same flow. * **Updated Wangxun txgbe driver.** diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index 6716a20141..d880a9c9d4 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -4653,7 +4653,6 @@ flow_check_match_action(const struct rte_flow_action actions[], { const struct rte_flow_action_sample *sample; int actions_n = 0; - int jump_flag = 0; uint32_t ratio = 0; int sub_type = 0; int flag = 0; @@ -4668,8 +4667,6 @@ flow_check_match_action(const struct rte_flow_action actions[], if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE || actions->type == RTE_FLOW_ACTION_TYPE_RSS) *qrss_action_pos = actions_n; - if (actions->type == RTE_FLOW_ACTION_TYPE_JUMP) - jump_flag = 1; if (actions->type == RTE_FLOW_ACTION_TYPE_SAMPLE) { sample = actions->conf; ratio = sample->ratio; @@ -4680,10 +4677,10 @@ flow_check_match_action(const struct rte_flow_action actions[], } if (flag && action == RTE_FLOW_ACTION_TYPE_SAMPLE && attr->transfer) { if (ratio == 1) { - /* JUMP Action not support for Mirroring; - * Mirroring support multi-destination; + /* FDB mirroring uses the destination array to implement + * instead of FLOW_SAMPLER object. */ - if (!jump_flag && sub_type != RTE_FLOW_ACTION_TYPE_END) + if (sub_type != RTE_FLOW_ACTION_TYPE_END) flag = 0; } } @@ -4704,8 +4701,8 @@ flow_check_match_action(const struct rte_flow_action actions[], * * @param dev * Pointer to Ethernet device. - * @param[in] fdb_tx - * FDB egress flow flag. + * @param[in] add_tag + * Add extra tag action flag. * @param[out] sfx_items * Suffix flow match items (list terminated by the END pattern item). * @param[in] actions @@ -4729,7 +4726,7 @@ flow_check_match_action(const struct rte_flow_action actions[], */ static int flow_sample_split_prep(struct rte_eth_dev *dev, - uint32_t fdb_tx, + int add_tag, struct rte_flow_item sfx_items[], const struct rte_flow_action actions[], struct rte_flow_action actions_sfx[], @@ -4752,7 +4749,11 @@ flow_sample_split_prep(struct rte_eth_dev *dev, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "invalid position of sample " "action in list"); - if (!fdb_tx) { + /* For CX5, add an extra tag action for NIC-RX and E-Switch ingress. + * For CX6DX and above, metadata registers Cx preserve their value, + * add an extra tag action for NIC-RX and E-Switch ingress and egress. + */ + if (add_tag) { /* Prepare the prefix tag action. */ set_tag = (void *)(actions_pre + actions_n + 1); ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, 0, error); @@ -4803,8 +4804,7 @@ flow_sample_split_prep(struct rte_eth_dev *dev, memcpy(actions_pre, actions, sizeof(struct rte_flow_action) * index); } - /* Add the extra tag action for NIC-RX and E-Switch ingress. */ - if (!fdb_tx) { + if (add_tag) { actions_pre[index++] = (struct rte_flow_action){ .type = (enum rte_flow_action_type) @@ -5217,6 +5217,7 @@ flow_create_split_sample(struct rte_eth_dev *dev, int actions_n = 0; int sample_action_pos; int qrss_action_pos; + int add_tag = 0; int ret = 0; if (priv->sampler_en) @@ -5238,16 +5239,21 @@ flow_create_split_sample(struct rte_eth_dev *dev, "sample flow"); /* The representor_id is -1 for uplink. */ fdb_tx = (attr->transfer && priv->representor_id != -1); - if (!fdb_tx) + /* + * When reg_c_preserve is set, metadata registers Cx preserve + * their value even through packet duplication. + */ + add_tag = (!fdb_tx || priv->config.hca_attr.reg_c_preserve); + if (add_tag) sfx_items = (struct rte_flow_item *)((char *)sfx_actions + act_size); pre_actions = sfx_actions + actions_n; - tag_id = flow_sample_split_prep(dev, fdb_tx, sfx_items, + tag_id = flow_sample_split_prep(dev, add_tag, sfx_items, actions, sfx_actions, pre_actions, actions_n, sample_action_pos, qrss_action_pos, error); - if (tag_id < 0 || (!fdb_tx && !tag_id)) { + if (tag_id < 0 || (add_tag && !tag_id)) { ret = -rte_errno; goto exit; } diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index a9e33b8ab8..8255627abc 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -564,6 +564,7 @@ struct mlx5_flow_sub_actions_list { void *dr_cnt_action; void *dr_port_id_action; void *dr_encap_action; + void *dr_jump_action; }; /* Sample sub-actions resource list. */ @@ -573,6 +574,7 @@ struct mlx5_flow_sub_actions_idx { uint32_t cnt; uint32_t rix_port_id_action; /**< Index to port ID action resource. */ uint32_t rix_encap_decap; /**< Index to encap/decap resource. */ + uint32_t rix_jump; /**< Index to the jump action resource. */ }; /* Sample action resource structure. */ diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index 707d6749e2..f1ce648fac 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -76,7 +76,7 @@ flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh, static int flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev, - uint32_t encap_decap_idx); + uint32_t encap_decap_idx); static int flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev, @@ -84,6 +84,10 @@ flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev, static void flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss); +static int +flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev, + uint32_t rix_jump); + /** * Initialize flow attributes structure according to flow items' types. * @@ -3662,7 +3666,7 @@ flow_dv_create_action_push_vlan(struct rte_eth_dev *dev, (dev, &res, dev_flow, error); } -static int fdb_mirror; +static int fdb_mirror_limit; /** * Validate the modify-header actions. @@ -3691,7 +3695,7 @@ flow_dv_validate_action_modify_hdr(const uint64_t action_flags, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "can't have encap action before" " modify action"); - if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) && fdb_mirror) + if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) && fdb_mirror_limit) return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "can't support sample action before" @@ -4027,12 +4031,6 @@ flow_dv_validate_action_jump(struct rte_eth_dev *dev, return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "jump with meter not support"); - if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) && fdb_mirror) - return rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ACTION, NULL, - "E-Switch mirroring can't support" - " Sample action and jump action in" - " same flow now"); if (!action->conf) return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION_CONF, @@ -4438,8 +4436,8 @@ flow_dv_validate_action_sample(uint64_t action_flags, uint16_t queue_index = 0xFFFF; int actions_n = 0; int ret; - fdb_mirror = 0; + fdb_mirror_limit = 0; if (!sample) return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, action, @@ -4579,7 +4577,7 @@ flow_dv_validate_action_sample(uint64_t action_flags, "E-Switch doesn't support " "any optional action " "for sampling"); - fdb_mirror = 1; + fdb_mirror_limit = 1; if (sub_action_flags & MLX5_FLOW_ACTION_QUEUE) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, @@ -9072,6 +9070,10 @@ flow_dv_sample_sub_actions_release(struct rte_eth_dev *dev, flow_dv_counter_free(dev, act_res->cnt); act_res->cnt = 0; } + if (act_res->rix_jump) { + flow_dv_jump_tbl_resource_release(dev, act_res->rix_jump); + act_res->rix_jump = 0; + } } int @@ -9284,6 +9286,7 @@ flow_dv_dest_array_create_cb(struct mlx5_cache_list *list __rte_unused, struct mlx5dv_dr_domain *domain; uint32_t idx = 0, res_idx = 0; struct rte_flow_error *error = ctx->error; + uint64_t action_flags; int ret; /* Register new destination array resource. */ @@ -9317,19 +9320,31 @@ flow_dv_dest_array_create_cb(struct mlx5_cache_list *list __rte_unused, } dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST; sample_act = &resource->sample_act[idx]; - if (sample_act->action_flags == MLX5_FLOW_ACTION_QUEUE) { + action_flags = sample_act->action_flags; + switch (action_flags) { + case MLX5_FLOW_ACTION_QUEUE: dest_attr[idx]->dest = sample_act->dr_queue_action; - } else if (sample_act->action_flags == - (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_ENCAP)) { + break; + case (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_ENCAP): dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST_REFORMAT; dest_attr[idx]->dest_reformat = &dest_reformat[idx]; dest_attr[idx]->dest_reformat->reformat = sample_act->dr_encap_action; dest_attr[idx]->dest_reformat->dest = sample_act->dr_port_id_action; - } else if (sample_act->action_flags == - MLX5_FLOW_ACTION_PORT_ID) { + break; + case MLX5_FLOW_ACTION_PORT_ID: dest_attr[idx]->dest = sample_act->dr_port_id_action; + break; + case MLX5_FLOW_ACTION_JUMP: + dest_attr[idx]->dest = sample_act->dr_jump_action; + break; + default: + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + NULL, + "unsupported actions type"); + goto error; } } /* create a dest array actioin */ @@ -9366,6 +9381,10 @@ error: !flow_dv_port_id_action_resource_release(dev, act_res->rix_port_id_action)) act_res->rix_port_id_action = 0; + if (act_res->rix_jump && + !flow_dv_jump_tbl_resource_release(dev, + act_res->rix_jump)) + act_res->rix_jump = 0; if (dest_attr[idx]) mlx5_free(dest_attr[idx]); } @@ -9739,6 +9758,14 @@ flow_dv_create_action_sample(struct rte_eth_dev *dev, sample_act->dr_port_id_action = dev_flow->dv.port_id_action->action; } + if (sample_act->action_flags & MLX5_FLOW_ACTION_JUMP) { + normal_idx++; + mdest_res->sample_idx[dest_index].rix_jump = + dev_flow->handle->rix_jump; + sample_act->dr_jump_action = + dev_flow->dv.jump->action; + dev_flow->handle->rix_jump = 0; + } sample_act->actions_num = normal_idx; /* update sample action resource into first index of array */ mdest_res->ft_type = res->ft_type; @@ -10498,6 +10525,8 @@ flow_dv_translate(struct rte_eth_dev *dev, dev_flow->dv.jump->action; action_flags |= MLX5_FLOW_ACTION_JUMP; dev_flow->handle->fate_action = MLX5_FLOW_FATE_JUMP; + sample_act->action_flags |= MLX5_FLOW_ACTION_JUMP; + num_of_dest++; break; case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC: case RTE_FLOW_ACTION_TYPE_SET_MAC_DST: @@ -10996,7 +11025,8 @@ flow_dv_translate(struct rte_eth_dev *dev, * So need remove the original these actions in the flow and only * use the sample action instead of. */ - if (num_of_dest > 1 && sample_act->dr_port_id_action) { + if (num_of_dest > 1 && + (sample_act->dr_port_id_action || sample_act->dr_jump_action)) { int i; void *temp_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0}; @@ -11006,6 +11036,9 @@ flow_dv_translate(struct rte_eth_dev *dev, dev_flow->dv.actions[i]) || (sample_act->dr_port_id_action && sample_act->dr_port_id_action == + dev_flow->dv.actions[i]) || + (sample_act->dr_jump_action && + sample_act->dr_jump_action == dev_flow->dv.actions[i])) continue; temp_actions[tmp_actions_n++] = dev_flow->dv.actions[i]; @@ -11280,8 +11313,8 @@ flow_dv_matcher_remove_cb(struct mlx5_cache_list *list __rte_unused, * * @param dev * Pointer to Ethernet device. - * @param handle - * Pointer to mlx5_flow_handle. + * @param port_id + * Index to port ID action resource. * * @return * 1 while a reference on it exists, 0 when freed. @@ -11353,21 +11386,21 @@ flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev, * * @param dev * Pointer to Ethernet device. - * @param handle - * Pointer to mlx5_flow_handle. + * @param rix_jump + * Index to the jump action resource. * * @return * 1 while a reference on it exists, 0 when freed. */ static int flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev, - struct mlx5_flow_handle *handle) + uint32_t rix_jump) { struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_flow_tbl_data_entry *tbl_data; tbl_data = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_JUMP], - handle->rix_jump); + rix_jump); if (!tbl_data) return 0; return flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl_data->tbl); @@ -11521,7 +11554,7 @@ flow_dv_fate_resource_release(struct rte_eth_dev *dev, mlx5_hrxq_release(dev, handle->rix_hrxq); break; case MLX5_FLOW_FATE_JUMP: - flow_dv_jump_tbl_resource_release(dev, handle); + flow_dv_jump_tbl_resource_release(dev, handle->rix_jump); break; case MLX5_FLOW_FATE_PORT_ID: flow_dv_port_id_action_resource_release(dev,