Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (c) 2020, Intel Corporation. */
0003 
0004 /* flow director ethtool support for iavf */
0005 
0006 #include "iavf.h"
0007 
0008 #define GTPU_PORT   2152
0009 #define NAT_T_ESP_PORT  4500
0010 #define PFCP_PORT   8805
0011 
0012 static const struct in6_addr ipv6_addr_full_mask = {
0013     .in6_u = {
0014         .u6_addr8 = {
0015             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0016             0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0017         }
0018     }
0019 };
0020 
0021 /**
0022  * iavf_pkt_udp_no_pay_len - the length of UDP packet without payload
0023  * @fltr: Flow Director filter data structure
0024  */
0025 static u16 iavf_pkt_udp_no_pay_len(struct iavf_fdir_fltr *fltr)
0026 {
0027     return sizeof(struct ethhdr) +
0028            (fltr->ip_ver == 4 ? sizeof(struct iphdr) : sizeof(struct ipv6hdr)) +
0029            sizeof(struct udphdr);
0030 }
0031 
0032 /**
0033  * iavf_fill_fdir_gtpu_hdr - fill the GTP-U protocol header
0034  * @fltr: Flow Director filter data structure
0035  * @proto_hdrs: Flow Director protocol headers data structure
0036  *
0037  * Returns 0 if the GTP-U protocol header is set successfully
0038  */
0039 static int
0040 iavf_fill_fdir_gtpu_hdr(struct iavf_fdir_fltr *fltr,
0041             struct virtchnl_proto_hdrs *proto_hdrs)
0042 {
0043     struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1];
0044     struct virtchnl_proto_hdr *ghdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
0045     struct virtchnl_proto_hdr *ehdr = NULL; /* Extension Header if it exists */
0046     u16 adj_offs, hdr_offs;
0047     int i;
0048 
0049     VIRTCHNL_SET_PROTO_HDR_TYPE(ghdr, GTPU_IP);
0050 
0051     adj_offs = iavf_pkt_udp_no_pay_len(fltr);
0052 
0053     for (i = 0; i < fltr->flex_cnt; i++) {
0054 #define IAVF_GTPU_HDR_TEID_OFFS0    4
0055 #define IAVF_GTPU_HDR_TEID_OFFS1    6
0056 #define IAVF_GTPU_HDR_N_PDU_AND_NEXT_EXTHDR_OFFS    10
0057 #define IAVF_GTPU_HDR_NEXT_EXTHDR_TYPE_MASK     0x00FF /* skip N_PDU */
0058 /* PDU Session Container Extension Header (PSC) */
0059 #define IAVF_GTPU_PSC_EXTHDR_TYPE           0x85
0060 #define IAVF_GTPU_HDR_PSC_PDU_TYPE_AND_QFI_OFFS     13
0061 #define IAVF_GTPU_HDR_PSC_PDU_QFI_MASK          0x3F /* skip Type */
0062 #define IAVF_GTPU_EH_QFI_IDX                1
0063 
0064         if (fltr->flex_words[i].offset < adj_offs)
0065             return -EINVAL;
0066 
0067         hdr_offs = fltr->flex_words[i].offset - adj_offs;
0068 
0069         switch (hdr_offs) {
0070         case IAVF_GTPU_HDR_TEID_OFFS0:
0071         case IAVF_GTPU_HDR_TEID_OFFS1: {
0072             __be16 *pay_word = (__be16 *)ghdr->buffer;
0073 
0074             pay_word[hdr_offs >> 1] = htons(fltr->flex_words[i].word);
0075             VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(ghdr, GTPU_IP, TEID);
0076             }
0077             break;
0078         case IAVF_GTPU_HDR_N_PDU_AND_NEXT_EXTHDR_OFFS:
0079             if ((fltr->flex_words[i].word &
0080                  IAVF_GTPU_HDR_NEXT_EXTHDR_TYPE_MASK) !=
0081                         IAVF_GTPU_PSC_EXTHDR_TYPE)
0082                 return -EOPNOTSUPP;
0083             if (!ehdr)
0084                 ehdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
0085             VIRTCHNL_SET_PROTO_HDR_TYPE(ehdr, GTPU_EH);
0086             break;
0087         case IAVF_GTPU_HDR_PSC_PDU_TYPE_AND_QFI_OFFS:
0088             if (!ehdr)
0089                 return -EINVAL;
0090             ehdr->buffer[IAVF_GTPU_EH_QFI_IDX] =
0091                     fltr->flex_words[i].word &
0092                         IAVF_GTPU_HDR_PSC_PDU_QFI_MASK;
0093             VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(ehdr, GTPU_EH, QFI);
0094             break;
0095         default:
0096             return -EINVAL;
0097         }
0098     }
0099 
0100     uhdr->field_selector = 0; /* The PF ignores the UDP header fields */
0101 
0102     return 0;
0103 }
0104 
0105 /**
0106  * iavf_fill_fdir_pfcp_hdr - fill the PFCP protocol header
0107  * @fltr: Flow Director filter data structure
0108  * @proto_hdrs: Flow Director protocol headers data structure
0109  *
0110  * Returns 0 if the PFCP protocol header is set successfully
0111  */
0112 static int
0113 iavf_fill_fdir_pfcp_hdr(struct iavf_fdir_fltr *fltr,
0114             struct virtchnl_proto_hdrs *proto_hdrs)
0115 {
0116     struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1];
0117     struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
0118     u16 adj_offs, hdr_offs;
0119     int i;
0120 
0121     VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, PFCP);
0122 
0123     adj_offs = iavf_pkt_udp_no_pay_len(fltr);
0124 
0125     for (i = 0; i < fltr->flex_cnt; i++) {
0126 #define IAVF_PFCP_HDR_SFIELD_AND_MSG_TYPE_OFFS  0
0127         if (fltr->flex_words[i].offset < adj_offs)
0128             return -EINVAL;
0129 
0130         hdr_offs = fltr->flex_words[i].offset - adj_offs;
0131 
0132         switch (hdr_offs) {
0133         case IAVF_PFCP_HDR_SFIELD_AND_MSG_TYPE_OFFS:
0134             hdr->buffer[0] = (fltr->flex_words[i].word >> 8) & 0xff;
0135             VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, PFCP, S_FIELD);
0136             break;
0137         default:
0138             return -EINVAL;
0139         }
0140     }
0141 
0142     uhdr->field_selector = 0; /* The PF ignores the UDP header fields */
0143 
0144     return 0;
0145 }
0146 
0147 /**
0148  * iavf_fill_fdir_nat_t_esp_hdr - fill the NAT-T-ESP protocol header
0149  * @fltr: Flow Director filter data structure
0150  * @proto_hdrs: Flow Director protocol headers data structure
0151  *
0152  * Returns 0 if the NAT-T-ESP protocol header is set successfully
0153  */
0154 static int
0155 iavf_fill_fdir_nat_t_esp_hdr(struct iavf_fdir_fltr *fltr,
0156                  struct virtchnl_proto_hdrs *proto_hdrs)
0157 {
0158     struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1];
0159     struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
0160     u16 adj_offs, hdr_offs;
0161     u32 spi = 0;
0162     int i;
0163 
0164     VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ESP);
0165 
0166     adj_offs = iavf_pkt_udp_no_pay_len(fltr);
0167 
0168     for (i = 0; i < fltr->flex_cnt; i++) {
0169 #define IAVF_NAT_T_ESP_SPI_OFFS0    0
0170 #define IAVF_NAT_T_ESP_SPI_OFFS1    2
0171         if (fltr->flex_words[i].offset < adj_offs)
0172             return -EINVAL;
0173 
0174         hdr_offs = fltr->flex_words[i].offset - adj_offs;
0175 
0176         switch (hdr_offs) {
0177         case IAVF_NAT_T_ESP_SPI_OFFS0:
0178             spi |= fltr->flex_words[i].word << 16;
0179             break;
0180         case IAVF_NAT_T_ESP_SPI_OFFS1:
0181             spi |= fltr->flex_words[i].word;
0182             break;
0183         default:
0184             return -EINVAL;
0185         }
0186     }
0187 
0188     if (!spi)
0189         return -EOPNOTSUPP; /* Not support IKE Header Format with SPI 0 */
0190 
0191     *(__be32 *)hdr->buffer = htonl(spi);
0192     VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ESP, SPI);
0193 
0194     uhdr->field_selector = 0; /* The PF ignores the UDP header fields */
0195 
0196     return 0;
0197 }
0198 
0199 /**
0200  * iavf_fill_fdir_udp_flex_pay_hdr - fill the UDP payload header
0201  * @fltr: Flow Director filter data structure
0202  * @proto_hdrs: Flow Director protocol headers data structure
0203  *
0204  * Returns 0 if the UDP payload defined protocol header is set successfully
0205  */
0206 static int
0207 iavf_fill_fdir_udp_flex_pay_hdr(struct iavf_fdir_fltr *fltr,
0208                 struct virtchnl_proto_hdrs *proto_hdrs)
0209 {
0210     int err;
0211 
0212     switch (ntohs(fltr->ip_data.dst_port)) {
0213     case GTPU_PORT:
0214         err = iavf_fill_fdir_gtpu_hdr(fltr, proto_hdrs);
0215         break;
0216     case NAT_T_ESP_PORT:
0217         err = iavf_fill_fdir_nat_t_esp_hdr(fltr, proto_hdrs);
0218         break;
0219     case PFCP_PORT:
0220         err = iavf_fill_fdir_pfcp_hdr(fltr, proto_hdrs);
0221         break;
0222     default:
0223         err = -EOPNOTSUPP;
0224         break;
0225     }
0226 
0227     return err;
0228 }
0229 
0230 /**
0231  * iavf_fill_fdir_ip4_hdr - fill the IPv4 protocol header
0232  * @fltr: Flow Director filter data structure
0233  * @proto_hdrs: Flow Director protocol headers data structure
0234  *
0235  * Returns 0 if the IPv4 protocol header is set successfully
0236  */
0237 static int
0238 iavf_fill_fdir_ip4_hdr(struct iavf_fdir_fltr *fltr,
0239                struct virtchnl_proto_hdrs *proto_hdrs)
0240 {
0241     struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
0242     struct iphdr *iph = (struct iphdr *)hdr->buffer;
0243 
0244     VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV4);
0245 
0246     if (fltr->ip_mask.tos == U8_MAX) {
0247         iph->tos = fltr->ip_data.tos;
0248         VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DSCP);
0249     }
0250 
0251     if (fltr->ip_mask.proto == U8_MAX) {
0252         iph->protocol = fltr->ip_data.proto;
0253         VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, PROT);
0254     }
0255 
0256     if (fltr->ip_mask.v4_addrs.src_ip == htonl(U32_MAX)) {
0257         iph->saddr = fltr->ip_data.v4_addrs.src_ip;
0258         VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, SRC);
0259     }
0260 
0261     if (fltr->ip_mask.v4_addrs.dst_ip == htonl(U32_MAX)) {
0262         iph->daddr = fltr->ip_data.v4_addrs.dst_ip;
0263         VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DST);
0264     }
0265 
0266     fltr->ip_ver = 4;
0267 
0268     return 0;
0269 }
0270 
0271 /**
0272  * iavf_fill_fdir_ip6_hdr - fill the IPv6 protocol header
0273  * @fltr: Flow Director filter data structure
0274  * @proto_hdrs: Flow Director protocol headers data structure
0275  *
0276  * Returns 0 if the IPv6 protocol header is set successfully
0277  */
0278 static int
0279 iavf_fill_fdir_ip6_hdr(struct iavf_fdir_fltr *fltr,
0280                struct virtchnl_proto_hdrs *proto_hdrs)
0281 {
0282     struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
0283     struct ipv6hdr *iph = (struct ipv6hdr *)hdr->buffer;
0284 
0285     VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV6);
0286 
0287     if (fltr->ip_mask.tclass == U8_MAX) {
0288         iph->priority = (fltr->ip_data.tclass >> 4) & 0xF;
0289         iph->flow_lbl[0] = (fltr->ip_data.tclass << 4) & 0xF0;
0290         VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, TC);
0291     }
0292 
0293     if (fltr->ip_mask.proto == U8_MAX) {
0294         iph->nexthdr = fltr->ip_data.proto;
0295         VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, PROT);
0296     }
0297 
0298     if (!memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_full_mask,
0299             sizeof(struct in6_addr))) {
0300         memcpy(&iph->saddr, &fltr->ip_data.v6_addrs.src_ip,
0301                sizeof(struct in6_addr));
0302         VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, SRC);
0303     }
0304 
0305     if (!memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_full_mask,
0306             sizeof(struct in6_addr))) {
0307         memcpy(&iph->daddr, &fltr->ip_data.v6_addrs.dst_ip,
0308                sizeof(struct in6_addr));
0309         VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, DST);
0310     }
0311 
0312     fltr->ip_ver = 6;
0313 
0314     return 0;
0315 }
0316 
0317 /**
0318  * iavf_fill_fdir_tcp_hdr - fill the TCP protocol header
0319  * @fltr: Flow Director filter data structure
0320  * @proto_hdrs: Flow Director protocol headers data structure
0321  *
0322  * Returns 0 if the TCP protocol header is set successfully
0323  */
0324 static int
0325 iavf_fill_fdir_tcp_hdr(struct iavf_fdir_fltr *fltr,
0326                struct virtchnl_proto_hdrs *proto_hdrs)
0327 {
0328     struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
0329     struct tcphdr *tcph = (struct tcphdr *)hdr->buffer;
0330 
0331     VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, TCP);
0332 
0333     if (fltr->ip_mask.src_port == htons(U16_MAX)) {
0334         tcph->source = fltr->ip_data.src_port;
0335         VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, SRC_PORT);
0336     }
0337 
0338     if (fltr->ip_mask.dst_port == htons(U16_MAX)) {
0339         tcph->dest = fltr->ip_data.dst_port;
0340         VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, DST_PORT);
0341     }
0342 
0343     return 0;
0344 }
0345 
0346 /**
0347  * iavf_fill_fdir_udp_hdr - fill the UDP protocol header
0348  * @fltr: Flow Director filter data structure
0349  * @proto_hdrs: Flow Director protocol headers data structure
0350  *
0351  * Returns 0 if the UDP protocol header is set successfully
0352  */
0353 static int
0354 iavf_fill_fdir_udp_hdr(struct iavf_fdir_fltr *fltr,
0355                struct virtchnl_proto_hdrs *proto_hdrs)
0356 {
0357     struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
0358     struct udphdr *udph = (struct udphdr *)hdr->buffer;
0359 
0360     VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, UDP);
0361 
0362     if (fltr->ip_mask.src_port == htons(U16_MAX)) {
0363         udph->source = fltr->ip_data.src_port;
0364         VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, SRC_PORT);
0365     }
0366 
0367     if (fltr->ip_mask.dst_port == htons(U16_MAX)) {
0368         udph->dest = fltr->ip_data.dst_port;
0369         VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, DST_PORT);
0370     }
0371 
0372     if (!fltr->flex_cnt)
0373         return 0;
0374 
0375     return iavf_fill_fdir_udp_flex_pay_hdr(fltr, proto_hdrs);
0376 }
0377 
0378 /**
0379  * iavf_fill_fdir_sctp_hdr - fill the SCTP protocol header
0380  * @fltr: Flow Director filter data structure
0381  * @proto_hdrs: Flow Director protocol headers data structure
0382  *
0383  * Returns 0 if the SCTP protocol header is set successfully
0384  */
0385 static int
0386 iavf_fill_fdir_sctp_hdr(struct iavf_fdir_fltr *fltr,
0387             struct virtchnl_proto_hdrs *proto_hdrs)
0388 {
0389     struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
0390     struct sctphdr *sctph = (struct sctphdr *)hdr->buffer;
0391 
0392     VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, SCTP);
0393 
0394     if (fltr->ip_mask.src_port == htons(U16_MAX)) {
0395         sctph->source = fltr->ip_data.src_port;
0396         VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, SRC_PORT);
0397     }
0398 
0399     if (fltr->ip_mask.dst_port == htons(U16_MAX)) {
0400         sctph->dest = fltr->ip_data.dst_port;
0401         VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, DST_PORT);
0402     }
0403 
0404     return 0;
0405 }
0406 
0407 /**
0408  * iavf_fill_fdir_ah_hdr - fill the AH protocol header
0409  * @fltr: Flow Director filter data structure
0410  * @proto_hdrs: Flow Director protocol headers data structure
0411  *
0412  * Returns 0 if the AH protocol header is set successfully
0413  */
0414 static int
0415 iavf_fill_fdir_ah_hdr(struct iavf_fdir_fltr *fltr,
0416               struct virtchnl_proto_hdrs *proto_hdrs)
0417 {
0418     struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
0419     struct ip_auth_hdr *ah = (struct ip_auth_hdr *)hdr->buffer;
0420 
0421     VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, AH);
0422 
0423     if (fltr->ip_mask.spi == htonl(U32_MAX)) {
0424         ah->spi = fltr->ip_data.spi;
0425         VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, AH, SPI);
0426     }
0427 
0428     return 0;
0429 }
0430 
0431 /**
0432  * iavf_fill_fdir_esp_hdr - fill the ESP protocol header
0433  * @fltr: Flow Director filter data structure
0434  * @proto_hdrs: Flow Director protocol headers data structure
0435  *
0436  * Returns 0 if the ESP protocol header is set successfully
0437  */
0438 static int
0439 iavf_fill_fdir_esp_hdr(struct iavf_fdir_fltr *fltr,
0440                struct virtchnl_proto_hdrs *proto_hdrs)
0441 {
0442     struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
0443     struct ip_esp_hdr *esph = (struct ip_esp_hdr *)hdr->buffer;
0444 
0445     VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ESP);
0446 
0447     if (fltr->ip_mask.spi == htonl(U32_MAX)) {
0448         esph->spi = fltr->ip_data.spi;
0449         VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ESP, SPI);
0450     }
0451 
0452     return 0;
0453 }
0454 
0455 /**
0456  * iavf_fill_fdir_l4_hdr - fill the L4 protocol header
0457  * @fltr: Flow Director filter data structure
0458  * @proto_hdrs: Flow Director protocol headers data structure
0459  *
0460  * Returns 0 if the L4 protocol header is set successfully
0461  */
0462 static int
0463 iavf_fill_fdir_l4_hdr(struct iavf_fdir_fltr *fltr,
0464               struct virtchnl_proto_hdrs *proto_hdrs)
0465 {
0466     struct virtchnl_proto_hdr *hdr;
0467     __be32 *l4_4_data;
0468 
0469     if (!fltr->ip_mask.proto) /* IPv4/IPv6 header only */
0470         return 0;
0471 
0472     hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
0473     l4_4_data = (__be32 *)hdr->buffer;
0474 
0475     /* L2TPv3 over IP with 'Session ID' */
0476     if (fltr->ip_data.proto == 115 && fltr->ip_mask.l4_header == htonl(U32_MAX)) {
0477         VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, L2TPV3);
0478         VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, L2TPV3, SESS_ID);
0479 
0480         *l4_4_data = fltr->ip_data.l4_header;
0481     } else {
0482         return -EOPNOTSUPP;
0483     }
0484 
0485     return 0;
0486 }
0487 
0488 /**
0489  * iavf_fill_fdir_eth_hdr - fill the Ethernet protocol header
0490  * @fltr: Flow Director filter data structure
0491  * @proto_hdrs: Flow Director protocol headers data structure
0492  *
0493  * Returns 0 if the Ethernet protocol header is set successfully
0494  */
0495 static int
0496 iavf_fill_fdir_eth_hdr(struct iavf_fdir_fltr *fltr,
0497                struct virtchnl_proto_hdrs *proto_hdrs)
0498 {
0499     struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
0500     struct ethhdr *ehdr = (struct ethhdr *)hdr->buffer;
0501 
0502     VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ETH);
0503 
0504     if (fltr->eth_mask.etype == htons(U16_MAX)) {
0505         if (fltr->eth_data.etype == htons(ETH_P_IP) ||
0506             fltr->eth_data.etype == htons(ETH_P_IPV6))
0507             return -EOPNOTSUPP;
0508 
0509         ehdr->h_proto = fltr->eth_data.etype;
0510         VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ETH, ETHERTYPE);
0511     }
0512 
0513     return 0;
0514 }
0515 
0516 /**
0517  * iavf_fill_fdir_add_msg - fill the Flow Director filter into virtchnl message
0518  * @adapter: pointer to the VF adapter structure
0519  * @fltr: Flow Director filter data structure
0520  *
0521  * Returns 0 if the add Flow Director virtchnl message is filled successfully
0522  */
0523 int iavf_fill_fdir_add_msg(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)
0524 {
0525     struct virtchnl_fdir_add *vc_msg = &fltr->vc_add_msg;
0526     struct virtchnl_proto_hdrs *proto_hdrs;
0527     int err;
0528 
0529     proto_hdrs = &vc_msg->rule_cfg.proto_hdrs;
0530 
0531     err = iavf_fill_fdir_eth_hdr(fltr, proto_hdrs); /* L2 always exists */
0532     if (err)
0533         return err;
0534 
0535     switch (fltr->flow_type) {
0536     case IAVF_FDIR_FLOW_IPV4_TCP:
0537         err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
0538               iavf_fill_fdir_tcp_hdr(fltr, proto_hdrs);
0539         break;
0540     case IAVF_FDIR_FLOW_IPV4_UDP:
0541         err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
0542               iavf_fill_fdir_udp_hdr(fltr, proto_hdrs);
0543         break;
0544     case IAVF_FDIR_FLOW_IPV4_SCTP:
0545         err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
0546               iavf_fill_fdir_sctp_hdr(fltr, proto_hdrs);
0547         break;
0548     case IAVF_FDIR_FLOW_IPV4_AH:
0549         err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
0550               iavf_fill_fdir_ah_hdr(fltr, proto_hdrs);
0551         break;
0552     case IAVF_FDIR_FLOW_IPV4_ESP:
0553         err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
0554               iavf_fill_fdir_esp_hdr(fltr, proto_hdrs);
0555         break;
0556     case IAVF_FDIR_FLOW_IPV4_OTHER:
0557         err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |
0558               iavf_fill_fdir_l4_hdr(fltr, proto_hdrs);
0559         break;
0560     case IAVF_FDIR_FLOW_IPV6_TCP:
0561         err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
0562               iavf_fill_fdir_tcp_hdr(fltr, proto_hdrs);
0563         break;
0564     case IAVF_FDIR_FLOW_IPV6_UDP:
0565         err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
0566               iavf_fill_fdir_udp_hdr(fltr, proto_hdrs);
0567         break;
0568     case IAVF_FDIR_FLOW_IPV6_SCTP:
0569         err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
0570               iavf_fill_fdir_sctp_hdr(fltr, proto_hdrs);
0571         break;
0572     case IAVF_FDIR_FLOW_IPV6_AH:
0573         err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
0574               iavf_fill_fdir_ah_hdr(fltr, proto_hdrs);
0575         break;
0576     case IAVF_FDIR_FLOW_IPV6_ESP:
0577         err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
0578               iavf_fill_fdir_esp_hdr(fltr, proto_hdrs);
0579         break;
0580     case IAVF_FDIR_FLOW_IPV6_OTHER:
0581         err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |
0582               iavf_fill_fdir_l4_hdr(fltr, proto_hdrs);
0583         break;
0584     case IAVF_FDIR_FLOW_NON_IP_L2:
0585         break;
0586     default:
0587         err = -EINVAL;
0588         break;
0589     }
0590 
0591     if (err)
0592         return err;
0593 
0594     vc_msg->vsi_id = adapter->vsi.id;
0595     vc_msg->rule_cfg.action_set.count = 1;
0596     vc_msg->rule_cfg.action_set.actions[0].type = fltr->action;
0597     vc_msg->rule_cfg.action_set.actions[0].act_conf.queue.index = fltr->q_index;
0598 
0599     return 0;
0600 }
0601 
0602 /**
0603  * iavf_fdir_flow_proto_name - get the flow protocol name
0604  * @flow_type: Flow Director filter flow type
0605  **/
0606 static const char *iavf_fdir_flow_proto_name(enum iavf_fdir_flow_type flow_type)
0607 {
0608     switch (flow_type) {
0609     case IAVF_FDIR_FLOW_IPV4_TCP:
0610     case IAVF_FDIR_FLOW_IPV6_TCP:
0611         return "TCP";
0612     case IAVF_FDIR_FLOW_IPV4_UDP:
0613     case IAVF_FDIR_FLOW_IPV6_UDP:
0614         return "UDP";
0615     case IAVF_FDIR_FLOW_IPV4_SCTP:
0616     case IAVF_FDIR_FLOW_IPV6_SCTP:
0617         return "SCTP";
0618     case IAVF_FDIR_FLOW_IPV4_AH:
0619     case IAVF_FDIR_FLOW_IPV6_AH:
0620         return "AH";
0621     case IAVF_FDIR_FLOW_IPV4_ESP:
0622     case IAVF_FDIR_FLOW_IPV6_ESP:
0623         return "ESP";
0624     case IAVF_FDIR_FLOW_IPV4_OTHER:
0625     case IAVF_FDIR_FLOW_IPV6_OTHER:
0626         return "Other";
0627     case IAVF_FDIR_FLOW_NON_IP_L2:
0628         return "Ethernet";
0629     default:
0630         return NULL;
0631     }
0632 }
0633 
0634 /**
0635  * iavf_print_fdir_fltr
0636  * @adapter: adapter structure
0637  * @fltr: Flow Director filter to print
0638  *
0639  * Print the Flow Director filter
0640  **/
0641 void iavf_print_fdir_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)
0642 {
0643     const char *proto = iavf_fdir_flow_proto_name(fltr->flow_type);
0644 
0645     if (!proto)
0646         return;
0647 
0648     switch (fltr->flow_type) {
0649     case IAVF_FDIR_FLOW_IPV4_TCP:
0650     case IAVF_FDIR_FLOW_IPV4_UDP:
0651     case IAVF_FDIR_FLOW_IPV4_SCTP:
0652         dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 %s: dst_port %hu src_port %hu\n",
0653              fltr->loc,
0654              &fltr->ip_data.v4_addrs.dst_ip,
0655              &fltr->ip_data.v4_addrs.src_ip,
0656              proto,
0657              ntohs(fltr->ip_data.dst_port),
0658              ntohs(fltr->ip_data.src_port));
0659         break;
0660     case IAVF_FDIR_FLOW_IPV4_AH:
0661     case IAVF_FDIR_FLOW_IPV4_ESP:
0662         dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 %s: SPI %u\n",
0663              fltr->loc,
0664              &fltr->ip_data.v4_addrs.dst_ip,
0665              &fltr->ip_data.v4_addrs.src_ip,
0666              proto,
0667              ntohl(fltr->ip_data.spi));
0668         break;
0669     case IAVF_FDIR_FLOW_IPV4_OTHER:
0670         dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 proto: %u L4_bytes: 0x%x\n",
0671              fltr->loc,
0672              &fltr->ip_data.v4_addrs.dst_ip,
0673              &fltr->ip_data.v4_addrs.src_ip,
0674              fltr->ip_data.proto,
0675              ntohl(fltr->ip_data.l4_header));
0676         break;
0677     case IAVF_FDIR_FLOW_IPV6_TCP:
0678     case IAVF_FDIR_FLOW_IPV6_UDP:
0679     case IAVF_FDIR_FLOW_IPV6_SCTP:
0680         dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 %s: dst_port %hu src_port %hu\n",
0681              fltr->loc,
0682              &fltr->ip_data.v6_addrs.dst_ip,
0683              &fltr->ip_data.v6_addrs.src_ip,
0684              proto,
0685              ntohs(fltr->ip_data.dst_port),
0686              ntohs(fltr->ip_data.src_port));
0687         break;
0688     case IAVF_FDIR_FLOW_IPV6_AH:
0689     case IAVF_FDIR_FLOW_IPV6_ESP:
0690         dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 %s: SPI %u\n",
0691              fltr->loc,
0692              &fltr->ip_data.v6_addrs.dst_ip,
0693              &fltr->ip_data.v6_addrs.src_ip,
0694              proto,
0695              ntohl(fltr->ip_data.spi));
0696         break;
0697     case IAVF_FDIR_FLOW_IPV6_OTHER:
0698         dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 proto: %u L4_bytes: 0x%x\n",
0699              fltr->loc,
0700              &fltr->ip_data.v6_addrs.dst_ip,
0701              &fltr->ip_data.v6_addrs.src_ip,
0702              fltr->ip_data.proto,
0703              ntohl(fltr->ip_data.l4_header));
0704         break;
0705     case IAVF_FDIR_FLOW_NON_IP_L2:
0706         dev_info(&adapter->pdev->dev, "Rule ID: %u eth_type: 0x%x\n",
0707              fltr->loc,
0708              ntohs(fltr->eth_data.etype));
0709         break;
0710     default:
0711         break;
0712     }
0713 }
0714 
0715 /**
0716  * iavf_fdir_is_dup_fltr - test if filter is already in list
0717  * @adapter: pointer to the VF adapter structure
0718  * @fltr: Flow Director filter data structure
0719  *
0720  * Returns true if the filter is found in the list
0721  */
0722 bool iavf_fdir_is_dup_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)
0723 {
0724     struct iavf_fdir_fltr *tmp;
0725 
0726     list_for_each_entry(tmp, &adapter->fdir_list_head, list) {
0727         if (tmp->flow_type != fltr->flow_type)
0728             continue;
0729 
0730         if (!memcmp(&tmp->eth_data, &fltr->eth_data,
0731                 sizeof(fltr->eth_data)) &&
0732             !memcmp(&tmp->ip_data, &fltr->ip_data,
0733                 sizeof(fltr->ip_data)) &&
0734             !memcmp(&tmp->ext_data, &fltr->ext_data,
0735                 sizeof(fltr->ext_data)))
0736             return true;
0737     }
0738 
0739     return false;
0740 }
0741 
0742 /**
0743  * iavf_find_fdir_fltr_by_loc - find filter with location
0744  * @adapter: pointer to the VF adapter structure
0745  * @loc: location to find.
0746  *
0747  * Returns pointer to Flow Director filter if found or null
0748  */
0749 struct iavf_fdir_fltr *iavf_find_fdir_fltr_by_loc(struct iavf_adapter *adapter, u32 loc)
0750 {
0751     struct iavf_fdir_fltr *rule;
0752 
0753     list_for_each_entry(rule, &adapter->fdir_list_head, list)
0754         if (rule->loc == loc)
0755             return rule;
0756 
0757     return NULL;
0758 }
0759 
0760 /**
0761  * iavf_fdir_list_add_fltr - add a new node to the flow director filter list
0762  * @adapter: pointer to the VF adapter structure
0763  * @fltr: filter node to add to structure
0764  */
0765 void iavf_fdir_list_add_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)
0766 {
0767     struct iavf_fdir_fltr *rule, *parent = NULL;
0768 
0769     list_for_each_entry(rule, &adapter->fdir_list_head, list) {
0770         if (rule->loc >= fltr->loc)
0771             break;
0772         parent = rule;
0773     }
0774 
0775     if (parent)
0776         list_add(&fltr->list, &parent->list);
0777     else
0778         list_add(&fltr->list, &adapter->fdir_list_head);
0779 }