2
* Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
11
#include <linux/sockios.h>
12
#include <arpa/inet.h>
13
#include "ethtool-util.h"
14
#include "ethtool-bitops.h"
16
static void invert_flow_mask(struct ethtool_rx_flow_spec *fsp)
20
for (i = 0; i < sizeof(fsp->m_u); i++)
21
fsp->m_u.hdata[i] ^= 0xFF;
24
static void rxclass_print_ipv4_rule(__be32 sip, __be32 sipm, __be32 dip,
25
__be32 dipm, u8 tos, u8 tosm)
27
char sip_str[INET_ADDRSTRLEN];
28
char sipm_str[INET_ADDRSTRLEN];
29
char dip_str[INET_ADDRSTRLEN];
30
char dipm_str[INET_ADDRSTRLEN];
33
"\tSrc IP addr: %s mask: %s\n"
34
"\tDest IP addr: %s mask: %s\n"
35
"\tTOS: 0x%x mask: 0x%x\n",
36
inet_ntop(AF_INET, &sip, sip_str, INET_ADDRSTRLEN),
37
inet_ntop(AF_INET, &sipm, sipm_str, INET_ADDRSTRLEN),
38
inet_ntop(AF_INET, &dip, dip_str, INET_ADDRSTRLEN),
39
inet_ntop(AF_INET, &dipm, dipm_str, INET_ADDRSTRLEN),
43
static void rxclass_print_nfc_spec_ext(struct ethtool_rx_flow_spec *fsp)
46
__u16 etype, etypem, tci, tcim;
48
if (!(fsp->flow_type & FLOW_EXT))
51
etype = ntohs(fsp->h_ext.vlan_etype);
52
etypem = ntohs(~fsp->m_ext.vlan_etype);
53
tci = ntohs(fsp->h_ext.vlan_tci);
54
tcim = ntohs(~fsp->m_ext.vlan_tci);
55
data = (u64)ntohl(fsp->h_ext.data[0]) << 32;
56
data = (u64)ntohl(fsp->h_ext.data[1]);
57
datam = (u64)ntohl(~fsp->m_ext.data[0]) << 32;
58
datam |= (u64)ntohl(~fsp->m_ext.data[1]);
61
"\tVLAN EtherType: 0x%x mask: 0x%x\n"
62
"\tVLAN: 0x%x mask: 0x%x\n"
63
"\tUser-defined: 0x%llx mask: 0x%llx\n",
64
etype, etypem, tci, tcim, data, datam);
67
static void rxclass_print_nfc_rule(struct ethtool_rx_flow_spec *fsp)
69
unsigned char *smac, *smacm, *dmac, *dmacm;
72
if (fsp->location != RX_CLS_LOC_UNSPEC)
73
fprintf(stdout, "Filter: %d\n", fsp->location);
75
fprintf(stdout, "Filter: Unspecified\n");
77
flow_type = fsp->flow_type & ~FLOW_EXT;
79
invert_flow_mask(fsp);
85
if (flow_type == TCP_V4_FLOW)
86
fprintf(stdout, "\tRule Type: TCP over IPv4\n");
87
else if (flow_type == UDP_V4_FLOW)
88
fprintf(stdout, "\tRule Type: UDP over IPv4\n");
90
fprintf(stdout, "\tRule Type: SCTP over IPv4\n");
91
rxclass_print_ipv4_rule(fsp->h_u.tcp_ip4_spec.ip4src,
92
fsp->m_u.tcp_ip4_spec.ip4src,
93
fsp->h_u.tcp_ip4_spec.ip4dst,
94
fsp->m_u.tcp_ip4_spec.ip4dst,
95
fsp->h_u.tcp_ip4_spec.tos,
96
fsp->m_u.tcp_ip4_spec.tos);
98
"\tSrc port: %d mask: 0x%x\n"
99
"\tDest port: %d mask: 0x%x\n",
100
ntohs(fsp->h_u.tcp_ip4_spec.psrc),
101
ntohs(fsp->m_u.tcp_ip4_spec.psrc),
102
ntohs(fsp->h_u.tcp_ip4_spec.pdst),
103
ntohs(fsp->m_u.tcp_ip4_spec.pdst));
107
if (flow_type == AH_V4_FLOW)
108
fprintf(stdout, "\tRule Type: IPSEC AH over IPv4\n");
110
fprintf(stdout, "\tRule Type: IPSEC ESP over IPv4\n");
111
rxclass_print_ipv4_rule(fsp->h_u.ah_ip4_spec.ip4src,
112
fsp->m_u.ah_ip4_spec.ip4src,
113
fsp->h_u.ah_ip4_spec.ip4dst,
114
fsp->m_u.ah_ip4_spec.ip4dst,
115
fsp->h_u.ah_ip4_spec.tos,
116
fsp->m_u.ah_ip4_spec.tos);
118
"\tSPI: %d mask: 0x%x\n",
119
ntohl(fsp->h_u.esp_ip4_spec.spi),
120
ntohl(fsp->m_u.esp_ip4_spec.spi));
123
fprintf(stdout, "\tRule Type: Raw IPv4\n");
124
rxclass_print_ipv4_rule(fsp->h_u.usr_ip4_spec.ip4src,
125
fsp->m_u.usr_ip4_spec.ip4src,
126
fsp->h_u.usr_ip4_spec.ip4dst,
127
fsp->m_u.usr_ip4_spec.ip4dst,
128
fsp->h_u.usr_ip4_spec.tos,
129
fsp->m_u.usr_ip4_spec.tos);
131
"\tProtocol: %d mask: 0x%x\n"
132
"\tL4 bytes: 0x%x mask: 0x%x\n",
133
fsp->h_u.usr_ip4_spec.proto,
134
fsp->m_u.usr_ip4_spec.proto,
135
ntohl(fsp->h_u.usr_ip4_spec.l4_4_bytes),
136
ntohl(fsp->m_u.usr_ip4_spec.l4_4_bytes));
139
dmac = fsp->h_u.ether_spec.h_dest;
140
dmacm = fsp->m_u.ether_spec.h_dest;
141
smac = fsp->h_u.ether_spec.h_source;
142
smacm = fsp->m_u.ether_spec.h_source;
145
"\tFlow Type: Raw Ethernet\n"
146
"\tSrc MAC addr: %02X:%02X:%02X:%02X:%02X:%02X"
147
" mask: %02X:%02X:%02X:%02X:%02X:%02X\n"
148
"\tDest MAC addr: %02X:%02X:%02X:%02X:%02X:%02X"
149
" mask: %02X:%02X:%02X:%02X:%02X:%02X\n"
150
"\tEthertype: 0x%X mask: 0x%X\n",
151
smac[0], smac[1], smac[2], smac[3], smac[4], smac[5],
152
smacm[0], smacm[1], smacm[2], smacm[3], smacm[4],
153
smacm[5], dmac[0], dmac[1], dmac[2], dmac[3], dmac[4],
154
dmac[5], dmacm[0], dmacm[1], dmacm[2], dmacm[3],
156
ntohs(fsp->h_u.ether_spec.h_proto),
157
ntohs(fsp->m_u.ether_spec.h_proto));
161
"\tUnknown Flow type: %d\n", flow_type);
165
rxclass_print_nfc_spec_ext(fsp);
167
if (fsp->ring_cookie != RX_CLS_FLOW_DISC)
168
fprintf(stdout, "\tAction: Direct to queue %llu\n",
171
fprintf(stdout, "\tAction: Drop\n");
173
fprintf(stdout, "\n");
176
static void rxclass_print_rule(struct ethtool_rx_flow_spec *fsp)
178
/* print the rule in this location */
179
switch (fsp->flow_type & ~FLOW_EXT) {
186
rxclass_print_nfc_rule(fsp);
189
if (fsp->h_u.usr_ip4_spec.ip_ver == ETH_RX_NFC_IP4) {
190
rxclass_print_nfc_rule(fsp);
193
/* IPv6 User Flow falls through to the case below */
199
fprintf(stderr, "IPv6 flows not implemented\n");
202
fprintf(stderr, "rxclass: Unknown flow type\n");
207
static int rxclass_get_count(int fd, struct ifreq *ifr, __u32 *count)
209
struct ethtool_rxnfc nfccmd;
212
/* request count and store */
213
nfccmd.cmd = ETHTOOL_GRXCLSRLCNT;
215
ifr->ifr_data = (caddr_t)&nfccmd;
216
err = ioctl(fd, SIOCETHTOOL, ifr);
217
*count = nfccmd.rule_cnt;
219
perror("rxclass: Cannot get RX class rule count");
224
int rxclass_rule_get(int fd, struct ifreq *ifr, __u32 loc)
226
struct ethtool_rxnfc nfccmd;
229
/* fetch rule from netdev */
230
nfccmd.cmd = ETHTOOL_GRXCLSRULE;
231
memset(&nfccmd.fs, 0, sizeof(struct ethtool_rx_flow_spec));
232
nfccmd.fs.location = loc;
233
ifr->ifr_data = (caddr_t)&nfccmd;
234
err = ioctl(fd, SIOCETHTOOL, ifr);
236
perror("rxclass: Cannot get RX class rule");
241
rxclass_print_rule(&nfccmd.fs);
245
int rxclass_rule_getall(int fd, struct ifreq *ifr)
247
struct ethtool_rxnfc *nfccmd;
252
/* determine rule count */
253
err = rxclass_get_count(fd, ifr, &count);
257
fprintf(stdout, "Total %d rules\n\n", count);
259
/* alloc memory for request of location list */
260
nfccmd = calloc(1, sizeof(*nfccmd) + (count * sizeof(__u32)));
262
perror("rxclass: Cannot allocate memory for"
263
" RX class rule locations");
267
/* request location list */
268
nfccmd->cmd = ETHTOOL_GRXCLSRLALL;
269
nfccmd->rule_cnt = count;
270
ifr->ifr_data = (caddr_t)nfccmd;
271
err = ioctl(fd, SIOCETHTOOL, ifr);
273
perror("rxclass: Cannot get RX class rules");
278
/* write locations to bitmap */
279
rule_locs = nfccmd->rule_locs;
280
for (i = 0; i < count; i++) {
281
err = rxclass_rule_get(fd, ifr, rule_locs[i]);
286
/* free memory and set flag to avoid reinit */
293
* This is a simple rule manager implementation for ordering rx flow
294
* classification rules based on newest rules being first in the list.
295
* The assumption is that this rule manager is the only one adding rules to
296
* the device's hardware classifier.
300
/* slot contains a bitmap indicating which filters are valid */
306
static struct rmgr_ctrl rmgr;
307
static int rmgr_init_done = 0;
309
static int rmgr_ins(__u32 loc)
311
/* verify location is in rule manager range */
312
if (loc >= rmgr.size) {
313
fprintf(stderr, "rmgr: Location out of range\n");
317
/* set bit for the rule */
318
set_bit(loc, rmgr.slot);
323
static int rmgr_find_empty_slot(struct ethtool_rx_flow_spec *fsp)
328
/* start at the end of the list since it is lowest priority */
331
/* locate the first slot a rule can be placed in */
332
slot_num = loc / BITS_PER_LONG;
335
* Avoid testing individual bits by inverting the word and checking
336
* to see if any bits are left set, if so there are empty spots. By
337
* moving 1 + loc % BITS_PER_LONG we align ourselves to the last bit
338
* in the previous word.
340
* If loc rolls over it should be greater than or equal to rmgr.size
341
* and as such we know we have reached the end of the list.
343
if (!~(rmgr.slot[slot_num] | (~1UL << rmgr.size % BITS_PER_LONG))) {
344
loc -= 1 + (loc % BITS_PER_LONG);
349
* Now that we are aligned with the last bit in each long we can just
350
* go though and eliminate all the longs with no free bits
352
while (loc < rmgr.size && !~(rmgr.slot[slot_num])) {
353
loc -= BITS_PER_LONG;
358
* If we still are inside the range, test individual bits as one is
359
* likely available for our use.
361
while (loc < rmgr.size && test_bit(loc, rmgr.slot))
364
/* location found, insert rule */
365
if (loc < rmgr.size) {
367
return rmgr_ins(loc);
370
/* No space to add this rule */
371
fprintf(stderr, "rmgr: Cannot find appropriate slot to insert rule\n");
376
static int rmgr_init(int fd, struct ifreq *ifr)
378
struct ethtool_rxnfc *nfccmd;
385
/* clear rule manager settings */
386
memset(&rmgr, 0, sizeof(struct rmgr_ctrl));
388
/* request count and store in rmgr.n_rules */
389
err = rxclass_get_count(fd, ifr, &rmgr.n_rules);
393
/* alloc memory for request of location list */
394
nfccmd = calloc(1, sizeof(*nfccmd) + (rmgr.n_rules * sizeof(__u32)));
396
perror("rmgr: Cannot allocate memory for"
397
" RX class rule locations");
401
/* request location list */
402
nfccmd->cmd = ETHTOOL_GRXCLSRLALL;
403
nfccmd->rule_cnt = rmgr.n_rules;
404
ifr->ifr_data = (caddr_t)nfccmd;
405
err = ioctl(fd, SIOCETHTOOL, ifr);
407
perror("rmgr: Cannot get RX class rules");
412
/* make certain the table size is valid */
413
rmgr.size = nfccmd->data;
414
if (rmgr.size == 0 || rmgr.size < rmgr.n_rules) {
415
perror("rmgr: Invalid RX class rules table size");
419
/* initialize bitmap for storage of valid locations */
420
rmgr.slot = calloc(1, BITS_TO_LONGS(rmgr.size) * sizeof(long));
422
perror("rmgr: Cannot allocate memory for RX class rules");
426
/* write locations to bitmap */
427
rule_locs = nfccmd->rule_locs;
428
for (i = 0; i < rmgr.n_rules; i++) {
429
err = rmgr_ins(rule_locs[i]);
434
/* free memory and set flag to avoid reinit */
441
static void rmgr_cleanup(void)
453
static int rmgr_set_location(int fd, struct ifreq *ifr,
454
struct ethtool_rx_flow_spec *fsp)
458
/* init table of available rules */
459
err = rmgr_init(fd, ifr);
463
/* verify rule location */
464
err = rmgr_find_empty_slot(fsp);
466
/* cleanup table and free resources */
472
int rxclass_rule_ins(int fd, struct ifreq *ifr,
473
struct ethtool_rx_flow_spec *fsp)
475
struct ethtool_rxnfc nfccmd;
476
__u32 loc = fsp->location;
480
* if location is unspecified pull rules from device
481
* and allocate a free rule for our use
483
if (loc == RX_CLS_LOC_UNSPEC) {
484
err = rmgr_set_location(fd, ifr, fsp);
489
/* notify netdev of new rule */
490
nfccmd.cmd = ETHTOOL_SRXCLSRLINS;
492
ifr->ifr_data = (caddr_t)&nfccmd;
493
err = ioctl(fd, SIOCETHTOOL, ifr);
495
perror("rmgr: Cannot insert RX class rule");
496
else if (loc == RX_CLS_LOC_UNSPEC)
497
printf("Added rule with ID %d\n", fsp->location);
502
int rxclass_rule_del(int fd, struct ifreq *ifr, __u32 loc)
504
struct ethtool_rxnfc nfccmd;
507
/* notify netdev of rule removal */
508
nfccmd.cmd = ETHTOOL_SRXCLSRLDEL;
509
nfccmd.fs.location = loc;
510
ifr->ifr_data = (caddr_t)&nfccmd;
511
err = ioctl(fd, SIOCETHTOOL, ifr);
513
perror("rmgr: Cannot delete RX class rule");
532
#define NFC_FLAG_RING 0x001
533
#define NFC_FLAG_LOC 0x002
534
#define NFC_FLAG_SADDR 0x004
535
#define NFC_FLAG_DADDR 0x008
536
#define NFC_FLAG_SPORT 0x010
537
#define NFC_FLAG_DPORT 0x020
538
#define NFC_FLAG_SPI 0x030
539
#define NFC_FLAG_TOS 0x040
540
#define NFC_FLAG_PROTO 0x080
541
#define NTUPLE_FLAG_VLAN 0x100
542
#define NTUPLE_FLAG_UDEF 0x200
543
#define NTUPLE_FLAG_VETH 0x400
547
rule_opt_type_t type;
553
static struct rule_opts rule_nfc_tcp_ip4[] = {
554
{ "src-ip", OPT_IP4, NFC_FLAG_SADDR,
555
offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.ip4src),
556
offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.ip4src) },
557
{ "dst-ip", OPT_IP4, NFC_FLAG_DADDR,
558
offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.ip4dst),
559
offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.ip4dst) },
560
{ "tos", OPT_U8, NFC_FLAG_TOS,
561
offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.tos),
562
offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.tos) },
563
{ "src-port", OPT_BE16, NFC_FLAG_SPORT,
564
offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.psrc),
565
offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.psrc) },
566
{ "dst-port", OPT_BE16, NFC_FLAG_DPORT,
567
offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.pdst),
568
offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.pdst) },
569
{ "action", OPT_U64, NFC_FLAG_RING,
570
offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
571
{ "loc", OPT_U32, NFC_FLAG_LOC,
572
offsetof(struct ethtool_rx_flow_spec, location), -1 },
573
{ "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
574
offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
575
offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
576
{ "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
577
offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
578
offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
579
{ "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
580
offsetof(struct ethtool_rx_flow_spec, h_ext.data),
581
offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
584
static struct rule_opts rule_nfc_esp_ip4[] = {
585
{ "src-ip", OPT_IP4, NFC_FLAG_SADDR,
586
offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.ip4src),
587
offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.ip4src) },
588
{ "dst-ip", OPT_IP4, NFC_FLAG_DADDR,
589
offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.ip4dst),
590
offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.ip4dst) },
591
{ "tos", OPT_U8, NFC_FLAG_TOS,
592
offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.tos),
593
offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.tos) },
594
{ "spi", OPT_BE32, NFC_FLAG_SPI,
595
offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.spi),
596
offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.spi) },
597
{ "action", OPT_U64, NFC_FLAG_RING,
598
offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
599
{ "loc", OPT_U32, NFC_FLAG_LOC,
600
offsetof(struct ethtool_rx_flow_spec, location), -1 },
601
{ "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
602
offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
603
offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
604
{ "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
605
offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
606
offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
607
{ "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
608
offsetof(struct ethtool_rx_flow_spec, h_ext.data),
609
offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
612
static struct rule_opts rule_nfc_usr_ip4[] = {
613
{ "src-ip", OPT_IP4, NFC_FLAG_SADDR,
614
offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.ip4src),
615
offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.ip4src) },
616
{ "dst-ip", OPT_IP4, NFC_FLAG_DADDR,
617
offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.ip4dst),
618
offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.ip4dst) },
619
{ "tos", OPT_U8, NFC_FLAG_TOS,
620
offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.tos),
621
offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.tos) },
622
{ "l4proto", OPT_U8, NFC_FLAG_PROTO,
623
offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.proto),
624
offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.proto) },
625
{ "spi", OPT_BE32, NFC_FLAG_SPI,
626
offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.l4_4_bytes),
627
offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.l4_4_bytes) },
628
{ "src-port", OPT_BE16, NFC_FLAG_SPORT,
629
offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.l4_4_bytes),
630
offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.l4_4_bytes) },
631
{ "dst-port", OPT_BE16, NFC_FLAG_DPORT,
632
offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.l4_4_bytes) + 2,
633
offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.l4_4_bytes) + 2 },
634
{ "action", OPT_U64, NFC_FLAG_RING,
635
offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
636
{ "loc", OPT_U32, NFC_FLAG_LOC,
637
offsetof(struct ethtool_rx_flow_spec, location), -1 },
638
{ "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
639
offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
640
offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
641
{ "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
642
offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
643
offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
644
{ "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
645
offsetof(struct ethtool_rx_flow_spec, h_ext.data),
646
offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
649
static struct rule_opts rule_nfc_ether[] = {
650
{ "src", OPT_MAC, NFC_FLAG_SADDR,
651
offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_dest),
652
offsetof(struct ethtool_rx_flow_spec, m_u.ether_spec.h_dest) },
653
{ "dst", OPT_MAC, NFC_FLAG_DADDR,
654
offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_source),
655
offsetof(struct ethtool_rx_flow_spec, m_u.ether_spec.h_source) },
656
{ "proto", OPT_BE16, NFC_FLAG_PROTO,
657
offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_proto),
658
offsetof(struct ethtool_rx_flow_spec, m_u.ether_spec.h_proto) },
659
{ "action", OPT_U64, NFC_FLAG_RING,
660
offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
661
{ "loc", OPT_U32, NFC_FLAG_LOC,
662
offsetof(struct ethtool_rx_flow_spec, location), -1 },
663
{ "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
664
offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
665
offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
666
{ "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
667
offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
668
offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
669
{ "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
670
offsetof(struct ethtool_rx_flow_spec, h_ext.data),
671
offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
674
static int rxclass_get_long(char *str, long long *val, int size)
676
long long max = ~0ULL >> (65 - size);
681
*val = strtoll(str, &endp, 0);
683
if (*endp || errno || (*val > max) || (*val < ~max))
689
static int rxclass_get_ulong(char *str, unsigned long long *val, int size)
691
long long max = ~0ULL >> (64 - size);
696
*val = strtoull(str, &endp, 0);
698
if (*endp || errno || (*val > max))
704
static int rxclass_get_ipv4(char *str, __be32 *val)
706
if (!inet_pton(AF_INET, str, val))
712
static int rxclass_get_ether(char *str, unsigned char *val)
714
unsigned int buf[ETH_ALEN];
717
if (!strchr(str, ':'))
720
count = sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x",
721
&buf[0], &buf[1], &buf[2],
722
&buf[3], &buf[4], &buf[5]);
724
if (count != ETH_ALEN)
729
val[count] = buf[count];
735
static int rxclass_get_val(char *str, unsigned char *p, u32 *flags,
736
const struct rule_opts *opt)
738
unsigned long long mask = ~0ULL;
741
if (*flags & opt->flag)
749
err = rxclass_get_long(str, &val, 32);
752
*(int *)&p[opt->offset] = (int)val;
753
if (opt->moffset >= 0)
754
*(int *)&p[opt->moffset] = (int)mask;
758
unsigned long long val;
759
err = rxclass_get_ulong(str, &val, 8);
762
*(u8 *)&p[opt->offset] = (u8)val;
763
if (opt->moffset >= 0)
764
*(u8 *)&p[opt->moffset] = (u8)mask;
768
unsigned long long val;
769
err = rxclass_get_ulong(str, &val, 16);
772
*(u16 *)&p[opt->offset] = (u16)val;
773
if (opt->moffset >= 0)
774
*(u16 *)&p[opt->moffset] = (u16)mask;
778
unsigned long long val;
779
err = rxclass_get_ulong(str, &val, 32);
782
*(u32 *)&p[opt->offset] = (u32)val;
783
if (opt->moffset >= 0)
784
*(u32 *)&p[opt->moffset] = (u32)mask;
788
unsigned long long val;
789
err = rxclass_get_ulong(str, &val, 64);
792
*(u64 *)&p[opt->offset] = (u64)val;
793
if (opt->moffset >= 0)
794
*(u64 *)&p[opt->moffset] = (u64)mask;
798
unsigned long long val;
799
err = rxclass_get_ulong(str, &val, 16);
802
*(__be16 *)&p[opt->offset] = htons((u16)val);
803
if (opt->moffset >= 0)
804
*(__be16 *)&p[opt->moffset] = (__be16)mask;
808
unsigned long long val;
809
err = rxclass_get_ulong(str, &val, 32);
812
*(__be32 *)&p[opt->offset] = htonl((u32)val);
813
if (opt->moffset >= 0)
814
*(__be32 *)&p[opt->moffset] = (__be32)mask;
818
unsigned long long val;
819
err = rxclass_get_ulong(str, &val, 64);
822
*(__be64 *)&p[opt->offset] = htonll((u64)val);
823
if (opt->moffset >= 0)
824
*(__be64 *)&p[opt->moffset] = (__be64)mask;
829
err = rxclass_get_ipv4(str, &val);
832
*(__be32 *)&p[opt->offset] = val;
833
if (opt->moffset >= 0)
834
*(__be32 *)&p[opt->moffset] = (__be32)mask;
838
unsigned char val[ETH_ALEN];
839
err = rxclass_get_ether(str, val);
842
memcpy(&p[opt->offset], val, ETH_ALEN);
843
if (opt->moffset >= 0)
844
memcpy(&p[opt->moffset], &mask, ETH_ALEN);
855
static int rxclass_get_mask(char *str, unsigned char *p,
856
const struct rule_opts *opt)
860
if (opt->moffset < 0)
866
err = rxclass_get_long(str, &val, 32);
869
*(int *)&p[opt->moffset] = ~(int)val;
873
unsigned long long val;
874
err = rxclass_get_ulong(str, &val, 8);
877
*(u8 *)&p[opt->moffset] = ~(u8)val;
881
unsigned long long val;
882
err = rxclass_get_ulong(str, &val, 16);
885
*(u16 *)&p[opt->moffset] = ~(u16)val;
889
unsigned long long val;
890
err = rxclass_get_ulong(str, &val, 32);
893
*(u32 *)&p[opt->moffset] = ~(u32)val;
897
unsigned long long val;
898
err = rxclass_get_ulong(str, &val, 64);
901
*(u64 *)&p[opt->moffset] = ~(u64)val;
905
unsigned long long val;
906
err = rxclass_get_ulong(str, &val, 16);
909
*(__be16 *)&p[opt->moffset] = ~htons((u16)val);
913
unsigned long long val;
914
err = rxclass_get_ulong(str, &val, 32);
917
*(__be32 *)&p[opt->moffset] = ~htonl((u32)val);
921
unsigned long long val;
922
err = rxclass_get_ulong(str, &val, 64);
925
*(__be64 *)&p[opt->moffset] = ~htonll((u64)val);
930
err = rxclass_get_ipv4(str, &val);
933
*(__be32 *)&p[opt->moffset] = ~val;
937
unsigned char val[ETH_ALEN];
939
err = rxclass_get_ether(str, val);
943
for (i = 0; i < ETH_ALEN; i++)
946
memcpy(&p[opt->moffset], val, ETH_ALEN);
957
int rxclass_parse_ruleopts(char **argp, int argc,
958
struct ethtool_rx_flow_spec *fsp)
960
const struct rule_opts *options;
961
unsigned char *p = (unsigned char *)fsp;
962
int i = 0, n_opts, err;
969
if (!strcmp(argp[0], "tcp4"))
970
flow_type = TCP_V4_FLOW;
971
else if (!strcmp(argp[0], "udp4"))
972
flow_type = UDP_V4_FLOW;
973
else if (!strcmp(argp[0], "sctp4"))
974
flow_type = SCTP_V4_FLOW;
975
else if (!strcmp(argp[0], "ah4"))
976
flow_type = AH_V4_FLOW;
977
else if (!strcmp(argp[0], "esp4"))
978
flow_type = ESP_V4_FLOW;
979
else if (!strcmp(argp[0], "ip4"))
980
flow_type = IP_USER_FLOW;
981
else if (!strcmp(argp[0], "ether"))
982
flow_type = ETHER_FLOW;
990
options = rule_nfc_tcp_ip4;
991
n_opts = ARRAY_SIZE(rule_nfc_tcp_ip4);
995
options = rule_nfc_esp_ip4;
996
n_opts = ARRAY_SIZE(rule_nfc_esp_ip4);
999
options = rule_nfc_usr_ip4;
1000
n_opts = ARRAY_SIZE(rule_nfc_usr_ip4);
1003
options = rule_nfc_ether;
1004
n_opts = ARRAY_SIZE(rule_nfc_ether);
1007
fprintf(stderr, "Add rule, invalid rule type[%s]\n", argp[0]);
1011
memset(p, 0, sizeof(*fsp));
1012
fsp->flow_type = flow_type;
1013
fsp->location = RX_CLS_LOC_UNSPEC;
1015
for (i = 1; i < argc;) {
1016
const struct rule_opts *opt;
1018
for (opt = options, idx = 0; idx < n_opts; idx++, opt++) {
1021
if (strcmp(argp[i], opt->name))
1028
err = rxclass_get_val(argp[i], p, &flags, opt);
1030
fprintf(stderr, "Invalid %s value[%s]\n",
1031
opt->name, argp[i]);
1039
sprintf(mask_name, "%s-mask", opt->name);
1040
if (strcmp(argp[i], "m") && strcmp(argp[i], mask_name))
1047
err = rxclass_get_mask(argp[i], p, opt);
1049
fprintf(stderr, "Invalid %s mask[%s]\n",
1050
opt->name, argp[i]);
1058
if (idx == n_opts) {
1059
fprintf(stdout, "Add rule, unrecognized option[%s]\n",
1065
if (flags & (NTUPLE_FLAG_VLAN | NTUPLE_FLAG_UDEF | NTUPLE_FLAG_VETH))
1066
fsp->flow_type |= FLOW_EXT;
1071
fprintf(stderr, "Add rule, invalid syntax\n");