[PATCH V4 net-next 1/6] net: hns3: refactor add_cls_flower to prepare for multiple actions

From: Jijie Shao

Date: Wed Jun 10 2026 - 02:11:06 EST


Remove the tc parameter from the add_cls_flower() ops callback and
refactor action parsing to support future extensions for SELECT_QUEUE
and DROP_PACKET actions.

Changes:
* Remove the tc parameter from the add_cls_flower() callback signature.
* Extract TC-based action parsing into hclge_get_tc_flower_action().
* Move the dissector->used_keys check from hclge_parse_cls_flower() to
hclge_check_cls_flower(), and restrict ETH_ADDRS to
HCLGE_FD_MODE_DEPTH_2K_WIDTH_400B_STAGE_1 mode since hardware only
supports MAC matching there.
* Migrate error reporting from dev_err() to netlink extended ACK (extack).

Signed-off-by: Jijie Shao <shaojijie@xxxxxxxxxx>
---
drivers/net/ethernet/hisilicon/hns3/hnae3.h | 2 +-
.../net/ethernet/hisilicon/hns3/hns3_enet.c | 3 +-
.../hisilicon/hns3/hns3pf/hclge_main.c | 93 ++++++++++++-------
3 files changed, 60 insertions(+), 38 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
index d7c3df1958f3..a724935b655a 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
@@ -778,7 +778,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);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
index 4c34a144d21c..6ecb32e28e79 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
@@ -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)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
index e17b92a411a2..77bd23e2c11e 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -7328,28 +7328,33 @@ static void hclge_get_cls_key_port(const struct flow_rule *flow,
}
}

+static int hclge_get_tc_flower_action(struct hclge_dev *hdev,
+ struct flow_cls_offload *cls_flower,
+ struct hclge_fd_rule *rule)
+{
+ struct netlink_ext_ack *extack = cls_flower->common.extack;
+ struct hnae3_handle *handle = &hdev->vport[0].nic;
+ int tc;
+
+ tc = tc_classid_to_hwtc(handle->netdev, cls_flower->classid);
+ if (tc < 0 || tc > hdev->tc_max) {
+ NL_SET_ERR_MSG_FMT_MOD(extack, "invalid traffic class: %d", tc);
+ return -EINVAL;
+ }
+
+ rule->action = HCLGE_FD_ACTION_SELECT_TC;
+ rule->cls_flower.tc = tc;
+ return 0;
+}
+
static int hclge_parse_cls_flower(struct hclge_dev *hdev,
struct flow_cls_offload *cls_flower,
struct hclge_fd_rule *rule)
{
struct flow_rule *flow = flow_cls_offload_flow_rule(cls_flower);
struct netlink_ext_ack *extack = cls_flower->common.extack;
- struct flow_dissector *dissector = flow->match.dissector;
int ret;

- if (dissector->used_keys &
- ~(BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
- BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
- BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
- BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
- BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
- BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
- BIT_ULL(FLOW_DISSECTOR_KEY_PORTS))) {
- dev_err(&hdev->pdev->dev, "unsupported key set: %#llx\n",
- dissector->used_keys);
- return -EOPNOTSUPP;
- }
-
hclge_get_cls_key_basic(flow, rule);
hclge_get_cls_key_mac(flow, rule);
hclge_get_cls_key_vlan(flow, rule);
@@ -7364,51 +7369,65 @@ static int hclge_parse_cls_flower(struct hclge_dev *hdev,
}

static int hclge_check_cls_flower(struct hclge_dev *hdev,
- struct flow_cls_offload *cls_flower, int tc)
+ struct flow_cls_offload *cls_flower)
{
+ struct flow_rule *flow = flow_cls_offload_flow_rule(cls_flower);
+ struct netlink_ext_ack *extack = cls_flower->common.extack;
+ struct flow_dissector *dissector = flow->match.dissector;
u32 prio = cls_flower->common.prio;
-
- if (tc < 0 || tc > hdev->tc_max) {
- dev_err(&hdev->pdev->dev, "invalid traffic class\n");
- return -EINVAL;
- }
+ u64 support_keys;

if (prio == 0 ||
prio > hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]) {
- dev_err(&hdev->pdev->dev,
- "prio %u should be in range[1, %u]\n",
- prio, hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]);
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "prio %u should be in range[1, %u]",
+ prio,
+ hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]);
return -EINVAL;
}

if (test_bit(prio - 1, hdev->fd_bmap)) {
- dev_err(&hdev->pdev->dev, "prio %u is already used\n", prio);
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "prio %u is already used", prio);
return -EINVAL;
}
+
+ support_keys = BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS);
+
+ if (hdev->fd_cfg.fd_mode == HCLGE_FD_MODE_DEPTH_2K_WIDTH_400B_STAGE_1)
+ support_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS);
+
+ if (dissector->used_keys & ~support_keys) {
+ NL_SET_ERR_MSG_FMT_MOD(extack, "unsupported key set: %#llx",
+ dissector->used_keys);
+ return -EOPNOTSUPP;
+ }
+
return 0;
}

static int hclge_add_cls_flower(struct hnae3_handle *handle,
- struct flow_cls_offload *cls_flower,
- int tc)
+ struct flow_cls_offload *cls_flower)
{
+ struct netlink_ext_ack *extack = cls_flower->common.extack;
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct hclge_fd_rule *rule;
int ret;

if (!hnae3_ae_dev_fd_supported(hdev->ae_dev)) {
- dev_err(&hdev->pdev->dev,
- "cls flower is not supported\n");
+ NL_SET_ERR_MSG_MOD(extack, "cls flower is not supported");
return -EOPNOTSUPP;
}

- ret = hclge_check_cls_flower(hdev, cls_flower, tc);
- if (ret) {
- dev_err(&hdev->pdev->dev,
- "failed to check cls flower params, ret = %d\n", ret);
+ ret = hclge_check_cls_flower(hdev, cls_flower);
+ if (ret)
return ret;
- }

rule = kzalloc_obj(*rule);
if (!rule)
@@ -7420,8 +7439,12 @@ static int hclge_add_cls_flower(struct hnae3_handle *handle,
return ret;
}

- rule->action = HCLGE_FD_ACTION_SELECT_TC;
- rule->cls_flower.tc = tc;
+ ret = hclge_get_tc_flower_action(hdev, cls_flower, rule);
+ if (ret) {
+ kfree(rule);
+ return ret;
+ }
+
rule->location = cls_flower->common.prio - 1;
rule->vf_id = 0;
rule->cls_flower.cookie = cls_flower->cookie;
--
2.33.0