linux/drivers/net/ethernet/intel/iavf/iavf_fdir.c
<<
>>
Prefs
   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}
 780