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 */
iavf_pkt_udp_no_pay_len(struct iavf_fdir_fltr * fltr)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
iavf_fill_fdir_gtpu_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)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
iavf_fill_fdir_pfcp_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)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
iavf_fill_fdir_nat_t_esp_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)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
iavf_fill_fdir_udp_flex_pay_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)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
iavf_fill_fdir_ip4_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)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
iavf_fill_fdir_ip6_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)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
iavf_fill_fdir_tcp_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)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
iavf_fill_fdir_udp_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)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
iavf_fill_fdir_sctp_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)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
iavf_fill_fdir_ah_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)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
iavf_fill_fdir_esp_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)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
iavf_fill_fdir_l4_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)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
iavf_fill_fdir_eth_hdr(struct iavf_fdir_fltr * fltr,struct virtchnl_proto_hdrs * proto_hdrs)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 */
iavf_fill_fdir_add_msg(struct iavf_adapter * adapter,struct iavf_fdir_fltr * fltr)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 **/
iavf_fdir_flow_proto_name(enum iavf_fdir_flow_type flow_type)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 **/
iavf_print_fdir_fltr(struct iavf_adapter * adapter,struct iavf_fdir_fltr * fltr)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 */
iavf_fdir_is_dup_fltr(struct iavf_adapter * adapter,struct iavf_fdir_fltr * fltr)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 */
iavf_find_fdir_fltr_by_loc(struct iavf_adapter * adapter,u32 loc)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 */
iavf_fdir_list_add_fltr(struct iavf_adapter * adapter,struct iavf_fdir_fltr * fltr)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