19 #include <netlink-local.h>
20 #include <netlink-tc.h>
21 #include <netlink/netlink.h>
22 #include <netlink/utils.h>
23 #include <netlink/route/rtnl.h>
24 #include <netlink/route/link.h>
25 #include <netlink/route/tc.h>
29 static struct nla_policy tc_policy[TCA_MAX+1] = {
31 .maxlen = TCKINDSIZ },
32 [TCA_STATS] = { .minlen =
sizeof(
struct tc_stats) },
36 int tca_parse(
struct nlattr **tb,
int maxattr,
struct rtnl_tca *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));
52 static 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) },
58 int tca_msg_parser(
struct nlmsghdr *n,
struct rtnl_tca *g)
60 struct nlattr *tb[TCA_MAX + 1];
64 err =
nlmsg_parse(n,
sizeof(*tm), tb, TCA_MAX, tc_policy);
68 if (tb[TCA_KIND] == NULL)
69 return nl_error(EINVAL,
"Missing tca kind TLV");
74 g->tc_family = tm->tcm_family;
75 g->tc_ifindex = tm->tcm_ifindex;
76 g->tc_handle = tm->tcm_handle;
77 g->tc_parent = tm->tcm_parent;
78 g->tc_info = tm->tcm_info;
80 g->ce_mask = (TCA_ATTR_FAMILY | TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE |
81 TCA_ATTR_PARENT | TCA_ATTR_INFO | TCA_ATTR_KIND);
83 if (tb[TCA_OPTIONS]) {
86 return nl_errno(ENOMEM);
87 g->ce_mask |= TCA_ATTR_OPTS;
92 struct nlattr *tbs[TCA_STATS_MAX + 1];
99 if (tbs[TCA_STATS_BASIC]) {
100 struct gnet_stats_basic *bs;
102 bs =
nla_data(tbs[TCA_STATS_BASIC]);
107 if (tbs[TCA_STATS_RATE_EST]) {
108 struct gnet_stats_rate_est *re;
110 re =
nla_data(tbs[TCA_STATS_RATE_EST]);
115 if (tbs[TCA_STATS_QUEUE]) {
116 struct gnet_stats_queue *q;
126 g->ce_mask |= TCA_ATTR_STATS;
128 if (tbs[TCA_STATS_APP]) {
130 if (g->tc_xstats == NULL)
136 struct tc_stats *st =
nla_data(tb[TCA_STATS]);
147 g->ce_mask |= TCA_ATTR_STATS;
151 if (tb[TCA_XSTATS]) {
153 if (g->tc_xstats == NULL)
155 g->ce_mask |= TCA_ATTR_XSTATS;
163 void tca_free_data(
struct rtnl_tca *tca)
169 int tca_clone(
struct rtnl_tca *dst,
struct rtnl_tca *src)
177 if (src->tc_xstats) {
185 return nl_get_errno();
188 int tca_dump_brief(
struct rtnl_tca *g,
const char *type,
191 char handle[32], parent[32];
192 struct nl_cache *link_cache;
196 dp_dump(p,
"%s %s ", g->tc_kind, type);
200 dp_dump(p,
"dev %s ",
204 dp_dump(p,
"dev %u ", g->tc_ifindex);
206 dp_dump(p,
"handle %s parent %s",
213 int tca_dump_full(
struct rtnl_tca *g,
struct nl_dump_params *p,
int line)
215 dp_dump_line(p, line++,
" ");
219 int tca_dump_stats(
struct rtnl_tca *g,
struct nl_dump_params *p,
int line)
223 strcpy(fmt,
" %7.2f %s %10u %10u %10u %10u %10u\n");
225 dp_dump_line(p, line++,
226 " Stats: bytes packets drops overlimits" \
233 dp_dump_line(p, line++, fmt, res, unit,
242 strcpy(fmt,
" %7.2f %s/s%9u pps");
252 int tca_compare(
struct nl_object *_a,
struct nl_object *_b,
253 uint32_t attrs,
int flags)
255 struct rtnl_tca *a = (
struct rtnl_tca *) _a;
256 struct rtnl_tca *b = (
struct rtnl_tca *) _b;
259 #define TC_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, TCA_ATTR_##ATTR, a, b, EXPR)
261 diff |= TC_DIFF(HANDLE, a->tc_handle != b->tc_handle);
262 diff |= TC_DIFF(PARENT, a->tc_parent != b->tc_parent);
263 diff |= TC_DIFF(IFINDEX, a->tc_ifindex != b->tc_ifindex);
264 diff |= TC_DIFF(KIND, strcmp(a->tc_kind, b->tc_kind));
271 void tca_set_ifindex(
struct rtnl_tca *t,
int ifindex)
273 t->tc_ifindex = ifindex;
274 t->ce_mask |= TCA_ATTR_IFINDEX;
277 int tca_get_ifindex(
struct rtnl_tca *t)
279 if (t->ce_mask & TCA_ATTR_IFINDEX)
280 return t->tc_ifindex;
285 void tca_set_handle(
struct rtnl_tca *t, uint32_t handle)
287 t->tc_handle = handle;
288 t->ce_mask |= TCA_ATTR_HANDLE;
291 uint32_t tca_get_handle(
struct rtnl_tca *t)
293 if (t->ce_mask & TCA_ATTR_HANDLE)
299 void tca_set_parent(
struct rtnl_tca *t, uint32_t parent)
301 t->tc_parent = parent;
302 t->ce_mask |= TCA_ATTR_PARENT;
305 uint32_t tca_get_parent(
struct rtnl_tca *t)
307 if (t->ce_mask & TCA_ATTR_PARENT)
313 void tca_set_kind(
struct rtnl_tca *t,
const char *kind)
315 strncpy(t->tc_kind, kind,
sizeof(t->tc_kind) - 1);
316 t->ce_mask |= TCA_ATTR_KIND;
319 char *tca_get_kind(
struct rtnl_tca *t)
321 if (t->ce_mask & TCA_ATTR_KIND)
327 uint64_t tca_get_stat(
struct rtnl_tca *t,
int id)
329 if (id < 0 || id > RTNL_TC_STATS_MAX)
332 return t->tc_stats[id];
335 struct nl_msg *tca_build_msg(
struct rtnl_tca *tca,
int type,
int flags)
338 struct tcmsg tchdr = {
339 .tcm_family = AF_UNSPEC,
340 .tcm_ifindex = tca->tc_ifindex,
341 .tcm_handle = tca->tc_handle,
342 .tcm_parent = tca->tc_parent,
347 goto nla_put_failure;
349 if (
nlmsg_append(msg, &tchdr,
sizeof(tchdr), NLMSG_ALIGNTO) < 0)
350 goto nla_put_failure;
352 if (tca->ce_mask & TCA_ATTR_KIND)
387 tx_time_secs = (double) bufsize / (
double) rate;
389 return tx_time_secs * 1000000.;
410 bufsize = (double) txtime * (
double) rate;
412 return bufsize / 1000000.;
424 for (i = 0; i < 32; i++)
425 if ((1 << i) == cell_size)
428 return nl_errno(EINVAL);
457 int i, size, cell_log;
464 size = (i << cell_log) + overhead;
495 if (TC_H_ROOT == handle)
496 snprintf(buf, len,
"root");
497 else if (TC_H_UNSPEC == handle)
498 snprintf(buf, len,
"none");
499 else if (0 == TC_H_MAJ(handle))
500 snprintf(buf, len,
":%02x", TC_H_MIN(handle));
501 else if (0 == TC_H_MIN(handle))
502 snprintf(buf, len,
"%02x:", TC_H_MAJ(handle) >> 16);
504 snprintf(buf, len,
"%02x:%02x",
505 TC_H_MAJ(handle) >> 16, TC_H_MIN(handle));
533 if (!strcasecmp(name,
"root")) {
538 if (!strcasecmp(name,
"none")) {
543 h = strtoul(name, &colon, 16);
558 if (
'\0' == colon[1]) {
563 uint32_t l = strtoul(colon+1, &end, 16);
574 }
else if (
'\0' == *colon) {