ice: Add support for PFCP hardware offload in switchdev
authorMarcin Szycik <marcin.szycik@linux.intel.com>
Wed, 27 Mar 2024 15:23:58 +0000 (16:23 +0100)
committerDavid S. Miller <davem@davemloft.net>
Mon, 1 Apr 2024 09:49:29 +0000 (10:49 +0100)
Add support for creating PFCP filters in switchdev mode. Add support
for parsing PFCP-specific tc options: S flag and SEID.

To create a PFCP filter, a special netdev must be created and passed
to tc command:

  ip link add pfcp0 type pfcp
  tc filter add dev eth0 ingress prio 1 flower pfcp_opts \
    1:123/ff:fffffffffffffff0 skip_hw action mirred egress redirect \
    dev pfcp0

Changes in iproute2 [1] are required to be able to use pfcp_opts in tc.

ICE COMMS package is required to create a filter as it contains PFCP
profiles.

Link: https://lore.kernel.org/netdev/20230614091758.11180-1-marcin.szycik@linux.intel.com
Signed-off-by: Marcin Szycik <marcin.szycik@linux.intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/intel/ice/ice_ddp.c
drivers/net/ethernet/intel/ice/ice_flex_type.h
drivers/net/ethernet/intel/ice/ice_protocol_type.h
drivers/net/ethernet/intel/ice/ice_switch.c
drivers/net/ethernet/intel/ice/ice_switch.h
drivers/net/ethernet/intel/ice/ice_tc_lib.c
drivers/net/ethernet/intel/ice/ice_tc_lib.h

index fc91c4d..2ffa11f 100644 (file)
@@ -721,6 +721,12 @@ static bool ice_is_gtp_c_profile(u16 prof_idx)
        }
 }
 
+static bool ice_is_pfcp_profile(u16 prof_idx)
+{
+       return prof_idx >= ICE_PROFID_IPV4_PFCP_NODE &&
+              prof_idx <= ICE_PROFID_IPV6_PFCP_SESSION;
+}
+
 /**
  * ice_get_sw_prof_type - determine switch profile type
  * @hw: pointer to the HW structure
@@ -738,6 +744,9 @@ static enum ice_prof_type ice_get_sw_prof_type(struct ice_hw *hw,
        if (ice_is_gtp_u_profile(prof_idx))
                return ICE_PROF_TUN_GTPU;
 
+       if (ice_is_pfcp_profile(prof_idx))
+               return ICE_PROF_TUN_PFCP;
+
        for (i = 0; i < hw->blk[ICE_BLK_SW].es.fvw; i++) {
                /* UDP tunnel will have UDP_OF protocol ID and VNI offset */
                if (fv->ew[i].prot_id == (u8)ICE_PROT_UDP_OF &&
index d427a79..817beca 100644 (file)
@@ -93,6 +93,7 @@ enum ice_tunnel_type {
        TNL_GRETAP,
        TNL_GTPC,
        TNL_GTPU,
+       TNL_PFCP,
        __TNL_TYPE_CNT,
        TNL_LAST = 0xFF,
        TNL_ALL = 0xFF,
@@ -358,7 +359,8 @@ enum ice_prof_type {
        ICE_PROF_TUN_GRE = 0x4,
        ICE_PROF_TUN_GTPU = 0x8,
        ICE_PROF_TUN_GTPC = 0x10,
-       ICE_PROF_TUN_ALL = 0x1E,
+       ICE_PROF_TUN_PFCP = 0x20,
+       ICE_PROF_TUN_ALL = 0x3E,
        ICE_PROF_ALL = 0xFF,
 };
 
index f6f2736..755a9c5 100644 (file)
@@ -43,6 +43,7 @@ enum ice_protocol_type {
        ICE_NVGRE,
        ICE_GTP,
        ICE_GTP_NO_PAY,
+       ICE_PFCP,
        ICE_PPPOE,
        ICE_L2TPV3,
        ICE_VLAN_EX,
@@ -61,6 +62,7 @@ enum ice_sw_tunnel_type {
        ICE_SW_TUN_NVGRE,
        ICE_SW_TUN_GTPU,
        ICE_SW_TUN_GTPC,
+       ICE_SW_TUN_PFCP,
        ICE_ALL_TUNNELS /* All tunnel types including NVGRE */
 };
 
@@ -202,6 +204,15 @@ struct ice_udp_gtp_hdr {
        u8 rsvrd;
 };
 
+struct ice_pfcp_hdr {
+       u8 flags;
+       u8 msg_type;
+       __be16 length;
+       __be64 seid;
+       __be32 seq;
+       u8 spare;
+} __packed __aligned(__alignof__(u16));
+
 struct ice_pppoe_hdr {
        u8 rsrvd_ver_type;
        u8 rsrvd_code;
@@ -418,6 +429,7 @@ union ice_prot_hdr {
        struct ice_udp_tnl_hdr tnl_hdr;
        struct ice_nvgre_hdr nvgre_hdr;
        struct ice_udp_gtp_hdr gtp_hdr;
+       struct ice_pfcp_hdr pfcp_hdr;
        struct ice_pppoe_hdr pppoe_hdr;
        struct ice_l2tpv3_sess_hdr l2tpv3_sess_hdr;
        struct ice_hw_metadata metadata;
index f1f9d6b..606c241 100644 (file)
@@ -42,6 +42,7 @@ enum {
        ICE_PKT_KMALLOC         = BIT(9),
        ICE_PKT_PPPOE           = BIT(10),
        ICE_PKT_L2TPV3          = BIT(11),
+       ICE_PKT_PFCP            = BIT(12),
 };
 
 struct ice_dummy_pkt_offsets {
@@ -1110,6 +1111,77 @@ ICE_DECLARE_PKT_TEMPLATE(ipv6_gtp) = {
        0x00, 0x00,
 };
 
+ICE_DECLARE_PKT_OFFSETS(pfcp_session_ipv4) = {
+       { ICE_MAC_OFOS,         0 },
+       { ICE_ETYPE_OL,         12 },
+       { ICE_IPV4_OFOS,        14 },
+       { ICE_UDP_ILOS,         34 },
+       { ICE_PFCP,             42 },
+       { ICE_PROTOCOL_LAST,    0 },
+};
+
+ICE_DECLARE_PKT_TEMPLATE(pfcp_session_ipv4) = {
+       0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x08, 0x00,             /* ICE_ETYPE_OL 12 */
+
+       0x45, 0x00, 0x00, 0x2c, /* ICE_IPV4_OFOS 14 */
+       0x00, 0x01, 0x00, 0x00,
+       0x00, 0x11, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x00, 0x00, 0x22, 0x65, /* ICE_UDP_ILOS 34 */
+       0x00, 0x18, 0x00, 0x00,
+
+       0x21, 0x01, 0x00, 0x0c, /* ICE_PFCP 42 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x00, 0x00,             /* 2 bytes for 4 byte alignment */
+};
+
+ICE_DECLARE_PKT_OFFSETS(pfcp_session_ipv6) = {
+       { ICE_MAC_OFOS,         0 },
+       { ICE_ETYPE_OL,         12 },
+       { ICE_IPV6_OFOS,        14 },
+       { ICE_UDP_ILOS,         54 },
+       { ICE_PFCP,             62 },
+       { ICE_PROTOCOL_LAST,    0 },
+};
+
+ICE_DECLARE_PKT_TEMPLATE(pfcp_session_ipv6) = {
+       0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x86, 0xdd,             /* ICE_ETYPE_OL 12 */
+
+       0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 14 */
+       0x00, 0x10, 0x11, 0x00, /* Next header UDP */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x00, 0x00, 0x22, 0x65, /* ICE_UDP_ILOS 54 */
+       0x00, 0x18, 0x00, 0x00,
+
+       0x21, 0x01, 0x00, 0x0c, /* ICE_PFCP 62 */
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00,
+
+       0x00, 0x00,             /* 2 bytes for 4 byte alignment */
+};
+
 ICE_DECLARE_PKT_OFFSETS(pppoe_ipv4_tcp) = {
        { ICE_MAC_OFOS,         0 },
        { ICE_ETYPE_OL,         12 },
@@ -1343,6 +1415,8 @@ static const struct ice_dummy_pkt_profile ice_dummy_pkt_profiles[] = {
        ICE_PKT_PROFILE(ipv4_gtpu_ipv4_tcp, ICE_PKT_TUN_GTPU),
        ICE_PKT_PROFILE(ipv6_gtp, ICE_PKT_TUN_GTPC | ICE_PKT_OUTER_IPV6),
        ICE_PKT_PROFILE(ipv4_gtpu_ipv4, ICE_PKT_TUN_GTPC),
+       ICE_PKT_PROFILE(pfcp_session_ipv6, ICE_PKT_PFCP | ICE_PKT_OUTER_IPV6),
+       ICE_PKT_PROFILE(pfcp_session_ipv4, ICE_PKT_PFCP),
        ICE_PKT_PROFILE(pppoe_ipv6_udp, ICE_PKT_PPPOE | ICE_PKT_OUTER_IPV6 |
                                        ICE_PKT_INNER_UDP),
        ICE_PKT_PROFILE(pppoe_ipv6_tcp, ICE_PKT_PPPOE | ICE_PKT_OUTER_IPV6),
@@ -4532,6 +4606,7 @@ static const struct ice_prot_ext_tbl_entry ice_prot_ext[ICE_PROTOCOL_LAST] = {
        ICE_PROTOCOL_ENTRY(ICE_NVGRE, 0, 2, 4, 6),
        ICE_PROTOCOL_ENTRY(ICE_GTP, 8, 10, 12, 14, 16, 18, 20, 22),
        ICE_PROTOCOL_ENTRY(ICE_GTP_NO_PAY, 8, 10, 12, 14),
+       ICE_PROTOCOL_ENTRY(ICE_PFCP, 8, 10, 12, 14, 16, 18, 20, 22),
        ICE_PROTOCOL_ENTRY(ICE_PPPOE, 0, 2, 4, 6),
        ICE_PROTOCOL_ENTRY(ICE_L2TPV3, 0, 2, 4, 6, 8, 10),
        ICE_PROTOCOL_ENTRY(ICE_VLAN_EX, 2, 0),
@@ -4565,6 +4640,7 @@ static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = {
        { ICE_NVGRE,            ICE_GRE_OF_HW },
        { ICE_GTP,              ICE_UDP_OF_HW },
        { ICE_GTP_NO_PAY,       ICE_UDP_ILOS_HW },
+       { ICE_PFCP,             ICE_UDP_ILOS_HW },
        { ICE_PPPOE,            ICE_PPPOE_HW },
        { ICE_L2TPV3,           ICE_L2TPV3_HW },
        { ICE_VLAN_EX,          ICE_VLAN_OF_HW },
@@ -5272,6 +5348,9 @@ ice_get_compat_fv_bitmap(struct ice_hw *hw, struct ice_adv_rule_info *rinfo,
        case ICE_SW_TUN_GTPC:
                prof_type = ICE_PROF_TUN_GTPC;
                break;
+       case ICE_SW_TUN_PFCP:
+               prof_type = ICE_PROF_TUN_PFCP;
+               break;
        case ICE_SW_TUN_AND_NON_TUN:
        default:
                prof_type = ICE_PROF_ALL;
@@ -5556,6 +5635,9 @@ ice_find_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
        case ICE_SW_TUN_VXLAN:
                match |= ICE_PKT_TUN_UDP;
                break;
+       case ICE_SW_TUN_PFCP:
+               match |= ICE_PKT_PFCP;
+               break;
        default:
                break;
        }
@@ -5696,6 +5778,9 @@ ice_fill_adv_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
                case ICE_GTP:
                        len = sizeof(struct ice_udp_gtp_hdr);
                        break;
+               case ICE_PFCP:
+                       len = sizeof(struct ice_pfcp_hdr);
+                       break;
                case ICE_PPPOE:
                        len = sizeof(struct ice_pppoe_hdr);
                        break;
index 89e6b18..322ef81 100644 (file)
@@ -22,6 +22,8 @@
 #define ICE_PROFID_IPV6_GTPC_NO_TEID                   45
 #define ICE_PROFID_IPV6_GTPU_TEID                      46
 #define ICE_PROFID_IPV6_GTPU_IPV6_TCP_INNER            70
+#define ICE_PROFID_IPV4_PFCP_NODE                      79
+#define ICE_PROFID_IPV6_PFCP_SESSION                   82
 
 #define ICE_SW_RULE_VSI_LIST_SIZE(s, n)                struct_size((s), vsi, (n))
 #define ICE_SW_RULE_RX_TX_HDR_SIZE(s, l)       struct_size((s), hdr_data, (l))
index 80797db..2f2fce2 100644 (file)
@@ -38,6 +38,9 @@ ice_tc_count_lkups(u32 flags, struct ice_tc_flower_lyr_2_4_hdrs *headers,
        if (flags & ICE_TC_FLWR_FIELD_GTP_OPTS)
                lkups_cnt++;
 
+       if (flags & ICE_TC_FLWR_FIELD_PFCP_OPTS)
+               lkups_cnt++;
+
        if (flags & (ICE_TC_FLWR_FIELD_ENC_SRC_IPV4 |
                     ICE_TC_FLWR_FIELD_ENC_DEST_IPV4 |
                     ICE_TC_FLWR_FIELD_ENC_SRC_IPV6 |
@@ -138,6 +141,8 @@ ice_proto_type_from_tunnel(enum ice_tunnel_type type)
                return ICE_GTP;
        case TNL_GTPC:
                return ICE_GTP_NO_PAY;
+       case TNL_PFCP:
+               return ICE_PFCP;
        default:
                return 0;
        }
@@ -157,6 +162,8 @@ ice_sw_type_from_tunnel(enum ice_tunnel_type type)
                return ICE_SW_TUN_GTPU;
        case TNL_GTPC:
                return ICE_SW_TUN_GTPC;
+       case TNL_PFCP:
+               return ICE_SW_TUN_PFCP;
        default:
                return ICE_NON_TUN;
        }
@@ -236,6 +243,22 @@ ice_tc_fill_tunnel_outer(u32 flags, struct ice_tc_flower_fltr *fltr,
                i++;
        }
 
+       if (flags & ICE_TC_FLWR_FIELD_PFCP_OPTS) {
+               struct ice_pfcp_hdr *hdr_h, *hdr_m;
+
+               hdr_h = &list[i].h_u.pfcp_hdr;
+               hdr_m = &list[i].m_u.pfcp_hdr;
+               list[i].type = ICE_PFCP;
+
+               hdr_h->flags = fltr->pfcp_meta_keys.type;
+               hdr_m->flags = fltr->pfcp_meta_masks.type & 0x01;
+
+               hdr_h->seid = fltr->pfcp_meta_keys.seid;
+               hdr_m->seid = fltr->pfcp_meta_masks.seid;
+
+               i++;
+       }
+
        if (flags & (ICE_TC_FLWR_FIELD_ENC_SRC_IPV4 |
                     ICE_TC_FLWR_FIELD_ENC_DEST_IPV4)) {
                list[i].type = ice_proto_type_from_ipv4(false);
@@ -366,8 +389,11 @@ ice_tc_fill_rules(struct ice_hw *hw, u32 flags,
        if (tc_fltr->tunnel_type != TNL_LAST) {
                i = ice_tc_fill_tunnel_outer(flags, tc_fltr, list, i);
 
-               headers = &tc_fltr->inner_headers;
-               inner = true;
+               /* PFCP is considered non-tunneled - don't swap headers. */
+               if (tc_fltr->tunnel_type != TNL_PFCP) {
+                       headers = &tc_fltr->inner_headers;
+                       inner = true;
+               }
        }
 
        if (flags & ICE_TC_FLWR_FIELD_ETH_TYPE_ID) {
@@ -621,6 +647,8 @@ static int ice_tc_tun_get_type(struct net_device *tunnel_dev)
         */
        if (netif_is_gtp(tunnel_dev))
                return TNL_GTPU;
+       if (netif_is_pfcp(tunnel_dev))
+               return TNL_PFCP;
        return TNL_LAST;
 }
 
@@ -1415,6 +1443,20 @@ ice_parse_tunnel_attr(struct net_device *dev, struct flow_rule *rule,
                fltr->flags |= ICE_TC_FLWR_FIELD_GTP_OPTS;
        }
 
+       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_OPTS) &&
+           fltr->tunnel_type == TNL_PFCP) {
+               struct flow_match_enc_opts match;
+
+               flow_rule_match_enc_opts(rule, &match);
+
+               memcpy(&fltr->pfcp_meta_keys, match.key->data,
+                      sizeof(struct pfcp_metadata));
+               memcpy(&fltr->pfcp_meta_masks, match.mask->data,
+                      sizeof(struct pfcp_metadata));
+
+               fltr->flags |= ICE_TC_FLWR_FIELD_PFCP_OPTS;
+       }
+
        return 0;
 }
 
@@ -1473,10 +1515,14 @@ ice_parse_cls_flower(struct net_device *filter_dev, struct ice_vsi *vsi,
                        return err;
                }
 
-               /* header pointers should point to the inner headers, outer
-                * header were already set by ice_parse_tunnel_attr
-                */
-               headers = &fltr->inner_headers;
+               /* PFCP is considered non-tunneled - don't swap headers. */
+               if (fltr->tunnel_type != TNL_PFCP) {
+                       /* Header pointers should point to the inner headers,
+                        * outer header were already set by
+                        * ice_parse_tunnel_attr().
+                        */
+                       headers = &fltr->inner_headers;
+               }
        } else if (dissector->used_keys &
                  (BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) |
                   BIT_ULL(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) |
index 5d188ad..d84f153 100644 (file)
@@ -4,6 +4,9 @@
 #ifndef _ICE_TC_LIB_H_
 #define _ICE_TC_LIB_H_
 
+#include <linux/bits.h>
+#include <net/pfcp.h>
+
 #define ICE_TC_FLWR_FIELD_DST_MAC              BIT(0)
 #define ICE_TC_FLWR_FIELD_SRC_MAC              BIT(1)
 #define ICE_TC_FLWR_FIELD_VLAN                 BIT(2)
@@ -34,6 +37,7 @@
 #define ICE_TC_FLWR_FIELD_VLAN_PRIO            BIT(27)
 #define ICE_TC_FLWR_FIELD_CVLAN_PRIO           BIT(28)
 #define ICE_TC_FLWR_FIELD_VLAN_TPID            BIT(29)
+#define ICE_TC_FLWR_FIELD_PFCP_OPTS            BIT(30)
 
 #define ICE_TC_FLOWER_MASK_32   0xFFFFFFFF
 
@@ -161,6 +165,8 @@ struct ice_tc_flower_fltr {
        __be32 tenant_id;
        struct gtp_pdu_session_info gtp_pdu_info_keys;
        struct gtp_pdu_session_info gtp_pdu_info_masks;
+       struct pfcp_metadata pfcp_meta_keys;
+       struct pfcp_metadata pfcp_meta_masks;
        u32 flags;
        u8 tunnel_type;
        struct ice_tc_flower_action     action;