15#include "nl-default.h"
17#include <netlink/netlink.h>
18#include <netlink/attr.h>
19#include <netlink/utils.h>
20#include <netlink/route/classifier.h>
21#include <netlink/route/cls/u32.h>
22#include <netlink/route/action.h>
25#include "nl-aux-route/nl-route.h"
33 struct nl_data *cu_pcnt;
34 struct nl_data *cu_selector;
35 struct nl_data *cu_mark;
37 struct nl_data *cu_police;
38 char cu_indev[IFNAMSIZ];
42#define U32_ATTR_DIVISOR 0x001
43#define U32_ATTR_HASH 0x002
44#define U32_ATTR_CLASSID 0x004
45#define U32_ATTR_LINK 0x008
46#define U32_ATTR_PCNT 0x010
47#define U32_ATTR_SELECTOR 0x020
48#define U32_ATTR_ACTION 0x040
49#define U32_ATTR_POLICE 0x080
50#define U32_ATTR_INDEV 0x100
51#define U32_ATTR_MARK 0x200
54static inline struct tc_u32_sel *u32_selector(
struct rtnl_u32 *u)
56 return (
struct tc_u32_sel *) u->cu_selector->d_data;
59static inline struct tc_u32_sel *u32_selector_alloc(
struct rtnl_u32 *u)
62 u->cu_selector =
nl_data_alloc(NULL,
sizeof(
struct tc_u32_sel));
64 return u32_selector(u);
67static inline struct tc_u32_mark *u32_mark_alloc(
struct rtnl_u32 *u)
72 return (
struct tc_u32_mark *) u->cu_mark->d_data;
75static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
77 [TCA_U32_HASH] = { .type =
NLA_U32 },
78 [TCA_U32_CLASSID] = { .type =
NLA_U32 },
79 [TCA_U32_LINK] = { .type =
NLA_U32 },
82 [TCA_U32_SEL] = { .minlen =
sizeof(
struct tc_u32_sel) },
83 [TCA_U32_PCNT] = { .minlen =
sizeof(
struct tc_u32_pcnt) },
84 [TCA_U32_MARK] = { .minlen =
sizeof(
struct tc_u32_mark) }
87static int u32_msg_parser(
struct rtnl_tc *tc,
void *data)
89 struct rtnl_u32 *u = data;
90 struct nlattr *tb[TCA_U32_MAX + 1];
93 err = tca_parse(tb, TCA_U32_MAX, tc, u32_policy);
97 if (tb[TCA_U32_DIVISOR]) {
99 u->cu_mask |= U32_ATTR_DIVISOR;
102 if (tb[TCA_U32_SEL]) {
106 u->cu_mask |= U32_ATTR_SELECTOR;
109 if (tb[TCA_U32_MARK]) {
113 u->cu_mask |= U32_ATTR_MARK;
116 if (tb[TCA_U32_HASH]) {
118 u->cu_mask |= U32_ATTR_HASH;
121 if (tb[TCA_U32_CLASSID]) {
123 u->cu_mask |= U32_ATTR_CLASSID;
126 if (tb[TCA_U32_LINK]) {
128 u->cu_mask |= U32_ATTR_LINK;
131 if (tb[TCA_U32_ACT]) {
132 u->cu_mask |= U32_ATTR_ACTION;
133 err = rtnl_act_parse(&u->cu_act, tb[TCA_U32_ACT]);
138 if (tb[TCA_U32_POLICE]) {
142 u->cu_mask |= U32_ATTR_POLICE;
145 if (tb[TCA_U32_PCNT]) {
146 struct tc_u32_sel *sel;
149 if (!tb[TCA_U32_SEL]) {
150 err = -NLE_MISSING_ATTR;
154 sel = u->cu_selector->d_data;
155 pcnt_size =
sizeof(
struct tc_u32_pcnt) +
156 (sel->nkeys *
sizeof(uint64_t));
157 if (
nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
165 u->cu_mask |= U32_ATTR_PCNT;
168 if (tb[TCA_U32_INDEV]) {
169 nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
170 u->cu_mask |= U32_ATTR_INDEV;
181static void u32_free_data(
struct rtnl_tc *tc,
void *data)
183 struct rtnl_u32 *u = data;
186 rtnl_act_put_all(&u->cu_act);
193static int u32_clone(
void *_dst,
void *_src)
195 struct rtnl_u32 *dst = _dst, *src = _src;
196 _nl_auto_nl_data
struct nl_data *selector = NULL;
197 _nl_auto_nl_data
struct nl_data *mark = NULL;
198 _nl_auto_nl_data
struct nl_data *police = NULL;
199 _nl_auto_nl_data
struct nl_data *pcnt = NULL;
200 _nl_auto_nl_data
struct nl_data *opts = NULL;
201 _nl_auto_nl_data
struct nl_data *xstats = NULL;
202 _nl_auto_nl_data
struct nl_data *subdata = NULL;
203 _nl_auto_rtnl_act
struct rtnl_act *act = NULL;
206 dst->cu_selector = NULL;
209 dst->cu_police = NULL;
211 if (src->cu_selector) {
222 if (!(act = rtnl_act_alloc()))
225 if (src->cu_act->c_opts) {
230 if (src->cu_act->c_xstats) {
235 if (src->cu_act->c_subdata) {
241 if (src->cu_police) {
254 dst->cu_selector = _nl_steal_pointer(&selector);
257 dst->cu_mark = _nl_steal_pointer(&mark);
260 dst->cu_police = _nl_steal_pointer(&police);
263 dst->cu_pcnt = _nl_steal_pointer(&pcnt);
266 dst->cu_act = _nl_steal_pointer(&act);
269 nl_init_list_head(&dst->cu_act->ce_list);
272 dst->cu_act->c_opts = _nl_steal_pointer(&opts);
275 dst->cu_act->c_xstats = _nl_steal_pointer(&xstats);
278 dst->cu_act->c_subdata = _nl_steal_pointer(&subdata);
280 if (dst->cu_act->c_link) {
284 dst->cu_act->a_next = NULL;
290static void u32_dump_line(
struct rtnl_tc *tc,
void *data,
293 struct rtnl_u32 *u = data;
299 if (u->cu_mask & U32_ATTR_DIVISOR)
300 nl_dump(p,
" divisor %u", u->cu_divisor);
301 else if (u->cu_mask & U32_ATTR_CLASSID)
306static void print_selector(
struct nl_dump_params *p,
struct tc_u32_sel *sel,
310 struct tc_u32_key *key;
312 if (sel->hmask || sel->hoff) {
317 nl_dump(p,
" hash at %u & 0x%x", sel->hoff, sel->hmask);
320 if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
321 nl_dump(p,
" offset at %u", sel->off);
323 if (sel->flags & TC_U32_VAROFFSET)
324 nl_dump(p,
" variable (at %u & 0x%x) >> %u",
325 sel->offoff, ntohs(sel->offmask), sel->offshift);
329 int flags = sel->flags;
332#define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
333 flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
335 PRINT_FLAG(TERMINAL);
337 PRINT_FLAG(VAROFFSET);
345 for (i = 0; i < sel->nkeys; i++) {
349 nl_dump_line(p,
" match key at %s%u ",
350 key->offmask ?
"nexthdr+" :
"", key->off);
353 nl_dump(p,
"[0x%u] ", key->offmask);
355 nl_dump(p,
"& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
358 (u->cu_mask & U32_ATTR_PCNT)) {
359 struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
362 (
long long unsigned)pcnt->kcnts[i]);
367static void u32_dump_details(
struct rtnl_tc *tc,
void *data,
370 struct rtnl_u32 *u = data;
371 struct tc_u32_sel *s = NULL;
372 struct tc_u32_mark *m;
377 if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
380 s = u->cu_selector->d_data;
381 nl_dump(p,
"nkeys %u", s->nkeys);
384 if (!(u->cu_mask & U32_ATTR_MARK)) {
387 m = u->cu_mark->d_data;
388 nl_dump(p,
" mark 0x%u 0x%u", m->val, m->mask);
391 if (u->cu_mask & U32_ATTR_HASH)
392 nl_dump(p,
" ht key 0x%x hash 0x%u",
393 TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
395 if (u->cu_mask & U32_ATTR_LINK)
396 nl_dump(p,
" link %u", u->cu_link);
398 if (u->cu_mask & U32_ATTR_INDEV)
399 nl_dump(p,
" indev %s", u->cu_indev);
401 if (u->cu_mask & U32_ATTR_SELECTOR)
402 print_selector(p, s, u);
407static void u32_dump_stats(
struct rtnl_tc *tc,
void *data,
410 struct rtnl_u32 *u = data;
415 if (u->cu_mask & U32_ATTR_PCNT) {
416 struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
419 nl_dump_line(p,
" hit %8llu count %8llu\n",
420 (
long long unsigned)pc->rhit,
421 (
long long unsigned)pc->rcnt);
425static int u32_msg_fill(
struct rtnl_tc *tc,
void *data,
struct nl_msg *msg)
427 struct rtnl_u32 *u = data;
432 if (u->cu_mask & U32_ATTR_DIVISOR)
435 if (u->cu_mask & U32_ATTR_HASH)
438 if (u->cu_mask & U32_ATTR_CLASSID)
441 if (u->cu_mask & U32_ATTR_LINK)
444 if (u->cu_mask & U32_ATTR_SELECTOR)
447 if (u->cu_mask & U32_ATTR_MARK)
450 if (u->cu_mask & U32_ATTR_ACTION) {
453 err = rtnl_act_fill(msg, TCA_U32_ACT, u->cu_act);
458 if (u->cu_mask & U32_ATTR_POLICE)
461 if (u->cu_mask & U32_ATTR_INDEV)
475void rtnl_u32_set_handle(
struct rtnl_cls *cls,
int htid,
int hash,
478 uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
483int rtnl_u32_set_classid(
struct rtnl_cls *cls, uint32_t classid)
490 u->cu_classid = classid;
491 u->cu_mask |= U32_ATTR_CLASSID;
496int rtnl_u32_get_classid(
struct rtnl_cls *cls, uint32_t *classid)
503 if (!(u->cu_mask & U32_ATTR_CLASSID))
506 *classid = u->cu_classid;
510int rtnl_u32_set_divisor(
struct rtnl_cls *cls, uint32_t divisor)
517 u->cu_divisor = divisor;
518 u->cu_mask |= U32_ATTR_DIVISOR;
522int rtnl_u32_set_link(
struct rtnl_cls *cls, uint32_t link)
530 u->cu_mask |= U32_ATTR_LINK;
534int rtnl_u32_set_hashtable(
struct rtnl_cls *cls, uint32_t ht)
542 u->cu_mask |= U32_ATTR_HASH;
546int rtnl_u32_set_hashmask(
struct rtnl_cls *cls, uint32_t hashmask, uint32_t offset)
549 struct tc_u32_sel *sel;
551 hashmask = htonl(hashmask);
556 sel = u32_selector_alloc(u);
560 sel->hmask = hashmask;
565int rtnl_u32_set_selector(
struct rtnl_cls *cls,
int offoff, uint32_t offmask,
char offshift, uint16_t off,
char flags)
568 struct tc_u32_sel *sel;
570 offmask = ntohs(offmask);
575 sel = u32_selector_alloc(u);
579 sel->offoff = offoff;
580 sel->offmask = offmask;
581 sel->offshift = offshift;
582 sel->flags |= TC_U32_VAROFFSET;
588int rtnl_u32_set_cls_terminal(
struct rtnl_cls *cls)
591 struct tc_u32_sel *sel;
596 sel = u32_selector_alloc(u);
600 sel->flags |= TC_U32_TERMINAL;
604int rtnl_u32_add_action(
struct rtnl_cls *cls,
struct rtnl_act *act)
615 if ((err = _rtnl_act_append_get(&u->cu_act, act)) < 0)
618 u->cu_mask |= U32_ATTR_ACTION;
622struct rtnl_act* rtnl_u32_get_action(
struct rtnl_cls *cls)
629 if (!(u->cu_mask & U32_ATTR_ACTION))
635int rtnl_u32_del_action(
struct rtnl_cls *cls,
struct rtnl_act *act)
646 if (!(u->cu_mask & U32_ATTR_ACTION))
649 ret = rtnl_act_remove(&u->cu_act, act);
654 u->cu_mask &= ~U32_ATTR_ACTION;
665int rtnl_u32_set_flags(
struct rtnl_cls *cls,
int flags)
667 struct tc_u32_sel *sel;
673 sel = u32_selector_alloc(u);
678 u->cu_mask |= U32_ATTR_SELECTOR;
698 int off,
int offmask)
700 struct tc_u32_sel *sel;
707 sel = u32_selector_alloc(u);
711 if (sel->nkeys == UCHAR_MAX)
714 err =
nl_data_append(u->cu_selector, NULL,
sizeof(
struct tc_u32_key));
719 sel = u32_selector(u);
721 sel->keys[sel->nkeys].mask = mask;
722 sel->keys[sel->nkeys].val = val & mask;
723 sel->keys[sel->nkeys].off = off;
724 sel->keys[sel->nkeys].offmask = offmask;
726 u->cu_mask |= U32_ATTR_SELECTOR;
731int rtnl_u32_add_mark(
struct rtnl_cls *cls, uint32_t val, uint32_t mask)
733 struct tc_u32_mark *mark;
739 mark = u32_mark_alloc(u);
746 u->cu_mask |= U32_ATTR_MARK;
751int rtnl_u32_del_mark(
struct rtnl_cls *cls)
761 if (!(u->cu_mask & U32_ATTR_MARK))
766 u->cu_mask &= ~U32_ATTR_MARK;
783 uint32_t *val, uint32_t *mask,
int *off,
int *offmask)
785 struct tc_u32_sel *sel;
791 if (!(u->cu_mask & U32_ATTR_SELECTOR))
794 sel = u32_selector(u);
795 if (index >= sel->nkeys)
798 *mask = sel->keys[index].mask;
799 *val = sel->keys[index].val;
800 *off = sel->keys[index].off;
801 *offmask = sel->keys[index].offmask;
806int rtnl_u32_add_key_uint8(
struct rtnl_cls *cls, uint8_t val, uint8_t mask,
807 int off,
int offmask)
809 int shift = 24 - 8 * (off & 3);
812 htonl((uint32_t)mask << shift),
826 int off,
int offmask)
828 int shift = ((off & 3) == 0 ? 16 : 0);
833 htonl((uint32_t)mask << shift),
847 int off,
int offmask)
853int rtnl_u32_add_key_in_addr(
struct rtnl_cls *cls,
const struct in_addr *addr,
854 uint8_t bitmask,
int off,
int offmask)
856 uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
860int rtnl_u32_add_key_in6_addr(
struct rtnl_cls *cls,
const struct in6_addr *addr,
861 uint8_t bitmask,
int off,
int offmask)
865 for (i = 1; i <= 4; i++) {
866 if (32 * i - bitmask <= 0) {
868 0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
871 else if (32 * i - bitmask < 32) {
872 uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
874 htonl(mask), off+4*(i-1), offmask)) < 0)
885static struct rtnl_tc_ops u32_ops = {
887 .to_type = RTNL_TC_TYPE_CLS,
888 .to_size =
sizeof(
struct rtnl_u32),
889 .to_msg_parser = u32_msg_parser,
890 .to_free_data = u32_free_data,
891 .to_clone = u32_clone,
892 .to_msg_fill = u32_msg_fill,
900static void _nl_init u32_init(
void)
905static void _nl_exit u32_exit(
void)
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
#define NLA_PUT_DATA(msg, attrtype, data)
Add abstract data attribute to netlink message.
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
Copy string attribute payload to a buffer.
int nla_len(const struct nlattr *nla)
Return length of the payload .
#define NLA_PUT_STRING(msg, attrtype, value)
Add string attribute to netlink message.
@ NLA_STRING
NUL terminated character string.
char * rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
Convert a traffic control handle to a character string (Reentrant).
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.
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.
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.
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.
struct nl_data * nl_data_clone(const struct nl_data *src)
Clone an abstract data object.
void nl_data_free(struct nl_data *data)
Free an abstract data object.
int nl_data_append(struct nl_data *data, const void *buf, size_t size)
Append data to an abstract data object.
struct nl_data * nl_data_alloc(const void *buf, size_t size)
Allocate a new abstract data object.
struct nl_data * nl_data_alloc_attr(const struct nlattr *nla)
Allocate abstract data object based on netlink attribute.
void nl_object_get(struct nl_object *obj)
Acquire a reference on a object.
void * rtnl_tc_data_peek(struct rtnl_tc *tc)
Returns the private data of the traffic control object.
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
void rtnl_tc_set_handle(struct rtnl_tc *tc, uint32_t id)
Set identifier of traffic control object.
void * rtnl_tc_data(struct rtnl_tc *)
Return pointer to private data of traffic control object.
int rtnl_tc_register(struct rtnl_tc_ops *)
Register a traffic control module.
void rtnl_tc_unregister(struct rtnl_tc_ops *)
Unregister a traffic control module.
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
@ NL_DUMP_STATS
Dump all attributes including statistics.
@ NL_DUMP_LINE
Dump object briefly on one line.
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
enum nl_dump_type dp_type
Specifies the type of dump that is requested.
Attribute validation policy.
uint16_t type
Type of attribute or NLA_UNSPEC.