From f50e8ddef17ffd643eedd3b54a66a52e148eaeb2 Mon Sep 17 00:00:00 2001 From: Shun Hao Date: Thu, 5 Aug 2021 11:28:22 +0300 Subject: [PATCH] mlx5: DR, Add support for SW encap action Currently, encap reformat action creation is done by using DevX to get the reformat_id. This patch adds the support that, when SW encap is supported, will use the new method for encap reformat creation by default, by copying encap data to SW-encap ICM memory directly. Otherwise, will fallback to try again, using DevX to create FW encap action. Because Dest Array action only supports encap action created by DevX, when the SW encap action is used by Dest Array, a DevX object will be created as well, using the same encap data. Signed-off-by: Shun Hao Reviewed-by: Yevgeny Kliteynik Signed-off-by: Yishai Hadas --- providers/mlx5/dr_action.c | 118 +++++++++++++++++++++++++++++++------ providers/mlx5/dr_dbg.c | 4 +- providers/mlx5/dr_send.c | 20 +++++-- providers/mlx5/dr_ste.c | 36 +++++++++++ providers/mlx5/mlx5dv_dr.h | 7 +++ 5 files changed, 160 insertions(+), 25 deletions(-) diff --git a/providers/mlx5/dr_action.c b/providers/mlx5/dr_action.c index 1c460de68..75d8dc95d 100644 --- a/providers/mlx5/dr_action.c +++ b/providers/mlx5/dr_action.c @@ -831,7 +831,7 @@ int dr_actions_build_ste_arr(struct mlx5dv_dr_matcher *matcher, } attr.reformat_size = action->reformat.reformat_size; - attr.reformat_id = action->reformat.dvo->object_id; + attr.reformat_id = dr_actions_reformat_get_id(action); attr.prio_tag_required = dmn->info.caps.prio_tag_required; break; case DR_ACTION_TYP_METER: @@ -1527,8 +1527,9 @@ dr_action_verify_reformat_params(enum mlx5dv_flow_action_packet_reformat_type re size_t data_sz, void *data) { - if ((!data && data_sz) || (data && !data_sz) || reformat_type > - MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL) { + if ((!data && data_sz) || (data && !data_sz) || + (dr_domain_is_support_sw_encap(dmn) && (data_sz > dmn->info.caps.max_encap_size)) || + reformat_type > MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL) { dr_dbg(dmn, "Invalid reformat parameter!\n"); goto out_err; } @@ -1557,31 +1558,88 @@ dr_action_verify_reformat_params(enum mlx5dv_flow_action_packet_reformat_type re return errno; } +static int dr_action_create_sw_reformat(struct mlx5dv_dr_domain *dmn, + struct mlx5dv_dr_action *action, + size_t data_sz, void *data) +{ + uint8_t *reformat_data; + int ret; + + reformat_data = calloc(1, data_sz); + if (!reformat_data) { + errno = ENOMEM; + return errno; + } + memcpy(reformat_data, data, data_sz); + action->reformat.data = reformat_data; + action->reformat.reformat_size = data_sz; + ret = dr_ste_alloc_encap(action); + if (ret) + goto free_reformat_data; + + return 0; + +free_reformat_data: + free(reformat_data); + action->reformat.data = NULL; + + return ret; +} + +static void dr_action_destroy_sw_reformat(struct mlx5dv_dr_action *action) +{ + dr_ste_free_encap(action); + free(action->reformat.data); +} + +static int dr_action_create_devx_reformat(struct mlx5dv_dr_domain *dmn, + struct mlx5dv_dr_action *action, + size_t data_sz, void *data) +{ + struct mlx5dv_devx_obj *obj; + enum reformat_type rt; + + if (action->action_type == DR_ACTION_TYP_L2_TO_TNL_L2) + rt = MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL; + else + rt = MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL; + + obj = dr_devx_create_reformat_ctx(dmn->ctx, rt, data_sz, data); + if (!obj) + return errno; + + action->reformat.dvo = obj; + action->reformat.reformat_size = data_sz; + + return 0; +} + +static void dr_action_destroy_devx_reformat(struct mlx5dv_dr_action *action) +{ + mlx5dv_devx_obj_destroy(action->reformat.dvo); +} + static int dr_action_create_reformat_action(struct mlx5dv_dr_domain *dmn, size_t data_sz, void *data, struct mlx5dv_dr_action *action) { - struct mlx5dv_devx_obj *obj; uint8_t *hw_actions; switch (action->action_type) { case DR_ACTION_TYP_L2_TO_TNL_L2: case DR_ACTION_TYP_L2_TO_TNL_L3: { - enum reformat_type rt; - - if (action->action_type == DR_ACTION_TYP_L2_TO_TNL_L2) - rt = MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL; - else - rt = MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL; + if (dr_domain_is_support_sw_encap(dmn) && + !dr_action_create_sw_reformat(dmn, action, data_sz, data)) + return 0; - obj = dr_devx_create_reformat_ctx(dmn->ctx, rt, data_sz, data); - if (!obj) + /* When failed creating sw encap, fallback to + * use devx to try again. + */ + if (dr_action_create_devx_reformat(dmn, action, data_sz, data)) return errno; - action->reformat.dvo = obj; - action->reformat.reformat_size = data_sz; return 0; } case DR_ACTION_TYP_TNL_L2_TO_L2: @@ -1720,6 +1778,14 @@ struct mlx5dv_dr_action *mlx5dv_dr_action_create_push_vlan(struct mlx5dv_dr_doma return action; } +uint32_t dr_actions_reformat_get_id(struct mlx5dv_dr_action *action) +{ + if (action->reformat.chunk) + return action->reformat.index; + + return action->reformat.dvo->object_id; +} + static int dr_action_modify_sw_to_hw_add(struct mlx5dv_dr_domain *dmn, __be64 *sw_action, @@ -2442,12 +2508,25 @@ dr_action_convert_to_fte_dest(struct mlx5dv_dr_domain *dmn, } if (dest_reformat) { + int ret = 0; + switch (dest_reformat->action_type) { case DR_ACTION_TYP_L2_TO_TNL_L2: case DR_ACTION_TYP_L2_TO_TNL_L3: if (dest_reformat->reformat.is_root_level) goto err_exit; + dr_domain_lock(dmn); + if (!dest_reformat->reformat.dvo) { + ret = dr_action_create_devx_reformat(dmn, + dest_reformat, + dest_reformat->reformat.reformat_size, + dest_reformat->reformat.data); + } + dr_domain_unlock(dmn); + if (ret) + goto err_exit; + fte_attr->extended_dest = true; dest_info->has_reformat = true; dest_info->reformat_id = dest_reformat->reformat.dvo->object_id; @@ -3013,10 +3092,15 @@ int mlx5dv_dr_action_destroy(struct mlx5dv_dr_action *action) break; case DR_ACTION_TYP_L2_TO_TNL_L2: case DR_ACTION_TYP_L2_TO_TNL_L3: - if (action->reformat.is_root_level) + if (action->reformat.is_root_level) { mlx5_destroy_flow_action(action->reformat.flow_action); - else - mlx5dv_devx_obj_destroy(action->reformat.dvo); + } else { + if (action->reformat.chunk) + dr_action_destroy_sw_reformat(action); + + if (action->reformat.dvo) + dr_action_destroy_devx_reformat(action); + } atomic_fetch_sub(&action->reformat.dmn->refcount, 1); break; case DR_ACTION_TYP_MODIFY_HDR: diff --git a/providers/mlx5/dr_dbg.c b/providers/mlx5/dr_dbg.c index f94e2789c..16c70acfa 100644 --- a/providers/mlx5/dr_dbg.c +++ b/providers/mlx5/dr_dbg.c @@ -186,12 +186,12 @@ static int dr_dump_rule_action(FILE *f, const uint64_t rule_id, case DR_ACTION_TYP_L2_TO_TNL_L2: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%x\n", DR_DUMP_REC_TYPE_ACTION_ENCAP_L2, action_id, - rule_id, action->reformat.dvo->object_id); + rule_id, dr_actions_reformat_get_id(action)); break; case DR_ACTION_TYP_L2_TO_TNL_L3: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%x\n", DR_DUMP_REC_TYPE_ACTION_ENCAP_L3, action_id, - rule_id, action->reformat.dvo->object_id); + rule_id, dr_actions_reformat_get_id(action)); break; case DR_ACTION_TYP_METER: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 ",0x%x,0x%" PRIx64 ",0x%" PRIx64 "\n", diff --git a/providers/mlx5/dr_send.c b/providers/mlx5/dr_send.c index 80a877d20..0018b173b 100644 --- a/providers/mlx5/dr_send.c +++ b/providers/mlx5/dr_send.c @@ -951,12 +951,20 @@ int dr_send_postsend_action(struct mlx5dv_dr_domain *dmn, num_qps = dmn->info.use_mqs ? DR_MAX_SEND_RINGS : 1; - send_info.write.addr = (uintptr_t)action->rewrite.param.data; - send_info.write.length = action->rewrite.param.num_of_actions * - DR_MODIFY_ACTION_SIZE; - send_info.write.lkey = 0; - send_info.remote_addr = dr_icm_pool_get_chunk_mr_addr(action->rewrite.param.chunk); - send_info.rkey = dr_icm_pool_get_chunk_rkey(action->rewrite.param.chunk); + if (action->action_type == DR_ACTION_TYP_L2_TO_TNL_L2 || + action->action_type == DR_ACTION_TYP_L2_TO_TNL_L3) { + send_info.write.addr = (uintptr_t)action->reformat.data; + send_info.write.length = action->reformat.reformat_size; + send_info.remote_addr = dr_icm_pool_get_chunk_mr_addr(action->reformat.chunk); + send_info.rkey = dr_icm_pool_get_chunk_rkey(action->reformat.chunk); + } else { + send_info.write.addr = (uintptr_t)action->rewrite.param.data; + send_info.write.length = action->rewrite.param.num_of_actions * + DR_MODIFY_ACTION_SIZE; + send_info.remote_addr = dr_icm_pool_get_chunk_mr_addr(action->rewrite.param.chunk); + send_info.rkey = dr_icm_pool_get_chunk_rkey(action->rewrite.param.chunk); + } + send_info.write.lkey = 0; /* To avoid race between action creation and its use in other QP * write it in all QP's. diff --git a/providers/mlx5/dr_ste.c b/providers/mlx5/dr_ste.c index 440b5bd9c..660a562c4 100644 --- a/providers/mlx5/dr_ste.c +++ b/providers/mlx5/dr_ste.c @@ -732,6 +732,42 @@ void dr_ste_free_modify_hdr(struct mlx5dv_dr_action *action) return dr_dealloc_modify_hdr_chunk(action); } +int dr_ste_alloc_encap(struct mlx5dv_dr_action *action) +{ + struct mlx5dv_dr_domain *dmn = action->reformat.dmn; + uint32_t dynamic_chunck_size; + int ret; + + dynamic_chunck_size = ilog32((action->reformat.reformat_size - 1) / + DR_SW_ENCAP_ENTRY_SIZE); + action->reformat.chunk = dr_icm_alloc_chunk(dmn->encap_icm_pool, + dynamic_chunck_size); + if (!action->reformat.chunk) + return errno; + + action->reformat.index = (dr_icm_pool_get_chunk_icm_addr(action->reformat.chunk) - + dmn->info.caps.indirect_encap_icm_base) / + DR_SW_ENCAP_ENTRY_SIZE; + + ret = dr_send_postsend_action(dmn, action); + if (ret) + goto postsend_err; + + return 0; + +postsend_err: + dr_icm_free_chunk(action->reformat.chunk); + action->reformat.chunk = NULL; + action->reformat.index = 0; + + return ret; +} + +void dr_ste_free_encap(struct mlx5dv_dr_action *action) +{ + dr_icm_free_chunk(action->reformat.chunk); +} + static int dr_ste_build_pre_check_spec(struct mlx5dv_dr_domain *dmn, struct dr_match_spec *m_spec, struct dr_match_spec *v_spec) diff --git a/providers/mlx5/mlx5dv_dr.h b/providers/mlx5/mlx5dv_dr.h index e80fa421a..689e92ff4 100644 --- a/providers/mlx5/mlx5dv_dr.h +++ b/providers/mlx5/mlx5dv_dr.h @@ -693,6 +693,8 @@ int dr_actions_build_attr(struct mlx5dv_dr_matcher *matcher, struct mlx5dv_flow_action_attr *attr, struct mlx5_flow_action_attr_aux *attr_aux); +uint32_t dr_actions_reformat_get_id(struct mlx5dv_dr_action *action); + struct dr_match_spec { uint32_t smac_47_16; /* Source MAC address of incoming packet */ uint32_t smac_15_0:16; /* Source MAC address of incoming packet */ @@ -1279,6 +1281,9 @@ struct mlx5dv_dr_action { struct ibv_flow_action *flow_action; /* root*/ struct { struct mlx5dv_devx_obj *dvo; + uint8_t *data; + uint32_t index; + struct dr_icm_chunk *chunk; uint32_t reformat_size; }; }; @@ -1781,6 +1786,8 @@ void dr_buddy_free_mem(struct dr_icm_buddy_mem *buddy, uint32_t seg, int order); void dr_ste_free_modify_hdr(struct mlx5dv_dr_action *action); int dr_ste_alloc_modify_hdr(struct mlx5dv_dr_action *action); +int dr_ste_alloc_encap(struct mlx5dv_dr_action *action); +void dr_ste_free_encap(struct mlx5dv_dr_action *action); void dr_vports_table_add_wire(struct dr_devx_vports *vports); void dr_vports_table_del_wire(struct dr_devx_vports *vports);