OSDN Git Service

octeontx2-pf: Add support to filter packet based on IP fragment
authorSuman Ghosh <sumang@marvell.com>
Thu, 24 Nov 2022 06:35:48 +0000 (12:05 +0530)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Nov 2022 11:06:23 +0000 (11:06 +0000)
1. Added support to filter packets based on IP fragment.
For IPv4 packets check for ip_flag == 0x20 (more fragment bit set).
For IPv6 packets check for next_header == 0x2c (next_header set to
'fragment header for IPv6')
2. Added configuration support from both "ethtool ntuple" and "tc flower".

Signed-off-by: Suman Ghosh <sumang@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/marvell/octeontx2/af/mbox.h
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_common.h
drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c

index c7c92c7..d2584eb 100644 (file)
@@ -1440,6 +1440,10 @@ struct flow_msg {
        u8 tc;
        __be16 sport;
        __be16 dport;
+       union {
+               u8 ip_flag;
+               u8 next_header;
+       };
 };
 
 struct npc_install_flow_req {
index d027c23..9beeead 100644 (file)
@@ -185,8 +185,10 @@ enum key_fields {
        NPC_VLAN_ETYPE_STAG, /* 0x88A8 */
        NPC_OUTER_VID,
        NPC_TOS,
+       NPC_IPFRAG_IPV4,
        NPC_SIP_IPV4,
        NPC_DIP_IPV4,
+       NPC_IPFRAG_IPV6,
        NPC_SIP_IPV6,
        NPC_DIP_IPV6,
        NPC_IPPROTO_TCP,
index 642e58a..cdb2e6d 100644 (file)
@@ -2799,6 +2799,14 @@ static void rvu_dbg_npc_mcam_show_flows(struct seq_file *s,
                        seq_printf(s, "%pI6 ", rule->packet.ip6dst);
                        seq_printf(s, "mask %pI6\n", rule->mask.ip6dst);
                        break;
+               case NPC_IPFRAG_IPV6:
+                       seq_printf(s, "0x%x ", rule->packet.next_header);
+                       seq_printf(s, "mask 0x%x\n", rule->mask.next_header);
+                       break;
+               case NPC_IPFRAG_IPV4:
+                       seq_printf(s, "0x%x ", rule->packet.ip_flag);
+                       seq_printf(s, "mask 0x%x\n", rule->mask.ip_flag);
+                       break;
                case NPC_SPORT_TCP:
                case NPC_SPORT_UDP:
                case NPC_SPORT_SCTP:
index f3fecd2..006beb5 100644 (file)
@@ -26,8 +26,10 @@ static const char * const npc_flow_names[] = {
        [NPC_VLAN_ETYPE_STAG] = "vlan ether type stag",
        [NPC_OUTER_VID] = "outer vlan id",
        [NPC_TOS]       = "tos",
+       [NPC_IPFRAG_IPV4] = "fragmented IPv4 header ",
        [NPC_SIP_IPV4]  = "ipv4 source ip",
        [NPC_DIP_IPV4]  = "ipv4 destination ip",
+       [NPC_IPFRAG_IPV6] = "fragmented IPv6 header ",
        [NPC_SIP_IPV6]  = "ipv6 source ip",
        [NPC_DIP_IPV6]  = "ipv6 destination ip",
        [NPC_IPPROTO_TCP] = "ip proto tcp",
@@ -484,8 +486,10 @@ do {                                                                              \
         * Example: Source IP is 4 bytes and starts at 12th byte of IP header
         */
        NPC_SCAN_HDR(NPC_TOS, NPC_LID_LC, NPC_LT_LC_IP, 1, 1);
+       NPC_SCAN_HDR(NPC_IPFRAG_IPV4, NPC_LID_LC, NPC_LT_LC_IP, 6, 1);
        NPC_SCAN_HDR(NPC_SIP_IPV4, NPC_LID_LC, NPC_LT_LC_IP, 12, 4);
        NPC_SCAN_HDR(NPC_DIP_IPV4, NPC_LID_LC, NPC_LT_LC_IP, 16, 4);
+       NPC_SCAN_HDR(NPC_IPFRAG_IPV6, NPC_LID_LC, NPC_LT_LC_IP6_EXT, 6, 1);
        NPC_SCAN_HDR(NPC_SIP_IPV6, NPC_LID_LC, NPC_LT_LC_IP6, 8, 16);
        NPC_SCAN_HDR(NPC_DIP_IPV6, NPC_LID_LC, NPC_LT_LC_IP6, 24, 16);
        NPC_SCAN_HDR(NPC_SPORT_UDP, NPC_LID_LD, NPC_LT_LD_UDP, 0, 2);
@@ -899,6 +903,8 @@ do {                                                                              \
        NPC_WRITE_FLOW(NPC_ETYPE, etype, ntohs(pkt->etype), 0,
                       ntohs(mask->etype), 0);
        NPC_WRITE_FLOW(NPC_TOS, tos, pkt->tos, 0, mask->tos, 0);
+       NPC_WRITE_FLOW(NPC_IPFRAG_IPV4, ip_flag, pkt->ip_flag, 0,
+                      mask->ip_flag, 0);
        NPC_WRITE_FLOW(NPC_SIP_IPV4, ip4src, ntohl(pkt->ip4src), 0,
                       ntohl(mask->ip4src), 0);
        NPC_WRITE_FLOW(NPC_DIP_IPV4, ip4dst, ntohl(pkt->ip4dst), 0,
@@ -919,6 +925,8 @@ do {                                                                              \
        NPC_WRITE_FLOW(NPC_OUTER_VID, vlan_tci, ntohs(pkt->vlan_tci), 0,
                       ntohs(mask->vlan_tci), 0);
 
+       NPC_WRITE_FLOW(NPC_IPFRAG_IPV6, next_header, pkt->next_header, 0,
+                      mask->next_header, 0);
        npc_update_ipv6_flow(rvu, entry, features, pkt, mask, output, intf);
        npc_update_vlan_features(rvu, entry, features, intf);
 
index 282db6f..99d0da7 100644 (file)
@@ -28,6 +28,9 @@
 #include "otx2_devlink.h"
 #include <rvu_trace.h>
 
+/* IPv4 flag more fragment bit */
+#define IPV4_FLAG_MORE                         0x20
+
 /* PCI device IDs */
 #define PCI_DEVID_OCTEONTX2_RVU_PF              0xA063
 #define PCI_DEVID_OCTEONTX2_RVU_VF             0xA064
index 13aa79e..684cb8e 100644 (file)
@@ -711,6 +711,11 @@ static int otx2_prepare_ipv6_flow(struct ethtool_rx_flow_spec *fsp,
                               sizeof(pmask->ip6dst));
                        req->features |= BIT_ULL(NPC_DIP_IPV6);
                }
+               if (ipv6_usr_hdr->l4_proto == IPPROTO_FRAGMENT) {
+                       pkt->next_header = ipv6_usr_hdr->l4_proto;
+                       pmask->next_header = ipv6_usr_mask->l4_proto;
+                       req->features |= BIT_ULL(NPC_IPFRAG_IPV6);
+               }
                pkt->etype = cpu_to_be16(ETH_P_IPV6);
                pmask->etype = cpu_to_be16(0xFFFF);
                req->features |= BIT_ULL(NPC_ETYPE);
@@ -891,10 +896,22 @@ static int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp,
                        req->features |= BIT_ULL(NPC_OUTER_VID);
                }
 
-               /* Not Drop/Direct to queue but use action in default entry */
-               if (fsp->m_ext.data[1] &&
-                   fsp->h_ext.data[1] == cpu_to_be32(OTX2_DEFAULT_ACTION))
-                       req->op = NIX_RX_ACTION_DEFAULT;
+               if (fsp->m_ext.data[1]) {
+                       if (flow_type == IP_USER_FLOW) {
+                               if (be32_to_cpu(fsp->h_ext.data[1]) != IPV4_FLAG_MORE)
+                                       return -EINVAL;
+
+                               pkt->ip_flag = be32_to_cpu(fsp->h_ext.data[1]);
+                               pmask->ip_flag = be32_to_cpu(fsp->m_ext.data[1]);
+                               req->features |= BIT_ULL(NPC_IPFRAG_IPV4);
+                       } else if (fsp->h_ext.data[1] ==
+                                       cpu_to_be32(OTX2_DEFAULT_ACTION)) {
+                               /* Not Drop/Direct to queue but use action
+                                * in default entry
+                                */
+                               req->op = NIX_RX_ACTION_DEFAULT;
+                       }
+               }
        }
 
        if (fsp->flow_type & FLOW_MAC_EXT &&
index e64318c..e421714 100644 (file)
@@ -532,6 +532,31 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
                        req->features |= BIT_ULL(NPC_IPPROTO_ICMP6);
        }
 
+       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
+               struct flow_match_control match;
+
+               flow_rule_match_control(rule, &match);
+               if (match.mask->flags & FLOW_DIS_FIRST_FRAG) {
+                       NL_SET_ERR_MSG_MOD(extack, "HW doesn't support frag first/later");
+                       return -EOPNOTSUPP;
+               }
+
+               if (match.mask->flags & FLOW_DIS_IS_FRAGMENT) {
+                       if (ntohs(flow_spec->etype) == ETH_P_IP) {
+                               flow_spec->ip_flag = IPV4_FLAG_MORE;
+                               flow_mask->ip_flag = 0xff;
+                               req->features |= BIT_ULL(NPC_IPFRAG_IPV4);
+                       } else if (ntohs(flow_spec->etype) == ETH_P_IPV6) {
+                               flow_spec->next_header = IPPROTO_FRAGMENT;
+                               flow_mask->next_header = 0xff;
+                               req->features |= BIT_ULL(NPC_IPFRAG_IPV6);
+                       } else {
+                               NL_SET_ERR_MSG_MOD(extack, "flow-type should be either IPv4 and IPv6");
+                               return -EOPNOTSUPP;
+                       }
+               }
+       }
+
        if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
                struct flow_match_eth_addrs match;