/* * Copyright (c) 2019 Mellanox Technologies, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include "mlx5dv_dr.h" #define BUFF_SIZE 1024 enum dr_dump_rec_type { DR_DUMP_REC_TYPE_DOMAIN = 3000, DR_DUMP_REC_TYPE_DOMAIN_INFO_FLEX_PARSER = 3001, DR_DUMP_REC_TYPE_DOMAIN_INFO_DEV_ATTR = 3002, DR_DUMP_REC_TYPE_DOMAIN_INFO_VPORT = 3003, DR_DUMP_REC_TYPE_DOMAIN_INFO_CAPS = 3004, DR_DUMP_REC_TYPE_DOMAIN_SEND_RING = 3005, DR_DUMP_REC_TYPE_TABLE = 3100, DR_DUMP_REC_TYPE_TABLE_RX = 3101, DR_DUMP_REC_TYPE_TABLE_TX = 3102, DR_DUMP_REC_TYPE_MATCHER = 3200, DR_DUMP_REC_TYPE_MATCHER_MASK_DEPRECATED = 3201, DR_DUMP_REC_TYPE_MATCHER_RX = 3202, DR_DUMP_REC_TYPE_MATCHER_TX = 3203, DR_DUMP_REC_TYPE_MATCHER_BUILDER = 3204, DR_DUMP_REC_TYPE_MATCHER_MASK = 3205, DR_DUMP_REC_TYPE_RULE = 3300, DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V0 = 3301, DR_DUMP_REC_TYPE_RULE_TX_ENTRY_V0 = 3302, DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V1 = 3303, DR_DUMP_REC_TYPE_RULE_TX_ENTRY_V1 = 3304, DR_DUMP_REC_TYPE_ACTION_ENCAP_L2 = 3400, DR_DUMP_REC_TYPE_ACTION_ENCAP_L3 = 3401, DR_DUMP_REC_TYPE_ACTION_MODIFY_HDR = 3402, DR_DUMP_REC_TYPE_ACTION_DROP = 3403, DR_DUMP_REC_TYPE_ACTION_QP = 3404, DR_DUMP_REC_TYPE_ACTION_FT = 3405, DR_DUMP_REC_TYPE_ACTION_CTR = 3406, DR_DUMP_REC_TYPE_ACTION_TAG = 3407, DR_DUMP_REC_TYPE_ACTION_VPORT = 3408, DR_DUMP_REC_TYPE_ACTION_DECAP_L2 = 3409, DR_DUMP_REC_TYPE_ACTION_DECAP_L3 = 3410, DR_DUMP_REC_TYPE_ACTION_DEVX_TIR = 3411, DR_DUMP_REC_TYPE_ACTION_PUSH_VLAN = 3412, DR_DUMP_REC_TYPE_ACTION_POP_VLAN = 3413, DR_DUMP_REC_TYPE_ACTION_METER = 3414, DR_DUMP_REC_TYPE_ACTION_SAMPLER = 3415, DR_DUMP_REC_TYPE_ACTION_DEST_ARRAY = 3416, DR_DUMP_REC_TYPE_ACTION_ASO_FIRST_HIT = 3417, DR_DUMP_REC_TYPE_ACTION_ASO_FLOW_METER = 3418, DR_DUMP_REC_TYPE_ACTION_ASO_CT = 3419, DR_DUMP_REC_TYPE_ACTION_MISS = 3423, DR_DUMP_REC_TYPE_ACTION_ROOT_FT = 3424, }; static uint64_t dr_dump_icm_to_idx(uint64_t icm_addr) { return (icm_addr >> 6) & 0xffffffff; } static void dump_hex_print(char *dest, char *src, uint32_t size) { int i; for (i = 0; i < size; i++) sprintf(&dest[2 * i], "%02x", (uint8_t)src[i]); } static int dr_dump_rule_action(FILE *f, const uint64_t rule_id, struct mlx5dv_dr_action *action) { const uint64_t action_id = (uint64_t) (uintptr_t) action; int ret; switch (action->action_type) { case DR_ACTION_TYP_DROP: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 "\n", DR_DUMP_REC_TYPE_ACTION_DROP, action_id, rule_id); break; case DR_ACTION_TYP_FT: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%x,0x%" PRIx64 "\n", DR_DUMP_REC_TYPE_ACTION_FT, action_id, rule_id, action->dest_tbl->devx_obj->object_id, (uint64_t)(uintptr_t)action->dest_tbl); break; case DR_ACTION_TYP_QP: if (action->dest_qp.is_qp) ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%x\n", DR_DUMP_REC_TYPE_ACTION_QP, action_id, rule_id, action->dest_qp.qp->qp_num); else ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 "\n", DR_DUMP_REC_TYPE_ACTION_DEVX_TIR, action_id, rule_id, action->dest_qp.devx_tir->rx_icm_addr); break; case DR_ACTION_TYP_CTR: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%x\n", DR_DUMP_REC_TYPE_ACTION_CTR, action_id, rule_id, action->ctr.devx_obj->object_id + action->ctr.offset); break; case DR_ACTION_TYP_TAG: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%x\n", DR_DUMP_REC_TYPE_ACTION_TAG, action_id, rule_id, action->flow_tag); break; case DR_ACTION_TYP_MODIFY_HDR: { struct dr_ptrn_obj *ptrn = action->rewrite.ptrn_arg.ptrn; struct dr_rewrite_param *param = &action->rewrite.param; struct dr_arg_obj *arg = action->rewrite.ptrn_arg.arg; bool ptrn_in_use = false; int i; if (!action->rewrite.single_action_opt && ptrn && arg) ptrn_in_use = true; ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%x,%d,0x%x,0x%" PRIx32 ",0x%" PRIx32, DR_DUMP_REC_TYPE_ACTION_MODIFY_HDR, action_id, rule_id, param->index, action->rewrite.single_action_opt, ptrn_in_use ? param->num_of_actions : 0, ptrn_in_use ? ptrn->rewrite_param.index : 0, ptrn_in_use ? dr_arg_get_object_id(arg) : 0); if (ret < 0) return ret; if (ptrn_in_use) { for (i = 0; i < param->num_of_actions; i++) { ret = fprintf(f, ",0x%016" PRIx64, be64toh(((__be64 *)param->data)[i])); if (ret < 0) return ret; } } ret = fprintf(f, "\n"); break; } case DR_ACTION_TYP_VPORT: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%x\n", DR_DUMP_REC_TYPE_ACTION_VPORT, action_id, rule_id, action->vport.caps->num); break; case DR_ACTION_TYP_TNL_L2_TO_L2: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 "\n", DR_DUMP_REC_TYPE_ACTION_DECAP_L2, action_id, rule_id); break; case DR_ACTION_TYP_TNL_L3_TO_L2: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%x\n", DR_DUMP_REC_TYPE_ACTION_DECAP_L3, action_id, rule_id, action->rewrite.param.index); break; 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, 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, 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", DR_DUMP_REC_TYPE_ACTION_METER, action_id, rule_id, (uint64_t)(uintptr_t)action->meter.next_ft, action->meter.devx_obj->object_id, action->meter.rx_icm_addr, action->meter.tx_icm_addr); break; case DR_ACTION_TYP_SAMPLER: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 ",0x%x,0x%x,0x%" PRIx64 ",0x%" PRIx64 "\n", DR_DUMP_REC_TYPE_ACTION_SAMPLER, action_id, rule_id, (uint64_t)(uintptr_t)action->sampler.sampler_default->next_ft, action->sampler.term_tbl->devx_tbl->ft_dvo->object_id, action->sampler.sampler_default->devx_obj->object_id, action->sampler.sampler_default->rx_icm_addr, (action->sampler.sampler_restore) ? action->sampler.sampler_restore->tx_icm_addr : action->sampler.sampler_default->tx_icm_addr); break; case DR_ACTION_TYP_DEST_ARRAY: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%x,0x%" PRIx64 ",0x%" PRIx64 "\n", DR_DUMP_REC_TYPE_ACTION_DEST_ARRAY, action_id, rule_id, action->dest_array.devx_tbl->ft_dvo->object_id, action->dest_array.rx_icm_addr, action->dest_array.tx_icm_addr); break; case DR_ACTION_TYP_POP_VLAN: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 "\n", DR_DUMP_REC_TYPE_ACTION_POP_VLAN, action_id, rule_id); break; case DR_ACTION_TYP_PUSH_VLAN: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%x\n", DR_DUMP_REC_TYPE_ACTION_PUSH_VLAN, action_id, rule_id, action->push_vlan.vlan_hdr); break; case DR_ACTION_TYP_ASO_FIRST_HIT: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%x\n", DR_DUMP_REC_TYPE_ACTION_ASO_FIRST_HIT, action_id, rule_id, action->aso.devx_obj->object_id); break; case DR_ACTION_TYP_ASO_FLOW_METER: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%x\n", DR_DUMP_REC_TYPE_ACTION_ASO_FLOW_METER, action_id, rule_id, action->aso.devx_obj->object_id); break; case DR_ACTION_TYP_ASO_CT: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%x\n", DR_DUMP_REC_TYPE_ACTION_ASO_CT, action_id, rule_id, action->aso.devx_obj->object_id); break; case DR_ACTION_TYP_MISS: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 "\n", DR_DUMP_REC_TYPE_ACTION_MISS, action_id, rule_id); break; case DR_ACTION_TYP_ROOT_FT: ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%x\n", DR_DUMP_REC_TYPE_ACTION_ROOT_FT, action_id, rule_id, action->root_tbl.devx_tbl->ft_dvo->object_id); break; default: return 0; } if (ret < 0) return ret; return 0; } static int dr_dump_rule_mem(FILE *f, struct dr_ste *ste, bool is_rx, const uint64_t rule_id, enum mlx5_ifc_steering_format_version format_ver) { char hw_ste_dump[BUFF_SIZE] = {}; enum dr_dump_rec_type mem_rec_type; int ret; if (format_ver == MLX5_HW_CONNECTX_5) { mem_rec_type = is_rx ? DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V0 : DR_DUMP_REC_TYPE_RULE_TX_ENTRY_V0; } else { mem_rec_type = is_rx ? DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V1 : DR_DUMP_REC_TYPE_RULE_TX_ENTRY_V1; } dump_hex_print(hw_ste_dump, (char *)ste->hw_ste, ste->size); ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",%s\n", mem_rec_type, dr_dump_icm_to_idx(dr_ste_get_icm_addr(ste)), rule_id, hw_ste_dump); if (ret < 0) return ret; return 0; } static int dr_dump_rule_rx_tx(FILE *f, struct dr_rule_rx_tx *nic_rule, bool is_rx, const uint64_t rule_id, enum mlx5_ifc_steering_format_version format_ver) { struct dr_ste *ste_arr[DR_RULE_MAX_STES + DR_ACTION_MAX_STES]; struct dr_ste *curr_ste = nic_rule->last_rule_ste; int ret, i; dr_rule_get_reverse_rule_members(ste_arr, curr_ste, &i); while (i--) { ret = dr_dump_rule_mem(f, ste_arr[i], is_rx, rule_id, format_ver); if (ret < 0) return ret; } return 0; } static int dr_dump_rule(FILE *f, struct mlx5dv_dr_rule *rule) { const uint64_t rule_id = (uint64_t) (uintptr_t) rule; enum mlx5_ifc_steering_format_version format_ver; struct dr_rule_rx_tx *rx = &rule->rx; struct dr_rule_rx_tx *tx = &rule->tx; int ret; int i; format_ver = rule->matcher->tbl->dmn->info.caps.sw_format_ver; ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 "\n", DR_DUMP_REC_TYPE_RULE, rule_id, (uint64_t) (uintptr_t) rule->matcher); if (ret < 0) return ret; if (!dr_is_root_table(rule->matcher->tbl)) { if (rx->nic_matcher) { ret = dr_dump_rule_rx_tx(f, rx, true, rule_id, format_ver); if (ret < 0) return ret; } if (tx->nic_matcher) { ret = dr_dump_rule_rx_tx(f, tx, false, rule_id, format_ver); if (ret < 0) return ret; } } for (i = 0; i < rule->num_actions; i++) { ret = dr_dump_rule_action(f, rule_id, rule->actions[i]); if (ret < 0) return ret; } return 0; } static int dr_dump_matcher_mask(FILE *f, struct dr_match_param *mask, uint8_t criteria, const uint64_t matcher_id) { char dump[BUFF_SIZE] = {}; int ret; ret = fprintf(f, "%d,0x%" PRIx64 ",", DR_DUMP_REC_TYPE_MATCHER_MASK, matcher_id); if (ret < 0) return ret; if (criteria & DR_MATCHER_CRITERIA_OUTER) { dump_hex_print(dump, (char *)&mask->outer, sizeof(mask->outer)); ret = fprintf(f, "%s,", dump); } else { ret = fprintf(f, ","); } if (ret < 0) return ret; if (criteria & DR_MATCHER_CRITERIA_INNER) { dump_hex_print(dump, (char *)&mask->inner, sizeof(mask->inner)); ret = fprintf(f, "%s,", dump); } else { ret = fprintf(f, ","); } if (ret < 0) return ret; if (criteria & DR_MATCHER_CRITERIA_MISC) { dump_hex_print(dump, (char *)&mask->misc, sizeof(mask->misc)); ret = fprintf(f, "%s,", dump); } else { ret = fprintf(f, ","); } if (ret < 0) return ret; if (criteria & DR_MATCHER_CRITERIA_MISC2) { dump_hex_print(dump, (char *)&mask->misc2, sizeof(mask->misc2)); ret = fprintf(f, "%s,", dump); } else { ret = fprintf(f, ","); } if (ret < 0) return ret; if (criteria & DR_MATCHER_CRITERIA_MISC3) { dump_hex_print(dump, (char *)&mask->misc3, sizeof(mask->misc3)); ret = fprintf(f, "%s,", dump); } else { ret = fprintf(f, ","); } if (criteria & DR_MATCHER_CRITERIA_MISC4) { dump_hex_print(dump, (char *)&mask->misc4, sizeof(mask->misc4)); ret = fprintf(f, "%s,", dump); } else { ret = fprintf(f, ","); } if (criteria & DR_MATCHER_CRITERIA_MISC5) { dump_hex_print(dump, (char *)&mask->misc5, sizeof(mask->misc5)); ret = fprintf(f, "%s\n", dump); } else { ret = fprintf(f, ",\n"); } if (ret < 0) return ret; return 0; } static int dr_dump_matcher_builder(FILE *f, struct dr_ste_build *builder, uint32_t index, bool is_rx, const uint64_t matcher_id) { bool is_match = builder->htbl_type == DR_STE_HTBL_TYPE_MATCH; int ret; ret = fprintf(f, "%d,0x%" PRIx64 ",%d,%d,0x%x,%d\n", DR_DUMP_REC_TYPE_MATCHER_BUILDER, matcher_id, index, is_rx, builder->lu_type, is_match ? builder->format_id : -1); if (ret < 0) return ret; return 0; } static int dr_dump_matcher_rx_tx(FILE *f, bool is_rx, struct dr_matcher_rx_tx *matcher_rx_tx, const uint64_t matcher_id) { enum dr_dump_rec_type rec_type; int i, ret; rec_type = is_rx ? DR_DUMP_REC_TYPE_MATCHER_RX : DR_DUMP_REC_TYPE_MATCHER_TX; ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",%d,0x%" PRIx64 ",0x%" PRIx64 ",%d\n", rec_type, (uint64_t) (uintptr_t) matcher_rx_tx, matcher_id, matcher_rx_tx->num_of_builders, dr_dump_icm_to_idx(dr_icm_pool_get_chunk_icm_addr(matcher_rx_tx->s_htbl->chunk)), dr_dump_icm_to_idx(dr_icm_pool_get_chunk_icm_addr(matcher_rx_tx->e_anchor->chunk)), matcher_rx_tx->fixed_size ? matcher_rx_tx->s_htbl->chunk_size : -1); if (ret < 0) return ret; for (i = 0; i < matcher_rx_tx->num_of_builders; i++) { ret = dr_dump_matcher_builder(f, &matcher_rx_tx->ste_builder[i], i, is_rx, matcher_id); if (ret < 0) return ret; } return 0; } static int dr_dump_matcher(FILE *f, struct mlx5dv_dr_matcher *matcher) { struct dr_matcher_rx_tx *rx = &matcher->rx; struct dr_matcher_rx_tx *tx = &matcher->tx; uint64_t matcher_id; int ret; matcher_id = (uint64_t) (uintptr_t) matcher; ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",%d\n", DR_DUMP_REC_TYPE_MATCHER, matcher_id, (uint64_t) (uintptr_t) matcher->tbl, matcher->prio); if (ret < 0) return ret; if (!dr_is_root_table(matcher->tbl)) { ret = dr_dump_matcher_mask(f, &matcher->mask, matcher->match_criteria, matcher_id); if (ret < 0) return ret; if (rx->nic_tbl) { ret = dr_dump_matcher_rx_tx(f, true, rx, matcher_id); if (ret < 0) return ret; } if (tx->nic_tbl) { ret = dr_dump_matcher_rx_tx(f, false, tx, matcher_id); if (ret < 0) return ret; } } return 0; } static int dr_dump_matcher_all(FILE *fout, struct mlx5dv_dr_matcher *matcher) { struct mlx5dv_dr_rule *rule; int ret; ret = dr_dump_matcher(fout, matcher); if (ret < 0) return ret; list_for_each(&matcher->rule_list, rule, rule_list) { ret = dr_dump_rule(fout, rule); if (ret < 0) return ret; } return 0; } static uint64_t dr_domain_id_calc(enum mlx5dv_dr_domain_type type) { return (getpid() << 8) | (type & 0xff); } static int dr_dump_table_rx_tx(FILE *f, bool is_rx, struct dr_table_rx_tx *table_rx_tx, const uint64_t table_id) { struct dr_icm_chunk *chunk = table_rx_tx->s_anchor->chunk; enum dr_dump_rec_type rec_type; int ret; rec_type = is_rx ? DR_DUMP_REC_TYPE_TABLE_RX : DR_DUMP_REC_TYPE_TABLE_TX; ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 "\n", rec_type, table_id, dr_dump_icm_to_idx(dr_icm_pool_get_chunk_icm_addr(chunk))); if (ret < 0) return ret; return 0; } static int dr_dump_table(FILE *f, struct mlx5dv_dr_table *table) { struct dr_table_rx_tx *rx = &table->rx; struct dr_table_rx_tx *tx = &table->tx; int ret; ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",%d,%d\n", DR_DUMP_REC_TYPE_TABLE, (uint64_t) (uintptr_t) table, dr_domain_id_calc(table->dmn->type), table->table_type, table->level); if (ret < 0) return ret; if (!dr_is_root_table(table)) { if (rx->nic_dmn) { ret = dr_dump_table_rx_tx(f, true, rx, (uint64_t) (uintptr_t) table); if (ret < 0) return ret; } if (tx->nic_dmn) { ret = dr_dump_table_rx_tx(f, false, tx, (uint64_t) (uintptr_t) table); if (ret < 0) return ret; } } return 0; } static int dr_dump_table_all(FILE *fout, struct mlx5dv_dr_table *tbl) { struct mlx5dv_dr_matcher *matcher; int ret; ret = dr_dump_table(fout, tbl); if (ret < 0) return ret; if (!dr_is_root_table(tbl)) { list_for_each(&tbl->matcher_list, matcher, matcher_list) { ret = dr_dump_matcher_all(fout, matcher); if (ret < 0) return ret; } } return 0; } static int dr_dump_send_ring(FILE *f, struct dr_send_ring *ring, const uint64_t domain_id) { int ret; ret = fprintf(f, "%d,0x%" PRIx64 ",0x%" PRIx64 ",0x%x,0x%x\n", DR_DUMP_REC_TYPE_DOMAIN_SEND_RING, (uint64_t) (uintptr_t) ring, domain_id, ring->cq.cqn, ring->qp->obj->object_id); if (ret < 0) return ret; return 0; } static int dr_dump_domain_info_flex_parser(FILE *f, const char *flex_parser_name, const uint8_t flex_parser_value, const uint64_t domain_id) { int ret; ret = fprintf(f, "%d,0x%" PRIx64 ",%s,0x%x\n", DR_DUMP_REC_TYPE_DOMAIN_INFO_FLEX_PARSER, domain_id, flex_parser_name, flex_parser_value); if (ret < 0) return ret; return 0; } static int dr_dump_vports_table(FILE *f, struct dr_vports_table *vports_tbl, const uint64_t domain_id) { struct dr_devx_vport_cap *vport_cap; int i, ret; if (!vports_tbl) return 0; for (i = 0; i < DR_VPORTS_BUCKETS; i++) { vport_cap = vports_tbl->buckets[i]; while (vport_cap) { ret = fprintf(f, "%d,0x%" PRIx64 ",%d,0x%x,0x%" PRIx64 ",0x%" PRIx64 "\n", DR_DUMP_REC_TYPE_DOMAIN_INFO_VPORT, domain_id, vport_cap->num, vport_cap->vport_gvmi, vport_cap->icm_address_rx, vport_cap->icm_address_tx); if (ret < 0) return ret; vport_cap = vport_cap->next; } } return 0; } static int dr_dump_domain_info_caps(FILE *f, struct dr_devx_caps *caps, const uint64_t domain_id) { int ret; ret = fprintf(f, "%d,0x%" PRIx64 ",0x%x,0x%" PRIx64 ",0x%" PRIx64 ",0x%x,%d,%d\n", DR_DUMP_REC_TYPE_DOMAIN_INFO_CAPS, domain_id, caps->gvmi, caps->nic_rx_drop_address, caps->nic_tx_drop_address, caps->flex_protocols, caps->vports.num_ports, caps->eswitch_manager); if (ret < 0) return ret; ret = dr_dump_vports_table(f, caps->vports.vports, domain_id); if (ret < 0) return ret; return 0; } static int dr_dump_domain_info_dev_attr(FILE *f, struct dr_domain_info *info, const uint64_t domain_id) { int ret; ret = fprintf(f, "%d,0x%" PRIx64 ",%u,%s,%d\n", DR_DUMP_REC_TYPE_DOMAIN_INFO_DEV_ATTR, domain_id, info->caps.vports.num_ports, info->attr.orig_attr.fw_ver, info->use_mqs); if (ret < 0) return ret; return 0; } static int dr_dump_domain_info(FILE *f, struct dr_domain_info *info, const uint64_t domain_id) { int ret; ret = dr_dump_domain_info_dev_attr(f, info, domain_id); if (ret < 0) return ret; ret = dr_dump_domain_info_caps(f, &info->caps, domain_id); if (ret < 0) return ret; ret = dr_dump_domain_info_flex_parser(f, "icmp_dw0", info->caps.flex_parser_id_icmp_dw0, domain_id); if (ret < 0) return ret; ret = dr_dump_domain_info_flex_parser(f, "icmp_dw1", info->caps.flex_parser_id_icmp_dw1, domain_id); if (ret < 0) return ret; ret = dr_dump_domain_info_flex_parser(f, "icmpv6_dw0", info->caps.flex_parser_id_icmpv6_dw0, domain_id); if (ret < 0) return ret; ret = dr_dump_domain_info_flex_parser(f, "icmpv6_dw1", info->caps.flex_parser_id_icmpv6_dw1, domain_id); if (ret < 0) return ret; return 0; } static int dr_dump_domain(FILE *f, struct mlx5dv_dr_domain *dmn) { enum mlx5dv_dr_domain_type dmn_type = dmn->type; char *dev_name = dmn->ctx->device->dev_name; uint64_t domain_id; int ret, i; domain_id = dr_domain_id_calc(dmn_type); ret = fprintf(f, "%d,0x%" PRIx64 ",%d,0%x,%d,%s,%s,%u,%u,%u,%u,%u\n", DR_DUMP_REC_TYPE_DOMAIN, domain_id, dmn_type, dmn->info.caps.gvmi, dmn->info.supp_sw_steering, PACKAGE_VERSION, dev_name, dmn->flags, dmn->num_buddies[DR_ICM_TYPE_STE], dmn->num_buddies[DR_ICM_TYPE_MODIFY_ACTION], dmn->num_buddies[DR_ICM_TYPE_MODIFY_HDR_PTRN], dmn->info.caps.sw_format_ver); if (ret < 0) return ret; ret = dr_dump_domain_info(f, &dmn->info, domain_id); if (ret < 0) return ret; if (dmn->info.supp_sw_steering) { for (i = 0; i < DR_MAX_SEND_RINGS; i++) { ret = dr_dump_send_ring(f, dmn->send_ring[i], domain_id); if (ret < 0) return ret; } } return 0; } static int dr_dump_domain_all(FILE *fout, struct mlx5dv_dr_domain *dmn) { struct mlx5dv_dr_table *tbl; int ret; ret = dr_dump_domain(fout, dmn); if (ret < 0) return ret; list_for_each(&dmn->tbl_list, tbl, tbl_list) { ret = dr_dump_table_all(fout, tbl); if (ret < 0) return ret; } return 0; } int mlx5dv_dump_dr_domain(FILE *fout, struct mlx5dv_dr_domain *dmn) { int ret; if (!fout || !dmn) return -EINVAL; pthread_spin_lock(&dmn->debug_lock); dr_domain_lock(dmn); ret = dr_dump_domain_all(fout, dmn); dr_domain_unlock(dmn); pthread_spin_unlock(&dmn->debug_lock); return ret; } int mlx5dv_dump_dr_table(FILE *fout, struct mlx5dv_dr_table *tbl) { int ret; if (!fout || !tbl) return -EINVAL; pthread_spin_lock(&tbl->dmn->debug_lock); dr_domain_lock(tbl->dmn); ret = dr_dump_domain(fout, tbl->dmn); if (ret < 0) goto out; ret = dr_dump_table_all(fout, tbl); out: dr_domain_unlock(tbl->dmn); pthread_spin_unlock(&tbl->dmn->debug_lock); return ret; } int mlx5dv_dump_dr_matcher(FILE *fout, struct mlx5dv_dr_matcher *matcher) { int ret; if (!fout || !matcher) return -EINVAL; pthread_spin_lock(&matcher->tbl->dmn->debug_lock); dr_domain_lock(matcher->tbl->dmn); ret = dr_dump_domain(fout, matcher->tbl->dmn); if (ret < 0) goto out; ret = dr_dump_table(fout, matcher->tbl); if (ret < 0) goto out; ret = dr_dump_matcher_all(fout, matcher); out: dr_domain_unlock(matcher->tbl->dmn); pthread_spin_unlock(&matcher->tbl->dmn->debug_lock); return ret; } int mlx5dv_dump_dr_rule(FILE *fout, struct mlx5dv_dr_rule *rule) { int ret; if (!fout || !rule) return -EINVAL; pthread_spin_lock(&rule->matcher->tbl->dmn->debug_lock); dr_domain_lock(rule->matcher->tbl->dmn); ret = dr_dump_domain(fout, rule->matcher->tbl->dmn); if (ret < 0) goto out; ret = dr_dump_table(fout, rule->matcher->tbl); if (ret < 0) goto out; ret = dr_dump_matcher(fout, rule->matcher); if (ret < 0) goto out; ret = dr_dump_rule(fout, rule); out: dr_domain_unlock(rule->matcher->tbl->dmn); pthread_spin_unlock(&rule->matcher->tbl->dmn->debug_lock); return ret; }