18 #include <netlink-local.h>
19 #include <netlink-tc.h>
20 #include <netlink/netlink.h>
21 #include <netlink/utils.h>
22 #include <netlink/route/rtnl.h>
23 #include <netlink/route/link.h>
24 #include <netlink/route/tc.h>
25 #include <netlink/route/tc-api.h>
29 static struct nl_list_head tc_ops_list[__RTNL_TC_TYPE_MAX];
32 static struct nla_policy tc_policy[TCA_MAX+1] = {
34 .maxlen = TCKINDSIZ },
35 [TCA_STATS] = { .minlen =
sizeof(
struct tc_stats) },
39 int tca_parse(
struct nlattr **tb,
int maxattr,
struct rtnl_tc *g,
43 if (g->ce_mask & TCA_ATTR_OPTS)
45 (
struct nlattr *) g->tc_opts->d_data,
46 g->tc_opts->d_size, policy);
50 memset(tb, 0,
sizeof(
struct nlattr *) * (maxattr + 1));
55 static struct nla_policy tc_stats2_policy[TCA_STATS_MAX+1] = {
56 [TCA_STATS_BASIC] = { .
minlen =
sizeof(
struct gnet_stats_basic) },
57 [TCA_STATS_RATE_EST] = { .minlen =
sizeof(
struct gnet_stats_rate_est) },
58 [TCA_STATS_QUEUE] = { .minlen =
sizeof(
struct gnet_stats_queue) },
61 int rtnl_tc_msg_parse(
struct nlmsghdr *n,
struct rtnl_tc *tc)
63 struct nl_cache *link_cache;
65 struct nlattr *tb[TCA_MAX + 1];
70 tc->ce_msgtype = n->nlmsg_type;
72 err =
nlmsg_parse(n,
sizeof(*tm), tb, TCA_MAX, tc_policy);
76 if (tb[TCA_KIND] == NULL)
77 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)
144 struct tc_stats *st =
nla_data(tb[TCA_STATS]);
155 tc->ce_mask |= TCA_ATTR_STATS;
159 if (tb[TCA_XSTATS]) {
161 if (tc->tc_xstats == NULL)
163 tc->ce_mask |= TCA_ATTR_XSTATS;
167 ops = rtnl_tc_get_ops(tc);
179 if ((link_cache = __nl_cache_mngt_require(
"route/link"))) {
193 int rtnl_tc_msg_build(
struct rtnl_tc *tc,
int type,
int flags,
194 struct nl_msg **result)
198 struct tcmsg tchdr = {
199 .tcm_family = AF_UNSPEC,
200 .tcm_ifindex = tc->tc_ifindex,
201 .tcm_handle = tc->tc_handle,
202 .tcm_parent = tc->tc_parent,
204 int err = -NLE_MSGSIZE;
210 if (
nlmsg_append(msg, &tchdr,
sizeof(tchdr), NLMSG_ALIGNTO) < 0)
211 goto nla_put_failure;
213 if (tc->ce_mask & TCA_ATTR_KIND)
216 ops = rtnl_tc_get_ops(tc);
222 goto nla_put_failure;
225 goto nla_put_failure;
238 void tca_set_kind(
struct rtnl_tc *t,
const char *kind)
240 strncpy(t->tc_kind, kind,
sizeof(t->tc_kind) - 1);
241 t->ce_mask |= TCA_ATTR_KIND;
267 tc->ce_mask &= ~TCA_ATTR_LINK;
269 tc->tc_ifindex = ifindex;
270 tc->ce_mask |= TCA_ATTR_IFINDEX;
279 return tc->tc_ifindex;
303 tc->tc_ifindex = link->l_index;
304 tc->ce_mask |= TCA_ATTR_LINK | TCA_ATTR_IFINDEX;
349 tc->ce_mask |= TCA_ATTR_MTU;
363 if (tc->ce_mask & TCA_ATTR_MTU)
365 else if (tc->ce_mask & TCA_ATTR_LINK)
366 return tc->tc_link->l_mtu;
384 tc->ce_mask |= TCA_ATTR_MPU;
412 tc->tc_overhead = overhead;
413 tc->ce_mask |= TCA_ATTR_OVERHEAD;
424 return tc->tc_overhead;
440 tc->tc_linktype = type;
441 tc->ce_mask |= TCA_ATTR_LINKTYPE;
455 if (tc->ce_mask & TCA_ATTR_LINKTYPE)
456 return tc->tc_linktype;
457 else if (tc->ce_mask & TCA_ATTR_LINK)
458 return tc->tc_link->l_arptype;
471 tc->ce_mask |= TCA_ATTR_HANDLE;
480 return tc->tc_handle;
491 tc->tc_parent = parent;
492 tc->ce_mask |= TCA_ATTR_PARENT;
501 return tc->tc_parent;
513 if (tc->ce_mask & TCA_ATTR_KIND)
516 strncpy(tc->tc_kind, kind,
sizeof(tc->tc_kind) - 1);
517 tc->ce_mask |= TCA_ATTR_KIND;
533 if (tc->ce_mask & TCA_ATTR_KIND)
548 if (id < 0 || id > RTNL_TC_STATS_MAX)
551 return tc->tc_stats[id];
579 tx_time_secs = (double) bufsize / (
double) rate;
581 return tx_time_secs * 1000000.;
602 bufsize = (double) txtime * (
double) rate;
604 return bufsize / 1000000.;
616 for (i = 0; i < 32; i++)
617 if ((1 << i) == cell_size)
646 static unsigned int align_to_atm(
unsigned int size)
649 cells = size / ATM_CELL_PAYLOAD;
650 if ((size % ATM_CELL_PAYLOAD) > 0)
653 linksize = cells * ATM_CELL_SIZE;
657 static unsigned int adjust_size(
unsigned int size,
unsigned int mpu,
665 return align_to_atm(size);
691 uint8_t cell_log = spec->rs_cell_log;
692 unsigned int size, i;
700 if (cell_log == UINT8_MAX) {
707 while ((mtu >> cell_log) >= RTNL_TC_RTABLE_SIZE)
711 for (i = 0; i < RTNL_TC_RTABLE_SIZE; i++) {
712 size = adjust_size((i + 1) << cell_log, spec->rs_mpu, linktype);
716 spec->rs_cell_align = -1;
717 spec->rs_cell_log = cell_log;
728 void rtnl_tc_free_data(
struct nl_object *obj)
730 struct rtnl_tc *tc =
TC_CAST(obj);
737 if (tc->tc_subdata) {
738 ops = rtnl_tc_get_ops(tc);
748 struct rtnl_tc *dst =
TC_CAST(dstobj);
749 struct rtnl_tc *src =
TC_CAST(srcobj);
754 dst->tc_link = src->tc_link;
763 if (src->tc_xstats) {
769 if (src->tc_subdata) {
775 ops = rtnl_tc_get_ops(src);
790 static int tc_dump(
struct rtnl_tc *tc,
enum nl_dump_type type,
797 type_ops = tc_type_ops[tc->tc_type];
798 if (type_ops && type_ops->
tt_dump[type])
799 type_ops->
tt_dump[type](tc, p);
801 ops = rtnl_tc_get_ops(tc);
802 if (ops && ops->
to_dump[type]) {
803 ops->
to_dump[type](tc, data, p);
813 struct rtnl_tc *tc =
TC_CAST(obj);
814 struct nl_cache *link_cache;
819 type_ops = tc_type_ops[tc->tc_type];
820 if (type_ops && type_ops->tt_dump_prefix)
821 nl_dump(p,
"%s ", type_ops->tt_dump_prefix);
823 nl_dump(p,
"%s ", tc->tc_kind);
830 nl_dump(p,
"dev %u ", tc->tc_ifindex);
844 struct rtnl_tc *tc =
TC_CAST(obj);
846 rtnl_tc_dump_line(OBJ_CAST(tc), p);
848 nl_dump_line(p,
" ");
850 if (tc->ce_mask & TCA_ATTR_MTU)
851 nl_dump(p,
" mtu %u", tc->tc_mtu);
853 if (tc->ce_mask & TCA_ATTR_MPU)
854 nl_dump(p,
" mpu %u", tc->tc_mpu);
856 if (tc->ce_mask & TCA_ATTR_OVERHEAD)
857 nl_dump(p,
" overhead %u", tc->tc_overhead);
866 struct rtnl_tc *tc =
TC_CAST(obj);
870 rtnl_tc_dump_details(OBJ_CAST(tc), p);
872 strcpy(fmt,
" %7.2f %s %10u %10u %10u %10u %10u\n");
875 " Stats: bytes packets drops overlimits" \
882 nl_dump_line(p, fmt, res, unit,
891 strcpy(fmt,
" %7.2f %s/s%9u pps");
903 uint32_t attrs,
int flags)
905 struct rtnl_tc *a =
TC_CAST(aobj);
906 struct rtnl_tc *b =
TC_CAST(bobj);
909 #define TC_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, TCA_ATTR_##ATTR, a, b, EXPR)
911 diff |= TC_DIFF(HANDLE, a->tc_handle != b->tc_handle);
912 diff |= TC_DIFF(PARENT, a->tc_parent != b->tc_parent);
913 diff |= TC_DIFF(IFINDEX, a->tc_ifindex != b->tc_ifindex);
914 diff |= TC_DIFF(KIND, strcmp(a->tc_kind, b->tc_kind));
927 struct rtnl_tc_ops *rtnl_tc_lookup_ops(
enum rtnl_tc_type type,
const char *kind)
931 nl_list_for_each_entry(ops, &tc_ops_list[type],
to_list)
932 if (!strcmp(kind, ops->
to_kind))
938 struct
rtnl_tc_ops *rtnl_tc_get_ops(struct rtnl_tc *tc)
941 tc->tc_ops = rtnl_tc_lookup_ops(tc->tc_type, tc->tc_kind);
963 for (i = 0; i < __RTNL_TC_TYPE_MAX; i++)
964 nl_init_list_head(&tc_ops_list[i]);
1000 if (!tc->tc_subdata) {
1007 if (!rtnl_tc_get_ops(tc))
1011 if (!(size = tc->tc_ops->to_size))
1037 if (tc->tc_ops != ops) {
1040 snprintf(buf,
sizeof(buf),
1041 "tc object %p used in %s context but is of type %s",
1042 tc, ops->
to_kind, tc->tc_ops->to_kind);
1053 if (ops->tt_type > RTNL_TC_TYPE_MAX)
1056 tc_type_ops[ops->tt_type] = ops;
1061 if (ops->tt_type > RTNL_TC_TYPE_MAX)
1064 tc_type_ops[ops->tt_type] = NULL;