[PATCH net-next 4/6] net: hns3: support IP and tunnel VNI dissectors for tc flow

From: Jijie Shao

Date: Mon May 18 2026 - 05:35:58 EST


Currently, the driver does not support FLOW_DISSECTOR_KEY_IP and
FLOW_DISSECTOR_KEY_ENC_KEYID. But the hardware supports
ip_tos (FLOW_DISSECTOR_KEY_IP) and
outer_tun_vni (FLOW_DISSECTOR_KEY_ENC_KEYID).

This patch adds support for FLOW_DISSECTOR_KEY_IP and
FLOW_DISSECTOR_KEY_ENC_KEYID.

Additionally, since tc flow cannot effectively support
l2_user_def, l3_user_def, and l4_user_def,
this patch explicitly sets them to not be used.

Signed-off-by: Jijie Shao <shaojijie@xxxxxxxxxx>
---
.../hisilicon/hns3/hns3pf/hclge_main.c | 78 +++++++++++++++++--
.../hisilicon/hns3/hns3pf/hclge_main.h | 4 +
2 files changed, 76 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
index bbbc017a0fb7..35380dbd1ecf 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -16,7 +16,7 @@
#include <linux/crash_dump.h>

#include <net/rtnetlink.h>
-
+#include <net/vxlan.h>
#include "hclge_cmd.h"
#include "hclge_dcb.h"
#include "hclge_main.h"
@@ -337,7 +337,9 @@ static const struct key_info tuple_key_info[] = {
{ OUTER_SRC_PORT, 16, KEY_OPT_LE16, -1, -1 },
{ OUTER_DST_PORT, 16, KEY_OPT_LE16, -1, -1 },
{ OUTER_L4_RSV, 32, KEY_OPT_LE32, -1, -1 },
- { OUTER_TUN_VNI, 24, KEY_OPT_VNI, -1, -1 },
+ { OUTER_TUN_VNI, 24, KEY_OPT_VNI,
+ offsetof(struct hclge_fd_rule, tuples.outer_tun_vni),
+ offsetof(struct hclge_fd_rule, tuples_mask.outer_tun_vni) },
{ OUTER_TUN_FLOW_ID, 8, KEY_OPT_U8, -1, -1 },
{ INNER_DST_MAC, 48, KEY_OPT_MAC,
offsetof(struct hclge_fd_rule, tuples.dst_mac),
@@ -5590,8 +5592,9 @@ static int hclge_init_fd_config(struct hclge_dev *hdev)

/* If use max 400bit key, we can support tuples for ether type */
if (hdev->fd_cfg.fd_mode == HCLGE_FD_MODE_DEPTH_2K_WIDTH_400B_STAGE_1) {
- key_cfg->tuple_active |=
- BIT(INNER_DST_MAC) | BIT(INNER_SRC_MAC);
+ key_cfg->tuple_active |= BIT(INNER_DST_MAC) |
+ BIT(INNER_SRC_MAC) |
+ BIT(OUTER_TUN_VNI);
if (hdev->ae_dev->dev_version >= HNAE3_DEVICE_VERSION_V3)
key_cfg->tuple_active |= HCLGE_FD_TUPLE_USER_DEF_TUPLES;
}
@@ -5760,6 +5763,17 @@ static bool hclge_fd_convert_tuple(u32 tuple_bit, u8 *key_x, u8 *key_y,
*(__le32 *)key_x = cpu_to_le32(tmp_x_l);
*(__le32 *)key_y = cpu_to_le32(tmp_y_l);

+ return true;
+ case KEY_OPT_VNI:
+ calc_x(tmp_x_l, *(u32 *)(&p[offset]), *(u32 *)(&p[moffset]));
+ calc_y(tmp_y_l, *(u32 *)(&p[offset]), *(u32 *)(&p[moffset]));
+ for (i = 0; i < HCLGE_VNI_LENGTH; i++) {
+ key_x[i] = (cpu_to_le32(tmp_x_l) >>
+ (i * BITS_PER_BYTE)) & 0xFF;
+ key_y[i] = (cpu_to_le32(tmp_y_l) >>
+ (i * BITS_PER_BYTE)) & 0xFF;
+ }
+
return true;
default:
return false;
@@ -7340,6 +7354,52 @@ static void hclge_get_cls_key_port(const struct flow_rule *flow,
}
}

+static int hclge_get_cls_enc_keyid(struct hclge_dev *hdev,
+ const struct flow_rule *flow,
+ struct hclge_fd_rule *rule)
+{
+ if (flow_rule_match_key(flow, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
+ struct flow_match_enc_keyid match;
+
+ flow_rule_match_enc_keyid(flow, &match);
+
+ /* vni is only 24 bits and must be greater than 0,
+ * and it can not be masked.
+ */
+ if (match.mask->keyid != HCLGE_FD_VXLAN_VNI_UNMASK ||
+ be32_to_cpu(match.key->keyid) >= VXLAN_N_VID ||
+ !match.key->keyid) {
+ dev_err(&hdev->pdev->dev, "invalid enc_keyid\n");
+ return -EINVAL;
+ }
+
+ rule->tuples.outer_tun_vni = be32_to_cpu(match.key->keyid);
+ rule->tuples_mask.outer_tun_vni =
+ be32_to_cpu(match.mask->keyid);
+ } else {
+ rule->unused_tuple |= BIT(OUTER_TUN_VNI);
+ }
+
+ return 0;
+}
+
+static void hclge_get_cls_key_ip_tos(const struct flow_rule *flow,
+ struct hclge_fd_rule *rule)
+{
+ if (flow_rule_match_key(flow, FLOW_DISSECTOR_KEY_IP)) {
+ struct flow_match_ip match;
+
+ flow_rule_match_ip(flow, &match);
+
+ rule->tuples.ip_tos = match.key->tos;
+ rule->tuples_mask.ip_tos = match.mask->tos;
+ if (!rule->tuples.ip_tos)
+ rule->unused_tuple |= BIT(INNER_IP_TOS);
+ } else {
+ rule->unused_tuple |= BIT(INNER_IP_TOS);
+ }
+}
+
static int hclge_get_tc_flower_action(struct hclge_dev *hdev,
struct flow_cls_offload *cls_flower,
struct hclge_fd_rule *rule)
@@ -7393,6 +7453,9 @@ static int hclge_parse_cls_flower(struct hclge_dev *hdev,
struct netlink_ext_ack *extack = cls_flower->common.extack;
int ret;

+ /* not support any user def tuples */
+ rule->unused_tuple |= HCLGE_FD_TUPLE_USER_DEF_TUPLES;
+
hclge_get_cls_key_basic(flow, rule);
hclge_get_cls_key_mac(flow, rule);
hclge_get_cls_key_vlan(flow, rule);
@@ -7402,8 +7465,9 @@ static int hclge_parse_cls_flower(struct hclge_dev *hdev,
return ret;

hclge_get_cls_key_port(flow, rule);
+ hclge_get_cls_key_ip_tos(flow, rule);

- return 0;
+ return hclge_get_cls_enc_keyid(hdev, flow, rule);
}

static int hclge_check_cls_flower(struct hclge_dev *hdev,
@@ -7433,7 +7497,9 @@ static int hclge_check_cls_flower(struct hclge_dev *hdev,
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))) {
+ BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_IP) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ENC_KEYID))) {
dev_err(&hdev->pdev->dev, "unsupported key set: %#llx\n",
dissector->used_keys);
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
index 032b472d2368..ccb19d960690 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
@@ -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 {
--
2.33.0