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