]>
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 void bstr_print(FILE *fd
, const struct bstr
*b
, int ascii
);
43 static inline void map_warning(int num
, char *kind
)
46 "Error: Unable to find ematch \"%s\" in %s\n" \
47 "Please assign a unique ID to the ematch kind the suggested " \
50 kind
, EMATCH_MAP
, num
, kind
);
53 static int lookup_map(__u16 num
, char *dst
, int len
, const char *file
)
57 FILE *fd
= fopen(file
, "r");
62 while (fgets(buf
, sizeof(buf
), fd
)) {
63 char namebuf
[512], *p
= buf
;
66 while (*p
== ' ' || *p
== '\t')
68 if (*p
== '#' || *p
== '\n' || *p
== 0)
71 if (sscanf(p
, "%d %s", &id
, namebuf
) != 2) {
72 fprintf(stderr
, "ematch map %s corrupted at %s\n",
79 strncpy(dst
, namebuf
, len
- 1);
91 static int lookup_map_id(char *kind
, int *dst
, const char *file
)
95 FILE *fd
= fopen(file
, "r");
100 while (fgets(buf
, sizeof(buf
), fd
)) {
101 char namebuf
[512], *p
= buf
;
104 while (*p
== ' ' || *p
== '\t')
106 if (*p
== '#' || *p
== '\n' || *p
== 0)
109 if (sscanf(p
, "%d %s", &id
, namebuf
) != 2) {
110 fprintf(stderr
, "ematch map %s corrupted at %s\n",
115 if (!strcasecmp(namebuf
, kind
)) {
130 static struct ematch_util
*get_ematch_kind(char *kind
)
135 struct ematch_util
*e
;
137 for (e
= ematch_list
; e
; e
= e
->next
) {
138 if (strcmp(e
->kind
, kind
) == 0)
142 snprintf(buf
, sizeof(buf
), "em_%s.so", kind
);
143 dlh
= dlopen(buf
, RTLD_LAZY
);
147 dlh
= body
= dlopen(NULL
, RTLD_LAZY
);
153 snprintf(buf
, sizeof(buf
), "%s_ematch_util", kind
);
158 e
->next
= ematch_list
;
164 static struct ematch_util
*get_ematch_kind_num(__u16 kind
)
168 if (lookup_map(kind
, name
, sizeof(name
), EMATCH_MAP
) < 0)
171 return get_ematch_kind(name
);
174 static int em_parse_call(struct nlmsghdr
*n
, struct tcf_ematch_hdr
*hdr
,
175 struct ematch_util
*e
, struct ematch
*t
)
177 if (e
->parse_eopt_argv
) {
178 int argc
= 0, i
= 0, ret
;
182 for (args
= t
->args
; args
; args
= bstr_next(args
))
184 argv
= calloc(argc
, sizeof(char *));
187 for (args
= t
->args
; args
; args
= bstr_next(args
))
188 argv
[i
++] = args
->data
;
190 ret
= e
->parse_eopt_argv(n
, hdr
, argc
, argv
);
196 return e
->parse_eopt(n
, hdr
, t
->args
->next
);
199 static int parse_tree(struct nlmsghdr
*n
, struct ematch
*tree
)
204 for (t
= tree
; t
; t
= t
->next
) {
206 struct tcf_ematch_hdr hdr
= { .flags
= t
->relation
};
209 hdr
.flags
|= TCF_EM_INVERT
;
211 tail
= addattr_nest(n
, MAX_MSG
, index
++);
214 __u32 r
= t
->child_ref
;
216 addraw_l(n
, MAX_MSG
, &hdr
, sizeof(hdr
));
217 addraw_l(n
, MAX_MSG
, &r
, sizeof(r
));
221 struct ematch_util
*e
;
226 strncpy(buf
, (char *) t
->args
->data
, sizeof(buf
)-1);
227 e
= get_ematch_kind(buf
);
229 fprintf(stderr
, "Unknown ematch \"%s\"\n",
234 err
= lookup_map_id(buf
, &num
, EMATCH_MAP
);
237 map_warning(e
->kind_num
, buf
);
242 if (em_parse_call(n
, &hdr
, e
, t
) < 0)
246 addattr_nest_end(n
, tail
);
252 static int flatten_tree(struct ematch
*head
, struct ematch
*tree
)
261 for (t
= head
; t
->next
; t
= t
->next
);
262 t
->next
= tree
->child
;
263 count
+= flatten_tree(head
, tree
->child
);
266 if (tree
->relation
== 0)
272 for (i
= 0, t
= head
; t
; t
= t
->next
, i
++)
275 for (t
= head
; t
; t
= t
->next
)
277 t
->child_ref
= t
->child
->index
;
282 __attribute__((format(printf
, 5, 6)))
283 int em_parse_error(int err
, struct bstr
*args
, struct bstr
*carg
,
284 struct ematch_util
*e
, char *fmt
, ...)
289 vfprintf(stderr
, fmt
, a
);
293 fprintf(stderr
, ": %s\n... ", ematch_err
);
295 fprintf(stderr
, "\n... ");
297 while (ematch_argc
< begin_argc
) {
298 if (ematch_argc
== (begin_argc
- 1))
299 fprintf(stderr
, ">>%s<< ", *begin_argv
);
301 fprintf(stderr
, "%s ", *begin_argv
);
306 fprintf(stderr
, "...\n");
309 fprintf(stderr
, "... %s(", e
->kind
);
311 fprintf(stderr
, "%s", args
== carg
? ">>" : "");
312 bstr_print(stderr
, args
, 1);
313 fprintf(stderr
, "%s%s", args
== carg
? "<<" : "",
314 args
->next
? " " : "");
317 fprintf(stderr
, ")...\n");
324 "where: EXPR := TERM [ { and | or } EXPR ]\n" \
325 " TERM := [ not ] { MATCH | '(' EXPR ')' }\n" \
326 " MATCH := module '(' ARGS ')'\n" \
327 " ARGS := ARG1 ARG2 ...\n" \
329 "Example: a(x y) and not (b(x) or c(x y z))\n");
331 e
->print_usage(stderr
);
336 static inline void free_ematch_err(void)
344 extern int ematch_parse(void);
346 int parse_ematch(int *argc_p
, char ***argv_p
, int tca_id
, struct nlmsghdr
*n
)
348 begin_argc
= ematch_argc
= *argc_p
;
349 begin_argv
= ematch_argv
= *argv_p
;
351 if (ematch_parse()) {
352 int err
= em_parse_error(EINVAL
, NULL
, NULL
, NULL
,
360 /* undo look ahead by parser */
365 struct rtattr
*tail
, *tail_list
;
367 struct tcf_ematch_tree_hdr hdr
= {
368 .nmatches
= flatten_tree(ematch_root
, ematch_root
),
369 .progid
= TCF_EM_PROG_TC
372 tail
= addattr_nest(n
, MAX_MSG
, tca_id
);
373 addattr_l(n
, MAX_MSG
, TCA_EMATCH_TREE_HDR
, &hdr
, sizeof(hdr
));
375 tail_list
= addattr_nest(n
, MAX_MSG
, TCA_EMATCH_TREE_LIST
);
377 if (parse_tree(n
, ematch_root
) < 0)
380 addattr_nest_end(n
, tail_list
);
381 addattr_nest_end(n
, tail
);
384 *argc_p
= ematch_argc
;
385 *argv_p
= ematch_argv
;
390 static int print_ematch_seq(FILE *fd
, struct rtattr
**tb
, int start
,
394 struct tcf_ematch_hdr
*hdr
;
402 dlen
= RTA_PAYLOAD(tb
[i
]) - sizeof(*hdr
);
403 data
= (void *) RTA_DATA(tb
[i
]) + sizeof(*hdr
);
408 hdr
= RTA_DATA(tb
[i
]);
410 if (hdr
->flags
& TCF_EM_INVERT
)
413 if (hdr
->kind
== 0) {
416 if (dlen
< sizeof(__u32
))
419 ref
= *(__u32
*) data
;
421 for (n
= 0; n
<= prefix
; n
++)
423 if (print_ematch_seq(fd
, tb
, ref
+ 1, prefix
+ 1) < 0)
425 for (n
= 0; n
< prefix
; n
++)
430 struct ematch_util
*e
;
432 e
= get_ematch_kind_num(hdr
->kind
);
434 fprintf(fd
, "[unknown ematch %d]\n",
437 fprintf(fd
, "%s(", e
->kind
);
438 if (e
->print_eopt(fd
, hdr
, data
, dlen
) < 0)
442 if (hdr
->flags
& TCF_EM_REL_MASK
)
443 for (n
= 0; n
< prefix
; n
++)
447 switch (hdr
->flags
& TCF_EM_REL_MASK
) {
466 static int print_ematch_list(FILE *fd
, struct tcf_ematch_tree_hdr
*hdr
,
472 tb
= malloc((hdr
->nmatches
+ 1) * sizeof(struct rtattr
*));
476 if (hdr
->nmatches
> 0) {
477 if (parse_rtattr_nested(tb
, hdr
->nmatches
, rta
) < 0)
481 if (print_ematch_seq(fd
, tb
, 1, 1) < 0)
491 int print_ematch(FILE *fd
, const struct rtattr
*rta
)
493 struct rtattr
*tb
[TCA_EMATCH_TREE_MAX
+1];
494 struct tcf_ematch_tree_hdr
*hdr
;
496 if (parse_rtattr_nested(tb
, TCA_EMATCH_TREE_MAX
, rta
) < 0)
499 if (tb
[TCA_EMATCH_TREE_HDR
] == NULL
) {
500 fprintf(stderr
, "Missing ematch tree header\n");
504 if (tb
[TCA_EMATCH_TREE_LIST
] == NULL
) {
505 fprintf(stderr
, "Missing ematch tree list\n");
509 if (RTA_PAYLOAD(tb
[TCA_EMATCH_TREE_HDR
]) < sizeof(*hdr
)) {
510 fprintf(stderr
, "Ematch tree header size mismatch\n");
514 hdr
= RTA_DATA(tb
[TCA_EMATCH_TREE_HDR
]);
516 return print_ematch_list(fd
, hdr
, tb
[TCA_EMATCH_TREE_LIST
]);
519 struct bstr
*bstr_alloc(const char *text
)
521 struct bstr
*b
= calloc(1, sizeof(*b
));
526 b
->data
= strdup(text
);
527 if (b
->data
== NULL
) {
532 b
->len
= strlen(text
);
537 unsigned long bstrtoul(const struct bstr
*b
)
543 memcpy(buf
, b
->data
, b
->len
);
546 l
= strtoul(buf
, &inv
, 0);
547 if (l
== ULONG_MAX
|| inv
== buf
)
553 static void bstr_print(FILE *fd
, const struct bstr
*b
, int ascii
)
559 for (i
= 0; i
< b
->len
; i
++)
560 fprintf(fd
, "%c", isprint(s
[i
]) ? s
[i
] : '.');
562 for (i
= 0; i
< b
->len
; i
++)
563 fprintf(fd
, "%02x", s
[i
]);
565 for (i
= 0; i
< b
->len
; i
++)
566 fprintf(fd
, "%c", isprint(s
[i
]) ? s
[i
] : '.');