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