mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-24 19:43:22 -04:00
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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
2593
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_fd.c
Normal file
2593
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_fd.c
Normal file
File diff suppressed because it is too large
Load Diff
33
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_fd.h
Normal file
33
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_fd.h
Normal 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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user