12#include <netlink-private/netlink.h>
13#include <netlink-private/tc.h>
14#include <netlink/netlink.h>
15#include <netlink/utils.h>
16#include <netlink/route/rtnl.h>
17#include <netlink/route/link.h>
18#include <netlink/route/tc.h>
19#include <netlink-private/route/tc-api.h>
21#include "netlink-private/utils.h"
25static struct nl_list_head tc_ops_list[__RTNL_TC_TYPE_MAX];
26static struct rtnl_tc_type_ops *tc_type_ops[__RTNL_TC_TYPE_MAX];
28static struct nla_policy tc_policy[TCA_MAX+1] = {
30 .maxlen = TCKINDSIZ },
31 [TCA_CHAIN] = { .type =
NLA_U32 },
32 [TCA_STATS] = { .minlen =
sizeof(
struct tc_stats) },
36int tca_parse(
struct nlattr **tb,
int maxattr,
struct rtnl_tc *g,
40 if (g->ce_mask & TCA_ATTR_OPTS)
42 (
struct nlattr *) g->tc_opts->d_data,
43 g->tc_opts->d_size, policy);
47 memset(tb, 0,
sizeof(
struct nlattr *) * (maxattr + 1));
52static struct nla_policy tc_stats2_policy[TCA_STATS_MAX+1] = {
53 [TCA_STATS_BASIC] = { .
minlen =
sizeof(
struct gnet_stats_basic) },
54 [TCA_STATS_RATE_EST] = { .minlen =
sizeof(
struct gnet_stats_rate_est) },
55 [TCA_STATS_QUEUE] = { .minlen =
sizeof(
struct gnet_stats_queue) },
58int rtnl_tc_msg_parse(
struct nlmsghdr *n,
struct rtnl_tc *tc)
60 struct nl_cache *link_cache;
61 struct rtnl_tc_ops *ops;
62 struct nlattr *tb[TCA_MAX + 1];
67 tc->ce_msgtype = n->nlmsg_type;
69 err =
nlmsg_parse(n,
sizeof(*tm), tb, TCA_MAX, tc_policy);
73 if (tb[TCA_KIND] == NULL)
74 return -NLE_MISSING_ATTR;
83 tc->tc_family = tm->tcm_family;
84 tc->tc_ifindex = tm->tcm_ifindex;
85 tc->tc_handle = tm->tcm_handle;
86 tc->tc_parent = tm->tcm_parent;
87 tc->tc_info = tm->tcm_info;
89 tc->ce_mask |= (TCA_ATTR_FAMILY | TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE|
90 TCA_ATTR_PARENT | TCA_ATTR_INFO);
92 if (tb[TCA_OPTIONS]) {
96 tc->ce_mask |= TCA_ATTR_OPTS;
100 struct nlattr *tbs[TCA_STATS_MAX + 1];
107 if (tbs[TCA_STATS_BASIC]) {
108 struct gnet_stats_basic *bs;
110 bs =
nla_data(tbs[TCA_STATS_BASIC]);
115 if (tbs[TCA_STATS_RATE_EST]) {
116 struct gnet_stats_rate_est *re;
118 re =
nla_data(tbs[TCA_STATS_RATE_EST]);
123 if (tbs[TCA_STATS_QUEUE]) {
124 struct gnet_stats_queue *q;
134 tc->ce_mask |= TCA_ATTR_STATS;
136 if (tbs[TCA_STATS_APP]) {
138 if (tc->tc_xstats == NULL)
140 tc->ce_mask |= TCA_ATTR_XSTATS;
145 struct tc_stats *st =
nla_data(tb[TCA_STATS]);
156 tc->ce_mask |= TCA_ATTR_STATS;
160 if (tb[TCA_XSTATS]) {
162 if (tc->tc_xstats == NULL)
164 tc->ce_mask |= TCA_ATTR_XSTATS;
168 ops = rtnl_tc_get_ops(tc);
169 if (ops && ops->to_msg_parser) {
175 err = ops->to_msg_parser(tc, data);
180 if ((link_cache = __nl_cache_mngt_require(
"route/link"))) {
194int rtnl_tc_msg_build(
struct rtnl_tc *tc,
int type,
int flags,
195 struct nl_msg **result)
198 struct rtnl_tc_ops *ops;
199 struct tcmsg tchdr = {
200 .tcm_family = AF_UNSPEC,
201 .tcm_ifindex = tc->tc_ifindex,
202 .tcm_handle = tc->tc_handle,
203 .tcm_parent = tc->tc_parent,
211 if (
nlmsg_append(msg, &tchdr,
sizeof(tchdr), NLMSG_ALIGNTO) < 0) {
216 if (tc->ce_mask & TCA_ATTR_KIND)
219 if (tc->ce_mask & TCA_ATTR_CHAIN)
222 ops = rtnl_tc_get_ops(tc);
223 if (ops && (ops->to_msg_fill || ops->to_msg_fill_raw)) {
227 if (ops->to_msg_fill) {
233 if ((err = ops->to_msg_fill(tc, data, msg)) < 0)
236 if (strcmp(
"cgroup", tc->tc_kind))
240 }
else if ((err = ops->to_msg_fill_raw(tc, data, msg)) < 0)
277 tc->ce_mask &= ~TCA_ATTR_LINK;
279 tc->tc_ifindex = ifindex;
280 tc->ce_mask |= TCA_ATTR_IFINDEX;
289 return tc->tc_ifindex;
315 tc->tc_ifindex = link->l_index;
316 tc->ce_mask |= TCA_ATTR_LINK | TCA_ATTR_IFINDEX;
361 tc->ce_mask |= TCA_ATTR_MTU;
375 if (tc->ce_mask & TCA_ATTR_MTU)
377 else if (tc->ce_mask & TCA_ATTR_LINK)
378 return tc->tc_link->l_mtu;
396 tc->ce_mask |= TCA_ATTR_MPU;
424 tc->tc_overhead = overhead;
425 tc->ce_mask |= TCA_ATTR_OVERHEAD;
436 return tc->tc_overhead;
452 tc->tc_linktype = type;
453 tc->ce_mask |= TCA_ATTR_LINKTYPE;
467 if (tc->ce_mask & TCA_ATTR_LINKTYPE)
468 return tc->tc_linktype;
469 else if (tc->ce_mask & TCA_ATTR_LINK)
470 return tc->tc_link->l_arptype;
483 tc->ce_mask |= TCA_ATTR_HANDLE;
492 return tc->tc_handle;
503 tc->tc_parent = parent;
504 tc->ce_mask |= TCA_ATTR_PARENT;
513 return tc->tc_parent;
525 if (tc->ce_mask & TCA_ATTR_KIND)
529 || strlen (kind) >=
sizeof (tc->tc_kind))
532 _nl_strncpy_assert(tc->tc_kind, kind,
sizeof(tc->tc_kind));
534 tc->ce_mask |= TCA_ATTR_KIND;
550 if (tc->ce_mask & TCA_ATTR_KIND)
565 if ((
unsigned int)
id > RTNL_TC_STATS_MAX)
568 return tc->tc_stats[id];
579 tc->tc_chain = chain;
580 tc->ce_mask |= TCA_ATTR_CHAIN;
593 if (!(tc->ce_mask & TCA_ATTR_CHAIN))
594 return -NLE_MISSING_ATTR;
595 *out_value = tc->tc_chain;
606static const struct trans_tbl tc_stats[] = {
618char *rtnl_tc_stat2str(
enum rtnl_tc_stat st,
char *buf,
size_t len)
620 return __type2str(st, buf, len, tc_stats, ARRAY_SIZE(tc_stats));
623int rtnl_tc_str2stat(
const char *name)
625 return __str2type(name, tc_stats, ARRAY_SIZE(tc_stats));
644 return ((
double) bufsize / (
double) rate) * 1000000.0;
663 return ((
double) txtime * (
double) rate) / 1000000.0;
675 for (i = 0; i < 32; i++)
676 if ((1 << i) == cell_size)
705static unsigned int align_to_atm(
unsigned int size)
708 cells = size / ATM_CELL_PAYLOAD;
709 if ((size % ATM_CELL_PAYLOAD) > 0)
712 linksize = cells * ATM_CELL_SIZE;
716static unsigned int adjust_size(
unsigned int size,
unsigned int mpu,
724 return align_to_atm(size);
750 uint8_t cell_log = spec->rs_cell_log;
751 unsigned int size, i;
759 if (cell_log == UINT8_MAX) {
766 while ((mtu >> cell_log) >= RTNL_TC_RTABLE_SIZE)
770 for (i = 0; i < RTNL_TC_RTABLE_SIZE; i++) {
771 size = adjust_size((i + 1) << cell_log, spec->rs_mpu, linktype);
772 dst[i] =
nl_us2ticks(rtnl_tc_calc_txtime64(size, spec->rs_rate64));
775 spec->rs_cell_align = -1;
776 spec->rs_cell_log = cell_log;
787void rtnl_tc_free_data(
struct nl_object *obj)
789 struct rtnl_tc *tc =
TC_CAST(obj);
790 struct rtnl_tc_ops *ops;
796 if (tc->tc_subdata) {
797 ops = rtnl_tc_get_ops(tc);
798 if (ops && ops->to_free_data)
799 ops->to_free_data(tc,
nl_data_get(tc->tc_subdata));
805int rtnl_tc_clone(
struct nl_object *dstobj,
struct nl_object *srcobj)
807 struct rtnl_tc *dst =
TC_CAST(dstobj);
808 struct rtnl_tc *src =
TC_CAST(srcobj);
809 struct rtnl_tc_ops *ops;
812 dst->tc_xstats = NULL;
813 dst->tc_subdata = NULL;
819 dst->tc_link = src->tc_link;
822 dst->ce_mask &= ~(TCA_ATTR_OPTS |
829 dst->ce_mask |= TCA_ATTR_OPTS;
832 if (src->tc_xstats) {
836 dst->ce_mask |= TCA_ATTR_XSTATS;
839 if (src->tc_subdata) {
852 ops = rtnl_tc_get_ops(src);
853 if (ops && ops->to_clone) {
861static int tc_dump(
struct rtnl_tc *tc,
enum nl_dump_type type,
864 struct rtnl_tc_type_ops *type_ops;
865 struct rtnl_tc_ops *ops;
868 type_ops = tc_type_ops[tc->tc_type];
869 if (type_ops && type_ops->tt_dump[type])
870 type_ops->tt_dump[type](tc, p);
872 ops = rtnl_tc_get_ops(tc);
873 if (ops && ops->to_dump[type]) {
874 ops->to_dump[type](tc, data, p);
881void rtnl_tc_dump_line(
struct nl_object *obj,
struct nl_dump_params *p)
883 struct rtnl_tc_type_ops *type_ops;
884 struct rtnl_tc *tc =
TC_CAST(obj);
885 struct nl_cache *link_cache;
890 type_ops = tc_type_ops[tc->tc_type];
891 if (type_ops && type_ops->tt_dump_prefix)
892 nl_dump(p,
"%s ", type_ops->tt_dump_prefix);
894 nl_dump(p,
"%s ", tc->tc_kind);
901 nl_dump(p,
"dev %u ", tc->tc_ifindex);
913 nl_cache_put(link_cache);
916void rtnl_tc_dump_details(
struct nl_object *obj,
struct nl_dump_params *p)
918 struct rtnl_tc *tc =
TC_CAST(obj);
920 rtnl_tc_dump_line(OBJ_CAST(tc), p);
922 nl_dump_line(p,
" ");
924 if (tc->ce_mask & TCA_ATTR_MTU)
925 nl_dump(p,
" mtu %u", tc->tc_mtu);
927 if (tc->ce_mask & TCA_ATTR_MPU)
928 nl_dump(p,
" mpu %u", tc->tc_mpu);
930 if (tc->ce_mask & TCA_ATTR_OVERHEAD)
931 nl_dump(p,
" overhead %u", tc->tc_overhead);
938void rtnl_tc_dump_stats(
struct nl_object *obj,
struct nl_dump_params *p)
940 struct rtnl_tc *tc =
TC_CAST(obj);
944 rtnl_tc_dump_details(OBJ_CAST(tc), p);
947 " stats: %-14s %-10s %-10s %-10s %-10s %-10s\n",
948 "bytes",
"packets",
"drops",
"overlimits",
"qlen",
"backlog");
954 " %10.2f %3s %10llu %-10llu %-10llu %-10llu %-10llu\n",
963 nl_dump_line(p,
" %10.2f %3s/s %10llu/s\n", res, unit,
967uint64_t rtnl_tc_compare(
struct nl_object *aobj,
struct nl_object *bobj,
968 uint64_t attrs,
int flags)
970 struct rtnl_tc *a =
TC_CAST(aobj);
971 struct rtnl_tc *b =
TC_CAST(bobj);
974#define TC_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, TCA_ATTR_##ATTR, a, b, EXPR)
976 diff |= TC_DIFF(HANDLE, a->tc_handle != b->tc_handle);
977 diff |= TC_DIFF(PARENT, a->tc_parent != b->tc_parent);
978 diff |= TC_DIFF(IFINDEX, a->tc_ifindex != b->tc_ifindex);
979 diff |= TC_DIFF(KIND, strcmp(a->tc_kind, b->tc_kind));
992struct rtnl_tc_ops *rtnl_tc_lookup_ops(
enum rtnl_tc_type type,
const char *kind)
994 struct rtnl_tc_ops *ops;
996 nl_list_for_each_entry(ops, &tc_ops_list[type], to_list)
997 if (!strcmp(kind, ops->to_kind))
1003struct rtnl_tc_ops *rtnl_tc_get_ops(
struct rtnl_tc *tc)
1006 tc->tc_ops = rtnl_tc_lookup_ops(tc->tc_type, tc->tc_kind);
1017 static int init = 0;
1028 for (i = 0; i < __RTNL_TC_TYPE_MAX; i++)
1029 nl_init_list_head(&tc_ops_list[i]);
1034 if (!ops->to_kind || ops->to_type > RTNL_TC_TYPE_MAX)
1037 if (rtnl_tc_lookup_ops(ops->to_type, ops->to_kind))
1040 nl_list_add_tail(&ops->to_list, &tc_ops_list[ops->to_type]);
1051 nl_list_del(&ops->to_list);
1064 return tc->tc_subdata ?
nl_data_get(tc->tc_subdata) : NULL;
1078 if (!tc->tc_subdata) {
1082 if (!rtnl_tc_get_ops(tc))
1086 if (!(size = tc->tc_ops->to_size))
1115 if (tc->tc_ops != ops) {
1118 snprintf(buf,
sizeof(buf),
1119 "tc object %p used in %s context but is of type %s",
1120 tc, ops->to_kind, tc->tc_ops->to_kind);
1124 *err = -NLE_OPNOTSUPP;
1137struct nl_af_group tc_groups[] = {
1138 { AF_UNSPEC, RTNLGRP_TC },
1139 { END_OF_GROUP_LIST },
1143void rtnl_tc_type_register(
struct rtnl_tc_type_ops *ops)
1145 if (ops->tt_type > RTNL_TC_TYPE_MAX)
1148 tc_type_ops[ops->tt_type] = ops;
1151void rtnl_tc_type_unregister(
struct rtnl_tc_type_ops *ops)
1153 if (ops->tt_type > RTNL_TC_TYPE_MAX)
1156 tc_type_ops[ops->tt_type] = NULL;
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, const struct nla_policy *policy)
Create attribute index based on a stream of attributes.
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
Copy string attribute payload to a buffer.
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy)
Create attribute index based on nested attribute.
#define NLA_PUT_STRING(msg, attrtype, value)
Add string attribute to netlink message.
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
int nla_nest_end_keep_empty(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes without stripping off empty attributes.
@ NLA_STRING
NUL terminated character string.
@ NLA_NESTED
Nested attributes.
struct nl_cache * nl_cache_mngt_require_safe(const char *name)
Return cache previously provided via nl_cache_mngt_provide()
char * rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
Convert a traffic control handle to a character string (Reentrant).
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.
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_data_get(const struct nl_data *data)
Get data buffer of abstract data object.
struct rtnl_link * rtnl_link_get(struct nl_cache *cache, int ifindex)
Lookup link in cache by interface index.
char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst, size_t len)
Translate interface index to corresponding link name.
void rtnl_link_put(struct rtnl_link *link)
Return a link object reference.
struct nl_msg * nlmsg_alloc_simple(int nlmsgtype, int flags)
Allocate a new netlink message.
void * nlmsg_data(const struct nlmsghdr *nlh)
Return pointer to message payload.
void nlmsg_free(struct nl_msg *msg)
Release a reference from an netlink message.
int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy)
parse attributes of a netlink message
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
void nl_object_get(struct nl_object *obj)
Acquire a reference on a object.
void rtnl_tc_set_mpu(struct rtnl_tc *tc, uint32_t mpu)
Set the Minimum Packet Unit (MPU) of a traffic control object.
uint32_t rtnl_tc_get_parent(struct rtnl_tc *tc)
Return parent identifier of a traffic control object.
void rtnl_tc_set_linktype(struct rtnl_tc *tc, uint32_t type)
Set the linktype of a traffic control object.
void * rtnl_tc_data_check(struct rtnl_tc *tc, struct rtnl_tc_ops *ops, int *err)
Check traffic control object type and return private data section.
int rtnl_tc_set_kind(struct rtnl_tc *tc, const char *kind)
Define the type of traffic control object.
void * rtnl_tc_data_peek(struct rtnl_tc *tc)
Returns the private data of the traffic control object.
int rtnl_tc_calc_cell_log(int cell_size)
Calculate the binary logarithm for a specific cell size.
int rtnl_tc_get_chain(struct rtnl_tc *tc, uint32_t *out_value)
Return chain index of traffic control object.
char * rtnl_tc_get_kind(struct rtnl_tc *tc)
Return kind of traffic control object.
void rtnl_tc_set_ifindex(struct rtnl_tc *tc, int ifindex)
Set interface index of traffic control object.
int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *spec, uint32_t *dst)
Compute a transmission time lookup table.
void rtnl_tc_set_overhead(struct rtnl_tc *tc, uint32_t overhead)
Set per packet overhead of a traffic control object.
int rtnl_tc_calc_bufsize(int txtime, int rate)
Calculate buffer size able to transmit in a specific time and rate.
uint32_t rtnl_tc_get_mtu(struct rtnl_tc *tc)
Return the MTU of traffic control object.
int rtnl_tc_get_ifindex(struct rtnl_tc *tc)
Return interface index of traffic control object.
void rtnl_tc_set_link(struct rtnl_tc *tc, struct rtnl_link *link)
Set link of traffic control object.
uint32_t rtnl_tc_get_handle(struct rtnl_tc *tc)
Return identifier of a traffic control object.
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
uint32_t rtnl_tc_get_overhead(struct rtnl_tc *tc)
Return per packet overhead of a traffic control object.
void rtnl_tc_set_handle(struct rtnl_tc *tc, uint32_t id)
Set identifier of traffic control object.
void rtnl_tc_set_parent(struct rtnl_tc *tc, uint32_t parent)
Set the parent identifier of a traffic control object.
void * rtnl_tc_data(struct rtnl_tc *tc)
Return pointer to private data of traffic control object.
int rtnl_tc_register(struct rtnl_tc_ops *ops)
Register a traffic control module.
void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
Unregister a traffic control module.
void rtnl_tc_set_mtu(struct rtnl_tc *tc, uint32_t mtu)
Set the Maximum Transmission Unit (MTU) of traffic control object.
void rtnl_tc_set_chain(struct rtnl_tc *tc, uint32_t chain)
Set the chain index of a traffic control object.
uint64_t rtnl_tc_get_stat(struct rtnl_tc *tc, enum rtnl_tc_stat id)
Return value of a statistical counter of a traffic control object.
rtnl_tc_stat
Traffic control statistical identifier.
struct rtnl_link * rtnl_tc_get_link(struct rtnl_tc *tc)
Get link of traffic control object.
uint32_t rtnl_tc_get_linktype(struct rtnl_tc *tc)
Return the linktype of a traffic control object.
uint32_t rtnl_tc_get_mpu(struct rtnl_tc *tc)
Return the Minimum Packet Unit (MPU) of a traffic control object.
int rtnl_tc_calc_txtime(int bufsize, int rate)
Calculate time required to transmit buffer at a specific rate.
@ RTNL_TC_PACKETS
Number of packets seen.
@ RTNL_TC_BYTES
Total bytes seen.
@ RTNL_TC_QLEN
Current queue length.
@ RTNL_TC_OVERLIMITS
Total number of overlimits.
@ RTNL_TC_DROPS
Total number of packets dropped.
@ RTNL_TC_RATE_PPS
Current packet/s (rate estimator)
@ RTNL_TC_REQUEUES
Total number of requeues.
@ RTNL_TC_BACKLOG
Current backlog length.
@ RTNL_TC_RATE_BPS
Current bits/s (rate estimator)
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
double nl_cancel_down_bytes(unsigned long long l, char **unit)
Cancel down a byte counter.
void nl_new_line(struct nl_dump_params *params)
Handle a new line while dumping.
nl_dump_type
Enumeration of dumping variations (dp_type)
uint32_t nl_us2ticks(uint32_t us)
Convert micro seconds to ticks.
@ NL_DUMP_LINE
Dump object briefly on one line.
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Attribute validation policy.
uint16_t minlen
Minimal length of payload required.
uint16_t type
Type of attribute or NLA_UNSPEC.