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 rtnl_u32 *u32_cls(
struct rtnl_cls *cls)
45 return (
struct rtnl_u32 *) cls->c_subdata;
48 static inline struct rtnl_u32 *u32_alloc(
struct rtnl_cls *cls)
51 cls->c_subdata = calloc(1,
sizeof(
struct rtnl_u32));
56 static inline struct tc_u32_sel *u32_selector(
struct rtnl_u32 *u)
58 return (
struct tc_u32_sel *) u->cu_selector->d_data;
61 static inline struct tc_u32_sel *u32_selector_alloc(
struct rtnl_u32 *u)
64 u->cu_selector =
nl_data_alloc(NULL,
sizeof(
struct tc_u32_sel));
66 return u32_selector(u);
69 static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
71 [TCA_U32_HASH] = { .type =
NLA_U32 },
72 [TCA_U32_CLASSID] = { .type =
NLA_U32 },
73 [TCA_U32_LINK] = { .type =
NLA_U32 },
76 [TCA_U32_SEL] = { .minlen =
sizeof(
struct tc_u32_sel) },
77 [TCA_U32_PCNT] = { .minlen =
sizeof(
struct tc_u32_pcnt) },
80 static int u32_msg_parser(
struct rtnl_cls *cls)
83 struct nlattr *tb[TCA_U32_MAX + 1];
86 err = tca_parse(tb, TCA_U32_MAX, (
struct rtnl_tca *) cls, u32_policy);
94 if (tb[TCA_U32_DIVISOR]) {
96 u->cu_mask |= U32_ATTR_DIVISOR;
99 if (tb[TCA_U32_SEL]) {
103 u->cu_mask |= U32_ATTR_SELECTOR;
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]) {
125 u->cu_mask |= U32_ATTR_ACTION;
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 = nl_error(EINVAL,
"Missing TCA_U32_SEL required "
145 sel = u->cu_selector->d_data;
146 pcnt_size =
sizeof(
struct tc_u32_pcnt) +
147 (sel->nkeys *
sizeof(uint64_t));
148 if (
nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
149 err = nl_error(EINVAL,
"Invalid size for TCA_U32_PCNT");
156 u->cu_mask |= U32_ATTR_PCNT;
159 if (tb[TCA_U32_INDEV]) {
160 nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
161 u->cu_mask |= U32_ATTR_INDEV;
167 err = nl_errno(ENOMEM);
172 static void u32_free_data(
struct rtnl_cls *cls)
174 struct rtnl_u32 *u = u32_cls(cls);
184 free(cls->c_subdata);
187 static int u32_clone(
struct rtnl_cls *_dst,
struct rtnl_cls *_src)
189 struct rtnl_u32 *dst, *src = u32_cls(_src);
194 dst = u32_alloc(_dst);
196 return nl_errno(ENOMEM);
198 if (src->cu_selector)
216 return nl_get_errno();
219 static int u32_dump_brief(
struct rtnl_cls *cls,
struct nl_dump_params *p,
222 struct rtnl_u32 *u = u32_cls(cls);
228 if (u->cu_mask & U32_ATTR_DIVISOR)
229 dp_dump(p,
" divisor %u", u->cu_divisor);
230 else if (u->cu_mask & U32_ATTR_CLASSID)
231 dp_dump(p,
" target %s",
238 static int print_selector(
struct nl_dump_params *p,
struct tc_u32_sel *sel,
239 struct rtnl_cls *cls,
struct rtnl_u32 *u,
int line)
242 struct tc_u32_key *key;
244 if (sel->hmask || sel->hoff) {
249 dp_dump(p,
" hash at %u & 0x%x", sel->hoff, sel->hmask);
252 if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
253 dp_dump(p,
" offset at %u", sel->off);
255 if (sel->flags & TC_U32_VAROFFSET)
256 dp_dump(p,
" variable (at %u & 0x%x) >> %u",
257 sel->offoff, ntohs(sel->offmask), sel->offshift);
261 int flags = sel->flags;
264 #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
265 flags &= ~TC_U32_##f; dp_dump(p, #f "%s", flags ? "," : ""); }
267 PRINT_FLAG(TERMINAL);
269 PRINT_FLAG(VAROFFSET);
277 for (i = 0; i < sel->nkeys; i++) {
278 key = (
struct tc_u32_key *) ((
char *) sel +
sizeof(*sel)) + i;
281 dp_dump_line(p, line++,
" match key at %s%u ",
282 key->offmask ?
"nexthdr+" :
"", key->off);
285 dp_dump(p,
"[0x%u] ", key->offmask);
287 dp_dump(p,
"& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
290 (u->cu_mask & U32_ATTR_PCNT)) {
291 struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
292 dp_dump(p,
" successful %" PRIu64, pcnt->kcnts[i]);
300 static int u32_dump_full(
struct rtnl_cls *cls,
struct nl_dump_params *p,
303 struct rtnl_u32 *u = u32_cls(cls);
304 struct tc_u32_sel *s;
309 if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
310 dp_dump(p,
"no-selector\n");
314 s = u->cu_selector->d_data;
316 dp_dump(p,
"nkeys %u ", s->nkeys);
318 if (u->cu_mask & U32_ATTR_HASH)
319 dp_dump(p,
"ht key 0x%x hash 0x%u",
320 TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
322 if (u->cu_mask & U32_ATTR_LINK)
323 dp_dump(p,
"link %u ", u->cu_link);
325 if (u->cu_mask & U32_ATTR_INDEV)
326 dp_dump(p,
"indev %s ", u->cu_indev);
328 line = print_selector(p, s, cls, u, line);
335 #define U32_ATTR_ACTION 0x040
336 #define U32_ATTR_POLICE 0x080
339 struct nl_data police;
343 static int u32_dump_stats(
struct rtnl_cls *cls,
struct nl_dump_params *p,
346 struct rtnl_u32 *u = u32_cls(cls);
351 if (u->cu_mask & U32_ATTR_PCNT) {
352 struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
354 dp_dump_line(p, line++,
"%s successful hits\n");
355 dp_dump_line(p, line++,
"%s %8llu %8llu\n",
363 static struct nl_msg *u32_get_opts(
struct rtnl_cls *cls)
376 if (u->cu_mask & U32_ATTR_DIVISOR)
379 if (u->cu_mask & U32_ATTR_HASH)
382 if (u->cu_mask & U32_ATTR_CLASSID)
385 if (u->cu_mask & U32_ATTR_LINK)
388 if (u->cu_mask & U32_ATTR_SELECTOR)
391 if (u->cu_mask & U32_ATTR_ACTION)
394 if (u->cu_mask & U32_ATTR_POLICE)
397 if (u->cu_mask & U32_ATTR_INDEV)
408 void rtnl_u32_set_handle(
struct rtnl_cls *cls,
int htid,
int hash,
411 uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
413 tca_set_handle((
struct rtnl_tca *) cls, handle );
416 int rtnl_u32_set_classid(
struct rtnl_cls *cls, uint32_t classid)
422 return nl_errno(ENOMEM);
424 u->cu_classid = classid;
425 u->cu_mask |= U32_ATTR_CLASSID;
437 int rtnl_u32_set_flags(
struct rtnl_cls *cls,
int flags)
439 struct tc_u32_sel *sel;
444 return nl_errno(ENOMEM);
446 sel = u32_selector_alloc(u);
448 return nl_errno(ENOMEM);
451 u->cu_mask |= U32_ATTR_SELECTOR;
471 int off,
int offmask)
473 struct tc_u32_sel *sel;
479 return nl_errno(ENOMEM);
481 sel = u32_selector_alloc(u);
483 return nl_errno(ENOMEM);
485 err =
nl_data_append(u->cu_selector, NULL,
sizeof(
struct tc_u32_key));
490 sel = u32_selector(u);
492 sel->keys[sel->nkeys].mask = mask;
493 sel->keys[sel->nkeys].val = val & mask;
494 sel->keys[sel->nkeys].off = off;
495 sel->keys[sel->nkeys].offmask = offmask;
497 u->cu_mask |= U32_ATTR_SELECTOR;
502 int rtnl_u32_add_key_uint8(
struct rtnl_cls *cls, uint8_t val, uint8_t mask,
503 int off,
int offmask)
505 int shift = 24 - 8 * (off & 3);
508 htonl((uint32_t)mask << shift),
522 int off,
int offmask)
524 int shift = ((off & 3) == 0 ? 16 : 0);
526 return nl_error(EINVAL,
"Invalid offset alignment");
529 htonl((uint32_t)mask << shift),
543 int off,
int offmask)
549 int rtnl_u32_add_key_in_addr(
struct rtnl_cls *cls,
struct in_addr *addr,
550 uint8_t bitmask,
int off,
int offmask)
552 uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
556 int rtnl_u32_add_key_in6_addr(
struct rtnl_cls *cls,
struct in6_addr *addr,
557 uint8_t bitmask,
int off,
int offmask)
561 for (i = 1; i <= 4; i++) {
562 if (32 * i - bitmask <= 0) {
564 0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
567 else if (32 * i - bitmask < 32) {
568 uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
570 htonl(mask), off+4*(i-1), offmask)) < 0)
583 .co_msg_parser = u32_msg_parser,
584 .co_free_data = u32_free_data,
585 .co_clone = u32_clone,
586 .co_get_opts = u32_get_opts,
592 static void __init u32_init(
void)
597 static void __exit u32_exit(
void)
Dump object in a brief one-liner.
char co_kind[32]
Kind/Name of classifier.
int rtnl_cls_unregister(struct rtnl_cls_ops *cops)
Unregister a classifier module.
struct nl_data * nl_data_clone(struct nl_data *src)
Clone an abstract data object.
attribute validation policy
enum nl_dump_type dp_type
Specifies the type of dump that is requested.
struct nl_msg * nlmsg_alloc(void)
Allocate a new netlink message with the default maximum payload size.
int nl_data_append(struct nl_data *data, void *buf, size_t size)
Append data to an abstract data 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.
char * rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
Convert a traffic control handle to a character string (Reentrant).
int nla_put_data(struct nl_msg *n, int attrtype, struct nl_data *data)
Add an abstract data netlink attribute to a netlink message.
int nla_len(const struct nlattr *nla)
length of payload
struct nl_data * nl_data_alloc(void *buf, size_t size)
Allocate a new abstract data object.
int nla_put_string(struct nl_msg *n, int attrtype, const char *str)
Add a string netlink attribute to a netlink message.
int rtnl_cls_register(struct rtnl_cls_ops *cops)
Register a classifier module.
uint16_t type
Type of attribute or NLA_UNSPEC.
struct nl_data * nla_get_data(struct nlattr *nla)
Return payload of abstract data 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.
uint32_t nla_get_u32(struct nlattr *nla)
Return payload of u32 attribute.
int nla_put_u32(struct nl_msg *n, int attrtype, uint32_t value)
Add a u32 netlink attribute to a netlink message.
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.
Dump all attributes but no statistics.
Dump all attributes including statistics.
size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
Copy string attribute payload into a sized buffer.
void nl_data_free(struct nl_data *data)
Free an abstract data object.