]> git.proxmox.com Git - mirror_iproute2.git/blob - tc/m_ematch.c
tc/pedit: make functions static
[mirror_iproute2.git] / tc / m_ematch.c
1 /*
2 * m_ematch.c Extended Matches
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 <fcntl.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
19 #include <string.h>
20 #include <dlfcn.h>
21 #include <stdarg.h>
22 #include <errno.h>
23
24 #include "utils.h"
25 #include "tc_util.h"
26 #include "m_ematch.h"
27
28 #define EMATCH_MAP "/etc/iproute2/ematch_map"
29
30 static struct ematch_util *ematch_list;
31
32 /* export to bison parser */
33 int ematch_argc;
34 char **ematch_argv;
35 char *ematch_err;
36 struct ematch *ematch_root;
37
38 static int begin_argc;
39 static char **begin_argv;
40
41 static inline void map_warning(int num, char *kind)
42 {
43 fprintf(stderr,
44 "Error: Unable to find ematch \"%s\" in %s\n" \
45 "Please assign a unique ID to the ematch kind the suggested " \
46 "entry is:\n" \
47 "\t%d\t%s\n",
48 kind, EMATCH_MAP, num, kind);
49 }
50
51 static int lookup_map(__u16 num, char *dst, int len, const char *file)
52 {
53 int err = -EINVAL;
54 char buf[512];
55 FILE *fd = fopen(file, "r");
56
57 if (fd == NULL)
58 return -errno;
59
60 while (fgets(buf, sizeof(buf), fd)) {
61 char namebuf[512], *p = buf;
62 int id;
63
64 while (*p == ' ' || *p == '\t')
65 p++;
66 if (*p == '#' || *p == '\n' || *p == 0)
67 continue;
68
69 if (sscanf(p, "%d %s", &id, namebuf) != 2) {
70 fprintf(stderr, "ematch map %s corrupted at %s\n",
71 file, p);
72 goto out;
73 }
74
75 if (id == num) {
76 if (dst)
77 strncpy(dst, namebuf, len - 1);
78 err = 0;
79 goto out;
80 }
81 }
82
83 err = -ENOENT;
84 out:
85 fclose(fd);
86 return err;
87 }
88
89 static int lookup_map_id(char *kind, int *dst, const char *file)
90 {
91 int err = -EINVAL;
92 char buf[512];
93 FILE *fd = fopen(file, "r");
94
95 if (fd == NULL)
96 return -errno;
97
98 while (fgets(buf, sizeof(buf), fd)) {
99 char namebuf[512], *p = buf;
100 int id;
101
102 while (*p == ' ' || *p == '\t')
103 p++;
104 if (*p == '#' || *p == '\n' || *p == 0)
105 continue;
106
107 if (sscanf(p, "%d %s", &id, namebuf) != 2) {
108 fprintf(stderr, "ematch map %s corrupted at %s\n",
109 file, p);
110 goto out;
111 }
112
113 if (!strcasecmp(namebuf, kind)) {
114 if (dst)
115 *dst = id;
116 err = 0;
117 goto out;
118 }
119 }
120
121 err = -ENOENT;
122 *dst = 0;
123 out:
124 fclose(fd);
125 return err;
126 }
127
128 static struct ematch_util *get_ematch_kind(char *kind)
129 {
130 static void *body;
131 void *dlh;
132 char buf[256];
133 struct ematch_util *e;
134
135 for (e = ematch_list; e; e = e->next) {
136 if (strcmp(e->kind, kind) == 0)
137 return e;
138 }
139
140 snprintf(buf, sizeof(buf), "em_%s.so", kind);
141 dlh = dlopen(buf, RTLD_LAZY);
142 if (dlh == NULL) {
143 dlh = body;
144 if (dlh == NULL) {
145 dlh = body = dlopen(NULL, RTLD_LAZY);
146 if (dlh == NULL)
147 return NULL;
148 }
149 }
150
151 snprintf(buf, sizeof(buf), "%s_ematch_util", kind);
152 e = dlsym(dlh, buf);
153 if (e == NULL)
154 return NULL;
155
156 e->next = ematch_list;
157 ematch_list = e;
158
159 return e;
160 }
161
162 static struct ematch_util *get_ematch_kind_num(__u16 kind)
163 {
164 char name[513];
165
166 if (lookup_map(kind, name, sizeof(name), EMATCH_MAP) < 0)
167 return NULL;
168
169 return get_ematch_kind(name);
170 }
171
172 static int em_parse_call(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
173 struct ematch_util *e, struct ematch *t)
174 {
175 if (e->parse_eopt_argv) {
176 int argc = 0, i = 0, ret;
177 struct bstr *args;
178 char **argv;
179
180 for (args = t->args; args; args = bstr_next(args))
181 argc++;
182 argv = calloc(argc, sizeof(char *));
183 if (!argv)
184 return -1;
185 for (args = t->args; args; args = bstr_next(args))
186 argv[i++] = args->data;
187
188 ret = e->parse_eopt_argv(n, hdr, argc, argv);
189
190 free(argv);
191 return ret;
192 }
193
194 return e->parse_eopt(n, hdr, t->args->next);
195 }
196
197 static int parse_tree(struct nlmsghdr *n, struct ematch *tree)
198 {
199 int index = 1;
200 struct ematch *t;
201
202 for (t = tree; t; t = t->next) {
203 struct rtattr *tail;
204 struct tcf_ematch_hdr hdr = { .flags = t->relation };
205
206 if (t->inverted)
207 hdr.flags |= TCF_EM_INVERT;
208
209 tail = addattr_nest(n, MAX_MSG, index++);
210
211 if (t->child) {
212 __u32 r = t->child_ref;
213
214 addraw_l(n, MAX_MSG, &hdr, sizeof(hdr));
215 addraw_l(n, MAX_MSG, &r, sizeof(r));
216 } else {
217 int num = 0, err;
218 char buf[64];
219 struct ematch_util *e;
220
221 if (t->args == NULL)
222 return -1;
223
224 strncpy(buf, (char *) t->args->data, sizeof(buf)-1);
225 e = get_ematch_kind(buf);
226 if (e == NULL) {
227 fprintf(stderr, "Unknown ematch \"%s\"\n",
228 buf);
229 return -1;
230 }
231
232 err = lookup_map_id(buf, &num, EMATCH_MAP);
233 if (err < 0) {
234 if (err == -ENOENT)
235 map_warning(e->kind_num, buf);
236 return err;
237 }
238
239 hdr.kind = num;
240 if (em_parse_call(n, &hdr, e, t) < 0)
241 return -1;
242 }
243
244 addattr_nest_end(n, tail);
245 }
246
247 return 0;
248 }
249
250 static int flatten_tree(struct ematch *head, struct ematch *tree)
251 {
252 int i, count = 0;
253 struct ematch *t;
254
255 for (;;) {
256 count++;
257
258 if (tree->child) {
259 for (t = head; t->next; t = t->next);
260 t->next = tree->child;
261 count += flatten_tree(head, tree->child);
262 }
263
264 if (tree->relation == 0)
265 break;
266
267 tree = tree->next;
268 }
269
270 for (i = 0, t = head; t; t = t->next, i++)
271 t->index = i;
272
273 for (t = head; t; t = t->next)
274 if (t->child)
275 t->child_ref = t->child->index;
276
277 return count;
278 }
279
280 __attribute__((format(printf, 5, 6)))
281 int em_parse_error(int err, struct bstr *args, struct bstr *carg,
282 struct ematch_util *e, char *fmt, ...)
283 {
284 va_list a;
285
286 va_start(a, fmt);
287 vfprintf(stderr, fmt, a);
288 va_end(a);
289
290 if (ematch_err)
291 fprintf(stderr, ": %s\n... ", ematch_err);
292 else
293 fprintf(stderr, "\n... ");
294
295 while (ematch_argc < begin_argc) {
296 if (ematch_argc == (begin_argc - 1))
297 fprintf(stderr, ">>%s<< ", *begin_argv);
298 else
299 fprintf(stderr, "%s ", *begin_argv);
300 begin_argv++;
301 begin_argc--;
302 }
303
304 fprintf(stderr, "...\n");
305
306 if (args) {
307 fprintf(stderr, "... %s(", e->kind);
308 while (args) {
309 fprintf(stderr, "%s", args == carg ? ">>" : "");
310 bstr_print(stderr, args, 1);
311 fprintf(stderr, "%s%s", args == carg ? "<<" : "",
312 args->next ? " " : "");
313 args = args->next;
314 }
315 fprintf(stderr, ")...\n");
316
317 }
318
319 if (e == NULL) {
320 fprintf(stderr,
321 "Usage: EXPR\n" \
322 "where: EXPR := TERM [ { and | or } EXPR ]\n" \
323 " TERM := [ not ] { MATCH | '(' EXPR ')' }\n" \
324 " MATCH := module '(' ARGS ')'\n" \
325 " ARGS := ARG1 ARG2 ...\n" \
326 "\n" \
327 "Example: a(x y) and not (b(x) or c(x y z))\n");
328 } else
329 e->print_usage(stderr);
330
331 return -err;
332 }
333
334 static inline void free_ematch_err(void)
335 {
336 if (ematch_err) {
337 free(ematch_err);
338 ematch_err = NULL;
339 }
340 }
341
342 extern int ematch_parse(void);
343
344 int parse_ematch(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
345 {
346 begin_argc = ematch_argc = *argc_p;
347 begin_argv = ematch_argv = *argv_p;
348
349 if (ematch_parse()) {
350 int err = em_parse_error(EINVAL, NULL, NULL, NULL,
351 "Parse error");
352 free_ematch_err();
353 return err;
354 }
355
356 free_ematch_err();
357
358 /* undo look ahead by parser */
359 ematch_argc++;
360 ematch_argv--;
361
362 if (ematch_root) {
363 struct rtattr *tail, *tail_list;
364
365 struct tcf_ematch_tree_hdr hdr = {
366 .nmatches = flatten_tree(ematch_root, ematch_root),
367 .progid = TCF_EM_PROG_TC
368 };
369
370 tail = addattr_nest(n, MAX_MSG, tca_id);
371 addattr_l(n, MAX_MSG, TCA_EMATCH_TREE_HDR, &hdr, sizeof(hdr));
372
373 tail_list = addattr_nest(n, MAX_MSG, TCA_EMATCH_TREE_LIST);
374
375 if (parse_tree(n, ematch_root) < 0)
376 return -1;
377
378 addattr_nest_end(n, tail_list);
379 addattr_nest_end(n, tail);
380 }
381
382 *argc_p = ematch_argc;
383 *argv_p = ematch_argv;
384
385 return 0;
386 }
387
388 static int print_ematch_seq(FILE *fd, struct rtattr **tb, int start,
389 int prefix)
390 {
391 int n, i = start;
392 struct tcf_ematch_hdr *hdr;
393 int dlen;
394 void *data;
395
396 for (;;) {
397 if (tb[i] == NULL)
398 return -1;
399
400 dlen = RTA_PAYLOAD(tb[i]) - sizeof(*hdr);
401 data = (void *) RTA_DATA(tb[i]) + sizeof(*hdr);
402
403 if (dlen < 0)
404 return -1;
405
406 hdr = RTA_DATA(tb[i]);
407
408 if (hdr->flags & TCF_EM_INVERT)
409 fprintf(fd, "NOT ");
410
411 if (hdr->kind == 0) {
412 __u32 ref;
413
414 if (dlen < sizeof(__u32))
415 return -1;
416
417 ref = *(__u32 *) data;
418 fprintf(fd, "(\n");
419 for (n = 0; n <= prefix; n++)
420 fprintf(fd, " ");
421 if (print_ematch_seq(fd, tb, ref + 1, prefix + 1) < 0)
422 return -1;
423 for (n = 0; n < prefix; n++)
424 fprintf(fd, " ");
425 fprintf(fd, ") ");
426
427 } else {
428 struct ematch_util *e;
429
430 e = get_ematch_kind_num(hdr->kind);
431 if (e == NULL)
432 fprintf(fd, "[unknown ematch %d]\n",
433 hdr->kind);
434 else {
435 fprintf(fd, "%s(", e->kind);
436 if (e->print_eopt(fd, hdr, data, dlen) < 0)
437 return -1;
438 fprintf(fd, ")\n");
439 }
440 if (hdr->flags & TCF_EM_REL_MASK)
441 for (n = 0; n < prefix; n++)
442 fprintf(fd, " ");
443 }
444
445 switch (hdr->flags & TCF_EM_REL_MASK) {
446 case TCF_EM_REL_AND:
447 fprintf(fd, "AND ");
448 break;
449
450 case TCF_EM_REL_OR:
451 fprintf(fd, "OR ");
452 break;
453
454 default:
455 return 0;
456 }
457
458 i++;
459 }
460
461 return 0;
462 }
463
464 static int print_ematch_list(FILE *fd, struct tcf_ematch_tree_hdr *hdr,
465 struct rtattr *rta)
466 {
467 int err = -1;
468 struct rtattr **tb;
469
470 tb = malloc((hdr->nmatches + 1) * sizeof(struct rtattr *));
471 if (tb == NULL)
472 return -1;
473
474 if (hdr->nmatches > 0) {
475 if (parse_rtattr_nested(tb, hdr->nmatches, rta) < 0)
476 goto errout;
477
478 fprintf(fd, "\n ");
479 if (print_ematch_seq(fd, tb, 1, 1) < 0)
480 goto errout;
481 }
482
483 err = 0;
484 errout:
485 free(tb);
486 return err;
487 }
488
489 int print_ematch(FILE *fd, const struct rtattr *rta)
490 {
491 struct rtattr *tb[TCA_EMATCH_TREE_MAX+1];
492 struct tcf_ematch_tree_hdr *hdr;
493
494 if (parse_rtattr_nested(tb, TCA_EMATCH_TREE_MAX, rta) < 0)
495 return -1;
496
497 if (tb[TCA_EMATCH_TREE_HDR] == NULL) {
498 fprintf(stderr, "Missing ematch tree header\n");
499 return -1;
500 }
501
502 if (tb[TCA_EMATCH_TREE_LIST] == NULL) {
503 fprintf(stderr, "Missing ematch tree list\n");
504 return -1;
505 }
506
507 if (RTA_PAYLOAD(tb[TCA_EMATCH_TREE_HDR]) < sizeof(*hdr)) {
508 fprintf(stderr, "Ematch tree header size mismatch\n");
509 return -1;
510 }
511
512 hdr = RTA_DATA(tb[TCA_EMATCH_TREE_HDR]);
513
514 return print_ematch_list(fd, hdr, tb[TCA_EMATCH_TREE_LIST]);
515 }
516
517 struct bstr *bstr_alloc(const char *text)
518 {
519 struct bstr *b = calloc(1, sizeof(*b));
520
521 if (b == NULL)
522 return NULL;
523
524 b->data = strdup(text);
525 if (b->data == NULL) {
526 free(b);
527 return NULL;
528 }
529
530 b->len = strlen(text);
531
532 return b;
533 }
534
535 unsigned long bstrtoul(const struct bstr *b)
536 {
537 char *inv = NULL;
538 unsigned long l;
539 char buf[b->len+1];
540
541 memcpy(buf, b->data, b->len);
542 buf[b->len] = '\0';
543
544 l = strtoul(buf, &inv, 0);
545 if (l == ULONG_MAX || inv == buf)
546 return ULONG_MAX;
547
548 return l;
549 }
550
551 void bstr_print(FILE *fd, const struct bstr *b, int ascii)
552 {
553 int i;
554 char *s = b->data;
555
556 if (ascii)
557 for (i = 0; i < b->len; i++)
558 fprintf(fd, "%c", isprint(s[i]) ? s[i] : '.');
559 else {
560 for (i = 0; i < b->len; i++)
561 fprintf(fd, "%02x", s[i]);
562 fprintf(fd, "\"");
563 for (i = 0; i < b->len; i++)
564 fprintf(fd, "%c", isprint(s[i]) ? s[i] : '.');
565 fprintf(fd, "\"");
566 }
567 }
568
569 void print_ematch_tree(const struct ematch *tree)
570 {
571 const struct ematch *t;
572
573 for (t = tree; t; t = t->next) {
574 if (t->inverted)
575 printf("NOT ");
576
577 if (t->child) {
578 printf("(");
579 print_ematch_tree(t->child);
580 printf(")");
581 } else {
582 struct bstr *b;
583
584 for (b = t->args; b; b = b->next)
585 printf("%s%s", b->data, b->next ? " " : "");
586 }
587
588 if (t->relation == TCF_EM_REL_AND)
589 printf(" AND ");
590 else if (t->relation == TCF_EM_REL_OR)
591 printf(" OR ");
592 }
593 }