1 /*
2 * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
3 */
4 #include <stdio.h>
5 #include <stdint.h>
6 #include <stddef.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <errno.h>
10
11 #include <linux/sockios.h>
12 #include <arpa/inet.h>
13 #include "internal.h"
14
invert_flow_mask(struct ethtool_rx_flow_spec * fsp)15 static void invert_flow_mask(struct ethtool_rx_flow_spec *fsp)
16 {
17 size_t i;
18
19 for (i = 0; i < sizeof(fsp->m_u); i++)
20 fsp->m_u.hdata[i] ^= 0xFF;
21 }
22
rxclass_print_ipv4_rule(__be32 sip,__be32 sipm,__be32 dip,__be32 dipm,u8 tos,u8 tosm)23 static void rxclass_print_ipv4_rule(__be32 sip, __be32 sipm, __be32 dip,
24 __be32 dipm, u8 tos, u8 tosm)
25 {
26 char sip_str[INET_ADDRSTRLEN];
27 char sipm_str[INET_ADDRSTRLEN];
28 char dip_str[INET_ADDRSTRLEN];
29 char dipm_str[INET_ADDRSTRLEN];
30
31 fprintf(stdout,
32 "\tSrc IP addr: %s mask: %s\n"
33 "\tDest IP addr: %s mask: %s\n"
34 "\tTOS: 0x%x mask: 0x%x\n",
35 inet_ntop(AF_INET, &sip, sip_str, INET_ADDRSTRLEN),
36 inet_ntop(AF_INET, &sipm, sipm_str, INET_ADDRSTRLEN),
37 inet_ntop(AF_INET, &dip, dip_str, INET_ADDRSTRLEN),
38 inet_ntop(AF_INET, &dipm, dipm_str, INET_ADDRSTRLEN),
39 tos, tosm);
40 }
41
rxclass_print_ipv6_rule(__be32 * sip,__be32 * sipm,__be32 * dip,__be32 * dipm,u8 tclass,u8 tclassm)42 static void rxclass_print_ipv6_rule(__be32 *sip, __be32 *sipm, __be32 *dip,
43 __be32 *dipm, u8 tclass, u8 tclassm)
44 {
45 char sip_str[INET6_ADDRSTRLEN];
46 char sipm_str[INET6_ADDRSTRLEN];
47 char dip_str[INET6_ADDRSTRLEN];
48 char dipm_str[INET6_ADDRSTRLEN];
49
50 fprintf(stdout,
51 "\tSrc IP addr: %s mask: %s\n"
52 "\tDest IP addr: %s mask: %s\n"
53 "\tTraffic Class: 0x%x mask: 0x%x\n",
54 inet_ntop(AF_INET6, sip, sip_str, INET6_ADDRSTRLEN),
55 inet_ntop(AF_INET6, sipm, sipm_str, INET6_ADDRSTRLEN),
56 inet_ntop(AF_INET6, dip, dip_str, INET6_ADDRSTRLEN),
57 inet_ntop(AF_INET6, dipm, dipm_str, INET6_ADDRSTRLEN),
58 tclass, tclassm);
59 }
60
rxclass_print_nfc_spec_ext(struct ethtool_rx_flow_spec * fsp)61 static void rxclass_print_nfc_spec_ext(struct ethtool_rx_flow_spec *fsp)
62 {
63 if (fsp->flow_type & FLOW_EXT) {
64 u64 data, datam;
65 __u16 etype, etypem, tci, tcim;
66 etype = ntohs(fsp->h_ext.vlan_etype);
67 etypem = ntohs(~fsp->m_ext.vlan_etype);
68 tci = ntohs(fsp->h_ext.vlan_tci);
69 tcim = ntohs(~fsp->m_ext.vlan_tci);
70 data = (u64)ntohl(fsp->h_ext.data[0]) << 32;
71 data |= (u64)ntohl(fsp->h_ext.data[1]);
72 datam = (u64)ntohl(~fsp->m_ext.data[0]) << 32;
73 datam |= (u64)ntohl(~fsp->m_ext.data[1]);
74
75 fprintf(stdout,
76 "\tVLAN EtherType: 0x%x mask: 0x%x\n"
77 "\tVLAN: 0x%x mask: 0x%x\n"
78 "\tUser-defined: 0x%llx mask: 0x%llx\n",
79 etype, etypem, tci, tcim, data, datam);
80 }
81
82 if (fsp->flow_type & FLOW_MAC_EXT) {
83 unsigned char *dmac, *dmacm;
84
85 dmac = fsp->h_ext.h_dest;
86 dmacm = fsp->m_ext.h_dest;
87
88 fprintf(stdout,
89 "\tDest MAC addr: %02X:%02X:%02X:%02X:%02X:%02X"
90 " mask: %02X:%02X:%02X:%02X:%02X:%02X\n",
91 dmac[0], dmac[1], dmac[2], dmac[3], dmac[4],
92 dmac[5], dmacm[0], dmacm[1], dmacm[2], dmacm[3],
93 dmacm[4], dmacm[5]);
94 }
95 }
96
rxclass_print_nfc_rule(struct ethtool_rx_flow_spec * fsp,__u32 rss_context)97 static void rxclass_print_nfc_rule(struct ethtool_rx_flow_spec *fsp,
98 __u32 rss_context)
99 {
100 unsigned char *smac, *smacm, *dmac, *dmacm;
101 __u32 flow_type;
102
103 fprintf(stdout, "Filter: %d\n", fsp->location);
104
105 flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
106
107 invert_flow_mask(fsp);
108
109 switch (flow_type) {
110 case TCP_V4_FLOW:
111 case UDP_V4_FLOW:
112 case SCTP_V4_FLOW:
113 if (flow_type == TCP_V4_FLOW)
114 fprintf(stdout, "\tRule Type: TCP over IPv4\n");
115 else if (flow_type == UDP_V4_FLOW)
116 fprintf(stdout, "\tRule Type: UDP over IPv4\n");
117 else
118 fprintf(stdout, "\tRule Type: SCTP over IPv4\n");
119 rxclass_print_ipv4_rule(fsp->h_u.tcp_ip4_spec.ip4src,
120 fsp->m_u.tcp_ip4_spec.ip4src,
121 fsp->h_u.tcp_ip4_spec.ip4dst,
122 fsp->m_u.tcp_ip4_spec.ip4dst,
123 fsp->h_u.tcp_ip4_spec.tos,
124 fsp->m_u.tcp_ip4_spec.tos);
125 fprintf(stdout,
126 "\tSrc port: %d mask: 0x%x\n"
127 "\tDest port: %d mask: 0x%x\n",
128 ntohs(fsp->h_u.tcp_ip4_spec.psrc),
129 ntohs(fsp->m_u.tcp_ip4_spec.psrc),
130 ntohs(fsp->h_u.tcp_ip4_spec.pdst),
131 ntohs(fsp->m_u.tcp_ip4_spec.pdst));
132 break;
133 case AH_V4_FLOW:
134 case ESP_V4_FLOW:
135 if (flow_type == AH_V4_FLOW)
136 fprintf(stdout, "\tRule Type: IPSEC AH over IPv4\n");
137 else
138 fprintf(stdout, "\tRule Type: IPSEC ESP over IPv4\n");
139 rxclass_print_ipv4_rule(fsp->h_u.ah_ip4_spec.ip4src,
140 fsp->m_u.ah_ip4_spec.ip4src,
141 fsp->h_u.ah_ip4_spec.ip4dst,
142 fsp->m_u.ah_ip4_spec.ip4dst,
143 fsp->h_u.ah_ip4_spec.tos,
144 fsp->m_u.ah_ip4_spec.tos);
145 fprintf(stdout,
146 "\tSPI: %d mask: 0x%x\n",
147 ntohl(fsp->h_u.esp_ip4_spec.spi),
148 ntohl(fsp->m_u.esp_ip4_spec.spi));
149 break;
150 case IPV4_USER_FLOW:
151 fprintf(stdout, "\tRule Type: Raw IPv4\n");
152 rxclass_print_ipv4_rule(fsp->h_u.usr_ip4_spec.ip4src,
153 fsp->m_u.usr_ip4_spec.ip4src,
154 fsp->h_u.usr_ip4_spec.ip4dst,
155 fsp->m_u.usr_ip4_spec.ip4dst,
156 fsp->h_u.usr_ip4_spec.tos,
157 fsp->m_u.usr_ip4_spec.tos);
158 fprintf(stdout,
159 "\tProtocol: %d mask: 0x%x\n"
160 "\tL4 bytes: 0x%x mask: 0x%x\n",
161 fsp->h_u.usr_ip4_spec.proto,
162 fsp->m_u.usr_ip4_spec.proto,
163 ntohl(fsp->h_u.usr_ip4_spec.l4_4_bytes),
164 ntohl(fsp->m_u.usr_ip4_spec.l4_4_bytes));
165 break;
166 case TCP_V6_FLOW:
167 case UDP_V6_FLOW:
168 case SCTP_V6_FLOW:
169 if (flow_type == TCP_V6_FLOW)
170 fprintf(stdout, "\tRule Type: TCP over IPv6\n");
171 else if (flow_type == UDP_V6_FLOW)
172 fprintf(stdout, "\tRule Type: UDP over IPv6\n");
173 else
174 fprintf(stdout, "\tRule Type: SCTP over IPv6\n");
175 rxclass_print_ipv6_rule(fsp->h_u.tcp_ip6_spec.ip6src,
176 fsp->m_u.tcp_ip6_spec.ip6src,
177 fsp->h_u.tcp_ip6_spec.ip6dst,
178 fsp->m_u.tcp_ip6_spec.ip6dst,
179 fsp->h_u.tcp_ip6_spec.tclass,
180 fsp->m_u.tcp_ip6_spec.tclass);
181 fprintf(stdout,
182 "\tSrc port: %d mask: 0x%x\n"
183 "\tDest port: %d mask: 0x%x\n",
184 ntohs(fsp->h_u.tcp_ip6_spec.psrc),
185 ntohs(fsp->m_u.tcp_ip6_spec.psrc),
186 ntohs(fsp->h_u.tcp_ip6_spec.pdst),
187 ntohs(fsp->m_u.tcp_ip6_spec.pdst));
188 break;
189 case AH_V6_FLOW:
190 case ESP_V6_FLOW:
191 if (flow_type == AH_V6_FLOW)
192 fprintf(stdout, "\tRule Type: IPSEC AH over IPv6\n");
193 else
194 fprintf(stdout, "\tRule Type: IPSEC ESP over IPv6\n");
195 rxclass_print_ipv6_rule(fsp->h_u.ah_ip6_spec.ip6src,
196 fsp->m_u.ah_ip6_spec.ip6src,
197 fsp->h_u.ah_ip6_spec.ip6dst,
198 fsp->m_u.ah_ip6_spec.ip6dst,
199 fsp->h_u.ah_ip6_spec.tclass,
200 fsp->m_u.ah_ip6_spec.tclass);
201 fprintf(stdout,
202 "\tSPI: %d mask: 0x%x\n",
203 ntohl(fsp->h_u.esp_ip6_spec.spi),
204 ntohl(fsp->m_u.esp_ip6_spec.spi));
205 break;
206 case IPV6_USER_FLOW:
207 fprintf(stdout, "\tRule Type: Raw IPv6\n");
208 rxclass_print_ipv6_rule(fsp->h_u.usr_ip6_spec.ip6src,
209 fsp->m_u.usr_ip6_spec.ip6src,
210 fsp->h_u.usr_ip6_spec.ip6dst,
211 fsp->m_u.usr_ip6_spec.ip6dst,
212 fsp->h_u.usr_ip6_spec.tclass,
213 fsp->m_u.usr_ip6_spec.tclass);
214 fprintf(stdout,
215 "\tProtocol: %d mask: 0x%x\n"
216 "\tL4 bytes: 0x%x mask: 0x%x\n",
217 fsp->h_u.usr_ip6_spec.l4_proto,
218 fsp->m_u.usr_ip6_spec.l4_proto,
219 ntohl(fsp->h_u.usr_ip6_spec.l4_4_bytes),
220 ntohl(fsp->m_u.usr_ip6_spec.l4_4_bytes));
221 break;
222 case ETHER_FLOW:
223 dmac = fsp->h_u.ether_spec.h_dest;
224 dmacm = fsp->m_u.ether_spec.h_dest;
225 smac = fsp->h_u.ether_spec.h_source;
226 smacm = fsp->m_u.ether_spec.h_source;
227
228 fprintf(stdout,
229 "\tFlow Type: Raw Ethernet\n"
230 "\tSrc MAC addr: %02X:%02X:%02X:%02X:%02X:%02X"
231 " mask: %02X:%02X:%02X:%02X:%02X:%02X\n"
232 "\tDest MAC addr: %02X:%02X:%02X:%02X:%02X:%02X"
233 " mask: %02X:%02X:%02X:%02X:%02X:%02X\n"
234 "\tEthertype: 0x%X mask: 0x%X\n",
235 smac[0], smac[1], smac[2], smac[3], smac[4], smac[5],
236 smacm[0], smacm[1], smacm[2], smacm[3], smacm[4],
237 smacm[5], dmac[0], dmac[1], dmac[2], dmac[3], dmac[4],
238 dmac[5], dmacm[0], dmacm[1], dmacm[2], dmacm[3],
239 dmacm[4], dmacm[5],
240 ntohs(fsp->h_u.ether_spec.h_proto),
241 ntohs(fsp->m_u.ether_spec.h_proto));
242 break;
243 default:
244 fprintf(stdout,
245 "\tUnknown Flow type: %d\n", flow_type);
246 break;
247 }
248
249 rxclass_print_nfc_spec_ext(fsp);
250
251 if (fsp->ring_cookie == RX_CLS_FLOW_DISC) {
252 fprintf(stdout, "\tAction: Drop\n");
253 } else if (fsp->ring_cookie == RX_CLS_FLOW_WAKE) {
254 fprintf(stdout, "\tAction: Wake-on-LAN\n");
255 } else if (fsp->flow_type & FLOW_RSS) {
256 u64 queue = ethtool_get_flow_spec_ring(fsp->ring_cookie);
257
258 fprintf(stdout, "\tAction: Direct to RSS Context %u", rss_context);
259 if (queue)
260 fprintf(stdout, " (queue base offset: %llu)", queue);
261 fprintf(stdout, "\n");
262 } else {
263 u64 vf = ethtool_get_flow_spec_ring_vf(fsp->ring_cookie);
264 u64 queue = ethtool_get_flow_spec_ring(fsp->ring_cookie);
265
266 /* A value of zero indicates that this rule targeted the main
267 * function. A positive value indicates which virtual function
268 * was targeted, so we'll subtract 1 in order to show the
269 * correct VF index
270 */
271 if (vf)
272 fprintf(stdout, "\tAction: Direct to VF %llu queue %llu\n",
273 vf - 1, queue);
274 else
275 fprintf(stdout, "\tAction: Direct to queue %llu\n",
276 queue);
277 }
278
279 fprintf(stdout, "\n");
280 }
281
rxclass_print_rule(struct ethtool_rx_flow_spec * fsp,__u32 rss_context)282 static void rxclass_print_rule(struct ethtool_rx_flow_spec *fsp,
283 __u32 rss_context)
284 {
285 /* print the rule in this location */
286 switch (fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS)) {
287 case TCP_V4_FLOW:
288 case UDP_V4_FLOW:
289 case SCTP_V4_FLOW:
290 case AH_V4_FLOW:
291 case ESP_V4_FLOW:
292 case TCP_V6_FLOW:
293 case UDP_V6_FLOW:
294 case SCTP_V6_FLOW:
295 case AH_V6_FLOW:
296 case ESP_V6_FLOW:
297 case IPV6_USER_FLOW:
298 case ETHER_FLOW:
299 rxclass_print_nfc_rule(fsp, rss_context);
300 break;
301 case IPV4_USER_FLOW:
302 if (fsp->h_u.usr_ip4_spec.ip_ver == ETH_RX_NFC_IP4)
303 rxclass_print_nfc_rule(fsp, rss_context);
304 else /* IPv6 uses IPV6_USER_FLOW */
305 fprintf(stderr, "IPV4_USER_FLOW with wrong ip_ver\n");
306 break;
307 default:
308 fprintf(stderr, "rxclass: Unknown flow type\n");
309 break;
310 }
311 }
312
rxclass_get_dev_info(struct cmd_context * ctx,__u32 * count,int * driver_select)313 static int rxclass_get_dev_info(struct cmd_context *ctx, __u32 *count,
314 int *driver_select)
315 {
316 struct ethtool_rxnfc nfccmd;
317 int err;
318
319 nfccmd.cmd = ETHTOOL_GRXCLSRLCNT;
320 nfccmd.data = 0;
321 err = send_ioctl(ctx, &nfccmd);
322 *count = nfccmd.rule_cnt;
323 if (driver_select)
324 *driver_select = !!(nfccmd.data & RX_CLS_LOC_SPECIAL);
325 if (err < 0)
326 perror("rxclass: Cannot get RX class rule count");
327
328 return err;
329 }
330
rxclass_rule_get(struct cmd_context * ctx,__u32 loc)331 int rxclass_rule_get(struct cmd_context *ctx, __u32 loc)
332 {
333 struct ethtool_rxnfc nfccmd;
334 int err;
335
336 /* fetch rule from netdev */
337 nfccmd.cmd = ETHTOOL_GRXCLSRULE;
338 memset(&nfccmd.fs, 0, sizeof(struct ethtool_rx_flow_spec));
339 nfccmd.fs.location = loc;
340 err = send_ioctl(ctx, &nfccmd);
341 if (err < 0) {
342 perror("rxclass: Cannot get RX class rule");
343 return err;
344 }
345
346 /* display rule */
347 rxclass_print_rule(&nfccmd.fs, (__u32)nfccmd.rss_context);
348 return err;
349 }
350
rxclass_rule_getall(struct cmd_context * ctx)351 int rxclass_rule_getall(struct cmd_context *ctx)
352 {
353 struct ethtool_rxnfc *nfccmd;
354 __u32 *rule_locs;
355 unsigned int i;
356 __u32 count;
357 int err;
358
359 /* determine rule count */
360 err = rxclass_get_dev_info(ctx, &count, NULL);
361 if (err < 0)
362 return err;
363
364 fprintf(stdout, "Total %d rules\n\n", count);
365
366 /* alloc memory for request of location list */
367 nfccmd = calloc(1, sizeof(*nfccmd) + (count * sizeof(__u32)));
368 if (!nfccmd) {
369 perror("rxclass: Cannot allocate memory for"
370 " RX class rule locations");
371 return -ENOMEM;
372 }
373
374 /* request location list */
375 nfccmd->cmd = ETHTOOL_GRXCLSRLALL;
376 nfccmd->rule_cnt = count;
377 err = send_ioctl(ctx, nfccmd);
378 if (err < 0) {
379 perror("rxclass: Cannot get RX class rules");
380 free(nfccmd);
381 return err;
382 }
383
384 /* write locations to bitmap */
385 rule_locs = nfccmd->rule_locs;
386 for (i = 0; i < count; i++) {
387 err = rxclass_rule_get(ctx, rule_locs[i]);
388 if (err < 0)
389 break;
390 }
391
392 /* free memory and set flag to avoid reinit */
393 free(nfccmd);
394
395 return err;
396 }
397
398 /*
399 * This is a simple rule manager implementation for ordering rx flow
400 * classification rules based on newest rules being first in the list.
401 * The assumption is that this rule manager is the only one adding rules to
402 * the device's hardware classifier.
403 */
404
405 struct rmgr_ctrl {
406 /* flag for device/driver that can select locations itself */
407 int driver_select;
408 /* slot contains a bitmap indicating which filters are valid */
409 unsigned long *slot;
410 __u32 n_rules;
411 __u32 size;
412 };
413
rmgr_ins(struct rmgr_ctrl * rmgr,__u32 loc)414 static int rmgr_ins(struct rmgr_ctrl *rmgr, __u32 loc)
415 {
416 /* verify location is in rule manager range */
417 if (loc >= rmgr->size) {
418 fprintf(stderr, "rmgr: Location out of range\n");
419 return -1;
420 }
421
422 /* set bit for the rule */
423 set_bit(loc, rmgr->slot);
424
425 return 0;
426 }
427
rmgr_find_empty_slot(struct rmgr_ctrl * rmgr,struct ethtool_rx_flow_spec * fsp)428 static int rmgr_find_empty_slot(struct rmgr_ctrl *rmgr,
429 struct ethtool_rx_flow_spec *fsp)
430 {
431 __u32 loc;
432 __u32 slot_num;
433
434 /* leave this to the driver if possible */
435 if (rmgr->driver_select)
436 return 0;
437
438 /* start at the end of the list since it is lowest priority */
439 loc = rmgr->size - 1;
440
441 /* locate the first slot a rule can be placed in */
442 slot_num = loc / BITS_PER_LONG;
443
444 /*
445 * Avoid testing individual bits by inverting the word and checking
446 * to see if any bits are left set, if so there are empty spots. By
447 * moving 1 + loc % BITS_PER_LONG we align ourselves to the last bit
448 * in the previous word.
449 *
450 * If loc rolls over it should be greater than or equal to rmgr->size
451 * and as such we know we have reached the end of the list.
452 */
453 if (!~(rmgr->slot[slot_num] | (~1UL << loc % BITS_PER_LONG))) {
454 loc -= 1 + (loc % BITS_PER_LONG);
455 slot_num--;
456 }
457
458 /*
459 * Now that we are aligned with the last bit in each long we can just
460 * go though and eliminate all the longs with no free bits
461 */
462 while (loc < rmgr->size && !~(rmgr->slot[slot_num])) {
463 loc -= BITS_PER_LONG;
464 slot_num--;
465 }
466
467 /*
468 * If we still are inside the range, test individual bits as one is
469 * likely available for our use.
470 */
471 while (loc < rmgr->size && test_bit(loc, rmgr->slot))
472 loc--;
473
474 /* location found, insert rule */
475 if (loc < rmgr->size) {
476 fsp->location = loc;
477 return rmgr_ins(rmgr, loc);
478 }
479
480 /* No space to add this rule */
481 fprintf(stderr, "rmgr: Cannot find appropriate slot to insert rule\n");
482
483 return -1;
484 }
485
rmgr_init(struct cmd_context * ctx,struct rmgr_ctrl * rmgr)486 static int rmgr_init(struct cmd_context *ctx, struct rmgr_ctrl *rmgr)
487 {
488 struct ethtool_rxnfc *nfccmd;
489 __u32 *rule_locs;
490 unsigned int i;
491 int err;
492
493 /* clear rule manager settings */
494 memset(rmgr, 0, sizeof(*rmgr));
495
496 /* request device/driver information */
497 err = rxclass_get_dev_info(ctx, &rmgr->n_rules, &rmgr->driver_select);
498 if (err < 0)
499 return err;
500
501 /* do not get the table if the device/driver can select locations */
502 if (rmgr->driver_select)
503 return 0;
504
505 /* alloc memory for request of location list */
506 nfccmd = calloc(1, sizeof(*nfccmd) + (rmgr->n_rules * sizeof(__u32)));
507 if (!nfccmd) {
508 perror("rmgr: Cannot allocate memory for"
509 " RX class rule locations");
510 return -1;
511 }
512
513 /* request location list */
514 nfccmd->cmd = ETHTOOL_GRXCLSRLALL;
515 nfccmd->rule_cnt = rmgr->n_rules;
516 err = send_ioctl(ctx, nfccmd);
517 if (err < 0) {
518 perror("rmgr: Cannot get RX class rules");
519 free(nfccmd);
520 return err;
521 }
522
523 /* make certain the table size is valid */
524 rmgr->size = nfccmd->data;
525 if (rmgr->size == 0 || rmgr->size < rmgr->n_rules) {
526 perror("rmgr: Invalid RX class rules table size");
527 return -1;
528 }
529
530 /* initialize bitmap for storage of valid locations */
531 rmgr->slot = calloc(1, BITS_TO_LONGS(rmgr->size) * sizeof(long));
532 if (!rmgr->slot) {
533 perror("rmgr: Cannot allocate memory for RX class rules");
534 return -1;
535 }
536
537 /* write locations to bitmap */
538 rule_locs = nfccmd->rule_locs;
539 for (i = 0; i < rmgr->n_rules; i++) {
540 err = rmgr_ins(rmgr, rule_locs[i]);
541 if (err < 0)
542 break;
543 }
544
545 free(nfccmd);
546
547 return err;
548 }
549
rmgr_cleanup(struct rmgr_ctrl * rmgr)550 static void rmgr_cleanup(struct rmgr_ctrl *rmgr)
551 {
552 free(rmgr->slot);
553 rmgr->slot = NULL;
554 rmgr->size = 0;
555 }
556
rmgr_set_location(struct cmd_context * ctx,struct ethtool_rx_flow_spec * fsp)557 static int rmgr_set_location(struct cmd_context *ctx,
558 struct ethtool_rx_flow_spec *fsp)
559 {
560 struct rmgr_ctrl rmgr;
561 int err;
562
563 /* init table of available rules */
564 err = rmgr_init(ctx, &rmgr);
565 if (err < 0)
566 goto out;
567
568 /* verify rule location */
569 err = rmgr_find_empty_slot(&rmgr, fsp);
570
571 out:
572 /* cleanup table and free resources */
573 rmgr_cleanup(&rmgr);
574
575 return err;
576 }
577
rxclass_rule_ins(struct cmd_context * ctx,struct ethtool_rx_flow_spec * fsp,__u32 rss_context)578 int rxclass_rule_ins(struct cmd_context *ctx,
579 struct ethtool_rx_flow_spec *fsp, __u32 rss_context)
580 {
581 struct ethtool_rxnfc nfccmd;
582 __u32 loc = fsp->location;
583 int err;
584
585 /*
586 * if location is unspecified and driver cannot select locations, pull
587 * rules from device and allocate a free rule for our use
588 */
589 if (loc & RX_CLS_LOC_SPECIAL) {
590 err = rmgr_set_location(ctx, fsp);
591 if (err < 0)
592 return err;
593 }
594
595 /* notify netdev of new rule */
596 nfccmd.cmd = ETHTOOL_SRXCLSRLINS;
597 nfccmd.rss_context = rss_context;
598 nfccmd.fs = *fsp;
599 err = send_ioctl(ctx, &nfccmd);
600 if (err < 0)
601 perror("rmgr: Cannot insert RX class rule");
602 else if (loc & RX_CLS_LOC_SPECIAL)
603 printf("Added rule with ID %d\n", nfccmd.fs.location);
604
605 return err;
606 }
607
rxclass_rule_del(struct cmd_context * ctx,__u32 loc)608 int rxclass_rule_del(struct cmd_context *ctx, __u32 loc)
609 {
610 struct ethtool_rxnfc nfccmd;
611 int err;
612
613 /* notify netdev of rule removal */
614 nfccmd.cmd = ETHTOOL_SRXCLSRLDEL;
615 nfccmd.fs.location = loc;
616 err = send_ioctl(ctx, &nfccmd);
617 if (err < 0)
618 perror("rmgr: Cannot delete RX class rule");
619
620 return err;
621 }
622
623 typedef enum {
624 OPT_NONE = 0,
625 OPT_S32,
626 OPT_U8,
627 OPT_U16,
628 OPT_U32,
629 OPT_U64,
630 OPT_RING_VF,
631 OPT_RING_QUEUE,
632 OPT_BE16,
633 OPT_BE32,
634 OPT_BE64,
635 OPT_IP4,
636 OPT_IP6,
637 OPT_MAC,
638 } rule_opt_type_t;
639
640 #define NFC_FLAG_RING 0x0001
641 #define NFC_FLAG_LOC 0x0002
642 #define NFC_FLAG_SADDR 0x0004
643 #define NFC_FLAG_DADDR 0x0008
644 #define NFC_FLAG_SPORT 0x0010
645 #define NFC_FLAG_DPORT 0x0020
646 #define NFC_FLAG_SPI 0x0030
647 #define NFC_FLAG_TOS 0x0040
648 #define NFC_FLAG_PROTO 0x0080
649 #define NTUPLE_FLAG_VLAN 0x0100
650 #define NTUPLE_FLAG_UDEF 0x0200
651 #define NTUPLE_FLAG_VETH 0x0400
652 #define NFC_FLAG_MAC_ADDR 0x0800
653 #define NFC_FLAG_RING_VF 0x1000
654 #define NFC_FLAG_RING_QUEUE 0x2000
655
656 struct rule_opts {
657 const char *name;
658 rule_opt_type_t type;
659 u32 flag;
660 int offset;
661 int moffset;
662 };
663
664 static const struct rule_opts rule_nfc_tcp_ip4[] = {
665 { "src-ip", OPT_IP4, NFC_FLAG_SADDR,
666 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.ip4src),
667 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.ip4src) },
668 { "dst-ip", OPT_IP4, NFC_FLAG_DADDR,
669 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.ip4dst),
670 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.ip4dst) },
671 { "tos", OPT_U8, NFC_FLAG_TOS,
672 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.tos),
673 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.tos) },
674 { "src-port", OPT_BE16, NFC_FLAG_SPORT,
675 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.psrc),
676 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.psrc) },
677 { "dst-port", OPT_BE16, NFC_FLAG_DPORT,
678 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.pdst),
679 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.pdst) },
680 { "action", OPT_U64, NFC_FLAG_RING,
681 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
682 { "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
683 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
684 { "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
685 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
686 { "loc", OPT_U32, NFC_FLAG_LOC,
687 offsetof(struct ethtool_rx_flow_spec, location), -1 },
688 { "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
689 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
690 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
691 { "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
692 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
693 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
694 { "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
695 offsetof(struct ethtool_rx_flow_spec, h_ext.data),
696 offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
697 { "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
698 offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
699 offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
700 };
701
702 static const struct rule_opts rule_nfc_esp_ip4[] = {
703 { "src-ip", OPT_IP4, NFC_FLAG_SADDR,
704 offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.ip4src),
705 offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.ip4src) },
706 { "dst-ip", OPT_IP4, NFC_FLAG_DADDR,
707 offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.ip4dst),
708 offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.ip4dst) },
709 { "tos", OPT_U8, NFC_FLAG_TOS,
710 offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.tos),
711 offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.tos) },
712 { "spi", OPT_BE32, NFC_FLAG_SPI,
713 offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.spi),
714 offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.spi) },
715 { "action", OPT_U64, NFC_FLAG_RING,
716 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
717 { "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
718 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
719 { "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
720 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
721 { "loc", OPT_U32, NFC_FLAG_LOC,
722 offsetof(struct ethtool_rx_flow_spec, location), -1 },
723 { "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
724 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
725 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
726 { "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
727 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
728 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
729 { "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
730 offsetof(struct ethtool_rx_flow_spec, h_ext.data),
731 offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
732 { "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
733 offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
734 offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
735 };
736
737 static const struct rule_opts rule_nfc_usr_ip4[] = {
738 { "src-ip", OPT_IP4, NFC_FLAG_SADDR,
739 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.ip4src),
740 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.ip4src) },
741 { "dst-ip", OPT_IP4, NFC_FLAG_DADDR,
742 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.ip4dst),
743 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.ip4dst) },
744 { "tos", OPT_U8, NFC_FLAG_TOS,
745 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.tos),
746 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.tos) },
747 { "l4proto", OPT_U8, NFC_FLAG_PROTO,
748 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.proto),
749 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.proto) },
750 { "l4data", OPT_BE32, NFC_FLAG_SPI,
751 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.l4_4_bytes),
752 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.l4_4_bytes) },
753 { "spi", OPT_BE32, NFC_FLAG_SPI,
754 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.l4_4_bytes),
755 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.l4_4_bytes) },
756 { "src-port", OPT_BE16, NFC_FLAG_SPORT,
757 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.l4_4_bytes),
758 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.l4_4_bytes) },
759 { "dst-port", OPT_BE16, NFC_FLAG_DPORT,
760 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.l4_4_bytes) + 2,
761 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.l4_4_bytes) + 2 },
762 { "action", OPT_U64, NFC_FLAG_RING,
763 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
764 { "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
765 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
766 { "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
767 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
768 { "loc", OPT_U32, NFC_FLAG_LOC,
769 offsetof(struct ethtool_rx_flow_spec, location), -1 },
770 { "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
771 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
772 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
773 { "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
774 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
775 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
776 { "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
777 offsetof(struct ethtool_rx_flow_spec, h_ext.data),
778 offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
779 { "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
780 offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
781 offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
782 };
783
784 static const struct rule_opts rule_nfc_tcp_ip6[] = {
785 { "src-ip", OPT_IP6, NFC_FLAG_SADDR,
786 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.ip6src),
787 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.ip6src) },
788 { "dst-ip", OPT_IP6, NFC_FLAG_DADDR,
789 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.ip6dst),
790 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.ip6dst) },
791 { "tclass", OPT_U8, NFC_FLAG_TOS,
792 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.tclass),
793 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.tclass) },
794 { "src-port", OPT_BE16, NFC_FLAG_SPORT,
795 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.psrc),
796 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.psrc) },
797 { "dst-port", OPT_BE16, NFC_FLAG_DPORT,
798 offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.pdst),
799 offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.pdst) },
800 { "action", OPT_U64, NFC_FLAG_RING,
801 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
802 { "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
803 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
804 { "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
805 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
806 { "loc", OPT_U32, NFC_FLAG_LOC,
807 offsetof(struct ethtool_rx_flow_spec, location), -1 },
808 { "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
809 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
810 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
811 { "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
812 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
813 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
814 { "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
815 offsetof(struct ethtool_rx_flow_spec, h_ext.data),
816 offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
817 { "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
818 offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
819 offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
820 };
821
822 static const struct rule_opts rule_nfc_esp_ip6[] = {
823 { "src-ip", OPT_IP6, NFC_FLAG_SADDR,
824 offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.ip6src),
825 offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.ip6src) },
826 { "dst-ip", OPT_IP6, NFC_FLAG_DADDR,
827 offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.ip6dst),
828 offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.ip6dst) },
829 { "tclass", OPT_U8, NFC_FLAG_TOS,
830 offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.tclass),
831 offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.tclass) },
832 { "spi", OPT_BE32, NFC_FLAG_SPI,
833 offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.spi),
834 offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.spi) },
835 { "action", OPT_U64, NFC_FLAG_RING,
836 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
837 { "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
838 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
839 { "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
840 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
841 { "loc", OPT_U32, NFC_FLAG_LOC,
842 offsetof(struct ethtool_rx_flow_spec, location), -1 },
843 { "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
844 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
845 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
846 { "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
847 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
848 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
849 { "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
850 offsetof(struct ethtool_rx_flow_spec, h_ext.data),
851 offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
852 { "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
853 offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
854 offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
855 };
856
857 static const struct rule_opts rule_nfc_usr_ip6[] = {
858 { "src-ip", OPT_IP6, NFC_FLAG_SADDR,
859 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.ip6src),
860 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.ip6src) },
861 { "dst-ip", OPT_IP6, NFC_FLAG_DADDR,
862 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.ip6dst),
863 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.ip6dst) },
864 { "tclass", OPT_U8, NFC_FLAG_TOS,
865 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.tclass),
866 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.tclass) },
867 { "l4proto", OPT_U8, NFC_FLAG_PROTO,
868 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_proto),
869 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_proto) },
870 { "l4data", OPT_BE32, NFC_FLAG_SPI,
871 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes),
872 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) },
873 { "spi", OPT_BE32, NFC_FLAG_SPI,
874 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes),
875 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) },
876 { "src-port", OPT_BE16, NFC_FLAG_SPORT,
877 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes),
878 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) },
879 { "dst-port", OPT_BE16, NFC_FLAG_DPORT,
880 offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes) + 2,
881 offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) + 2 },
882 { "action", OPT_U64, NFC_FLAG_RING,
883 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
884 { "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
885 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
886 { "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
887 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
888 { "loc", OPT_U32, NFC_FLAG_LOC,
889 offsetof(struct ethtool_rx_flow_spec, location), -1 },
890 { "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
891 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
892 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
893 { "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
894 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
895 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
896 { "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
897 offsetof(struct ethtool_rx_flow_spec, h_ext.data),
898 offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
899 { "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
900 offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
901 offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
902 };
903
904 static const struct rule_opts rule_nfc_ether[] = {
905 { "src", OPT_MAC, NFC_FLAG_SADDR,
906 offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_source),
907 offsetof(struct ethtool_rx_flow_spec, m_u.ether_spec.h_source) },
908 { "dst", OPT_MAC, NFC_FLAG_DADDR,
909 offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_dest),
910 offsetof(struct ethtool_rx_flow_spec, m_u.ether_spec.h_dest) },
911 { "proto", OPT_BE16, NFC_FLAG_PROTO,
912 offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_proto),
913 offsetof(struct ethtool_rx_flow_spec, m_u.ether_spec.h_proto) },
914 { "action", OPT_U64, NFC_FLAG_RING,
915 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
916 { "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
917 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
918 { "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
919 offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
920 { "loc", OPT_U32, NFC_FLAG_LOC,
921 offsetof(struct ethtool_rx_flow_spec, location), -1 },
922 { "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
923 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
924 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
925 { "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
926 offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
927 offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
928 { "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
929 offsetof(struct ethtool_rx_flow_spec, h_ext.data),
930 offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
931 };
932
rxclass_get_long(char * str,long long * val,int size)933 static int rxclass_get_long(char *str, long long *val, int size)
934 {
935 long long max = ~0ULL >> (65 - size);
936 char *endp;
937
938 errno = 0;
939
940 *val = strtoll(str, &endp, 0);
941
942 if (*endp || errno || (*val > max) || (*val < ~max))
943 return -1;
944
945 return 0;
946 }
947
rxclass_get_ulong(char * str,unsigned long long * val,int size)948 static int rxclass_get_ulong(char *str, unsigned long long *val, int size)
949 {
950 unsigned long long max = ~0ULL >> (64 - size);
951 char *endp;
952
953 errno = 0;
954
955 *val = strtoull(str, &endp, 0);
956
957 if (*endp || errno || (*val > max))
958 return -1;
959
960 return 0;
961 }
962
rxclass_get_ipv4(char * str,__be32 * val)963 static int rxclass_get_ipv4(char *str, __be32 *val)
964 {
965 if (!inet_pton(AF_INET, str, val))
966 return -1;
967
968 return 0;
969 }
970
rxclass_get_ipv6(char * str,__be32 * val)971 static int rxclass_get_ipv6(char *str, __be32 *val)
972 {
973 if (!inet_pton(AF_INET6, str, val))
974 return -1;
975
976 return 0;
977 }
978
rxclass_get_ether(char * str,unsigned char * val)979 static int rxclass_get_ether(char *str, unsigned char *val)
980 {
981 unsigned int buf[ETH_ALEN];
982 int count;
983
984 if (!strchr(str, ':'))
985 return -1;
986
987 count = sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x",
988 &buf[0], &buf[1], &buf[2],
989 &buf[3], &buf[4], &buf[5]);
990
991 if (count != ETH_ALEN)
992 return -1;
993
994 do {
995 count--;
996 val[count] = buf[count];
997 } while (count);
998
999 return 0;
1000 }
1001
rxclass_get_val(char * str,unsigned char * p,u32 * flags,const struct rule_opts * opt)1002 static int rxclass_get_val(char *str, unsigned char *p, u32 *flags,
1003 const struct rule_opts *opt)
1004 {
1005 unsigned long long mask = ~0ULL;
1006 int err = 0;
1007
1008 if (*flags & opt->flag)
1009 return -1;
1010
1011 *flags |= opt->flag;
1012
1013 switch (opt->type) {
1014 case OPT_S32: {
1015 long long val;
1016 err = rxclass_get_long(str, &val, 32);
1017 if (err)
1018 return -1;
1019 *(int *)&p[opt->offset] = (int)val;
1020 if (opt->moffset >= 0)
1021 *(int *)&p[opt->moffset] = (int)mask;
1022 break;
1023 }
1024 case OPT_U8: {
1025 unsigned long long val;
1026 err = rxclass_get_ulong(str, &val, 8);
1027 if (err)
1028 return -1;
1029 *(u8 *)&p[opt->offset] = (u8)val;
1030 if (opt->moffset >= 0)
1031 *(u8 *)&p[opt->moffset] = (u8)mask;
1032 break;
1033 }
1034 case OPT_U16: {
1035 unsigned long long val;
1036 err = rxclass_get_ulong(str, &val, 16);
1037 if (err)
1038 return -1;
1039 *(u16 *)&p[opt->offset] = (u16)val;
1040 if (opt->moffset >= 0)
1041 *(u16 *)&p[opt->moffset] = (u16)mask;
1042 break;
1043 }
1044 case OPT_U32: {
1045 unsigned long long val;
1046 err = rxclass_get_ulong(str, &val, 32);
1047 if (err)
1048 return -1;
1049 *(u32 *)&p[opt->offset] = (u32)val;
1050 if (opt->moffset >= 0)
1051 *(u32 *)&p[opt->moffset] = (u32)mask;
1052 break;
1053 }
1054 case OPT_U64: {
1055 unsigned long long val;
1056 err = rxclass_get_ulong(str, &val, 64);
1057 if (err)
1058 return -1;
1059 *(u64 *)&p[opt->offset] = (u64)val;
1060 if (opt->moffset >= 0)
1061 *(u64 *)&p[opt->moffset] = (u64)mask;
1062 break;
1063 }
1064 case OPT_RING_VF: {
1065 unsigned long long val;
1066 err = rxclass_get_ulong(str, &val, 8);
1067 if (err)
1068 return -1;
1069
1070 /* The ring_cookie uses 0 to indicate the rule targets the
1071 * main function, so add 1 to the value in order to target the
1072 * correct virtual function.
1073 */
1074 val++;
1075
1076 *(u64 *)&p[opt->offset] &= ~ETHTOOL_RX_FLOW_SPEC_RING_VF;
1077 *(u64 *)&p[opt->offset] |= (u64)val << ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF;
1078 break;
1079 }
1080 case OPT_RING_QUEUE: {
1081 unsigned long long val;
1082 err = rxclass_get_ulong(str, &val, 32);
1083 if (err)
1084 return -1;
1085 *(u64 *)&p[opt->offset] &= ~ETHTOOL_RX_FLOW_SPEC_RING;
1086 *(u64 *)&p[opt->offset] |= (u64)val;
1087 break;
1088 }
1089 case OPT_BE16: {
1090 unsigned long long val;
1091 err = rxclass_get_ulong(str, &val, 16);
1092 if (err)
1093 return -1;
1094 *(__be16 *)&p[opt->offset] = htons((u16)val);
1095 if (opt->moffset >= 0)
1096 *(__be16 *)&p[opt->moffset] = (__be16)mask;
1097 break;
1098 }
1099 case OPT_BE32: {
1100 unsigned long long val;
1101 err = rxclass_get_ulong(str, &val, 32);
1102 if (err)
1103 return -1;
1104 *(__be32 *)&p[opt->offset] = htonl((u32)val);
1105 if (opt->moffset >= 0)
1106 *(__be32 *)&p[opt->moffset] = (__be32)mask;
1107 break;
1108 }
1109 case OPT_BE64: {
1110 unsigned long long val;
1111 err = rxclass_get_ulong(str, &val, 64);
1112 if (err)
1113 return -1;
1114 *(__be64 *)&p[opt->offset] = htonll((u64)val);
1115 if (opt->moffset >= 0)
1116 *(__be64 *)&p[opt->moffset] = (__be64)mask;
1117 break;
1118 }
1119 case OPT_IP4: {
1120 __be32 val;
1121 err = rxclass_get_ipv4(str, &val);
1122 if (err)
1123 return -1;
1124 *(__be32 *)&p[opt->offset] = val;
1125 if (opt->moffset >= 0)
1126 *(__be32 *)&p[opt->moffset] = (__be32)mask;
1127 break;
1128 }
1129 case OPT_IP6: {
1130 __be32 val[4];
1131 err = rxclass_get_ipv6(str, val);
1132 if (err)
1133 return -1;
1134 memcpy(&p[opt->offset], val, sizeof(val));
1135 if (opt->moffset >= 0)
1136 memset(&p[opt->moffset], mask, sizeof(val));
1137 break;
1138 }
1139 case OPT_MAC: {
1140 unsigned char val[ETH_ALEN];
1141 err = rxclass_get_ether(str, val);
1142 if (err)
1143 return -1;
1144 memcpy(&p[opt->offset], val, ETH_ALEN);
1145 if (opt->moffset >= 0)
1146 memcpy(&p[opt->moffset], &mask, ETH_ALEN);
1147 break;
1148 }
1149 case OPT_NONE:
1150 default:
1151 return -1;
1152 }
1153
1154 return 0;
1155 }
1156
rxclass_get_mask(char * str,unsigned char * p,const struct rule_opts * opt)1157 static int rxclass_get_mask(char *str, unsigned char *p,
1158 const struct rule_opts *opt)
1159 {
1160 int err = 0;
1161
1162 if (opt->moffset < 0)
1163 return -1;
1164
1165 switch (opt->type) {
1166 case OPT_S32: {
1167 long long val;
1168 err = rxclass_get_long(str, &val, 32);
1169 if (err)
1170 return -1;
1171 *(int *)&p[opt->moffset] = ~(int)val;
1172 break;
1173 }
1174 case OPT_U8: {
1175 unsigned long long val;
1176 err = rxclass_get_ulong(str, &val, 8);
1177 if (err)
1178 return -1;
1179 *(u8 *)&p[opt->moffset] = ~(u8)val;
1180 break;
1181 }
1182 case OPT_U16: {
1183 unsigned long long val;
1184 err = rxclass_get_ulong(str, &val, 16);
1185 if (err)
1186 return -1;
1187 *(u16 *)&p[opt->moffset] = ~(u16)val;
1188 break;
1189 }
1190 case OPT_U32: {
1191 unsigned long long val;
1192 err = rxclass_get_ulong(str, &val, 32);
1193 if (err)
1194 return -1;
1195 *(u32 *)&p[opt->moffset] = ~(u32)val;
1196 break;
1197 }
1198 case OPT_U64: {
1199 unsigned long long val;
1200 err = rxclass_get_ulong(str, &val, 64);
1201 if (err)
1202 return -1;
1203 *(u64 *)&p[opt->moffset] = ~(u64)val;
1204 break;
1205 }
1206 case OPT_BE16: {
1207 unsigned long long val;
1208 err = rxclass_get_ulong(str, &val, 16);
1209 if (err)
1210 return -1;
1211 *(__be16 *)&p[opt->moffset] = ~htons((u16)val);
1212 break;
1213 }
1214 case OPT_BE32: {
1215 unsigned long long val;
1216 err = rxclass_get_ulong(str, &val, 32);
1217 if (err)
1218 return -1;
1219 *(__be32 *)&p[opt->moffset] = ~htonl((u32)val);
1220 break;
1221 }
1222 case OPT_BE64: {
1223 unsigned long long val;
1224 err = rxclass_get_ulong(str, &val, 64);
1225 if (err)
1226 return -1;
1227 *(__be64 *)&p[opt->moffset] = ~htonll((u64)val);
1228 break;
1229 }
1230 case OPT_IP4: {
1231 __be32 val;
1232 err = rxclass_get_ipv4(str, &val);
1233 if (err)
1234 return -1;
1235 *(__be32 *)&p[opt->moffset] = ~val;
1236 break;
1237 }
1238 case OPT_IP6: {
1239 __be32 val[4], *field;
1240 int i;
1241 err = rxclass_get_ipv6(str, val);
1242 if (err)
1243 return -1;
1244 field = (__be32 *)&p[opt->moffset];
1245 for (i = 0; i < 4; i++)
1246 field[i] = ~val[i];
1247 break;
1248 }
1249 case OPT_MAC: {
1250 unsigned char val[ETH_ALEN];
1251 int i;
1252 err = rxclass_get_ether(str, val);
1253 if (err)
1254 return -1;
1255
1256 for (i = 0; i < ETH_ALEN; i++)
1257 val[i] = ~val[i];
1258
1259 memcpy(&p[opt->moffset], val, ETH_ALEN);
1260 break;
1261 }
1262 case OPT_NONE:
1263 default:
1264 return -1;
1265 }
1266
1267 return 0;
1268 }
1269
rxclass_parse_ruleopts(struct cmd_context * ctx,struct ethtool_rx_flow_spec * fsp,__u32 * rss_context)1270 int rxclass_parse_ruleopts(struct cmd_context *ctx,
1271 struct ethtool_rx_flow_spec *fsp, __u32 *rss_context)
1272 {
1273 const struct rule_opts *options;
1274 unsigned char *p = (unsigned char *)fsp;
1275 int i = 0, n_opts, err;
1276 u32 flags = 0;
1277 int flow_type;
1278 int argc = ctx->argc;
1279 char **argp = ctx->argp;
1280
1281 if (argc < 1)
1282 goto syntax_err;
1283
1284 if (!strcmp(argp[0], "tcp4"))
1285 flow_type = TCP_V4_FLOW;
1286 else if (!strcmp(argp[0], "udp4"))
1287 flow_type = UDP_V4_FLOW;
1288 else if (!strcmp(argp[0], "sctp4"))
1289 flow_type = SCTP_V4_FLOW;
1290 else if (!strcmp(argp[0], "ah4"))
1291 flow_type = AH_V4_FLOW;
1292 else if (!strcmp(argp[0], "esp4"))
1293 flow_type = ESP_V4_FLOW;
1294 else if (!strcmp(argp[0], "ip4"))
1295 flow_type = IPV4_USER_FLOW;
1296 else if (!strcmp(argp[0], "tcp6"))
1297 flow_type = TCP_V6_FLOW;
1298 else if (!strcmp(argp[0], "udp6"))
1299 flow_type = UDP_V6_FLOW;
1300 else if (!strcmp(argp[0], "sctp6"))
1301 flow_type = SCTP_V6_FLOW;
1302 else if (!strcmp(argp[0], "ah6"))
1303 flow_type = AH_V6_FLOW;
1304 else if (!strcmp(argp[0], "esp6"))
1305 flow_type = ESP_V6_FLOW;
1306 else if (!strcmp(argp[0], "ip6"))
1307 flow_type = IPV6_USER_FLOW;
1308 else if (!strcmp(argp[0], "ether"))
1309 flow_type = ETHER_FLOW;
1310 else
1311 goto syntax_err;
1312
1313 switch (flow_type) {
1314 case TCP_V4_FLOW:
1315 case UDP_V4_FLOW:
1316 case SCTP_V4_FLOW:
1317 options = rule_nfc_tcp_ip4;
1318 n_opts = ARRAY_SIZE(rule_nfc_tcp_ip4);
1319 break;
1320 case AH_V4_FLOW:
1321 case ESP_V4_FLOW:
1322 options = rule_nfc_esp_ip4;
1323 n_opts = ARRAY_SIZE(rule_nfc_esp_ip4);
1324 break;
1325 case IPV4_USER_FLOW:
1326 options = rule_nfc_usr_ip4;
1327 n_opts = ARRAY_SIZE(rule_nfc_usr_ip4);
1328 break;
1329 case TCP_V6_FLOW:
1330 case UDP_V6_FLOW:
1331 case SCTP_V6_FLOW:
1332 options = rule_nfc_tcp_ip6;
1333 n_opts = ARRAY_SIZE(rule_nfc_tcp_ip6);
1334 break;
1335 case AH_V6_FLOW:
1336 case ESP_V6_FLOW:
1337 options = rule_nfc_esp_ip6;
1338 n_opts = ARRAY_SIZE(rule_nfc_esp_ip6);
1339 break;
1340 case IPV6_USER_FLOW:
1341 options = rule_nfc_usr_ip6;
1342 n_opts = ARRAY_SIZE(rule_nfc_usr_ip6);
1343 break;
1344 case ETHER_FLOW:
1345 options = rule_nfc_ether;
1346 n_opts = ARRAY_SIZE(rule_nfc_ether);
1347 break;
1348 default:
1349 fprintf(stderr, "Add rule, invalid rule type[%s]\n", argp[0]);
1350 return -1;
1351 }
1352
1353 memset(p, 0, sizeof(*fsp));
1354 fsp->flow_type = flow_type;
1355 fsp->location = RX_CLS_LOC_ANY;
1356
1357 for (i = 1; i < argc;) {
1358 const struct rule_opts *opt;
1359 int idx;
1360
1361 /* special handling for 'context %d' as it doesn't go in
1362 * the struct ethtool_rx_flow_spec
1363 */
1364 if (!strcmp(argp[i], "context")) {
1365 unsigned long long val;
1366
1367 i++;
1368 if (i >= argc) {
1369 fprintf(stderr, "'context' missing value\n");
1370 return -1;
1371 }
1372
1373 if (rxclass_get_ulong(argp[i], &val, 32)) {
1374 fprintf(stderr, "Invalid context value[%s]\n",
1375 argp[i]);
1376 return -1;
1377 }
1378
1379 /* Can't use the ALLOC special value as the context ID
1380 * of a filter to insert
1381 */
1382 if ((__u32)val == ETH_RXFH_CONTEXT_ALLOC) {
1383 fprintf(stderr, "Bad context value %x\n",
1384 (__u32)val);
1385 return -1;
1386 }
1387
1388 *rss_context = (__u32)val;
1389 fsp->flow_type |= FLOW_RSS;
1390 i++;
1391 continue;
1392 }
1393
1394 for (opt = options, idx = 0; idx < n_opts; idx++, opt++) {
1395 char mask_name[16];
1396
1397 if (strcmp(argp[i], opt->name))
1398 continue;
1399
1400 i++;
1401 if (i >= argc)
1402 break;
1403
1404 err = rxclass_get_val(argp[i], p, &flags, opt);
1405 if (err) {
1406 fprintf(stderr, "Invalid %s value[%s]\n",
1407 opt->name, argp[i]);
1408 return -1;
1409 }
1410
1411 i++;
1412 if (i >= argc)
1413 break;
1414
1415 sprintf(mask_name, "%s-mask", opt->name);
1416 if (strcmp(argp[i], "m") && strcmp(argp[i], mask_name))
1417 break;
1418
1419 i++;
1420 if (i >= argc)
1421 goto syntax_err;
1422
1423 err = rxclass_get_mask(argp[i], p, opt);
1424 if (err) {
1425 fprintf(stderr, "Invalid %s mask[%s]\n",
1426 opt->name, argp[i]);
1427 return -1;
1428 }
1429
1430 i++;
1431
1432 break;
1433 }
1434 if (idx == n_opts) {
1435 fprintf(stdout, "Add rule, unrecognized option[%s]\n",
1436 argp[i]);
1437 return -1;
1438 }
1439 }
1440
1441 if ((flags & NFC_FLAG_RING) && (flags & NFC_FLAG_RING_QUEUE)) {
1442 fprintf(stderr, "action and queue are not compatible\n");
1443 return -1;
1444 }
1445
1446 if ((flags & NFC_FLAG_RING) && (flags & NFC_FLAG_RING_VF)) {
1447 fprintf(stderr, "action and vf are not compatible\n");
1448 return -1;
1449 }
1450
1451 if (flow_type == IPV4_USER_FLOW)
1452 fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
1453 if (flags & (NTUPLE_FLAG_VLAN | NTUPLE_FLAG_UDEF | NTUPLE_FLAG_VETH))
1454 fsp->flow_type |= FLOW_EXT;
1455 if (flags & NFC_FLAG_MAC_ADDR)
1456 fsp->flow_type |= FLOW_MAC_EXT;
1457
1458 return 0;
1459
1460 syntax_err:
1461 fprintf(stderr, "Add rule, invalid syntax\n");
1462 return -1;
1463 }
1464