From cd36b15b8b9b4bacc08d6a329fc9802f0efa2930 Mon Sep 17 00:00:00 2001 From: Guangbin Huang Date: Wed, 25 May 2022 20:15:56 +0800 Subject: [PATCH 211/283] net: hns3: support set/get VxLAN rule of rx flow director by ethtool driver inclusion category: feature bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8EN49 ---------------------------------------------------------------------- This patch adds support rule type of vxlan4 and vxlan6 for rx flow director by command ethtool -u/-U. Signed-off-by: Guangbin Huang Signed-off-by: Jiantao Xiao Signed-off-by: Xiaodong Li Conflicts: drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h --- .../hisilicon/hns3/hns3pf/hclge_main.c | 279 +++++++++++++++++- .../hisilicon/hns3/hns3pf/hclge_main.h | 3 + 2 files changed, 274 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index de98538855c4..de5c85415865 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -16,6 +16,7 @@ #include #include #include "kcompat.h" +#include #include "hclge_cmd.h" #include "hclge_dcb.h" #include "hclge_ext.h" @@ -435,7 +436,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), @@ -5762,8 +5765,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); /* roce_type is used to filter roce frames * dst_vport is used to specify the rule @@ -5870,6 +5874,8 @@ static int hclge_fd_ad_config(struct hclge_dev *hdev, u8 stage, int loc, static bool hclge_fd_convert_tuple(u32 tuple_bit, u8 *key_x, u8 *key_y, struct hclge_fd_rule *rule) { +#define HCLGE_VNI_LENGTH 3 + int offset, moffset, ip_offset; enum HCLGE_FD_KEY_OPT key_opt; u16 tmp_x_s, tmp_y_s; @@ -5922,6 +5928,16 @@ 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; @@ -6138,6 +6154,45 @@ static int hclge_fd_check_ip4_tuple(struct ethtool_usrip4_spec *spec, return 0; } +static int hclge_fd_check_vxlan4_tuple(struct ethtool_rx_flow_spec *fs, + u32 *unused_tuple) +{ + struct ethtool_vxlan4_spec *spec = &fs->h_u.vxlan_ip4_spec; + struct ethtool_vxlan4_spec *mask = &fs->m_u.vxlan_ip4_spec; + + /* Vni is only 24 bits and must be greater than 0, and it can not be + * masked. + */ + if (!spec->vni || be32_to_cpu(spec->vni) >= VXLAN_N_VID || + mask->vni != HCLGE_FD_VXLAN_VNI_UNMASK || !unused_tuple) + return -EINVAL; + + *unused_tuple |= BIT(INNER_SRC_PORT) | BIT(INNER_DST_PORT); + + if (is_zero_ether_addr(spec->src)) + *unused_tuple |= BIT(INNER_SRC_MAC); + + if (is_zero_ether_addr(spec->dst)) + *unused_tuple |= BIT(INNER_DST_MAC); + + if (!spec->eth_type) + *unused_tuple |= BIT(INNER_ETH_TYPE); + + if (!spec->ip4src) + *unused_tuple |= BIT(INNER_SRC_IP); + + if (!spec->ip4dst) + *unused_tuple |= BIT(INNER_DST_IP); + + if (!spec->tos) + *unused_tuple |= BIT(INNER_IP_TOS); + + if (!spec->l4_proto) + *unused_tuple |= BIT(INNER_IP_PROTO); + + return 0; +} + static int hclge_fd_check_tcpip6_tuple(struct ethtool_tcpip6_spec *spec, u32 *unused_tuple) { @@ -6194,6 +6249,45 @@ static int hclge_fd_check_ip6_tuple(struct ethtool_usrip6_spec *spec, return 0; } +static int hclge_fd_check_vxlan6_tuple(struct ethtool_rx_flow_spec *fs, + u32 *unused_tuple) +{ + struct ethtool_vxlan6_spec *spec = &fs->h_u.vxlan_ip6_spec; + struct ethtool_vxlan6_spec *mask = &fs->m_u.vxlan_ip6_spec; + + /* Vni is only 24 bits and must be greater than 0, and it can not be + * masked. + */ + if (!spec->vni || be32_to_cpu(spec->vni) >= VXLAN_N_VID || + mask->vni != HCLGE_FD_VXLAN_VNI_UNMASK || !unused_tuple) + return -EINVAL; + + *unused_tuple |= BIT(INNER_SRC_PORT) | BIT(INNER_DST_PORT); + + if (is_zero_ether_addr(spec->src)) + *unused_tuple |= BIT(INNER_SRC_MAC); + + if (is_zero_ether_addr(spec->dst)) + *unused_tuple |= BIT(INNER_DST_MAC); + + if (!spec->eth_type) + *unused_tuple |= BIT(INNER_ETH_TYPE); + + if (ipv6_addr_any((struct in6_addr *)spec->ip6src)) + *unused_tuple |= BIT(INNER_SRC_IP); + + if (ipv6_addr_any((struct in6_addr *)spec->ip6dst)) + *unused_tuple |= BIT(INNER_DST_IP); + + if (!spec->tclass) + *unused_tuple |= BIT(INNER_IP_TOS); + + if (!spec->l4_proto) + *unused_tuple |= BIT(INNER_IP_PROTO); + + return 0; +} + static int hclge_fd_check_ether_tuple(struct ethhdr *spec, u32 *unused_tuple) { if (!spec || !unused_tuple) @@ -6287,6 +6381,9 @@ static int hclge_fd_check_spec(struct hclge_dev *hdev, ret = hclge_fd_check_ip4_tuple(&fs->h_u.usr_ip4_spec, unused_tuple); break; + case VXLAN_V4_FLOW: + ret = hclge_fd_check_vxlan4_tuple(fs, unused_tuple); + break; case SCTP_V6_FLOW: case TCP_V6_FLOW: case UDP_V6_FLOW: @@ -6297,6 +6394,9 @@ static int hclge_fd_check_spec(struct hclge_dev *hdev, ret = hclge_fd_check_ip6_tuple(&fs->h_u.usr_ip6_spec, unused_tuple); break; + case VXLAN_V6_FLOW: + ret = hclge_fd_check_vxlan6_tuple(fs, unused_tuple); + break; case ETHER_FLOW: if (hdev->fd_cfg.fd_mode != HCLGE_FD_MODE_DEPTH_2K_WIDTH_400B_STAGE_1) { @@ -6391,6 +6491,68 @@ static int hclge_fd_update_rule_list(struct hclge_dev *hdev, return 0; } +static void hclge_fd_get_vxlan4_tuple(struct ethtool_rx_flow_spec *fs, + struct hclge_fd_rule *rule) +{ + struct ethtool_vxlan4_spec *h = &fs->h_u.vxlan_ip4_spec; + struct ethtool_vxlan4_spec *m = &fs->m_u.vxlan_ip4_spec; + + rule->tuples.outer_tun_vni = be32_to_cpu(h->vni); + rule->tuples_mask.outer_tun_vni = be32_to_cpu(m->vni); + + ether_addr_copy(rule->tuples.src_mac, h->src); + ether_addr_copy(rule->tuples_mask.src_mac, m->src); + + ether_addr_copy(rule->tuples.dst_mac, h->dst); + ether_addr_copy(rule->tuples_mask.dst_mac, m->dst); + + rule->tuples.ether_proto = be16_to_cpu(h->eth_type); + rule->tuples_mask.ether_proto = be16_to_cpu(m->eth_type); + + rule->tuples.ip_tos = h->tos; + rule->tuples_mask.ip_tos = m->tos; + + rule->tuples.ip_proto = h->l4_proto; + rule->tuples_mask.ip_proto = m->l4_proto; + + rule->tuples.src_ip[IPV4_INDEX] = be32_to_cpu(h->ip4src); + rule->tuples_mask.src_ip[IPV4_INDEX] = be32_to_cpu(m->ip4src); + + rule->tuples.dst_ip[IPV4_INDEX] = be32_to_cpu(h->ip4dst); + rule->tuples_mask.dst_ip[IPV4_INDEX] = be32_to_cpu(m->ip4dst); +} + +static void hclge_fd_get_vxlan6_tuple(struct ethtool_rx_flow_spec *fs, + struct hclge_fd_rule *rule) +{ + struct ethtool_vxlan6_spec *h = &fs->h_u.vxlan_ip6_spec; + struct ethtool_vxlan6_spec *m = &fs->m_u.vxlan_ip6_spec; + + rule->tuples.outer_tun_vni = be32_to_cpu(h->vni); + rule->tuples_mask.outer_tun_vni = be32_to_cpu(m->vni); + + ether_addr_copy(rule->tuples.src_mac, h->src); + ether_addr_copy(rule->tuples_mask.src_mac, m->src); + + ether_addr_copy(rule->tuples.dst_mac, h->dst); + ether_addr_copy(rule->tuples_mask.dst_mac, m->dst); + + rule->tuples.ether_proto = be16_to_cpu(h->eth_type); + rule->tuples_mask.ether_proto = be16_to_cpu(m->eth_type); + + rule->tuples.ip_tos = h->tclass; + rule->tuples_mask.ip_tos = m->tclass; + + rule->tuples.ip_proto = h->l4_proto; + rule->tuples_mask.ip_proto = m->l4_proto; + + be32_to_cpu_array(rule->tuples.src_ip, h->ip6src, IPV6_SIZE); + be32_to_cpu_array(rule->tuples_mask.src_ip, m->ip6src, IPV6_SIZE); + + be32_to_cpu_array(rule->tuples.dst_ip, h->ip6dst, IPV6_SIZE); + be32_to_cpu_array(rule->tuples_mask.dst_ip, m->ip6dst, IPV6_SIZE); +} + static int hclge_fd_get_tuple(struct hclge_dev *hdev, struct ethtool_rx_flow_spec *fs, struct hclge_fd_rule *rule) @@ -6424,7 +6586,6 @@ static int hclge_fd_get_tuple(struct hclge_dev *hdev, rule->tuples.ether_proto = ETH_P_IP; rule->tuples_mask.ether_proto = 0xFFFF; - break; case IP_USER_FLOW: rule->tuples.src_ip[IPV4_INDEX] = @@ -6445,7 +6606,9 @@ static int hclge_fd_get_tuple(struct hclge_dev *hdev, rule->tuples.ether_proto = ETH_P_IP; rule->tuples_mask.ether_proto = 0xFFFF; - + break; + case VXLAN_V4_FLOW: + hclge_fd_get_vxlan4_tuple(fs, rule); break; case SCTP_V6_FLOW: case TCP_V6_FLOW: @@ -6470,7 +6633,6 @@ static int hclge_fd_get_tuple(struct hclge_dev *hdev, rule->tuples.ether_proto = ETH_P_IPV6; rule->tuples_mask.ether_proto = 0xFFFF; - break; case IPV6_USER_FLOW: be32_to_cpu_array(rule->tuples.src_ip, @@ -6488,7 +6650,9 @@ static int hclge_fd_get_tuple(struct hclge_dev *hdev, rule->tuples.ether_proto = ETH_P_IPV6; rule->tuples_mask.ether_proto = 0xFFFF; - + break; + case VXLAN_V6_FLOW: + hclge_fd_get_vxlan6_tuple(fs, rule); break; case ETHER_FLOW: ether_addr_copy(rule->tuples.src_mac, @@ -6505,7 +6669,6 @@ static int hclge_fd_get_tuple(struct hclge_dev *hdev, be16_to_cpu(fs->h_u.ether_spec.h_proto); rule->tuples_mask.ether_proto = be16_to_cpu(fs->m_u.ether_spec.h_proto); - break; default: return -EOPNOTSUPP; @@ -6836,6 +6999,48 @@ static void hclge_fd_get_ip4_info(struct hclge_fd_rule *rule, spec->ip_ver = ETH_RX_NFC_IP4; } +static void hclge_fd_get_vxlan4_info(struct hclge_fd_rule *rule, + struct ethtool_vxlan4_spec *spec, + struct ethtool_vxlan4_spec *spec_mask) +{ + spec->vni = cpu_to_be32(rule->tuples.outer_tun_vni); + spec_mask->vni = rule->unused_tuple & BIT(OUTER_TUN_VNI) ? 0 : + cpu_to_be32(rule->tuples_mask.outer_tun_vni); + + ether_addr_copy(spec->src, rule->tuples.src_mac); + ether_addr_copy(spec->dst, rule->tuples.dst_mac); + + if (rule->unused_tuple & BIT(INNER_SRC_MAC)) + eth_zero_addr(spec_mask->src); + else + ether_addr_copy(spec_mask->src, rule->tuples_mask.src_mac); + + if (rule->unused_tuple & BIT(INNER_DST_MAC)) + eth_zero_addr(spec_mask->dst); + else + ether_addr_copy(spec_mask->dst, rule->tuples_mask.dst_mac); + + spec->eth_type = cpu_to_be16(rule->tuples.ether_proto); + spec_mask->eth_type = rule->unused_tuple & BIT(INNER_ETH_TYPE) ? 0 : + cpu_to_be16(rule->tuples_mask.ether_proto); + + spec->tos = rule->tuples.ip_tos; + spec_mask->tos = rule->unused_tuple & BIT(INNER_IP_TOS) ? 0 : + rule->tuples_mask.ip_tos; + + spec->l4_proto = rule->tuples.ip_proto; + spec_mask->l4_proto = rule->unused_tuple & BIT(INNER_IP_PROTO) ? 0 : + rule->tuples_mask.ip_proto; + + spec->ip4src = cpu_to_be32(rule->tuples.src_ip[IPV4_INDEX]); + spec_mask->ip4src = rule->unused_tuple & BIT(INNER_SRC_IP) ? 0 : + cpu_to_be32(rule->tuples_mask.src_ip[IPV4_INDEX]); + + spec->ip4dst = cpu_to_be32(rule->tuples.dst_ip[IPV4_INDEX]); + spec_mask->ip4dst = rule->unused_tuple & BIT(INNER_DST_IP) ? 0 : + cpu_to_be32(rule->tuples_mask.dst_ip[IPV4_INDEX]); +} + static void hclge_fd_get_tcpip6_info(struct hclge_fd_rule *rule, struct ethtool_tcpip6_spec *spec, struct ethtool_tcpip6_spec *spec_mask) @@ -6888,6 +7093,56 @@ static void hclge_fd_get_ip6_info(struct hclge_fd_rule *rule, 0 : rule->tuples_mask.ip_proto; } +static void hclge_fd_get_vxlan6_info(struct hclge_fd_rule *rule, + struct ethtool_vxlan6_spec *spec, + struct ethtool_vxlan6_spec *spec_mask) +{ + spec->vni = cpu_to_be32(rule->tuples.outer_tun_vni); + spec_mask->vni = rule->unused_tuple & BIT(OUTER_TUN_VNI) ? 0 : + cpu_to_be32(rule->tuples_mask.outer_tun_vni); + + ether_addr_copy(spec->src, rule->tuples.src_mac); + ether_addr_copy(spec->dst, rule->tuples.dst_mac); + + if (rule->unused_tuple & BIT(INNER_SRC_MAC)) + eth_zero_addr(spec_mask->src); + else + ether_addr_copy(spec_mask->src, rule->tuples_mask.src_mac); + + if (rule->unused_tuple & BIT(INNER_DST_MAC)) + eth_zero_addr(spec_mask->dst); + else + ether_addr_copy(spec_mask->dst, rule->tuples_mask.dst_mac); + + spec->eth_type = cpu_to_be16(rule->tuples.ether_proto); + spec_mask->eth_type = rule->unused_tuple & BIT(INNER_ETH_TYPE) ? 0 : + cpu_to_be16(rule->tuples_mask.ether_proto); + + spec->tclass = rule->tuples.ip_tos; + spec_mask->tclass = rule->unused_tuple & BIT(INNER_IP_TOS) ? 0 : + rule->tuples_mask.ip_tos; + + spec->l4_proto = rule->tuples.ip_proto; + spec_mask->l4_proto = rule->unused_tuple & BIT(INNER_IP_PROTO) ? 0 : + rule->tuples_mask.ip_proto; + + cpu_to_be32_array(spec->ip6src, + rule->tuples.src_ip, IPV6_SIZE); + cpu_to_be32_array(spec->ip6dst, + rule->tuples.dst_ip, IPV6_SIZE); + if (rule->unused_tuple & BIT(INNER_SRC_IP)) + memset(spec_mask->ip6src, 0, sizeof(spec_mask->ip6src)); + else + cpu_to_be32_array(spec_mask->ip6src, rule->tuples_mask.src_ip, + IPV6_SIZE); + + if (rule->unused_tuple & BIT(INNER_DST_IP)) + memset(spec_mask->ip6dst, 0, sizeof(spec_mask->ip6dst)); + else + cpu_to_be32_array(spec_mask->ip6dst, rule->tuples_mask.dst_ip, + IPV6_SIZE); +} + static void hclge_fd_get_ether_info(struct hclge_fd_rule *rule, struct ethhdr *spec, struct ethhdr *spec_mask) @@ -6969,6 +7224,10 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle, hclge_fd_get_ip4_info(rule, &fs->h_u.usr_ip4_spec, &fs->m_u.usr_ip4_spec); break; + case VXLAN_V4_FLOW: + hclge_fd_get_vxlan4_info(rule, &fs->h_u.vxlan_ip4_spec, + &fs->m_u.vxlan_ip4_spec); + break; case SCTP_V6_FLOW: case TCP_V6_FLOW: case UDP_V6_FLOW: @@ -6979,6 +7238,10 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle, hclge_fd_get_ip6_info(rule, &fs->h_u.usr_ip6_spec, &fs->m_u.usr_ip6_spec); break; + case VXLAN_V6_FLOW: + hclge_fd_get_vxlan6_info(rule, &fs->h_u.vxlan_ip6_spec, + &fs->m_u.vxlan_ip6_spec); + break; /* The flow type of fd rule has been checked before adding in to rule * list. As other flow types have been handled, it must be ETHER_FLOW * for the default case diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 7c0e15b5b0e0..f100e9ad5842 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -651,6 +651,8 @@ struct key_info { #define MAX_KEY_BYTES (MAX_KEY_DWORDS * 4) #define MAX_META_DATA_LENGTH 32 +#define HCLGE_FD_VXLAN_VNI_UNMASK GENMASK(31, 0) + /* assigned by firmware, the real filter number for each pf may be less */ #define MAX_FD_FILTER_NUM 4096 #define HCLGE_ARFS_EXPIRE_INTERVAL 5UL @@ -707,6 +709,7 @@ struct hclge_fd_rule_tuples { u16 ether_proto; u8 ip_tos; u8 ip_proto; + u32 outer_tun_vni; }; struct hclge_fd_rule { -- 2.34.1