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