[PATCH V2 net-next 5/6] net: hns3: debugfs support for dumping fd rules
From: Jijie Shao <shaojijie@huawei.com>
Date: 2026-05-23 10:55:19
Also in:
lkml
Subsystem:
hisilicon network subsystem 3 driver (hns3), hisilicon network subsystem driver, networking drivers, the rest · Maintainers:
Jian Shen, Jijie Shao, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
Currently, the tc tool only supports adding and deleting rules from the driver but does not support querying rules from the driver. This patch adds a rule dump file in debugfs to check whether the driver's configuration matches the configuration issued by tc flow. Signed-off-by: Jijie Shao <shaojijie@huawei.com> --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 1 + .../ethernet/hisilicon/hns3/hns3_debugfs.c | 6 + .../hisilicon/hns3/hns3pf/hclge_debugfs.c | 150 ++++++++++++++++++ 3 files changed, 157 insertions(+)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
index a724935b655a..a8798eecd9fb 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h@@ -331,6 +331,7 @@ enum hnae3_dbg_cmd { HNAE3_DBG_CMD_TX_QUEUE_INFO, HNAE3_DBG_CMD_FD_TCAM, HNAE3_DBG_CMD_FD_COUNTER, + HNAE3_DBG_CMD_FD_RULE, HNAE3_DBG_CMD_MAC_TNL_STATUS, HNAE3_DBG_CMD_SERV_INFO, HNAE3_DBG_CMD_UMV_INFO,
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
index 4cce4f4ba6b0..1347edac7699 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c@@ -273,6 +273,12 @@ static struct hns3_dbg_cmd_info hns3_dbg_cmd[] = { .dentry = HNS3_DBG_DENTRY_FD, .init = hns3_dbg_common_init_t2, }, + { + .name = "fd_rule", + .cmd = HNAE3_DBG_CMD_FD_RULE, + .dentry = HNS3_DBG_DENTRY_FD, + .init = hns3_dbg_common_init_t2, + }, { .name = "service_task_info", .cmd = HNAE3_DBG_CMD_SERV_INFO,
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
index 3dab3a271aa6..5698e1140793 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c@@ -2121,6 +2121,152 @@ static int hclge_dbg_dump_fd_counter(struct seq_file *s, void *data) return 0; } +__printf(4, 5) +static void hclge_fd_dump_item(struct seq_file *s, const char *name, + const char *suffix, const char *fmt, ...) +{ + va_list args; + + seq_printf(s, "\t\t%s%s: ", name, suffix); + + va_start(args, fmt); + seq_vprintf(s, fmt, args); + va_end(args); + + seq_putc(s, '\n'); +} + +#define hclge_fd_dump_any(s, rule, type, name, fmt, key, mask) \ +do { \ + typeof(s) _s = (s); \ + typeof(name) _name = (name); \ + typeof(fmt) _fmt = (fmt); \ + \ + if (!((rule)->unused_tuple & BIT(type))) { \ + hclge_fd_dump_item(_s, _name, "", _fmt, key); \ + hclge_fd_dump_item(_s, _name, "_mask", _fmt, mask); \ + } \ +} while (0) +#define hclge_fd_dump_u32 hclge_fd_dump_any +#define hclge_fd_dump_ptr hclge_fd_dump_any + +#define HCLGE_IS_IPV4(ip) ({ \ + typeof(ip) _ip = (ip); \ + (!((_ip)[0]) && !((_ip)[1]) && !((_ip)[2]) && (_ip)[IPV4_INDEX]); }) + +static void hclge_fd_dump_ip(struct seq_file *s, + struct hclge_fd_rule *rule, + u32 type, const char *name, + const u32 *ip, const u32 *mask) +{ + __be32 be_mask[IPV6_ADDR_WORDS]; + __be32 be_ip[IPV6_ADDR_WORDS]; + + if (rule->unused_tuple & BIT(type)) + return; + + ipv6_addr_cpu_to_be32(be_ip, ip); + ipv6_addr_cpu_to_be32(be_mask, mask); + + if (HCLGE_IS_IPV4(ip)) + hclge_fd_dump_ptr(s, rule, type, name, "%pI4", + &be_ip[IPV4_INDEX], &be_mask[IPV4_INDEX]); + else + hclge_fd_dump_ptr(s, rule, type, name, "%pI6", + be_ip, be_mask); +} + +static void hclge_dbg_dump_fd_tuples(struct seq_file *s, + struct hclge_fd_rule *rule) +{ + seq_puts(s, "\trule tuples:\n"); + + hclge_fd_dump_ptr(s, rule, INNER_DST_MAC, "dst_mac", "%pM", + rule->tuples.dst_mac, rule->tuples_mask.dst_mac); + hclge_fd_dump_ptr(s, rule, INNER_SRC_MAC, "src_mac", "%pM", + rule->tuples.src_mac, rule->tuples_mask.src_mac); + hclge_fd_dump_u32(s, rule, INNER_VLAN_TAG_FST, "vlan_tag", "0x%04x", + rule->tuples.vlan_tag1, rule->tuples_mask.vlan_tag1); + hclge_fd_dump_u32(s, rule, INNER_ETH_TYPE, "ether_proto", "0x%04x", + rule->tuples.ether_proto, + rule->tuples_mask.ether_proto); + hclge_fd_dump_u32(s, rule, INNER_L2_RSV, "l2_user_def", "0x%04x", + rule->tuples.l2_user_def, + rule->tuples_mask.l2_user_def); + hclge_fd_dump_ip(s, rule, INNER_SRC_IP, "src_ip", + rule->tuples.src_ip, rule->tuples_mask.src_ip); + hclge_fd_dump_ip(s, rule, INNER_DST_IP, "dst_ip", + rule->tuples.dst_ip, rule->tuples_mask.dst_ip); + hclge_fd_dump_u32(s, rule, INNER_IP_TOS, "ip_tos", "0x%02x", + rule->tuples.ip_tos, rule->tuples_mask.ip_tos); + hclge_fd_dump_u32(s, rule, INNER_IP_PROTO, "ip_proto", "0x%02x", + rule->tuples.ip_proto, rule->tuples_mask.ip_proto); + hclge_fd_dump_u32(s, rule, INNER_L3_RSV, "l3_user_def", "0x%04x", + rule->tuples.l3_user_def, + rule->tuples_mask.l3_user_def); + hclge_fd_dump_u32(s, rule, INNER_SRC_PORT, "src_port", "0x%04x", + rule->tuples.src_port, rule->tuples_mask.src_port); + hclge_fd_dump_u32(s, rule, INNER_DST_PORT, "dst_port", "0x%04x", + rule->tuples.dst_port, rule->tuples_mask.dst_port); + hclge_fd_dump_u32(s, rule, INNER_L4_RSV, "l4_user_def", "0x%08x", + rule->tuples.l4_user_def, + rule->tuples_mask.l4_user_def); + hclge_fd_dump_u32(s, rule, OUTER_TUN_VNI, "outer_tun_vni", "0x%06x", + rule->tuples.outer_tun_vni, + rule->tuples_mask.outer_tun_vni); +} + +static void hclge_dbg_dump_fd_action(struct seq_file *s, + struct hclge_fd_rule *rule) +{ + static const char * const action_str[] = { + [HCLGE_FD_ACTION_SELECT_QUEUE] = "select_queue", + [HCLGE_FD_ACTION_DROP_PACKET] = "drop_packet", + [HCLGE_FD_ACTION_SELECT_TC] = "select_tc", + }; + + seq_printf(s, "\taction: %s\n", action_str[rule->action]); + + if (rule->action == HCLGE_FD_ACTION_SELECT_QUEUE) + seq_printf(s, "\tqueue_id: %u\n", rule->queue_id); + else if (rule->action == HCLGE_FD_ACTION_SELECT_TC) + seq_printf(s, "\ttc: %u\n", rule->cls_flower.tc); +} + +static void hclge_dbg_dump_fd_type(struct hclge_dev *hdev, struct seq_file *s) +{ + static const char *const rule_type_str[] = { + [HCLGE_FD_RULE_NONE] = "none", + [HCLGE_FD_ARFS_ACTIVE] = "arfs", + [HCLGE_FD_EP_ACTIVE] = "ep", + [HCLGE_FD_TC_FLOWER_ACTIVE] = "tc_flow" + }; + + seq_printf(s, "fd type: %s\n", rule_type_str[hdev->fd_active_type]); +} + +static int hclge_dbg_dump_fd_rule(struct seq_file *s, void *data) +{ + struct hclge_dev *hdev = hclge_seq_file_to_hdev(s); + struct hclge_fd_rule *rule; + + hclge_dbg_dump_fd_type(hdev, s); + + spin_lock_bh(&hdev->fd_rule_lock); + hlist_for_each_entry(rule, &hdev->fd_rule_list, rule_node) { + if (rule->state != HCLGE_FD_ACTIVE) + continue; + + seq_printf(s, "location: %u\n", rule->location); + seq_printf(s, "vport_id: %u\n", rule->vf_id); + hclge_dbg_dump_fd_action(s, rule); + hclge_dbg_dump_fd_tuples(s, rule); + } + spin_unlock_bh(&hdev->fd_rule_lock); + + return 0; +} + static const struct hclge_dbg_status_dfx_info hclge_dbg_rst_info[] = { {HCLGE_MISC_VECTOR_REG_BASE, "vector0 interrupt enable status"}, {HCLGE_MISC_RESET_STS_REG, "reset interrupt source"},
@@ -2913,6 +3059,10 @@ static const struct hclge_dbg_func hclge_dbg_cmd_func[] = { .cmd = HNAE3_DBG_CMD_FD_TCAM, .dbg_read_func = hclge_dbg_dump_fd_tcam, }, + { + .cmd = HNAE3_DBG_CMD_FD_RULE, + .dbg_read_func = hclge_dbg_dump_fd_rule, + }, { .cmd = HNAE3_DBG_CMD_MAC_TNL_STATUS, .dbg_read_func = hclge_dbg_dump_mac_tnl_status,
--
2.33.0