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> 25 #include <linux/tc_ematch/tc_em_cmp.h> 27 #include "ematch_syntax.h" 28 #include "ematch_grammar.h" 35 static NL_LIST_HEAD(ematch_ops_list);
51 NL_DBG(1,
"ematch module \"%s\" registered\n", ops->eo_name);
53 nl_list_add_tail(&ops->eo_list, &ematch_ops_list);
70 nl_list_for_each_entry(ops, &ematch_ops_list, eo_list)
71 if (ops->eo_kind == kind)
89 nl_list_for_each_entry(ops, &ematch_ops_list, eo_list)
90 if (!strcasecmp(ops->eo_name, name))
111 struct rtnl_ematch *e;
113 if (!(e = calloc(1,
sizeof(*e))))
116 NL_DBG(2,
"allocated ematch %p\n", e);
118 NL_INIT_LIST_HEAD(&e->e_list);
119 NL_INIT_LIST_HEAD(&e->e_childs);
132 struct rtnl_ematch *child)
134 if (parent->e_kind != TCF_EM_CONTAINER)
135 return -NLE_OPNOTSUPP;
137 NL_DBG(2,
"added ematch %p \"%s\" to container %p\n",
138 child, child->e_ops->eo_name, parent);
140 nl_list_add_tail(&child->e_list, &parent->e_childs);
151 NL_DBG(2,
"unlinked ematch %p from any lists\n", ematch);
153 if (!nl_list_empty(&ematch->e_childs))
154 NL_DBG(1,
"warning: ematch %p with childs was unlinked\n",
157 nl_list_del(&ematch->e_list);
158 nl_init_list_head(&ematch->e_list);
161 void rtnl_ematch_free(
struct rtnl_ematch *ematch)
163 NL_DBG(2,
"freed ematch %p\n", ematch);
165 free(ematch->e_data);
169 int rtnl_ematch_set_ops(
struct rtnl_ematch *ematch,
struct rtnl_ematch_ops *ops)
175 ematch->e_kind = ops->eo_kind;
177 if (ops->eo_datalen) {
178 ematch->e_data = calloc(1, ops->eo_datalen);
182 ematch->e_datalen = ops->eo_datalen;
188 int rtnl_ematch_set_kind(
struct rtnl_ematch *ematch, uint16_t kind)
195 ematch->e_kind = kind;
198 rtnl_ematch_set_ops(ematch, ops);
203 int rtnl_ematch_set_name(
struct rtnl_ematch *ematch,
const char *name)
211 return -NLE_OPNOTSUPP;
213 rtnl_ematch_set_ops(ematch, ops);
218 void rtnl_ematch_set_flags(
struct rtnl_ematch *ematch, uint16_t flags)
220 ematch->e_flags |= flags;
223 void rtnl_ematch_unset_flags(
struct rtnl_ematch *ematch, uint16_t flags)
225 ematch->e_flags &= ~flags;
228 uint16_t rtnl_ematch_get_flags(
struct rtnl_ematch *ematch)
230 return ematch->e_flags;
233 void *rtnl_ematch_data(
struct rtnl_ematch *ematch)
235 return ematch->e_data;
250 struct rtnl_ematch_tree *tree;
252 if (!(tree = calloc(1,
sizeof(*tree))))
255 NL_INIT_LIST_HEAD(&tree->et_list);
256 tree->et_progid = progid;
258 NL_DBG(2,
"allocated new ematch tree %p, progid=%u\n", tree, progid);
265 struct rtnl_ematch *pos, *next;
267 nl_list_for_each_entry_safe(pos, next, head, e_list) {
268 if (!nl_list_empty(&pos->e_childs))
269 free_ematch_list(&pos->e_childs);
270 rtnl_ematch_free(pos);
285 free_ematch_list(&tree->et_list);
287 NL_DBG(2,
"Freed ematch tree %p\n", tree);
294 struct rtnl_ematch *
new = NULL, *pos = NULL;
296 nl_list_for_each_entry(pos, src, e_list) {
301 new->e_id = pos->e_id;
302 new->e_kind = pos->e_kind;
303 new->e_flags = pos->e_flags;
304 new->e_index = pos->e_index;
305 new->e_datalen = pos->e_datalen;
308 if (rtnl_ematch_set_ops(
new, pos->e_ops))
312 if (!nl_list_empty(&pos->e_childs)) {
313 if (clone_ematch_list(&new->e_childs, &pos->e_childs) < 0)
316 nl_list_add_tail(&new->e_list, dst);
324 free_ematch_list(dst);
336 struct rtnl_ematch_tree *dst = NULL;
344 clone_ematch_list(&dst->et_list, &src->et_list);
355 struct rtnl_ematch *ematch)
357 nl_list_add_tail(&ematch->e_list, &tree->et_list);
360 static inline uint32_t container_ref(
struct rtnl_ematch *ematch)
362 return *((uint32_t *) rtnl_ematch_data(ematch));
365 static int link_tree(
struct rtnl_ematch *index[],
int nmatches,
int pos,
368 struct rtnl_ematch *ematch;
371 for (i = pos; i < nmatches; i++) {
374 nl_list_add_tail(&ematch->e_list, root);
376 if (ematch->e_kind == TCF_EM_CONTAINER)
377 link_tree(index, nmatches, container_ref(ematch),
380 if (!(ematch->e_flags & TCF_EM_REL_MASK))
388 static struct nla_policy tree_policy[TCA_EMATCH_TREE_MAX+1] = {
389 [TCA_EMATCH_TREE_HDR] = { .
minlen=
sizeof(
struct tcf_ematch_tree_hdr) },
390 [TCA_EMATCH_TREE_LIST] = { .type =
NLA_NESTED },
400 struct nlattr *a, *tb[TCA_EMATCH_TREE_MAX+1];
401 struct tcf_ematch_tree_hdr *thdr;
402 struct rtnl_ematch_tree *tree;
403 struct rtnl_ematch **index;
404 int nmatches = 0, err, remaining;
406 NL_DBG(2,
"Parsing attribute %p as ematch tree\n", attr);
412 if (!tb[TCA_EMATCH_TREE_HDR])
413 return -NLE_MISSING_ATTR;
415 thdr =
nla_data(tb[TCA_EMATCH_TREE_HDR]);
418 if (thdr->nmatches == 0) {
419 NL_DBG(2,
"Ignoring empty ematch configuration\n");
423 if (!tb[TCA_EMATCH_TREE_LIST])
424 return -NLE_MISSING_ATTR;
426 NL_DBG(2,
"ematch tree found with nmatches=%u, progid=%u\n",
427 thdr->nmatches, thdr->progid);
434 if (thdr->nmatches > (
nla_len(tb[TCA_EMATCH_TREE_LIST]) /
438 if (!(index = calloc(thdr->nmatches,
sizeof(
struct rtnl_ematch *))))
448 struct tcf_ematch_hdr *hdr;
449 struct rtnl_ematch *ematch;
453 NL_DBG(3,
"parsing ematch attribute %d, len=%u\n",
456 if (
nla_len(a) <
sizeof(*hdr)) {
462 if (nmatches >= thdr->nmatches) {
468 data = (
char *)
nla_data(a) + NLA_ALIGN(
sizeof(*hdr));
469 len =
nla_len(a) - NLA_ALIGN(
sizeof(*hdr));
471 NL_DBG(3,
"ematch attribute matchid=%u, kind=%u, flags=%u\n",
472 hdr->matchid, hdr->kind, hdr->flags);
478 if (hdr->kind == TCF_EM_CONTAINER &&
479 *((uint32_t *) data) >= thdr->nmatches) {
489 ematch->e_id = hdr->matchid;
490 ematch->e_kind = hdr->kind;
491 ematch->e_flags = hdr->flags;
494 if (ops->eo_minlen && len < ops->eo_minlen) {
495 rtnl_ematch_free(ematch);
500 rtnl_ematch_set_ops(ematch, ops);
503 (err = ops->eo_parse(ematch, data, len)) < 0) {
504 rtnl_ematch_free(ematch);
509 NL_DBG(3,
"index[%d] = %p\n", nmatches, ematch);
510 index[nmatches++] = ematch;
513 if (nmatches != thdr->nmatches) {
518 err = link_tree(index, nmatches, 0, &tree->et_list);
533 static void dump_ematch_sequence(
struct nl_list_head *head,
536 struct rtnl_ematch *match;
538 nl_list_for_each_entry(match, head, e_list) {
539 if (match->e_flags & TCF_EM_INVERT)
542 if (match->e_kind == TCF_EM_CONTAINER) {
544 dump_ematch_sequence(&match->e_childs, p);
546 }
else if (!match->e_ops) {
547 nl_dump(p,
"[unknown ematch %d]", match->e_kind);
549 if (match->e_ops->eo_dump)
550 match->e_ops->eo_dump(match, p);
555 switch (match->e_flags & TCF_EM_REL_MASK) {
569 void rtnl_ematch_tree_dump(
struct rtnl_ematch_tree *tree,
575 dump_ematch_sequence(&tree->et_list, p);
579 static int update_container_index(
struct nl_list_head *list,
int *index)
581 struct rtnl_ematch *e;
583 nl_list_for_each_entry(e, list, e_list)
584 e->e_index = (*index)++;
586 nl_list_for_each_entry(e, list, e_list) {
587 if (e->e_kind == TCF_EM_CONTAINER) {
590 if (nl_list_empty(&e->e_childs))
591 return -NLE_OBJ_NOTFOUND;
593 *((uint32_t *) e->e_data) = *index;
595 err = update_container_index(&e->e_childs, index);
604 static int fill_ematch_sequence(
struct nl_msg *msg,
struct nl_list_head *list)
606 struct rtnl_ematch *e;
608 nl_list_for_each_entry(e, list, e_list) {
609 struct tcf_ematch_hdr match = {
623 if (e->e_ops->eo_fill)
624 err = e->e_ops->eo_fill(e, msg);
625 else if (e->e_flags & TCF_EM_SIMPLE)
627 else if (e->e_datalen > 0)
630 NL_DBG(3,
"msg %p: added ematch [%d] id=%d kind=%d flags=%d\n",
631 msg, e->e_index, match.matchid, match.kind, match.flags);
639 nl_list_for_each_entry(e, list, e_list) {
640 if (e->e_kind == TCF_EM_CONTAINER &&
641 fill_ematch_sequence(msg, &e->e_childs) < 0)
648 int rtnl_ematch_fill_attr(
struct nl_msg *msg,
int attrid,
649 struct rtnl_ematch_tree *tree)
651 struct tcf_ematch_tree_hdr thdr = {
652 .progid = tree->et_progid,
654 struct nlattr *list, *topattr;
659 err = update_container_index(&tree->et_list, &index);
664 goto nla_put_failure;
666 thdr.nmatches = index;
667 NLA_PUT(msg, TCA_EMATCH_TREE_HDR,
sizeof(thdr), &thdr);
670 goto nla_put_failure;
672 if (fill_ematch_sequence(msg, &tree->et_list) < 0)
673 goto nla_put_failure;
687 extern int ematch_parse(
void *,
char **,
struct nl_list_head *);
689 int rtnl_ematch_parse_expr(
const char *expr,
char **errp,
690 struct rtnl_ematch_tree **result)
692 struct rtnl_ematch_tree *tree;
694 yyscan_t scanner = NULL;
697 NL_DBG(2,
"Parsing ematch expression \"%s\"\n", expr);
702 if ((err = ematch_lex_init(&scanner)) < 0) {
707 buf = ematch__scan_string(expr, scanner);
709 if ((err = ematch_parse(scanner, errp, &tree->et_list)) != 0) {
710 ematch__delete_buffer(buf, scanner);
711 err = -NLE_PARSE_ERR;
715 ematch_lex_destroy(scanner);
722 ematch_lex_destroy(scanner);
729 static const char *layer_txt[] = {
730 [TCF_LAYER_LINK] =
"eth",
731 [TCF_LAYER_NETWORK] =
"ip",
732 [TCF_LAYER_TRANSPORT] =
"tcp",
735 char *rtnl_ematch_offset2txt(uint8_t layer, uint16_t offset,
char *buf,
size_t len)
737 snprintf(buf, len,
"%s+%u",
738 (layer <= TCF_LAYER_MAX) ? layer_txt[layer] :
"?",
744 static const char *operand_txt[] = {
745 [TCF_EM_OPND_EQ] =
"=",
746 [TCF_EM_OPND_LT] =
"<",
747 [TCF_EM_OPND_GT] =
">",
750 char *rtnl_ematch_opnd2txt(uint8_t opnd,
char *buf,
size_t len)
752 snprintf(buf, len,
"%s",
753 opnd < ARRAY_SIZE(operand_txt) ? operand_txt[opnd] :
"?");
Attribute validation policy.
struct rtnl_ematch_tree * rtnl_ematch_tree_clone(struct rtnl_ematch_tree *src)
Clone ematch tree object.
void rtnl_ematch_tree_add(struct rtnl_ematch_tree *tree, struct rtnl_ematch *ematch)
Add ematch object to the end of the ematch tree.
struct rtnl_ematch_tree * rtnl_ematch_tree_alloc(uint16_t progid)
Allocate ematch tree object.
void rtnl_ematch_tree_free(struct rtnl_ematch_tree *tree)
Free ematch tree object.
struct rtnl_ematch_ops * rtnl_ematch_lookup_ops(int kind)
Lookup ematch module by identification number.
struct rtnl_ematch_ops * rtnl_ematch_lookup_ops_by_name(const char *name)
Lookup ematch module by name.
int nla_total_size(int payload)
Return size of attribute including padding.
struct rtnl_ematch * rtnl_ematch_alloc(void)
Allocate ematch object.
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
int rtnl_ematch_parse_attr(struct nlattr *attr, struct rtnl_ematch_tree **result)
Parse ematch netlink attributes.
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy)
Create attribute index based on nested attribute.
#define NLA_PUT(msg, attrtype, attrlen, data)
Add unspecific attribute to netlink message.
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
int rtnl_ematch_register(struct rtnl_ematch_ops *ops)
Register ematch module.
int nla_len(const struct nlattr *nla)
Return length of the payload .
uint16_t minlen
Minimal length of payload required.
#define nla_for_each_nested(pos, nla, rem)
Iterate over a stream of nested attributes.
void rtnl_ematch_unlink(struct rtnl_ematch *ematch)
Remove ematch from the list of ematches it is linked to.
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Extended Match Operations.
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
int rtnl_ematch_add_child(struct rtnl_ematch *parent, struct rtnl_ematch *child)
Add ematch to the end of the parent's list of children.