Busybox: Upgrade to 1.21.1 (stable). lsof active.
[tomato.git] / release / src / router / iproute2 / tc / m_ematch.c
blob918afd62c319116e1ec6e11884584673adf11ec2
1 /*
2 * m_ematch.c Extended Matches
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>
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 <stdarg.h>
23 #include <errno.h>
25 #include "utils.h"
26 #include "tc_util.h"
27 #include "m_ematch.h"
29 #define EMATCH_MAP "/etc/iproute2/ematch_map"
31 static struct ematch_util *ematch_list;
33 /* export to bison parser */
34 int ematch_argc;
35 char **ematch_argv;
36 char *ematch_err = NULL;
37 struct ematch *ematch_root;
39 static int begin_argc;
40 static char **begin_argv;
42 static inline void map_warning(int num, char *kind)
44 fprintf(stderr,
45 "Error: Unable to find ematch \"%s\" in %s\n" \
46 "Please assign a unique ID to the ematch kind the suggested " \
47 "entry is:\n" \
48 "\t%d\t%s\n",
49 kind, EMATCH_MAP, num, kind);
52 static int lookup_map(__u16 num, char *dst, int len, const char *file)
54 int err = -EINVAL;
55 char buf[512];
56 FILE *fd = fopen(file, "r");
58 if (fd == NULL)
59 return -errno;
61 while (fgets(buf, sizeof(buf), fd)) {
62 char namebuf[512], *p = buf;
63 int id;
65 while (*p == ' ' || *p == '\t')
66 p++;
67 if (*p == '#' || *p == '\n' || *p == 0)
68 continue;
70 if (sscanf(p, "%d %s", &id, namebuf) != 2) {
71 fprintf(stderr, "ematch map %s corrupted at %s\n",
72 file, p);
73 goto out;
76 if (id == num) {
77 if (dst)
78 strncpy(dst, namebuf, len - 1);
79 err = 0;
80 goto out;
84 err = -ENOENT;
85 out:
86 fclose(fd);
87 return err;
90 static int lookup_map_id(char *kind, int *dst, const char *file)
92 int err = -EINVAL;
93 char buf[512];
94 FILE *fd = fopen(file, "r");
96 if (fd == NULL)
97 return -errno;
99 while (fgets(buf, sizeof(buf), fd)) {
100 char namebuf[512], *p = buf;
101 int id;
103 while (*p == ' ' || *p == '\t')
104 p++;
105 if (*p == '#' || *p == '\n' || *p == 0)
106 continue;
108 if (sscanf(p, "%d %s", &id, namebuf) != 2) {
109 fprintf(stderr, "ematch map %s corrupted at %s\n",
110 file, p);
111 goto out;
114 if (!strcasecmp(namebuf, kind)) {
115 if (dst)
116 *dst = id;
117 err = 0;
118 goto out;
122 err = -ENOENT;
123 *dst = 0;
124 out:
125 fclose(fd);
126 return err;
129 static struct ematch_util *get_ematch_kind(char *kind)
131 static void *body;
132 void *dlh;
133 char buf[256];
134 struct ematch_util *e;
136 for (e = ematch_list; e; e = e->next) {
137 if (strcmp(e->kind, kind) == 0)
138 return e;
141 snprintf(buf, sizeof(buf), "em_%s.so", kind);
142 dlh = dlopen(buf, RTLD_LAZY);
143 if (dlh == NULL) {
144 dlh = body;
145 if (dlh == NULL) {
146 dlh = body = dlopen(NULL, RTLD_LAZY);
147 if (dlh == NULL)
148 return NULL;
152 snprintf(buf, sizeof(buf), "%s_ematch_util", kind);
153 e = dlsym(dlh, buf);
154 if (e == NULL)
155 return NULL;
157 e->next = ematch_list;
158 ematch_list = e;
160 return e;
163 static struct ematch_util *get_ematch_kind_num(__u16 kind)
165 char name[32];
167 if (lookup_map(kind, name, sizeof(name), EMATCH_MAP) < 0)
168 return NULL;
170 return get_ematch_kind(name);
172 return NULL;
175 static int parse_tree(struct nlmsghdr *n, struct ematch *tree)
177 int index = 1;
178 struct ematch *t;
180 for (t = tree; t; t = t->next) {
181 struct rtattr *tail = NLMSG_TAIL(n);
182 struct tcf_ematch_hdr hdr = {
183 .flags = t->relation
186 if (t->inverted)
187 hdr.flags |= TCF_EM_INVERT;
189 addattr_l(n, MAX_MSG, index++, NULL, 0);
191 if (t->child) {
192 __u32 r = t->child_ref;
193 addraw_l(n, MAX_MSG, &hdr, sizeof(hdr));
194 addraw_l(n, MAX_MSG, &r, sizeof(r));
195 } else {
196 int num = 0, err;
197 char buf[64];
198 struct ematch_util *e;
200 if (t->args == NULL)
201 return -1;
203 strncpy(buf, (char*) t->args->data, sizeof(buf)-1);
204 e = get_ematch_kind(buf);
205 if (e == NULL) {
206 fprintf(stderr, "Unknown ematch \"%s\"\n",
207 buf);
208 return -1;
211 err = lookup_map_id(buf, &num, EMATCH_MAP);
212 if (err < 0) {
213 if (err == -ENOENT)
214 map_warning(e->kind_num, buf);
215 return err;
218 hdr.kind = num;
219 if (e->parse_eopt(n, &hdr, t->args->next) < 0)
220 return -1;
223 tail->rta_len = (void*) NLMSG_TAIL(n) - (void*) tail;
226 return 0;
229 static int flatten_tree(struct ematch *head, struct ematch *tree)
231 int i, count = 0;
232 struct ematch *t;
234 for (;;) {
235 count++;
237 if (tree->child) {
238 for (t = head; t->next; t = t->next);
239 t->next = tree->child;
240 count += flatten_tree(head, tree->child);
243 if (tree->relation == 0)
244 break;
246 tree = tree->next;
249 for (i = 0, t = head; t; t = t->next, i++)
250 t->index = i;
252 for (t = head; t; t = t->next)
253 if (t->child)
254 t->child_ref = t->child->index;
256 return count;
259 int em_parse_error(int err, struct bstr *args, struct bstr *carg,
260 struct ematch_util *e, char *fmt, ...)
262 va_list a;
264 va_start(a, fmt);
265 vfprintf(stderr, fmt, a);
266 va_end(a);
268 if (ematch_err)
269 fprintf(stderr, ": %s\n... ", ematch_err);
270 else
271 fprintf(stderr, "\n... ");
273 while (ematch_argc < begin_argc) {
274 if (ematch_argc == (begin_argc - 1))
275 fprintf(stderr, ">>%s<< ", *begin_argv);
276 else
277 fprintf(stderr, "%s ", *begin_argv);
278 begin_argv++;
279 begin_argc--;
282 fprintf(stderr, "...\n");
284 if (args) {
285 fprintf(stderr, "... %s(", e->kind);
286 while (args) {
287 fprintf(stderr, "%s", args == carg ? ">>" : "");
288 bstr_print(stderr, args, 1);
289 fprintf(stderr, "%s%s", args == carg ? "<<" : "",
290 args->next ? " " : "");
291 args = args->next;
293 fprintf(stderr, ")...\n");
297 if (e == NULL) {
298 fprintf(stderr,
299 "Usage: EXPR\n" \
300 "where: EXPR := TERM [ { and | or } EXPR ]\n" \
301 " TERM := [ not ] { MATCH | '(' EXPR ')' }\n" \
302 " MATCH := module '(' ARGS ')'\n" \
303 " ARGS := ARG1 ARG2 ...\n" \
304 "\n" \
305 "Example: a(x y) and not (b(x) or c(x y z))\n");
306 } else
307 e->print_usage(stderr);
309 return -err;
312 static inline void free_ematch_err(void)
314 if (ematch_err) {
315 free(ematch_err);
316 ematch_err = NULL;
320 extern int ematch_parse(void);
322 int parse_ematch(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
324 begin_argc = ematch_argc = *argc_p;
325 begin_argv = ematch_argv = *argv_p;
327 if (ematch_parse()) {
328 int err = em_parse_error(EINVAL, NULL, NULL, NULL,
329 "Parse error");
330 free_ematch_err();
331 return err;
334 free_ematch_err();
336 /* undo look ahead by parser */
337 ematch_argc++;
338 ematch_argv--;
340 if (ematch_root) {
341 struct rtattr *tail, *tail_list;
343 struct tcf_ematch_tree_hdr hdr = {
344 .nmatches = flatten_tree(ematch_root, ematch_root),
345 .progid = TCF_EM_PROG_TC
348 tail = NLMSG_TAIL(n);
349 addattr_l(n, MAX_MSG, tca_id, NULL, 0);
350 addattr_l(n, MAX_MSG, TCA_EMATCH_TREE_HDR, &hdr, sizeof(hdr));
352 tail_list = NLMSG_TAIL(n);
353 addattr_l(n, MAX_MSG, TCA_EMATCH_TREE_LIST, NULL, 0);
355 if (parse_tree(n, ematch_root) < 0)
356 return -1;
358 tail_list->rta_len = (void*) NLMSG_TAIL(n) - (void*) tail_list;
359 tail->rta_len = (void*) NLMSG_TAIL(n) - (void*) tail;
362 *argc_p = ematch_argc;
363 *argv_p = ematch_argv;
365 return 0;
368 static int print_ematch_seq(FILE *fd, struct rtattr **tb, int start,
369 int prefix)
371 int n, i = start;
372 struct tcf_ematch_hdr *hdr;
373 int dlen;
374 void *data;
376 for (;;) {
377 if (tb[i] == NULL)
378 return -1;
380 dlen = RTA_PAYLOAD(tb[i]) - sizeof(*hdr);
381 data = (void *) RTA_DATA(tb[i]) + sizeof(*hdr);
383 if (dlen < 0)
384 return -1;
386 hdr = RTA_DATA(tb[i]);
388 if (hdr->flags & TCF_EM_INVERT)
389 fprintf(fd, "NOT ");
391 if (hdr->kind == 0) {
392 __u32 ref;
394 if (dlen < sizeof(__u32))
395 return -1;
397 ref = *(__u32 *) data;
398 fprintf(fd, "(\n");
399 for (n = 0; n <= prefix; n++)
400 fprintf(fd, " ");
401 if (print_ematch_seq(fd, tb, ref + 1, prefix + 1) < 0)
402 return -1;
403 for (n = 0; n < prefix; n++)
404 fprintf(fd, " ");
405 fprintf(fd, ") ");
407 } else {
408 struct ematch_util *e;
410 e = get_ematch_kind_num(hdr->kind);
411 if (e == NULL)
412 fprintf(fd, "[unknown ematch %d]\n",
413 hdr->kind);
414 else {
415 fprintf(fd, "%s(", e->kind);
416 if (e->print_eopt(fd, hdr, data, dlen) < 0)
417 return -1;
418 fprintf(fd, ")\n");
420 if (hdr->flags & TCF_EM_REL_MASK)
421 for (n = 0; n < prefix; n++)
422 fprintf(fd, " ");
425 switch (hdr->flags & TCF_EM_REL_MASK) {
426 case TCF_EM_REL_AND:
427 fprintf(fd, "AND ");
428 break;
430 case TCF_EM_REL_OR:
431 fprintf(fd, "OR ");
432 break;
434 default:
435 return 0;
438 i++;
441 return 0;
444 static int print_ematch_list(FILE *fd, struct tcf_ematch_tree_hdr *hdr,
445 struct rtattr *rta)
447 int err = -1;
448 struct rtattr **tb;
450 tb = malloc((hdr->nmatches + 1) * sizeof(struct rtattr *));
451 if (tb == NULL)
452 return -1;
454 if (hdr->nmatches > 0) {
455 if (parse_rtattr_nested(tb, hdr->nmatches, rta) < 0)
456 goto errout;
458 fprintf(fd, "\n ");
459 if (print_ematch_seq(fd, tb, 1, 1) < 0)
460 goto errout;
463 err = 0;
464 errout:
465 free(tb);
466 return err;
469 int print_ematch(FILE *fd, const struct rtattr *rta)
471 struct rtattr *tb[TCA_EMATCH_TREE_MAX+1];
472 struct tcf_ematch_tree_hdr *hdr;
474 if (parse_rtattr_nested(tb, TCA_EMATCH_TREE_MAX, rta) < 0)
475 return -1;
477 if (tb[TCA_EMATCH_TREE_HDR] == NULL) {
478 fprintf(stderr, "Missing ematch tree header\n");
479 return -1;
482 if (tb[TCA_EMATCH_TREE_LIST] == NULL) {
483 fprintf(stderr, "Missing ematch tree list\n");
484 return -1;
487 if (RTA_PAYLOAD(tb[TCA_EMATCH_TREE_HDR]) < sizeof(*hdr)) {
488 fprintf(stderr, "Ematch tree header size mismatch\n");
489 return -1;
492 hdr = RTA_DATA(tb[TCA_EMATCH_TREE_HDR]);
494 return print_ematch_list(fd, hdr, tb[TCA_EMATCH_TREE_LIST]);