]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bnxt_en: Enhance ethtool ntuple support for ip flows besides TCP/UDP
authorVikas Gupta <vikas.gupta@broadcom.com>
Mon, 5 Feb 2024 22:31:54 +0000 (14:31 -0800)
committerJakub Kicinski <kuba@kernel.org>
Fri, 9 Feb 2024 20:37:41 +0000 (12:37 -0800)
Enable flow type ipv4/ipv6
1) for protocols ICMPV4 and ICMPV6.
2) for wildcard match. Wildcard matches to TCP/UDP/ICMP.
   Note that, IPPROTO_RAW(255) i.e. a reserved protocol
   considered for a wildcard.

Reviewed-by: Andy Gospodarek <andrew.gospodarek@broadcom.com>
Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
Signed-off-by: Vikas Gupta <vikas.gupta@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Link: https://lore.kernel.org/r/20240205223202.25341-6-michael.chan@broadcom.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h

index 0d65d45740450d13dc6d981209eb0e15e5043475..027e3601d7612441158c19864d7d48b38548208e 100644 (file)
@@ -8891,6 +8891,10 @@ static int bnxt_hwrm_cfa_adv_flow_mgnt_qcaps(struct bnxt *bp)
            CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_RFS_RING_TBL_IDX_V2_SUPPORTED)
                bp->fw_cap |= BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2;
 
+       if (flags &
+           CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_RX_EXT_IP_PROTO_SUPPORTED)
+               bp->fw_cap |= BNXT_FW_CAP_CFA_NTUPLE_RX_EXT_IP_PROTO;
+
 hwrm_cfa_adv_qcaps_exit:
        hwrm_req_drop(bp, req);
        return rc;
index aae180fa63b7a31f371553d26a7e19a033d58daa..16f18c70c7bbe4ac0ea98fddfc5a10b4d8f3ffcb 100644 (file)
@@ -2302,6 +2302,7 @@ struct bnxt {
        #define BNXT_FW_CAP_PRE_RESV_VNICS              BIT_ULL(35)
        #define BNXT_FW_CAP_BACKING_STORE_V2            BIT_ULL(36)
        #define BNXT_FW_CAP_VNIC_TUNNEL_TPA             BIT_ULL(37)
+       #define BNXT_FW_CAP_CFA_NTUPLE_RX_EXT_IP_PROTO  BIT_ULL(38)
 
        u32                     fw_dbg_cap;
 
index 408a086f62aed50fa48652930f55c14a7ed0a1cd..5a100aeb2b7889be708e010f95ef00ebd8ab65b4 100644 (file)
@@ -1130,28 +1130,50 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd)
        fkeys = &fltr->fkeys;
        fmasks = &fltr->fmasks;
        if (fkeys->basic.n_proto == htons(ETH_P_IP)) {
-               if (fkeys->basic.ip_proto == IPPROTO_TCP)
+               if (fkeys->basic.ip_proto == IPPROTO_ICMP ||
+                   fkeys->basic.ip_proto == IPPROTO_RAW) {
+                       fs->flow_type = IP_USER_FLOW;
+                       fs->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
+                       if (fkeys->basic.ip_proto == IPPROTO_ICMP)
+                               fs->h_u.usr_ip4_spec.proto = IPPROTO_ICMP;
+                       else
+                               fs->h_u.usr_ip4_spec.proto = IPPROTO_RAW;
+                       fs->m_u.usr_ip4_spec.proto = BNXT_IP_PROTO_FULL_MASK;
+               } else if (fkeys->basic.ip_proto == IPPROTO_TCP) {
                        fs->flow_type = TCP_V4_FLOW;
-               else if (fkeys->basic.ip_proto == IPPROTO_UDP)
+               } else if (fkeys->basic.ip_proto == IPPROTO_UDP) {
                        fs->flow_type = UDP_V4_FLOW;
-               else
+               } else {
                        goto fltr_err;
+               }
 
                fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src;
                fs->m_u.tcp_ip4_spec.ip4src = fmasks->addrs.v4addrs.src;
                fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst;
                fs->m_u.tcp_ip4_spec.ip4dst = fmasks->addrs.v4addrs.dst;
-               fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src;
-               fs->m_u.tcp_ip4_spec.psrc = fmasks->ports.src;
-               fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst;
-               fs->m_u.tcp_ip4_spec.pdst = fmasks->ports.dst;
+               if (fs->flow_type == TCP_V4_FLOW ||
+                   fs->flow_type == UDP_V4_FLOW) {
+                       fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src;
+                       fs->m_u.tcp_ip4_spec.psrc = fmasks->ports.src;
+                       fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst;
+                       fs->m_u.tcp_ip4_spec.pdst = fmasks->ports.dst;
+               }
        } else {
-               if (fkeys->basic.ip_proto == IPPROTO_TCP)
+               if (fkeys->basic.ip_proto == IPPROTO_ICMPV6 ||
+                   fkeys->basic.ip_proto == IPPROTO_RAW) {
+                       fs->flow_type = IPV6_USER_FLOW;
+                       if (fkeys->basic.ip_proto == IPPROTO_ICMPV6)
+                               fs->h_u.usr_ip6_spec.l4_proto = IPPROTO_ICMPV6;
+                       else
+                               fs->h_u.usr_ip6_spec.l4_proto = IPPROTO_RAW;
+                       fs->m_u.usr_ip6_spec.l4_proto = BNXT_IP_PROTO_FULL_MASK;
+               } else if (fkeys->basic.ip_proto == IPPROTO_TCP) {
                        fs->flow_type = TCP_V6_FLOW;
-               else if (fkeys->basic.ip_proto == IPPROTO_UDP)
+               } else if (fkeys->basic.ip_proto == IPPROTO_UDP) {
                        fs->flow_type = UDP_V6_FLOW;
-               else
+               } else {
                        goto fltr_err;
+               }
 
                *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] =
                        fkeys->addrs.v6addrs.src;
@@ -1161,10 +1183,13 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd)
                        fkeys->addrs.v6addrs.dst;
                *(struct in6_addr *)&fs->m_u.tcp_ip6_spec.ip6dst[0] =
                        fmasks->addrs.v6addrs.dst;
-               fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src;
-               fs->m_u.tcp_ip6_spec.psrc = fmasks->ports.src;
-               fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst;
-               fs->m_u.tcp_ip6_spec.pdst = fmasks->ports.dst;
+               if (fs->flow_type == TCP_V6_FLOW ||
+                   fs->flow_type == UDP_V6_FLOW) {
+                       fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src;
+                       fs->m_u.tcp_ip6_spec.psrc = fmasks->ports.src;
+                       fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst;
+                       fs->m_u.tcp_ip6_spec.pdst = fmasks->ports.dst;
+               }
        }
 
        fs->ring_cookie = fltr->base.rxq;
@@ -1228,6 +1253,28 @@ static int bnxt_add_l2_cls_rule(struct bnxt *bp,
        return rc;
 }
 
+static bool bnxt_verify_ntuple_ip4_flow(struct ethtool_usrip4_spec *ip_spec,
+                                       struct ethtool_usrip4_spec *ip_mask)
+{
+       if (ip_mask->l4_4_bytes || ip_mask->tos ||
+           ip_spec->ip_ver != ETH_RX_NFC_IP4 ||
+           ip_mask->proto != BNXT_IP_PROTO_FULL_MASK ||
+           (ip_spec->proto != IPPROTO_RAW && ip_spec->proto != IPPROTO_ICMP))
+               return false;
+       return true;
+}
+
+static bool bnxt_verify_ntuple_ip6_flow(struct ethtool_usrip6_spec *ip_spec,
+                                       struct ethtool_usrip6_spec *ip_mask)
+{
+       if (ip_mask->l4_4_bytes || ip_mask->tclass ||
+           ip_mask->l4_proto != BNXT_IP_PROTO_FULL_MASK ||
+           (ip_spec->l4_proto != IPPROTO_RAW &&
+            ip_spec->l4_proto != IPPROTO_ICMPV6))
+               return false;
+       return true;
+}
+
 static int bnxt_add_ntuple_cls_rule(struct bnxt *bp,
                                    struct ethtool_rx_flow_spec *fs)
 {
@@ -1247,6 +1294,18 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp,
        if ((flow_type & (FLOW_MAC_EXT | FLOW_EXT)) || vf)
                return -EOPNOTSUPP;
 
+       if (flow_type == IP_USER_FLOW) {
+               if (!bnxt_verify_ntuple_ip4_flow(&fs->h_u.usr_ip4_spec,
+                                                &fs->m_u.usr_ip4_spec))
+                       return -EOPNOTSUPP;
+       }
+
+       if (flow_type == IPV6_USER_FLOW) {
+               if (!bnxt_verify_ntuple_ip6_flow(&fs->h_u.usr_ip6_spec,
+                                                &fs->m_u.usr_ip6_spec))
+                       return -EOPNOTSUPP;
+       }
+
        new_fltr = kzalloc(sizeof(*new_fltr), GFP_KERNEL);
        if (!new_fltr)
                return -ENOMEM;
@@ -1259,6 +1318,18 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp,
 
        rc = -EOPNOTSUPP;
        switch (flow_type) {
+       case IP_USER_FLOW: {
+               struct ethtool_usrip4_spec *ip_spec = &fs->h_u.usr_ip4_spec;
+               struct ethtool_usrip4_spec *ip_mask = &fs->m_u.usr_ip4_spec;
+
+               fkeys->basic.ip_proto = ip_spec->proto;
+               fkeys->basic.n_proto = htons(ETH_P_IP);
+               fkeys->addrs.v4addrs.src = ip_spec->ip4src;
+               fmasks->addrs.v4addrs.src = ip_mask->ip4src;
+               fkeys->addrs.v4addrs.dst = ip_spec->ip4dst;
+               fmasks->addrs.v4addrs.dst = ip_mask->ip4dst;
+               break;
+       }
        case TCP_V4_FLOW:
        case UDP_V4_FLOW: {
                struct ethtool_tcpip4_spec *ip_spec = &fs->h_u.tcp_ip4_spec;
@@ -1278,6 +1349,18 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp,
                fmasks->ports.dst = ip_mask->pdst;
                break;
        }
+       case IPV6_USER_FLOW: {
+               struct ethtool_usrip6_spec *ip_spec = &fs->h_u.usr_ip6_spec;
+               struct ethtool_usrip6_spec *ip_mask = &fs->m_u.usr_ip6_spec;
+
+               fkeys->basic.ip_proto = ip_spec->l4_proto;
+               fkeys->basic.n_proto = htons(ETH_P_IPV6);
+               fkeys->addrs.v6addrs.src = *(struct in6_addr *)&ip_spec->ip6src;
+               fmasks->addrs.v6addrs.src = *(struct in6_addr *)&ip_mask->ip6src;
+               fkeys->addrs.v6addrs.dst = *(struct in6_addr *)&ip_spec->ip6dst;
+               fmasks->addrs.v6addrs.dst = *(struct in6_addr *)&ip_mask->ip6dst;
+               break;
+       }
        case TCP_V6_FLOW:
        case UDP_V6_FLOW: {
                struct ethtool_tcpip6_spec *ip_spec = &fs->h_u.tcp_ip6_spec;
@@ -1349,6 +1432,15 @@ static int bnxt_srxclsrlins(struct bnxt *bp, struct ethtool_rxnfc *cmd)
        if (fs->location != RX_CLS_LOC_ANY)
                return -EINVAL;
 
+       flow_type = fs->flow_type;
+       if ((flow_type == IP_USER_FLOW ||
+            flow_type == IPV6_USER_FLOW) &&
+           !(bp->fw_cap & BNXT_FW_CAP_CFA_NTUPLE_RX_EXT_IP_PROTO))
+               return -EOPNOTSUPP;
+       if (flow_type & (FLOW_MAC_EXT | FLOW_RSS))
+               return -EINVAL;
+       flow_type &= ~FLOW_EXT;
+
        ring = ethtool_get_flow_spec_ring(fs->ring_cookie);
        vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie);
        if (BNXT_VF(bp) && vf)
@@ -1358,10 +1450,6 @@ static int bnxt_srxclsrlins(struct bnxt *bp, struct ethtool_rxnfc *cmd)
        if (!vf && ring >= bp->rx_nr_rings)
                return -EINVAL;
 
-       flow_type = fs->flow_type;
-       if (flow_type & (FLOW_MAC_EXT | FLOW_RSS))
-               return -EINVAL;
-       flow_type &= ~FLOW_EXT;
        if (flow_type == ETHER_FLOW)
                rc = bnxt_add_l2_cls_rule(bp, fs);
        else
index 0ea0f4a36a040348e205231cb02666734a9b6878..e2ee030237d4a8753c0653eb0612e34b538dcc6a 100644 (file)
@@ -43,6 +43,8 @@ struct bnxt_led_cfg {
 
 #define BNXT_PXP_REG_LEN       0x3110
 
+#define BNXT_IP_PROTO_FULL_MASK        0xFF
+
 extern const struct ethtool_ops bnxt_ethtool_ops;
 
 u32 bnxt_get_rxfh_indir_size(struct net_device *dev);