libnl  3.2.7
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-2011 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-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-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  int 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 %8llu count %8llu\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 /** @} */
378 
379 /**
380  * @name Selector Modifications
381  * @{
382  */
383 
384 int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
385 {
386  struct tc_u32_sel *sel;
387  struct rtnl_u32 *u;
388 
389  if (!(u = rtnl_tc_data(TC_CAST(cls))))
390  return -NLE_NOMEM;
391 
392  sel = u32_selector_alloc(u);
393  if (!sel)
394  return -NLE_NOMEM;
395 
396  sel->flags |= flags;
397  u->cu_mask |= U32_ATTR_SELECTOR;
398 
399  return 0;
400 }
401 
402 /**
403  * Append new 32-bit key to the selector
404  *
405  * @arg cls classifier to be modifier
406  * @arg val value to be matched (network byte-order)
407  * @arg mask mask to be applied before matching (network byte-order)
408  * @arg off offset, in bytes, to start matching
409  * @arg offmask offset mask
410  *
411  * General selectors define the pattern, mask and offset the pattern will be
412  * matched to the packet contents. Using the general selectors you can match
413  * virtually any single bit in the IP (or upper layer) header.
414  *
415 */
416 int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
417  int off, int offmask)
418 {
419  struct tc_u32_sel *sel;
420  struct rtnl_u32 *u;
421  int err;
422 
423  if (!(u = rtnl_tc_data(TC_CAST(cls))))
424  return -NLE_NOMEM;
425 
426  sel = u32_selector_alloc(u);
427  if (!sel)
428  return -NLE_NOMEM;
429 
430  err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
431  if (err < 0)
432  return err;
433 
434  /* the selector might have been moved by realloc */
435  sel = u32_selector(u);
436 
437  sel->keys[sel->nkeys].mask = mask;
438  sel->keys[sel->nkeys].val = val & mask;
439  sel->keys[sel->nkeys].off = off;
440  sel->keys[sel->nkeys].offmask = offmask;
441  sel->nkeys++;
442  u->cu_mask |= U32_ATTR_SELECTOR;
443 
444  return 0;
445 }
446 
447 int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
448  int off, int offmask)
449 {
450  int shift = 24 - 8 * (off & 3);
451 
452  return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
453  htonl((uint32_t)mask << shift),
454  off & ~3, offmask);
455 }
456 
457 /**
458  * Append new selector key to match a 16-bit number
459  *
460  * @arg cls classifier to be modified
461  * @arg val value to be matched (host byte-order)
462  * @arg mask mask to be applied before matching (host byte-order)
463  * @arg off offset, in bytes, to start matching
464  * @arg offmask offset mask
465 */
466 int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
467  int off, int offmask)
468 {
469  int shift = ((off & 3) == 0 ? 16 : 0);
470  if (off % 2)
471  return -NLE_INVAL;
472 
473  return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
474  htonl((uint32_t)mask << shift),
475  off & ~3, offmask);
476 }
477 
478 /**
479  * Append new selector key to match a 32-bit number
480  *
481  * @arg cls classifier to be modified
482  * @arg val value to be matched (host byte-order)
483  * @arg mask mask to be applied before matching (host byte-order)
484  * @arg off offset, in bytes, to start matching
485  * @arg offmask offset mask
486 */
487 int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
488  int off, int offmask)
489 {
490  return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
491  off & ~3, offmask);
492 }
493 
494 int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, struct in_addr *addr,
495  uint8_t bitmask, int off, int offmask)
496 {
497  uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
498  return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
499 }
500 
501 int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr,
502  uint8_t bitmask, int off, int offmask)
503 {
504  int i, err;
505 
506  for (i = 1; i <= 4; i++) {
507  if (32 * i - bitmask <= 0) {
508  if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
509  0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
510  return err;
511  }
512  else if (32 * i - bitmask < 32) {
513  uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
514  if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
515  htonl(mask), off+4*(i-1), offmask)) < 0)
516  return err;
517  }
518  /* otherwise, if (32*i - bitmask >= 32) no key is generated */
519  }
520 
521  return 0;
522 }
523 
524 /** @} */
525 
526 static struct rtnl_tc_ops u32_ops = {
527  .to_kind = "u32",
528  .to_type = RTNL_TC_TYPE_CLS,
529  .to_size = sizeof(struct rtnl_u32),
530  .to_msg_parser = u32_msg_parser,
531  .to_free_data = u32_free_data,
532  .to_clone = u32_clone,
533  .to_msg_fill = u32_msg_fill,
534  .to_dump = {
535  [NL_DUMP_LINE] = u32_dump_line,
536  [NL_DUMP_DETAILS] = u32_dump_details,
537  [NL_DUMP_STATS] = u32_dump_stats,
538  },
539 };
540 
541 static void __init u32_init(void)
542 {
543  rtnl_tc_register(&u32_ops);
544 }
545 
546 static void __exit u32_exit(void)
547 {
548  rtnl_tc_unregister(&u32_ops);
549 }
550 
551 /** @} */