]>
git.proxmox.com Git - mirror_iproute2.git/blob - tc/m_ematch.c
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>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
28 #define EMATCH_MAP "/etc/iproute2/ematch_map"
30 static struct ematch_util
*ematch_list
;
32 /* export to bison parser */
36 struct ematch
*ematch_root
;
38 static int begin_argc
;
39 static char **begin_argv
;
41 static inline void map_warning(int num
, char *kind
)
44 "Error: Unable to find ematch \"%s\" in %s\n" \
45 "Please assign a unique ID to the ematch kind the suggested " \
48 kind
, EMATCH_MAP
, num
, kind
);
51 static int lookup_map(__u16 num
, char *dst
, int len
, const char *file
)
55 FILE *fd
= fopen(file
, "r");
60 while (fgets(buf
, sizeof(buf
), fd
)) {
61 char namebuf
[512], *p
= buf
;
64 while (*p
== ' ' || *p
== '\t')
66 if (*p
== '#' || *p
== '\n' || *p
== 0)
69 if (sscanf(p
, "%d %s", &id
, namebuf
) != 2) {
70 fprintf(stderr
, "ematch map %s corrupted at %s\n",
77 strncpy(dst
, namebuf
, len
- 1);
89 static int lookup_map_id(char *kind
, int *dst
, const char *file
)
93 FILE *fd
= fopen(file
, "r");
98 while (fgets(buf
, sizeof(buf
), fd
)) {
99 char namebuf
[512], *p
= buf
;
102 while (*p
== ' ' || *p
== '\t')
104 if (*p
== '#' || *p
== '\n' || *p
== 0)
107 if (sscanf(p
, "%d %s", &id
, namebuf
) != 2) {
108 fprintf(stderr
, "ematch map %s corrupted at %s\n",
113 if (!strcasecmp(namebuf
, kind
)) {
128 static struct ematch_util
*get_ematch_kind(char *kind
)
133 struct ematch_util
*e
;
135 for (e
= ematch_list
; e
; e
= e
->next
) {
136 if (strcmp(e
->kind
, kind
) == 0)
140 snprintf(buf
, sizeof(buf
), "em_%s.so", kind
);
141 dlh
= dlopen(buf
, RTLD_LAZY
);
145 dlh
= body
= dlopen(NULL
, RTLD_LAZY
);
151 snprintf(buf
, sizeof(buf
), "%s_ematch_util", kind
);
156 e
->next
= ematch_list
;
162 static struct ematch_util
*get_ematch_kind_num(__u16 kind
)
166 if (lookup_map(kind
, name
, sizeof(name
), EMATCH_MAP
) < 0)
169 return get_ematch_kind(name
);
172 static int parse_tree(struct nlmsghdr
*n
, struct ematch
*tree
)
177 for (t
= tree
; t
; t
= t
->next
) {
179 struct tcf_ematch_hdr hdr
= { .flags
= t
->relation
};
182 hdr
.flags
|= TCF_EM_INVERT
;
184 tail
= addattr_nest(n
, MAX_MSG
, index
++);
187 __u32 r
= t
->child_ref
;
189 addraw_l(n
, MAX_MSG
, &hdr
, sizeof(hdr
));
190 addraw_l(n
, MAX_MSG
, &r
, sizeof(r
));
194 struct ematch_util
*e
;
199 strncpy(buf
, (char *) t
->args
->data
, sizeof(buf
)-1);
200 e
= get_ematch_kind(buf
);
202 fprintf(stderr
, "Unknown ematch \"%s\"\n",
207 err
= lookup_map_id(buf
, &num
, EMATCH_MAP
);
210 map_warning(e
->kind_num
, buf
);
215 if (e
->parse_eopt(n
, &hdr
, t
->args
->next
) < 0)
219 addattr_nest_end(n
, tail
);
225 static int flatten_tree(struct ematch
*head
, struct ematch
*tree
)
234 for (t
= head
; t
->next
; t
= t
->next
);
235 t
->next
= tree
->child
;
236 count
+= flatten_tree(head
, tree
->child
);
239 if (tree
->relation
== 0)
245 for (i
= 0, t
= head
; t
; t
= t
->next
, i
++)
248 for (t
= head
; t
; t
= t
->next
)
250 t
->child_ref
= t
->child
->index
;
255 int em_parse_error(int err
, struct bstr
*args
, struct bstr
*carg
,
256 struct ematch_util
*e
, char *fmt
, ...)
261 vfprintf(stderr
, fmt
, a
);
265 fprintf(stderr
, ": %s\n... ", ematch_err
);
267 fprintf(stderr
, "\n... ");
269 while (ematch_argc
< begin_argc
) {
270 if (ematch_argc
== (begin_argc
- 1))
271 fprintf(stderr
, ">>%s<< ", *begin_argv
);
273 fprintf(stderr
, "%s ", *begin_argv
);
278 fprintf(stderr
, "...\n");
281 fprintf(stderr
, "... %s(", e
->kind
);
283 fprintf(stderr
, "%s", args
== carg
? ">>" : "");
284 bstr_print(stderr
, args
, 1);
285 fprintf(stderr
, "%s%s", args
== carg
? "<<" : "",
286 args
->next
? " " : "");
289 fprintf(stderr
, ")...\n");
296 "where: EXPR := TERM [ { and | or } EXPR ]\n" \
297 " TERM := [ not ] { MATCH | '(' EXPR ')' }\n" \
298 " MATCH := module '(' ARGS ')'\n" \
299 " ARGS := ARG1 ARG2 ...\n" \
301 "Example: a(x y) and not (b(x) or c(x y z))\n");
303 e
->print_usage(stderr
);
308 static inline void free_ematch_err(void)
316 extern int ematch_parse(void);
318 int parse_ematch(int *argc_p
, char ***argv_p
, int tca_id
, struct nlmsghdr
*n
)
320 begin_argc
= ematch_argc
= *argc_p
;
321 begin_argv
= ematch_argv
= *argv_p
;
323 if (ematch_parse()) {
324 int err
= em_parse_error(EINVAL
, NULL
, NULL
, NULL
,
332 /* undo look ahead by parser */
337 struct rtattr
*tail
, *tail_list
;
339 struct tcf_ematch_tree_hdr hdr
= {
340 .nmatches
= flatten_tree(ematch_root
, ematch_root
),
341 .progid
= TCF_EM_PROG_TC
344 tail
= addattr_nest(n
, MAX_MSG
, tca_id
);
345 addattr_l(n
, MAX_MSG
, TCA_EMATCH_TREE_HDR
, &hdr
, sizeof(hdr
));
347 tail_list
= addattr_nest(n
, MAX_MSG
, TCA_EMATCH_TREE_LIST
);
349 if (parse_tree(n
, ematch_root
) < 0)
352 addattr_nest_end(n
, tail_list
);
353 addattr_nest_end(n
, tail
);
356 *argc_p
= ematch_argc
;
357 *argv_p
= ematch_argv
;
362 static int print_ematch_seq(FILE *fd
, struct rtattr
**tb
, int start
,
366 struct tcf_ematch_hdr
*hdr
;
374 dlen
= RTA_PAYLOAD(tb
[i
]) - sizeof(*hdr
);
375 data
= (void *) RTA_DATA(tb
[i
]) + sizeof(*hdr
);
380 hdr
= RTA_DATA(tb
[i
]);
382 if (hdr
->flags
& TCF_EM_INVERT
)
385 if (hdr
->kind
== 0) {
388 if (dlen
< sizeof(__u32
))
391 ref
= *(__u32
*) data
;
393 for (n
= 0; n
<= prefix
; n
++)
395 if (print_ematch_seq(fd
, tb
, ref
+ 1, prefix
+ 1) < 0)
397 for (n
= 0; n
< prefix
; n
++)
402 struct ematch_util
*e
;
404 e
= get_ematch_kind_num(hdr
->kind
);
406 fprintf(fd
, "[unknown ematch %d]\n",
409 fprintf(fd
, "%s(", e
->kind
);
410 if (e
->print_eopt(fd
, hdr
, data
, dlen
) < 0)
414 if (hdr
->flags
& TCF_EM_REL_MASK
)
415 for (n
= 0; n
< prefix
; n
++)
419 switch (hdr
->flags
& TCF_EM_REL_MASK
) {
438 static int print_ematch_list(FILE *fd
, struct tcf_ematch_tree_hdr
*hdr
,
444 tb
= malloc((hdr
->nmatches
+ 1) * sizeof(struct rtattr
*));
448 if (hdr
->nmatches
> 0) {
449 if (parse_rtattr_nested(tb
, hdr
->nmatches
, rta
) < 0)
453 if (print_ematch_seq(fd
, tb
, 1, 1) < 0)
463 int print_ematch(FILE *fd
, const struct rtattr
*rta
)
465 struct rtattr
*tb
[TCA_EMATCH_TREE_MAX
+1];
466 struct tcf_ematch_tree_hdr
*hdr
;
468 if (parse_rtattr_nested(tb
, TCA_EMATCH_TREE_MAX
, rta
) < 0)
471 if (tb
[TCA_EMATCH_TREE_HDR
] == NULL
) {
472 fprintf(stderr
, "Missing ematch tree header\n");
476 if (tb
[TCA_EMATCH_TREE_LIST
] == NULL
) {
477 fprintf(stderr
, "Missing ematch tree list\n");
481 if (RTA_PAYLOAD(tb
[TCA_EMATCH_TREE_HDR
]) < sizeof(*hdr
)) {
482 fprintf(stderr
, "Ematch tree header size mismatch\n");
486 hdr
= RTA_DATA(tb
[TCA_EMATCH_TREE_HDR
]);
488 return print_ematch_list(fd
, hdr
, tb
[TCA_EMATCH_TREE_LIST
]);
491 struct bstr
*bstr_alloc(const char *text
)
493 struct bstr
*b
= calloc(1, sizeof(*b
));
498 b
->data
= strdup(text
);
499 if (b
->data
== NULL
) {
504 b
->len
= strlen(text
);
509 unsigned long bstrtoul(const struct bstr
*b
)
515 memcpy(buf
, b
->data
, b
->len
);
518 l
= strtoul(buf
, &inv
, 0);
519 if (l
== ULONG_MAX
|| inv
== buf
)
525 void bstr_print(FILE *fd
, const struct bstr
*b
, int ascii
)
531 for (i
= 0; i
< b
->len
; i
++)
532 fprintf(fd
, "%c", isprint(s
[i
]) ? s
[i
] : '.');
534 for (i
= 0; i
< b
->len
; i
++)
535 fprintf(fd
, "%02x", s
[i
]);
537 for (i
= 0; i
< b
->len
; i
++)
538 fprintf(fd
, "%c", isprint(s
[i
]) ? s
[i
] : '.');
543 void print_ematch_tree(const struct ematch
*tree
)
545 const struct ematch
*t
;
547 for (t
= tree
; t
; t
= t
->next
) {
553 print_ematch_tree(t
->child
);
558 for (b
= t
->args
; b
; b
= b
->next
)
559 printf("%s%s", b
->data
, b
->next
? " " : "");
562 if (t
->relation
== TCF_EM_REL_AND
)
564 else if (t
->relation
== TCF_EM_REL_OR
)