~ubuntu-branches/ubuntu/hardy/iproute/hardy-proposed

« back to all changes in this revision

Viewing changes to tc/em_meta.c

  • Committer: Bazaar Package Importer
  • Author(s): Scott James Remnant
  • Date: 2006-07-06 10:23:46 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060706102346-tyd1mfjvay0nmz90
Tags: 20051007-4ubuntu1
* Merge from debian unstable, remaining changes:
  - versioned dependency on linux-kernel-headers,
  - MAX_ROUNDS patch to ip/ipaddress.c

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * em_meta.c            Metadata Ematch
 
3
 *
 
4
 *              This program is free software; you can distribute it and/or
 
5
 *              modify it under the terms of the GNU General Public License
 
6
 *              as published by the Free Software Foundation; either version
 
7
 *              2 of the License, or (at your option) any later version.
 
8
 *
 
9
 * Authors:     Thomas Graf <tgraf@suug.ch>
 
10
 */
 
11
 
 
12
#include <stdio.h>
 
13
#include <stdlib.h>
 
14
#include <unistd.h>
 
15
#include <syslog.h>
 
16
#include <fcntl.h>
 
17
#include <sys/socket.h>
 
18
#include <netinet/in.h>
 
19
#include <arpa/inet.h>
 
20
#include <string.h>
 
21
#include <dlfcn.h>
 
22
#include <errno.h>
 
23
 
 
24
#include "m_ematch.h"
 
25
#include <linux/tc_ematch/tc_em_meta.h>
 
26
 
 
27
extern struct ematch_util meta_ematch_util;
 
28
 
 
29
static void meta_print_usage(FILE *fd)
 
30
{
 
31
        fprintf(fd,
 
32
            "Usage: meta(OBJECT { eq | lt | gt } OBJECT)\n" \
 
33
            "where: OBJECT  := { META_ID | VALUE }\n" \
 
34
            "       META_ID := id [ shift SHIFT ] [ mask MASK ]\n" \
 
35
            "\n" \
 
36
            "Example: meta(nfmark gt 24)\n" \
 
37
            "         meta(indev shift 1 eq \"ppp\"\n" \
 
38
            "         meta(tcindex mask 0xf0 eq 0xf0)\n" \
 
39
            "         meta(dev eq indev)\n" \
 
40
            "\n" \
 
41
            "For a list of meta identifiers, use meta(list).\n");
 
42
}
 
43
 
 
44
struct meta_entry {
 
45
        int             id;
 
46
        char *          kind;
 
47
        char *          mask;
 
48
        char *          desc;
 
49
} meta_table[] = {
 
50
#define TCF_META_ID_SECTION 0
 
51
#define __A(id, name, mask, desc) { TCF_META_ID_##id, name, mask, desc }
 
52
        __A(SECTION,            "Generic", "", ""),
 
53
        __A(RANDOM,             "random",       "i",
 
54
                                "Random value (32 bit)"),
 
55
        __A(LOADAVG_0,          "loadavg_1",    "i",
 
56
                                "Load average in last minute"),
 
57
        __A(LOADAVG_1,          "loadavg_5",    "i",
 
58
                                "Load average in last 5 minutes"),
 
59
        __A(LOADAVG_2,          "loadavg_15",   "i",
 
60
                                "Load average in last 15 minutes"),
 
61
 
 
62
        __A(SECTION,            "Interfaces", "", ""),
 
63
        __A(DEV,                "dev",          "iv",
 
64
                                "Device the packet is on"),
 
65
        __A(SECTION,            "Packet attributes", "", ""),
 
66
        __A(PRIORITY,           "priority",     "i",
 
67
                                "Priority of packet"),
 
68
        __A(PROTOCOL,           "protocol",     "i",
 
69
                                "Link layer protocol"),
 
70
        __A(PKTTYPE,            "pkt_type",     "i",
 
71
                                "Packet type (uni|multi|broad|...)cast"),
 
72
        __A(PKTLEN,             "pkt_len",      "i",
 
73
                                "Length of packet"),
 
74
        __A(DATALEN,            "data_len",     "i",
 
75
                                "Length of data in packet"),
 
76
        __A(MACLEN,             "mac_len",      "i",
 
77
                                "Length of link layer header"),
 
78
 
 
79
        __A(SECTION,            "Netfilter", "", ""),
 
80
        __A(NFMARK,             "nf_mark",      "i",
 
81
                                "Netfilter mark"),
 
82
        __A(NFMARK,             "fwmark",       "i",
 
83
                                "Alias for nf_mark"),
 
84
 
 
85
        __A(SECTION,            "Traffic Control", "", ""),
 
86
        __A(TCINDEX,            "tc_index",     "i",    "TC Index"),
 
87
        __A(SECTION,            "Routing", "", ""),
 
88
        __A(RTCLASSID,          "rt_classid",   "i",
 
89
                                "Routing ClassID (cls_route)"),
 
90
        __A(RTIIF,              "rt_iif",       "i",
 
91
                                "Incoming interface index"),
 
92
 
 
93
        __A(SECTION,            "Sockets", "", ""),
 
94
        __A(SK_FAMILY,          "sk_family",    "i",    "Address family"),
 
95
        __A(SK_STATE,           "sk_state",     "i",    "State"),
 
96
        __A(SK_REUSE,           "sk_reuse",     "i",    "Reuse Flag"),
 
97
        __A(SK_BOUND_IF,        "sk_bind_if",   "iv",   "Bound interface"),
 
98
        __A(SK_REFCNT,          "sk_refcnt",    "i",    "Reference counter"),
 
99
        __A(SK_SHUTDOWN,        "sk_shutdown",  "i",    "Shutdown mask"),
 
100
        __A(SK_PROTO,           "sk_proto",     "i",    "Protocol"),
 
101
        __A(SK_TYPE,            "sk_type",      "i",    "Type"),
 
102
        __A(SK_RCVBUF,          "sk_rcvbuf",    "i",    "Receive buffer size"),
 
103
        __A(SK_RMEM_ALLOC,      "sk_rmem",      "i",    "RMEM"),
 
104
        __A(SK_WMEM_ALLOC,      "sk_wmem",      "i",    "WMEM"),
 
105
        __A(SK_OMEM_ALLOC,      "sk_omem",      "i",    "OMEM"),
 
106
        __A(SK_WMEM_QUEUED,     "sk_wmem_queue","i",    "WMEM queue"),
 
107
        __A(SK_SND_QLEN,        "sk_snd_queue", "i",    "Send queue length"),
 
108
        __A(SK_RCV_QLEN,        "sk_rcv_queue", "i",    "Receive queue length"),
 
109
        __A(SK_ERR_QLEN,        "sk_err_queue", "i",    "Error queue length"),
 
110
        __A(SK_FORWARD_ALLOCS,  "sk_fwd_alloc", "i",    "Forward allocations"),
 
111
        __A(SK_SNDBUF,          "sk_sndbuf",    "i",    "Send buffer size"),
 
112
#undef __A
 
113
};
 
114
 
 
115
static inline int map_type(char k)
 
116
{
 
117
        switch (k) {
 
118
                case 'i': return TCF_META_TYPE_INT;
 
119
                case 'v': return TCF_META_TYPE_VAR;
 
120
        }
 
121
 
 
122
        fprintf(stderr, "BUG: Unknown map character '%c'\n", k);
 
123
        return INT_MAX;
 
124
}
 
125
 
 
126
static struct meta_entry * lookup_meta_entry(struct bstr *kind)
 
127
{
 
128
        int i;
 
129
 
 
130
        for (i = 0; i < (sizeof(meta_table)/sizeof(meta_table[0])); i++)
 
131
                if (!bstrcmp(kind, meta_table[i].kind) &&
 
132
                    meta_table[i].id != 0)
 
133
                        return &meta_table[i];
 
134
        
 
135
        return NULL;
 
136
}
 
137
 
 
138
static struct meta_entry * lookup_meta_entry_byid(int id)
 
139
{
 
140
        int i;
 
141
 
 
142
        for (i = 0; i < (sizeof(meta_table)/sizeof(meta_table[0])); i++)
 
143
                if (meta_table[i].id == id)
 
144
                        return &meta_table[i];
 
145
        
 
146
        return NULL;
 
147
}
 
148
 
 
149
static inline void dump_value(struct nlmsghdr *n, int tlv, unsigned long val,
 
150
                              struct tcf_meta_val *hdr)
 
151
{
 
152
        __u32 t;
 
153
 
 
154
        switch (TCF_META_TYPE(hdr->kind)) {
 
155
                case TCF_META_TYPE_INT:
 
156
                        t = val;
 
157
                        addattr_l(n, MAX_MSG, tlv, &t, sizeof(t));
 
158
                        break;
 
159
 
 
160
                case TCF_META_TYPE_VAR:
 
161
                        if (TCF_META_ID(hdr->kind) == TCF_META_ID_VALUE) {
 
162
                                struct bstr *a = (struct bstr *) val;
 
163
                                addattr_l(n, MAX_MSG, tlv, a->data, a->len);
 
164
                        }
 
165
                        break;
 
166
        }
 
167
}
 
168
 
 
169
static inline int is_compatible(struct tcf_meta_val *what,
 
170
                                struct tcf_meta_val *needed)
 
171
{
 
172
        char *p;
 
173
        struct meta_entry *entry;
 
174
        
 
175
        entry = lookup_meta_entry_byid(TCF_META_ID(what->kind));
 
176
 
 
177
        if (entry == NULL)
 
178
                return 0;
 
179
        
 
180
        for (p = entry->mask; p; p++)
 
181
                if (map_type(*p) == TCF_META_TYPE(needed->kind))
 
182
                        return 1;
 
183
 
 
184
        return 0;
 
185
}
 
186
 
 
187
static void list_meta_ids(FILE *fd)
 
188
{
 
189
        int i;
 
190
 
 
191
        fprintf(fd,
 
192
            "--------------------------------------------------------\n" \
 
193
            "  ID               Type       Description\n" \
 
194
            "--------------------------------------------------------");
 
195
 
 
196
        for (i = 0; i < (sizeof(meta_table)/sizeof(meta_table[0])); i++) {
 
197
                if (meta_table[i].id == TCF_META_ID_SECTION) {
 
198
                        fprintf(fd, "\n%s:\n", meta_table[i].kind);
 
199
                } else {
 
200
                        char *p = meta_table[i].mask;
 
201
                        char buf[64] = {0};
 
202
 
 
203
                        fprintf(fd, "  %-16s ", meta_table[i].kind);
 
204
 
 
205
                        while (*p) {
 
206
                                int type = map_type(*p);
 
207
 
 
208
                                switch (type) {
 
209
                                        case TCF_META_TYPE_INT:
 
210
                                                strcat(buf, "INT");
 
211
                                                break;
 
212
 
 
213
                                        case TCF_META_TYPE_VAR:
 
214
                                                strcat(buf, "VAR");
 
215
                                                break;
 
216
                                }
 
217
 
 
218
                                if (*(++p))
 
219
                                        strcat(buf, ",");
 
220
                        }
 
221
 
 
222
                        fprintf(fd, "%-10s %s\n", buf, meta_table[i].desc);
 
223
                }
 
224
        }
 
225
 
 
226
        fprintf(fd,
 
227
            "--------------------------------------------------------\n");
 
228
}
 
229
 
 
230
#undef TCF_META_ID_SECTION
 
231
 
 
232
#define PARSE_FAILURE ((void *) (-1))
 
233
 
 
234
#define PARSE_ERR(CARG, FMT, ARGS...) \
 
235
        em_parse_error(EINVAL, args, CARG, &meta_ematch_util, FMT ,##ARGS)
 
236
 
 
237
static inline int can_adopt(struct tcf_meta_val *val)
 
238
{
 
239
        return !!TCF_META_ID(val->kind);
 
240
}
 
241
 
 
242
static inline int overwrite_type(struct tcf_meta_val *src,
 
243
                                 struct tcf_meta_val *dst)
 
244
{
 
245
        return (TCF_META_TYPE(dst->kind) << 12) | TCF_META_ID(src->kind);
 
246
}
 
247
        
 
248
 
 
249
static inline struct bstr *
 
250
parse_object(struct bstr *args, struct bstr *arg, struct tcf_meta_val *obj,
 
251
             unsigned long *dst, struct tcf_meta_val *left)
 
252
{
 
253
        struct meta_entry *entry;
 
254
        unsigned long num;
 
255
        struct bstr *a;
 
256
 
 
257
        if (arg->quoted) {
 
258
                obj->kind = TCF_META_TYPE_VAR << 12;
 
259
                obj->kind |= TCF_META_ID_VALUE;
 
260
                *dst = (unsigned long) arg;
 
261
                return bstr_next(arg);
 
262
        }
 
263
 
 
264
        num = bstrtoul(arg);
 
265
        if (num != LONG_MAX) {
 
266
                obj->kind = TCF_META_TYPE_INT << 12;
 
267
                obj->kind |= TCF_META_ID_VALUE;
 
268
                *dst = (unsigned long) num;
 
269
                return bstr_next(arg);
 
270
        }
 
271
 
 
272
        entry = lookup_meta_entry(arg);
 
273
 
 
274
        if (entry == NULL) {
 
275
                PARSE_ERR(arg, "meta: unknown meta id\n");
 
276
                return PARSE_FAILURE;
 
277
        }
 
278
 
 
279
        obj->kind = entry->id | (map_type(entry->mask[0]) << 12);
 
280
 
 
281
        if (left) {
 
282
                struct tcf_meta_val *right = obj;
 
283
                
 
284
                if (TCF_META_TYPE(right->kind) == TCF_META_TYPE(left->kind))
 
285
                        goto compatible;
 
286
 
 
287
                if (can_adopt(left) && !can_adopt(right)) {
 
288
                        if (is_compatible(left, right))
 
289
                                left->kind = overwrite_type(left, right);
 
290
                        else
 
291
                                goto not_compatible;
 
292
                } else if (can_adopt(right) && !can_adopt(left)) {
 
293
                        if (is_compatible(right, left))
 
294
                                right->kind = overwrite_type(right, left);
 
295
                        else
 
296
                                goto not_compatible;
 
297
                } else if (can_adopt(left) && can_adopt(right)) {
 
298
                        if (is_compatible(left, right))
 
299
                                left->kind = overwrite_type(left, right);
 
300
                        else if (is_compatible(right, left))
 
301
                                right->kind = overwrite_type(right, left);
 
302
                        else
 
303
                                goto not_compatible;
 
304
                } else 
 
305
                        goto not_compatible;
 
306
        }
 
307
 
 
308
compatible:
 
309
 
 
310
        a = bstr_next(arg);
 
311
 
 
312
        while(a) {
 
313
                if (!bstrcmp(a, "shift")) {
 
314
                        unsigned long shift;
 
315
 
 
316
                        if (a->next == NULL) {
 
317
                                PARSE_ERR(a, "meta: missing argument");
 
318
                                return PARSE_FAILURE;
 
319
                        }
 
320
                        a = bstr_next(a);
 
321
                        
 
322
                        shift = bstrtoul(a);
 
323
                        if (shift == LONG_MAX) {
 
324
                                PARSE_ERR(a, "meta: invalid shift, must " \
 
325
                                    "be numeric");
 
326
                                return PARSE_FAILURE;
 
327
                        }
 
328
 
 
329
                        obj->shift = (__u8) shift;
 
330
                        a = bstr_next(a);
 
331
                } else if (!bstrcmp(a, "mask")) {
 
332
                        unsigned long mask;
 
333
 
 
334
                        if (a->next == NULL) {
 
335
                                PARSE_ERR(a, "meta: missing argument");
 
336
                                return PARSE_FAILURE;
 
337
                        }
 
338
                        a = bstr_next(a);
 
339
                        
 
340
                        mask = bstrtoul(a);
 
341
                        if (mask == LONG_MAX) {
 
342
                                PARSE_ERR(a, "meta: invalid mask, must be " \
 
343
                                    "numeric");
 
344
                                return PARSE_FAILURE;
 
345
                        }
 
346
                        *dst = (unsigned long) mask;
 
347
                        a = bstr_next(a);
 
348
                } else
 
349
                        break;
 
350
        }
 
351
 
 
352
        return a;
 
353
 
 
354
not_compatible:
 
355
        PARSE_ERR(arg, "lvalue and rvalue are not compatible.");
 
356
        return PARSE_FAILURE;
 
357
}
 
358
 
 
359
static int meta_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
 
360
                           struct bstr *args)
 
361
{
 
362
        int opnd;
 
363
        struct bstr *a;
 
364
        struct tcf_meta_hdr meta_hdr;
 
365
        unsigned long lvalue = 0, rvalue = 0;
 
366
 
 
367
        memset(&meta_hdr, 0, sizeof(meta_hdr));
 
368
 
 
369
        if (args == NULL)
 
370
                return PARSE_ERR(args, "meta: missing arguments");
 
371
 
 
372
        if (!bstrcmp(args, "list")) {
 
373
                list_meta_ids(stderr);
 
374
                return -1;
 
375
        }
 
376
 
 
377
        a = parse_object(args, args, &meta_hdr.left, &lvalue, NULL);
 
378
        if (a == PARSE_FAILURE)
 
379
                return -1;
 
380
        else if (a == NULL)
 
381
                return PARSE_ERR(args, "meta: missing operand");
 
382
 
 
383
        if (!bstrcmp(a, "eq"))
 
384
                opnd = TCF_EM_OPND_EQ;
 
385
        else if (!bstrcmp(a, "gt"))
 
386
                opnd = TCF_EM_OPND_GT;
 
387
        else if (!bstrcmp(a, "lt"))
 
388
                opnd = TCF_EM_OPND_LT;
 
389
        else
 
390
                return PARSE_ERR(a, "meta: invalid operand");
 
391
 
 
392
        meta_hdr.left.op = (__u8) opnd;
 
393
 
 
394
        if (a->next == NULL)
 
395
                return PARSE_ERR(args, "meta: missing rvalue");
 
396
        a = bstr_next(a);
 
397
 
 
398
        a = parse_object(args, a, &meta_hdr.right, &rvalue, &meta_hdr.left);
 
399
        if (a == PARSE_FAILURE)
 
400
                return -1;
 
401
        else if (a != NULL)
 
402
                return PARSE_ERR(a, "meta: unexpected trailer");
 
403
        
 
404
 
 
405
        addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
 
406
 
 
407
        addattr_l(n, MAX_MSG, TCA_EM_META_HDR, &meta_hdr, sizeof(meta_hdr));
 
408
 
 
409
        if (lvalue)
 
410
                dump_value(n, TCA_EM_META_LVALUE, lvalue, &meta_hdr.left);
 
411
 
 
412
        if (rvalue)
 
413
                dump_value(n, TCA_EM_META_RVALUE, rvalue, &meta_hdr.right);
 
414
 
 
415
        return 0;
 
416
}
 
417
#undef PARSE_ERR
 
418
 
 
419
static inline void print_binary(FILE *fd, unsigned char *str, int len)
 
420
{
 
421
        int i;
 
422
 
 
423
        for (i = 0; i < len; i++)
 
424
                if (!isprint(str[i]))
 
425
                        goto binary;
 
426
 
 
427
        for (i = 0; i < len; i++)
 
428
                fprintf(fd, "%c", str[i]);
 
429
        return;
 
430
 
 
431
binary:
 
432
        for (i = 0; i < len; i++)
 
433
                fprintf(fd, "%02x ", str[i]);
 
434
 
 
435
        fprintf(fd, "\"");
 
436
        for (i = 0; i < len; i++)
 
437
                fprintf(fd, "%c", isprint(str[i]) ? str[i] : '.');
 
438
        fprintf(fd, "\"");
 
439
}
 
440
 
 
441
static inline int print_value(FILE *fd, int type, struct rtattr *rta)
 
442
{
 
443
        if (rta == NULL) {
 
444
                fprintf(stderr, "Missing value TLV\n");
 
445
                return -1;
 
446
        }
 
447
 
 
448
        switch(type) {
 
449
                case TCF_META_TYPE_INT:
 
450
                        if (RTA_PAYLOAD(rta) < sizeof(__u32)) {
 
451
                                fprintf(stderr, "meta int type value TLV " \
 
452
                                    "size mismatch.\n");
 
453
                                return -1;
 
454
                        }
 
455
                        fprintf(fd, "%d", *(__u32 *) RTA_DATA(rta));
 
456
                        break;
 
457
 
 
458
                case TCF_META_TYPE_VAR:
 
459
                        print_binary(fd, RTA_DATA(rta), RTA_PAYLOAD(rta));
 
460
                        break;
 
461
        }
 
462
 
 
463
        return 0;
 
464
}
 
465
 
 
466
static int print_object(FILE *fd, struct tcf_meta_val *obj, struct rtattr *rta)
 
467
{
 
468
        int id = TCF_META_ID(obj->kind);
 
469
        int type = TCF_META_TYPE(obj->kind);
 
470
        struct meta_entry *entry;
 
471
 
 
472
        if (id == TCF_META_ID_VALUE)
 
473
                return print_value(fd, type, rta);
 
474
 
 
475
        entry = lookup_meta_entry_byid(id);
 
476
 
 
477
        if (entry == NULL)
 
478
                fprintf(fd, "[unknown meta id %d]", id);
 
479
        else
 
480
                fprintf(fd, "%s", entry->kind);
 
481
 
 
482
        if (obj->shift)
 
483
                fprintf(fd, " shift %d", obj->shift);
 
484
 
 
485
        switch (type) {
 
486
                case TCF_META_TYPE_INT:
 
487
                        if (rta) {
 
488
                                if (RTA_PAYLOAD(rta) < sizeof(__u32))
 
489
                                        goto size_mismatch;
 
490
 
 
491
                                fprintf(fd, " mask 0x%08x",
 
492
                                    *(__u32*) RTA_DATA(rta));
 
493
                        }
 
494
                        break;
 
495
        }
 
496
 
 
497
        return 0;
 
498
 
 
499
size_mismatch:
 
500
        fprintf(stderr, "meta int type mask TLV size mismatch\n");
 
501
        return -1;
 
502
}
 
503
 
 
504
 
 
505
static int meta_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
 
506
                           int data_len)
 
507
{
 
508
        struct rtattr *tb[TCA_EM_META_MAX+1];
 
509
        struct tcf_meta_hdr *meta_hdr;
 
510
 
 
511
        if (parse_rtattr(tb, TCA_EM_META_MAX, data, data_len) < 0)
 
512
                return -1;
 
513
 
 
514
        if (tb[TCA_EM_META_HDR] == NULL) {
 
515
                fprintf(stderr, "Missing meta header\n");
 
516
                return -1;
 
517
        }
 
518
 
 
519
        if (RTA_PAYLOAD(tb[TCA_EM_META_HDR]) < sizeof(*meta_hdr)) {
 
520
                fprintf(stderr, "Meta header size mismatch\n");
 
521
                return -1;
 
522
        }
 
523
 
 
524
        meta_hdr = RTA_DATA(tb[TCA_EM_META_HDR]);
 
525
 
 
526
        if (print_object(fd, &meta_hdr->left, tb[TCA_EM_META_LVALUE]) < 0)
 
527
                return -1;
 
528
 
 
529
        switch (meta_hdr->left.op) {
 
530
                case TCF_EM_OPND_EQ:
 
531
                        fprintf(fd, " eq ");
 
532
                        break;
 
533
                case TCF_EM_OPND_LT:
 
534
                        fprintf(fd, " lt ");
 
535
                        break;
 
536
                case TCF_EM_OPND_GT:
 
537
                        fprintf(fd, " gt ");
 
538
                        break;
 
539
        }
 
540
 
 
541
        return print_object(fd, &meta_hdr->right, tb[TCA_EM_META_RVALUE]);
 
542
}
 
543
 
 
544
struct ematch_util meta_ematch_util = {
 
545
        .kind = "meta",
 
546
        .kind_num = TCF_EM_META,
 
547
        .parse_eopt = meta_parse_eopt,
 
548
        .print_eopt = meta_print_eopt,
 
549
        .print_usage = meta_print_usage
 
550
};