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 --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 1 + .../ethernet/hisilicon/hns3/hns3_debugfs.c | 6 + .../hisilicon/hns3/hns3pf/hclge_debugfs.c | 156 ++++++++++++++++++ 3 files changed, 163 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..d5009809420c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -2121,6 +2121,158 @@ static int hclge_dbg_dump_fd_counter(struct seq_file *s, void *data) return 0; } +static void hclge_fd_dump_u32(struct seq_file *s, + struct hclge_fd_rule *rule, + u32 type, const char *name, + const char *fmt, u32 key, u32 mask) +{ + if (rule->unused_tuple & BIT(type)) + return; + + seq_printf(s, "\t\t%s: ", name); + seq_printf(s, fmt, key); + seq_putc(s, '\n'); + + seq_printf(s, "\t\t%s_mask: ", name); + seq_printf(s, fmt, mask); + seq_putc(s, '\n'); +} + +static void hclge_fd_dump_ptr(struct seq_file *s, + struct hclge_fd_rule *rule, + u32 type, const char *name, + const char *fmt, + const void *key, const void *mask) +{ + if (rule->unused_tuple & BIT(type)) + return; + + seq_printf(s, "\t\t%s: ", name); + seq_printf(s, fmt, key); + seq_putc(s, '\n'); + + seq_printf(s, "\t\t%s_mask: ", name); + seq_printf(s, fmt, mask); + seq_putc(s, '\n'); +} + +#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) +{ + u32 be_mask[IPV6_ADDR_WORDS]; + u32 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 +3065,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