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>
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
42 static inline struct tc_u32_sel *u32_selector(
struct rtnl_u32 *u)
44 return (
struct tc_u32_sel *) u->cu_selector->d_data;
47 static inline struct tc_u32_sel *u32_selector_alloc(
struct rtnl_u32 *u)
50 u->cu_selector =
nl_data_alloc(NULL,
sizeof(
struct tc_u32_sel));
52 return u32_selector(u);
55 static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
57 [TCA_U32_HASH] = { .type =
NLA_U32 },
58 [TCA_U32_CLASSID] = { .type =
NLA_U32 },
59 [TCA_U32_LINK] = { .type =
NLA_U32 },
62 [TCA_U32_SEL] = { .minlen =
sizeof(
struct tc_u32_sel) },
63 [TCA_U32_PCNT] = { .minlen =
sizeof(
struct tc_u32_pcnt) },
66 static int u32_msg_parser(
struct rtnl_tc *tc,
void *data)
68 struct rtnl_u32 *u = data;
69 struct nlattr *tb[TCA_U32_MAX + 1];
72 err = tca_parse(tb, TCA_U32_MAX, tc, u32_policy);
76 if (tb[TCA_U32_DIVISOR]) {
78 u->cu_mask |= U32_ATTR_DIVISOR;
81 if (tb[TCA_U32_SEL]) {
85 u->cu_mask |= U32_ATTR_SELECTOR;
88 if (tb[TCA_U32_HASH]) {
90 u->cu_mask |= U32_ATTR_HASH;
93 if (tb[TCA_U32_CLASSID]) {
95 u->cu_mask |= U32_ATTR_CLASSID;
98 if (tb[TCA_U32_LINK]) {
100 u->cu_mask |= U32_ATTR_LINK;
103 if (tb[TCA_U32_ACT]) {
107 u->cu_mask |= U32_ATTR_ACTION;
110 if (tb[TCA_U32_POLICE]) {
114 u->cu_mask |= U32_ATTR_POLICE;
117 if (tb[TCA_U32_PCNT]) {
118 struct tc_u32_sel *sel;
121 if (!tb[TCA_U32_SEL]) {
122 err = -NLE_MISSING_ATTR;
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) {
137 u->cu_mask |= U32_ATTR_PCNT;
140 if (tb[TCA_U32_INDEV]) {
141 nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
142 u->cu_mask |= U32_ATTR_INDEV;
153 static void u32_free_data(
struct rtnl_tc *tc,
void *data)
155 struct rtnl_u32 *u = data;
163 static int u32_clone(
void *_dst,
void *_src)
165 struct rtnl_u32 *dst = _dst, *src = _src;
167 if (src->cu_selector &&
171 if (src->cu_act && !(dst->cu_act =
nl_data_clone(src->cu_act)))
174 if (src->cu_police && !(dst->cu_police =
nl_data_clone(src->cu_police)))
177 if (src->cu_pcnt && !(dst->cu_pcnt =
nl_data_clone(src->cu_pcnt)))
183 static void u32_dump_line(
struct rtnl_tc *tc,
void *data,
186 struct rtnl_u32 *u = data;
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)
199 static void print_selector(
struct nl_dump_params *p,
struct tc_u32_sel *sel,
203 struct tc_u32_key *key;
205 if (sel->hmask || sel->hoff) {
210 nl_dump(p,
" hash at %u & 0x%x", sel->hoff, sel->hmask);
213 if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
214 nl_dump(p,
" offset at %u", sel->off);
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);
222 int flags = sel->flags;
225 #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
226 flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
228 PRINT_FLAG(TERMINAL);
230 PRINT_FLAG(VAROFFSET);
238 for (i = 0; i < sel->nkeys; i++) {
239 key = (
struct tc_u32_key *) ((
char *) sel +
sizeof(*sel)) + i;
242 nl_dump_line(p,
" match key at %s%u ",
243 key->offmask ?
"nexthdr+" :
"", key->off);
246 nl_dump(p,
"[0x%u] ", key->offmask);
248 nl_dump(p,
"& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
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]);
258 static void u32_dump_details(
struct rtnl_tc *tc,
void *data,
261 struct rtnl_u32 *u = data;
262 struct tc_u32_sel *s;
267 if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
272 s = u->cu_selector->d_data;
274 nl_dump(p,
"nkeys %u ", s->nkeys);
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));
280 if (u->cu_mask & U32_ATTR_LINK)
281 nl_dump(p,
"link %u ", u->cu_link);
283 if (u->cu_mask & U32_ATTR_INDEV)
284 nl_dump(p,
"indev %s ", u->cu_indev);
286 print_selector(p, s, u);
290 #define U32_ATTR_ACTION 0x040
291 #define U32_ATTR_POLICE 0x080
294 struct nl_data police;
298 static void u32_dump_stats(
struct rtnl_tc *tc,
void *data,
301 struct rtnl_u32 *u = data;
306 if (u->cu_mask & U32_ATTR_PCNT) {
307 struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
309 nl_dump_line(p,
" hit %8" PRIu64
" count %8" PRIu64
"\n",
314 static int u32_msg_fill(
struct rtnl_tc *tc,
void *data,
struct nl_msg *msg)
316 struct rtnl_u32 *u = data;
321 if (u->cu_mask & U32_ATTR_DIVISOR)
324 if (u->cu_mask & U32_ATTR_HASH)
327 if (u->cu_mask & U32_ATTR_CLASSID)
330 if (u->cu_mask & U32_ATTR_LINK)
333 if (u->cu_mask & U32_ATTR_SELECTOR)
336 if (u->cu_mask & U32_ATTR_ACTION)
339 if (u->cu_mask & U32_ATTR_POLICE)
342 if (u->cu_mask & U32_ATTR_INDEV)
356 void rtnl_u32_set_handle(
struct rtnl_cls *cls,
int htid,
int hash,
359 uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
364 int rtnl_u32_set_classid(
struct rtnl_cls *cls, uint32_t classid)
371 u->cu_classid = classid;
372 u->cu_mask |= U32_ATTR_CLASSID;
377 int rtnl_u32_set_divisor(
struct rtnl_cls *cls, uint32_t divisor)
384 u->cu_divisor = divisor;
385 u->cu_mask |= U32_ATTR_DIVISOR;
389 int rtnl_u32_set_link(
struct rtnl_cls *cls, uint32_t link)
397 u->cu_mask |= U32_ATTR_LINK;
401 int rtnl_u32_set_hashtable(
struct rtnl_cls *cls, uint32_t ht)
409 u->cu_mask |= U32_ATTR_HASH;
413 int rtnl_u32_set_hashmask(
struct rtnl_cls *cls, uint32_t hashmask, uint32_t offset)
416 struct tc_u32_sel *sel;
419 hashmask = htonl(hashmask);
424 sel = u32_selector_alloc(u);
428 err =
nl_data_append(u->cu_selector, NULL,
sizeof(
struct tc_u32_key));
432 sel = u32_selector(u);
434 sel->hmask = hashmask;
439 int rtnl_u32_set_cls_terminal(
struct rtnl_cls *cls)
442 struct tc_u32_sel *sel;
448 sel = u32_selector_alloc(u);
452 err =
nl_data_append(u->cu_selector, NULL,
sizeof(
struct tc_u32_key));
456 sel = u32_selector(u);
458 sel->flags |= TC_U32_TERMINAL;
469 int rtnl_u32_set_flags(
struct rtnl_cls *cls,
int flags)
471 struct tc_u32_sel *sel;
477 sel = u32_selector_alloc(u);
482 u->cu_mask |= U32_ATTR_SELECTOR;
502 int off,
int offmask)
504 struct tc_u32_sel *sel;
511 sel = u32_selector_alloc(u);
515 err =
nl_data_append(u->cu_selector, NULL,
sizeof(
struct tc_u32_key));
520 sel = u32_selector(u);
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;
527 u->cu_mask |= U32_ATTR_SELECTOR;
532 int rtnl_u32_add_key_uint8(
struct rtnl_cls *cls, uint8_t val, uint8_t mask,
533 int off,
int offmask)
535 int shift = 24 - 8 * (off & 3);
538 htonl((uint32_t)mask << shift),
552 int off,
int offmask)
554 int shift = ((off & 3) == 0 ? 16 : 0);
559 htonl((uint32_t)mask << shift),
573 int off,
int offmask)
579 int rtnl_u32_add_key_in_addr(
struct rtnl_cls *cls,
struct in_addr *addr,
580 uint8_t bitmask,
int off,
int offmask)
582 uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
586 int rtnl_u32_add_key_in6_addr(
struct rtnl_cls *cls,
struct in6_addr *addr,
587 uint8_t bitmask,
int off,
int offmask)
591 for (i = 1; i <= 4; i++) {
592 if (32 * i - bitmask <= 0) {
594 0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
597 else if (32 * i - bitmask < 32) {
598 uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
600 htonl(mask), off+4*(i-1), offmask)) < 0)
611 static struct rtnl_tc_ops u32_ops = {
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,
626 static void __init u32_init(
void)
631 static void __exit u32_exit(
void)