libnl  3.6.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  nl_dump(p, " successful %" PRIu64, pcnt->kcnts[i]);
347  }
348  }
349 }
350 
351 static void u32_dump_details(struct rtnl_tc *tc, void *data,
352  struct nl_dump_params *p)
353 {
354  struct rtnl_u32 *u = data;
355  struct tc_u32_sel *s = NULL;
356  struct tc_u32_mark *m;
357 
358  if (!u)
359  return;
360 
361  if (!(u->cu_mask & (U32_ATTR_SELECTOR & U32_ATTR_MARK))) {
362  nl_dump(p, "no-selector no-mark\n");
363  return;
364  }
365 
366  if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
367  nl_dump(p, "no-selector");
368  } else {
369  s = u->cu_selector->d_data;
370  nl_dump(p, "nkeys %u", s->nkeys);
371  }
372 
373  if (!(u->cu_mask & U32_ATTR_MARK)) {
374  nl_dump(p, " no-mark");
375  } else {
376  m = u->cu_mark->d_data;
377  nl_dump(p, " mark 0x%u 0x%u", m->val, m->mask);
378  }
379 
380  if (u->cu_mask & U32_ATTR_HASH)
381  nl_dump(p, " ht key 0x%x hash 0x%u",
382  TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
383 
384  if (u->cu_mask & U32_ATTR_LINK)
385  nl_dump(p, " link %u", u->cu_link);
386 
387  if (u->cu_mask & U32_ATTR_INDEV)
388  nl_dump(p, " indev %s", u->cu_indev);
389 
390  if (u->cu_mask & U32_ATTR_SELECTOR)
391  print_selector(p, s, u);
392 
393  nl_dump(p, "\n");
394 }
395 
396 static void u32_dump_stats(struct rtnl_tc *tc, void *data,
397  struct nl_dump_params *p)
398 {
399  struct rtnl_u32 *u = data;
400 
401  if (!u)
402  return;
403 
404  if (u->cu_mask & U32_ATTR_PCNT) {
405  struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
406  nl_dump(p, "\n");
407  nl_dump_line(p, " hit %8" PRIu64 " count %8" PRIu64 "\n",
408  pc->rhit, pc->rcnt);
409  }
410 }
411 
412 static int u32_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
413 {
414  struct rtnl_u32 *u = data;
415 
416  if (!u)
417  return 0;
418 
419  if (u->cu_mask & U32_ATTR_DIVISOR)
420  NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor);
421 
422  if (u->cu_mask & U32_ATTR_HASH)
423  NLA_PUT_U32(msg, TCA_U32_HASH, u->cu_hash);
424 
425  if (u->cu_mask & U32_ATTR_CLASSID)
426  NLA_PUT_U32(msg, TCA_U32_CLASSID, u->cu_classid);
427 
428  if (u->cu_mask & U32_ATTR_LINK)
429  NLA_PUT_U32(msg, TCA_U32_LINK, u->cu_link);
430 
431  if (u->cu_mask & U32_ATTR_SELECTOR)
432  NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector);
433 
434  if (u->cu_mask & U32_ATTR_MARK)
435  NLA_PUT_DATA(msg, TCA_U32_MARK, u->cu_mark);
436 
437  if (u->cu_mask & U32_ATTR_ACTION) {
438  int err;
439 
440  err = rtnl_act_fill(msg, TCA_U32_ACT, u->cu_act);
441  if (err < 0)
442  return err;
443  }
444 
445  if (u->cu_mask & U32_ATTR_POLICE)
446  NLA_PUT_DATA(msg, TCA_U32_POLICE, u->cu_police);
447 
448  if (u->cu_mask & U32_ATTR_INDEV)
449  NLA_PUT_STRING(msg, TCA_U32_INDEV, u->cu_indev);
450 
451  return 0;
452 
453 nla_put_failure:
454  return -NLE_NOMEM;
455 }
456 
457 /**
458  * @name Attribute Modifications
459  * @{
460  */
461 
462 void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
463  int nodeid)
464 {
465  uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
466 
467  rtnl_tc_set_handle((struct rtnl_tc *) cls, handle );
468 }
469 
470 int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
471 {
472  struct rtnl_u32 *u;
473 
474  if (!(u = rtnl_tc_data(TC_CAST(cls))))
475  return -NLE_NOMEM;
476 
477  u->cu_classid = classid;
478  u->cu_mask |= U32_ATTR_CLASSID;
479 
480  return 0;
481 }
482 
483 int rtnl_u32_get_classid(struct rtnl_cls *cls, uint32_t *classid)
484 {
485  struct rtnl_u32 *u;
486 
487  if (!(u = rtnl_tc_data_peek(TC_CAST(cls))))
488  return -NLE_INVAL;
489 
490  if (!(u->cu_mask & U32_ATTR_CLASSID))
491  return -NLE_INVAL;
492 
493  *classid = u->cu_classid;
494  return 0;
495 }
496 
497 int rtnl_u32_set_divisor(struct rtnl_cls *cls, uint32_t divisor)
498 {
499  struct rtnl_u32 *u;
500 
501  if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
502  return -NLE_NOMEM;
503 
504  u->cu_divisor = divisor;
505  u->cu_mask |= U32_ATTR_DIVISOR;
506  return 0;
507 }
508 
509 int rtnl_u32_set_link(struct rtnl_cls *cls, uint32_t link)
510 {
511  struct rtnl_u32 *u;
512 
513  if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
514  return -NLE_NOMEM;
515 
516  u->cu_link = link;
517  u->cu_mask |= U32_ATTR_LINK;
518  return 0;
519 }
520 
521 int rtnl_u32_set_hashtable(struct rtnl_cls *cls, uint32_t ht)
522 {
523  struct rtnl_u32 *u;
524 
525  if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
526  return -NLE_NOMEM;
527 
528  u->cu_hash = ht;
529  u->cu_mask |= U32_ATTR_HASH;
530  return 0;
531 }
532 
533 int rtnl_u32_set_hashmask(struct rtnl_cls *cls, uint32_t hashmask, uint32_t offset)
534 {
535  struct rtnl_u32 *u;
536  struct tc_u32_sel *sel;
537 
538  hashmask = htonl(hashmask);
539 
540  if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
541  return -NLE_NOMEM;
542 
543  sel = u32_selector_alloc(u);
544  if (!sel)
545  return -NLE_NOMEM;
546 
547  sel->hmask = hashmask;
548  sel->hoff = offset;
549  return 0;
550 }
551 
552 int rtnl_u32_set_selector(struct rtnl_cls *cls, int offoff, uint32_t offmask, char offshift, uint16_t off, char flags)
553 {
554  struct rtnl_u32 *u;
555  struct tc_u32_sel *sel;
556 
557  offmask = ntohs(offmask);
558 
559  if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
560  return -NLE_NOMEM;
561 
562  sel = u32_selector_alloc(u);
563  if (!sel)
564  return -NLE_NOMEM;
565 
566  sel->offoff = offoff;
567  sel->offmask = offmask;
568  sel->offshift = offshift;
569  sel->flags |= TC_U32_VAROFFSET;
570  sel->off = off;
571  sel->flags |= flags;
572  return 0;
573 }
574 
575 int rtnl_u32_set_cls_terminal(struct rtnl_cls *cls)
576 {
577  struct rtnl_u32 *u;
578  struct tc_u32_sel *sel;
579 
580  if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
581  return -NLE_NOMEM;
582 
583  sel = u32_selector_alloc(u);
584  if (!sel)
585  return -NLE_NOMEM;
586 
587  sel->flags |= TC_U32_TERMINAL;
588  return 0;
589 }
590 
591 int rtnl_u32_add_action(struct rtnl_cls *cls, struct rtnl_act *act)
592 {
593  struct rtnl_u32 *u;
594  int err;
595 
596  if (!act)
597  return 0;
598 
599  if (!(u = rtnl_tc_data(TC_CAST(cls))))
600  return -NLE_NOMEM;
601 
602  u->cu_mask |= U32_ATTR_ACTION;
603  if ((err = rtnl_act_append(&u->cu_act, act)))
604  return err;
605 
606  /* In case user frees it */
607  rtnl_act_get(act);
608  return 0;
609 }
610 
611 struct rtnl_act* rtnl_u32_get_action(struct rtnl_cls *cls)
612 {
613  struct rtnl_u32 *u;
614 
615  if (!(u = rtnl_tc_data_peek(TC_CAST(cls))))
616  return NULL;
617 
618  if (!(u->cu_mask & U32_ATTR_ACTION))
619  return NULL;
620 
621  return u->cu_act;
622 }
623 
624 int rtnl_u32_del_action(struct rtnl_cls *cls, struct rtnl_act *act)
625 {
626  struct rtnl_u32 *u;
627  int ret;
628 
629  if (!act)
630  return 0;
631 
632  if (!(u = rtnl_tc_data(TC_CAST(cls))))
633  return -NLE_NOMEM;
634 
635  if (!(u->cu_mask & U32_ATTR_ACTION))
636  return -NLE_INVAL;
637 
638  ret = rtnl_act_remove(&u->cu_act, act);
639  if (ret)
640  return ret;
641 
642  if (!u->cu_act)
643  u->cu_mask &= ~U32_ATTR_ACTION;
644  rtnl_act_put(act);
645  return 0;
646 }
647 /** @} */
648 
649 /**
650  * @name Selector Modifications
651  * @{
652  */
653 
654 int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
655 {
656  struct tc_u32_sel *sel;
657  struct rtnl_u32 *u;
658 
659  if (!(u = rtnl_tc_data(TC_CAST(cls))))
660  return -NLE_NOMEM;
661 
662  sel = u32_selector_alloc(u);
663  if (!sel)
664  return -NLE_NOMEM;
665 
666  sel->flags |= flags;
667  u->cu_mask |= U32_ATTR_SELECTOR;
668 
669  return 0;
670 }
671 
672 /**
673  * Append new 32-bit key to the selector
674  *
675  * @arg cls classifier to be modifier
676  * @arg val value to be matched (network byte-order)
677  * @arg mask mask to be applied before matching (network byte-order)
678  * @arg off offset, in bytes, to start matching
679  * @arg offmask offset mask
680  *
681  * General selectors define the pattern, mask and offset the pattern will be
682  * matched to the packet contents. Using the general selectors you can match
683  * virtually any single bit in the IP (or upper layer) header.
684  *
685 */
686 int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
687  int off, int offmask)
688 {
689  struct tc_u32_sel *sel;
690  struct rtnl_u32 *u;
691  int err;
692 
693  if (!(u = rtnl_tc_data(TC_CAST(cls))))
694  return -NLE_NOMEM;
695 
696  sel = u32_selector_alloc(u);
697  if (!sel)
698  return -NLE_NOMEM;
699 
700  if (sel->nkeys == UCHAR_MAX)
701  return -NLE_NOMEM;
702 
703  err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
704  if (err < 0)
705  return err;
706 
707  /* the selector might have been moved by realloc */
708  sel = u32_selector(u);
709 
710  sel->keys[sel->nkeys].mask = mask;
711  sel->keys[sel->nkeys].val = val & mask;
712  sel->keys[sel->nkeys].off = off;
713  sel->keys[sel->nkeys].offmask = offmask;
714  sel->nkeys++;
715  u->cu_mask |= U32_ATTR_SELECTOR;
716 
717  return 0;
718 }
719 
720 int rtnl_u32_add_mark(struct rtnl_cls *cls, uint32_t val, uint32_t mask)
721 {
722  struct tc_u32_mark *mark;
723  struct rtnl_u32 *u;
724 
725  if (!(u = rtnl_tc_data(TC_CAST(cls))))
726  return -NLE_NOMEM;
727 
728  mark = u32_mark_alloc(u);
729  if (!mark)
730  return -NLE_NOMEM;
731 
732  mark->mask = mask;
733  mark->val = val;
734 
735  u->cu_mask |= U32_ATTR_MARK;
736 
737  return 0;
738 }
739 
740 int rtnl_u32_del_mark(struct rtnl_cls *cls)
741 {
742  struct rtnl_u32 *u;
743 
744  if (!(u = rtnl_tc_data(TC_CAST(cls))))
745  return -NLE_NOMEM;
746 
747  if (!(u->cu_mask))
748  return -NLE_INVAL;
749 
750  if (!(u->cu_mask & U32_ATTR_MARK))
751  return -NLE_INVAL;
752 
753  nl_data_free(u->cu_mark);
754  u->cu_mark = NULL;
755  u->cu_mask &= ~U32_ATTR_MARK;
756 
757  return 0;
758 }
759 
760 /**
761  * Get the 32-bit key from the selector
762  *
763  * @arg cls classifier to be retrieve
764  * @arg index the index of the array of keys, start with 0
765  * @arg val pointer to store value after masked (network byte-order)
766  * @arg mask pointer to store the mask (network byte-order)
767  * @arg off pointer to store the offset
768  * @arg offmask pointer to store offset mask
769  *
770 */
771 int rtnl_u32_get_key(struct rtnl_cls *cls, uint8_t index,
772  uint32_t *val, uint32_t *mask, int *off, int *offmask)
773 {
774  struct tc_u32_sel *sel;
775  struct rtnl_u32 *u;
776 
777  if (!(u = rtnl_tc_data(TC_CAST(cls))))
778  return -NLE_NOMEM;
779 
780  if (!(u->cu_mask & U32_ATTR_SELECTOR))
781  return -NLE_INVAL;
782 
783  sel = u32_selector(u);
784  if (index >= sel->nkeys)
785  return -NLE_RANGE;
786 
787  *mask = sel->keys[index].mask;
788  *val = sel->keys[index].val;
789  *off = sel->keys[index].off;
790  *offmask = sel->keys[index].offmask;
791  return 0;
792 }
793 
794 
795 int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
796  int off, int offmask)
797 {
798  int shift = 24 - 8 * (off & 3);
799 
800  return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
801  htonl((uint32_t)mask << shift),
802  off & ~3, offmask);
803 }
804 
805 /**
806  * Append new selector key to match a 16-bit number
807  *
808  * @arg cls classifier to be modified
809  * @arg val value to be matched (host byte-order)
810  * @arg mask mask to be applied before matching (host byte-order)
811  * @arg off offset, in bytes, to start matching
812  * @arg offmask offset mask
813 */
814 int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
815  int off, int offmask)
816 {
817  int shift = ((off & 3) == 0 ? 16 : 0);
818  if (off % 2)
819  return -NLE_INVAL;
820 
821  return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
822  htonl((uint32_t)mask << shift),
823  off & ~3, offmask);
824 }
825 
826 /**
827  * Append new selector key to match a 32-bit number
828  *
829  * @arg cls classifier to be modified
830  * @arg val value to be matched (host byte-order)
831  * @arg mask mask to be applied before matching (host byte-order)
832  * @arg off offset, in bytes, to start matching
833  * @arg offmask offset mask
834 */
835 int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
836  int off, int offmask)
837 {
838  return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
839  off & ~3, offmask);
840 }
841 
842 int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, const struct in_addr *addr,
843  uint8_t bitmask, int off, int offmask)
844 {
845  uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
846  return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
847 }
848 
849 int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, const struct in6_addr *addr,
850  uint8_t bitmask, int off, int offmask)
851 {
852  int i, err;
853 
854  for (i = 1; i <= 4; i++) {
855  if (32 * i - bitmask <= 0) {
856  if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
857  0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
858  return err;
859  }
860  else if (32 * i - bitmask < 32) {
861  uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
862  if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
863  htonl(mask), off+4*(i-1), offmask)) < 0)
864  return err;
865  }
866  /* otherwise, if (32*i - bitmask >= 32) no key is generated */
867  }
868 
869  return 0;
870 }
871 
872 /** @} */
873 
874 static struct rtnl_tc_ops u32_ops = {
875  .to_kind = "u32",
876  .to_type = RTNL_TC_TYPE_CLS,
877  .to_size = sizeof(struct rtnl_u32),
878  .to_msg_parser = u32_msg_parser,
879  .to_free_data = u32_free_data,
880  .to_clone = u32_clone,
881  .to_msg_fill = u32_msg_fill,
882  .to_dump = {
883  [NL_DUMP_LINE] = u32_dump_line,
884  [NL_DUMP_DETAILS] = u32_dump_details,
885  [NL_DUMP_STATS] = u32_dump_stats,
886  },
887 };
888 
889 static void __init u32_init(void)
890 {
891  rtnl_tc_register(&u32_ops);
892 }
893 
894 static void __exit u32_exit(void)
895 {
896  rtnl_tc_unregister(&u32_ops);
897 }
898 
899 /** @} */
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:771
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:686
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:835
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:814
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:1079
void * rtnl_tc_data_peek(struct rtnl_tc *tc)
Returns the private data of the traffic control object.
Definition: tc.c:1065
#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:1018
void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
Unregister a traffic control module.
Definition: tc.c:1052
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