iavf_fdir.c (22016B)
1// SPDX-License-Identifier: GPL-2.0 2/* Copyright (c) 2020, Intel Corporation. */ 3 4/* flow director ethtool support for iavf */ 5 6#include "iavf.h" 7 8#define GTPU_PORT 2152 9#define NAT_T_ESP_PORT 4500 10#define PFCP_PORT 8805 11 12static const struct in6_addr ipv6_addr_full_mask = { 13 .in6_u = { 14 .u6_addr8 = { 15 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 16 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 17 } 18 } 19}; 20 21/** 22 * iavf_pkt_udp_no_pay_len - the length of UDP packet without payload 23 * @fltr: Flow Director filter data structure 24 */ 25static u16 iavf_pkt_udp_no_pay_len(struct iavf_fdir_fltr *fltr) 26{ 27 return sizeof(struct ethhdr) + 28 (fltr->ip_ver == 4 ? sizeof(struct iphdr) : sizeof(struct ipv6hdr)) + 29 sizeof(struct udphdr); 30} 31 32/** 33 * iavf_fill_fdir_gtpu_hdr - fill the GTP-U protocol header 34 * @fltr: Flow Director filter data structure 35 * @proto_hdrs: Flow Director protocol headers data structure 36 * 37 * Returns 0 if the GTP-U protocol header is set successfully 38 */ 39static int 40iavf_fill_fdir_gtpu_hdr(struct iavf_fdir_fltr *fltr, 41 struct virtchnl_proto_hdrs *proto_hdrs) 42{ 43 struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1]; 44 struct virtchnl_proto_hdr *ghdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 45 struct virtchnl_proto_hdr *ehdr = NULL; /* Extension Header if it exists */ 46 u16 adj_offs, hdr_offs; 47 int i; 48 49 VIRTCHNL_SET_PROTO_HDR_TYPE(ghdr, GTPU_IP); 50 51 adj_offs = iavf_pkt_udp_no_pay_len(fltr); 52 53 for (i = 0; i < fltr->flex_cnt; i++) { 54#define IAVF_GTPU_HDR_TEID_OFFS0 4 55#define IAVF_GTPU_HDR_TEID_OFFS1 6 56#define IAVF_GTPU_HDR_N_PDU_AND_NEXT_EXTHDR_OFFS 10 57#define IAVF_GTPU_HDR_NEXT_EXTHDR_TYPE_MASK 0x00FF /* skip N_PDU */ 58/* PDU Session Container Extension Header (PSC) */ 59#define IAVF_GTPU_PSC_EXTHDR_TYPE 0x85 60#define IAVF_GTPU_HDR_PSC_PDU_TYPE_AND_QFI_OFFS 13 61#define IAVF_GTPU_HDR_PSC_PDU_QFI_MASK 0x3F /* skip Type */ 62#define IAVF_GTPU_EH_QFI_IDX 1 63 64 if (fltr->flex_words[i].offset < adj_offs) 65 return -EINVAL; 66 67 hdr_offs = fltr->flex_words[i].offset - adj_offs; 68 69 switch (hdr_offs) { 70 case IAVF_GTPU_HDR_TEID_OFFS0: 71 case IAVF_GTPU_HDR_TEID_OFFS1: { 72 __be16 *pay_word = (__be16 *)ghdr->buffer; 73 74 pay_word[hdr_offs >> 1] = htons(fltr->flex_words[i].word); 75 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(ghdr, GTPU_IP, TEID); 76 } 77 break; 78 case IAVF_GTPU_HDR_N_PDU_AND_NEXT_EXTHDR_OFFS: 79 if ((fltr->flex_words[i].word & 80 IAVF_GTPU_HDR_NEXT_EXTHDR_TYPE_MASK) != 81 IAVF_GTPU_PSC_EXTHDR_TYPE) 82 return -EOPNOTSUPP; 83 if (!ehdr) 84 ehdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 85 VIRTCHNL_SET_PROTO_HDR_TYPE(ehdr, GTPU_EH); 86 break; 87 case IAVF_GTPU_HDR_PSC_PDU_TYPE_AND_QFI_OFFS: 88 if (!ehdr) 89 return -EINVAL; 90 ehdr->buffer[IAVF_GTPU_EH_QFI_IDX] = 91 fltr->flex_words[i].word & 92 IAVF_GTPU_HDR_PSC_PDU_QFI_MASK; 93 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(ehdr, GTPU_EH, QFI); 94 break; 95 default: 96 return -EINVAL; 97 } 98 } 99 100 uhdr->field_selector = 0; /* The PF ignores the UDP header fields */ 101 102 return 0; 103} 104 105/** 106 * iavf_fill_fdir_pfcp_hdr - fill the PFCP protocol header 107 * @fltr: Flow Director filter data structure 108 * @proto_hdrs: Flow Director protocol headers data structure 109 * 110 * Returns 0 if the PFCP protocol header is set successfully 111 */ 112static int 113iavf_fill_fdir_pfcp_hdr(struct iavf_fdir_fltr *fltr, 114 struct virtchnl_proto_hdrs *proto_hdrs) 115{ 116 struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1]; 117 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 118 u16 adj_offs, hdr_offs; 119 int i; 120 121 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, PFCP); 122 123 adj_offs = iavf_pkt_udp_no_pay_len(fltr); 124 125 for (i = 0; i < fltr->flex_cnt; i++) { 126#define IAVF_PFCP_HDR_SFIELD_AND_MSG_TYPE_OFFS 0 127 if (fltr->flex_words[i].offset < adj_offs) 128 return -EINVAL; 129 130 hdr_offs = fltr->flex_words[i].offset - adj_offs; 131 132 switch (hdr_offs) { 133 case IAVF_PFCP_HDR_SFIELD_AND_MSG_TYPE_OFFS: 134 hdr->buffer[0] = (fltr->flex_words[i].word >> 8) & 0xff; 135 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, PFCP, S_FIELD); 136 break; 137 default: 138 return -EINVAL; 139 } 140 } 141 142 uhdr->field_selector = 0; /* The PF ignores the UDP header fields */ 143 144 return 0; 145} 146 147/** 148 * iavf_fill_fdir_nat_t_esp_hdr - fill the NAT-T-ESP protocol header 149 * @fltr: Flow Director filter data structure 150 * @proto_hdrs: Flow Director protocol headers data structure 151 * 152 * Returns 0 if the NAT-T-ESP protocol header is set successfully 153 */ 154static int 155iavf_fill_fdir_nat_t_esp_hdr(struct iavf_fdir_fltr *fltr, 156 struct virtchnl_proto_hdrs *proto_hdrs) 157{ 158 struct virtchnl_proto_hdr *uhdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1]; 159 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 160 u16 adj_offs, hdr_offs; 161 u32 spi = 0; 162 int i; 163 164 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ESP); 165 166 adj_offs = iavf_pkt_udp_no_pay_len(fltr); 167 168 for (i = 0; i < fltr->flex_cnt; i++) { 169#define IAVF_NAT_T_ESP_SPI_OFFS0 0 170#define IAVF_NAT_T_ESP_SPI_OFFS1 2 171 if (fltr->flex_words[i].offset < adj_offs) 172 return -EINVAL; 173 174 hdr_offs = fltr->flex_words[i].offset - adj_offs; 175 176 switch (hdr_offs) { 177 case IAVF_NAT_T_ESP_SPI_OFFS0: 178 spi |= fltr->flex_words[i].word << 16; 179 break; 180 case IAVF_NAT_T_ESP_SPI_OFFS1: 181 spi |= fltr->flex_words[i].word; 182 break; 183 default: 184 return -EINVAL; 185 } 186 } 187 188 if (!spi) 189 return -EOPNOTSUPP; /* Not support IKE Header Format with SPI 0 */ 190 191 *(__be32 *)hdr->buffer = htonl(spi); 192 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ESP, SPI); 193 194 uhdr->field_selector = 0; /* The PF ignores the UDP header fields */ 195 196 return 0; 197} 198 199/** 200 * iavf_fill_fdir_udp_flex_pay_hdr - fill the UDP payload header 201 * @fltr: Flow Director filter data structure 202 * @proto_hdrs: Flow Director protocol headers data structure 203 * 204 * Returns 0 if the UDP payload defined protocol header is set successfully 205 */ 206static int 207iavf_fill_fdir_udp_flex_pay_hdr(struct iavf_fdir_fltr *fltr, 208 struct virtchnl_proto_hdrs *proto_hdrs) 209{ 210 int err; 211 212 switch (ntohs(fltr->ip_data.dst_port)) { 213 case GTPU_PORT: 214 err = iavf_fill_fdir_gtpu_hdr(fltr, proto_hdrs); 215 break; 216 case NAT_T_ESP_PORT: 217 err = iavf_fill_fdir_nat_t_esp_hdr(fltr, proto_hdrs); 218 break; 219 case PFCP_PORT: 220 err = iavf_fill_fdir_pfcp_hdr(fltr, proto_hdrs); 221 break; 222 default: 223 err = -EOPNOTSUPP; 224 break; 225 } 226 227 return err; 228} 229 230/** 231 * iavf_fill_fdir_ip4_hdr - fill the IPv4 protocol header 232 * @fltr: Flow Director filter data structure 233 * @proto_hdrs: Flow Director protocol headers data structure 234 * 235 * Returns 0 if the IPv4 protocol header is set successfully 236 */ 237static int 238iavf_fill_fdir_ip4_hdr(struct iavf_fdir_fltr *fltr, 239 struct virtchnl_proto_hdrs *proto_hdrs) 240{ 241 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 242 struct iphdr *iph = (struct iphdr *)hdr->buffer; 243 244 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV4); 245 246 if (fltr->ip_mask.tos == U8_MAX) { 247 iph->tos = fltr->ip_data.tos; 248 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DSCP); 249 } 250 251 if (fltr->ip_mask.proto == U8_MAX) { 252 iph->protocol = fltr->ip_data.proto; 253 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, PROT); 254 } 255 256 if (fltr->ip_mask.v4_addrs.src_ip == htonl(U32_MAX)) { 257 iph->saddr = fltr->ip_data.v4_addrs.src_ip; 258 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, SRC); 259 } 260 261 if (fltr->ip_mask.v4_addrs.dst_ip == htonl(U32_MAX)) { 262 iph->daddr = fltr->ip_data.v4_addrs.dst_ip; 263 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DST); 264 } 265 266 fltr->ip_ver = 4; 267 268 return 0; 269} 270 271/** 272 * iavf_fill_fdir_ip6_hdr - fill the IPv6 protocol header 273 * @fltr: Flow Director filter data structure 274 * @proto_hdrs: Flow Director protocol headers data structure 275 * 276 * Returns 0 if the IPv6 protocol header is set successfully 277 */ 278static int 279iavf_fill_fdir_ip6_hdr(struct iavf_fdir_fltr *fltr, 280 struct virtchnl_proto_hdrs *proto_hdrs) 281{ 282 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 283 struct ipv6hdr *iph = (struct ipv6hdr *)hdr->buffer; 284 285 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV6); 286 287 if (fltr->ip_mask.tclass == U8_MAX) { 288 iph->priority = (fltr->ip_data.tclass >> 4) & 0xF; 289 iph->flow_lbl[0] = (fltr->ip_data.tclass << 4) & 0xF0; 290 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, TC); 291 } 292 293 if (fltr->ip_mask.proto == U8_MAX) { 294 iph->nexthdr = fltr->ip_data.proto; 295 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, PROT); 296 } 297 298 if (!memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_full_mask, 299 sizeof(struct in6_addr))) { 300 memcpy(&iph->saddr, &fltr->ip_data.v6_addrs.src_ip, 301 sizeof(struct in6_addr)); 302 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, SRC); 303 } 304 305 if (!memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_full_mask, 306 sizeof(struct in6_addr))) { 307 memcpy(&iph->daddr, &fltr->ip_data.v6_addrs.dst_ip, 308 sizeof(struct in6_addr)); 309 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, DST); 310 } 311 312 fltr->ip_ver = 6; 313 314 return 0; 315} 316 317/** 318 * iavf_fill_fdir_tcp_hdr - fill the TCP protocol header 319 * @fltr: Flow Director filter data structure 320 * @proto_hdrs: Flow Director protocol headers data structure 321 * 322 * Returns 0 if the TCP protocol header is set successfully 323 */ 324static int 325iavf_fill_fdir_tcp_hdr(struct iavf_fdir_fltr *fltr, 326 struct virtchnl_proto_hdrs *proto_hdrs) 327{ 328 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 329 struct tcphdr *tcph = (struct tcphdr *)hdr->buffer; 330 331 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, TCP); 332 333 if (fltr->ip_mask.src_port == htons(U16_MAX)) { 334 tcph->source = fltr->ip_data.src_port; 335 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, SRC_PORT); 336 } 337 338 if (fltr->ip_mask.dst_port == htons(U16_MAX)) { 339 tcph->dest = fltr->ip_data.dst_port; 340 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, DST_PORT); 341 } 342 343 return 0; 344} 345 346/** 347 * iavf_fill_fdir_udp_hdr - fill the UDP protocol header 348 * @fltr: Flow Director filter data structure 349 * @proto_hdrs: Flow Director protocol headers data structure 350 * 351 * Returns 0 if the UDP protocol header is set successfully 352 */ 353static int 354iavf_fill_fdir_udp_hdr(struct iavf_fdir_fltr *fltr, 355 struct virtchnl_proto_hdrs *proto_hdrs) 356{ 357 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 358 struct udphdr *udph = (struct udphdr *)hdr->buffer; 359 360 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, UDP); 361 362 if (fltr->ip_mask.src_port == htons(U16_MAX)) { 363 udph->source = fltr->ip_data.src_port; 364 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, SRC_PORT); 365 } 366 367 if (fltr->ip_mask.dst_port == htons(U16_MAX)) { 368 udph->dest = fltr->ip_data.dst_port; 369 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, DST_PORT); 370 } 371 372 if (!fltr->flex_cnt) 373 return 0; 374 375 return iavf_fill_fdir_udp_flex_pay_hdr(fltr, proto_hdrs); 376} 377 378/** 379 * iavf_fill_fdir_sctp_hdr - fill the SCTP protocol header 380 * @fltr: Flow Director filter data structure 381 * @proto_hdrs: Flow Director protocol headers data structure 382 * 383 * Returns 0 if the SCTP protocol header is set successfully 384 */ 385static int 386iavf_fill_fdir_sctp_hdr(struct iavf_fdir_fltr *fltr, 387 struct virtchnl_proto_hdrs *proto_hdrs) 388{ 389 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 390 struct sctphdr *sctph = (struct sctphdr *)hdr->buffer; 391 392 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, SCTP); 393 394 if (fltr->ip_mask.src_port == htons(U16_MAX)) { 395 sctph->source = fltr->ip_data.src_port; 396 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, SRC_PORT); 397 } 398 399 if (fltr->ip_mask.dst_port == htons(U16_MAX)) { 400 sctph->dest = fltr->ip_data.dst_port; 401 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, DST_PORT); 402 } 403 404 return 0; 405} 406 407/** 408 * iavf_fill_fdir_ah_hdr - fill the AH protocol header 409 * @fltr: Flow Director filter data structure 410 * @proto_hdrs: Flow Director protocol headers data structure 411 * 412 * Returns 0 if the AH protocol header is set successfully 413 */ 414static int 415iavf_fill_fdir_ah_hdr(struct iavf_fdir_fltr *fltr, 416 struct virtchnl_proto_hdrs *proto_hdrs) 417{ 418 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 419 struct ip_auth_hdr *ah = (struct ip_auth_hdr *)hdr->buffer; 420 421 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, AH); 422 423 if (fltr->ip_mask.spi == htonl(U32_MAX)) { 424 ah->spi = fltr->ip_data.spi; 425 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, AH, SPI); 426 } 427 428 return 0; 429} 430 431/** 432 * iavf_fill_fdir_esp_hdr - fill the ESP protocol header 433 * @fltr: Flow Director filter data structure 434 * @proto_hdrs: Flow Director protocol headers data structure 435 * 436 * Returns 0 if the ESP protocol header is set successfully 437 */ 438static int 439iavf_fill_fdir_esp_hdr(struct iavf_fdir_fltr *fltr, 440 struct virtchnl_proto_hdrs *proto_hdrs) 441{ 442 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 443 struct ip_esp_hdr *esph = (struct ip_esp_hdr *)hdr->buffer; 444 445 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ESP); 446 447 if (fltr->ip_mask.spi == htonl(U32_MAX)) { 448 esph->spi = fltr->ip_data.spi; 449 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ESP, SPI); 450 } 451 452 return 0; 453} 454 455/** 456 * iavf_fill_fdir_l4_hdr - fill the L4 protocol header 457 * @fltr: Flow Director filter data structure 458 * @proto_hdrs: Flow Director protocol headers data structure 459 * 460 * Returns 0 if the L4 protocol header is set successfully 461 */ 462static int 463iavf_fill_fdir_l4_hdr(struct iavf_fdir_fltr *fltr, 464 struct virtchnl_proto_hdrs *proto_hdrs) 465{ 466 struct virtchnl_proto_hdr *hdr; 467 __be32 *l4_4_data; 468 469 if (!fltr->ip_mask.proto) /* IPv4/IPv6 header only */ 470 return 0; 471 472 hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 473 l4_4_data = (__be32 *)hdr->buffer; 474 475 /* L2TPv3 over IP with 'Session ID' */ 476 if (fltr->ip_data.proto == 115 && fltr->ip_mask.l4_header == htonl(U32_MAX)) { 477 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, L2TPV3); 478 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, L2TPV3, SESS_ID); 479 480 *l4_4_data = fltr->ip_data.l4_header; 481 } else { 482 return -EOPNOTSUPP; 483 } 484 485 return 0; 486} 487 488/** 489 * iavf_fill_fdir_eth_hdr - fill the Ethernet protocol header 490 * @fltr: Flow Director filter data structure 491 * @proto_hdrs: Flow Director protocol headers data structure 492 * 493 * Returns 0 if the Ethernet protocol header is set successfully 494 */ 495static int 496iavf_fill_fdir_eth_hdr(struct iavf_fdir_fltr *fltr, 497 struct virtchnl_proto_hdrs *proto_hdrs) 498{ 499 struct virtchnl_proto_hdr *hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++]; 500 struct ethhdr *ehdr = (struct ethhdr *)hdr->buffer; 501 502 VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, ETH); 503 504 if (fltr->eth_mask.etype == htons(U16_MAX)) { 505 if (fltr->eth_data.etype == htons(ETH_P_IP) || 506 fltr->eth_data.etype == htons(ETH_P_IPV6)) 507 return -EOPNOTSUPP; 508 509 ehdr->h_proto = fltr->eth_data.etype; 510 VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, ETH, ETHERTYPE); 511 } 512 513 return 0; 514} 515 516/** 517 * iavf_fill_fdir_add_msg - fill the Flow Director filter into virtchnl message 518 * @adapter: pointer to the VF adapter structure 519 * @fltr: Flow Director filter data structure 520 * 521 * Returns 0 if the add Flow Director virtchnl message is filled successfully 522 */ 523int iavf_fill_fdir_add_msg(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr) 524{ 525 struct virtchnl_fdir_add *vc_msg = &fltr->vc_add_msg; 526 struct virtchnl_proto_hdrs *proto_hdrs; 527 int err; 528 529 proto_hdrs = &vc_msg->rule_cfg.proto_hdrs; 530 531 err = iavf_fill_fdir_eth_hdr(fltr, proto_hdrs); /* L2 always exists */ 532 if (err) 533 return err; 534 535 switch (fltr->flow_type) { 536 case IAVF_FDIR_FLOW_IPV4_TCP: 537 err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) | 538 iavf_fill_fdir_tcp_hdr(fltr, proto_hdrs); 539 break; 540 case IAVF_FDIR_FLOW_IPV4_UDP: 541 err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) | 542 iavf_fill_fdir_udp_hdr(fltr, proto_hdrs); 543 break; 544 case IAVF_FDIR_FLOW_IPV4_SCTP: 545 err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) | 546 iavf_fill_fdir_sctp_hdr(fltr, proto_hdrs); 547 break; 548 case IAVF_FDIR_FLOW_IPV4_AH: 549 err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) | 550 iavf_fill_fdir_ah_hdr(fltr, proto_hdrs); 551 break; 552 case IAVF_FDIR_FLOW_IPV4_ESP: 553 err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) | 554 iavf_fill_fdir_esp_hdr(fltr, proto_hdrs); 555 break; 556 case IAVF_FDIR_FLOW_IPV4_OTHER: 557 err = iavf_fill_fdir_ip4_hdr(fltr, proto_hdrs) | 558 iavf_fill_fdir_l4_hdr(fltr, proto_hdrs); 559 break; 560 case IAVF_FDIR_FLOW_IPV6_TCP: 561 err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) | 562 iavf_fill_fdir_tcp_hdr(fltr, proto_hdrs); 563 break; 564 case IAVF_FDIR_FLOW_IPV6_UDP: 565 err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) | 566 iavf_fill_fdir_udp_hdr(fltr, proto_hdrs); 567 break; 568 case IAVF_FDIR_FLOW_IPV6_SCTP: 569 err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) | 570 iavf_fill_fdir_sctp_hdr(fltr, proto_hdrs); 571 break; 572 case IAVF_FDIR_FLOW_IPV6_AH: 573 err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) | 574 iavf_fill_fdir_ah_hdr(fltr, proto_hdrs); 575 break; 576 case IAVF_FDIR_FLOW_IPV6_ESP: 577 err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) | 578 iavf_fill_fdir_esp_hdr(fltr, proto_hdrs); 579 break; 580 case IAVF_FDIR_FLOW_IPV6_OTHER: 581 err = iavf_fill_fdir_ip6_hdr(fltr, proto_hdrs) | 582 iavf_fill_fdir_l4_hdr(fltr, proto_hdrs); 583 break; 584 case IAVF_FDIR_FLOW_NON_IP_L2: 585 break; 586 default: 587 err = -EINVAL; 588 break; 589 } 590 591 if (err) 592 return err; 593 594 vc_msg->vsi_id = adapter->vsi.id; 595 vc_msg->rule_cfg.action_set.count = 1; 596 vc_msg->rule_cfg.action_set.actions[0].type = fltr->action; 597 vc_msg->rule_cfg.action_set.actions[0].act_conf.queue.index = fltr->q_index; 598 599 return 0; 600} 601 602/** 603 * iavf_fdir_flow_proto_name - get the flow protocol name 604 * @flow_type: Flow Director filter flow type 605 **/ 606static const char *iavf_fdir_flow_proto_name(enum iavf_fdir_flow_type flow_type) 607{ 608 switch (flow_type) { 609 case IAVF_FDIR_FLOW_IPV4_TCP: 610 case IAVF_FDIR_FLOW_IPV6_TCP: 611 return "TCP"; 612 case IAVF_FDIR_FLOW_IPV4_UDP: 613 case IAVF_FDIR_FLOW_IPV6_UDP: 614 return "UDP"; 615 case IAVF_FDIR_FLOW_IPV4_SCTP: 616 case IAVF_FDIR_FLOW_IPV6_SCTP: 617 return "SCTP"; 618 case IAVF_FDIR_FLOW_IPV4_AH: 619 case IAVF_FDIR_FLOW_IPV6_AH: 620 return "AH"; 621 case IAVF_FDIR_FLOW_IPV4_ESP: 622 case IAVF_FDIR_FLOW_IPV6_ESP: 623 return "ESP"; 624 case IAVF_FDIR_FLOW_IPV4_OTHER: 625 case IAVF_FDIR_FLOW_IPV6_OTHER: 626 return "Other"; 627 case IAVF_FDIR_FLOW_NON_IP_L2: 628 return "Ethernet"; 629 default: 630 return NULL; 631 } 632} 633 634/** 635 * iavf_print_fdir_fltr 636 * @adapter: adapter structure 637 * @fltr: Flow Director filter to print 638 * 639 * Print the Flow Director filter 640 **/ 641void iavf_print_fdir_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr) 642{ 643 const char *proto = iavf_fdir_flow_proto_name(fltr->flow_type); 644 645 if (!proto) 646 return; 647 648 switch (fltr->flow_type) { 649 case IAVF_FDIR_FLOW_IPV4_TCP: 650 case IAVF_FDIR_FLOW_IPV4_UDP: 651 case IAVF_FDIR_FLOW_IPV4_SCTP: 652 dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 %s: dst_port %hu src_port %hu\n", 653 fltr->loc, 654 &fltr->ip_data.v4_addrs.dst_ip, 655 &fltr->ip_data.v4_addrs.src_ip, 656 proto, 657 ntohs(fltr->ip_data.dst_port), 658 ntohs(fltr->ip_data.src_port)); 659 break; 660 case IAVF_FDIR_FLOW_IPV4_AH: 661 case IAVF_FDIR_FLOW_IPV4_ESP: 662 dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 %s: SPI %u\n", 663 fltr->loc, 664 &fltr->ip_data.v4_addrs.dst_ip, 665 &fltr->ip_data.v4_addrs.src_ip, 666 proto, 667 ntohl(fltr->ip_data.spi)); 668 break; 669 case IAVF_FDIR_FLOW_IPV4_OTHER: 670 dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI4 src_ip %pI4 proto: %u L4_bytes: 0x%x\n", 671 fltr->loc, 672 &fltr->ip_data.v4_addrs.dst_ip, 673 &fltr->ip_data.v4_addrs.src_ip, 674 fltr->ip_data.proto, 675 ntohl(fltr->ip_data.l4_header)); 676 break; 677 case IAVF_FDIR_FLOW_IPV6_TCP: 678 case IAVF_FDIR_FLOW_IPV6_UDP: 679 case IAVF_FDIR_FLOW_IPV6_SCTP: 680 dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 %s: dst_port %hu src_port %hu\n", 681 fltr->loc, 682 &fltr->ip_data.v6_addrs.dst_ip, 683 &fltr->ip_data.v6_addrs.src_ip, 684 proto, 685 ntohs(fltr->ip_data.dst_port), 686 ntohs(fltr->ip_data.src_port)); 687 break; 688 case IAVF_FDIR_FLOW_IPV6_AH: 689 case IAVF_FDIR_FLOW_IPV6_ESP: 690 dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 %s: SPI %u\n", 691 fltr->loc, 692 &fltr->ip_data.v6_addrs.dst_ip, 693 &fltr->ip_data.v6_addrs.src_ip, 694 proto, 695 ntohl(fltr->ip_data.spi)); 696 break; 697 case IAVF_FDIR_FLOW_IPV6_OTHER: 698 dev_info(&adapter->pdev->dev, "Rule ID: %u dst_ip: %pI6 src_ip %pI6 proto: %u L4_bytes: 0x%x\n", 699 fltr->loc, 700 &fltr->ip_data.v6_addrs.dst_ip, 701 &fltr->ip_data.v6_addrs.src_ip, 702 fltr->ip_data.proto, 703 ntohl(fltr->ip_data.l4_header)); 704 break; 705 case IAVF_FDIR_FLOW_NON_IP_L2: 706 dev_info(&adapter->pdev->dev, "Rule ID: %u eth_type: 0x%x\n", 707 fltr->loc, 708 ntohs(fltr->eth_data.etype)); 709 break; 710 default: 711 break; 712 } 713} 714 715/** 716 * iavf_fdir_is_dup_fltr - test if filter is already in list 717 * @adapter: pointer to the VF adapter structure 718 * @fltr: Flow Director filter data structure 719 * 720 * Returns true if the filter is found in the list 721 */ 722bool iavf_fdir_is_dup_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr) 723{ 724 struct iavf_fdir_fltr *tmp; 725 726 list_for_each_entry(tmp, &adapter->fdir_list_head, list) { 727 if (tmp->flow_type != fltr->flow_type) 728 continue; 729 730 if (!memcmp(&tmp->eth_data, &fltr->eth_data, 731 sizeof(fltr->eth_data)) && 732 !memcmp(&tmp->ip_data, &fltr->ip_data, 733 sizeof(fltr->ip_data)) && 734 !memcmp(&tmp->ext_data, &fltr->ext_data, 735 sizeof(fltr->ext_data))) 736 return true; 737 } 738 739 return false; 740} 741 742/** 743 * iavf_find_fdir_fltr_by_loc - find filter with location 744 * @adapter: pointer to the VF adapter structure 745 * @loc: location to find. 746 * 747 * Returns pointer to Flow Director filter if found or null 748 */ 749struct iavf_fdir_fltr *iavf_find_fdir_fltr_by_loc(struct iavf_adapter *adapter, u32 loc) 750{ 751 struct iavf_fdir_fltr *rule; 752 753 list_for_each_entry(rule, &adapter->fdir_list_head, list) 754 if (rule->loc == loc) 755 return rule; 756 757 return NULL; 758} 759 760/** 761 * iavf_fdir_list_add_fltr - add a new node to the flow director filter list 762 * @adapter: pointer to the VF adapter structure 763 * @fltr: filter node to add to structure 764 */ 765void iavf_fdir_list_add_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr) 766{ 767 struct iavf_fdir_fltr *rule, *parent = NULL; 768 769 list_for_each_entry(rule, &adapter->fdir_list_head, list) { 770 if (rule->loc >= fltr->loc) 771 break; 772 parent = rule; 773 } 774 775 if (parent) 776 list_add(&fltr->list, &parent->list); 777 else 778 list_add(&fltr->list, &adapter->fdir_list_head); 779}