libnl  3.2.21
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 
30 /** @cond SKIP */
31 #define U32_ATTR_DIVISOR 0x001
32 #define U32_ATTR_HASH 0x002
33 #define U32_ATTR_CLASSID 0x004
34 #define U32_ATTR_LINK 0x008
35 #define U32_ATTR_PCNT 0x010
36 #define U32_ATTR_SELECTOR 0x020
37 #define U32_ATTR_ACTION 0x040
38 #define U32_ATTR_POLICE 0x080
39 #define U32_ATTR_INDEV 0x100
40 /** @endcond */
41 
42 static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u)
43 {
44  return (struct tc_u32_sel *) u->cu_selector->d_data;
45 }
46 
47 static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u)
48 {
49  if (!u->cu_selector)
50  u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel));
51 
52  return u32_selector(u);
53 }
54 
55 static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
56  [TCA_U32_DIVISOR] = { .type = NLA_U32 },
57  [TCA_U32_HASH] = { .type = NLA_U32 },
58  [TCA_U32_CLASSID] = { .type = NLA_U32 },
59  [TCA_U32_LINK] = { .type = NLA_U32 },
60  [TCA_U32_INDEV] = { .type = NLA_STRING,
61  .maxlen = IFNAMSIZ },
62  [TCA_U32_SEL] = { .minlen = sizeof(struct tc_u32_sel) },
63  [TCA_U32_PCNT] = { .minlen = sizeof(struct tc_u32_pcnt) },
64 };
65 
66 static int u32_msg_parser(struct rtnl_tc *tc, void *data)
67 {
68  struct rtnl_u32 *u = data;
69  struct nlattr *tb[TCA_U32_MAX + 1];
70  int err;
71 
72  err = tca_parse(tb, TCA_U32_MAX, tc, u32_policy);
73  if (err < 0)
74  return err;
75 
76  if (tb[TCA_U32_DIVISOR]) {
77  u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
78  u->cu_mask |= U32_ATTR_DIVISOR;
79  }
80 
81  if (tb[TCA_U32_SEL]) {
82  u->cu_selector = nl_data_alloc_attr(tb[TCA_U32_SEL]);
83  if (!u->cu_selector)
84  goto errout_nomem;
85  u->cu_mask |= U32_ATTR_SELECTOR;
86  }
87 
88  if (tb[TCA_U32_HASH]) {
89  u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]);
90  u->cu_mask |= U32_ATTR_HASH;
91  }
92 
93  if (tb[TCA_U32_CLASSID]) {
94  u->cu_classid = nla_get_u32(tb[TCA_U32_CLASSID]);
95  u->cu_mask |= U32_ATTR_CLASSID;
96  }
97 
98  if (tb[TCA_U32_LINK]) {
99  u->cu_link = nla_get_u32(tb[TCA_U32_LINK]);
100  u->cu_mask |= U32_ATTR_LINK;
101  }
102 
103  if (tb[TCA_U32_ACT]) {
104  u->cu_act = nl_data_alloc_attr(tb[TCA_U32_ACT]);
105  if (!u->cu_act)
106  goto errout_nomem;
107  u->cu_mask |= U32_ATTR_ACTION;
108  }
109 
110  if (tb[TCA_U32_POLICE]) {
111  u->cu_police = nl_data_alloc_attr(tb[TCA_U32_POLICE]);
112  if (!u->cu_police)
113  goto errout_nomem;
114  u->cu_mask |= U32_ATTR_POLICE;
115  }
116 
117  if (tb[TCA_U32_PCNT]) {
118  struct tc_u32_sel *sel;
119  size_t pcnt_size;
120 
121  if (!tb[TCA_U32_SEL]) {
122  err = -NLE_MISSING_ATTR;
123  goto errout;
124  }
125 
126  sel = u->cu_selector->d_data;
127  pcnt_size = sizeof(struct tc_u32_pcnt) +
128  (sel->nkeys * sizeof(uint64_t));
129  if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
130  err = -NLE_INVAL;
131  goto errout;
132  }
133 
134  u->cu_pcnt = nl_data_alloc_attr(tb[TCA_U32_PCNT]);
135  if (!u->cu_pcnt)
136  goto errout_nomem;
137  u->cu_mask |= U32_ATTR_PCNT;
138  }
139 
140  if (tb[TCA_U32_INDEV]) {
141  nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
142  u->cu_mask |= U32_ATTR_INDEV;
143  }
144 
145  return 0;
146 
147 errout_nomem:
148  err = -NLE_NOMEM;
149 errout:
150  return err;
151 }
152 
153 static void u32_free_data(struct rtnl_tc *tc, void *data)
154 {
155  struct rtnl_u32 *u = data;
156 
157  nl_data_free(u->cu_selector);
158  nl_data_free(u->cu_act);
159  nl_data_free(u->cu_police);
160  nl_data_free(u->cu_pcnt);
161 }
162 
163 static int u32_clone(void *_dst, void *_src)
164 {
165  struct rtnl_u32 *dst = _dst, *src = _src;
166 
167  if (src->cu_selector &&
168  !(dst->cu_selector = nl_data_clone(src->cu_selector)))
169  return -NLE_NOMEM;
170 
171  if (src->cu_act && !(dst->cu_act = nl_data_clone(src->cu_act)))
172  return -NLE_NOMEM;
173 
174  if (src->cu_police && !(dst->cu_police = nl_data_clone(src->cu_police)))
175  return -NLE_NOMEM;
176 
177  if (src->cu_pcnt && !(dst->cu_pcnt = nl_data_clone(src->cu_pcnt)))
178  return -NLE_NOMEM;
179 
180  return 0;
181 }
182 
183 static void u32_dump_line(struct rtnl_tc *tc, void *data,
184  struct nl_dump_params *p)
185 {
186  struct rtnl_u32 *u = data;
187  char buf[32];
188 
189  if (!u)
190  return;
191 
192  if (u->cu_mask & U32_ATTR_DIVISOR)
193  nl_dump(p, " divisor %u", u->cu_divisor);
194  else if (u->cu_mask & U32_ATTR_CLASSID)
195  nl_dump(p, " target %s",
196  rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
197 }
198 
199 static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
200  struct rtnl_u32 *u)
201 {
202  int i;
203  struct tc_u32_key *key;
204 
205  if (sel->hmask || sel->hoff) {
206  /* I guess this will never be used since the kernel only
207  * exports the selector if no divisor is set but hash offset
208  * and hash mask make only sense in hash filters with divisor
209  * set */
210  nl_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
211  }
212 
213  if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
214  nl_dump(p, " offset at %u", sel->off);
215 
216  if (sel->flags & TC_U32_VAROFFSET)
217  nl_dump(p, " variable (at %u & 0x%x) >> %u",
218  sel->offoff, ntohs(sel->offmask), sel->offshift);
219  }
220 
221  if (sel->flags) {
222  int flags = sel->flags;
223  nl_dump(p, " <");
224 
225 #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
226  flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
227 
228  PRINT_FLAG(TERMINAL);
229  PRINT_FLAG(OFFSET);
230  PRINT_FLAG(VAROFFSET);
231  PRINT_FLAG(EAT);
232 #undef PRINT_FLAG
233 
234  nl_dump(p, ">");
235  }
236 
237 
238  for (i = 0; i < sel->nkeys; i++) {
239  key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i;
240 
241  nl_dump(p, "\n");
242  nl_dump_line(p, " match key at %s%u ",
243  key->offmask ? "nexthdr+" : "", key->off);
244 
245  if (key->offmask)
246  nl_dump(p, "[0x%u] ", key->offmask);
247 
248  nl_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
249 
250  if (p->dp_type == NL_DUMP_STATS &&
251  (u->cu_mask & U32_ATTR_PCNT)) {
252  struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
253  nl_dump(p, " successful %" PRIu64, pcnt->kcnts[i]);
254  }
255  }
256 }
257 
258 static void u32_dump_details(struct rtnl_tc *tc, void *data,
259  struct nl_dump_params *p)
260 {
261  struct rtnl_u32 *u = data;
262  struct tc_u32_sel *s;
263 
264  if (!u)
265  return;
266 
267  if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
268  nl_dump(p, "no-selector\n");
269  return;
270  }
271 
272  s = u->cu_selector->d_data;
273 
274  nl_dump(p, "nkeys %u ", s->nkeys);
275 
276  if (u->cu_mask & U32_ATTR_HASH)
277  nl_dump(p, "ht key 0x%x hash 0x%u",
278  TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
279 
280  if (u->cu_mask & U32_ATTR_LINK)
281  nl_dump(p, "link %u ", u->cu_link);
282 
283  if (u->cu_mask & U32_ATTR_INDEV)
284  nl_dump(p, "indev %s ", u->cu_indev);
285 
286  print_selector(p, s, u);
287  nl_dump(p, "\n");
288 
289 #if 0
290 #define U32_ATTR_ACTION 0x040
291 #define U32_ATTR_POLICE 0x080
292 
293  struct nl_data act;
294  struct nl_data police;
295 #endif
296 }
297 
298 static void u32_dump_stats(struct rtnl_tc *tc, void *data,
299  struct nl_dump_params *p)
300 {
301  struct rtnl_u32 *u = data;
302 
303  if (!u)
304  return;
305 
306  if (u->cu_mask & U32_ATTR_PCNT) {
307  struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
308  nl_dump(p, "\n");
309  nl_dump_line(p, " hit %8" PRIu64 " count %8" PRIu64 "\n",
310  pc->rhit, pc->rcnt);
311  }
312 }
313 
314 static int u32_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
315 {
316  struct rtnl_u32 *u = data;
317 
318  if (!u)
319  return 0;
320 
321  if (u->cu_mask & U32_ATTR_DIVISOR)
322  NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor);
323 
324  if (u->cu_mask & U32_ATTR_HASH)
325  NLA_PUT_U32(msg, TCA_U32_HASH, u->cu_hash);
326 
327  if (u->cu_mask & U32_ATTR_CLASSID)
328  NLA_PUT_U32(msg, TCA_U32_CLASSID, u->cu_classid);
329 
330  if (u->cu_mask & U32_ATTR_LINK)
331  NLA_PUT_U32(msg, TCA_U32_LINK, u->cu_link);
332 
333  if (u->cu_mask & U32_ATTR_SELECTOR)
334  NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector);
335 
336  if (u->cu_mask & U32_ATTR_ACTION)
337  NLA_PUT_DATA(msg, TCA_U32_ACT, u->cu_act);
338 
339  if (u->cu_mask & U32_ATTR_POLICE)
340  NLA_PUT_DATA(msg, TCA_U32_POLICE, u->cu_police);
341 
342  if (u->cu_mask & U32_ATTR_INDEV)
343  NLA_PUT_STRING(msg, TCA_U32_INDEV, u->cu_indev);
344 
345  return 0;
346 
347 nla_put_failure:
348  return -NLE_NOMEM;
349 }
350 
351 /**
352  * @name Attribute Modifications
353  * @{
354  */
355 
356 void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
357  int nodeid)
358 {
359  uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
360 
361  rtnl_tc_set_handle((struct rtnl_tc *) cls, handle );
362 }
363 
364 int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
365 {
366  struct rtnl_u32 *u;
367 
368  if (!(u = rtnl_tc_data(TC_CAST(cls))))
369  return -NLE_NOMEM;
370 
371  u->cu_classid = classid;
372  u->cu_mask |= U32_ATTR_CLASSID;
373 
374  return 0;
375 }
376 
377 int rtnl_u32_set_divisor(struct rtnl_cls *cls, uint32_t divisor)
378 {
379  struct rtnl_u32 *u;
380 
381  if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
382  return -NLE_NOMEM;
383 
384  u->cu_divisor = divisor;
385  u->cu_mask |= U32_ATTR_DIVISOR;
386  return 0;
387 }
388 
389 int rtnl_u32_set_link(struct rtnl_cls *cls, uint32_t link)
390 {
391  struct rtnl_u32 *u;
392 
393  if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
394  return -NLE_NOMEM;
395 
396  u->cu_link = link;
397  u->cu_mask |= U32_ATTR_LINK;
398  return 0;
399 }
400 
401 int rtnl_u32_set_hashtable(struct rtnl_cls *cls, uint32_t ht)
402 {
403  struct rtnl_u32 *u;
404 
405  if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
406  return -NLE_NOMEM;
407 
408  u->cu_hash = ht;
409  u->cu_mask |= U32_ATTR_HASH;
410  return 0;
411 }
412 
413 int rtnl_u32_set_hashmask(struct rtnl_cls *cls, uint32_t hashmask, uint32_t offset)
414 {
415  struct rtnl_u32 *u;
416  struct tc_u32_sel *sel;
417  int err;
418 
419  hashmask = htonl(hashmask);
420 
421  if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
422  return -NLE_NOMEM;
423 
424  sel = u32_selector_alloc(u);
425  if (!sel)
426  return -NLE_NOMEM;
427 
428  err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
429  if(err < 0)
430  return err;
431 
432  sel = u32_selector(u);
433 
434  sel->hmask = hashmask;
435  sel->hoff = offset;
436  return 0;
437 }
438 
439 int rtnl_u32_set_cls_terminal(struct rtnl_cls *cls)
440 {
441  struct rtnl_u32 *u;
442  struct tc_u32_sel *sel;
443  int err;
444 
445  if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
446  return -NLE_NOMEM;
447 
448  sel = u32_selector_alloc(u);
449  if (!sel)
450  return -NLE_NOMEM;
451 
452  err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
453  if(err < 0)
454  return err;
455 
456  sel = u32_selector(u);
457 
458  sel->flags |= TC_U32_TERMINAL;
459  return 0;
460 }
461 
462 /** @} */
463 
464 /**
465  * @name Selector Modifications
466  * @{
467  */
468 
469 int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
470 {
471  struct tc_u32_sel *sel;
472  struct rtnl_u32 *u;
473 
474  if (!(u = rtnl_tc_data(TC_CAST(cls))))
475  return -NLE_NOMEM;
476 
477  sel = u32_selector_alloc(u);
478  if (!sel)
479  return -NLE_NOMEM;
480 
481  sel->flags |= flags;
482  u->cu_mask |= U32_ATTR_SELECTOR;
483 
484  return 0;
485 }
486 
487 /**
488  * Append new 32-bit key to the selector
489  *
490  * @arg cls classifier to be modifier
491  * @arg val value to be matched (network byte-order)
492  * @arg mask mask to be applied before matching (network byte-order)
493  * @arg off offset, in bytes, to start matching
494  * @arg offmask offset mask
495  *
496  * General selectors define the pattern, mask and offset the pattern will be
497  * matched to the packet contents. Using the general selectors you can match
498  * virtually any single bit in the IP (or upper layer) header.
499  *
500 */
501 int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
502  int off, int offmask)
503 {
504  struct tc_u32_sel *sel;
505  struct rtnl_u32 *u;
506  int err;
507 
508  if (!(u = rtnl_tc_data(TC_CAST(cls))))
509  return -NLE_NOMEM;
510 
511  sel = u32_selector_alloc(u);
512  if (!sel)
513  return -NLE_NOMEM;
514 
515  err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
516  if (err < 0)
517  return err;
518 
519  /* the selector might have been moved by realloc */
520  sel = u32_selector(u);
521 
522  sel->keys[sel->nkeys].mask = mask;
523  sel->keys[sel->nkeys].val = val & mask;
524  sel->keys[sel->nkeys].off = off;
525  sel->keys[sel->nkeys].offmask = offmask;
526  sel->nkeys++;
527  u->cu_mask |= U32_ATTR_SELECTOR;
528 
529  return 0;
530 }
531 
532 int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
533  int off, int offmask)
534 {
535  int shift = 24 - 8 * (off & 3);
536 
537  return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
538  htonl((uint32_t)mask << shift),
539  off & ~3, offmask);
540 }
541 
542 /**
543  * Append new selector key to match a 16-bit number
544  *
545  * @arg cls classifier to be modified
546  * @arg val value to be matched (host byte-order)
547  * @arg mask mask to be applied before matching (host byte-order)
548  * @arg off offset, in bytes, to start matching
549  * @arg offmask offset mask
550 */
551 int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
552  int off, int offmask)
553 {
554  int shift = ((off & 3) == 0 ? 16 : 0);
555  if (off % 2)
556  return -NLE_INVAL;
557 
558  return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
559  htonl((uint32_t)mask << shift),
560  off & ~3, offmask);
561 }
562 
563 /**
564  * Append new selector key to match a 32-bit number
565  *
566  * @arg cls classifier to be modified
567  * @arg val value to be matched (host byte-order)
568  * @arg mask mask to be applied before matching (host byte-order)
569  * @arg off offset, in bytes, to start matching
570  * @arg offmask offset mask
571 */
572 int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
573  int off, int offmask)
574 {
575  return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
576  off & ~3, offmask);
577 }
578 
579 int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, struct in_addr *addr,
580  uint8_t bitmask, int off, int offmask)
581 {
582  uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
583  return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
584 }
585 
586 int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr,
587  uint8_t bitmask, int off, int offmask)
588 {
589  int i, err;
590 
591  for (i = 1; i <= 4; i++) {
592  if (32 * i - bitmask <= 0) {
593  if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
594  0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
595  return err;
596  }
597  else if (32 * i - bitmask < 32) {
598  uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
599  if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
600  htonl(mask), off+4*(i-1), offmask)) < 0)
601  return err;
602  }
603  /* otherwise, if (32*i - bitmask >= 32) no key is generated */
604  }
605 
606  return 0;
607 }
608 
609 /** @} */
610 
611 static struct rtnl_tc_ops u32_ops = {
612  .to_kind = "u32",
613  .to_type = RTNL_TC_TYPE_CLS,
614  .to_size = sizeof(struct rtnl_u32),
615  .to_msg_parser = u32_msg_parser,
616  .to_free_data = u32_free_data,
617  .to_clone = u32_clone,
618  .to_msg_fill = u32_msg_fill,
619  .to_dump = {
620  [NL_DUMP_LINE] = u32_dump_line,
621  [NL_DUMP_DETAILS] = u32_dump_details,
622  [NL_DUMP_STATS] = u32_dump_stats,
623  },
624 };
625 
626 static void __init u32_init(void)
627 {
628  rtnl_tc_register(&u32_ops);
629 }
630 
631 static void __exit u32_exit(void)
632 {
633  rtnl_tc_unregister(&u32_ops);
634 }
635 
636 /** @} */