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