ice: Add GTPU FDIR filter for AVF
authorQi Zhang <qi.z.zhang@intel.com>
Tue, 9 Mar 2021 03:08:08 +0000 (11:08 +0800)
committerTony Nguyen <anthony.l.nguyen@intel.com>
Mon, 22 Mar 2021 18:32:12 +0000 (11:32 -0700)
Add new FDIR filter type to forward GTPU packets by matching TEID or QFI.
The filter is only enabled when COMMS DDP package is downloaded.

Signed-off-by: Yahui Cao <yahui.cao@intel.com>
Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
Tested-by: Chen Bo <BoX.C.Chen@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
drivers/net/ethernet/intel/ice/ice_fdir.c
drivers/net/ethernet/intel/ice/ice_fdir.h
drivers/net/ethernet/intel/ice/ice_type.h
drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c

index b9c65d0..e0b1aa1 100644 (file)
@@ -40,6 +40,66 @@ static const u8 ice_fdir_ipv4_pkt[] = {
        0x00, 0x00
 };
 
+static const u8 ice_fdir_udp4_gtpu4_pkt[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00,
+       0x00, 0x4c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x08, 0x68, 0x08, 0x68, 0x00, 0x00,
+       0x00, 0x00, 0x34, 0xff, 0x00, 0x28, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x02, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00,
+       0x00, 0x1c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+};
+
+static const u8 ice_fdir_tcp4_gtpu4_pkt[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00,
+       0x00, 0x58, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x08, 0x68, 0x08, 0x68, 0x00, 0x00,
+       0x00, 0x00, 0x34, 0xff, 0x00, 0x28, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x02, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00,
+       0x00, 0x28, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06,
+       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,
+};
+
+static const u8 ice_fdir_icmp4_gtpu4_pkt[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00,
+       0x00, 0x4c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x08, 0x68, 0x08, 0x68, 0x00, 0x00,
+       0x00, 0x00, 0x34, 0xff, 0x00, 0x28, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x02, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00,
+       0x00, 0x1c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+};
+
+static const u8 ice_fdir_ipv4_gtpu4_pkt[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00,
+       0x00, 0x44, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x08, 0x68, 0x08, 0x68, 0x00, 0x00,
+       0x00, 0x00, 0x34, 0xff, 0x00, 0x28, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x02, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00,
+       0x00, 0x14, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+};
+
 static const u8 ice_fdir_non_ip_l2_pkt[] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -245,6 +305,34 @@ static const struct ice_fdir_base_pkt ice_fdir_pkt[] = {
                sizeof(ice_fdir_ip4_tun_pkt), ice_fdir_ip4_tun_pkt,
        },
        {
+               ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_UDP,
+               sizeof(ice_fdir_udp4_gtpu4_pkt),
+               ice_fdir_udp4_gtpu4_pkt,
+               sizeof(ice_fdir_udp4_gtpu4_pkt),
+               ice_fdir_udp4_gtpu4_pkt,
+       },
+       {
+               ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_TCP,
+               sizeof(ice_fdir_tcp4_gtpu4_pkt),
+               ice_fdir_tcp4_gtpu4_pkt,
+               sizeof(ice_fdir_tcp4_gtpu4_pkt),
+               ice_fdir_tcp4_gtpu4_pkt,
+       },
+       {
+               ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_ICMP,
+               sizeof(ice_fdir_icmp4_gtpu4_pkt),
+               ice_fdir_icmp4_gtpu4_pkt,
+               sizeof(ice_fdir_icmp4_gtpu4_pkt),
+               ice_fdir_icmp4_gtpu4_pkt,
+       },
+       {
+               ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER,
+               sizeof(ice_fdir_ipv4_gtpu4_pkt),
+               ice_fdir_ipv4_gtpu4_pkt,
+               sizeof(ice_fdir_ipv4_gtpu4_pkt),
+               ice_fdir_ipv4_gtpu4_pkt,
+       },
+       {
                ICE_FLTR_PTYPE_NON_IP_L2,
                sizeof(ice_fdir_non_ip_l2_pkt), ice_fdir_non_ip_l2_pkt,
                sizeof(ice_fdir_non_ip_l2_pkt), ice_fdir_non_ip_l2_pkt,
@@ -492,6 +580,22 @@ static void ice_pkt_insert_ipv6_addr(u8 *pkt, int offset, __be32 *addr)
 }
 
 /**
+ * ice_pkt_insert_u6_qfi - insert a u6 value QFI into a memory buffer for GTPU
+ * @pkt: packet buffer
+ * @offset: offset into buffer
+ * @data: 8 bit value to convert and insert into pkt at offset
+ *
+ * This function is designed for inserting QFI (6 bits) for GTPU.
+ */
+static void ice_pkt_insert_u6_qfi(u8 *pkt, int offset, u8 data)
+{
+       u8 ret;
+
+       ret = (data & 0x3F) + (*(pkt + offset) & 0xC0);
+       memcpy(pkt + offset, &ret, sizeof(ret));
+}
+
+/**
  * ice_pkt_insert_u8 - insert a u8 value into a memory buffer.
  * @pkt: packet buffer
  * @offset: offset into buffer
@@ -685,6 +789,19 @@ ice_fdir_get_gen_prgm_pkt(struct ice_hw *hw, struct ice_fdir_fltr *input,
                                  input->ip.v4.proto);
                ice_pkt_insert_mac_addr(loc, input->ext_data.dst_mac);
                break;
+       case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_UDP:
+       case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_TCP:
+       case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_ICMP:
+       case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER:
+               ice_pkt_insert_u32(loc, ICE_IPV4_DST_ADDR_OFFSET,
+                                  input->ip.v4.src_ip);
+               ice_pkt_insert_u32(loc, ICE_IPV4_SRC_ADDR_OFFSET,
+                                  input->ip.v4.dst_ip);
+               ice_pkt_insert_u32(loc, ICE_IPV4_GTPU_TEID_OFFSET,
+                                  input->gtpu_data.teid);
+               ice_pkt_insert_u6_qfi(loc, ICE_IPV4_GTPU_QFI_OFFSET,
+                                     input->gtpu_data.qfi);
+               break;
        case ICE_FLTR_PTYPE_NON_IP_L2:
                ice_pkt_insert_u16(loc, ICE_MAC_ETHTYPE_OFFSET,
                                   input->ext_data.ether_type);
index 7db6bc3..2945421 100644 (file)
@@ -31,6 +31,8 @@
 #define ICE_IPV6_TC_OFFSET             14
 #define ICE_IPV6_HLIM_OFFSET           21
 #define ICE_IPV6_PROTO_OFFSET          20
+#define ICE_IPV4_GTPU_TEID_OFFSET      46
+#define ICE_IPV4_GTPU_QFI_OFFSET       56
 
 #define ICE_FDIR_MAX_FLTRS             16384
 
@@ -114,6 +116,24 @@ struct ice_fdir_v6 {
        u8 hlim;
 };
 
+struct ice_fdir_udp_gtp {
+       u8 flags;
+       u8 msg_type;
+       __be16 rsrvd_len;
+       __be32 teid;
+       __be16 rsrvd_seq_nbr;
+       u8 rsrvd_n_pdu_nbr;
+       u8 rsrvd_next_ext_type;
+       u8 rsvrd_ext_len;
+       u8      pdu_type:4,
+               spare:4;
+       u8      ppp:1,
+               rqi:1,
+               qfi:6;
+       u32 rsvrd;
+       u8 next_ext;
+};
+
 struct ice_fdir_extra {
        u8 dst_mac[ETH_ALEN];   /* dest MAC address */
        u8 src_mac[ETH_ALEN];   /* src MAC address */
@@ -132,6 +152,9 @@ struct ice_fdir_fltr {
                struct ice_fdir_v6 v6;
        } ip, mask;
 
+       struct ice_fdir_udp_gtp gtpu_data;
+       struct ice_fdir_udp_gtp gtpu_mask;
+
        struct ice_fdir_extra ext_data;
        struct ice_fdir_extra ext_mask;
 
index de4ddf2..c55076d 100644 (file)
@@ -192,6 +192,10 @@ enum ice_fltr_ptype {
        ICE_FLTR_PTYPE_NONF_IPV4_TCP,
        ICE_FLTR_PTYPE_NONF_IPV4_SCTP,
        ICE_FLTR_PTYPE_NONF_IPV4_OTHER,
+       ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_UDP,
+       ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_TCP,
+       ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_ICMP,
+       ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER,
        ICE_FLTR_PTYPE_NON_IP_L2,
        ICE_FLTR_PTYPE_FRAG_IPV4,
        ICE_FLTR_PTYPE_NONF_IPV6_UDP,
index f211c28..e0bcd5b 100644 (file)
        ((u64)(((((flow) + (tun_offs)) & ICE_FLOW_PROF_TYPE_M)) | \
              (((u64)(vsi) << ICE_FLOW_PROF_VSI_S) & ICE_FLOW_PROF_VSI_M)))
 
+#define GTPU_TEID_OFFSET 4
+#define GTPU_EH_QFI_OFFSET 1
+#define GTPU_EH_QFI_MASK 0x3F
+
+enum ice_fdir_tunnel_type {
+       ICE_FDIR_TUNNEL_TYPE_NONE = 0,
+       ICE_FDIR_TUNNEL_TYPE_GTPU,
+       ICE_FDIR_TUNNEL_TYPE_GTPU_EH,
+};
+
 struct virtchnl_fdir_fltr_conf {
        struct ice_fdir_fltr input;
+       enum ice_fdir_tunnel_type ttype;
 };
 
 static enum virtchnl_proto_hdr_type vc_pattern_ether[] = {
@@ -85,6 +96,23 @@ static enum virtchnl_proto_hdr_type vc_pattern_ipv6_sctp[] = {
        VIRTCHNL_PROTO_HDR_NONE,
 };
 
+static enum virtchnl_proto_hdr_type vc_pattern_ipv4_gtpu[] = {
+       VIRTCHNL_PROTO_HDR_ETH,
+       VIRTCHNL_PROTO_HDR_IPV4,
+       VIRTCHNL_PROTO_HDR_UDP,
+       VIRTCHNL_PROTO_HDR_GTPU_IP,
+       VIRTCHNL_PROTO_HDR_NONE,
+};
+
+static enum virtchnl_proto_hdr_type vc_pattern_ipv4_gtpu_eh[] = {
+       VIRTCHNL_PROTO_HDR_ETH,
+       VIRTCHNL_PROTO_HDR_IPV4,
+       VIRTCHNL_PROTO_HDR_UDP,
+       VIRTCHNL_PROTO_HDR_GTPU_IP,
+       VIRTCHNL_PROTO_HDR_GTPU_EH,
+       VIRTCHNL_PROTO_HDR_NONE,
+};
+
 struct virtchnl_fdir_pattern_match_item {
        enum virtchnl_proto_hdr_type *list;
        u64 input_set;
@@ -112,6 +140,8 @@ static const struct virtchnl_fdir_pattern_match_item vc_fdir_pattern_comms[] = {
        {vc_pattern_ipv6_udp,                 0,         NULL},
        {vc_pattern_ipv6_sctp,                0,         NULL},
        {vc_pattern_ether,                    0,         NULL},
+       {vc_pattern_ipv4_gtpu,                0,         NULL},
+       {vc_pattern_ipv4_gtpu_eh,             0,         NULL},
 };
 
 struct virtchnl_fdir_inset_map {
@@ -136,6 +166,8 @@ static const struct virtchnl_fdir_inset_map fdir_inset_map[] = {
        {VIRTCHNL_PROTO_HDR_TCP_DST_PORT, ICE_FLOW_FIELD_IDX_TCP_DST_PORT},
        {VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT, ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT},
        {VIRTCHNL_PROTO_HDR_SCTP_DST_PORT, ICE_FLOW_FIELD_IDX_SCTP_DST_PORT},
+       {VIRTCHNL_PROTO_HDR_GTPU_IP_TEID, ICE_FLOW_FIELD_IDX_GTPU_IP_TEID},
+       {VIRTCHNL_PROTO_HDR_GTPU_EH_QFI, ICE_FLOW_FIELD_IDX_GTPU_EH_QFI},
 };
 
 /**
@@ -385,6 +417,7 @@ ice_vc_fdir_set_flow_hdr(struct ice_vf *vf,
                         struct ice_flow_seg_info *seg)
 {
        enum ice_fltr_ptype flow = conf->input.flow_type;
+       enum ice_fdir_tunnel_type ttype = conf->ttype;
        struct device *dev = ice_pf_to_dev(vf->pf);
 
        switch (flow) {
@@ -405,6 +438,25 @@ ice_vc_fdir_set_flow_hdr(struct ice_vf *vf,
                                  ICE_FLOW_SEG_HDR_IPV4 |
                                  ICE_FLOW_SEG_HDR_IPV_OTHER);
                break;
+       case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_UDP:
+       case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_TCP:
+       case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_ICMP:
+       case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER:
+               if (ttype == ICE_FDIR_TUNNEL_TYPE_GTPU) {
+                       ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_IP |
+                                         ICE_FLOW_SEG_HDR_IPV4 |
+                                         ICE_FLOW_SEG_HDR_IPV_OTHER);
+               } else if (ttype == ICE_FDIR_TUNNEL_TYPE_GTPU_EH) {
+                       ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_EH |
+                                         ICE_FLOW_SEG_HDR_GTPU_IP |
+                                         ICE_FLOW_SEG_HDR_IPV4 |
+                                         ICE_FLOW_SEG_HDR_IPV_OTHER);
+               } else {
+                       dev_dbg(dev, "Invalid tunnel type 0x%x for VF %d\n",
+                               flow, vf->vf_id);
+                       return -EINVAL;
+               }
+               break;
        case ICE_FLTR_PTYPE_NONF_IPV4_SCTP:
                ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_SCTP |
                                  ICE_FLOW_SEG_HDR_IPV4 |
@@ -800,6 +852,7 @@ ice_vc_fdir_parse_pattern(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
                struct tcphdr *tcph;
                struct ethhdr *eth;
                struct iphdr *iph;
+               u8 *rawh;
 
                switch (hdr->type) {
                case VIRTCHNL_PROTO_HDR_ETH:
@@ -891,6 +944,21 @@ ice_vc_fdir_parse_pattern(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
                                }
                        }
                        break;
+               case VIRTCHNL_PROTO_HDR_GTPU_IP:
+                       rawh = (u8 *)hdr->buffer;
+                       input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER;
+
+                       if (hdr->field_selector)
+                               input->gtpu_data.teid = *(__be32 *)(&rawh[GTPU_TEID_OFFSET]);
+                       conf->ttype = ICE_FDIR_TUNNEL_TYPE_GTPU;
+                       break;
+               case VIRTCHNL_PROTO_HDR_GTPU_EH:
+                       rawh = (u8 *)hdr->buffer;
+
+                       if (hdr->field_selector)
+                               input->gtpu_data.qfi = rawh[GTPU_EH_QFI_OFFSET] & GTPU_EH_QFI_MASK;
+                       conf->ttype = ICE_FDIR_TUNNEL_TYPE_GTPU_EH;
+                       break;
                default:
                        dev_dbg(dev, "Invalid header type 0x:%x for VF %d\n",
                                hdr->type, vf->vf_id);
@@ -1016,12 +1084,18 @@ ice_vc_fdir_comp_rules(struct virtchnl_fdir_fltr_conf *conf_a,
        struct ice_fdir_fltr *a = &conf_a->input;
        struct ice_fdir_fltr *b = &conf_b->input;
 
+       if (conf_a->ttype != conf_b->ttype)
+               return false;
        if (a->flow_type != b->flow_type)
                return false;
        if (memcmp(&a->ip, &b->ip, sizeof(a->ip)))
                return false;
        if (memcmp(&a->mask, &b->mask, sizeof(a->mask)))
                return false;
+       if (memcmp(&a->gtpu_data, &b->gtpu_data, sizeof(a->gtpu_data)))
+               return false;
+       if (memcmp(&a->gtpu_mask, &b->gtpu_mask, sizeof(a->gtpu_mask)))
+               return false;
        if (memcmp(&a->ext_data, &b->ext_data, sizeof(a->ext_data)))
                return false;
        if (memcmp(&a->ext_mask, &b->ext_mask, sizeof(a->ext_mask)))