]> git.baikalelectronics.ru Git - kernel.git/commitdiff
octeontx2-pf: Add flow classification using IP next level protocol
authorNaveen Mamindlapalli <naveenm@marvell.com>
Mon, 11 Jan 2021 11:25:37 +0000 (16:55 +0530)
committerJakub Kicinski <kuba@kernel.org>
Thu, 14 Jan 2021 03:11:48 +0000 (19:11 -0800)
This patch adds support to install flow rules using ipv4 proto or
ipv6 next header field to distinguish between tcp/udp/sctp/esp/ah
flows when user doesn't specify the other match creteria related to
the flow such as tcp/udp/sctp source port and destination port, ah/esp
spi value. This is achieved by matching the layer type extracted by
NPC HW into the search key. Modified the driver to use Ethertype as
match criteria when user doesn't specify source IP address and dest
IP address. The esp/ah flow rule matching using security parameter
index (spi) is not supported as of now since the field is not extracted
into MCAM search key. Modified npc_check_field function to return bool.

Signed-off-by: Naveen Mamindlapalli <naveenm@marvell.com>
Signed-off-by: Sunil Goutham <sgoutham@marvell.com>
Link: https://lore.kernel.org/r/20210111112537.3277-1-naveenm@marvell.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/marvell/octeontx2/af/npc.h
drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c

index a1f79445db713e6c3aa0ca85e623eddc043380ce..3c640f6aba92289a3329897f477269b73ade6941 100644 (file)
@@ -162,6 +162,11 @@ enum key_fields {
        NPC_DIP_IPV4,
        NPC_SIP_IPV6,
        NPC_DIP_IPV6,
+       NPC_IPPROTO_TCP,
+       NPC_IPPROTO_UDP,
+       NPC_IPPROTO_SCTP,
+       NPC_IPPROTO_AH,
+       NPC_IPPROTO_ESP,
        NPC_SPORT_TCP,
        NPC_DPORT_TCP,
        NPC_SPORT_UDP,
index d27543c1a166a99ba8590412fc5bc5e4dbd2e92c..0c6882e84d425b6fb0057804634793bba60cedda 100644 (file)
@@ -1757,6 +1757,7 @@ static void rvu_dbg_npc_mcam_show_flows(struct seq_file *s,
                        seq_printf(s, "mask 0x%x\n", ntohs(rule->mask.dport));
                        break;
                default:
+                       seq_puts(s, "\n");
                        break;
                }
        }
index 14832b66d1fec47f1e0f4d8f52f392d1ccfdb017..7572321cea79e387f398ef7754563444746575ab 100644 (file)
@@ -26,6 +26,11 @@ static const char * const npc_flow_names[] = {
        [NPC_DIP_IPV4]  = "ipv4 destination ip",
        [NPC_SIP_IPV6]  = "ipv6 source ip",
        [NPC_DIP_IPV6]  = "ipv6 destination ip",
+       [NPC_IPPROTO_TCP] = "ip proto tcp",
+       [NPC_IPPROTO_UDP] = "ip proto udp",
+       [NPC_IPPROTO_SCTP] = "ip proto sctp",
+       [NPC_IPPROTO_AH] = "ip proto AH",
+       [NPC_IPPROTO_ESP] = "ip proto ESP",
        [NPC_SPORT_TCP] = "tcp source port",
        [NPC_DPORT_TCP] = "tcp destination port",
        [NPC_SPORT_UDP] = "udp source port",
@@ -212,13 +217,13 @@ static bool npc_check_overlap(struct rvu *rvu, int blkaddr,
        return false;
 }
 
-static int npc_check_field(struct rvu *rvu, int blkaddr, enum key_fields type,
-                          u8 intf)
+static bool npc_check_field(struct rvu *rvu, int blkaddr, enum key_fields type,
+                           u8 intf)
 {
        if (!npc_is_field_present(rvu, type, intf) ||
            npc_check_overlap(rvu, blkaddr, type, 0, intf))
-               return -EOPNOTSUPP;
-       return 0;
+               return false;
+       return true;
 }
 
 static void npc_scan_parse_result(struct npc_mcam *mcam, u8 bit_number,
@@ -448,14 +453,13 @@ static void npc_set_features(struct rvu *rvu, int blkaddr, u8 intf)
        struct npc_mcam *mcam = &rvu->hw->mcam;
        u64 *features = &mcam->rx_features;
        u64 tcp_udp_sctp;
-       int err, hdr;
+       int hdr;
 
        if (is_npc_intf_tx(intf))
                features = &mcam->tx_features;
 
        for (hdr = NPC_DMAC; hdr < NPC_HEADER_FIELDS_MAX; hdr++) {
-               err = npc_check_field(rvu, blkaddr, hdr, intf);
-               if (!err)
+               if (npc_check_field(rvu, blkaddr, hdr, intf))
                        *features |= BIT_ULL(hdr);
        }
 
@@ -464,13 +468,26 @@ static void npc_set_features(struct rvu *rvu, int blkaddr, u8 intf)
                       BIT_ULL(NPC_SPORT_SCTP) | BIT_ULL(NPC_DPORT_SCTP);
 
        /* for tcp/udp/sctp corresponding layer type should be in the key */
-       if (*features & tcp_udp_sctp)
-               if (npc_check_field(rvu, blkaddr, NPC_LD, intf))
+       if (*features & tcp_udp_sctp) {
+               if (!npc_check_field(rvu, blkaddr, NPC_LD, intf))
                        *features &= ~tcp_udp_sctp;
+               else
+                       *features |= BIT_ULL(NPC_IPPROTO_TCP) |
+                                    BIT_ULL(NPC_IPPROTO_UDP) |
+                                    BIT_ULL(NPC_IPPROTO_SCTP);
+       }
+
+       /* for AH, check if corresponding layer type is present in the key */
+       if (npc_check_field(rvu, blkaddr, NPC_LD, intf))
+               *features |= BIT_ULL(NPC_IPPROTO_AH);
+
+       /* for ESP, check if corresponding layer type is present in the key */
+       if (npc_check_field(rvu, blkaddr, NPC_LE, intf))
+               *features |= BIT_ULL(NPC_IPPROTO_ESP);
 
        /* for vlan corresponding layer type should be in the key */
        if (*features & BIT_ULL(NPC_OUTER_VID))
-               if (npc_check_field(rvu, blkaddr, NPC_LB, intf))
+               if (!npc_check_field(rvu, blkaddr, NPC_LB, intf))
                        *features &= ~BIT_ULL(NPC_OUTER_VID);
 }
 
@@ -743,13 +760,13 @@ static void npc_update_flow(struct rvu *rvu, struct mcam_entry *entry,
                return;
 
        /* For tcp/udp/sctp LTYPE should be present in entry */
-       if (features & (BIT_ULL(NPC_SPORT_TCP) | BIT_ULL(NPC_DPORT_TCP)))
+       if (features & BIT_ULL(NPC_IPPROTO_TCP))
                npc_update_entry(rvu, NPC_LD, entry, NPC_LT_LD_TCP,
                                 0, ~0ULL, 0, intf);
-       if (features & (BIT_ULL(NPC_SPORT_UDP) | BIT_ULL(NPC_DPORT_UDP)))
+       if (features & BIT_ULL(NPC_IPPROTO_UDP))
                npc_update_entry(rvu, NPC_LD, entry, NPC_LT_LD_UDP,
                                 0, ~0ULL, 0, intf);
-       if (features & (BIT_ULL(NPC_SPORT_SCTP) | BIT_ULL(NPC_DPORT_SCTP)))
+       if (features & BIT_ULL(NPC_IPPROTO_SCTP))
                npc_update_entry(rvu, NPC_LD, entry, NPC_LT_LD_SCTP,
                                 0, ~0ULL, 0, intf);
 
@@ -758,6 +775,15 @@ static void npc_update_flow(struct rvu *rvu, struct mcam_entry *entry,
                                 NPC_LT_LB_STAG_QINQ | NPC_LT_LB_CTAG, 0,
                                 NPC_LT_LB_STAG_QINQ & NPC_LT_LB_CTAG, 0, intf);
 
+       /* For AH, LTYPE should be present in entry */
+       if (features & BIT_ULL(NPC_IPPROTO_AH))
+               npc_update_entry(rvu, NPC_LD, entry, NPC_LT_LD_AH,
+                                0, ~0ULL, 0, intf);
+       /* For ESP, LTYPE should be present in entry */
+       if (features & BIT_ULL(NPC_IPPROTO_ESP))
+               npc_update_entry(rvu, NPC_LE, entry, NPC_LT_LE_ESP,
+                                0, ~0ULL, 0, intf);
+
 #define NPC_WRITE_FLOW(field, member, val_lo, val_hi, mask_lo, mask_hi)              \
 do {                                                                         \
        if (features & BIT_ULL((field))) {                                    \
index 6dd442d88d0e534cf95d2a4e5f80092a6fbb4a6f..d6b5bf247e31bf0420ea089d768e0a969cd89a47 100644 (file)
@@ -272,14 +272,16 @@ int otx2_get_all_flows(struct otx2_nic *pfvf, struct ethtool_rxnfc *nfc,
        return err;
 }
 
-static void otx2_prepare_ipv4_flow(struct ethtool_rx_flow_spec *fsp,
-                                  struct npc_install_flow_req *req,
-                                  u32 flow_type)
+static int otx2_prepare_ipv4_flow(struct ethtool_rx_flow_spec *fsp,
+                                 struct npc_install_flow_req *req,
+                                 u32 flow_type)
 {
        struct ethtool_usrip4_spec *ipv4_usr_mask = &fsp->m_u.usr_ip4_spec;
        struct ethtool_usrip4_spec *ipv4_usr_hdr = &fsp->h_u.usr_ip4_spec;
        struct ethtool_tcpip4_spec *ipv4_l4_mask = &fsp->m_u.tcp_ip4_spec;
        struct ethtool_tcpip4_spec *ipv4_l4_hdr = &fsp->h_u.tcp_ip4_spec;
+       struct ethtool_ah_espip4_spec *ah_esp_hdr = &fsp->h_u.ah_ip4_spec;
+       struct ethtool_ah_espip4_spec *ah_esp_mask = &fsp->m_u.ah_ip4_spec;
        struct flow_msg *pmask = &req->mask;
        struct flow_msg *pkt = &req->packet;
 
@@ -299,10 +301,16 @@ static void otx2_prepare_ipv4_flow(struct ethtool_rx_flow_spec *fsp,
                               sizeof(pmask->ip4dst));
                        req->features |= BIT_ULL(NPC_DIP_IPV4);
                }
+               pkt->etype = cpu_to_be16(ETH_P_IP);
+               pmask->etype = cpu_to_be16(0xFFFF);
+               req->features |= BIT_ULL(NPC_ETYPE);
                break;
        case TCP_V4_FLOW:
        case UDP_V4_FLOW:
        case SCTP_V4_FLOW:
+               pkt->etype = cpu_to_be16(ETH_P_IP);
+               pmask->etype = cpu_to_be16(0xFFFF);
+               req->features |= BIT_ULL(NPC_ETYPE);
                if (ipv4_l4_mask->ip4src) {
                        memcpy(&pkt->ip4src, &ipv4_l4_hdr->ip4src,
                               sizeof(pkt->ip4src));
@@ -341,20 +349,60 @@ static void otx2_prepare_ipv4_flow(struct ethtool_rx_flow_spec *fsp,
                        else
                                req->features |= BIT_ULL(NPC_DPORT_SCTP);
                }
+               if (flow_type == UDP_V4_FLOW)
+                       req->features |= BIT_ULL(NPC_IPPROTO_UDP);
+               else if (flow_type == TCP_V4_FLOW)
+                       req->features |= BIT_ULL(NPC_IPPROTO_TCP);
+               else
+                       req->features |= BIT_ULL(NPC_IPPROTO_SCTP);
+               break;
+       case AH_V4_FLOW:
+       case ESP_V4_FLOW:
+               pkt->etype = cpu_to_be16(ETH_P_IP);
+               pmask->etype = cpu_to_be16(0xFFFF);
+               req->features |= BIT_ULL(NPC_ETYPE);
+               if (ah_esp_mask->ip4src) {
+                       memcpy(&pkt->ip4src, &ah_esp_hdr->ip4src,
+                              sizeof(pkt->ip4src));
+                       memcpy(&pmask->ip4src, &ah_esp_mask->ip4src,
+                              sizeof(pmask->ip4src));
+                       req->features |= BIT_ULL(NPC_SIP_IPV4);
+               }
+               if (ah_esp_mask->ip4dst) {
+                       memcpy(&pkt->ip4dst, &ah_esp_hdr->ip4dst,
+                              sizeof(pkt->ip4dst));
+                       memcpy(&pmask->ip4dst, &ah_esp_mask->ip4dst,
+                              sizeof(pmask->ip4dst));
+                       req->features |= BIT_ULL(NPC_DIP_IPV4);
+               }
+
+               /* NPC profile doesn't extract AH/ESP header fields */
+               if ((ah_esp_mask->spi & ah_esp_hdr->spi) ||
+                   (ah_esp_mask->tos & ah_esp_mask->tos))
+                       return -EOPNOTSUPP;
+
+               if (flow_type == AH_V4_FLOW)
+                       req->features |= BIT_ULL(NPC_IPPROTO_AH);
+               else
+                       req->features |= BIT_ULL(NPC_IPPROTO_ESP);
                break;
        default:
                break;
        }
+
+       return 0;
 }
 
-static void otx2_prepare_ipv6_flow(struct ethtool_rx_flow_spec *fsp,
-                                  struct npc_install_flow_req *req,
-                                  u32 flow_type)
+static int otx2_prepare_ipv6_flow(struct ethtool_rx_flow_spec *fsp,
+                                 struct npc_install_flow_req *req,
+                                 u32 flow_type)
 {
        struct ethtool_usrip6_spec *ipv6_usr_mask = &fsp->m_u.usr_ip6_spec;
        struct ethtool_usrip6_spec *ipv6_usr_hdr = &fsp->h_u.usr_ip6_spec;
        struct ethtool_tcpip6_spec *ipv6_l4_mask = &fsp->m_u.tcp_ip6_spec;
        struct ethtool_tcpip6_spec *ipv6_l4_hdr = &fsp->h_u.tcp_ip6_spec;
+       struct ethtool_ah_espip6_spec *ah_esp_hdr = &fsp->h_u.ah_ip6_spec;
+       struct ethtool_ah_espip6_spec *ah_esp_mask = &fsp->m_u.ah_ip6_spec;
        struct flow_msg *pmask = &req->mask;
        struct flow_msg *pkt = &req->packet;
 
@@ -374,10 +422,16 @@ static void otx2_prepare_ipv6_flow(struct ethtool_rx_flow_spec *fsp,
                               sizeof(pmask->ip6dst));
                        req->features |= BIT_ULL(NPC_DIP_IPV6);
                }
+               pkt->etype = cpu_to_be16(ETH_P_IPV6);
+               pmask->etype = cpu_to_be16(0xFFFF);
+               req->features |= BIT_ULL(NPC_ETYPE);
                break;
        case TCP_V6_FLOW:
        case UDP_V6_FLOW:
        case SCTP_V6_FLOW:
+               pkt->etype = cpu_to_be16(ETH_P_IPV6);
+               pmask->etype = cpu_to_be16(0xFFFF);
+               req->features |= BIT_ULL(NPC_ETYPE);
                if (!ipv6_addr_any((struct in6_addr *)ipv6_l4_mask->ip6src)) {
                        memcpy(&pkt->ip6src, &ipv6_l4_hdr->ip6src,
                               sizeof(pkt->ip6src));
@@ -416,10 +470,47 @@ static void otx2_prepare_ipv6_flow(struct ethtool_rx_flow_spec *fsp,
                        else
                                req->features |= BIT_ULL(NPC_DPORT_SCTP);
                }
+               if (flow_type == UDP_V6_FLOW)
+                       req->features |= BIT_ULL(NPC_IPPROTO_UDP);
+               else if (flow_type == TCP_V6_FLOW)
+                       req->features |= BIT_ULL(NPC_IPPROTO_TCP);
+               else
+                       req->features |= BIT_ULL(NPC_IPPROTO_SCTP);
                break;
+       case AH_V6_FLOW:
+       case ESP_V6_FLOW:
+               pkt->etype = cpu_to_be16(ETH_P_IPV6);
+               pmask->etype = cpu_to_be16(0xFFFF);
+               req->features |= BIT_ULL(NPC_ETYPE);
+               if (!ipv6_addr_any((struct in6_addr *)ah_esp_hdr->ip6src)) {
+                       memcpy(&pkt->ip6src, &ah_esp_hdr->ip6src,
+                              sizeof(pkt->ip6src));
+                       memcpy(&pmask->ip6src, &ah_esp_mask->ip6src,
+                              sizeof(pmask->ip6src));
+                       req->features |= BIT_ULL(NPC_SIP_IPV6);
+               }
+               if (!ipv6_addr_any((struct in6_addr *)ah_esp_hdr->ip6dst)) {
+                       memcpy(&pkt->ip6dst, &ah_esp_hdr->ip6dst,
+                              sizeof(pkt->ip6dst));
+                       memcpy(&pmask->ip6dst, &ah_esp_mask->ip6dst,
+                              sizeof(pmask->ip6dst));
+                       req->features |= BIT_ULL(NPC_DIP_IPV6);
+               }
+
+               /* NPC profile doesn't extract AH/ESP header fields */
+               if ((ah_esp_mask->spi & ah_esp_hdr->spi) ||
+                   (ah_esp_mask->tclass & ah_esp_mask->tclass))
+                       return -EOPNOTSUPP;
+
+               if (flow_type == AH_V6_FLOW)
+                       req->features |= BIT_ULL(NPC_IPPROTO_AH);
+               else
+                       req->features |= BIT_ULL(NPC_IPPROTO_ESP);
        default:
                break;
        }
+
+       return 0;
 }
 
 int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp,
@@ -430,6 +521,7 @@ int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp,
        struct flow_msg *pmask = &req->mask;
        struct flow_msg *pkt = &req->packet;
        u32 flow_type;
+       int ret;
 
        flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
        switch (flow_type) {
@@ -457,13 +549,21 @@ int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp,
        case TCP_V4_FLOW:
        case UDP_V4_FLOW:
        case SCTP_V4_FLOW:
-               otx2_prepare_ipv4_flow(fsp, req, flow_type);
+       case AH_V4_FLOW:
+       case ESP_V4_FLOW:
+               ret = otx2_prepare_ipv4_flow(fsp, req, flow_type);
+               if (ret)
+                       return ret;
                break;
        case IPV6_USER_FLOW:
        case TCP_V6_FLOW:
        case UDP_V6_FLOW:
        case SCTP_V6_FLOW:
-               otx2_prepare_ipv6_flow(fsp, req, flow_type);
+       case AH_V6_FLOW:
+       case ESP_V6_FLOW:
+               ret = otx2_prepare_ipv6_flow(fsp, req, flow_type);
+               if (ret)
+                       return ret;
                break;
        default:
                return -EOPNOTSUPP;