2
* em_meta.c Metadata Ematch
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.
9
* Authors: Thomas Graf <tgraf@suug.ch>
17
#include <sys/socket.h>
18
#include <netinet/in.h>
19
#include <arpa/inet.h>
25
#include <linux/tc_ematch/tc_em_meta.h>
27
extern struct ematch_util meta_ematch_util;
29
static void meta_print_usage(FILE *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" \
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" \
41
"For a list of meta identifiers, use meta(list).\n");
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"),
62
__A(SECTION, "Interfaces", "", ""),
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",
74
__A(DATALEN, "data_len", "i",
75
"Length of data in packet"),
76
__A(MACLEN, "mac_len", "i",
77
"Length of link layer header"),
79
__A(SECTION, "Netfilter", "", ""),
80
__A(NFMARK, "nf_mark", "i",
82
__A(NFMARK, "fwmark", "i",
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"),
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"),
115
static inline int map_type(char k)
118
case 'i': return TCF_META_TYPE_INT;
119
case 'v': return TCF_META_TYPE_VAR;
122
fprintf(stderr, "BUG: Unknown map character '%c'\n", k);
126
static struct meta_entry * lookup_meta_entry(struct bstr *kind)
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];
138
static struct meta_entry * lookup_meta_entry_byid(int id)
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];
149
static inline void dump_value(struct nlmsghdr *n, int tlv, unsigned long val,
150
struct tcf_meta_val *hdr)
154
switch (TCF_META_TYPE(hdr->kind)) {
155
case TCF_META_TYPE_INT:
157
addattr_l(n, MAX_MSG, tlv, &t, sizeof(t));
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);
169
static inline int is_compatible(struct tcf_meta_val *what,
170
struct tcf_meta_val *needed)
173
struct meta_entry *entry;
175
entry = lookup_meta_entry_byid(TCF_META_ID(what->kind));
180
for (p = entry->mask; p; p++)
181
if (map_type(*p) == TCF_META_TYPE(needed->kind))
187
static void list_meta_ids(FILE *fd)
192
"--------------------------------------------------------\n" \
193
" ID Type Description\n" \
194
"--------------------------------------------------------");
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);
200
char *p = meta_table[i].mask;
203
fprintf(fd, " %-16s ", meta_table[i].kind);
206
int type = map_type(*p);
209
case TCF_META_TYPE_INT:
213
case TCF_META_TYPE_VAR:
222
fprintf(fd, "%-10s %s\n", buf, meta_table[i].desc);
227
"--------------------------------------------------------\n");
230
#undef TCF_META_ID_SECTION
232
#define PARSE_FAILURE ((void *) (-1))
234
#define PARSE_ERR(CARG, FMT, ARGS...) \
235
em_parse_error(EINVAL, args, CARG, &meta_ematch_util, FMT ,##ARGS)
237
static inline int can_adopt(struct tcf_meta_val *val)
239
return !!TCF_META_ID(val->kind);
242
static inline int overwrite_type(struct tcf_meta_val *src,
243
struct tcf_meta_val *dst)
245
return (TCF_META_TYPE(dst->kind) << 12) | TCF_META_ID(src->kind);
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)
253
struct meta_entry *entry;
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);
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);
272
entry = lookup_meta_entry(arg);
275
PARSE_ERR(arg, "meta: unknown meta id\n");
276
return PARSE_FAILURE;
279
obj->kind = entry->id | (map_type(entry->mask[0]) << 12);
282
struct tcf_meta_val *right = obj;
284
if (TCF_META_TYPE(right->kind) == TCF_META_TYPE(left->kind))
287
if (can_adopt(left) && !can_adopt(right)) {
288
if (is_compatible(left, right))
289
left->kind = overwrite_type(left, right);
292
} else if (can_adopt(right) && !can_adopt(left)) {
293
if (is_compatible(right, left))
294
right->kind = overwrite_type(right, left);
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);
313
if (!bstrcmp(a, "shift")) {
316
if (a->next == NULL) {
317
PARSE_ERR(a, "meta: missing argument");
318
return PARSE_FAILURE;
323
if (shift == LONG_MAX) {
324
PARSE_ERR(a, "meta: invalid shift, must " \
326
return PARSE_FAILURE;
329
obj->shift = (__u8) shift;
331
} else if (!bstrcmp(a, "mask")) {
334
if (a->next == NULL) {
335
PARSE_ERR(a, "meta: missing argument");
336
return PARSE_FAILURE;
341
if (mask == LONG_MAX) {
342
PARSE_ERR(a, "meta: invalid mask, must be " \
344
return PARSE_FAILURE;
346
*dst = (unsigned long) mask;
355
PARSE_ERR(arg, "lvalue and rvalue are not compatible.");
356
return PARSE_FAILURE;
359
static int meta_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
364
struct tcf_meta_hdr meta_hdr;
365
unsigned long lvalue = 0, rvalue = 0;
367
memset(&meta_hdr, 0, sizeof(meta_hdr));
370
return PARSE_ERR(args, "meta: missing arguments");
372
if (!bstrcmp(args, "list")) {
373
list_meta_ids(stderr);
377
a = parse_object(args, args, &meta_hdr.left, &lvalue, NULL);
378
if (a == PARSE_FAILURE)
381
return PARSE_ERR(args, "meta: missing operand");
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;
390
return PARSE_ERR(a, "meta: invalid operand");
392
meta_hdr.left.op = (__u8) opnd;
395
return PARSE_ERR(args, "meta: missing rvalue");
398
a = parse_object(args, a, &meta_hdr.right, &rvalue, &meta_hdr.left);
399
if (a == PARSE_FAILURE)
402
return PARSE_ERR(a, "meta: unexpected trailer");
405
addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
407
addattr_l(n, MAX_MSG, TCA_EM_META_HDR, &meta_hdr, sizeof(meta_hdr));
410
dump_value(n, TCA_EM_META_LVALUE, lvalue, &meta_hdr.left);
413
dump_value(n, TCA_EM_META_RVALUE, rvalue, &meta_hdr.right);
419
static inline void print_binary(FILE *fd, unsigned char *str, int len)
423
for (i = 0; i < len; i++)
424
if (!isprint(str[i]))
427
for (i = 0; i < len; i++)
428
fprintf(fd, "%c", str[i]);
432
for (i = 0; i < len; i++)
433
fprintf(fd, "%02x ", str[i]);
436
for (i = 0; i < len; i++)
437
fprintf(fd, "%c", isprint(str[i]) ? str[i] : '.');
441
static inline int print_value(FILE *fd, int type, struct rtattr *rta)
444
fprintf(stderr, "Missing value TLV\n");
449
case TCF_META_TYPE_INT:
450
if (RTA_PAYLOAD(rta) < sizeof(__u32)) {
451
fprintf(stderr, "meta int type value TLV " \
455
fprintf(fd, "%d", *(__u32 *) RTA_DATA(rta));
458
case TCF_META_TYPE_VAR:
459
print_binary(fd, RTA_DATA(rta), RTA_PAYLOAD(rta));
466
static int print_object(FILE *fd, struct tcf_meta_val *obj, struct rtattr *rta)
468
int id = TCF_META_ID(obj->kind);
469
int type = TCF_META_TYPE(obj->kind);
470
struct meta_entry *entry;
472
if (id == TCF_META_ID_VALUE)
473
return print_value(fd, type, rta);
475
entry = lookup_meta_entry_byid(id);
478
fprintf(fd, "[unknown meta id %d]", id);
480
fprintf(fd, "%s", entry->kind);
483
fprintf(fd, " shift %d", obj->shift);
486
case TCF_META_TYPE_INT:
488
if (RTA_PAYLOAD(rta) < sizeof(__u32))
491
fprintf(fd, " mask 0x%08x",
492
*(__u32*) RTA_DATA(rta));
500
fprintf(stderr, "meta int type mask TLV size mismatch\n");
505
static int meta_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
508
struct rtattr *tb[TCA_EM_META_MAX+1];
509
struct tcf_meta_hdr *meta_hdr;
511
if (parse_rtattr(tb, TCA_EM_META_MAX, data, data_len) < 0)
514
if (tb[TCA_EM_META_HDR] == NULL) {
515
fprintf(stderr, "Missing meta header\n");
519
if (RTA_PAYLOAD(tb[TCA_EM_META_HDR]) < sizeof(*meta_hdr)) {
520
fprintf(stderr, "Meta header size mismatch\n");
524
meta_hdr = RTA_DATA(tb[TCA_EM_META_HDR]);
526
if (print_object(fd, &meta_hdr->left, tb[TCA_EM_META_LVALUE]) < 0)
529
switch (meta_hdr->left.op) {
541
return print_object(fd, &meta_hdr->right, tb[TCA_EM_META_RVALUE]);
544
struct ematch_util meta_ematch_util = {
546
.kind_num = TCF_EM_META,
547
.parse_eopt = meta_parse_eopt,
548
.print_eopt = meta_print_eopt,
549
.print_usage = meta_print_usage