162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2020, Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci/* flow director ethtool support for iavf */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include "iavf.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define GTPU_PORT 2152 962306a36Sopenharmony_ci#define NAT_T_ESP_PORT 4500 1062306a36Sopenharmony_ci#define PFCP_PORT 8805 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic const struct in6_addr ipv6_addr_full_mask = { 1362306a36Sopenharmony_ci .in6_u = { 1462306a36Sopenharmony_ci .u6_addr8 = { 1562306a36Sopenharmony_ci 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1662306a36Sopenharmony_ci 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1762306a36Sopenharmony_ci } 1862306a36Sopenharmony_ci } 1962306a36Sopenharmony_ci}; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic const struct in6_addr ipv6_addr_zero_mask = { 2262306a36Sopenharmony_ci .in6_u = { 2362306a36Sopenharmony_ci .u6_addr8 = { 2462306a36Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2562306a36Sopenharmony_ci } 2662306a36Sopenharmony_ci } 2762306a36Sopenharmony_ci}; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/** 3062306a36Sopenharmony_ci * iavf_validate_fdir_fltr_masks - validate Flow Director filter fields masks 3162306a36Sopenharmony_ci * @adapter: pointer to the VF adapter structure 3262306a36Sopenharmony_ci * @fltr: Flow Director filter data structure 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * Returns 0 if all masks of packet fields are either full or empty. Returns 3562306a36Sopenharmony_ci * error on at least one partial mask. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ciint iavf_validate_fdir_fltr_masks(struct iavf_adapter *adapter, 3862306a36Sopenharmony_ci struct iavf_fdir_fltr *fltr) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci if (fltr->eth_mask.etype && fltr->eth_mask.etype != htons(U16_MAX)) 4162306a36Sopenharmony_ci goto partial_mask; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (fltr->ip_ver == 4) { 4462306a36Sopenharmony_ci if (fltr->ip_mask.v4_addrs.src_ip && 4562306a36Sopenharmony_ci fltr->ip_mask.v4_addrs.src_ip != htonl(U32_MAX)) 4662306a36Sopenharmony_ci goto partial_mask; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (fltr->ip_mask.v4_addrs.dst_ip && 4962306a36Sopenharmony_ci fltr->ip_mask.v4_addrs.dst_ip != htonl(U32_MAX)) 5062306a36Sopenharmony_ci goto partial_mask; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (fltr->ip_mask.tos && fltr->ip_mask.tos != U8_MAX) 5362306a36Sopenharmony_ci goto partial_mask; 5462306a36Sopenharmony_ci } else if (fltr->ip_ver == 6) { 5562306a36Sopenharmony_ci if (memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_zero_mask, 5662306a36Sopenharmony_ci sizeof(struct in6_addr)) && 5762306a36Sopenharmony_ci memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_full_mask, 5862306a36Sopenharmony_ci sizeof(struct in6_addr))) 5962306a36Sopenharmony_ci goto partial_mask; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_zero_mask, 6262306a36Sopenharmony_ci sizeof(struct in6_addr)) && 6362306a36Sopenharmony_ci memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_full_mask, 6462306a36Sopenharmony_ci sizeof(struct in6_addr))) 6562306a36Sopenharmony_ci goto partial_mask; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (fltr->ip_mask.tclass && fltr->ip_mask.tclass != U8_MAX) 6862306a36Sopenharmony_ci goto partial_mask; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (fltr->ip_mask.proto && fltr->ip_mask.proto != U8_MAX) 7262306a36Sopenharmony_ci goto partial_mask; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (fltr->ip_mask.src_port && fltr->ip_mask.src_port != htons(U16_MAX)) 7562306a36Sopenharmony_ci goto partial_mask; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (fltr->ip_mask.dst_port && fltr->ip_mask.dst_port != htons(U16_MAX)) 7862306a36Sopenharmony_ci goto partial_mask; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (fltr->ip_mask.spi && fltr->ip_mask.spi != htonl(U32_MAX)) 8162306a36Sopenharmony_ci goto partial_mask; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (fltr->ip_mask.l4_header && 8462306a36Sopenharmony_ci fltr->ip_mask.l4_header != htonl(U32_MAX)) 8562306a36Sopenharmony_ci goto partial_mask; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return 0; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cipartial_mask: 9062306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Failed to add Flow Director filter, partial masks are not supported\n"); 9162306a36Sopenharmony_ci return -EOPNOTSUPP; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/** 9562306a36Sopenharmony_ci * iavf_pkt_udp_no_pay_len - the length of UDP packet without payload 9662306a36Sopenharmony_ci * @fltr: Flow Director filter data structure 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_cistatic u16 iavf_pkt_udp_no_pay_len(struct iavf_fdir_fltr *fltr) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci return sizeof(struct ethhdr) + 10162306a36Sopenharmony_ci (fltr->ip_ver == 4 ? sizeof(struct iphdr) : sizeof(struct ipv6hdr)) + 10262306a36Sopenharmony_ci sizeof(struct udphdr); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/** 10662306a36Sopenharmony_ci * iavf_fill_fdir_gtpu_hdr - fill the GTP-U protocol header 10762306a36Sopenharmony_ci * @fltr: Flow Director filter data structure 10862306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci * Returns 0 if the GTP-U protocol header is set successfully 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_cistatic int 11362306a36Sopenharmony_ciiavf_fill_fdir_gtpu_hdr(struct iavf_fdir_fltr *fltr, 11462306a36Sopenharmony_ci struct virtchnl_proto_hdrs *proto_hdrs) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1]; 11762306a36Sopenharmony_ci struct virtchnl_proto_hdr *ghdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 11862306a36Sopenharmony_ci struct virtchnl_proto_hdr *ehdr = NULL; /* Extension Header if it exists */ 11962306a36Sopenharmony_ci u16 adj_offs, hdr_offs; 12062306a36Sopenharmony_ci int i; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci VIRTCHNL_SET_PROTO_HDR_TYPE(ghdr, GTPU_IP); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci adj_offs = iavf_pkt_udp_no_pay_len(fltr); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci for (i = 0; i < fltr->flex_cnt; i++) { 12762306a36Sopenharmony_ci#define IAVF_GTPU_HDR_TEID_OFFS0 4 12862306a36Sopenharmony_ci#define IAVF_GTPU_HDR_TEID_OFFS1 6 12962306a36Sopenharmony_ci#define IAVF_GTPU_HDR_N_PDU_AND_NEXT_EXTHDR_OFFS 10 13062306a36Sopenharmony_ci#define IAVF_GTPU_HDR_NEXT_EXTHDR_TYPE_MASK 0x00FF /* skip N_PDU */ 13162306a36Sopenharmony_ci/* PDU Session Container Extension Header (PSC) */ 13262306a36Sopenharmony_ci#define IAVF_GTPU_PSC_EXTHDR_TYPE 0x85 13362306a36Sopenharmony_ci#define IAVF_GTPU_HDR_PSC_PDU_TYPE_AND_QFI_OFFS 13 13462306a36Sopenharmony_ci#define IAVF_GTPU_HDR_PSC_PDU_QFI_MASK 0x3F /* skip Type */ 13562306a36Sopenharmony_ci#define IAVF_GTPU_EH_QFI_IDX 1 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (fltr->flex_words[i].offset < adj_offs) 13862306a36Sopenharmony_ci return -EINVAL; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci hdr_offs = fltr->flex_words[i].offset - adj_offs; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci switch (hdr_offs) { 14362306a36Sopenharmony_ci case IAVF_GTPU_HDR_TEID_OFFS0: 14462306a36Sopenharmony_ci case IAVF_GTPU_HDR_TEID_OFFS1: { 14562306a36Sopenharmony_ci __be16 *pay_word = (__be16 *)ghdr->buffer; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci pay_word[hdr_offs >> 1] = htons(fltr->flex_words[i].word); 14862306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(ghdr, GTPU_IP, TEID); 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci break; 15162306a36Sopenharmony_ci case IAVF_GTPU_HDR_N_PDU_AND_NEXT_EXTHDR_OFFS: 15262306a36Sopenharmony_ci if ((fltr->flex_words[i].word & 15362306a36Sopenharmony_ci IAVF_GTPU_HDR_NEXT_EXTHDR_TYPE_MASK) != 15462306a36Sopenharmony_ci IAVF_GTPU_PSC_EXTHDR_TYPE) 15562306a36Sopenharmony_ci return -EOPNOTSUPP; 15662306a36Sopenharmony_ci if (!ehdr) 15762306a36Sopenharmony_ci ehdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 15862306a36Sopenharmony_ci VIRTCHNL_SET_PROTO_HDR_TYPE(ehdr, GTPU_EH); 15962306a36Sopenharmony_ci break; 16062306a36Sopenharmony_ci case IAVF_GTPU_HDR_PSC_PDU_TYPE_AND_QFI_OFFS: 16162306a36Sopenharmony_ci if (!ehdr) 16262306a36Sopenharmony_ci return -EINVAL; 16362306a36Sopenharmony_ci ehdr->buffer[IAVF_GTPU_EH_QFI_IDX] = 16462306a36Sopenharmony_ci fltr->flex_words[i].word & 16562306a36Sopenharmony_ci IAVF_GTPU_HDR_PSC_PDU_QFI_MASK; 16662306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(ehdr, GTPU_EH, QFI); 16762306a36Sopenharmony_ci break; 16862306a36Sopenharmony_ci default: 16962306a36Sopenharmony_ci return -EINVAL; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci uhdr->field_selector = 0; /* The PF ignores the UDP header fields */ 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci return 0; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/** 17962306a36Sopenharmony_ci * iavf_fill_fdir_pfcp_hdr - fill the PFCP protocol header 18062306a36Sopenharmony_ci * @fltr: Flow Director filter data structure 18162306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure 18262306a36Sopenharmony_ci * 18362306a36Sopenharmony_ci * Returns 0 if the PFCP protocol header is set successfully 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_cistatic int 18662306a36Sopenharmony_ciiavf_fill_fdir_pfcp_hdr(struct iavf_fdir_fltr *fltr, 18762306a36Sopenharmony_ci struct virtchnl_proto_hdrs *proto_hdrs) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1]; 19062306a36Sopenharmony_ci struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 19162306a36Sopenharmony_ci u16 adj_offs, hdr_offs; 19262306a36Sopenharmony_ci int i; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, PFCP); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci adj_offs = iavf_pkt_udp_no_pay_len(fltr); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci for (i = 0; i < fltr->flex_cnt; i++) { 19962306a36Sopenharmony_ci#define IAVF_PFCP_HDR_SFIELD_AND_MSG_TYPE_OFFS 0 20062306a36Sopenharmony_ci if (fltr->flex_words[i].offset < adj_offs) 20162306a36Sopenharmony_ci return -EINVAL; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci hdr_offs = fltr->flex_words[i].offset - adj_offs; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci switch (hdr_offs) { 20662306a36Sopenharmony_ci case IAVF_PFCP_HDR_SFIELD_AND_MSG_TYPE_OFFS: 20762306a36Sopenharmony_ci hdr->buffer[0] = (fltr->flex_words[i].word >> 8) & 0xff; 20862306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, PFCP, S_FIELD); 20962306a36Sopenharmony_ci break; 21062306a36Sopenharmony_ci default: 21162306a36Sopenharmony_ci return -EINVAL; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci uhdr->field_selector = 0; /* The PF ignores the UDP header fields */ 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci return 0; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci/** 22162306a36Sopenharmony_ci * iavf_fill_fdir_nat_t_esp_hdr - fill the NAT-T-ESP protocol header 22262306a36Sopenharmony_ci * @fltr: Flow Director filter data structure 22362306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure 22462306a36Sopenharmony_ci * 22562306a36Sopenharmony_ci * Returns 0 if the NAT-T-ESP protocol header is set successfully 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_cistatic int 22862306a36Sopenharmony_ciiavf_fill_fdir_nat_t_esp_hdr(struct iavf_fdir_fltr *fltr, 22962306a36Sopenharmony_ci struct virtchnl_proto_hdrs *proto_hdrs) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1]; 23262306a36Sopenharmony_ci struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 23362306a36Sopenharmony_ci u16 adj_offs, hdr_offs; 23462306a36Sopenharmony_ci u32 spi = 0; 23562306a36Sopenharmony_ci int i; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ESP); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci adj_offs = iavf_pkt_udp_no_pay_len(fltr); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci for (i = 0; i < fltr->flex_cnt; i++) { 24262306a36Sopenharmony_ci#define IAVF_NAT_T_ESP_SPI_OFFS0 0 24362306a36Sopenharmony_ci#define IAVF_NAT_T_ESP_SPI_OFFS1 2 24462306a36Sopenharmony_ci if (fltr->flex_words[i].offset < adj_offs) 24562306a36Sopenharmony_ci return -EINVAL; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci hdr_offs = fltr->flex_words[i].offset - adj_offs; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci switch (hdr_offs) { 25062306a36Sopenharmony_ci case IAVF_NAT_T_ESP_SPI_OFFS0: 25162306a36Sopenharmony_ci spi |= fltr->flex_words[i].word << 16; 25262306a36Sopenharmony_ci break; 25362306a36Sopenharmony_ci case IAVF_NAT_T_ESP_SPI_OFFS1: 25462306a36Sopenharmony_ci spi |= fltr->flex_words[i].word; 25562306a36Sopenharmony_ci break; 25662306a36Sopenharmony_ci default: 25762306a36Sopenharmony_ci return -EINVAL; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (!spi) 26262306a36Sopenharmony_ci return -EOPNOTSUPP; /* Not support IKE Header Format with SPI 0 */ 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci *(__be32 *)hdr->buffer = htonl(spi); 26562306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ESP, SPI); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci uhdr->field_selector = 0; /* The PF ignores the UDP header fields */ 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci return 0; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/** 27362306a36Sopenharmony_ci * iavf_fill_fdir_udp_flex_pay_hdr - fill the UDP payload header 27462306a36Sopenharmony_ci * @fltr: Flow Director filter data structure 27562306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure 27662306a36Sopenharmony_ci * 27762306a36Sopenharmony_ci * Returns 0 if the UDP payload defined protocol header is set successfully 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_cistatic int 28062306a36Sopenharmony_ciiavf_fill_fdir_udp_flex_pay_hdr(struct iavf_fdir_fltr *fltr, 28162306a36Sopenharmony_ci struct virtchnl_proto_hdrs *proto_hdrs) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci int err; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci switch (ntohs(fltr->ip_data.dst_port)) { 28662306a36Sopenharmony_ci case GTPU_PORT: 28762306a36Sopenharmony_ci err = iavf_fill_fdir_gtpu_hdr(fltr, proto_hdrs); 28862306a36Sopenharmony_ci break; 28962306a36Sopenharmony_ci case NAT_T_ESP_PORT: 29062306a36Sopenharmony_ci err = iavf_fill_fdir_nat_t_esp_hdr(fltr, proto_hdrs); 29162306a36Sopenharmony_ci break; 29262306a36Sopenharmony_ci case PFCP_PORT: 29362306a36Sopenharmony_ci err = iavf_fill_fdir_pfcp_hdr(fltr, proto_hdrs); 29462306a36Sopenharmony_ci break; 29562306a36Sopenharmony_ci default: 29662306a36Sopenharmony_ci err = -EOPNOTSUPP; 29762306a36Sopenharmony_ci break; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return err; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci/** 30462306a36Sopenharmony_ci * iavf_fill_fdir_ip4_hdr - fill the IPv4 protocol header 30562306a36Sopenharmony_ci * @fltr: Flow Director filter data structure 30662306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure 30762306a36Sopenharmony_ci * 30862306a36Sopenharmony_ci * Returns 0 if the IPv4 protocol header is set successfully 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_cistatic int 31162306a36Sopenharmony_ciiavf_fill_fdir_ip4_hdr(struct iavf_fdir_fltr *fltr, 31262306a36Sopenharmony_ci struct virtchnl_proto_hdrs *proto_hdrs) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 31562306a36Sopenharmony_ci struct iphdr *iph = (struct iphdr *)hdr->buffer; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV4); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (fltr->ip_mask.tos == U8_MAX) { 32062306a36Sopenharmony_ci iph->tos = fltr->ip_data.tos; 32162306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DSCP); 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (fltr->ip_mask.proto == U8_MAX) { 32562306a36Sopenharmony_ci iph->protocol = fltr->ip_data.proto; 32662306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, PROT); 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (fltr->ip_mask.v4_addrs.src_ip == htonl(U32_MAX)) { 33062306a36Sopenharmony_ci iph->saddr = fltr->ip_data.v4_addrs.src_ip; 33162306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, SRC); 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (fltr->ip_mask.v4_addrs.dst_ip == htonl(U32_MAX)) { 33562306a36Sopenharmony_ci iph->daddr = fltr->ip_data.v4_addrs.dst_ip; 33662306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DST); 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return 0; 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci/** 34362306a36Sopenharmony_ci * iavf_fill_fdir_ip6_hdr - fill the IPv6 protocol header 34462306a36Sopenharmony_ci * @fltr: Flow Director filter data structure 34562306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure 34662306a36Sopenharmony_ci * 34762306a36Sopenharmony_ci * Returns 0 if the IPv6 protocol header is set successfully 34862306a36Sopenharmony_ci */ 34962306a36Sopenharmony_cistatic int 35062306a36Sopenharmony_ciiavf_fill_fdir_ip6_hdr(struct iavf_fdir_fltr *fltr, 35162306a36Sopenharmony_ci struct virtchnl_proto_hdrs *proto_hdrs) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 35462306a36Sopenharmony_ci struct ipv6hdr *iph = (struct ipv6hdr *)hdr->buffer; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV6); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (fltr->ip_mask.tclass == U8_MAX) { 35962306a36Sopenharmony_ci iph->priority = (fltr->ip_data.tclass >> 4) & 0xF; 36062306a36Sopenharmony_ci iph->flow_lbl[0] = (fltr->ip_data.tclass << 4) & 0xF0; 36162306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, TC); 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (fltr->ip_mask.proto == U8_MAX) { 36562306a36Sopenharmony_ci iph->nexthdr = fltr->ip_data.proto; 36662306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, PROT); 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (!memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_full_mask, 37062306a36Sopenharmony_ci sizeof(struct in6_addr))) { 37162306a36Sopenharmony_ci memcpy(&iph->saddr, &fltr->ip_data.v6_addrs.src_ip, 37262306a36Sopenharmony_ci sizeof(struct in6_addr)); 37362306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, SRC); 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (!memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_full_mask, 37762306a36Sopenharmony_ci sizeof(struct in6_addr))) { 37862306a36Sopenharmony_ci memcpy(&iph->daddr, &fltr->ip_data.v6_addrs.dst_ip, 37962306a36Sopenharmony_ci sizeof(struct in6_addr)); 38062306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, DST); 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci return 0; 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci/** 38762306a36Sopenharmony_ci * iavf_fill_fdir_tcp_hdr - fill the TCP protocol header 38862306a36Sopenharmony_ci * @fltr: Flow Director filter data structure 38962306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure 39062306a36Sopenharmony_ci * 39162306a36Sopenharmony_ci * Returns 0 if the TCP protocol header is set successfully 39262306a36Sopenharmony_ci */ 39362306a36Sopenharmony_cistatic int 39462306a36Sopenharmony_ciiavf_fill_fdir_tcp_hdr(struct iavf_fdir_fltr *fltr, 39562306a36Sopenharmony_ci struct virtchnl_proto_hdrs *proto_hdrs) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 39862306a36Sopenharmony_ci struct tcphdr *tcph = (struct tcphdr *)hdr->buffer; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, TCP); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (fltr->ip_mask.src_port == htons(U16_MAX)) { 40362306a36Sopenharmony_ci tcph->source = fltr->ip_data.src_port; 40462306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, SRC_PORT); 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (fltr->ip_mask.dst_port == htons(U16_MAX)) { 40862306a36Sopenharmony_ci tcph->dest = fltr->ip_data.dst_port; 40962306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, DST_PORT); 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return 0; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci/** 41662306a36Sopenharmony_ci * iavf_fill_fdir_udp_hdr - fill the UDP protocol header 41762306a36Sopenharmony_ci * @fltr: Flow Director filter data structure 41862306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure 41962306a36Sopenharmony_ci * 42062306a36Sopenharmony_ci * Returns 0 if the UDP protocol header is set successfully 42162306a36Sopenharmony_ci */ 42262306a36Sopenharmony_cistatic int 42362306a36Sopenharmony_ciiavf_fill_fdir_udp_hdr(struct iavf_fdir_fltr *fltr, 42462306a36Sopenharmony_ci struct virtchnl_proto_hdrs *proto_hdrs) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 42762306a36Sopenharmony_ci struct udphdr *udph = (struct udphdr *)hdr->buffer; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, UDP); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (fltr->ip_mask.src_port == htons(U16_MAX)) { 43262306a36Sopenharmony_ci udph->source = fltr->ip_data.src_port; 43362306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, SRC_PORT); 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (fltr->ip_mask.dst_port == htons(U16_MAX)) { 43762306a36Sopenharmony_ci udph->dest = fltr->ip_data.dst_port; 43862306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, DST_PORT); 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (!fltr->flex_cnt) 44262306a36Sopenharmony_ci return 0; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci return iavf_fill_fdir_udp_flex_pay_hdr(fltr, proto_hdrs); 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci/** 44862306a36Sopenharmony_ci * iavf_fill_fdir_sctp_hdr - fill the SCTP protocol header 44962306a36Sopenharmony_ci * @fltr: Flow Director filter data structure 45062306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure 45162306a36Sopenharmony_ci * 45262306a36Sopenharmony_ci * Returns 0 if the SCTP protocol header is set successfully 45362306a36Sopenharmony_ci */ 45462306a36Sopenharmony_cistatic int 45562306a36Sopenharmony_ciiavf_fill_fdir_sctp_hdr(struct iavf_fdir_fltr *fltr, 45662306a36Sopenharmony_ci struct virtchnl_proto_hdrs *proto_hdrs) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 45962306a36Sopenharmony_ci struct sctphdr *sctph = (struct sctphdr *)hdr->buffer; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, SCTP); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (fltr->ip_mask.src_port == htons(U16_MAX)) { 46462306a36Sopenharmony_ci sctph->source = fltr->ip_data.src_port; 46562306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, SRC_PORT); 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (fltr->ip_mask.dst_port == htons(U16_MAX)) { 46962306a36Sopenharmony_ci sctph->dest = fltr->ip_data.dst_port; 47062306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, DST_PORT); 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci return 0; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci/** 47762306a36Sopenharmony_ci * iavf_fill_fdir_ah_hdr - fill the AH protocol header 47862306a36Sopenharmony_ci * @fltr: Flow Director filter data structure 47962306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure 48062306a36Sopenharmony_ci * 48162306a36Sopenharmony_ci * Returns 0 if the AH protocol header is set successfully 48262306a36Sopenharmony_ci */ 48362306a36Sopenharmony_cistatic int 48462306a36Sopenharmony_ciiavf_fill_fdir_ah_hdr(struct iavf_fdir_fltr *fltr, 48562306a36Sopenharmony_ci struct virtchnl_proto_hdrs *proto_hdrs) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 48862306a36Sopenharmony_ci struct ip_auth_hdr *ah = (struct ip_auth_hdr *)hdr->buffer; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, AH); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (fltr->ip_mask.spi == htonl(U32_MAX)) { 49362306a36Sopenharmony_ci ah->spi = fltr->ip_data.spi; 49462306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, AH, SPI); 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return 0; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci/** 50162306a36Sopenharmony_ci * iavf_fill_fdir_esp_hdr - fill the ESP protocol header 50262306a36Sopenharmony_ci * @fltr: Flow Director filter data structure 50362306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure 50462306a36Sopenharmony_ci * 50562306a36Sopenharmony_ci * Returns 0 if the ESP protocol header is set successfully 50662306a36Sopenharmony_ci */ 50762306a36Sopenharmony_cistatic int 50862306a36Sopenharmony_ciiavf_fill_fdir_esp_hdr(struct iavf_fdir_fltr *fltr, 50962306a36Sopenharmony_ci struct virtchnl_proto_hdrs *proto_hdrs) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 51262306a36Sopenharmony_ci struct ip_esp_hdr *esph = (struct ip_esp_hdr *)hdr->buffer; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ESP); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci if (fltr->ip_mask.spi == htonl(U32_MAX)) { 51762306a36Sopenharmony_ci esph->spi = fltr->ip_data.spi; 51862306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ESP, SPI); 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return 0; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci/** 52562306a36Sopenharmony_ci * iavf_fill_fdir_l4_hdr - fill the L4 protocol header 52662306a36Sopenharmony_ci * @fltr: Flow Director filter data structure 52762306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure 52862306a36Sopenharmony_ci * 52962306a36Sopenharmony_ci * Returns 0 if the L4 protocol header is set successfully 53062306a36Sopenharmony_ci */ 53162306a36Sopenharmony_cistatic int 53262306a36Sopenharmony_ciiavf_fill_fdir_l4_hdr(struct iavf_fdir_fltr *fltr, 53362306a36Sopenharmony_ci struct virtchnl_proto_hdrs *proto_hdrs) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci struct virtchnl_proto_hdr *hdr; 53662306a36Sopenharmony_ci __be32 *l4_4_data; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (!fltr->ip_mask.proto) /* IPv4/IPv6 header only */ 53962306a36Sopenharmony_ci return 0; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 54262306a36Sopenharmony_ci l4_4_data = (__be32 *)hdr->buffer; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* L2TPv3 over IP with 'Session ID' */ 54562306a36Sopenharmony_ci if (fltr->ip_data.proto == 115 && fltr->ip_mask.l4_header == htonl(U32_MAX)) { 54662306a36Sopenharmony_ci VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, L2TPV3); 54762306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, L2TPV3, SESS_ID); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci *l4_4_data = fltr->ip_data.l4_header; 55062306a36Sopenharmony_ci } else { 55162306a36Sopenharmony_ci return -EOPNOTSUPP; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci return 0; 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci/** 55862306a36Sopenharmony_ci * iavf_fill_fdir_eth_hdr - fill the Ethernet protocol header 55962306a36Sopenharmony_ci * @fltr: Flow Director filter data structure 56062306a36Sopenharmony_ci * @proto_hdrs: Flow Director protocol headers data structure 56162306a36Sopenharmony_ci * 56262306a36Sopenharmony_ci * Returns 0 if the Ethernet protocol header is set successfully 56362306a36Sopenharmony_ci */ 56462306a36Sopenharmony_cistatic int 56562306a36Sopenharmony_ciiavf_fill_fdir_eth_hdr(struct iavf_fdir_fltr *fltr, 56662306a36Sopenharmony_ci struct virtchnl_proto_hdrs *proto_hdrs) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 56962306a36Sopenharmony_ci struct ethhdr *ehdr = (struct ethhdr *)hdr->buffer; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ETH); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (fltr->eth_mask.etype == htons(U16_MAX)) { 57462306a36Sopenharmony_ci if (fltr->eth_data.etype == htons(ETH_P_IP) || 57562306a36Sopenharmony_ci fltr->eth_data.etype == htons(ETH_P_IPV6)) 57662306a36Sopenharmony_ci return -EOPNOTSUPP; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci ehdr->h_proto = fltr->eth_data.etype; 57962306a36Sopenharmony_ci VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ETH, ETHERTYPE); 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci return 0; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci/** 58662306a36Sopenharmony_ci * iavf_fill_fdir_add_msg - fill the Flow Director filter into virtchnl message 58762306a36Sopenharmony_ci * @adapter: pointer to the VF adapter structure 58862306a36Sopenharmony_ci * @fltr: Flow Director filter data structure 58962306a36Sopenharmony_ci * 59062306a36Sopenharmony_ci * Returns 0 if the add Flow Director virtchnl message is filled successfully 59162306a36Sopenharmony_ci */ 59262306a36Sopenharmony_ciint iavf_fill_fdir_add_msg(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci struct virtchnl_fdir_add *vc_msg = &fltr->vc_add_msg; 59562306a36Sopenharmony_ci struct virtchnl_proto_hdrs *proto_hdrs; 59662306a36Sopenharmony_ci int err; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci proto_hdrs = &vc_msg->rule_cfg.proto_hdrs; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci err = iavf_fill_fdir_eth_hdr(fltr, proto_hdrs); /* L2 always exists */ 60162306a36Sopenharmony_ci if (err) 60262306a36Sopenharmony_ci return err; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci switch (fltr->flow_type) { 60562306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV4_TCP: 60662306a36Sopenharmony_ci err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) | 60762306a36Sopenharmony_ci iavf_fill_fdir_tcp_hdr(fltr, proto_hdrs); 60862306a36Sopenharmony_ci break; 60962306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV4_UDP: 61062306a36Sopenharmony_ci err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) | 61162306a36Sopenharmony_ci iavf_fill_fdir_udp_hdr(fltr, proto_hdrs); 61262306a36Sopenharmony_ci break; 61362306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV4_SCTP: 61462306a36Sopenharmony_ci err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) | 61562306a36Sopenharmony_ci iavf_fill_fdir_sctp_hdr(fltr, proto_hdrs); 61662306a36Sopenharmony_ci break; 61762306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV4_AH: 61862306a36Sopenharmony_ci err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) | 61962306a36Sopenharmony_ci iavf_fill_fdir_ah_hdr(fltr, proto_hdrs); 62062306a36Sopenharmony_ci break; 62162306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV4_ESP: 62262306a36Sopenharmony_ci err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) | 62362306a36Sopenharmony_ci iavf_fill_fdir_esp_hdr(fltr, proto_hdrs); 62462306a36Sopenharmony_ci break; 62562306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV4_OTHER: 62662306a36Sopenharmony_ci err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) | 62762306a36Sopenharmony_ci iavf_fill_fdir_l4_hdr(fltr, proto_hdrs); 62862306a36Sopenharmony_ci break; 62962306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV6_TCP: 63062306a36Sopenharmony_ci err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) | 63162306a36Sopenharmony_ci iavf_fill_fdir_tcp_hdr(fltr, proto_hdrs); 63262306a36Sopenharmony_ci break; 63362306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV6_UDP: 63462306a36Sopenharmony_ci err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) | 63562306a36Sopenharmony_ci iavf_fill_fdir_udp_hdr(fltr, proto_hdrs); 63662306a36Sopenharmony_ci break; 63762306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV6_SCTP: 63862306a36Sopenharmony_ci err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) | 63962306a36Sopenharmony_ci iavf_fill_fdir_sctp_hdr(fltr, proto_hdrs); 64062306a36Sopenharmony_ci break; 64162306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV6_AH: 64262306a36Sopenharmony_ci err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) | 64362306a36Sopenharmony_ci iavf_fill_fdir_ah_hdr(fltr, proto_hdrs); 64462306a36Sopenharmony_ci break; 64562306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV6_ESP: 64662306a36Sopenharmony_ci err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) | 64762306a36Sopenharmony_ci iavf_fill_fdir_esp_hdr(fltr, proto_hdrs); 64862306a36Sopenharmony_ci break; 64962306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV6_OTHER: 65062306a36Sopenharmony_ci err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) | 65162306a36Sopenharmony_ci iavf_fill_fdir_l4_hdr(fltr, proto_hdrs); 65262306a36Sopenharmony_ci break; 65362306a36Sopenharmony_ci case IAVF_FDIR_FLOW_NON_IP_L2: 65462306a36Sopenharmony_ci break; 65562306a36Sopenharmony_ci default: 65662306a36Sopenharmony_ci err = -EINVAL; 65762306a36Sopenharmony_ci break; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (err) 66162306a36Sopenharmony_ci return err; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci vc_msg->vsi_id = adapter->vsi.id; 66462306a36Sopenharmony_ci vc_msg->rule_cfg.action_set.count = 1; 66562306a36Sopenharmony_ci vc_msg->rule_cfg.action_set.actions[0].type = fltr->action; 66662306a36Sopenharmony_ci vc_msg->rule_cfg.action_set.actions[0].act_conf.queue.index = fltr->q_index; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci return 0; 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci/** 67262306a36Sopenharmony_ci * iavf_fdir_flow_proto_name - get the flow protocol name 67362306a36Sopenharmony_ci * @flow_type: Flow Director filter flow type 67462306a36Sopenharmony_ci **/ 67562306a36Sopenharmony_cistatic const char *iavf_fdir_flow_proto_name(enum iavf_fdir_flow_type flow_type) 67662306a36Sopenharmony_ci{ 67762306a36Sopenharmony_ci switch (flow_type) { 67862306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV4_TCP: 67962306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV6_TCP: 68062306a36Sopenharmony_ci return "TCP"; 68162306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV4_UDP: 68262306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV6_UDP: 68362306a36Sopenharmony_ci return "UDP"; 68462306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV4_SCTP: 68562306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV6_SCTP: 68662306a36Sopenharmony_ci return "SCTP"; 68762306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV4_AH: 68862306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV6_AH: 68962306a36Sopenharmony_ci return "AH"; 69062306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV4_ESP: 69162306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV6_ESP: 69262306a36Sopenharmony_ci return "ESP"; 69362306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV4_OTHER: 69462306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV6_OTHER: 69562306a36Sopenharmony_ci return "Other"; 69662306a36Sopenharmony_ci case IAVF_FDIR_FLOW_NON_IP_L2: 69762306a36Sopenharmony_ci return "Ethernet"; 69862306a36Sopenharmony_ci default: 69962306a36Sopenharmony_ci return NULL; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci} 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci/** 70462306a36Sopenharmony_ci * iavf_print_fdir_fltr 70562306a36Sopenharmony_ci * @adapter: adapter structure 70662306a36Sopenharmony_ci * @fltr: Flow Director filter to print 70762306a36Sopenharmony_ci * 70862306a36Sopenharmony_ci * Print the Flow Director filter 70962306a36Sopenharmony_ci **/ 71062306a36Sopenharmony_civoid iavf_print_fdir_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci const char *proto = iavf_fdir_flow_proto_name(fltr->flow_type); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (!proto) 71562306a36Sopenharmony_ci return; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci switch (fltr->flow_type) { 71862306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV4_TCP: 71962306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV4_UDP: 72062306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV4_SCTP: 72162306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 %s: dst_port %hu src_port %hu\n", 72262306a36Sopenharmony_ci fltr->loc, 72362306a36Sopenharmony_ci &fltr->ip_data.v4_addrs.dst_ip, 72462306a36Sopenharmony_ci &fltr->ip_data.v4_addrs.src_ip, 72562306a36Sopenharmony_ci proto, 72662306a36Sopenharmony_ci ntohs(fltr->ip_data.dst_port), 72762306a36Sopenharmony_ci ntohs(fltr->ip_data.src_port)); 72862306a36Sopenharmony_ci break; 72962306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV4_AH: 73062306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV4_ESP: 73162306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 %s: SPI %u\n", 73262306a36Sopenharmony_ci fltr->loc, 73362306a36Sopenharmony_ci &fltr->ip_data.v4_addrs.dst_ip, 73462306a36Sopenharmony_ci &fltr->ip_data.v4_addrs.src_ip, 73562306a36Sopenharmony_ci proto, 73662306a36Sopenharmony_ci ntohl(fltr->ip_data.spi)); 73762306a36Sopenharmony_ci break; 73862306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV4_OTHER: 73962306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 proto: %u L4_bytes: 0x%x\n", 74062306a36Sopenharmony_ci fltr->loc, 74162306a36Sopenharmony_ci &fltr->ip_data.v4_addrs.dst_ip, 74262306a36Sopenharmony_ci &fltr->ip_data.v4_addrs.src_ip, 74362306a36Sopenharmony_ci fltr->ip_data.proto, 74462306a36Sopenharmony_ci ntohl(fltr->ip_data.l4_header)); 74562306a36Sopenharmony_ci break; 74662306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV6_TCP: 74762306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV6_UDP: 74862306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV6_SCTP: 74962306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 %s: dst_port %hu src_port %hu\n", 75062306a36Sopenharmony_ci fltr->loc, 75162306a36Sopenharmony_ci &fltr->ip_data.v6_addrs.dst_ip, 75262306a36Sopenharmony_ci &fltr->ip_data.v6_addrs.src_ip, 75362306a36Sopenharmony_ci proto, 75462306a36Sopenharmony_ci ntohs(fltr->ip_data.dst_port), 75562306a36Sopenharmony_ci ntohs(fltr->ip_data.src_port)); 75662306a36Sopenharmony_ci break; 75762306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV6_AH: 75862306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV6_ESP: 75962306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 %s: SPI %u\n", 76062306a36Sopenharmony_ci fltr->loc, 76162306a36Sopenharmony_ci &fltr->ip_data.v6_addrs.dst_ip, 76262306a36Sopenharmony_ci &fltr->ip_data.v6_addrs.src_ip, 76362306a36Sopenharmony_ci proto, 76462306a36Sopenharmony_ci ntohl(fltr->ip_data.spi)); 76562306a36Sopenharmony_ci break; 76662306a36Sopenharmony_ci case IAVF_FDIR_FLOW_IPV6_OTHER: 76762306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 proto: %u L4_bytes: 0x%x\n", 76862306a36Sopenharmony_ci fltr->loc, 76962306a36Sopenharmony_ci &fltr->ip_data.v6_addrs.dst_ip, 77062306a36Sopenharmony_ci &fltr->ip_data.v6_addrs.src_ip, 77162306a36Sopenharmony_ci fltr->ip_data.proto, 77262306a36Sopenharmony_ci ntohl(fltr->ip_data.l4_header)); 77362306a36Sopenharmony_ci break; 77462306a36Sopenharmony_ci case IAVF_FDIR_FLOW_NON_IP_L2: 77562306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "Rule ID: %u eth_type: 0x%x\n", 77662306a36Sopenharmony_ci fltr->loc, 77762306a36Sopenharmony_ci ntohs(fltr->eth_data.etype)); 77862306a36Sopenharmony_ci break; 77962306a36Sopenharmony_ci default: 78062306a36Sopenharmony_ci break; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci/** 78562306a36Sopenharmony_ci * iavf_fdir_is_dup_fltr - test if filter is already in list 78662306a36Sopenharmony_ci * @adapter: pointer to the VF adapter structure 78762306a36Sopenharmony_ci * @fltr: Flow Director filter data structure 78862306a36Sopenharmony_ci * 78962306a36Sopenharmony_ci * Returns true if the filter is found in the list 79062306a36Sopenharmony_ci */ 79162306a36Sopenharmony_cibool iavf_fdir_is_dup_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr) 79262306a36Sopenharmony_ci{ 79362306a36Sopenharmony_ci struct iavf_fdir_fltr *tmp; 79462306a36Sopenharmony_ci bool ret = false; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci spin_lock_bh(&adapter->fdir_fltr_lock); 79762306a36Sopenharmony_ci list_for_each_entry(tmp, &adapter->fdir_list_head, list) { 79862306a36Sopenharmony_ci if (tmp->flow_type != fltr->flow_type) 79962306a36Sopenharmony_ci continue; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (!memcmp(&tmp->eth_data, &fltr->eth_data, 80262306a36Sopenharmony_ci sizeof(fltr->eth_data)) && 80362306a36Sopenharmony_ci !memcmp(&tmp->ip_data, &fltr->ip_data, 80462306a36Sopenharmony_ci sizeof(fltr->ip_data)) && 80562306a36Sopenharmony_ci !memcmp(&tmp->ext_data, &fltr->ext_data, 80662306a36Sopenharmony_ci sizeof(fltr->ext_data))) { 80762306a36Sopenharmony_ci ret = true; 80862306a36Sopenharmony_ci break; 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci spin_unlock_bh(&adapter->fdir_fltr_lock); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci return ret; 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci/** 81762306a36Sopenharmony_ci * iavf_find_fdir_fltr_by_loc - find filter with location 81862306a36Sopenharmony_ci * @adapter: pointer to the VF adapter structure 81962306a36Sopenharmony_ci * @loc: location to find. 82062306a36Sopenharmony_ci * 82162306a36Sopenharmony_ci * Returns pointer to Flow Director filter if found or null 82262306a36Sopenharmony_ci */ 82362306a36Sopenharmony_cistruct iavf_fdir_fltr *iavf_find_fdir_fltr_by_loc(struct iavf_adapter *adapter, u32 loc) 82462306a36Sopenharmony_ci{ 82562306a36Sopenharmony_ci struct iavf_fdir_fltr *rule; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci list_for_each_entry(rule, &adapter->fdir_list_head, list) 82862306a36Sopenharmony_ci if (rule->loc == loc) 82962306a36Sopenharmony_ci return rule; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci return NULL; 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci/** 83562306a36Sopenharmony_ci * iavf_fdir_list_add_fltr - add a new node to the flow director filter list 83662306a36Sopenharmony_ci * @adapter: pointer to the VF adapter structure 83762306a36Sopenharmony_ci * @fltr: filter node to add to structure 83862306a36Sopenharmony_ci */ 83962306a36Sopenharmony_civoid iavf_fdir_list_add_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr) 84062306a36Sopenharmony_ci{ 84162306a36Sopenharmony_ci struct iavf_fdir_fltr *rule, *parent = NULL; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci list_for_each_entry(rule, &adapter->fdir_list_head, list) { 84462306a36Sopenharmony_ci if (rule->loc >= fltr->loc) 84562306a36Sopenharmony_ci break; 84662306a36Sopenharmony_ci parent = rule; 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if (parent) 85062306a36Sopenharmony_ci list_add(&fltr->list, &parent->list); 85162306a36Sopenharmony_ci else 85262306a36Sopenharmony_ci list_add(&fltr->list, &adapter->fdir_list_head); 85362306a36Sopenharmony_ci} 854