This commit was generated by cvs2svn to compensate for changes in r2587,
[iproute2.git] / tc / em_meta.c
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 };