2 * lib/route/cls/u32.c u32 classifier
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
9 * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch>
10 * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com>
11 * Copyright (c) 2005-2006 Siemens AG Oesterreich
16 * @defgroup u32 Universal 32-bit Classifier
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>
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
43 static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u)
45 return (struct tc_u32_sel *) u->cu_selector->d_data;
48 static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u)
51 u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel));
53 return u32_selector(u);
56 static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
57 [TCA_U32_DIVISOR] = { .type = NLA_U32 },
58 [TCA_U32_HASH] = { .type = NLA_U32 },
59 [TCA_U32_CLASSID] = { .type = NLA_U32 },
60 [TCA_U32_LINK] = { .type = NLA_U32 },
61 [TCA_U32_INDEV] = { .type = NLA_STRING,
63 [TCA_U32_SEL] = { .minlen = sizeof(struct tc_u32_sel) },
64 [TCA_U32_PCNT] = { .minlen = sizeof(struct tc_u32_pcnt) },
67 static int u32_msg_parser(struct rtnl_cls *cls)
69 struct rtnl_u32 *u = rtnl_cls_data(cls);
70 struct nlattr *tb[TCA_U32_MAX + 1];
73 err = tca_parse(tb, TCA_U32_MAX, (struct rtnl_tca *) cls, u32_policy);
77 if (tb[TCA_U32_DIVISOR]) {
78 u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
79 u->cu_mask |= U32_ATTR_DIVISOR;
82 if (tb[TCA_U32_SEL]) {
83 u->cu_selector = nl_data_alloc_attr(tb[TCA_U32_SEL]);
86 u->cu_mask |= U32_ATTR_SELECTOR;
89 if (tb[TCA_U32_HASH]) {
90 u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]);
91 u->cu_mask |= U32_ATTR_HASH;
94 if (tb[TCA_U32_CLASSID]) {
95 u->cu_classid = nla_get_u32(tb[TCA_U32_CLASSID]);
96 u->cu_mask |= U32_ATTR_CLASSID;
99 if (tb[TCA_U32_LINK]) {
100 u->cu_link = nla_get_u32(tb[TCA_U32_LINK]);
101 u->cu_mask |= U32_ATTR_LINK;
104 if (tb[TCA_U32_ACT]) {
105 u->cu_act = nl_data_alloc_attr(tb[TCA_U32_ACT]);
108 u->cu_mask |= U32_ATTR_ACTION;
111 if (tb[TCA_U32_POLICE]) {
112 u->cu_police = nl_data_alloc_attr(tb[TCA_U32_POLICE]);
115 u->cu_mask |= U32_ATTR_POLICE;
118 if (tb[TCA_U32_PCNT]) {
119 struct tc_u32_sel *sel;
122 if (!tb[TCA_U32_SEL]) {
123 err = -NLE_MISSING_ATTR;
127 sel = u->cu_selector->d_data;
128 pcnt_size = sizeof(struct tc_u32_pcnt) +
129 (sel->nkeys * sizeof(uint64_t));
130 if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
135 u->cu_pcnt = nl_data_alloc_attr(tb[TCA_U32_PCNT]);
138 u->cu_mask |= U32_ATTR_PCNT;
141 if (tb[TCA_U32_INDEV]) {
142 nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
143 u->cu_mask |= U32_ATTR_INDEV;
154 static void u32_free_data(struct rtnl_cls *cls)
156 struct rtnl_u32 *u = rtnl_cls_data(cls);
158 nl_data_free(u->cu_selector);
159 nl_data_free(u->cu_act);
160 nl_data_free(u->cu_police);
161 nl_data_free(u->cu_pcnt);
164 static int u32_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src)
166 struct rtnl_u32 *dst = rtnl_cls_data(_dst);
167 struct rtnl_u32 *src = rtnl_cls_data(_src);
169 if (src->cu_selector &&
170 !(dst->cu_selector = nl_data_clone(src->cu_selector)))
173 if (src->cu_act && !(dst->cu_act = nl_data_clone(src->cu_act)))
176 if (src->cu_police && !(dst->cu_police = nl_data_clone(src->cu_police)))
179 if (src->cu_pcnt && !(dst->cu_pcnt = nl_data_clone(src->cu_pcnt)))
185 static void u32_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p)
187 struct rtnl_u32 *u = rtnl_cls_data(cls);
190 if (u->cu_mask & U32_ATTR_DIVISOR)
191 nl_dump(p, " divisor %u", u->cu_divisor);
192 else if (u->cu_mask & U32_ATTR_CLASSID)
193 nl_dump(p, " target %s",
194 rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
197 static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
198 struct rtnl_cls *cls, struct rtnl_u32 *u)
201 struct tc_u32_key *key;
203 if (sel->hmask || sel->hoff) {
204 /* I guess this will never be used since the kernel only
205 * exports the selector if no divisor is set but hash offset
206 * and hash mask make only sense in hash filters with divisor
208 nl_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
211 if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
212 nl_dump(p, " offset at %u", sel->off);
214 if (sel->flags & TC_U32_VAROFFSET)
215 nl_dump(p, " variable (at %u & 0x%x) >> %u",
216 sel->offoff, ntohs(sel->offmask), sel->offshift);
220 int flags = sel->flags;
223 #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
224 flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
226 PRINT_FLAG(TERMINAL);
228 PRINT_FLAG(VAROFFSET);
236 for (i = 0; i < sel->nkeys; i++) {
237 key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i;
240 nl_dump_line(p, " match key at %s%u ",
241 key->offmask ? "nexthdr+" : "", key->off);
244 nl_dump(p, "[0x%u] ", key->offmask);
246 nl_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
248 if (p->dp_type == NL_DUMP_STATS &&
249 (u->cu_mask & U32_ATTR_PCNT)) {
250 struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
251 nl_dump(p, " successful %" PRIu64, pcnt->kcnts[i]);
256 static void u32_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p)
258 struct rtnl_u32 *u = rtnl_cls_data(cls);
259 struct tc_u32_sel *s;
261 if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
262 nl_dump(p, "no-selector\n");
266 s = u->cu_selector->d_data;
268 nl_dump(p, "nkeys %u ", s->nkeys);
270 if (u->cu_mask & U32_ATTR_HASH)
271 nl_dump(p, "ht key 0x%x hash 0x%u",
272 TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
274 if (u->cu_mask & U32_ATTR_LINK)
275 nl_dump(p, "link %u ", u->cu_link);
277 if (u->cu_mask & U32_ATTR_INDEV)
278 nl_dump(p, "indev %s ", u->cu_indev);
280 print_selector(p, s, cls, u);
284 #define U32_ATTR_ACTION 0x040
285 #define U32_ATTR_POLICE 0x080
288 struct nl_data police;
292 static void u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p)
294 struct rtnl_u32 *u = rtnl_cls_data(cls);
296 if (u->cu_mask & U32_ATTR_PCNT) {
297 struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
299 nl_dump_line(p, " hit %8llu count %8llu\n",
304 static int u32_get_opts(struct rtnl_cls *cls, struct nl_msg *msg)
306 struct rtnl_u32 *u = rtnl_cls_data(cls);
308 if (u->cu_mask & U32_ATTR_DIVISOR)
309 NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor);
311 if (u->cu_mask & U32_ATTR_HASH)
312 NLA_PUT_U32(msg, TCA_U32_HASH, u->cu_hash);
314 if (u->cu_mask & U32_ATTR_CLASSID)
315 NLA_PUT_U32(msg, TCA_U32_CLASSID, u->cu_classid);
317 if (u->cu_mask & U32_ATTR_LINK)
318 NLA_PUT_U32(msg, TCA_U32_LINK, u->cu_link);
320 if (u->cu_mask & U32_ATTR_SELECTOR)
321 NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector);
323 if (u->cu_mask & U32_ATTR_ACTION)
324 NLA_PUT_DATA(msg, TCA_U32_ACT, u->cu_act);
326 if (u->cu_mask & U32_ATTR_POLICE)
327 NLA_PUT_DATA(msg, TCA_U32_POLICE, u->cu_police);
329 if (u->cu_mask & U32_ATTR_INDEV)
330 NLA_PUT_STRING(msg, TCA_U32_INDEV, u->cu_indev);
339 * @name Attribute Modifications
343 void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
346 uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
348 tca_set_handle((struct rtnl_tca *) cls, handle );
351 int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
353 struct rtnl_u32 *u = rtnl_cls_data(cls);
355 u->cu_classid = classid;
356 u->cu_mask |= U32_ATTR_CLASSID;
364 * @name Selector Modifications
368 int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
370 struct tc_u32_sel *sel;
371 struct rtnl_u32 *u = rtnl_cls_data(cls);
373 sel = u32_selector_alloc(u);
378 u->cu_mask |= U32_ATTR_SELECTOR;
384 * Append new 32-bit key to the selector
386 * @arg cls classifier to be modifier
387 * @arg val value to be matched (network byte-order)
388 * @arg mask mask to be applied before matching (network byte-order)
389 * @arg off offset, in bytes, to start matching
390 * @arg offmask offset mask
392 * General selectors define the pattern, mask and offset the pattern will be
393 * matched to the packet contents. Using the general selectors you can match
394 * virtually any single bit in the IP (or upper layer) header.
397 int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
398 int off, int offmask)
400 struct tc_u32_sel *sel;
401 struct rtnl_u32 *u = rtnl_cls_data(cls);
404 sel = u32_selector_alloc(u);
408 err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
412 /* the selector might have been moved by realloc */
413 sel = u32_selector(u);
415 sel->keys[sel->nkeys].mask = mask;
416 sel->keys[sel->nkeys].val = val & mask;
417 sel->keys[sel->nkeys].off = off;
418 sel->keys[sel->nkeys].offmask = offmask;
420 u->cu_mask |= U32_ATTR_SELECTOR;
425 int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
426 int off, int offmask)
428 int shift = 24 - 8 * (off & 3);
430 return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
431 htonl((uint32_t)mask << shift),
436 * Append new selector key to match a 16-bit number
438 * @arg cls classifier to be modified
439 * @arg val value to be matched (host byte-order)
440 * @arg mask mask to be applied before matching (host byte-order)
441 * @arg off offset, in bytes, to start matching
442 * @arg offmask offset mask
444 int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
445 int off, int offmask)
447 int shift = ((off & 3) == 0 ? 16 : 0);
451 return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
452 htonl((uint32_t)mask << shift),
457 * Append new selector key to match a 32-bit number
459 * @arg cls classifier to be modified
460 * @arg val value to be matched (host byte-order)
461 * @arg mask mask to be applied before matching (host byte-order)
462 * @arg off offset, in bytes, to start matching
463 * @arg offmask offset mask
465 int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
466 int off, int offmask)
468 return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
472 int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, struct in_addr *addr,
473 uint8_t bitmask, int off, int offmask)
475 uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
476 return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
479 int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr,
480 uint8_t bitmask, int off, int offmask)
484 for (i = 1; i <= 4; i++) {
485 if (32 * i - bitmask <= 0) {
486 if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
487 0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
490 else if (32 * i - bitmask < 32) {
491 uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
492 if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
493 htonl(mask), off+4*(i-1), offmask)) < 0)
496 /* otherwise, if (32*i - bitmask >= 32) no key is generated */
504 static struct rtnl_cls_ops u32_ops = {
506 .co_size = sizeof(struct rtnl_u32),
507 .co_msg_parser = u32_msg_parser,
508 .co_free_data = u32_free_data,
509 .co_clone = u32_clone,
510 .co_get_opts = u32_get_opts,
512 [NL_DUMP_LINE] = u32_dump_line,
513 [NL_DUMP_DETAILS] = u32_dump_details,
514 [NL_DUMP_STATS] = u32_dump_stats,
518 static void __init u32_init(void)
520 rtnl_cls_register(&u32_ops);
523 static void __exit u32_exit(void)
525 rtnl_cls_unregister(&u32_ops);