libnl 3.7.0
ematch.c
1/* SPDX-License-Identifier: LGPL-2.1-only */
2/*
3 * Copyright (c) 2008-2013 Thomas Graf <tgraf@suug.ch>
4 */
5
6/**
7 * @ingroup cls
8 * @defgroup ematch Extended Match
9 *
10 * @{
11 */
12
13#include <netlink-private/netlink.h>
14#include <netlink-private/tc.h>
15#include <netlink/netlink.h>
16#include <netlink/route/classifier.h>
17#include <netlink/route/cls/ematch.h>
18#include <netlink/route/cls/ematch/cmp.h>
19#include <linux/tc_ematch/tc_em_cmp.h>
20
21#include "ematch_syntax.h"
22#include "ematch_grammar.h"
23
24/**
25 * @name Module API
26 * @{
27 */
28
29static NL_LIST_HEAD(ematch_ops_list);
30
31/**
32 * Register ematch module
33 * @arg ops Module operations.
34 *
35 * This function must be called by each ematch module at initialization
36 * time. It registers the calling module as available module.
37 *
38 * @return 0 on success or a negative error code.
39 */
41{
42 if (rtnl_ematch_lookup_ops(ops->eo_kind))
43 return -NLE_EXIST;
44
45 NL_DBG(1, "ematch module \"%s\" registered\n", ops->eo_name);
46
47 nl_list_add_tail(&ops->eo_list, &ematch_ops_list);
48
49 return 0;
50}
51
52/**
53 * Lookup ematch module by identification number.
54 * @arg kind Module kind.
55 *
56 * Searches the list of registered ematch modules for match and returns it.
57 *
58 * @return Module operations or NULL if not found.
59 */
61{
62 struct rtnl_ematch_ops *ops;
63
64 nl_list_for_each_entry(ops, &ematch_ops_list, eo_list)
65 if (ops->eo_kind == kind)
66 return ops;
67
68 return NULL;
69}
70
71/**
72 * Lookup ematch module by name
73 * @arg name Name of ematch module.
74 *
75 * Searches the list of registered ematch modules for a match and returns it.
76 *
77 * @return Module operations or NULL if not fuond.
78 */
80{
81 struct rtnl_ematch_ops *ops;
82
83 nl_list_for_each_entry(ops, &ematch_ops_list, eo_list)
84 if (!strcasecmp(ops->eo_name, name))
85 return ops;
86
87 return NULL;
88}
89
90/** @} */
91
92/**
93 * @name Match
94 */
95
96/**
97 * Allocate ematch object.
98 *
99 * Allocates and initializes an ematch object.
100 *
101 * @return New ematch object or NULL.
102 */
103struct rtnl_ematch *rtnl_ematch_alloc(void)
104{
105 struct rtnl_ematch *e;
106
107 if (!(e = calloc(1, sizeof(*e))))
108 return NULL;
109
110 NL_DBG(2, "allocated ematch %p\n", e);
111
112 NL_INIT_LIST_HEAD(&e->e_list);
113 NL_INIT_LIST_HEAD(&e->e_childs);
114
115 return e;
116}
117
118/**
119 * Add ematch to the end of the parent's list of children.
120 * @arg parent parent ematch object
121 * @arg child ematch object to be added to parent
122 *
123 * The parent must be a container ematch.
124 */
125int rtnl_ematch_add_child(struct rtnl_ematch *parent,
126 struct rtnl_ematch *child)
127{
128 if (parent->e_kind != TCF_EM_CONTAINER)
129 return -NLE_OPNOTSUPP;
130
131 NL_DBG(2, "added ematch %p \"%s\" to container %p\n",
132 child, child->e_ops->eo_name, parent);
133
134 nl_list_add_tail(&child->e_list, &parent->e_childs);
135
136 return 0;
137}
138
139/**
140 * Remove ematch from the list of ematches it is linked to.
141 * @arg ematch ematch object
142 */
143void rtnl_ematch_unlink(struct rtnl_ematch *ematch)
144{
145 NL_DBG(2, "unlinked ematch %p from any lists\n", ematch);
146
147 if (!nl_list_empty(&ematch->e_childs))
148 NL_DBG(1, "warning: ematch %p with childs was unlinked\n",
149 ematch);
150
151 nl_list_del(&ematch->e_list);
152 nl_init_list_head(&ematch->e_list);
153}
154
155void rtnl_ematch_free(struct rtnl_ematch *ematch)
156{
157 NL_DBG(2, "freed ematch %p\n", ematch);
158 rtnl_ematch_unlink(ematch);
159 free(ematch->e_data);
160 free(ematch);
161}
162
163int rtnl_ematch_set_ops(struct rtnl_ematch *ematch, struct rtnl_ematch_ops *ops)
164{
165 if (ematch->e_ops)
166 return -NLE_EXIST;
167
168 ematch->e_ops = ops;
169 ematch->e_kind = ops->eo_kind;
170
171 if (ops->eo_datalen) {
172 ematch->e_data = calloc(1, ops->eo_datalen);
173 if (!ematch->e_data)
174 return -NLE_NOMEM;
175
176 ematch->e_datalen = ops->eo_datalen;
177 }
178
179 return 0;
180}
181
182int rtnl_ematch_set_kind(struct rtnl_ematch *ematch, uint16_t kind)
183{
184 struct rtnl_ematch_ops *ops;
185
186 if (ematch->e_kind)
187 return -NLE_EXIST;
188
189 ematch->e_kind = kind;
190
191 if ((ops = rtnl_ematch_lookup_ops(kind)))
192 rtnl_ematch_set_ops(ematch, ops);
193
194 return 0;
195}
196
197int rtnl_ematch_set_name(struct rtnl_ematch *ematch, const char *name)
198{
199 struct rtnl_ematch_ops *ops;
200
201 if (ematch->e_kind)
202 return -NLE_EXIST;
203
204 if (!(ops = rtnl_ematch_lookup_ops_by_name(name)))
205 return -NLE_OPNOTSUPP;
206
207 rtnl_ematch_set_ops(ematch, ops);
208
209 return 0;
210}
211
212void rtnl_ematch_set_flags(struct rtnl_ematch *ematch, uint16_t flags)
213{
214 ematch->e_flags |= flags;
215}
216
217void rtnl_ematch_unset_flags(struct rtnl_ematch *ematch, uint16_t flags)
218{
219 ematch->e_flags &= ~flags;
220}
221
222uint16_t rtnl_ematch_get_flags(struct rtnl_ematch *ematch)
223{
224 return ematch->e_flags;
225}
226
227void *rtnl_ematch_data(struct rtnl_ematch *ematch)
228{
229 return ematch->e_data;
230}
231
232/** @} */
233
234/**
235 * @name Tree
236 */
237
238/**
239 * Allocate ematch tree object
240 * @arg progid program id
241 */
242struct rtnl_ematch_tree *rtnl_ematch_tree_alloc(uint16_t progid)
243{
244 struct rtnl_ematch_tree *tree;
245
246 if (!(tree = calloc(1, sizeof(*tree))))
247 return NULL;
248
249 NL_INIT_LIST_HEAD(&tree->et_list);
250 tree->et_progid = progid;
251
252 NL_DBG(2, "allocated new ematch tree %p, progid=%u\n", tree, progid);
253
254 return tree;
255}
256
257static void free_ematch_list(struct nl_list_head *head)
258{
259 struct rtnl_ematch *pos, *next;
260
261 nl_list_for_each_entry_safe(pos, next, head, e_list) {
262 if (!nl_list_empty(&pos->e_childs))
263 free_ematch_list(&pos->e_childs);
264 rtnl_ematch_free(pos);
265 }
266}
267
268/**
269 * Free ematch tree object
270 * @arg tree ematch tree object
271 *
272 * This function frees the ematch tree and all ematches attached to it.
273 */
274void rtnl_ematch_tree_free(struct rtnl_ematch_tree *tree)
275{
276 if (!tree)
277 return;
278
279 free_ematch_list(&tree->et_list);
280
281 NL_DBG(2, "Freed ematch tree %p\n", tree);
282
283 free(tree);
284}
285
286static int clone_ematch_list(struct nl_list_head *dst, struct nl_list_head *src)
287{
288 struct rtnl_ematch *new = NULL, *pos = NULL;
289
290 nl_list_for_each_entry(pos, src, e_list) {
291 new = rtnl_ematch_alloc();
292 if (!new)
293 goto nomem;
294
295 new->e_id = pos->e_id;
296 new->e_kind = pos->e_kind;
297 new->e_flags = pos->e_flags;
298 new->e_index = pos->e_index;
299 new->e_datalen = pos->e_datalen;
300
301 if (pos->e_ops) {
302 if (rtnl_ematch_set_ops(new, pos->e_ops))
303 goto nomem;
304 }
305
306 if (!nl_list_empty(&pos->e_childs)) {
307 if (clone_ematch_list(&new->e_childs, &pos->e_childs) < 0)
308 goto nomem;
309 }
310 nl_list_add_tail(&new->e_list, dst);
311 }
312
313 return 0;
314
315nomem:
316 if (new)
317 free(new);
318 free_ematch_list(dst);
319 return -NLE_NOMEM;
320}
321
322/**
323 * Clone ematch tree object
324 * @arg src ematch tree object
325 *
326 * This function clones the ematch tree and all ematches attached to it.
327 */
328struct rtnl_ematch_tree *rtnl_ematch_tree_clone(struct rtnl_ematch_tree *src)
329{
330 struct rtnl_ematch_tree *dst = NULL;
331
332 if (!src)
333 return NULL;
334
335 if (!(dst = rtnl_ematch_tree_alloc(src->et_progid)))
336 return NULL;
337
338 clone_ematch_list(&dst->et_list, &src->et_list);
339
340 return dst;
341}
342
343/**
344 * Add ematch object to the end of the ematch tree
345 * @arg tree ematch tree object
346 * @arg ematch ematch object to add
347 */
348void rtnl_ematch_tree_add(struct rtnl_ematch_tree *tree,
349 struct rtnl_ematch *ematch)
350{
351 nl_list_add_tail(&ematch->e_list, &tree->et_list);
352}
353
354static inline uint32_t container_ref(struct rtnl_ematch *ematch)
355{
356 return *((uint32_t *) rtnl_ematch_data(ematch));
357}
358
359static int link_tree(struct rtnl_ematch *index[], int nmatches, int pos,
360 struct nl_list_head *root)
361{
362 struct rtnl_ematch *ematch;
363 int i;
364
365 for (i = pos; i < nmatches; i++) {
366 ematch = index[i];
367
368 nl_list_add_tail(&ematch->e_list, root);
369
370 if (ematch->e_kind == TCF_EM_CONTAINER)
371 link_tree(index, nmatches, container_ref(ematch),
372 &ematch->e_childs);
373
374 if (!(ematch->e_flags & TCF_EM_REL_MASK))
375 return 0;
376 }
377
378 /* Last entry in chain can't possibly have no relation */
379 return -NLE_INVAL;
380}
381
382static struct nla_policy tree_policy[TCA_EMATCH_TREE_MAX+1] = {
383 [TCA_EMATCH_TREE_HDR] = { .minlen=sizeof(struct tcf_ematch_tree_hdr) },
384 [TCA_EMATCH_TREE_LIST] = { .type = NLA_NESTED },
385};
386
387/**
388 * Parse ematch netlink attributes
389 *
390 * @return 0 on success or a negative error code.
391 */
392int rtnl_ematch_parse_attr(struct nlattr *attr, struct rtnl_ematch_tree **result)
393{
394 struct nlattr *a, *tb[TCA_EMATCH_TREE_MAX+1];
395 struct tcf_ematch_tree_hdr *thdr;
396 struct rtnl_ematch_tree *tree;
397 struct rtnl_ematch **index;
398 int nmatches = 0, err, remaining;
399
400 NL_DBG(2, "Parsing attribute %p as ematch tree\n", attr);
401
402 err = nla_parse_nested(tb, TCA_EMATCH_TREE_MAX, attr, tree_policy);
403 if (err < 0)
404 return err;
405
406 if (!tb[TCA_EMATCH_TREE_HDR])
407 return -NLE_MISSING_ATTR;
408
409 thdr = nla_data(tb[TCA_EMATCH_TREE_HDR]);
410
411 /* Ignore empty trees */
412 if (thdr->nmatches == 0) {
413 NL_DBG(2, "Ignoring empty ematch configuration\n");
414 return 0;
415 }
416
417 if (!tb[TCA_EMATCH_TREE_LIST])
418 return -NLE_MISSING_ATTR;
419
420 NL_DBG(2, "ematch tree found with nmatches=%u, progid=%u\n",
421 thdr->nmatches, thdr->progid);
422
423 /*
424 * Do some basic sanity checking since we will allocate
425 * index[thdr->nmatches]. Calculate how many ematch headers fit into
426 * the provided data and make sure nmatches does not exceed it.
427 */
428 if (thdr->nmatches > (nla_len(tb[TCA_EMATCH_TREE_LIST]) /
429 nla_total_size(sizeof(struct tcf_ematch_hdr))))
430 return -NLE_INVAL;
431
432 if (!(index = calloc(thdr->nmatches, sizeof(struct rtnl_ematch *))))
433 return -NLE_NOMEM;
434
435 if (!(tree = rtnl_ematch_tree_alloc(thdr->progid))) {
436 err = -NLE_NOMEM;
437 goto errout;
438 }
439
440 nla_for_each_nested(a, tb[TCA_EMATCH_TREE_LIST], remaining) {
441 struct rtnl_ematch_ops *ops;
442 struct tcf_ematch_hdr *hdr;
443 struct rtnl_ematch *ematch;
444 void *data;
445 size_t len;
446
447 NL_DBG(3, "parsing ematch attribute %d, len=%u\n",
448 nmatches+1, nla_len(a));
449
450 if (nla_len(a) < sizeof(*hdr)) {
451 err = -NLE_INVAL;
452 goto errout;
453 }
454
455 /* Quit as soon as we've parsed more matches than expected */
456 if (nmatches >= thdr->nmatches) {
457 err = -NLE_RANGE;
458 goto errout;
459 }
460
461 hdr = nla_data(a);
462 data = (char *) nla_data(a) + NLA_ALIGN(sizeof(*hdr));
463 len = nla_len(a) - NLA_ALIGN(sizeof(*hdr));
464
465 NL_DBG(3, "ematch attribute matchid=%u, kind=%u, flags=%u\n",
466 hdr->matchid, hdr->kind, hdr->flags);
467
468 /*
469 * Container matches contain a reference to another sequence
470 * of matches. Ensure that the reference is within boundries.
471 */
472 if (hdr->kind == TCF_EM_CONTAINER &&
473 *((uint32_t *) data) >= thdr->nmatches) {
474 err = -NLE_INVAL;
475 goto errout;
476 }
477
478 if (!(ematch = rtnl_ematch_alloc())) {
479 err = -NLE_NOMEM;
480 goto errout;
481 }
482
483 ematch->e_id = hdr->matchid;
484 ematch->e_kind = hdr->kind;
485 ematch->e_flags = hdr->flags;
486
487 if ((ops = rtnl_ematch_lookup_ops(hdr->kind))) {
488 if (ops->eo_minlen && len < ops->eo_minlen) {
489 rtnl_ematch_free(ematch);
490 err = -NLE_INVAL;
491 goto errout;
492 }
493
494 rtnl_ematch_set_ops(ematch, ops);
495
496 if (ops->eo_parse &&
497 (err = ops->eo_parse(ematch, data, len)) < 0) {
498 rtnl_ematch_free(ematch);
499 goto errout;
500 }
501 }
502
503 NL_DBG(3, "index[%d] = %p\n", nmatches, ematch);
504 index[nmatches++] = ematch;
505 }
506
507 if (nmatches != thdr->nmatches) {
508 err = -NLE_INVAL;
509 goto errout;
510 }
511
512 err = link_tree(index, nmatches, 0, &tree->et_list);
513 if (err < 0)
514 goto errout;
515
516 free(index);
517 *result = tree;
518
519 return 0;
520
521errout:
523 free(index);
524 return err;
525}
526
527static void dump_ematch_sequence(struct nl_list_head *head,
528 struct nl_dump_params *p)
529{
530 struct rtnl_ematch *match;
531
532 nl_list_for_each_entry(match, head, e_list) {
533 if (match->e_flags & TCF_EM_INVERT)
534 nl_dump(p, "!");
535
536 if (match->e_kind == TCF_EM_CONTAINER) {
537 nl_dump(p, "(");
538 dump_ematch_sequence(&match->e_childs, p);
539 nl_dump(p, ")");
540 } else if (!match->e_ops) {
541 nl_dump(p, "[unknown ematch %d]", match->e_kind);
542 } else {
543 if (match->e_ops->eo_dump)
544 match->e_ops->eo_dump(match, p);
545 else
546 nl_dump(p, "[data]");
547 }
548
549 switch (match->e_flags & TCF_EM_REL_MASK) {
550 case TCF_EM_REL_AND:
551 nl_dump(p, " AND ");
552 break;
553 case TCF_EM_REL_OR:
554 nl_dump(p, " OR ");
555 break;
556 default:
557 /* end of first level ematch sequence */
558 return;
559 }
560 }
561}
562
563void rtnl_ematch_tree_dump(struct rtnl_ematch_tree *tree,
564 struct nl_dump_params *p)
565{
566 if (!tree)
567 BUG();
568
569 dump_ematch_sequence(&tree->et_list, p);
570 nl_dump(p, "\n");
571}
572
573static int update_container_index(struct nl_list_head *list, int *index)
574{
575 struct rtnl_ematch *e;
576
577 nl_list_for_each_entry(e, list, e_list)
578 e->e_index = (*index)++;
579
580 nl_list_for_each_entry(e, list, e_list) {
581 if (e->e_kind == TCF_EM_CONTAINER) {
582 int err;
583
584 if (nl_list_empty(&e->e_childs))
585 return -NLE_OBJ_NOTFOUND;
586
587 *((uint32_t *) e->e_data) = *index;
588
589 err = update_container_index(&e->e_childs, index);
590 if (err < 0)
591 return err;
592 }
593 }
594
595 return 0;
596}
597
598static int fill_ematch_sequence(struct nl_msg *msg, struct nl_list_head *list)
599{
600 struct rtnl_ematch *e;
601
602 nl_list_for_each_entry(e, list, e_list) {
603 struct tcf_ematch_hdr match = {
604 .matchid = e->e_id,
605 .kind = e->e_kind,
606 .flags = e->e_flags,
607 };
608 struct nlattr *attr;
609 int err = 0;
610
611 if (!(attr = nla_nest_start(msg, e->e_index + 1)))
612 return -NLE_NOMEM;
613
614 if (nlmsg_append(msg, &match, sizeof(match), 0) < 0)
615 return -NLE_NOMEM;
616
617 if (e->e_ops->eo_fill)
618 err = e->e_ops->eo_fill(e, msg);
619 else if (e->e_flags & TCF_EM_SIMPLE)
620 err = nlmsg_append(msg, e->e_data, 4, 0);
621 else if (e->e_datalen > 0)
622 err = nlmsg_append(msg, e->e_data, e->e_datalen, 0);
623
624 NL_DBG(3, "msg %p: added ematch [%d] id=%d kind=%d flags=%d\n",
625 msg, e->e_index, match.matchid, match.kind, match.flags);
626
627 if (err < 0)
628 return -NLE_NOMEM;
629
630 nla_nest_end(msg, attr);
631 }
632
633 nl_list_for_each_entry(e, list, e_list) {
634 if (e->e_kind == TCF_EM_CONTAINER &&
635 fill_ematch_sequence(msg, &e->e_childs) < 0)
636 return -NLE_NOMEM;
637 }
638
639 return 0;
640}
641
642int rtnl_ematch_fill_attr(struct nl_msg *msg, int attrid,
643 struct rtnl_ematch_tree *tree)
644{
645 struct tcf_ematch_tree_hdr thdr = {
646 .progid = tree->et_progid,
647 };
648 struct nlattr *list, *topattr;
649 int err, index = 0;
650
651 /* Assign index number to each ematch to allow for references
652 * to be made while constructing the sequence of matches. */
653 err = update_container_index(&tree->et_list, &index);
654 if (err < 0)
655 return err;
656
657 if (!(topattr = nla_nest_start(msg, attrid)))
658 goto nla_put_failure;
659
660 thdr.nmatches = index;
661 NLA_PUT(msg, TCA_EMATCH_TREE_HDR, sizeof(thdr), &thdr);
662
663 if (!(list = nla_nest_start(msg, TCA_EMATCH_TREE_LIST)))
664 goto nla_put_failure;
665
666 if (fill_ematch_sequence(msg, &tree->et_list) < 0)
667 goto nla_put_failure;
668
669 nla_nest_end(msg, list);
670
671 nla_nest_end(msg, topattr);
672
673 return 0;
674
675nla_put_failure:
676 return -NLE_NOMEM;
677}
678
679/** @} */
680
681extern int ematch_parse(void *, char **, struct nl_list_head *);
682
683int rtnl_ematch_parse_expr(const char *expr, char **errp,
684 struct rtnl_ematch_tree **result)
685{
686 struct rtnl_ematch_tree *tree;
687 YY_BUFFER_STATE buf = NULL;
688 yyscan_t scanner = NULL;
689 int err;
690
691 NL_DBG(2, "Parsing ematch expression \"%s\"\n", expr);
692
693 if (!(tree = rtnl_ematch_tree_alloc(RTNL_EMATCH_PROGID)))
694 return -NLE_FAILURE;
695
696 if (ematch_lex_init(&scanner) < 0) {
697 err = -NLE_FAILURE;
698 goto errout;
699 }
700
701 buf = ematch__scan_string(expr, scanner);
702
703 if (ematch_parse(scanner, errp, &tree->et_list) != 0) {
704 ematch__delete_buffer(buf, scanner);
705 err = -NLE_PARSE_ERR;
706 goto errout;
707 }
708
709 ematch_lex_destroy(scanner);
710 *result = tree;
711
712 return 0;
713
714errout:
715 if (scanner)
716 ematch_lex_destroy(scanner);
717
719
720 return err;
721}
722
723static const char *layer_txt[] = {
724 [TCF_LAYER_LINK] = "eth",
725 [TCF_LAYER_NETWORK] = "ip",
726 [TCF_LAYER_TRANSPORT] = "tcp",
727};
728
729char *rtnl_ematch_offset2txt(uint8_t layer, uint16_t offset, char *buf, size_t len)
730{
731 snprintf(buf, len, "%s+%u",
732 (layer <= TCF_LAYER_MAX) ? layer_txt[layer] : "?",
733 offset);
734
735 return buf;
736}
737
738static const char *operand_txt[] = {
739 [TCF_EM_OPND_EQ] = "=",
740 [TCF_EM_OPND_LT] = "<",
741 [TCF_EM_OPND_GT] = ">",
742};
743
744char *rtnl_ematch_opnd2txt(uint8_t opnd, char *buf, size_t len)
745{
746 snprintf(buf, len, "%s",
747 opnd < ARRAY_SIZE(operand_txt) ? operand_txt[opnd] : "?");
748
749 return buf;
750}
751
752/** @} */
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
Definition: attr.c:114
#define NLA_PUT(msg, attrtype, attrlen, data)
Add unspecific attribute to netlink message.
Definition: attr.h:159
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
Definition: attr.c:898
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy)
Create attribute index based on nested attribute.
Definition: attr.c:1016
#define nla_for_each_nested(pos, nla, rem)
Iterate over a stream of nested attributes.
Definition: attr.h:324
int nla_len(const struct nlattr *nla)
Return length of the payload .
Definition: attr.c:125
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
Definition: attr.c:961
int nla_total_size(int payload)
Return size of attribute including padding.
Definition: attr.c:67
@ NLA_NESTED
Nested attributes.
Definition: attr.h:42
struct rtnl_ematch_ops * rtnl_ematch_lookup_ops(int kind)
Lookup ematch module by identification number.
Definition: ematch.c:60
void rtnl_ematch_tree_add(struct rtnl_ematch_tree *tree, struct rtnl_ematch *ematch)
Add ematch object to the end of the ematch tree.
Definition: ematch.c:348
void rtnl_ematch_tree_free(struct rtnl_ematch_tree *tree)
Free ematch tree object.
Definition: ematch.c:274
struct rtnl_ematch_tree * rtnl_ematch_tree_alloc(uint16_t progid)
Allocate ematch tree object.
Definition: ematch.c:242
struct rtnl_ematch * rtnl_ematch_alloc(void)
Allocate ematch object.
Definition: ematch.c:103
int rtnl_ematch_register(struct rtnl_ematch_ops *ops)
Register ematch module.
Definition: ematch.c:40
int rtnl_ematch_parse_attr(struct nlattr *attr, struct rtnl_ematch_tree **result)
Parse ematch netlink attributes.
Definition: ematch.c:392
void rtnl_ematch_unlink(struct rtnl_ematch *ematch)
Remove ematch from the list of ematches it is linked to.
Definition: ematch.c:143
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.
Definition: ematch.c:125
struct rtnl_ematch_ops * rtnl_ematch_lookup_ops_by_name(const char *name)
Lookup ematch module by name.
Definition: ematch.c:79
struct rtnl_ematch_tree * rtnl_ematch_tree_clone(struct rtnl_ematch_tree *src)
Clone ematch tree object.
Definition: ematch.c:328
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
Definition: msg.c:442
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition: utils.c:955
Dumping parameters.
Definition: types.h:28
Attribute validation policy.
Definition: attr.h:63
uint16_t minlen
Minimal length of payload required.
Definition: attr.h:68
Extended Match Operations.
Definition: ematch.h:28