libnl  1.1.4
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-2006 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_api
16  * @defgroup u32 Universal 32-bit Classifier
17  *
18  * @{
19  */
20 
21 #include <netlink-local.h>
22 #include <netlink-tc.h>
23 #include <netlink/netlink.h>
24 #include <netlink/attr.h>
25 #include <netlink/utils.h>
26 #include <netlink/route/tc.h>
27 #include <netlink/route/classifier.h>
28 #include <netlink/route/classifier-modules.h>
29 #include <netlink/route/cls/u32.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 /** @endcond */
42 
43 static inline struct rtnl_u32 *u32_cls(struct rtnl_cls *cls)
44 {
45  return (struct rtnl_u32 *) cls->c_subdata;
46 }
47 
48 static inline struct rtnl_u32 *u32_alloc(struct rtnl_cls *cls)
49 {
50  if (!cls->c_subdata)
51  cls->c_subdata = calloc(1, sizeof(struct rtnl_u32));
52 
53  return u32_cls(cls);
54 }
55 
56 static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u)
57 {
58  return (struct tc_u32_sel *) u->cu_selector->d_data;
59 }
60 
61 static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u)
62 {
63  if (!u->cu_selector)
64  u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel));
65 
66  return u32_selector(u);
67 }
68 
69 static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
70  [TCA_U32_DIVISOR] = { .type = NLA_U32 },
71  [TCA_U32_HASH] = { .type = NLA_U32 },
72  [TCA_U32_CLASSID] = { .type = NLA_U32 },
73  [TCA_U32_LINK] = { .type = NLA_U32 },
74  [TCA_U32_INDEV] = { .type = NLA_STRING,
75  .maxlen = IFNAMSIZ },
76  [TCA_U32_SEL] = { .minlen = sizeof(struct tc_u32_sel) },
77  [TCA_U32_PCNT] = { .minlen = sizeof(struct tc_u32_pcnt) },
78 };
79 
80 static int u32_msg_parser(struct rtnl_cls *cls)
81 {
82  int err;
83  struct nlattr *tb[TCA_U32_MAX + 1];
84  struct rtnl_u32 *u;
85 
86  err = tca_parse(tb, TCA_U32_MAX, (struct rtnl_tca *) cls, u32_policy);
87  if (err < 0)
88  return err;
89 
90  u = u32_alloc(cls);
91  if (!u)
92  goto errout_nomem;
93 
94  if (tb[TCA_U32_DIVISOR]) {
95  u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
96  u->cu_mask |= U32_ATTR_DIVISOR;
97  }
98 
99  if (tb[TCA_U32_SEL]) {
100  u->cu_selector = nla_get_data(tb[TCA_U32_SEL]);
101  if (!u->cu_selector)
102  goto errout_nomem;
103  u->cu_mask |= U32_ATTR_SELECTOR;
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_act = nla_get_data(tb[TCA_U32_ACT]);
123  if (!u->cu_act)
124  goto errout_nomem;
125  u->cu_mask |= U32_ATTR_ACTION;
126  }
127 
128  if (tb[TCA_U32_POLICE]) {
129  u->cu_police = nla_get_data(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  int pcnt_size;
138 
139  if (!tb[TCA_U32_SEL]) {
140  err = nl_error(EINVAL, "Missing TCA_U32_SEL required "
141  "for TCA_U32_PCNT");
142  goto errout;
143  }
144 
145  sel = u->cu_selector->d_data;
146  pcnt_size = sizeof(struct tc_u32_pcnt) +
147  (sel->nkeys * sizeof(uint64_t));
148  if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
149  err = nl_error(EINVAL, "Invalid size for TCA_U32_PCNT");
150  goto errout;
151  }
152 
153  u->cu_pcnt = nla_get_data(tb[TCA_U32_PCNT]);
154  if (!u->cu_pcnt)
155  goto errout_nomem;
156  u->cu_mask |= U32_ATTR_PCNT;
157  }
158 
159  if (tb[TCA_U32_INDEV]) {
160  nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
161  u->cu_mask |= U32_ATTR_INDEV;
162  }
163 
164  return 0;
165 
166 errout_nomem:
167  err = nl_errno(ENOMEM);
168 errout:
169  return err;
170 }
171 
172 static void u32_free_data(struct rtnl_cls *cls)
173 {
174  struct rtnl_u32 *u = u32_cls(cls);
175 
176  if (!u)
177  return;
178 
179  nl_data_free(u->cu_selector);
180  nl_data_free(u->cu_act);
181  nl_data_free(u->cu_police);
182  nl_data_free(u->cu_pcnt);
183 
184  free(cls->c_subdata);
185 }
186 
187 static int u32_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src)
188 {
189  struct rtnl_u32 *dst, *src = u32_cls(_src);
190 
191  if (!src)
192  return 0;
193 
194  dst = u32_alloc(_dst);
195  if (!dst)
196  return nl_errno(ENOMEM);
197 
198  if (src->cu_selector)
199  if (!(dst->cu_selector = nl_data_clone(src->cu_selector)))
200  goto errout;
201 
202  if (src->cu_act)
203  if (!(dst->cu_act = nl_data_clone(src->cu_act)))
204  goto errout;
205 
206  if (src->cu_police)
207  if (!(dst->cu_police = nl_data_clone(src->cu_police)))
208  goto errout;
209 
210  if (src->cu_pcnt)
211  if (!(dst->cu_pcnt = nl_data_clone(src->cu_pcnt)))
212  goto errout;
213 
214  return 0;
215 errout:
216  return nl_get_errno();
217 }
218 
219 static int u32_dump_brief(struct rtnl_cls *cls, struct nl_dump_params *p,
220  int line)
221 {
222  struct rtnl_u32 *u = u32_cls(cls);
223  char buf[32];
224 
225  if (!u)
226  goto ignore;
227 
228  if (u->cu_mask & U32_ATTR_DIVISOR)
229  dp_dump(p, " divisor %u", u->cu_divisor);
230  else if (u->cu_mask & U32_ATTR_CLASSID)
231  dp_dump(p, " target %s",
232  rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
233 
234 ignore:
235  return line;
236 }
237 
238 static int print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
239  struct rtnl_cls *cls, struct rtnl_u32 *u, int line)
240 {
241  int i;
242  struct tc_u32_key *key;
243 
244  if (sel->hmask || sel->hoff) {
245  /* I guess this will never be used since the kernel only
246  * exports the selector if no divisor is set but hash offset
247  * and hash mask make only sense in hash filters with divisor
248  * set */
249  dp_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
250  }
251 
252  if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
253  dp_dump(p, " offset at %u", sel->off);
254 
255  if (sel->flags & TC_U32_VAROFFSET)
256  dp_dump(p, " variable (at %u & 0x%x) >> %u",
257  sel->offoff, ntohs(sel->offmask), sel->offshift);
258  }
259 
260  if (sel->flags) {
261  int flags = sel->flags;
262  dp_dump(p, " <");
263 
264 #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
265  flags &= ~TC_U32_##f; dp_dump(p, #f "%s", flags ? "," : ""); }
266 
267  PRINT_FLAG(TERMINAL);
268  PRINT_FLAG(OFFSET);
269  PRINT_FLAG(VAROFFSET);
270  PRINT_FLAG(EAT);
271 #undef PRINT_FLAG
272 
273  dp_dump(p, ">");
274  }
275 
276 
277  for (i = 0; i < sel->nkeys; i++) {
278  key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i;
279 
280  dp_dump(p, "\n");
281  dp_dump_line(p, line++, " match key at %s%u ",
282  key->offmask ? "nexthdr+" : "", key->off);
283 
284  if (key->offmask)
285  dp_dump(p, "[0x%u] ", key->offmask);
286 
287  dp_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
288 
289  if (p->dp_type == NL_DUMP_STATS &&
290  (u->cu_mask & U32_ATTR_PCNT)) {
291  struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
292  dp_dump(p, " successful %" PRIu64, pcnt->kcnts[i]);
293  }
294  }
295 
296  return line;
297 }
298 
299 
300 static int u32_dump_full(struct rtnl_cls *cls, struct nl_dump_params *p,
301  int line)
302 {
303  struct rtnl_u32 *u = u32_cls(cls);
304  struct tc_u32_sel *s;
305 
306  if (!u)
307  goto ignore;
308 
309  if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
310  dp_dump(p, "no-selector\n");
311  return line;
312  }
313 
314  s = u->cu_selector->d_data;
315 
316  dp_dump(p, "nkeys %u ", s->nkeys);
317 
318  if (u->cu_mask & U32_ATTR_HASH)
319  dp_dump(p, "ht key 0x%x hash 0x%u",
320  TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
321 
322  if (u->cu_mask & U32_ATTR_LINK)
323  dp_dump(p, "link %u ", u->cu_link);
324 
325  if (u->cu_mask & U32_ATTR_INDEV)
326  dp_dump(p, "indev %s ", u->cu_indev);
327 
328  line = print_selector(p, s, cls, u, line);
329  dp_dump(p, "\n");
330 
331 ignore:
332  return line;
333 
334 #if 0
335 #define U32_ATTR_ACTION 0x040
336 #define U32_ATTR_POLICE 0x080
337 
338  struct nl_data act;
339  struct nl_data police;
340 #endif
341 }
342 
343 static int u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p,
344  int line)
345 {
346  struct rtnl_u32 *u = u32_cls(cls);
347 
348  if (!u)
349  goto ignore;
350 
351  if (u->cu_mask & U32_ATTR_PCNT) {
352  struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
353  dp_dump(p, "\n");
354  dp_dump_line(p, line++, "%s successful hits\n");
355  dp_dump_line(p, line++, "%s %8llu %8llu\n",
356  pc->rhit, pc->rcnt);
357  }
358 
359 ignore:
360  return line;
361 }
362 
363 static struct nl_msg *u32_get_opts(struct rtnl_cls *cls)
364 {
365  struct rtnl_u32 *u;
366  struct nl_msg *msg;
367 
368  u = u32_cls(cls);
369  if (!u)
370  return NULL;
371 
372  msg = nlmsg_alloc();
373  if (!msg)
374  return NULL;
375 
376  if (u->cu_mask & U32_ATTR_DIVISOR)
377  nla_put_u32(msg, TCA_U32_DIVISOR, u->cu_divisor);
378 
379  if (u->cu_mask & U32_ATTR_HASH)
380  nla_put_u32(msg, TCA_U32_HASH, u->cu_hash);
381 
382  if (u->cu_mask & U32_ATTR_CLASSID)
383  nla_put_u32(msg, TCA_U32_CLASSID, u->cu_classid);
384 
385  if (u->cu_mask & U32_ATTR_LINK)
386  nla_put_u32(msg, TCA_U32_LINK, u->cu_link);
387 
388  if (u->cu_mask & U32_ATTR_SELECTOR)
389  nla_put_data(msg, TCA_U32_SEL, u->cu_selector);
390 
391  if (u->cu_mask & U32_ATTR_ACTION)
392  nla_put_data(msg, TCA_U32_ACT, u->cu_act);
393 
394  if (u->cu_mask & U32_ATTR_POLICE)
395  nla_put_data(msg, TCA_U32_POLICE, u->cu_police);
396 
397  if (u->cu_mask & U32_ATTR_INDEV)
398  nla_put_string(msg, TCA_U32_INDEV, u->cu_indev);
399 
400  return msg;
401 }
402 
403 /**
404  * @name Attribute Modifications
405  * @{
406  */
407 
408 void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
409  int nodeid)
410 {
411  uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
412 
413  tca_set_handle((struct rtnl_tca *) cls, handle );
414 }
415 
416 int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
417 {
418  struct rtnl_u32 *u;
419 
420  u = u32_alloc(cls);
421  if (!u)
422  return nl_errno(ENOMEM);
423 
424  u->cu_classid = classid;
425  u->cu_mask |= U32_ATTR_CLASSID;
426 
427  return 0;
428 }
429 
430 /** @} */
431 
432 /**
433  * @name Selector Modifications
434  * @{
435  */
436 
437 int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
438 {
439  struct tc_u32_sel *sel;
440  struct rtnl_u32 *u;
441 
442  u = u32_alloc(cls);
443  if (!u)
444  return nl_errno(ENOMEM);
445 
446  sel = u32_selector_alloc(u);
447  if (!sel)
448  return nl_errno(ENOMEM);
449 
450  sel->flags |= flags;
451  u->cu_mask |= U32_ATTR_SELECTOR;
452 
453  return 0;
454 }
455 
456 /**
457  * Append new 32-bit key to the selector
458  *
459  * @arg cls classifier to be modifier
460  * @arg val value to be matched (network byte-order)
461  * @arg mask mask to be applied before matching (network byte-order)
462  * @arg off offset, in bytes, to start matching
463  * @arg offmask offset mask
464  *
465  * General selectors define the pattern, mask and offset the pattern will be
466  * matched to the packet contents. Using the general selectors you can match
467  * virtually any single bit in the IP (or upper layer) header.
468  *
469 */
470 int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
471  int off, int offmask)
472 {
473  struct tc_u32_sel *sel;
474  struct rtnl_u32 *u;
475  int err;
476 
477  u = u32_alloc(cls);
478  if (!u)
479  return nl_errno(ENOMEM);
480 
481  sel = u32_selector_alloc(u);
482  if (!sel)
483  return nl_errno(ENOMEM);
484 
485  err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
486  if (err < 0)
487  return err;
488 
489  /* the selector might have been moved by realloc */
490  sel = u32_selector(u);
491 
492  sel->keys[sel->nkeys].mask = mask;
493  sel->keys[sel->nkeys].val = val & mask;
494  sel->keys[sel->nkeys].off = off;
495  sel->keys[sel->nkeys].offmask = offmask;
496  sel->nkeys++;
497  u->cu_mask |= U32_ATTR_SELECTOR;
498 
499  return 0;
500 }
501 
502 int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
503  int off, int offmask)
504 {
505  int shift = 24 - 8 * (off & 3);
506 
507  return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
508  htonl((uint32_t)mask << shift),
509  off & ~3, offmask);
510 }
511 
512 /**
513  * Append new selector key to match a 16-bit number
514  *
515  * @arg cls classifier to be modified
516  * @arg val value to be matched (host byte-order)
517  * @arg mask mask to be applied before matching (host byte-order)
518  * @arg off offset, in bytes, to start matching
519  * @arg offmask offset mask
520 */
521 int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
522  int off, int offmask)
523 {
524  int shift = ((off & 3) == 0 ? 16 : 0);
525  if (off % 2)
526  return nl_error(EINVAL, "Invalid offset alignment");
527 
528  return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
529  htonl((uint32_t)mask << shift),
530  off & ~3, offmask);
531 }
532 
533 /**
534  * Append new selector key to match a 32-bit number
535  *
536  * @arg cls classifier to be modified
537  * @arg val value to be matched (host byte-order)
538  * @arg mask mask to be applied before matching (host byte-order)
539  * @arg off offset, in bytes, to start matching
540  * @arg offmask offset mask
541 */
542 int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
543  int off, int offmask)
544 {
545  return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
546  off & ~3, offmask);
547 }
548 
549 int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, struct in_addr *addr,
550  uint8_t bitmask, int off, int offmask)
551 {
552  uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
553  return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
554 }
555 
556 int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr,
557  uint8_t bitmask, int off, int offmask)
558 {
559  int i, err;
560 
561  for (i = 1; i <= 4; i++) {
562  if (32 * i - bitmask <= 0) {
563  if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
564  0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
565  return err;
566  }
567  else if (32 * i - bitmask < 32) {
568  uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
569  if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
570  htonl(mask), off+4*(i-1), offmask)) < 0)
571  return err;
572  }
573  /* otherwise, if (32*i - bitmask >= 32) no key is generated */
574  }
575 
576  return 0;
577 }
578 
579 /** @} */
580 
581 static struct rtnl_cls_ops u32_ops = {
582  .co_kind = "u32",
583  .co_msg_parser = u32_msg_parser,
584  .co_free_data = u32_free_data,
585  .co_clone = u32_clone,
586  .co_get_opts = u32_get_opts,
587  .co_dump[NL_DUMP_BRIEF] = u32_dump_brief,
588  .co_dump[NL_DUMP_FULL] = u32_dump_full,
589  .co_dump[NL_DUMP_STATS] = u32_dump_stats,
590 };
591 
592 static void __init u32_init(void)
593 {
594  rtnl_cls_register(&u32_ops);
595 }
596 
597 static void __exit u32_exit(void)
598 {
599  rtnl_cls_unregister(&u32_ops);
600 }
601 
602 /** @} */
32bit integer
Definition: attr.h:39
Dump object in a brief one-liner.
Definition: types.h:22
char co_kind[32]
Kind/Name of classifier.
int rtnl_cls_unregister(struct rtnl_cls_ops *cops)
Unregister a classifier module.
Definition: cls_api.c:59
struct nl_data * nl_data_clone(struct nl_data *src)
Clone an abstract data object.
Definition: data.c:69
attribute validation policy
Definition: attr.h:73
enum nl_dump_type dp_type
Specifies the type of dump that is requested.
Definition: types.h:41
struct nl_msg * nlmsg_alloc(void)
Allocate a new netlink message with the default maximum payload size.
Definition: msg.c:401
int nl_data_append(struct nl_data *data, void *buf, size_t size)
Append data to an abstract data object.
Definition: data.c:85
character string
Definition: attr.h:41
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:521
char * rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
Convert a traffic control handle to a character string (Reentrant).
Definition: tc.c:493
int nla_put_data(struct nl_msg *n, int attrtype, struct nl_data *data)
Add an abstract data netlink attribute to a netlink message.
Definition: attr.c:623
int nla_len(const struct nlattr *nla)
length of payload
Definition: attr.c:160
struct nl_data * nl_data_alloc(void *buf, size_t size)
Allocate a new abstract data object.
Definition: data.c:38
int nla_put_string(struct nl_msg *n, int attrtype, const char *str)
Add a string netlink attribute to a netlink message.
Definition: attr.c:591
int rtnl_cls_register(struct rtnl_cls_ops *cops)
Register a classifier module.
Definition: cls_api.c:38
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition: attr.h:75
Classifier operations.
Dumping parameters.
Definition: types.h:36
struct nl_data * nla_get_data(struct nlattr *nla)
Return payload of abstract data attribute.
Definition: attr.c:776
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:470
uint32_t nla_get_u32(struct nlattr *nla)
Return payload of u32 attribute.
Definition: attr.c:693
int nla_put_u32(struct nl_msg *n, int attrtype, uint32_t value)
Add a u32 netlink attribute to a netlink message.
Definition: attr.c:569
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:542
Dump all attributes but no statistics.
Definition: types.h:23
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 into a sized buffer.
Definition: attr.c:407
void nl_data_free(struct nl_data *data)
Free an abstract data object.
Definition: data.c:110