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