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