]>
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>
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 */
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
= { .flags
= t
->relation
};
183 hdr
.flags
|= TCF_EM_INVERT
;
185 addattr_l(n
, MAX_MSG
, index
++, NULL
, 0);
188 __u32 r
= t
->child_ref
;
190 addraw_l(n
, MAX_MSG
, &hdr
, sizeof(hdr
));
191 addraw_l(n
, MAX_MSG
, &r
, sizeof(r
));
195 struct ematch_util
*e
;
200 strncpy(buf
, (char *) t
->args
->data
, sizeof(buf
)-1);
201 e
= get_ematch_kind(buf
);
203 fprintf(stderr
, "Unknown ematch \"%s\"\n",
208 err
= lookup_map_id(buf
, &num
, EMATCH_MAP
);
211 map_warning(e
->kind_num
, buf
);
216 if (e
->parse_eopt(n
, &hdr
, t
->args
->next
) < 0)
220 tail
->rta_len
= (void *) NLMSG_TAIL(n
) - (void *) tail
;
226 static int flatten_tree(struct ematch
*head
, struct ematch
*tree
)
235 for (t
= head
; t
->next
; t
= t
->next
);
236 t
->next
= tree
->child
;
237 count
+= flatten_tree(head
, tree
->child
);
240 if (tree
->relation
== 0)
246 for (i
= 0, t
= head
; t
; t
= t
->next
, i
++)
249 for (t
= head
; t
; t
= t
->next
)
251 t
->child_ref
= t
->child
->index
;
256 int em_parse_error(int err
, struct bstr
*args
, struct bstr
*carg
,
257 struct ematch_util
*e
, char *fmt
, ...)
262 vfprintf(stderr
, fmt
, a
);
266 fprintf(stderr
, ": %s\n... ", ematch_err
);
268 fprintf(stderr
, "\n... ");
270 while (ematch_argc
< begin_argc
) {
271 if (ematch_argc
== (begin_argc
- 1))
272 fprintf(stderr
, ">>%s<< ", *begin_argv
);
274 fprintf(stderr
, "%s ", *begin_argv
);
279 fprintf(stderr
, "...\n");
282 fprintf(stderr
, "... %s(", e
->kind
);
284 fprintf(stderr
, "%s", args
== carg
? ">>" : "");
285 bstr_print(stderr
, args
, 1);
286 fprintf(stderr
, "%s%s", args
== carg
? "<<" : "",
287 args
->next
? " " : "");
290 fprintf(stderr
, ")...\n");
297 "where: EXPR := TERM [ { and | or } EXPR ]\n" \
298 " TERM := [ not ] { MATCH | '(' EXPR ')' }\n" \
299 " MATCH := module '(' ARGS ')'\n" \
300 " ARGS := ARG1 ARG2 ...\n" \
302 "Example: a(x y) and not (b(x) or c(x y z))\n");
304 e
->print_usage(stderr
);
309 static inline void free_ematch_err(void)
317 extern int ematch_parse(void);
319 int parse_ematch(int *argc_p
, char ***argv_p
, int tca_id
, struct nlmsghdr
*n
)
321 begin_argc
= ematch_argc
= *argc_p
;
322 begin_argv
= ematch_argv
= *argv_p
;
324 if (ematch_parse()) {
325 int err
= em_parse_error(EINVAL
, NULL
, NULL
, NULL
,
333 /* undo look ahead by parser */
338 struct rtattr
*tail
, *tail_list
;
340 struct tcf_ematch_tree_hdr hdr
= {
341 .nmatches
= flatten_tree(ematch_root
, ematch_root
),
342 .progid
= TCF_EM_PROG_TC
345 tail
= NLMSG_TAIL(n
);
346 addattr_l(n
, MAX_MSG
, tca_id
, NULL
, 0);
347 addattr_l(n
, MAX_MSG
, TCA_EMATCH_TREE_HDR
, &hdr
, sizeof(hdr
));
349 tail_list
= NLMSG_TAIL(n
);
350 addattr_l(n
, MAX_MSG
, TCA_EMATCH_TREE_LIST
, NULL
, 0);
352 if (parse_tree(n
, ematch_root
) < 0)
355 tail_list
->rta_len
= (void *) NLMSG_TAIL(n
) - (void *) tail_list
;
356 tail
->rta_len
= (void *) NLMSG_TAIL(n
) - (void *) tail
;
359 *argc_p
= ematch_argc
;
360 *argv_p
= ematch_argv
;
365 static int print_ematch_seq(FILE *fd
, struct rtattr
**tb
, int start
,
369 struct tcf_ematch_hdr
*hdr
;
377 dlen
= RTA_PAYLOAD(tb
[i
]) - sizeof(*hdr
);
378 data
= (void *) RTA_DATA(tb
[i
]) + sizeof(*hdr
);
383 hdr
= RTA_DATA(tb
[i
]);
385 if (hdr
->flags
& TCF_EM_INVERT
)
388 if (hdr
->kind
== 0) {
391 if (dlen
< sizeof(__u32
))
394 ref
= *(__u32
*) data
;
396 for (n
= 0; n
<= prefix
; n
++)
398 if (print_ematch_seq(fd
, tb
, ref
+ 1, prefix
+ 1) < 0)
400 for (n
= 0; n
< prefix
; n
++)
405 struct ematch_util
*e
;
407 e
= get_ematch_kind_num(hdr
->kind
);
409 fprintf(fd
, "[unknown ematch %d]\n",
412 fprintf(fd
, "%s(", e
->kind
);
413 if (e
->print_eopt(fd
, hdr
, data
, dlen
) < 0)
417 if (hdr
->flags
& TCF_EM_REL_MASK
)
418 for (n
= 0; n
< prefix
; n
++)
422 switch (hdr
->flags
& TCF_EM_REL_MASK
) {
441 static int print_ematch_list(FILE *fd
, struct tcf_ematch_tree_hdr
*hdr
,
447 tb
= malloc((hdr
->nmatches
+ 1) * sizeof(struct rtattr
*));
451 if (hdr
->nmatches
> 0) {
452 if (parse_rtattr_nested(tb
, hdr
->nmatches
, rta
) < 0)
456 if (print_ematch_seq(fd
, tb
, 1, 1) < 0)
466 int print_ematch(FILE *fd
, const struct rtattr
*rta
)
468 struct rtattr
*tb
[TCA_EMATCH_TREE_MAX
+1];
469 struct tcf_ematch_tree_hdr
*hdr
;
471 if (parse_rtattr_nested(tb
, TCA_EMATCH_TREE_MAX
, rta
) < 0)
474 if (tb
[TCA_EMATCH_TREE_HDR
] == NULL
) {
475 fprintf(stderr
, "Missing ematch tree header\n");
479 if (tb
[TCA_EMATCH_TREE_LIST
] == NULL
) {
480 fprintf(stderr
, "Missing ematch tree list\n");
484 if (RTA_PAYLOAD(tb
[TCA_EMATCH_TREE_HDR
]) < sizeof(*hdr
)) {
485 fprintf(stderr
, "Ematch tree header size mismatch\n");
489 hdr
= RTA_DATA(tb
[TCA_EMATCH_TREE_HDR
]);
491 return print_ematch_list(fd
, hdr
, tb
[TCA_EMATCH_TREE_LIST
]);
494 struct bstr
*bstr_alloc(const char *text
)
496 struct bstr
*b
= calloc(1, sizeof(*b
));
501 b
->data
= strdup(text
);
502 if (b
->data
== NULL
) {
507 b
->len
= strlen(text
);
512 unsigned long bstrtoul(const struct bstr
*b
)
518 memcpy(buf
, b
->data
, b
->len
);
521 l
= strtoul(buf
, &inv
, 0);
522 if (l
== ULONG_MAX
|| inv
== buf
)
528 void bstr_print(FILE *fd
, const struct bstr
*b
, int ascii
)
534 for (i
= 0; i
< b
->len
; i
++)
535 fprintf(fd
, "%c", isprint(s
[i
]) ? s
[i
] : '.');
537 for (i
= 0; i
< b
->len
; i
++)
538 fprintf(fd
, "%02x", s
[i
]);
540 for (i
= 0; i
< b
->len
; i
++)
541 fprintf(fd
, "%c", isprint(s
[i
]) ? s
[i
] : '.');
546 void print_ematch_tree(const struct ematch
*tree
)
548 const struct ematch
*t
;
550 for (t
= tree
; t
; t
= t
->next
) {
556 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
)