cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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}