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