libnl  3.7.0
u32.c
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
4  * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com>
5  * Copyright (c) 2005-2006 Siemens AG Oesterreich
6  */
7 
8 /**
9  * @ingroup cls
10  * @defgroup cls_u32 Universal 32-bit Classifier
11  *
12  * @{
13  */
14 
15 #include <netlink-private/netlink.h>
16 #include <netlink-private/tc.h>
17 #include <netlink/netlink.h>
18 #include <netlink/attr.h>
19 #include <netlink/utils.h>
20 #include <netlink-private/route/tc-api.h>
21 #include <netlink/route/classifier.h>
22 #include <netlink/route/cls/u32.h>
23 #include <netlink/route/action.h>
24 
25 #include "netlink-private/utils.h"
26 
27 /** @cond SKIP */
28 #define U32_ATTR_DIVISOR 0x001
29 #define U32_ATTR_HASH 0x002
30 #define U32_ATTR_CLASSID 0x004
31 #define U32_ATTR_LINK 0x008
32 #define U32_ATTR_PCNT 0x010
33 #define U32_ATTR_SELECTOR 0x020
34 #define U32_ATTR_ACTION 0x040
35 #define U32_ATTR_POLICE 0x080
36 #define U32_ATTR_INDEV 0x100
37 #define U32_ATTR_MARK 0x200
38 /** @endcond */
39 
40 static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u)
41 {
42  return (struct tc_u32_sel *) u->cu_selector->d_data;
43 }
44 
45 static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u)
46 {
47  if (!u->cu_selector)
48  u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel));
49 
50  return u32_selector(u);
51 }
52 
53 static inline struct tc_u32_mark *u32_mark_alloc(struct rtnl_u32 *u)
54 {
55  if (!u->cu_mark)
56  u->cu_mark = nl_data_alloc(NULL, sizeof(struct tc_u32_mark));
57 
58  return (struct tc_u32_mark *) u->cu_mark->d_data;
59 }
60 
61 static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
62  [TCA_U32_DIVISOR] = { .type = NLA_U32 },
63  [TCA_U32_HASH] = { .type = NLA_U32 },
64  [TCA_U32_CLASSID] = { .type = NLA_U32 },
65  [TCA_U32_LINK] = { .type = NLA_U32 },
66  [TCA_U32_INDEV] = { .type = NLA_STRING,
67  .maxlen = IFNAMSIZ },
68  [TCA_U32_SEL] = { .minlen = sizeof(struct tc_u32_sel) },
69  [TCA_U32_PCNT] = { .minlen = sizeof(struct tc_u32_pcnt) },
70  [TCA_U32_MARK] = { .minlen = sizeof(struct tc_u32_mark) }
71 };
72 
73 static int u32_msg_parser(struct rtnl_tc *tc, void *data)
74 {
75  struct rtnl_u32 *u = data;
76  struct nlattr *tb[TCA_U32_MAX + 1];
77  int err;
78 
79  err = tca_parse(tb, TCA_U32_MAX, tc, u32_policy);
80  if (err < 0)
81  return err;
82 
83  if (tb[TCA_U32_DIVISOR]) {
84  u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
85  u->cu_mask |= U32_ATTR_DIVISOR;
86  }
87 
88  if (tb[TCA_U32_SEL]) {
89  u->cu_selector = nl_data_alloc_attr(tb[TCA_U32_SEL]);
90  if (!u->cu_selector)
91  goto errout_nomem;
92  u->cu_mask |= U32_ATTR_SELECTOR;
93  }
94 
95  if (tb[TCA_U32_MARK]) {
96  u->cu_mark = nl_data_alloc_attr(tb[TCA_U32_MARK]);
97  if (!u->cu_mark)
98  goto errout_nomem;
99  u->cu_mask |= U32_ATTR_MARK;
100  }
101 
102  if (tb[TCA_U32_HASH]) {
103  u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]);
104  u->cu_mask |= U32_ATTR_HASH;
105  }
106 
107  if (tb[TCA_U32_CLASSID]) {
108  u->cu_classid = nla_get_u32(tb[TCA_U32_CLASSID]);
109  u->cu_mask |= U32_ATTR_CLASSID;
110  }
111 
112  if (tb[TCA_U32_LINK]) {
113  u->cu_link = nla_get_u32(tb[TCA_U32_LINK]);
114  u->cu_mask |= U32_ATTR_LINK;
115  }
116 
117  if (tb[TCA_U32_ACT]) {
118  u->cu_mask |= U32_ATTR_ACTION;
119  err = rtnl_act_parse(&u->cu_act, tb[TCA_U32_ACT]);
120  if (err < 0)
121  return err;
122  }
123 
124  if (tb[TCA_U32_POLICE]) {
125  u->cu_police = nl_data_alloc_attr(tb[TCA_U32_POLICE]);
126  if (!u->cu_police)
127  goto errout_nomem;
128  u->cu_mask |= U32_ATTR_POLICE;
129  }
130 
131  if (tb[TCA_U32_PCNT]) {
132  struct tc_u32_sel *sel;
133  size_t pcnt_size;
134 
135  if (!tb[TCA_U32_SEL]) {
136  err = -NLE_MISSING_ATTR;
137  goto errout;
138  }
139 
140  sel = u->cu_selector->d_data;
141  pcnt_size = sizeof(struct tc_u32_pcnt) +
142  (sel->nkeys * sizeof(uint64_t));
143  if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
144  err = -NLE_INVAL;
145  goto errout;
146  }
147 
148  u->cu_pcnt = nl_data_alloc_attr(tb[TCA_U32_PCNT]);
149  if (!u->cu_pcnt)
150  goto errout_nomem;
151  u->cu_mask |= U32_ATTR_PCNT;
152  }
153 
154  if (tb[TCA_U32_INDEV]) {
155  nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
156  u->cu_mask |= U32_ATTR_INDEV;
157  }
158 
159  return 0;
160 
161 errout_nomem:
162  err = -NLE_NOMEM;
163 errout:
164  return err;
165 }
166 
167 static void u32_free_data(struct rtnl_tc *tc, void *data)
168 {
169  struct rtnl_u32 *u = data;
170 
171  if (u->cu_act)
172  rtnl_act_put_all(&u->cu_act);
173  nl_data_free(u->cu_mark);
174  nl_data_free(u->cu_selector);
175  nl_data_free(u->cu_police);
176  nl_data_free(u->cu_pcnt);
177 }
178 
179 static int u32_clone(void *_dst, void *_src)
180 {
181  struct rtnl_u32 *dst = _dst, *src = _src;
182  _nl_auto_nl_data struct nl_data *selector = NULL;
183  _nl_auto_nl_data struct nl_data *mark = NULL;
184  _nl_auto_nl_data struct nl_data *police = NULL;
185  _nl_auto_nl_data struct nl_data *pcnt = NULL;
186  _nl_auto_nl_data struct nl_data *opts = NULL;
187  _nl_auto_nl_data struct nl_data *xstats = NULL;
188  _nl_auto_nl_data struct nl_data *subdata = NULL;
189  _nl_auto_rtnl_act struct rtnl_act *act = NULL;
190 
191  dst->cu_pcnt = NULL;
192  dst->cu_selector = NULL;
193  dst->cu_mark = NULL;
194  dst->cu_act = NULL;
195  dst->cu_police = NULL;
196 
197  if (src->cu_selector) {
198  if (!(selector = nl_data_clone(src->cu_selector)))
199  return -NLE_NOMEM;
200  }
201 
202  if (src->cu_mark) {
203  if (!(mark = nl_data_clone(src->cu_mark)))
204  return -NLE_NOMEM;
205  }
206 
207  if (src->cu_act) {
208  if (!(act = rtnl_act_alloc()))
209  return -NLE_NOMEM;
210 
211  if (src->cu_act->c_opts) {
212  if (!(opts = nl_data_clone(src->cu_act->c_opts)))
213  return -NLE_NOMEM;
214  }
215 
216  if (src->cu_act->c_xstats) {
217  if (!(xstats = nl_data_clone(src->cu_act->c_xstats)))
218  return -NLE_NOMEM;
219  }
220 
221  if (src->cu_act->c_subdata) {
222  if (!(subdata = nl_data_clone(src->cu_act->c_subdata)))
223  return -NLE_NOMEM;
224  }
225  }
226 
227  if (src->cu_police) {
228  if (!(police = nl_data_clone(src->cu_police)))
229  return -NLE_NOMEM;
230  }
231 
232  if (src->cu_pcnt) {
233  if (!(pcnt = nl_data_clone(src->cu_pcnt)))
234  return -NLE_NOMEM;
235  }
236 
237  /* we've passed the critical point and its safe to proceed */
238 
239  if (selector)
240  dst->cu_selector = _nl_steal_pointer(&selector);
241 
242  if (mark)
243  dst->cu_mark = _nl_steal_pointer(&mark);
244 
245  if (police)
246  dst->cu_police = _nl_steal_pointer(&police);
247 
248  if (pcnt)
249  dst->cu_pcnt = _nl_steal_pointer(&pcnt);
250 
251  if (act) {
252  dst->cu_act = _nl_steal_pointer(&act);
253 
254  /* action nl list next and prev pointers must be updated */
255  nl_init_list_head(&dst->cu_act->ce_list);
256 
257  if (opts)
258  dst->cu_act->c_opts = _nl_steal_pointer(&opts);
259 
260  if (xstats)
261  dst->cu_act->c_xstats = _nl_steal_pointer(&xstats);
262 
263  if (subdata)
264  dst->cu_act->c_subdata = _nl_steal_pointer(&subdata);
265 
266  if (dst->cu_act->c_link) {
267  nl_object_get(OBJ_CAST(dst->cu_act->c_link));
268  }
269 
270  dst->cu_act->a_next = NULL; /* Only clone first in chain */
271  }
272 
273  return 0;
274 }
275 
276 static void u32_dump_line(struct rtnl_tc *tc, void *data,
277  struct nl_dump_params *p)
278 {
279  struct rtnl_u32 *u = data;
280  char buf[32];
281 
282  if (!u)
283  return;
284 
285  if (u->cu_mask & U32_ATTR_DIVISOR)
286  nl_dump(p, " divisor %u", u->cu_divisor);
287  else if (u->cu_mask & U32_ATTR_CLASSID)
288  nl_dump(p, " target %s",
289  rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
290 }
291 
292 static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
293  struct rtnl_u32 *u)
294 {
295  int i;
296  struct tc_u32_key *key;
297 
298  if (sel->hmask || sel->hoff) {
299  /* I guess this will never be used since the kernel only
300  * exports the selector if no divisor is set but hash offset
301  * and hash mask make only sense in hash filters with divisor
302  * set */
303  nl_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
304  }
305 
306  if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
307  nl_dump(p, " offset at %u", sel->off);
308 
309  if (sel->flags & TC_U32_VAROFFSET)
310  nl_dump(p, " variable (at %u & 0x%x) >> %u",
311  sel->offoff, ntohs(sel->offmask), sel->offshift);
312  }
313 
314  if (sel->flags) {
315  int flags = sel->flags;
316  nl_dump(p, " <");
317 
318 #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
319  flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
320 
321  PRINT_FLAG(TERMINAL);
322  PRINT_FLAG(OFFSET);
323  PRINT_FLAG(VAROFFSET);
324  PRINT_FLAG(EAT);
325 #undef PRINT_FLAG
326 
327  nl_dump(p, ">");
328  }
329 
330 
331  for (i = 0; i < sel->nkeys; i++) {
332  key = &sel->keys[i];
333 
334  nl_dump(p, "\n");
335  nl_dump_line(p, " match key at %s%u ",
336  key->offmask ? "nexthdr+" : "", key->off);
337 
338  if (key->offmask)
339  nl_dump(p, "[0x%u] ", key->offmask);
340 
341  nl_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
342 
343  if (p->dp_type == NL_DUMP_STATS &&
344  (u->cu_mask & U32_ATTR_PCNT)) {
345  struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
346 
347  nl_dump(p, " successful %llu",
348  (long long unsigned)pcnt->kcnts[i]);
349  }
350  }
351 }
352 
353 static void u32_dump_details(struct rtnl_tc *tc, void *data,
354  struct nl_dump_params *p)
355 {
356  struct rtnl_u32 *u = data;
357  struct tc_u32_sel *s = NULL;
358  struct tc_u32_mark *m;
359 
360  if (!u)
361  return;
362 
363  if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
364  nl_dump(p, "no-selector");
365  } else {
366  s = u->cu_selector->d_data;
367  nl_dump(p, "nkeys %u", s->nkeys);
368  }
369 
370  if (!(u->cu_mask & U32_ATTR_MARK)) {
371  nl_dump(p, " no-mark");
372  } else {
373  m = u->cu_mark->d_data;
374  nl_dump(p, " mark 0x%u 0x%u", m->val, m->mask);
375  }
376 
377  if (u->cu_mask & U32_ATTR_HASH)
378  nl_dump(p, " ht key 0x%x hash 0x%u",
379  TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
380 
381  if (u->cu_mask & U32_ATTR_LINK)
382  nl_dump(p, " link %u", u->cu_link);
383 
384  if (u->cu_mask & U32_ATTR_INDEV)
385  nl_dump(p, " indev %s", u->cu_indev);
386 
387  if (u->cu_mask & U32_ATTR_SELECTOR)
388  print_selector(p, s, u);
389 
390  nl_dump(p, "\n");
391 }
392 
393 static void u32_dump_stats(struct rtnl_tc *tc, void *data,
394  struct nl_dump_params *p)
395 {
396  struct rtnl_u32 *u = data;
397 
398  if (!u)
399  return;
400 
401  if (u->cu_mask & U32_ATTR_PCNT) {
402  struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
403 
404  nl_dump(p, "\n");
405  nl_dump_line(p, " hit %8llu count %8llu\n",
406  (long long unsigned)pc->rhit,
407  (long long unsigned)pc->rcnt);
408  }
409 }
410 
411 static int u32_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
412 {
413  struct rtnl_u32 *u = data;
414 
415  if (!u)
416  return 0;
417 
418  if (u->cu_mask & U32_ATTR_DIVISOR)
419  NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor);
420 
421  if (u->cu_mask & U32_ATTR_HASH)
422  NLA_PUT_U32(msg, TCA_U32_HASH, u->cu_hash);
423 
424  if (u->cu_mask & U32_ATTR_CLASSID)
425  NLA_PUT_U32(msg, TCA_U32_CLASSID, u->cu_classid);
426 
427  if (u->cu_mask & U32_ATTR_LINK)
428  NLA_PUT_U32(msg, TCA_U32_LINK, u->cu_link);
429 
430  if (u->cu_mask & U32_ATTR_SELECTOR)
431  NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector);
432 
433  if (u->cu_mask & U32_ATTR_MARK)
434  NLA_PUT_DATA(msg, TCA_U32_MARK, u->cu_mark);
435 
436  if (u->cu_mask & U32_ATTR_ACTION) {
437  int err;
438 
439  err = rtnl_act_fill(msg, TCA_U32_ACT, u->cu_act);
440  if (err < 0)
441  return err;
442  }
443 
444  if (u->cu_mask & U32_ATTR_POLICE)
445  NLA_PUT_DATA(msg, TCA_U32_POLICE, u->cu_police);
446 
447  if (u->cu_mask & U32_ATTR_INDEV)
448  NLA_PUT_STRING(msg, TCA_U32_INDEV, u->cu_indev);
449 
450  return 0;
451 
452 nla_put_failure:
453  return -NLE_NOMEM;
454 }
455 
456 /**
457  * @name Attribute Modifications
458  * @{
459  */
460 
461 void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
462  int nodeid)
463 {
464  uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
465 
466  rtnl_tc_set_handle((struct rtnl_tc *) cls, handle );
467 }
468 
469 int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
470 {
471  struct rtnl_u32 *u;
472 
473  if (!(u = rtnl_tc_data(TC_CAST(cls))))
474  return -NLE_NOMEM;
475 
476  u->cu_classid = classid;
477  u->cu_mask |= U32_ATTR_CLASSID;
478 
479  return 0;
480 }
481 
482 int rtnl_u32_get_classid(struct rtnl_cls *cls, uint32_t *classid)
483 {
484  struct rtnl_u32 *u;
485 
486  if (!(u = rtnl_tc_data_peek(TC_CAST(cls))))
487  return -NLE_INVAL;
488 
489  if (!(u->cu_mask & U32_ATTR_CLASSID))
490  return -NLE_INVAL;
491 
492  *classid = u->cu_classid;
493  return 0;
494 }
495 
496 int rtnl_u32_set_divisor(struct rtnl_cls *cls, uint32_t divisor)
497 {
498  struct rtnl_u32 *u;
499 
500  if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
501  return -NLE_NOMEM;
502 
503  u->cu_divisor = divisor;
504  u->cu_mask |= U32_ATTR_DIVISOR;
505  return 0;
506 }
507 
508 int rtnl_u32_set_link(struct rtnl_cls *cls, uint32_t link)
509 {
510  struct rtnl_u32 *u;
511 
512  if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
513  return -NLE_NOMEM;
514 
515  u->cu_link = link;
516  u->cu_mask |= U32_ATTR_LINK;
517  return 0;
518 }
519 
520 int rtnl_u32_set_hashtable(struct rtnl_cls *cls, uint32_t ht)
521 {
522  struct rtnl_u32 *u;
523 
524  if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
525  return -NLE_NOMEM;
526 
527  u->cu_hash = ht;
528  u->cu_mask |= U32_ATTR_HASH;
529  return 0;
530 }
531 
532 int rtnl_u32_set_hashmask(struct rtnl_cls *cls, uint32_t hashmask, uint32_t offset)
533 {
534  struct rtnl_u32 *u;
535  struct tc_u32_sel *sel;
536 
537  hashmask = htonl(hashmask);
538 
539  if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
540  return -NLE_NOMEM;
541 
542  sel = u32_selector_alloc(u);
543  if (!sel)
544  return -NLE_NOMEM;
545 
546  sel->hmask = hashmask;
547  sel->hoff = offset;
548  return 0;
549 }
550 
551 int rtnl_u32_set_selector(struct rtnl_cls *cls, int offoff, uint32_t offmask, char offshift, uint16_t off, char flags)
552 {
553  struct rtnl_u32 *u;
554  struct tc_u32_sel *sel;
555 
556  offmask = ntohs(offmask);
557 
558  if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
559  return -NLE_NOMEM;
560 
561  sel = u32_selector_alloc(u);
562  if (!sel)
563  return -NLE_NOMEM;
564 
565  sel->offoff = offoff;
566  sel->offmask = offmask;
567  sel->offshift = offshift;
568  sel->flags |= TC_U32_VAROFFSET;
569  sel->off = off;
570  sel->flags |= flags;
571  return 0;
572 }
573 
574 int rtnl_u32_set_cls_terminal(struct rtnl_cls *cls)
575 {
576  struct rtnl_u32 *u;
577  struct tc_u32_sel *sel;
578 
579  if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
580  return -NLE_NOMEM;
581 
582  sel = u32_selector_alloc(u);
583  if (!sel)
584  return -NLE_NOMEM;
585 
586  sel->flags |= TC_U32_TERMINAL;
587  return 0;
588 }
589 
590 int rtnl_u32_add_action(struct rtnl_cls *cls, struct rtnl_act *act)
591 {
592  struct rtnl_u32 *u;
593  int err;
594 
595  if (!act)
596  return 0;
597 
598  if (!(u = rtnl_tc_data(TC_CAST(cls))))
599  return -NLE_NOMEM;
600 
601  u->cu_mask |= U32_ATTR_ACTION;
602  if ((err = rtnl_act_append(&u->cu_act, act)))
603  return err;
604 
605  /* In case user frees it */
606  rtnl_act_get(act);
607  return 0;
608 }
609 
610 struct rtnl_act* rtnl_u32_get_action(struct rtnl_cls *cls)
611 {
612  struct rtnl_u32 *u;
613 
614  if (!(u = rtnl_tc_data_peek(TC_CAST(cls))))
615  return NULL;
616 
617  if (!(u->cu_mask & U32_ATTR_ACTION))
618  return NULL;
619 
620  return u->cu_act;
621 }
622 
623 int rtnl_u32_del_action(struct rtnl_cls *cls, struct rtnl_act *act)
624 {
625  struct rtnl_u32 *u;
626  int ret;
627 
628  if (!act)
629  return 0;
630 
631  if (!(u = rtnl_tc_data(TC_CAST(cls))))
632  return -NLE_NOMEM;
633 
634  if (!(u->cu_mask & U32_ATTR_ACTION))
635  return -NLE_INVAL;
636 
637  ret = rtnl_act_remove(&u->cu_act, act);
638  if (ret)
639  return ret;
640 
641  if (!u->cu_act)
642  u->cu_mask &= ~U32_ATTR_ACTION;
643  rtnl_act_put(act);
644  return 0;
645 }
646 /** @} */
647 
648 /**
649  * @name Selector Modifications
650  * @{
651  */
652 
653 int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
654 {
655  struct tc_u32_sel *sel;
656  struct rtnl_u32 *u;
657 
658  if (!(u = rtnl_tc_data(TC_CAST(cls))))
659  return -NLE_NOMEM;
660 
661  sel = u32_selector_alloc(u);
662  if (!sel)
663  return -NLE_NOMEM;
664 
665  sel->flags |= flags;
666  u->cu_mask |= U32_ATTR_SELECTOR;
667 
668  return 0;
669 }
670 
671 /**
672  * Append new 32-bit key to the selector
673  *
674  * @arg cls classifier to be modifier
675  * @arg val value to be matched (network byte-order)
676  * @arg mask mask to be applied before matching (network byte-order)
677  * @arg off offset, in bytes, to start matching
678  * @arg offmask offset mask
679  *
680  * General selectors define the pattern, mask and offset the pattern will be
681  * matched to the packet contents. Using the general selectors you can match
682  * virtually any single bit in the IP (or upper layer) header.
683  *
684 */
685 int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
686  int off, int offmask)
687 {
688  struct tc_u32_sel *sel;
689  struct rtnl_u32 *u;
690  int err;
691 
692  if (!(u = rtnl_tc_data(TC_CAST(cls))))
693  return -NLE_NOMEM;
694 
695  sel = u32_selector_alloc(u);
696  if (!sel)
697  return -NLE_NOMEM;
698 
699  if (sel->nkeys == UCHAR_MAX)
700  return -NLE_NOMEM;
701 
702  err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
703  if (err < 0)
704  return err;
705 
706  /* the selector might have been moved by realloc */
707  sel = u32_selector(u);
708 
709  sel->keys[sel->nkeys].mask = mask;
710  sel->keys[sel->nkeys].val = val & mask;
711  sel->keys[sel->nkeys].off = off;
712  sel->keys[sel->nkeys].offmask = offmask;
713  sel->nkeys++;
714  u->cu_mask |= U32_ATTR_SELECTOR;
715 
716  return 0;
717 }
718 
719 int rtnl_u32_add_mark(struct rtnl_cls *cls, uint32_t val, uint32_t mask)
720 {
721  struct tc_u32_mark *mark;
722  struct rtnl_u32 *u;
723 
724  if (!(u = rtnl_tc_data(TC_CAST(cls))))
725  return -NLE_NOMEM;
726 
727  mark = u32_mark_alloc(u);
728  if (!mark)
729  return -NLE_NOMEM;
730 
731  mark->mask = mask;
732  mark->val = val;
733 
734  u->cu_mask |= U32_ATTR_MARK;
735 
736  return 0;
737 }
738 
739 int rtnl_u32_del_mark(struct rtnl_cls *cls)
740 {
741  struct rtnl_u32 *u;
742 
743  if (!(u = rtnl_tc_data(TC_CAST(cls))))
744  return -NLE_NOMEM;
745 
746  if (!(u->cu_mask))
747  return -NLE_INVAL;
748 
749  if (!(u->cu_mask & U32_ATTR_MARK))
750  return -NLE_INVAL;
751 
752  nl_data_free(u->cu_mark);
753  u->cu_mark = NULL;
754  u->cu_mask &= ~U32_ATTR_MARK;
755 
756  return 0;
757 }
758 
759 /**
760  * Get the 32-bit key from the selector
761  *
762  * @arg cls classifier to be retrieve
763  * @arg index the index of the array of keys, start with 0
764  * @arg val pointer to store value after masked (network byte-order)
765  * @arg mask pointer to store the mask (network byte-order)
766  * @arg off pointer to store the offset
767  * @arg offmask pointer to store offset mask
768  *
769 */
770 int rtnl_u32_get_key(struct rtnl_cls *cls, uint8_t index,
771  uint32_t *val, uint32_t *mask, int *off, int *offmask)
772 {
773  struct tc_u32_sel *sel;
774  struct rtnl_u32 *u;
775 
776  if (!(u = rtnl_tc_data(TC_CAST(cls))))
777  return -NLE_NOMEM;
778 
779  if (!(u->cu_mask & U32_ATTR_SELECTOR))
780  return -NLE_INVAL;
781 
782  sel = u32_selector(u);
783  if (index >= sel->nkeys)
784  return -NLE_RANGE;
785 
786  *mask = sel->keys[index].mask;
787  *val = sel->keys[index].val;
788  *off = sel->keys[index].off;
789  *offmask = sel->keys[index].offmask;
790  return 0;
791 }
792 
793 
794 int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
795  int off, int offmask)
796 {
797  int shift = 24 - 8 * (off & 3);
798 
799  return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
800  htonl((uint32_t)mask << shift),
801  off & ~3, offmask);
802 }
803 
804 /**
805  * Append new selector key to match a 16-bit number
806  *
807  * @arg cls classifier to be modified
808  * @arg val value to be matched (host byte-order)
809  * @arg mask mask to be applied before matching (host byte-order)
810  * @arg off offset, in bytes, to start matching
811  * @arg offmask offset mask
812 */
813 int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
814  int off, int offmask)
815 {
816  int shift = ((off & 3) == 0 ? 16 : 0);
817  if (off % 2)
818  return -NLE_INVAL;
819 
820  return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
821  htonl((uint32_t)mask << shift),
822  off & ~3, offmask);
823 }
824 
825 /**
826  * Append new selector key to match a 32-bit number
827  *
828  * @arg cls classifier to be modified
829  * @arg val value to be matched (host byte-order)
830  * @arg mask mask to be applied before matching (host byte-order)
831  * @arg off offset, in bytes, to start matching
832  * @arg offmask offset mask
833 */
834 int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
835  int off, int offmask)
836 {
837  return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
838  off & ~3, offmask);
839 }
840 
841 int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, const struct in_addr *addr,
842  uint8_t bitmask, int off, int offmask)
843 {
844  uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
845  return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
846 }
847 
848 int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, const struct in6_addr *addr,
849  uint8_t bitmask, int off, int offmask)
850 {
851  int i, err;
852 
853  for (i = 1; i <= 4; i++) {
854  if (32 * i - bitmask <= 0) {
855  if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
856  0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
857  return err;
858  }
859  else if (32 * i - bitmask < 32) {
860  uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
861  if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
862  htonl(mask), off+4*(i-1), offmask)) < 0)
863  return err;
864  }
865  /* otherwise, if (32*i - bitmask >= 32) no key is generated */
866  }
867 
868  return 0;
869 }
870 
871 /** @} */
872 
873 static struct rtnl_tc_ops u32_ops = {
874  .to_kind = "u32",
875  .to_type = RTNL_TC_TYPE_CLS,
876  .to_size = sizeof(struct rtnl_u32),
877  .to_msg_parser = u32_msg_parser,
878  .to_free_data = u32_free_data,
879  .to_clone = u32_clone,
880  .to_msg_fill = u32_msg_fill,
881  .to_dump = {
882  [NL_DUMP_LINE] = u32_dump_line,
883  [NL_DUMP_DETAILS] = u32_dump_details,
884  [NL_DUMP_STATS] = u32_dump_stats,
885  },
886 };
887 
888 static void __init u32_init(void)
889 {
890  rtnl_tc_register(&u32_ops);
891 }
892 
893 static void __exit u32_exit(void)
894 {
895  rtnl_tc_unregister(&u32_ops);
896 }
897 
898 /** @} */
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
Definition: attr.c:699
#define NLA_PUT_DATA(msg, attrtype, data)
Add abstract data attribute to netlink message.
Definition: attr.h:293
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
Definition: attr.h:230
size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
Copy string attribute payload to a buffer.
Definition: attr.c:371
int nla_len(const struct nlattr *nla)
Return length of the payload .
Definition: attr.c:125
#define NLA_PUT_STRING(msg, attrtype, value)
Add string attribute to netlink message.
Definition: attr.h:257
@ NLA_STRING
NUL terminated character string.
Definition: attr.h:39
@ NLA_U32
32 bit integer
Definition: attr.h:37
char * rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
Convert a traffic control handle to a character string (Reentrant).
Definition: classid.c:103
int rtnl_u32_get_key(struct rtnl_cls *cls, uint8_t index, uint32_t *val, uint32_t *mask, int *off, int *offmask)
Get the 32-bit key from the selector.
Definition: u32.c:770
int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask, int off, int offmask)
Append new 32-bit key to the selector.
Definition: u32.c:685
int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask, int off, int offmask)
Append new selector key to match a 32-bit number.
Definition: u32.c:834
int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask, int off, int offmask)
Append new selector key to match a 16-bit number.
Definition: u32.c:813
struct nl_data * nl_data_alloc(const void *buf, size_t size)
Allocate a new abstract data object.
Definition: data.c:44
struct nl_data * nl_data_clone(const struct nl_data *src)
Clone an abstract data object.
Definition: data.c:89
void nl_data_free(struct nl_data *data)
Free an abstract data object.
Definition: data.c:128
int nl_data_append(struct nl_data *data, const void *buf, size_t size)
Append data to an abstract data object.
Definition: data.c:105
struct nl_data * nl_data_alloc_attr(const struct nlattr *nla)
Allocate abstract data object based on netlink attribute.
Definition: data.c:78
void nl_object_get(struct nl_object *obj)
Acquire a reference on a object.
Definition: object.c:203
void * rtnl_tc_data(struct rtnl_tc *tc)
Return pointer to private data of traffic control object.
Definition: tc.c:1076
void * rtnl_tc_data_peek(struct rtnl_tc *tc)
Returns the private data of the traffic control object.
Definition: tc.c:1062
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
Definition: tc.h:50
void rtnl_tc_set_handle(struct rtnl_tc *tc, uint32_t id)
Set identifier of traffic control object.
Definition: tc.c:480
int rtnl_tc_register(struct rtnl_tc_ops *ops)
Register a traffic control module.
Definition: tc.c:1015
void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
Unregister a traffic control module.
Definition: tc.c:1049
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition: utils.c:955
@ NL_DUMP_STATS
Dump all attributes including statistics.
Definition: types.h:18
@ NL_DUMP_LINE
Dump object briefly on one line.
Definition: types.h:16
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Definition: types.h:17
Dumping parameters.
Definition: types.h:28
enum nl_dump_type dp_type
Specifies the type of dump that is requested.
Definition: types.h:32
Attribute validation policy.
Definition: attr.h:63
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition: attr.h:65