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 #include <netlink/route/action.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
41 #define U32_ATTR_MARK 0x200
44 static inline struct tc_u32_sel *u32_selector(
struct rtnl_u32 *u)
46 return (
struct tc_u32_sel *) u->cu_selector->d_data;
49 static inline struct tc_u32_sel *u32_selector_alloc(
struct rtnl_u32 *u)
52 u->cu_selector =
nl_data_alloc(NULL,
sizeof(
struct tc_u32_sel));
54 return u32_selector(u);
57 static inline struct tc_u32_mark *u32_mark_alloc(
struct rtnl_u32 *u)
62 return (
struct tc_u32_mark *) u->cu_mark->d_data;
65 static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
67 [TCA_U32_HASH] = { .type =
NLA_U32 },
68 [TCA_U32_CLASSID] = { .type =
NLA_U32 },
69 [TCA_U32_LINK] = { .type =
NLA_U32 },
72 [TCA_U32_SEL] = { .minlen =
sizeof(
struct tc_u32_sel) },
73 [TCA_U32_PCNT] = { .minlen =
sizeof(
struct tc_u32_pcnt) },
74 [TCA_U32_MARK] = { .minlen =
sizeof(
struct tc_u32_mark) }
77 static int u32_msg_parser(
struct rtnl_tc *tc,
void *data)
79 struct rtnl_u32 *u = data;
80 struct nlattr *tb[TCA_U32_MAX + 1];
83 err = tca_parse(tb, TCA_U32_MAX, tc, u32_policy);
87 if (tb[TCA_U32_DIVISOR]) {
89 u->cu_mask |= U32_ATTR_DIVISOR;
92 if (tb[TCA_U32_SEL]) {
96 u->cu_mask |= U32_ATTR_SELECTOR;
99 if (tb[TCA_U32_MARK]) {
103 u->cu_mask |= U32_ATTR_MARK;
106 if (tb[TCA_U32_HASH]) {
108 u->cu_mask |= U32_ATTR_HASH;
111 if (tb[TCA_U32_CLASSID]) {
113 u->cu_mask |= U32_ATTR_CLASSID;
116 if (tb[TCA_U32_LINK]) {
118 u->cu_mask |= U32_ATTR_LINK;
121 if (tb[TCA_U32_ACT]) {
122 u->cu_mask |= U32_ATTR_ACTION;
123 err = rtnl_act_parse(&u->cu_act, tb[TCA_U32_ACT]);
128 if (tb[TCA_U32_POLICE]) {
132 u->cu_mask |= U32_ATTR_POLICE;
135 if (tb[TCA_U32_PCNT]) {
136 struct tc_u32_sel *sel;
139 if (!tb[TCA_U32_SEL]) {
140 err = -NLE_MISSING_ATTR;
144 sel = u->cu_selector->d_data;
145 pcnt_size =
sizeof(
struct tc_u32_pcnt) +
146 (sel->nkeys *
sizeof(uint64_t));
147 if (
nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
155 u->cu_mask |= U32_ATTR_PCNT;
158 if (tb[TCA_U32_INDEV]) {
159 nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
160 u->cu_mask |= U32_ATTR_INDEV;
171 static void u32_free_data(
struct rtnl_tc *tc,
void *data)
173 struct rtnl_u32 *u = data;
176 rtnl_act_put_all(&u->cu_act);
183 static int u32_clone(
void *_dst,
void *_src)
185 struct rtnl_u32 *dst = _dst, *src = _src;
187 if (src->cu_selector &&
196 if (!(dst->cu_act = rtnl_act_alloc()))
199 memcpy(dst->cu_act, src->cu_act,
sizeof(
struct rtnl_act));
202 if (src->cu_police && !(dst->cu_police =
nl_data_clone(src->cu_police)))
205 if (src->cu_pcnt && !(dst->cu_pcnt =
nl_data_clone(src->cu_pcnt)))
211 static void u32_dump_line(
struct rtnl_tc *tc,
void *data,
214 struct rtnl_u32 *u = data;
220 if (u->cu_mask & U32_ATTR_DIVISOR)
221 nl_dump(p,
" divisor %u", u->cu_divisor);
222 else if (u->cu_mask & U32_ATTR_CLASSID)
227 static void print_selector(
struct nl_dump_params *p,
struct tc_u32_sel *sel,
231 struct tc_u32_key *key;
233 if (sel->hmask || sel->hoff) {
238 nl_dump(p,
" hash at %u & 0x%x", sel->hoff, sel->hmask);
241 if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
242 nl_dump(p,
" offset at %u", sel->off);
244 if (sel->flags & TC_U32_VAROFFSET)
245 nl_dump(p,
" variable (at %u & 0x%x) >> %u",
246 sel->offoff, ntohs(sel->offmask), sel->offshift);
250 int flags = sel->flags;
253 #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
254 flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
256 PRINT_FLAG(TERMINAL);
258 PRINT_FLAG(VAROFFSET);
266 for (i = 0; i < sel->nkeys; i++) {
267 key = (
struct tc_u32_key *) ((
char *) sel +
sizeof(*sel)) + i;
270 nl_dump_line(p,
" match key at %s%u ",
271 key->offmask ?
"nexthdr+" :
"", key->off);
274 nl_dump(p,
"[0x%u] ", key->offmask);
276 nl_dump(p,
"& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
279 (u->cu_mask & U32_ATTR_PCNT)) {
280 struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
281 nl_dump(p,
" successful %" PRIu64, pcnt->kcnts[i]);
286 static void u32_dump_details(
struct rtnl_tc *tc,
void *data,
289 struct rtnl_u32 *u = data;
290 struct tc_u32_sel *s = NULL;
291 struct tc_u32_mark *m;
296 if (!(u->cu_mask & (U32_ATTR_SELECTOR & U32_ATTR_MARK))) {
297 nl_dump(p,
"no-selector no-mark\n");
301 if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
304 s = u->cu_selector->d_data;
305 nl_dump(p,
"nkeys %u", s->nkeys);
308 if (!(u->cu_mask & U32_ATTR_MARK)) {
311 m = u->cu_mark->d_data;
312 nl_dump(p,
" mark 0x%u 0x%u", m->val, m->mask);
315 if (u->cu_mask & U32_ATTR_HASH)
316 nl_dump(p,
" ht key 0x%x hash 0x%u",
317 TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
319 if (u->cu_mask & U32_ATTR_LINK)
320 nl_dump(p,
" link %u", u->cu_link);
322 if (u->cu_mask & U32_ATTR_INDEV)
323 nl_dump(p,
" indev %s", u->cu_indev);
325 if (u->cu_mask & U32_ATTR_SELECTOR)
326 print_selector(p, s, u);
331 static void u32_dump_stats(
struct rtnl_tc *tc,
void *data,
334 struct rtnl_u32 *u = data;
339 if (u->cu_mask & U32_ATTR_PCNT) {
340 struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
342 nl_dump_line(p,
" hit %8" PRIu64
" count %8" PRIu64
"\n",
347 static int u32_msg_fill(
struct rtnl_tc *tc,
void *data,
struct nl_msg *msg)
349 struct rtnl_u32 *u = data;
354 if (u->cu_mask & U32_ATTR_DIVISOR)
357 if (u->cu_mask & U32_ATTR_HASH)
360 if (u->cu_mask & U32_ATTR_CLASSID)
363 if (u->cu_mask & U32_ATTR_LINK)
366 if (u->cu_mask & U32_ATTR_SELECTOR)
369 if (u->cu_mask & U32_ATTR_MARK)
372 if (u->cu_mask & U32_ATTR_ACTION) {
375 err = rtnl_act_fill(msg, TCA_U32_ACT, u->cu_act);
380 if (u->cu_mask & U32_ATTR_POLICE)
383 if (u->cu_mask & U32_ATTR_INDEV)
397 void rtnl_u32_set_handle(
struct rtnl_cls *cls,
int htid,
int hash,
400 uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
405 int rtnl_u32_set_classid(
struct rtnl_cls *cls, uint32_t classid)
412 u->cu_classid = classid;
413 u->cu_mask |= U32_ATTR_CLASSID;
418 int rtnl_u32_get_classid(
struct rtnl_cls *cls, uint32_t *classid)
425 if (!(u->cu_mask & U32_ATTR_CLASSID))
428 *classid = u->cu_classid;
432 int rtnl_u32_set_divisor(
struct rtnl_cls *cls, uint32_t divisor)
439 u->cu_divisor = divisor;
440 u->cu_mask |= U32_ATTR_DIVISOR;
444 int rtnl_u32_set_link(
struct rtnl_cls *cls, uint32_t link)
452 u->cu_mask |= U32_ATTR_LINK;
456 int rtnl_u32_set_hashtable(
struct rtnl_cls *cls, uint32_t ht)
464 u->cu_mask |= U32_ATTR_HASH;
468 int rtnl_u32_set_hashmask(
struct rtnl_cls *cls, uint32_t hashmask, uint32_t offset)
471 struct tc_u32_sel *sel;
474 hashmask = htonl(hashmask);
479 sel = u32_selector_alloc(u);
483 err =
nl_data_append(u->cu_selector, NULL,
sizeof(
struct tc_u32_key));
487 sel = u32_selector(u);
489 sel->hmask = hashmask;
494 int rtnl_u32_set_cls_terminal(
struct rtnl_cls *cls)
497 struct tc_u32_sel *sel;
503 sel = u32_selector_alloc(u);
507 err =
nl_data_append(u->cu_selector, NULL,
sizeof(
struct tc_u32_key));
511 sel = u32_selector(u);
513 sel->flags |= TC_U32_TERMINAL;
517 int rtnl_u32_add_action(
struct rtnl_cls *cls,
struct rtnl_act *act)
527 u->cu_mask |= U32_ATTR_ACTION;
530 return rtnl_act_append(&u->cu_act, act);
533 int rtnl_u32_del_action(
struct rtnl_cls *cls,
struct rtnl_act *act)
544 if (!(u->cu_mask & U32_ATTR_ACTION))
547 ret = rtnl_act_remove(&u->cu_act, act);
552 u->cu_mask &= ~U32_ATTR_ACTION;
563 int rtnl_u32_set_flags(
struct rtnl_cls *cls,
int flags)
565 struct tc_u32_sel *sel;
571 sel = u32_selector_alloc(u);
576 u->cu_mask |= U32_ATTR_SELECTOR;
596 int off,
int offmask)
598 struct tc_u32_sel *sel;
605 sel = u32_selector_alloc(u);
609 err =
nl_data_append(u->cu_selector, NULL,
sizeof(
struct tc_u32_key));
614 sel = u32_selector(u);
616 sel->keys[sel->nkeys].mask = mask;
617 sel->keys[sel->nkeys].val = val & mask;
618 sel->keys[sel->nkeys].off = off;
619 sel->keys[sel->nkeys].offmask = offmask;
621 u->cu_mask |= U32_ATTR_SELECTOR;
626 int rtnl_u32_add_mark(
struct rtnl_cls *cls, uint32_t val, uint32_t mask)
628 struct tc_u32_mark *mark;
634 mark = u32_mark_alloc(u);
641 u->cu_mask |= U32_ATTR_MARK;
646 int rtnl_u32_del_mark(
struct rtnl_cls *cls)
656 if (!(u->cu_mask & U32_ATTR_MARK))
661 u->cu_mask &= ~U32_ATTR_MARK;
678 uint32_t *val, uint32_t *mask,
int *off,
int *offmask)
680 struct tc_u32_sel *sel;
686 if (!(u->cu_mask & U32_ATTR_SELECTOR))
690 sel = u32_selector(u);
691 if (index >= sel->nkeys)
694 *mask = sel->keys[index].mask;
695 *val = sel->keys[index].val;
696 *off = sel->keys[index].off;
697 *offmask = sel->keys[index].offmask;
702 int rtnl_u32_add_key_uint8(
struct rtnl_cls *cls, uint8_t val, uint8_t mask,
703 int off,
int offmask)
705 int shift = 24 - 8 * (off & 3);
708 htonl((uint32_t)mask << shift),
722 int off,
int offmask)
724 int shift = ((off & 3) == 0 ? 16 : 0);
729 htonl((uint32_t)mask << shift),
743 int off,
int offmask)
749 int rtnl_u32_add_key_in_addr(
struct rtnl_cls *cls,
const struct in_addr *addr,
750 uint8_t bitmask,
int off,
int offmask)
752 uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
756 int rtnl_u32_add_key_in6_addr(
struct rtnl_cls *cls,
const struct in6_addr *addr,
757 uint8_t bitmask,
int off,
int offmask)
761 for (i = 1; i <= 4; i++) {
762 if (32 * i - bitmask <= 0) {
764 0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
767 else if (32 * i - bitmask < 32) {
768 uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
770 htonl(mask), off+4*(i-1), offmask)) < 0)
781 static struct rtnl_tc_ops u32_ops = {
783 .to_type = RTNL_TC_TYPE_CLS,
784 .to_size =
sizeof(
struct rtnl_u32),
785 .to_msg_parser = u32_msg_parser,
786 .to_free_data = u32_free_data,
787 .to_clone = u32_clone,
788 .to_msg_fill = u32_msg_fill,
796 static void __init u32_init(
void)
801 static void __exit u32_exit(
void)
Dump object briefly on one line.
int rtnl_tc_register(struct rtnl_tc_ops *ops)
Register a traffic control module.
Attribute validation policy.
#define NLA_PUT_DATA(msg, attrtype, data)
Add abstract data attribute to netlink message.
enum nl_dump_type dp_type
Specifies the type of dump that is requested.
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.
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
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.
struct nl_data * nl_data_alloc_attr(const struct nlattr *nla)
Allocate abstract data object based on netlink attribute.
int nl_data_append(struct nl_data *data, const void *buf, size_t size)
Append data to an abstract data object.
NUL terminated character string.
Dump all attributes but no statistics.
void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
Unregister a traffic control module.
int rtnl_u32_get_key(struct rtnl_cls *cls, uint8_t index, uint32_t *val, uint32_t *mask, int *off, int *offmask)
Get the 32-bit key from the selector.
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
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.
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
int nla_len(const struct nlattr *nla)
Return length of the payload .
void rtnl_tc_set_handle(struct rtnl_tc *tc, uint32_t id)
Set identifier of traffic control object.
struct nl_data * nl_data_clone(const struct nl_data *src)
Clone an abstract data object.
void * rtnl_tc_data(struct rtnl_tc *tc)
Return pointer to private data of traffic control object.
struct nl_data * nl_data_alloc(const void *buf, size_t size)
Allocate a new abstract data object.
#define NLA_PUT_STRING(msg, attrtype, value)
Add string attribute to netlink message.
uint16_t type
Type of attribute or NLA_UNSPEC.
char * rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
Convert a traffic control handle to a character string (Reentrant).
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
void * rtnl_tc_data_peek(struct rtnl_tc *tc)
Returns the private data of the traffic control object.
Dump all attributes including statistics.
size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
Copy string attribute payload to a buffer.
void nl_data_free(struct nl_data *data)
Free an abstract data object.