19 #include <netlink-private/netlink.h>
20 #include <netlink-private/tc.h>
21 #include <netlink/netlink.h>
22 #include <netlink/route/classifier.h>
23 #include <netlink/route/cls/ematch.h>
24 #include <netlink/route/cls/ematch/cmp.h>
26 #include "ematch_syntax.h"
27 #include "ematch_grammar.h"
34 static NL_LIST_HEAD(ematch_ops_list);
50 NL_DBG(1,
"ematch module \"%s\" registered\n", ops->eo_name);
52 nl_list_add_tail(&ops->eo_list, &ematch_ops_list);
69 nl_list_for_each_entry(ops, &ematch_ops_list, eo_list)
70 if (ops->eo_kind == kind)
88 nl_list_for_each_entry(ops, &ematch_ops_list, eo_list)
89 if (!strcasecmp(ops->eo_name, name))
110 struct rtnl_ematch *e;
112 if (!(e = calloc(1,
sizeof(*e))))
115 NL_DBG(2,
"allocated ematch %p\n", e);
117 NL_INIT_LIST_HEAD(&e->e_list);
118 NL_INIT_LIST_HEAD(&e->e_childs);
131 struct rtnl_ematch *child)
133 if (parent->e_kind != TCF_EM_CONTAINER)
134 return -NLE_OPNOTSUPP;
136 NL_DBG(2,
"added ematch %p \"%s\" to container %p\n",
137 child, child->e_ops->eo_name, parent);
139 nl_list_add_tail(&child->e_list, &parent->e_childs);
150 NL_DBG(2,
"unlinked ematch %p from any lists\n", ematch);
152 if (!nl_list_empty(&ematch->e_childs))
153 NL_DBG(1,
"warning: ematch %p with childs was unlinked\n",
156 nl_list_del(&ematch->e_list);
157 nl_init_list_head(&ematch->e_list);
160 void rtnl_ematch_free(
struct rtnl_ematch *ematch)
162 NL_DBG(2,
"freed ematch %p\n", ematch);
164 free(ematch->e_data);
168 int rtnl_ematch_set_ops(
struct rtnl_ematch *ematch,
struct rtnl_ematch_ops *ops)
174 ematch->e_kind = ops->eo_kind;
176 if (ops->eo_datalen) {
177 ematch->e_data = calloc(1, ops->eo_datalen);
181 ematch->e_datalen = ops->eo_datalen;
187 int rtnl_ematch_set_kind(
struct rtnl_ematch *ematch, uint16_t kind)
194 ematch->e_kind = kind;
197 rtnl_ematch_set_ops(ematch, ops);
202 int rtnl_ematch_set_name(
struct rtnl_ematch *ematch,
const char *name)
210 return -NLE_OPNOTSUPP;
212 rtnl_ematch_set_ops(ematch, ops);
217 void rtnl_ematch_set_flags(
struct rtnl_ematch *ematch, uint16_t flags)
219 ematch->e_flags |= flags;
222 void rtnl_ematch_unset_flags(
struct rtnl_ematch *ematch, uint16_t flags)
224 ematch->e_flags &= ~flags;
227 uint16_t rtnl_ematch_get_flags(
struct rtnl_ematch *ematch)
229 return ematch->e_flags;
232 void *rtnl_ematch_data(
struct rtnl_ematch *ematch)
234 return ematch->e_data;
249 struct rtnl_ematch_tree *tree;
251 if (!(tree = calloc(1,
sizeof(*tree))))
254 NL_INIT_LIST_HEAD(&tree->et_list);
255 tree->et_progid = progid;
257 NL_DBG(2,
"allocated new ematch tree %p, progid=%u\n", tree, progid);
264 struct rtnl_ematch *pos, *next;
266 nl_list_for_each_entry_safe(pos, next, head, e_list) {
267 if (!nl_list_empty(&pos->e_childs))
268 free_ematch_list(&pos->e_childs);
269 rtnl_ematch_free(pos);
284 free_ematch_list(&tree->et_list);
287 NL_DBG(2,
"Freed ematch tree %p\n", tree);
296 struct rtnl_ematch *ematch)
298 nl_list_add_tail(&ematch->e_list, &tree->et_list);
301 static inline uint32_t container_ref(
struct rtnl_ematch *ematch)
303 return *((uint32_t *) rtnl_ematch_data(ematch));
306 static int link_tree(
struct rtnl_ematch *index[],
int nmatches,
int pos,
309 struct rtnl_ematch *ematch;
312 for (i = pos; i < nmatches; i++) {
315 nl_list_add_tail(&ematch->e_list, root);
317 if (ematch->e_kind == TCF_EM_CONTAINER)
318 link_tree(index, nmatches, container_ref(ematch),
321 if (!(ematch->e_flags & TCF_EM_REL_MASK))
329 static struct nla_policy tree_policy[TCA_EMATCH_TREE_MAX+1] = {
330 [TCA_EMATCH_TREE_HDR] = { .
minlen=
sizeof(
struct tcf_ematch_tree_hdr) },
331 [TCA_EMATCH_TREE_LIST] = { .type =
NLA_NESTED },
341 struct nlattr *a, *tb[TCA_EMATCH_TREE_MAX+1];
342 struct tcf_ematch_tree_hdr *thdr;
343 struct rtnl_ematch_tree *tree;
344 struct rtnl_ematch **index;
345 int nmatches = 0, err, remaining;
347 NL_DBG(2,
"Parsing attribute %p as ematch tree\n", attr);
353 if (!tb[TCA_EMATCH_TREE_HDR])
354 return -NLE_MISSING_ATTR;
356 thdr =
nla_data(tb[TCA_EMATCH_TREE_HDR]);
359 if (thdr->nmatches == 0) {
360 NL_DBG(2,
"Ignoring empty ematch configuration\n");
364 if (!tb[TCA_EMATCH_TREE_LIST])
365 return -NLE_MISSING_ATTR;
367 NL_DBG(2,
"ematch tree found with nmatches=%u, progid=%u\n",
368 thdr->nmatches, thdr->progid);
375 if (thdr->nmatches > (
nla_len(tb[TCA_EMATCH_TREE_LIST]) /
379 if (!(index = calloc(thdr->nmatches,
sizeof(
struct rtnl_ematch *))))
389 struct tcf_ematch_hdr *hdr;
390 struct rtnl_ematch *ematch;
394 NL_DBG(3,
"parsing ematch attribute %d, len=%u\n",
397 if (
nla_len(a) <
sizeof(*hdr)) {
403 if (nmatches >= thdr->nmatches) {
409 data =
nla_data(a) + NLA_ALIGN(
sizeof(*hdr));
410 len =
nla_len(a) - NLA_ALIGN(
sizeof(*hdr));
412 NL_DBG(3,
"ematch attribute matchid=%u, kind=%u, flags=%u\n",
413 hdr->matchid, hdr->kind, hdr->flags);
419 if (hdr->kind == TCF_EM_CONTAINER &&
420 *((uint32_t *) data) >= thdr->nmatches) {
430 ematch->e_id = hdr->matchid;
431 ematch->e_kind = hdr->kind;
432 ematch->e_flags = hdr->flags;
435 if (ops->eo_minlen && len < ops->eo_minlen) {
436 rtnl_ematch_free(ematch);
441 rtnl_ematch_set_ops(ematch, ops);
444 (err = ops->eo_parse(ematch, data, len)) < 0) {
445 rtnl_ematch_free(ematch);
450 NL_DBG(3,
"index[%d] = %p\n", nmatches, ematch);
451 index[nmatches++] = ematch;
454 if (nmatches != thdr->nmatches) {
459 err = link_tree(index, nmatches, 0, &tree->et_list);
474 static void dump_ematch_sequence(
struct nl_list_head *head,
477 struct rtnl_ematch *match;
479 nl_list_for_each_entry(match, head, e_list) {
480 if (match->e_flags & TCF_EM_INVERT)
483 if (match->e_kind == TCF_EM_CONTAINER) {
485 dump_ematch_sequence(&match->e_childs, p);
487 }
else if (!match->e_ops) {
488 nl_dump(p,
"[unknown ematch %d]", match->e_kind);
490 if (match->e_ops->eo_dump)
491 match->e_ops->eo_dump(match, p);
496 switch (match->e_flags & TCF_EM_REL_MASK) {
510 void rtnl_ematch_tree_dump(
struct rtnl_ematch_tree *tree,
516 dump_ematch_sequence(&tree->et_list, p);
520 static int update_container_index(
struct nl_list_head *list,
int *index)
522 struct rtnl_ematch *e;
524 nl_list_for_each_entry(e, list, e_list)
525 e->e_index = (*index)++;
527 nl_list_for_each_entry(e, list, e_list) {
528 if (e->e_kind == TCF_EM_CONTAINER) {
531 if (nl_list_empty(&e->e_childs))
532 return -NLE_OBJ_NOTFOUND;
534 *((uint32_t *) e->e_data) = *index;
536 err = update_container_index(&e->e_childs, index);
545 static int fill_ematch_sequence(
struct nl_msg *msg,
struct nl_list_head *list)
547 struct rtnl_ematch *e;
549 nl_list_for_each_entry(e, list, e_list) {
550 struct tcf_ematch_hdr match = {
564 if (e->e_ops->eo_fill)
565 err = e->e_ops->eo_fill(e, msg);
566 else if (e->e_flags & TCF_EM_SIMPLE)
568 else if (e->e_datalen > 0)
571 NL_DBG(3,
"msg %p: added ematch [%d] id=%d kind=%d flags=%d\n",
572 msg, e->e_index, match.matchid, match.kind, match.flags);
580 nl_list_for_each_entry(e, list, e_list) {
581 if (e->e_kind == TCF_EM_CONTAINER &&
582 fill_ematch_sequence(msg, &e->e_childs) < 0)
589 int rtnl_ematch_fill_attr(
struct nl_msg *msg,
int attrid,
590 struct rtnl_ematch_tree *tree)
592 struct tcf_ematch_tree_hdr thdr = {
593 .progid = tree->et_progid,
595 struct nlattr *list, *topattr;
600 err = update_container_index(&tree->et_list, &index);
605 goto nla_put_failure;
607 thdr.nmatches = index;
608 NLA_PUT(msg, TCA_EMATCH_TREE_HDR,
sizeof(thdr), &thdr);
611 goto nla_put_failure;
613 if (fill_ematch_sequence(msg, &tree->et_list) < 0)
614 goto nla_put_failure;
628 extern int ematch_parse(
void *,
char **,
struct nl_list_head *);
630 int rtnl_ematch_parse_expr(
const char *expr,
char **errp,
631 struct rtnl_ematch_tree **result)
633 struct rtnl_ematch_tree *tree;
635 yyscan_t scanner = NULL;
638 NL_DBG(2,
"Parsing ematch expression \"%s\"\n", expr);
643 if ((err = ematch_lex_init(&scanner)) < 0) {
648 buf = ematch__scan_string(expr, scanner);
650 if ((err = ematch_parse(scanner, errp, &tree->et_list)) != 0) {
651 ematch__delete_buffer(buf, scanner);
652 err = -NLE_PARSE_ERR;
657 ematch_lex_destroy(scanner);
665 ematch_lex_destroy(scanner);
672 static const char *layer_txt[] = {
673 [TCF_LAYER_LINK] =
"eth",
674 [TCF_LAYER_NETWORK] =
"ip",
675 [TCF_LAYER_TRANSPORT] =
"tcp",
678 char *rtnl_ematch_offset2txt(uint8_t layer, uint16_t offset,
char *buf,
size_t len)
680 snprintf(buf, len,
"%s+%u",
681 (layer <= TCF_LAYER_MAX) ? layer_txt[layer] :
"?",
687 static const char *operand_txt[] = {
688 [TCF_EM_OPND_EQ] =
"=",
689 [TCF_EM_OPND_LT] =
"<",
690 [TCF_EM_OPND_GT] =
">",
693 char *rtnl_ematch_opnd2txt(uint8_t opnd,
char *buf,
size_t len)
695 snprintf(buf, len,
"%s",
696 opnd <= ARRAY_SIZE(operand_txt) ? operand_txt[opnd] :
"?");