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>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
29 #define EMATCH_MAP "/etc/iproute2/ematch_map"
31 static struct ematch_util *ematch_list;
33 /* export to bison parser */
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)
45 "Error: Unable to find ematch \"%s\" in %s\n" \
46 "Please assign a unique ID to the ematch kind the suggested " \
49 kind, EMATCH_MAP, num, kind);
52 static int lookup_map(__u16 num, char *dst, int len, const char *file)
56 FILE *fd = fopen(file, "r");
61 while (fgets(buf, sizeof(buf), fd)) {
62 char namebuf[512], *p = buf;
65 while (*p == ' ' || *p == '\t')
67 if (*p == '#' || *p == '\n' || *p == 0)
70 if (sscanf(p, "%d %s", &id, namebuf) != 2) {
71 fprintf(stderr, "ematch map %s corrupted at %s\n",
78 strncpy(dst, namebuf, len - 1);
90 static int lookup_map_id(char *kind, int *dst, const char *file)
94 FILE *fd = fopen(file, "r");
99 while (fgets(buf, sizeof(buf), fd)) {
100 char namebuf[512], *p = buf;
103 while (*p == ' ' || *p == '\t')
105 if (*p == '#' || *p == '\n' || *p == 0)
108 if (sscanf(p, "%d %s", &id, namebuf) != 2) {
109 fprintf(stderr, "ematch map %s corrupted at %s\n",
114 if (!strcasecmp(namebuf, kind)) {
129 static struct ematch_util *get_ematch_kind(char *kind)
134 struct ematch_util *e;
136 for (e = ematch_list; e; e = e->next) {
137 if (strcmp(e->kind, kind) == 0)
141 snprintf(buf, sizeof(buf), "em_%s.so", kind);
142 dlh = dlopen(buf, RTLD_LAZY);
146 dlh = body = dlopen(NULL, RTLD_LAZY);
152 snprintf(buf, sizeof(buf), "%s_ematch_util", kind);
157 e->next = ematch_list;
163 static struct ematch_util *get_ematch_kind_num(__u16 kind)
167 if (lookup_map(kind, name, sizeof(name), EMATCH_MAP) < 0)
170 return get_ematch_kind(name);
173 static int parse_tree(struct nlmsghdr *n, struct ematch *tree)
178 for (t = tree; t; t = t->next) {
179 struct rtattr *tail = NLMSG_TAIL(n);
180 struct tcf_ematch_hdr hdr = {
185 hdr.flags |= TCF_EM_INVERT;
187 addattr_l(n, MAX_MSG, index++, NULL, 0);
190 __u32 r = t->child_ref;
191 addraw_l(n, MAX_MSG, &hdr, sizeof(hdr));
192 addraw_l(n, MAX_MSG, &r, sizeof(r));
196 struct ematch_util *e;
201 strncpy(buf, (char*) t->args->data, sizeof(buf)-1);
202 e = get_ematch_kind(buf);
204 fprintf(stderr, "Unknown ematch \"%s\"\n",
209 err = lookup_map_id(buf, &num, EMATCH_MAP);
212 map_warning(e->kind_num, buf);
217 if (e->parse_eopt(n, &hdr, t->args->next) < 0)
221 tail->rta_len = (void*) NLMSG_TAIL(n) - (void*) tail;
227 static int flatten_tree(struct ematch *head, struct ematch *tree)
236 for (t = head; t->next; t = t->next);
237 t->next = tree->child;
238 count += flatten_tree(head, tree->child);
241 if (tree->relation == 0)
247 for (i = 0, t = head; t; t = t->next, i++)
250 for (t = head; t; t = t->next)
252 t->child_ref = t->child->index;
257 int em_parse_error(int err, struct bstr *args, struct bstr *carg,
258 struct ematch_util *e, char *fmt, ...)
263 vfprintf(stderr, fmt, a);
267 fprintf(stderr, ": %s\n... ", ematch_err);
269 fprintf(stderr, "\n... ");
271 while (ematch_argc < begin_argc) {
272 if (ematch_argc == (begin_argc - 1))
273 fprintf(stderr, ">>%s<< ", *begin_argv);
275 fprintf(stderr, "%s ", *begin_argv);
280 fprintf(stderr, "...\n");
283 fprintf(stderr, "... %s(", e->kind);
285 fprintf(stderr, "%s", args == carg ? ">>" : "");
286 bstr_print(stderr, args, 1);
287 fprintf(stderr, "%s%s", args == carg ? "<<" : "",
288 args->next ? " " : "");
291 fprintf(stderr, ")...\n");
298 "where: EXPR := TERM [ { and | or } EXPR ]\n" \
299 " TERM := [ not ] { MATCH | '(' EXPR ')' }\n" \
300 " MATCH := module '(' ARGS ')'\n" \
301 " ARGS := ARG1 ARG2 ...\n" \
303 "Example: a(x y) and not (b(x) or c(x y z))\n");
305 e->print_usage(stderr);
310 static inline void free_ematch_err(void)
318 extern int ematch_parse(void);
320 int parse_ematch(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
322 begin_argc = ematch_argc = *argc_p;
323 begin_argv = ematch_argv = *argv_p;
325 if (ematch_parse()) {
326 int err = em_parse_error(EINVAL, NULL, NULL, NULL,
334 /* undo look ahead by parser */
339 struct rtattr *tail, *tail_list;
341 struct tcf_ematch_tree_hdr hdr = {
342 .nmatches = flatten_tree(ematch_root, ematch_root),
343 .progid = TCF_EM_PROG_TC
346 tail = NLMSG_TAIL(n);
347 addattr_l(n, MAX_MSG, tca_id, NULL, 0);
348 addattr_l(n, MAX_MSG, TCA_EMATCH_TREE_HDR, &hdr, sizeof(hdr));
350 tail_list = NLMSG_TAIL(n);
351 addattr_l(n, MAX_MSG, TCA_EMATCH_TREE_LIST, NULL, 0);
353 if (parse_tree(n, ematch_root) < 0)
356 tail_list->rta_len = (void*) NLMSG_TAIL(n) - (void*) tail_list;
357 tail->rta_len = (void*) NLMSG_TAIL(n) - (void*) tail;
360 *argc_p = ematch_argc;
361 *argv_p = ematch_argv;
366 static int print_ematch_seq(FILE *fd, struct rtattr **tb, int start,
370 struct tcf_ematch_hdr *hdr;
378 dlen = RTA_PAYLOAD(tb[i]) - sizeof(*hdr);
379 data = (void *) RTA_DATA(tb[i]) + sizeof(*hdr);
384 hdr = RTA_DATA(tb[i]);
386 if (hdr->flags & TCF_EM_INVERT)
389 if (hdr->kind == 0) {
392 if (dlen < sizeof(__u32))
395 ref = *(__u32 *) data;
397 for (n = 0; n <= prefix; n++)
399 if (print_ematch_seq(fd, tb, ref + 1, prefix + 1) < 0)
401 for (n = 0; n < prefix; n++)
406 struct ematch_util *e;
408 e = get_ematch_kind_num(hdr->kind);
410 fprintf(fd, "[unknown ematch %d]\n",
413 fprintf(fd, "%s(", e->kind);
414 if (e->print_eopt(fd, hdr, data, dlen) < 0)
418 if (hdr->flags & TCF_EM_REL_MASK)
419 for (n = 0; n < prefix; n++)
423 switch (hdr->flags & TCF_EM_REL_MASK) {
442 static int print_ematch_list(FILE *fd, struct tcf_ematch_tree_hdr *hdr,
448 tb = malloc((hdr->nmatches + 1) * sizeof(struct rtattr *));
452 if (hdr->nmatches > 0) {
453 if (parse_rtattr_nested(tb, hdr->nmatches, rta) < 0)
457 if (print_ematch_seq(fd, tb, 1, 1) < 0)
467 int print_ematch(FILE *fd, const struct rtattr *rta)
469 struct rtattr *tb[TCA_EMATCH_TREE_MAX+1];
470 struct tcf_ematch_tree_hdr *hdr;
472 if (parse_rtattr_nested(tb, TCA_EMATCH_TREE_MAX, rta) < 0)
475 if (tb[TCA_EMATCH_TREE_HDR] == NULL) {
476 fprintf(stderr, "Missing ematch tree header\n");
480 if (tb[TCA_EMATCH_TREE_LIST] == NULL) {
481 fprintf(stderr, "Missing ematch tree list\n");
485 if (RTA_PAYLOAD(tb[TCA_EMATCH_TREE_HDR]) < sizeof(*hdr)) {
486 fprintf(stderr, "Ematch tree header size mismatch\n");
490 hdr = RTA_DATA(tb[TCA_EMATCH_TREE_HDR]);
492 return print_ematch_list(fd, hdr, tb[TCA_EMATCH_TREE_LIST]);
495 struct bstr * bstr_alloc(const char *text)
497 struct bstr *b = calloc(1, sizeof(*b));
502 b->data = strdup(text);
503 if (b->data == NULL) {
508 b->len = strlen(text);
513 unsigned long bstrtoul(const struct bstr *b)
519 memcpy(buf, b->data, b->len);
522 l = strtoul(buf, &inv, 0);
523 if (l == ULONG_MAX || inv == buf)
529 void bstr_print(FILE *fd, const struct bstr *b, int ascii)
535 for (i = 0; i < b->len; i++)
536 fprintf(fd, "%c", isprint(s[i]) ? s[i] : '.');
538 for (i = 0; i < b->len; i++)
539 fprintf(fd, "%02x", s[i]);
541 for (i = 0; i < b->len; i++)
542 fprintf(fd, "%c", isprint(s[i]) ? s[i] : '.');
547 void print_ematch_tree(const struct ematch *tree)
549 const struct ematch *t;
551 for (t = tree; t; t = t->next) {
557 print_ematch_tree(t->child);
561 for (b = t->args; b; b = b->next)
562 printf("%s%s", b->data, b->next ? " " : "");
565 if (t->relation == TCF_EM_REL_AND)
567 else if (t->relation == TCF_EM_REL_OR)