~ubuntu-branches/ubuntu/trusty/ethtool/trusty-proposed

« back to all changes in this revision

Viewing changes to rxclass.c

  • Committer: Bazaar Package Importer
  • Author(s): Ben Hutchings
  • Date: 2011-06-04 21:55:17 UTC
  • mto: This revision was merged to the branch mainline in revision 16.
  • Revision ID: james.westby@ubuntu.com-20110604215517-rfbyqdpqphnp2vt7
Tags: upstream-2.6.39
ImportĀ upstreamĀ versionĀ 2.6.39

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "ethtool-util.h"
 
14
#include "ethtool-bitops.h"
 
15
 
 
16
static void invert_flow_mask(struct ethtool_rx_flow_spec *fsp)
 
17
{
 
18
        size_t i;
 
19
 
 
20
        for (i = 0; i < sizeof(fsp->m_u); i++)
 
21
                fsp->m_u.hdata[i] ^= 0xFF;
 
22
}
 
23
 
 
24
static void rxclass_print_ipv4_rule(__be32 sip, __be32 sipm, __be32 dip,
 
25
                                    __be32 dipm, u8 tos, u8 tosm)
 
26
{
 
27
        char sip_str[INET_ADDRSTRLEN];
 
28
        char sipm_str[INET_ADDRSTRLEN];
 
29
        char dip_str[INET_ADDRSTRLEN];
 
30
        char dipm_str[INET_ADDRSTRLEN];
 
31
 
 
32
        fprintf(stdout,
 
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),
 
40
                tos, tosm);
 
41
}
 
42
 
 
43
static void rxclass_print_nfc_spec_ext(struct ethtool_rx_flow_spec *fsp)
 
44
{
 
45
        u64 data, datam;
 
46
        __u16 etype, etypem, tci, tcim;
 
47
 
 
48
        if (!(fsp->flow_type & FLOW_EXT))
 
49
                return;
 
50
 
 
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]);
 
59
 
 
60
        fprintf(stdout,
 
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);
 
65
}
 
66
 
 
67
static void rxclass_print_nfc_rule(struct ethtool_rx_flow_spec *fsp)
 
68
{
 
69
        unsigned char   *smac, *smacm, *dmac, *dmacm;
 
70
        __u32           flow_type;
 
71
 
 
72
        if (fsp->location != RX_CLS_LOC_UNSPEC)
 
73
                fprintf(stdout, "Filter: %d\n", fsp->location);
 
74
        else
 
75
                fprintf(stdout, "Filter: Unspecified\n");
 
76
 
 
77
        flow_type = fsp->flow_type & ~FLOW_EXT;
 
78
 
 
79
        invert_flow_mask(fsp);
 
80
 
 
81
        switch (flow_type) {
 
82
        case TCP_V4_FLOW:
 
83
        case UDP_V4_FLOW:
 
84
        case SCTP_V4_FLOW:
 
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");
 
89
                else
 
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);
 
97
                fprintf(stdout,
 
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));
 
104
                break;
 
105
        case AH_V4_FLOW:
 
106
        case ESP_V4_FLOW:
 
107
                if (flow_type == AH_V4_FLOW)
 
108
                        fprintf(stdout, "\tRule Type: IPSEC AH over IPv4\n");
 
109
                else
 
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);
 
117
                fprintf(stdout,
 
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));
 
121
                break;
 
122
        case IP_USER_FLOW:
 
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);
 
130
                fprintf(stdout,
 
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));
 
137
                break;
 
138
        case ETHER_FLOW:
 
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;
 
143
 
 
144
                fprintf(stdout,
 
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],
 
155
                        dmacm[4], dmacm[5],
 
156
                        ntohs(fsp->h_u.ether_spec.h_proto),
 
157
                        ntohs(fsp->m_u.ether_spec.h_proto));
 
158
                break;
 
159
        default:
 
160
                fprintf(stdout,
 
161
                        "\tUnknown Flow type: %d\n", flow_type);
 
162
                break;
 
163
        }
 
164
 
 
165
        rxclass_print_nfc_spec_ext(fsp);
 
166
 
 
167
        if (fsp->ring_cookie != RX_CLS_FLOW_DISC)
 
168
                fprintf(stdout, "\tAction: Direct to queue %llu\n",
 
169
                        fsp->ring_cookie);
 
170
        else
 
171
                fprintf(stdout, "\tAction: Drop\n");
 
172
 
 
173
        fprintf(stdout, "\n");
 
174
}
 
175
 
 
176
static void rxclass_print_rule(struct ethtool_rx_flow_spec *fsp)
 
177
{
 
178
        /* print the rule in this location */
 
179
        switch (fsp->flow_type & ~FLOW_EXT) {
 
180
        case TCP_V4_FLOW:
 
181
        case UDP_V4_FLOW:
 
182
        case SCTP_V4_FLOW:
 
183
        case AH_V4_FLOW:
 
184
        case ESP_V4_FLOW:
 
185
        case ETHER_FLOW:
 
186
                rxclass_print_nfc_rule(fsp);
 
187
                break;
 
188
        case IP_USER_FLOW:
 
189
                if (fsp->h_u.usr_ip4_spec.ip_ver == ETH_RX_NFC_IP4) {
 
190
                        rxclass_print_nfc_rule(fsp);
 
191
                        break;
 
192
                }
 
193
                /* IPv6 User Flow falls through to the case below */
 
194
        case TCP_V6_FLOW:
 
195
        case UDP_V6_FLOW:
 
196
        case SCTP_V6_FLOW:
 
197
        case AH_V6_FLOW:
 
198
        case ESP_V6_FLOW:
 
199
                fprintf(stderr, "IPv6 flows not implemented\n");
 
200
                break;
 
201
        default:
 
202
                fprintf(stderr, "rxclass: Unknown flow type\n");
 
203
                break;
 
204
        }
 
205
}
 
206
 
 
207
static int rxclass_get_count(int fd, struct ifreq *ifr, __u32 *count)
 
208
{
 
209
        struct ethtool_rxnfc nfccmd;
 
210
        int err;
 
211
 
 
212
        /* request count and store */
 
213
        nfccmd.cmd = ETHTOOL_GRXCLSRLCNT;
 
214
        nfccmd.rule_cnt = 0;
 
215
        ifr->ifr_data = (caddr_t)&nfccmd;
 
216
        err = ioctl(fd, SIOCETHTOOL, ifr);
 
217
        *count = nfccmd.rule_cnt;
 
218
        if (err < 0)
 
219
                perror("rxclass: Cannot get RX class rule count");
 
220
 
 
221
        return err;
 
222
}
 
223
 
 
224
int rxclass_rule_get(int fd, struct ifreq *ifr, __u32 loc)
 
225
{
 
226
        struct ethtool_rxnfc nfccmd;
 
227
        int err;
 
228
 
 
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);
 
235
        if (err < 0) {
 
236
                perror("rxclass: Cannot get RX class rule");
 
237
                return err;
 
238
        }
 
239
 
 
240
        /* display rule */
 
241
        rxclass_print_rule(&nfccmd.fs);
 
242
        return err;
 
243
}
 
244
 
 
245
int rxclass_rule_getall(int fd, struct ifreq *ifr)
 
246
{
 
247
        struct ethtool_rxnfc *nfccmd;
 
248
        __u32 *rule_locs;
 
249
        int err, i;
 
250
        __u32 count;
 
251
 
 
252
        /* determine rule count */
 
253
        err = rxclass_get_count(fd, ifr, &count);
 
254
        if (err < 0)
 
255
                return err;
 
256
 
 
257
        fprintf(stdout, "Total %d rules\n\n", count);
 
258
 
 
259
        /* alloc memory for request of location list */
 
260
        nfccmd = calloc(1, sizeof(*nfccmd) + (count * sizeof(__u32)));
 
261
        if (!nfccmd) {
 
262
                perror("rxclass: Cannot allocate memory for"
 
263
                       " RX class rule locations");
 
264
                return -ENOMEM;
 
265
        }
 
266
 
 
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);
 
272
        if (err < 0) {
 
273
                perror("rxclass: Cannot get RX class rules");
 
274
                free(nfccmd);
 
275
                return err;
 
276
        }
 
277
 
 
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]);
 
282
                if (err < 0)
 
283
                        break;
 
284
        }
 
285
 
 
286
        /* free memory and set flag to avoid reinit */
 
287
        free(nfccmd);
 
288
 
 
289
        return err;
 
290
}
 
291
 
 
292
/*
 
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.
 
297
 */
 
298
 
 
299
struct rmgr_ctrl {
 
300
        /* slot contains a bitmap indicating which filters are valid */
 
301
        unsigned long           *slot;
 
302
        __u32                   n_rules;
 
303
        __u32                   size;
 
304
};
 
305
 
 
306
static struct rmgr_ctrl rmgr;
 
307
static int rmgr_init_done = 0;
 
308
 
 
309
static int rmgr_ins(__u32 loc)
 
310
{
 
311
        /* verify location is in rule manager range */
 
312
        if (loc >= rmgr.size) {
 
313
                fprintf(stderr, "rmgr: Location out of range\n");
 
314
                return -1;
 
315
        }
 
316
 
 
317
        /* set bit for the rule */
 
318
        set_bit(loc, rmgr.slot);
 
319
 
 
320
        return 0;
 
321
}
 
322
 
 
323
static int rmgr_find_empty_slot(struct ethtool_rx_flow_spec *fsp)
 
324
{
 
325
        __u32 loc;
 
326
        __u32 slot_num;
 
327
 
 
328
        /* start at the end of the list since it is lowest priority */
 
329
        loc = rmgr.size - 1;
 
330
 
 
331
        /* locate the first slot a rule can be placed in */
 
332
        slot_num = loc / BITS_PER_LONG;
 
333
 
 
334
        /*
 
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.
 
339
         *
 
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.
 
342
         */
 
343
        if (!~(rmgr.slot[slot_num] | (~1UL << rmgr.size % BITS_PER_LONG))) {
 
344
                loc -= 1 + (loc % BITS_PER_LONG);
 
345
                slot_num--;
 
346
        }
 
347
 
 
348
        /*
 
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
 
351
         */
 
352
        while (loc < rmgr.size && !~(rmgr.slot[slot_num])) {
 
353
                loc -= BITS_PER_LONG;
 
354
                slot_num--;
 
355
        }
 
356
 
 
357
        /*
 
358
         * If we still are inside the range, test individual bits as one is
 
359
         * likely available for our use.
 
360
         */
 
361
        while (loc < rmgr.size && test_bit(loc, rmgr.slot))
 
362
                loc--;
 
363
 
 
364
        /* location found, insert rule */
 
365
        if (loc < rmgr.size) {
 
366
                fsp->location = loc;
 
367
                return rmgr_ins(loc);
 
368
        }
 
369
 
 
370
        /* No space to add this rule */
 
371
        fprintf(stderr, "rmgr: Cannot find appropriate slot to insert rule\n");
 
372
 
 
373
        return -1;
 
374
}
 
375
 
 
376
static int rmgr_init(int fd, struct ifreq *ifr)
 
377
{
 
378
        struct ethtool_rxnfc *nfccmd;
 
379
        int err, i;
 
380
        __u32 *rule_locs;
 
381
 
 
382
        if (rmgr_init_done)
 
383
                return 0;
 
384
 
 
385
        /* clear rule manager settings */
 
386
        memset(&rmgr, 0, sizeof(struct rmgr_ctrl));
 
387
 
 
388
        /* request count and store in rmgr.n_rules */
 
389
        err = rxclass_get_count(fd, ifr, &rmgr.n_rules);
 
390
        if (err < 0)
 
391
                return err;
 
392
 
 
393
        /* alloc memory for request of location list */
 
394
        nfccmd = calloc(1, sizeof(*nfccmd) + (rmgr.n_rules * sizeof(__u32)));
 
395
        if (!nfccmd) {
 
396
                perror("rmgr: Cannot allocate memory for"
 
397
                       " RX class rule locations");
 
398
                return -1;
 
399
        }
 
400
 
 
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);
 
406
        if (err < 0) {
 
407
                perror("rmgr: Cannot get RX class rules");
 
408
                free(nfccmd);
 
409
                return err;
 
410
        }
 
411
 
 
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");
 
416
                return -1;
 
417
        }
 
418
 
 
419
        /* initialize bitmap for storage of valid locations */
 
420
        rmgr.slot = calloc(1, BITS_TO_LONGS(rmgr.size) * sizeof(long));
 
421
        if (!rmgr.slot) {
 
422
                perror("rmgr: Cannot allocate memory for RX class rules");
 
423
                return -1;
 
424
        }
 
425
 
 
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]);
 
430
                if (err < 0)
 
431
                        break;
 
432
        }
 
433
 
 
434
        /* free memory and set flag to avoid reinit */
 
435
        free(nfccmd);
 
436
        rmgr_init_done = 1;
 
437
 
 
438
        return err;
 
439
}
 
440
 
 
441
static void rmgr_cleanup(void)
 
442
{
 
443
        if (!rmgr_init_done)
 
444
                return;
 
445
 
 
446
        rmgr_init_done = 0;
 
447
 
 
448
        free(rmgr.slot);
 
449
        rmgr.slot = NULL;
 
450
        rmgr.size = 0;
 
451
}
 
452
 
 
453
static int rmgr_set_location(int fd, struct ifreq *ifr,
 
454
                             struct ethtool_rx_flow_spec *fsp)
 
455
{
 
456
        int err;
 
457
 
 
458
        /* init table of available rules */
 
459
        err = rmgr_init(fd, ifr);
 
460
        if (err < 0)
 
461
                return err;
 
462
 
 
463
        /* verify rule location */
 
464
        err = rmgr_find_empty_slot(fsp);
 
465
 
 
466
        /* cleanup table and free resources */
 
467
        rmgr_cleanup();
 
468
 
 
469
        return err;
 
470
}
 
471
 
 
472
int rxclass_rule_ins(int fd, struct ifreq *ifr,
 
473
                     struct ethtool_rx_flow_spec *fsp)
 
474
{
 
475
        struct ethtool_rxnfc nfccmd;
 
476
        __u32 loc = fsp->location;
 
477
        int err;
 
478
 
 
479
        /*
 
480
         * if location is unspecified pull rules from device
 
481
         * and allocate a free rule for our use
 
482
         */
 
483
        if (loc == RX_CLS_LOC_UNSPEC) {
 
484
                err = rmgr_set_location(fd, ifr, fsp);
 
485
                if (err < 0)
 
486
                        return err;
 
487
        }
 
488
 
 
489
        /* notify netdev of new rule */
 
490
        nfccmd.cmd = ETHTOOL_SRXCLSRLINS;
 
491
        nfccmd.fs = *fsp;
 
492
        ifr->ifr_data = (caddr_t)&nfccmd;
 
493
        err = ioctl(fd, SIOCETHTOOL, ifr);
 
494
        if (err < 0)
 
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);
 
498
 
 
499
        return 0;
 
500
}
 
501
 
 
502
int rxclass_rule_del(int fd, struct ifreq *ifr, __u32 loc)
 
503
{
 
504
        struct ethtool_rxnfc nfccmd;
 
505
        int err;
 
506
 
 
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);
 
512
        if (err < 0)
 
513
                perror("rmgr: Cannot delete RX class rule");
 
514
 
 
515
        return err;
 
516
}
 
517
 
 
518
typedef enum {
 
519
        OPT_NONE = 0,
 
520
        OPT_S32,
 
521
        OPT_U8,
 
522
        OPT_U16,
 
523
        OPT_U32,
 
524
        OPT_U64,
 
525
        OPT_BE16,
 
526
        OPT_BE32,
 
527
        OPT_BE64,
 
528
        OPT_IP4,
 
529
        OPT_MAC,
 
530
} rule_opt_type_t;
 
531
 
 
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
 
544
 
 
545
struct rule_opts {
 
546
        const char      *name;
 
547
        rule_opt_type_t type;
 
548
        u32             flag;
 
549
        int             offset;
 
550
        int             moffset;
 
551
};
 
552
 
 
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) },
 
582
};
 
583
 
 
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) },
 
610
};
 
611
 
 
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) },
 
647
};
 
648
 
 
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) },
 
672
};
 
673
 
 
674
static int rxclass_get_long(char *str, long long *val, int size)
 
675
{
 
676
        long long max = ~0ULL >> (65 - size);
 
677
        char *endp;
 
678
 
 
679
        errno = 0;
 
680
 
 
681
        *val = strtoll(str, &endp, 0);
 
682
 
 
683
        if (*endp || errno || (*val > max) || (*val < ~max))
 
684
                return -1;
 
685
 
 
686
        return 0;
 
687
}
 
688
 
 
689
static int rxclass_get_ulong(char *str, unsigned long long *val, int size)
 
690
{
 
691
        long long max = ~0ULL >> (64 - size);
 
692
        char *endp;
 
693
 
 
694
        errno = 0;
 
695
 
 
696
        *val = strtoull(str, &endp, 0);
 
697
 
 
698
        if (*endp || errno || (*val > max))
 
699
                return -1;
 
700
 
 
701
        return 0;
 
702
}
 
703
 
 
704
static int rxclass_get_ipv4(char *str, __be32 *val)
 
705
{
 
706
        if (!inet_pton(AF_INET, str, val))
 
707
                return -1;
 
708
 
 
709
        return 0;
 
710
}
 
711
 
 
712
static int rxclass_get_ether(char *str, unsigned char *val)
 
713
{
 
714
        unsigned int buf[ETH_ALEN];
 
715
        int count;
 
716
 
 
717
        if (!strchr(str, ':'))
 
718
                return -1;
 
719
 
 
720
        count = sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x",
 
721
                       &buf[0], &buf[1], &buf[2],
 
722
                       &buf[3], &buf[4], &buf[5]);
 
723
 
 
724
        if (count != ETH_ALEN)
 
725
                return -1;
 
726
 
 
727
        do {
 
728
                count--;
 
729
                val[count] = buf[count];
 
730
        } while (count);
 
731
 
 
732
        return 0;
 
733
}
 
734
 
 
735
static int rxclass_get_val(char *str, unsigned char *p, u32 *flags,
 
736
                           const struct rule_opts *opt)
 
737
{
 
738
        unsigned long long mask = ~0ULL;
 
739
        int err = 0;
 
740
 
 
741
        if (*flags & opt->flag)
 
742
                return -1;
 
743
 
 
744
        *flags |= opt->flag;
 
745
 
 
746
        switch (opt->type) {
 
747
        case OPT_S32: {
 
748
                long long val;
 
749
                err = rxclass_get_long(str, &val, 32);
 
750
                if (err)
 
751
                        return -1;
 
752
                *(int *)&p[opt->offset] = (int)val;
 
753
                if (opt->moffset >= 0)
 
754
                        *(int *)&p[opt->moffset] = (int)mask;
 
755
                break;
 
756
        }
 
757
        case OPT_U8: {
 
758
                unsigned long long val;
 
759
                err = rxclass_get_ulong(str, &val, 8);
 
760
                if (err)
 
761
                        return -1;
 
762
                *(u8 *)&p[opt->offset] = (u8)val;
 
763
                if (opt->moffset >= 0)
 
764
                        *(u8 *)&p[opt->moffset] = (u8)mask;
 
765
                break;
 
766
        }
 
767
        case OPT_U16: {
 
768
                unsigned long long val;
 
769
                err = rxclass_get_ulong(str, &val, 16);
 
770
                if (err)
 
771
                        return -1;
 
772
                *(u16 *)&p[opt->offset] = (u16)val;
 
773
                if (opt->moffset >= 0)
 
774
                        *(u16 *)&p[opt->moffset] = (u16)mask;
 
775
                break;
 
776
        }
 
777
        case OPT_U32: {
 
778
                unsigned long long val;
 
779
                err = rxclass_get_ulong(str, &val, 32);
 
780
                if (err)
 
781
                        return -1;
 
782
                *(u32 *)&p[opt->offset] = (u32)val;
 
783
                if (opt->moffset >= 0)
 
784
                        *(u32 *)&p[opt->moffset] = (u32)mask;
 
785
                break;
 
786
        }
 
787
        case OPT_U64: {
 
788
                unsigned long long val;
 
789
                err = rxclass_get_ulong(str, &val, 64);
 
790
                if (err)
 
791
                        return -1;
 
792
                *(u64 *)&p[opt->offset] = (u64)val;
 
793
                if (opt->moffset >= 0)
 
794
                        *(u64 *)&p[opt->moffset] = (u64)mask;
 
795
                break;
 
796
        }
 
797
        case OPT_BE16: {
 
798
                unsigned long long val;
 
799
                err = rxclass_get_ulong(str, &val, 16);
 
800
                if (err)
 
801
                        return -1;
 
802
                *(__be16 *)&p[opt->offset] = htons((u16)val);
 
803
                if (opt->moffset >= 0)
 
804
                        *(__be16 *)&p[opt->moffset] = (__be16)mask;
 
805
                break;
 
806
        }
 
807
        case OPT_BE32: {
 
808
                unsigned long long val;
 
809
                err = rxclass_get_ulong(str, &val, 32);
 
810
                if (err)
 
811
                        return -1;
 
812
                *(__be32 *)&p[opt->offset] = htonl((u32)val);
 
813
                if (opt->moffset >= 0)
 
814
                        *(__be32 *)&p[opt->moffset] = (__be32)mask;
 
815
                break;
 
816
        }
 
817
        case OPT_BE64: {
 
818
                unsigned long long val;
 
819
                err = rxclass_get_ulong(str, &val, 64);
 
820
                if (err)
 
821
                        return -1;
 
822
                *(__be64 *)&p[opt->offset] = htonll((u64)val);
 
823
                if (opt->moffset >= 0)
 
824
                        *(__be64 *)&p[opt->moffset] = (__be64)mask;
 
825
                break;
 
826
        }
 
827
        case OPT_IP4: {
 
828
                __be32 val;
 
829
                err = rxclass_get_ipv4(str, &val);
 
830
                if (err)
 
831
                        return -1;
 
832
                *(__be32 *)&p[opt->offset] = val;
 
833
                if (opt->moffset >= 0)
 
834
                        *(__be32 *)&p[opt->moffset] = (__be32)mask;
 
835
                break;
 
836
        }
 
837
        case OPT_MAC: {
 
838
                unsigned char val[ETH_ALEN];
 
839
                err = rxclass_get_ether(str, val);
 
840
                if (err)
 
841
                        return -1;
 
842
                memcpy(&p[opt->offset], val, ETH_ALEN);
 
843
                if (opt->moffset >= 0)
 
844
                        memcpy(&p[opt->moffset], &mask, ETH_ALEN);
 
845
                break;
 
846
        }
 
847
        case OPT_NONE:
 
848
        default:
 
849
                return -1;
 
850
        }
 
851
 
 
852
        return 0;
 
853
}
 
854
 
 
855
static int rxclass_get_mask(char *str, unsigned char *p,
 
856
                            const struct rule_opts *opt)
 
857
{
 
858
        int err = 0;
 
859
 
 
860
        if (opt->moffset < 0)
 
861
                return -1;
 
862
 
 
863
        switch (opt->type) {
 
864
        case OPT_S32: {
 
865
                long long val;
 
866
                err = rxclass_get_long(str, &val, 32);
 
867
                if (err)
 
868
                        return -1;
 
869
                *(int *)&p[opt->moffset] = ~(int)val;
 
870
                break;
 
871
        }
 
872
        case OPT_U8: {
 
873
                unsigned long long val;
 
874
                err = rxclass_get_ulong(str, &val, 8);
 
875
                if (err)
 
876
                        return -1;
 
877
                *(u8 *)&p[opt->moffset] = ~(u8)val;
 
878
                break;
 
879
        }
 
880
        case OPT_U16: {
 
881
                unsigned long long val;
 
882
                err = rxclass_get_ulong(str, &val, 16);
 
883
                if (err)
 
884
                        return -1;
 
885
                *(u16 *)&p[opt->moffset] = ~(u16)val;
 
886
                break;
 
887
        }
 
888
        case OPT_U32: {
 
889
                unsigned long long val;
 
890
                err = rxclass_get_ulong(str, &val, 32);
 
891
                if (err)
 
892
                        return -1;
 
893
                *(u32 *)&p[opt->moffset] = ~(u32)val;
 
894
                break;
 
895
        }
 
896
        case OPT_U64: {
 
897
                unsigned long long val;
 
898
                err = rxclass_get_ulong(str, &val, 64);
 
899
                if (err)
 
900
                        return -1;
 
901
                *(u64 *)&p[opt->moffset] = ~(u64)val;
 
902
                break;
 
903
        }
 
904
        case OPT_BE16: {
 
905
                unsigned long long val;
 
906
                err = rxclass_get_ulong(str, &val, 16);
 
907
                if (err)
 
908
                        return -1;
 
909
                *(__be16 *)&p[opt->moffset] = ~htons((u16)val);
 
910
                break;
 
911
        }
 
912
        case OPT_BE32: {
 
913
                unsigned long long val;
 
914
                err = rxclass_get_ulong(str, &val, 32);
 
915
                if (err)
 
916
                        return -1;
 
917
                *(__be32 *)&p[opt->moffset] = ~htonl((u32)val);
 
918
                break;
 
919
        }
 
920
        case OPT_BE64: {
 
921
                unsigned long long val;
 
922
                err = rxclass_get_ulong(str, &val, 64);
 
923
                if (err)
 
924
                        return -1;
 
925
                *(__be64 *)&p[opt->moffset] = ~htonll((u64)val);
 
926
                break;
 
927
        }
 
928
        case OPT_IP4: {
 
929
                __be32 val;
 
930
                err = rxclass_get_ipv4(str, &val);
 
931
                if (err)
 
932
                        return -1;
 
933
                *(__be32 *)&p[opt->moffset] = ~val;
 
934
                break;
 
935
        }
 
936
        case OPT_MAC: {
 
937
                unsigned char val[ETH_ALEN];
 
938
                int i;
 
939
                err = rxclass_get_ether(str, val);
 
940
                if (err)
 
941
                        return -1;
 
942
 
 
943
                for (i = 0; i < ETH_ALEN; i++)
 
944
                        val[i] = ~val[i];
 
945
 
 
946
                memcpy(&p[opt->moffset], val, ETH_ALEN);
 
947
                break;
 
948
        }
 
949
        case OPT_NONE:
 
950
        default:
 
951
                return -1;
 
952
        }
 
953
 
 
954
        return 0;
 
955
}
 
956
 
 
957
int rxclass_parse_ruleopts(char **argp, int argc,
 
958
                           struct ethtool_rx_flow_spec *fsp)
 
959
{
 
960
        const struct rule_opts *options;
 
961
        unsigned char *p = (unsigned char *)fsp;
 
962
        int i = 0, n_opts, err;
 
963
        u32 flags = 0;
 
964
        int flow_type;
 
965
 
 
966
        if (argc < 1)
 
967
                goto syntax_err;
 
968
 
 
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;
 
983
        else
 
984
                goto syntax_err;
 
985
 
 
986
        switch (flow_type) {
 
987
        case TCP_V4_FLOW:
 
988
        case UDP_V4_FLOW:
 
989
        case SCTP_V4_FLOW:
 
990
                options = rule_nfc_tcp_ip4;
 
991
                n_opts = ARRAY_SIZE(rule_nfc_tcp_ip4);
 
992
                break;
 
993
        case AH_V4_FLOW:
 
994
        case ESP_V4_FLOW:
 
995
                options = rule_nfc_esp_ip4;
 
996
                n_opts = ARRAY_SIZE(rule_nfc_esp_ip4);
 
997
                break;
 
998
        case IP_USER_FLOW:
 
999
                options = rule_nfc_usr_ip4;
 
1000
                n_opts = ARRAY_SIZE(rule_nfc_usr_ip4);
 
1001
                break;
 
1002
        case ETHER_FLOW:
 
1003
                options = rule_nfc_ether;
 
1004
                n_opts = ARRAY_SIZE(rule_nfc_ether);
 
1005
                break;
 
1006
        default:
 
1007
                fprintf(stderr, "Add rule, invalid rule type[%s]\n", argp[0]);
 
1008
                return -1;
 
1009
        }
 
1010
 
 
1011
        memset(p, 0, sizeof(*fsp));
 
1012
        fsp->flow_type = flow_type;
 
1013
        fsp->location = RX_CLS_LOC_UNSPEC;
 
1014
 
 
1015
        for (i = 1; i < argc;) {
 
1016
                const struct rule_opts *opt;
 
1017
                int idx;
 
1018
                for (opt = options, idx = 0; idx < n_opts; idx++, opt++) {
 
1019
                        char mask_name[16];
 
1020
 
 
1021
                        if (strcmp(argp[i], opt->name))
 
1022
                                continue;
 
1023
 
 
1024
                        i++;
 
1025
                        if (i >= argc)
 
1026
                                break;
 
1027
 
 
1028
                        err = rxclass_get_val(argp[i], p, &flags, opt);
 
1029
                        if (err) {
 
1030
                                fprintf(stderr, "Invalid %s value[%s]\n",
 
1031
                                        opt->name, argp[i]);
 
1032
                                return -1;
 
1033
                        }
 
1034
 
 
1035
                        i++;
 
1036
                        if (i >= argc)
 
1037
                                break;
 
1038
 
 
1039
                        sprintf(mask_name, "%s-mask", opt->name);
 
1040
                        if (strcmp(argp[i], "m") && strcmp(argp[i], mask_name))
 
1041
                                break;
 
1042
 
 
1043
                        i++;
 
1044
                        if (i >= argc)
 
1045
                                goto syntax_err;
 
1046
 
 
1047
                        err = rxclass_get_mask(argp[i], p, opt);
 
1048
                        if (err) {
 
1049
                                fprintf(stderr, "Invalid %s mask[%s]\n",
 
1050
                                        opt->name, argp[i]);
 
1051
                                return -1;
 
1052
                        }
 
1053
 
 
1054
                        i++;
 
1055
 
 
1056
                        break;
 
1057
                }
 
1058
                if (idx == n_opts) {
 
1059
                        fprintf(stdout, "Add rule, unrecognized option[%s]\n",
 
1060
                                argp[i]);
 
1061
                        return -1;
 
1062
                }
 
1063
        }
 
1064
 
 
1065
        if (flags & (NTUPLE_FLAG_VLAN | NTUPLE_FLAG_UDEF | NTUPLE_FLAG_VETH))
 
1066
                fsp->flow_type |= FLOW_EXT;
 
1067
 
 
1068
        return 0;
 
1069
 
 
1070
syntax_err:
 
1071
        fprintf(stderr, "Add rule, invalid syntax\n");
 
1072
        return -1;
 
1073
}