Merge tag 'io_uring-5.13-2021-06-03' of git://git.kernel.dk/linux-block
[linux-2.6-microblaze.git] / drivers / net / ethernet / intel / iavf / iavf_fdir.c
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 }