928 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2020, Intel Corporation. */3 4/* flow director ethtool support for iavf */5 6#include <linux/bitfield.h>7#include "iavf.h"8 9#define GTPU_PORT 215210#define NAT_T_ESP_PORT 450011#define PFCP_PORT 880512 13static const struct in6_addr ipv6_addr_full_mask = {14 .in6_u = {15 .u6_addr8 = {16 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,17 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,18 }19 }20};21 22static const struct in6_addr ipv6_addr_zero_mask = {23 .in6_u = {24 .u6_addr8 = {25 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,26 }27 }28};29 30/**31 * iavf_validate_fdir_fltr_masks - validate Flow Director filter fields masks32 * @adapter: pointer to the VF adapter structure33 * @fltr: Flow Director filter data structure34 *35 * Returns 0 if all masks of packet fields are either full or empty. Returns36 * error on at least one partial mask.37 */38int iavf_validate_fdir_fltr_masks(struct iavf_adapter *adapter,39 struct iavf_fdir_fltr *fltr)40{41 if (fltr->eth_mask.etype && fltr->eth_mask.etype != htons(U16_MAX))42 goto partial_mask;43 44 if (fltr->ip_ver == 4) {45 if (fltr->ip_mask.v4_addrs.src_ip &&46 fltr->ip_mask.v4_addrs.src_ip != htonl(U32_MAX))47 goto partial_mask;48 49 if (fltr->ip_mask.v4_addrs.dst_ip &&50 fltr->ip_mask.v4_addrs.dst_ip != htonl(U32_MAX))51 goto partial_mask;52 53 if (fltr->ip_mask.tos && fltr->ip_mask.tos != U8_MAX)54 goto partial_mask;55 } else if (fltr->ip_ver == 6) {56 if (memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_zero_mask,57 sizeof(struct in6_addr)) &&58 memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_full_mask,59 sizeof(struct in6_addr)))60 goto partial_mask;61 62 if (memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_zero_mask,63 sizeof(struct in6_addr)) &&64 memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_full_mask,65 sizeof(struct in6_addr)))66 goto partial_mask;67 68 if (fltr->ip_mask.tclass && fltr->ip_mask.tclass != U8_MAX)69 goto partial_mask;70 }71 72 if (fltr->ip_mask.proto && fltr->ip_mask.proto != U8_MAX)73 goto partial_mask;74 75 if (fltr->ip_mask.src_port && fltr->ip_mask.src_port != htons(U16_MAX))76 goto partial_mask;77 78 if (fltr->ip_mask.dst_port && fltr->ip_mask.dst_port != htons(U16_MAX))79 goto partial_mask;80 81 if (fltr->ip_mask.spi && fltr->ip_mask.spi != htonl(U32_MAX))82 goto partial_mask;83 84 if (fltr->ip_mask.l4_header &&85 fltr->ip_mask.l4_header != htonl(U32_MAX))86 goto partial_mask;87 88 return 0;89 90partial_mask:91 dev_err(&adapter->pdev->dev, "Failed to add Flow Director filter, partial masks are not supported\n");92 return -EOPNOTSUPP;93}94 95/**96 * iavf_pkt_udp_no_pay_len - the length of UDP packet without payload97 * @fltr: Flow Director filter data structure98 */99static u16 iavf_pkt_udp_no_pay_len(struct iavf_fdir_fltr *fltr)100{101 return sizeof(struct ethhdr) +102 (fltr->ip_ver == 4 ? sizeof(struct iphdr) : sizeof(struct ipv6hdr)) +103 sizeof(struct udphdr);104}105 106/**107 * iavf_fill_fdir_gtpu_hdr - fill the GTP-U protocol header108 * @fltr: Flow Director filter data structure109 * @proto_hdrs: Flow Director protocol headers data structure110 *111 * Returns 0 if the GTP-U protocol header is set successfully112 */113static int114iavf_fill_fdir_gtpu_hdr(struct iavf_fdir_fltr *fltr,115 struct virtchnl_proto_hdrs *proto_hdrs)116{117 struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1];118 struct virtchnl_proto_hdr *ghdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];119 struct virtchnl_proto_hdr *ehdr = NULL; /* Extension Header if it exists */120 u16 adj_offs, hdr_offs;121 int i;122 123 VIRTCHNL_SET_PROTO_HDR_TYPE(ghdr, GTPU_IP);124 125 adj_offs = iavf_pkt_udp_no_pay_len(fltr);126 127 for (i = 0; i < fltr->flex_cnt; i++) {128#define IAVF_GTPU_HDR_TEID_OFFS0 4129#define IAVF_GTPU_HDR_TEID_OFFS1 6130#define IAVF_GTPU_HDR_N_PDU_AND_NEXT_EXTHDR_OFFS 10131#define IAVF_GTPU_HDR_NEXT_EXTHDR_TYPE_MASK 0x00FF /* skip N_PDU */132/* PDU Session Container Extension Header (PSC) */133#define IAVF_GTPU_PSC_EXTHDR_TYPE 0x85134#define IAVF_GTPU_HDR_PSC_PDU_TYPE_AND_QFI_OFFS 13135#define IAVF_GTPU_HDR_PSC_PDU_QFI_MASK 0x3F /* skip Type */136#define IAVF_GTPU_EH_QFI_IDX 1137 138 if (fltr->flex_words[i].offset < adj_offs)139 return -EINVAL;140 141 hdr_offs = fltr->flex_words[i].offset - adj_offs;142 143 switch (hdr_offs) {144 case IAVF_GTPU_HDR_TEID_OFFS0:145 case IAVF_GTPU_HDR_TEID_OFFS1: {146 __be16 *pay_word = (__be16 *)ghdr->buffer;147 148 pay_word[hdr_offs >> 1] = htons(fltr->flex_words[i].word);149 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(ghdr, GTPU_IP, TEID);150 }151 break;152 case IAVF_GTPU_HDR_N_PDU_AND_NEXT_EXTHDR_OFFS:153 if ((fltr->flex_words[i].word &154 IAVF_GTPU_HDR_NEXT_EXTHDR_TYPE_MASK) !=155 IAVF_GTPU_PSC_EXTHDR_TYPE)156 return -EOPNOTSUPP;157 if (!ehdr)158 ehdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];159 VIRTCHNL_SET_PROTO_HDR_TYPE(ehdr, GTPU_EH);160 break;161 case IAVF_GTPU_HDR_PSC_PDU_TYPE_AND_QFI_OFFS:162 if (!ehdr)163 return -EINVAL;164 ehdr->buffer[IAVF_GTPU_EH_QFI_IDX] =165 fltr->flex_words[i].word &166 IAVF_GTPU_HDR_PSC_PDU_QFI_MASK;167 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(ehdr, GTPU_EH, QFI);168 break;169 default:170 return -EINVAL;171 }172 }173 174 uhdr->field_selector = 0; /* The PF ignores the UDP header fields */175 176 return 0;177}178 179/**180 * iavf_fill_fdir_pfcp_hdr - fill the PFCP protocol header181 * @fltr: Flow Director filter data structure182 * @proto_hdrs: Flow Director protocol headers data structure183 *184 * Returns 0 if the PFCP protocol header is set successfully185 */186static int187iavf_fill_fdir_pfcp_hdr(struct iavf_fdir_fltr *fltr,188 struct virtchnl_proto_hdrs *proto_hdrs)189{190 struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1];191 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];192 u16 adj_offs, hdr_offs;193 int i;194 195 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, PFCP);196 197 adj_offs = iavf_pkt_udp_no_pay_len(fltr);198 199 for (i = 0; i < fltr->flex_cnt; i++) {200#define IAVF_PFCP_HDR_SFIELD_AND_MSG_TYPE_OFFS 0201 if (fltr->flex_words[i].offset < adj_offs)202 return -EINVAL;203 204 hdr_offs = fltr->flex_words[i].offset - adj_offs;205 206 switch (hdr_offs) {207 case IAVF_PFCP_HDR_SFIELD_AND_MSG_TYPE_OFFS:208 hdr->buffer[0] = (fltr->flex_words[i].word >> 8) & 0xff;209 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, PFCP, S_FIELD);210 break;211 default:212 return -EINVAL;213 }214 }215 216 uhdr->field_selector = 0; /* The PF ignores the UDP header fields */217 218 return 0;219}220 221/**222 * iavf_fill_fdir_nat_t_esp_hdr - fill the NAT-T-ESP protocol header223 * @fltr: Flow Director filter data structure224 * @proto_hdrs: Flow Director protocol headers data structure225 *226 * Returns 0 if the NAT-T-ESP protocol header is set successfully227 */228static int229iavf_fill_fdir_nat_t_esp_hdr(struct iavf_fdir_fltr *fltr,230 struct virtchnl_proto_hdrs *proto_hdrs)231{232 struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1];233 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];234 u16 adj_offs, hdr_offs;235 u32 spi = 0;236 int i;237 238 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ESP);239 240 adj_offs = iavf_pkt_udp_no_pay_len(fltr);241 242 for (i = 0; i < fltr->flex_cnt; i++) {243#define IAVF_NAT_T_ESP_SPI_OFFS0 0244#define IAVF_NAT_T_ESP_SPI_OFFS1 2245 if (fltr->flex_words[i].offset < adj_offs)246 return -EINVAL;247 248 hdr_offs = fltr->flex_words[i].offset - adj_offs;249 250 switch (hdr_offs) {251 case IAVF_NAT_T_ESP_SPI_OFFS0:252 spi |= fltr->flex_words[i].word << 16;253 break;254 case IAVF_NAT_T_ESP_SPI_OFFS1:255 spi |= fltr->flex_words[i].word;256 break;257 default:258 return -EINVAL;259 }260 }261 262 if (!spi)263 return -EOPNOTSUPP; /* Not support IKE Header Format with SPI 0 */264 265 *(__be32 *)hdr->buffer = htonl(spi);266 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ESP, SPI);267 268 uhdr->field_selector = 0; /* The PF ignores the UDP header fields */269 270 return 0;271}272 273/**274 * iavf_fill_fdir_udp_flex_pay_hdr - fill the UDP payload header275 * @fltr: Flow Director filter data structure276 * @proto_hdrs: Flow Director protocol headers data structure277 *278 * Returns 0 if the UDP payload defined protocol header is set successfully279 */280static int281iavf_fill_fdir_udp_flex_pay_hdr(struct iavf_fdir_fltr *fltr,282 struct virtchnl_proto_hdrs *proto_hdrs)283{284 int err;285 286 switch (ntohs(fltr->ip_data.dst_port)) {287 case GTPU_PORT:288 err = iavf_fill_fdir_gtpu_hdr(fltr, proto_hdrs);289 break;290 case NAT_T_ESP_PORT:291 err = iavf_fill_fdir_nat_t_esp_hdr(fltr, proto_hdrs);292 break;293 case PFCP_PORT:294 err = iavf_fill_fdir_pfcp_hdr(fltr, proto_hdrs);295 break;296 default:297 err = -EOPNOTSUPP;298 break;299 }300 301 return err;302}303 304/**305 * iavf_fill_fdir_ip4_hdr - fill the IPv4 protocol header306 * @fltr: Flow Director filter data structure307 * @proto_hdrs: Flow Director protocol headers data structure308 *309 * Returns 0 if the IPv4 protocol header is set successfully310 */311static int312iavf_fill_fdir_ip4_hdr(struct iavf_fdir_fltr *fltr,313 struct virtchnl_proto_hdrs *proto_hdrs)314{315 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];316 struct iphdr *iph = (struct iphdr *)hdr->buffer;317 318 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV4);319 320 if (fltr->ip_mask.tos == U8_MAX) {321 iph->tos = fltr->ip_data.tos;322 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DSCP);323 }324 325 if (fltr->ip_mask.proto == U8_MAX) {326 iph->protocol = fltr->ip_data.proto;327 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, PROT);328 }329 330 if (fltr->ip_mask.v4_addrs.src_ip == htonl(U32_MAX)) {331 iph->saddr = fltr->ip_data.v4_addrs.src_ip;332 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, SRC);333 }334 335 if (fltr->ip_mask.v4_addrs.dst_ip == htonl(U32_MAX)) {336 iph->daddr = fltr->ip_data.v4_addrs.dst_ip;337 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DST);338 }339 340 return 0;341}342 343/**344 * iavf_fill_fdir_ip6_hdr - fill the IPv6 protocol header345 * @fltr: Flow Director filter data structure346 * @proto_hdrs: Flow Director protocol headers data structure347 *348 * Returns 0 if the IPv6 protocol header is set successfully349 */350static int351iavf_fill_fdir_ip6_hdr(struct iavf_fdir_fltr *fltr,352 struct virtchnl_proto_hdrs *proto_hdrs)353{354 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];355 struct ipv6hdr *iph = (struct ipv6hdr *)hdr->buffer;356 357 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV6);358 359 if (fltr->ip_mask.tclass == U8_MAX) {360 iph->priority = (fltr->ip_data.tclass >> 4) & 0xF;361 iph->flow_lbl[0] = FIELD_PREP(0xF0, fltr->ip_data.tclass);362 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, TC);363 }364 365 if (fltr->ip_mask.proto == U8_MAX) {366 iph->nexthdr = fltr->ip_data.proto;367 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, PROT);368 }369 370 if (!memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_full_mask,371 sizeof(struct in6_addr))) {372 memcpy(&iph->saddr, &fltr->ip_data.v6_addrs.src_ip,373 sizeof(struct in6_addr));374 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, SRC);375 }376 377 if (!memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_full_mask,378 sizeof(struct in6_addr))) {379 memcpy(&iph->daddr, &fltr->ip_data.v6_addrs.dst_ip,380 sizeof(struct in6_addr));381 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, DST);382 }383 384 return 0;385}386 387/**388 * iavf_fill_fdir_tcp_hdr - fill the TCP protocol header389 * @fltr: Flow Director filter data structure390 * @proto_hdrs: Flow Director protocol headers data structure391 *392 * Returns 0 if the TCP protocol header is set successfully393 */394static int395iavf_fill_fdir_tcp_hdr(struct iavf_fdir_fltr *fltr,396 struct virtchnl_proto_hdrs *proto_hdrs)397{398 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];399 struct tcphdr *tcph = (struct tcphdr *)hdr->buffer;400 401 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, TCP);402 403 if (fltr->ip_mask.src_port == htons(U16_MAX)) {404 tcph->source = fltr->ip_data.src_port;405 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, SRC_PORT);406 }407 408 if (fltr->ip_mask.dst_port == htons(U16_MAX)) {409 tcph->dest = fltr->ip_data.dst_port;410 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, DST_PORT);411 }412 413 return 0;414}415 416/**417 * iavf_fill_fdir_udp_hdr - fill the UDP protocol header418 * @fltr: Flow Director filter data structure419 * @proto_hdrs: Flow Director protocol headers data structure420 *421 * Returns 0 if the UDP protocol header is set successfully422 */423static int424iavf_fill_fdir_udp_hdr(struct iavf_fdir_fltr *fltr,425 struct virtchnl_proto_hdrs *proto_hdrs)426{427 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];428 struct udphdr *udph = (struct udphdr *)hdr->buffer;429 430 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, UDP);431 432 if (fltr->ip_mask.src_port == htons(U16_MAX)) {433 udph->source = fltr->ip_data.src_port;434 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, SRC_PORT);435 }436 437 if (fltr->ip_mask.dst_port == htons(U16_MAX)) {438 udph->dest = fltr->ip_data.dst_port;439 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, DST_PORT);440 }441 442 if (!fltr->flex_cnt)443 return 0;444 445 return iavf_fill_fdir_udp_flex_pay_hdr(fltr, proto_hdrs);446}447 448/**449 * iavf_fill_fdir_sctp_hdr - fill the SCTP protocol header450 * @fltr: Flow Director filter data structure451 * @proto_hdrs: Flow Director protocol headers data structure452 *453 * Returns 0 if the SCTP protocol header is set successfully454 */455static int456iavf_fill_fdir_sctp_hdr(struct iavf_fdir_fltr *fltr,457 struct virtchnl_proto_hdrs *proto_hdrs)458{459 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];460 struct sctphdr *sctph = (struct sctphdr *)hdr->buffer;461 462 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, SCTP);463 464 if (fltr->ip_mask.src_port == htons(U16_MAX)) {465 sctph->source = fltr->ip_data.src_port;466 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, SRC_PORT);467 }468 469 if (fltr->ip_mask.dst_port == htons(U16_MAX)) {470 sctph->dest = fltr->ip_data.dst_port;471 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, DST_PORT);472 }473 474 return 0;475}476 477/**478 * iavf_fill_fdir_ah_hdr - fill the AH protocol header479 * @fltr: Flow Director filter data structure480 * @proto_hdrs: Flow Director protocol headers data structure481 *482 * Returns 0 if the AH protocol header is set successfully483 */484static int485iavf_fill_fdir_ah_hdr(struct iavf_fdir_fltr *fltr,486 struct virtchnl_proto_hdrs *proto_hdrs)487{488 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];489 struct ip_auth_hdr *ah = (struct ip_auth_hdr *)hdr->buffer;490 491 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, AH);492 493 if (fltr->ip_mask.spi == htonl(U32_MAX)) {494 ah->spi = fltr->ip_data.spi;495 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, AH, SPI);496 }497 498 return 0;499}500 501/**502 * iavf_fill_fdir_esp_hdr - fill the ESP protocol header503 * @fltr: Flow Director filter data structure504 * @proto_hdrs: Flow Director protocol headers data structure505 *506 * Returns 0 if the ESP protocol header is set successfully507 */508static int509iavf_fill_fdir_esp_hdr(struct iavf_fdir_fltr *fltr,510 struct virtchnl_proto_hdrs *proto_hdrs)511{512 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];513 struct ip_esp_hdr *esph = (struct ip_esp_hdr *)hdr->buffer;514 515 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ESP);516 517 if (fltr->ip_mask.spi == htonl(U32_MAX)) {518 esph->spi = fltr->ip_data.spi;519 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ESP, SPI);520 }521 522 return 0;523}524 525/**526 * iavf_fill_fdir_l4_hdr - fill the L4 protocol header527 * @fltr: Flow Director filter data structure528 * @proto_hdrs: Flow Director protocol headers data structure529 *530 * Returns 0 if the L4 protocol header is set successfully531 */532static int533iavf_fill_fdir_l4_hdr(struct iavf_fdir_fltr *fltr,534 struct virtchnl_proto_hdrs *proto_hdrs)535{536 struct virtchnl_proto_hdr *hdr;537 __be32 *l4_4_data;538 539 if (!fltr->ip_mask.proto) /* IPv4/IPv6 header only */540 return 0;541 542 hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];543 l4_4_data = (__be32 *)hdr->buffer;544 545 /* L2TPv3 over IP with 'Session ID' */546 if (fltr->ip_data.proto == 115 && fltr->ip_mask.l4_header == htonl(U32_MAX)) {547 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, L2TPV3);548 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, L2TPV3, SESS_ID);549 550 *l4_4_data = fltr->ip_data.l4_header;551 } else {552 return -EOPNOTSUPP;553 }554 555 return 0;556}557 558/**559 * iavf_fill_fdir_eth_hdr - fill the Ethernet protocol header560 * @fltr: Flow Director filter data structure561 * @proto_hdrs: Flow Director protocol headers data structure562 *563 * Returns 0 if the Ethernet protocol header is set successfully564 */565static int566iavf_fill_fdir_eth_hdr(struct iavf_fdir_fltr *fltr,567 struct virtchnl_proto_hdrs *proto_hdrs)568{569 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];570 struct ethhdr *ehdr = (struct ethhdr *)hdr->buffer;571 572 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ETH);573 574 if (fltr->eth_mask.etype == htons(U16_MAX)) {575 if (fltr->eth_data.etype == htons(ETH_P_IP) ||576 fltr->eth_data.etype == htons(ETH_P_IPV6))577 return -EOPNOTSUPP;578 579 ehdr->h_proto = fltr->eth_data.etype;580 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ETH, ETHERTYPE);581 }582 583 return 0;584}585 586/**587 * iavf_fill_fdir_add_msg - fill the Flow Director filter into virtchnl message588 * @adapter: pointer to the VF adapter structure589 * @fltr: Flow Director filter data structure590 *591 * Returns 0 if the add Flow Director virtchnl message is filled successfully592 */593int iavf_fill_fdir_add_msg(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)594{595 struct virtchnl_fdir_add *vc_msg = &fltr->vc_add_msg;596 struct virtchnl_proto_hdrs *proto_hdrs;597 int err;598 599 proto_hdrs = &vc_msg->rule_cfg.proto_hdrs;600 601 err = iavf_fill_fdir_eth_hdr(fltr, proto_hdrs); /* L2 always exists */602 if (err)603 return err;604 605 switch (fltr->flow_type) {606 case IAVF_FDIR_FLOW_IPV4_TCP:607 err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |608 iavf_fill_fdir_tcp_hdr(fltr, proto_hdrs);609 break;610 case IAVF_FDIR_FLOW_IPV4_UDP:611 err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |612 iavf_fill_fdir_udp_hdr(fltr, proto_hdrs);613 break;614 case IAVF_FDIR_FLOW_IPV4_SCTP:615 err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |616 iavf_fill_fdir_sctp_hdr(fltr, proto_hdrs);617 break;618 case IAVF_FDIR_FLOW_IPV4_AH:619 err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |620 iavf_fill_fdir_ah_hdr(fltr, proto_hdrs);621 break;622 case IAVF_FDIR_FLOW_IPV4_ESP:623 err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |624 iavf_fill_fdir_esp_hdr(fltr, proto_hdrs);625 break;626 case IAVF_FDIR_FLOW_IPV4_OTHER:627 err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) |628 iavf_fill_fdir_l4_hdr(fltr, proto_hdrs);629 break;630 case IAVF_FDIR_FLOW_IPV6_TCP:631 err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |632 iavf_fill_fdir_tcp_hdr(fltr, proto_hdrs);633 break;634 case IAVF_FDIR_FLOW_IPV6_UDP:635 err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |636 iavf_fill_fdir_udp_hdr(fltr, proto_hdrs);637 break;638 case IAVF_FDIR_FLOW_IPV6_SCTP:639 err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |640 iavf_fill_fdir_sctp_hdr(fltr, proto_hdrs);641 break;642 case IAVF_FDIR_FLOW_IPV6_AH:643 err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |644 iavf_fill_fdir_ah_hdr(fltr, proto_hdrs);645 break;646 case IAVF_FDIR_FLOW_IPV6_ESP:647 err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |648 iavf_fill_fdir_esp_hdr(fltr, proto_hdrs);649 break;650 case IAVF_FDIR_FLOW_IPV6_OTHER:651 err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) |652 iavf_fill_fdir_l4_hdr(fltr, proto_hdrs);653 break;654 case IAVF_FDIR_FLOW_NON_IP_L2:655 break;656 default:657 err = -EINVAL;658 break;659 }660 661 if (err)662 return err;663 664 vc_msg->vsi_id = adapter->vsi.id;665 vc_msg->rule_cfg.action_set.count = 1;666 vc_msg->rule_cfg.action_set.actions[0].type = fltr->action;667 vc_msg->rule_cfg.action_set.actions[0].act_conf.queue.index = fltr->q_index;668 669 return 0;670}671 672/**673 * iavf_fdir_flow_proto_name - get the flow protocol name674 * @flow_type: Flow Director filter flow type675 **/676static const char *iavf_fdir_flow_proto_name(enum iavf_fdir_flow_type flow_type)677{678 switch (flow_type) {679 case IAVF_FDIR_FLOW_IPV4_TCP:680 case IAVF_FDIR_FLOW_IPV6_TCP:681 return "TCP";682 case IAVF_FDIR_FLOW_IPV4_UDP:683 case IAVF_FDIR_FLOW_IPV6_UDP:684 return "UDP";685 case IAVF_FDIR_FLOW_IPV4_SCTP:686 case IAVF_FDIR_FLOW_IPV6_SCTP:687 return "SCTP";688 case IAVF_FDIR_FLOW_IPV4_AH:689 case IAVF_FDIR_FLOW_IPV6_AH:690 return "AH";691 case IAVF_FDIR_FLOW_IPV4_ESP:692 case IAVF_FDIR_FLOW_IPV6_ESP:693 return "ESP";694 case IAVF_FDIR_FLOW_IPV4_OTHER:695 case IAVF_FDIR_FLOW_IPV6_OTHER:696 return "Other";697 case IAVF_FDIR_FLOW_NON_IP_L2:698 return "Ethernet";699 default:700 return NULL;701 }702}703 704/**705 * iavf_print_fdir_fltr706 * @adapter: adapter structure707 * @fltr: Flow Director filter to print708 *709 * Print the Flow Director filter710 **/711void iavf_print_fdir_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)712{713 const char *proto = iavf_fdir_flow_proto_name(fltr->flow_type);714 715 if (!proto)716 return;717 718 switch (fltr->flow_type) {719 case IAVF_FDIR_FLOW_IPV4_TCP:720 case IAVF_FDIR_FLOW_IPV4_UDP:721 case IAVF_FDIR_FLOW_IPV4_SCTP:722 dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 %s: dst_port %hu src_port %hu\n",723 fltr->loc,724 &fltr->ip_data.v4_addrs.dst_ip,725 &fltr->ip_data.v4_addrs.src_ip,726 proto,727 ntohs(fltr->ip_data.dst_port),728 ntohs(fltr->ip_data.src_port));729 break;730 case IAVF_FDIR_FLOW_IPV4_AH:731 case IAVF_FDIR_FLOW_IPV4_ESP:732 dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 %s: SPI %u\n",733 fltr->loc,734 &fltr->ip_data.v4_addrs.dst_ip,735 &fltr->ip_data.v4_addrs.src_ip,736 proto,737 ntohl(fltr->ip_data.spi));738 break;739 case IAVF_FDIR_FLOW_IPV4_OTHER:740 dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 proto: %u L4_bytes: 0x%x\n",741 fltr->loc,742 &fltr->ip_data.v4_addrs.dst_ip,743 &fltr->ip_data.v4_addrs.src_ip,744 fltr->ip_data.proto,745 ntohl(fltr->ip_data.l4_header));746 break;747 case IAVF_FDIR_FLOW_IPV6_TCP:748 case IAVF_FDIR_FLOW_IPV6_UDP:749 case IAVF_FDIR_FLOW_IPV6_SCTP:750 dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 %s: dst_port %hu src_port %hu\n",751 fltr->loc,752 &fltr->ip_data.v6_addrs.dst_ip,753 &fltr->ip_data.v6_addrs.src_ip,754 proto,755 ntohs(fltr->ip_data.dst_port),756 ntohs(fltr->ip_data.src_port));757 break;758 case IAVF_FDIR_FLOW_IPV6_AH:759 case IAVF_FDIR_FLOW_IPV6_ESP:760 dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 %s: SPI %u\n",761 fltr->loc,762 &fltr->ip_data.v6_addrs.dst_ip,763 &fltr->ip_data.v6_addrs.src_ip,764 proto,765 ntohl(fltr->ip_data.spi));766 break;767 case IAVF_FDIR_FLOW_IPV6_OTHER:768 dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 proto: %u L4_bytes: 0x%x\n",769 fltr->loc,770 &fltr->ip_data.v6_addrs.dst_ip,771 &fltr->ip_data.v6_addrs.src_ip,772 fltr->ip_data.proto,773 ntohl(fltr->ip_data.l4_header));774 break;775 case IAVF_FDIR_FLOW_NON_IP_L2:776 dev_info(&adapter->pdev->dev, "Rule ID: %u eth_type: 0x%x\n",777 fltr->loc,778 ntohs(fltr->eth_data.etype));779 break;780 default:781 break;782 }783}784 785/**786 * iavf_fdir_is_dup_fltr - test if filter is already in list787 * @adapter: pointer to the VF adapter structure788 * @fltr: Flow Director filter data structure789 *790 * Returns true if the filter is found in the list791 */792bool iavf_fdir_is_dup_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr)793{794 struct iavf_fdir_fltr *tmp;795 bool ret = false;796 797 spin_lock_bh(&adapter->fdir_fltr_lock);798 list_for_each_entry(tmp, &adapter->fdir_list_head, list) {799 if (iavf_is_raw_fdir(fltr))800 continue;801 802 if (tmp->flow_type != fltr->flow_type)803 continue;804 805 if (!memcmp(&tmp->eth_data, &fltr->eth_data,806 sizeof(fltr->eth_data)) &&807 !memcmp(&tmp->ip_data, &fltr->ip_data,808 sizeof(fltr->ip_data)) &&809 !memcmp(&tmp->ext_data, &fltr->ext_data,810 sizeof(fltr->ext_data))) {811 ret = true;812 break;813 }814 }815 spin_unlock_bh(&adapter->fdir_fltr_lock);816 817 return ret;818}819 820/**821 * iavf_find_fdir_fltr - find FDIR filter822 * @adapter: pointer to the VF adapter structure823 * @is_raw: filter type, is raw (tc u32) or not (ethtool)824 * @data: data to ID the filter, type dependent825 *826 * Returns: pointer to Flow Director filter if found or NULL. Lock must be held.827 */828struct iavf_fdir_fltr *iavf_find_fdir_fltr(struct iavf_adapter *adapter,829 bool is_raw, u32 data)830{831 struct iavf_fdir_fltr *rule;832 833 list_for_each_entry(rule, &adapter->fdir_list_head, list) {834 if ((is_raw && rule->cls_u32_handle == data) ||835 (!is_raw && rule->loc == data))836 return rule;837 }838 839 return NULL;840}841 842/**843 * iavf_fdir_add_fltr - add a new node to the flow director filter list844 * @adapter: pointer to the VF adapter structure845 * @fltr: filter node to add to structure846 *847 * Return: 0 on success or negative errno on failure.848 */849int iavf_fdir_add_fltr(struct iavf_adapter *adapter,850 struct iavf_fdir_fltr *fltr)851{852 struct iavf_fdir_fltr *rule, *parent = NULL;853 854 spin_lock_bh(&adapter->fdir_fltr_lock);855 if (iavf_fdir_max_reached(adapter)) {856 spin_unlock_bh(&adapter->fdir_fltr_lock);857 dev_err(&adapter->pdev->dev,858 "Unable to add Flow Director filter (limit (%u) reached)\n",859 IAVF_MAX_FDIR_FILTERS);860 return -ENOSPC;861 }862 863 list_for_each_entry(rule, &adapter->fdir_list_head, list) {864 if (iavf_is_raw_fdir(fltr))865 break;866 867 if (rule->loc >= fltr->loc)868 break;869 parent = rule;870 }871 872 if (parent)873 list_add(&fltr->list, &parent->list);874 else875 list_add(&fltr->list, &adapter->fdir_list_head);876 877 iavf_inc_fdir_active_fltr(adapter, fltr);878 879 if (adapter->link_up)880 fltr->state = IAVF_FDIR_FLTR_ADD_REQUEST;881 else882 fltr->state = IAVF_FDIR_FLTR_INACTIVE;883 spin_unlock_bh(&adapter->fdir_fltr_lock);884 885 if (adapter->link_up)886 iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_FDIR_FILTER);887 888 return 0;889}890 891/**892 * iavf_fdir_del_fltr - delete a flow director filter from the list893 * @adapter: pointer to the VF adapter structure894 * @is_raw: filter type, is raw (tc u32) or not (ethtool)895 * @data: data to ID the filter, type dependent896 *897 * Return: 0 on success or negative errno on failure.898 */899int iavf_fdir_del_fltr(struct iavf_adapter *adapter, bool is_raw, u32 data)900{901 struct iavf_fdir_fltr *fltr = NULL;902 int err = 0;903 904 spin_lock_bh(&adapter->fdir_fltr_lock);905 fltr = iavf_find_fdir_fltr(adapter, is_raw, data);906 907 if (fltr) {908 if (fltr->state == IAVF_FDIR_FLTR_ACTIVE) {909 fltr->state = IAVF_FDIR_FLTR_DEL_REQUEST;910 } else if (fltr->state == IAVF_FDIR_FLTR_INACTIVE) {911 list_del(&fltr->list);912 iavf_dec_fdir_active_fltr(adapter, fltr);913 kfree(fltr);914 fltr = NULL;915 } else {916 err = -EBUSY;917 }918 } else if (adapter->fdir_active_fltr) {919 err = -EINVAL;920 }921 922 if (fltr && fltr->state == IAVF_FDIR_FLTR_DEL_REQUEST)923 iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_DEL_FDIR_FILTER);924 925 spin_unlock_bh(&adapter->fdir_fltr_lock);926 return err;927}928