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 
12 static 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  */
25 static 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  */
39 static int
40 iavf_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  */
112 static int
113 iavf_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  */
154 static int
155 iavf_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  */
206 static int
207 iavf_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  */
237 static int
238 iavf_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  */
278 static int
279 iavf_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  */
324 static int
325 iavf_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  */
353 static int
354 iavf_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  */
385 static int
386 iavf_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  */
414 static int
415 iavf_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  */
438 static int
439 iavf_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  */
462 static int
463 iavf_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  */
495 static int
496 iavf_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  */
523 int 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  **/
606 static 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  **/
641 void 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  */
722 bool 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  */
749 struct 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  */
765 void 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