Merge branch 'net-hns3-enhance-tc-flow-offload-support'

Jijie Shao says:

====================
net: hns3: enhance tc flow offload support

This patchset enhances the tc flow offload support for hns3 driver:

- Patch 1: Refactor hclge_add_cls_flower() to support more actions
- Patch 2: Improve unused_tuple parameter setting for separate src/dst configuration
- Patch 3: Add support for HCLGE_FD_ACTION_SELECT_QUEUE and HCLGE_FD_ACTION_DROP_PACKET actions
- Patch 4: Add support for FLOW_DISSECTOR_KEY_IP and FLOW_DISSECTOR_KEY_ENC_KEYID dissectors
- Patch 5: Add debugfs support for dumping FD rules
- Patch 6: Move FD code to a separate file (hclge_fd.c) for better code organization
====================

Link: https://patch.msgid.link/20260610060618.834987-1-shaojijie@huawei.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2026-06-13 17:56:20 -07:00
9 changed files with 2818 additions and 2452 deletions

View File

@@ -24,5 +24,6 @@ hclgevf-objs = hns3vf/hclgevf_main.o hns3vf/hclgevf_mbx.o hns3vf/hclgevf_devlin
obj-$(CONFIG_HNS3_HCLGE) += hclge.o hclge-common.o
hclge-objs = hns3pf/hclge_main.o hns3pf/hclge_mdio.o hns3pf/hclge_tm.o hns3pf/hclge_regs.o \
hns3pf/hclge_mbx.o hns3pf/hclge_err.o hns3pf/hclge_debugfs.o hns3pf/hclge_ptp.o hns3pf/hclge_devlink.o \
hns3pf/hclge_fd.o
hclge-$(CONFIG_HNS3_DCB) += hns3pf/hclge_dcb.o

View File

@@ -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,
@@ -778,7 +779,7 @@ struct hnae3_ae_ops {
u32 len, u8 *data);
bool (*get_cmdq_stat)(struct hnae3_handle *handle);
int (*add_cls_flower)(struct hnae3_handle *handle,
struct flow_cls_offload *cls_flower, int tc);
struct flow_cls_offload *cls_flower);
int (*del_cls_flower)(struct hnae3_handle *handle,
struct flow_cls_offload *cls_flower);
bool (*cls_flower_active)(struct hnae3_handle *handle);

View File

@@ -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,

View File

@@ -2678,13 +2678,12 @@ static int hns3_setup_tc(struct net_device *netdev, void *type_data)
static int hns3_setup_tc_cls_flower(struct hns3_nic_priv *priv,
struct flow_cls_offload *flow)
{
int tc = tc_classid_to_hwtc(priv->netdev, flow->classid);
struct hnae3_handle *h = hns3_get_handle(priv->netdev);
switch (flow->command) {
case FLOW_CLS_REPLACE:
if (h->ae_algo->ops->add_cls_flower)
return h->ae_algo->ops->add_cls_flower(h, flow, tc);
return h->ae_algo->ops->add_cls_flower(h, flow);
break;
case FLOW_CLS_DESTROY:
if (h->ae_algo->ops->del_cls_flower)

View File

@@ -2121,6 +2121,157 @@ 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
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) ||
rule->unused_tuple & BIT(INNER_ETH_TYPE))
return;
ipv6_addr_cpu_to_be32(be_ip, ip);
ipv6_addr_cpu_to_be32(be_mask, mask);
if (rule->tuples.ether_proto == ETH_P_IPV6)
hclge_fd_dump_ptr(s, rule, type, name, "%pI6",
be_ip, be_mask);
else
hclge_fd_dump_ptr(s, rule, type, name, "%pI4",
&be_ip[IPV4_INDEX], &be_mask[IPV4_INDEX]);
}
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",
};
if (rule->action <= HCLGE_FD_ACTION_SELECT_TC)
seq_printf(s, "\taction: %s\n", action_str[rule->action]);
else
seq_printf(s, "\taction: %s\n", "unknown");
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 type_str[] = {
[HCLGE_FD_RULE_NONE] = "none",
[HCLGE_FD_ARFS_ACTIVE] = "arfs",
[HCLGE_FD_EP_ACTIVE] = "ep",
[HCLGE_FD_TC_FLOWER_ACTIVE] = "tc_flow"
};
if (hdev->fd_active_type <= HCLGE_FD_TC_FLOWER_ACTIVE)
seq_printf(s, "fd type: %s\n", type_str[hdev->fd_active_type]);
else
seq_printf(s, "fd type: %s\n", "unknown");
}
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;
if (!hnae3_ae_dev_fd_supported(hdev->ae_dev))
return -EOPNOTSUPP;
spin_lock_bh(&hdev->fd_rule_lock);
hclge_dbg_dump_fd_type(hdev, s);
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 +3064,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,

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2026 Hisilicon Limited. */
#ifndef __HCLGE_FD_H
#define __HCLGE_FD_H
struct hnae3_handle;
struct hclge_dev;
int hclge_init_fd_config(struct hclge_dev *hdev);
int hclge_add_fd_entry(struct hnae3_handle *handle, struct ethtool_rxnfc *cmd);
int hclge_del_fd_entry(struct hnae3_handle *handle, struct ethtool_rxnfc *cmd);
void hclge_del_all_fd_entries(struct hclge_dev *hdev);
int hclge_restore_fd_entries(struct hnae3_handle *handle);
int hclge_get_fd_rule_cnt(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd);
int hclge_get_fd_rule_info(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd);
int hclge_get_all_rules(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd, u32 *rule_locs);
void hclge_enable_fd(struct hnae3_handle *handle, bool enable);
int hclge_add_fd_entry_by_arfs(struct hnae3_handle *handle, u16 queue_id,
u16 flow_id, struct flow_keys *fkeys);
int hclge_add_cls_flower(struct hnae3_handle *handle,
struct flow_cls_offload *cls_flower);
int hclge_del_cls_flower(struct hnae3_handle *handle,
struct flow_cls_offload *cls_flower);
bool hclge_is_cls_flower_active(struct hnae3_handle *handle);
int hclge_clear_arfs_rules(struct hclge_dev *hdev);
void hclge_sync_fd_table(struct hclge_dev *hdev);
void hclge_rfs_filter_expire(struct hclge_dev *hdev);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -645,6 +645,9 @@ struct key_info {
#define HCLGE_FD_USER_DEF_DATA GENMASK(15, 0)
#define HCLGE_FD_USER_DEF_OFFSET GENMASK(15, 0)
#define HCLGE_FD_USER_DEF_OFFSET_UNMASK GENMASK(15, 0)
#define HCLGE_FD_VXLAN_VNI_UNMASK GENMASK(31, 0)
#define HCLGE_VNI_LENGTH 3
/* assigned by firmware, the real filter number for each pf may be less */
#define MAX_FD_FILTER_NUM 4096
@@ -738,6 +741,7 @@ struct hclge_fd_rule_tuples {
u32 l4_user_def;
u8 ip_tos;
u8 ip_proto;
u32 outer_tun_vni;
};
struct hclge_fd_rule {
@@ -1175,4 +1179,6 @@ int hclge_mac_update_stats(struct hclge_dev *hdev);
struct hclge_vport *hclge_get_vf_vport(struct hclge_dev *hdev, int vf);
int hclge_inform_vf_reset(struct hclge_vport *vport, u16 reset_type);
int hclge_query_scc_version(struct hclge_dev *hdev, u32 *scc_version);
u32 hclge_get_port_number(enum HLCGE_PORT_TYPE port_type, u8 pf_id,
u8 vf_id, u8 network_port_id);
#endif