144d362409d5469aed47d19e7908d19bd194493aThomas Graf/*
244d362409d5469aed47d19e7908d19bd194493aThomas Graf * lib/route/tc.c		Traffic Control
344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
444d362409d5469aed47d19e7908d19bd194493aThomas Graf *	This library is free software; you can redistribute it and/or
544d362409d5469aed47d19e7908d19bd194493aThomas Graf *	modify it under the terms of the GNU Lesser General Public
644d362409d5469aed47d19e7908d19bd194493aThomas Graf *	License as published by the Free Software Foundation version 2.1
744d362409d5469aed47d19e7908d19bd194493aThomas Graf *	of the License.
844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
98a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
1044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
1144d362409d5469aed47d19e7908d19bd194493aThomas Graf
1244d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
1344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @ingroup rtnl
1444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @defgroup tc Traffic Control
1544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @brief
1644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
1744d362409d5469aed47d19e7908d19bd194493aThomas Graf */
1844d362409d5469aed47d19e7908d19bd194493aThomas Graf
1944d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-local.h>
2044d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-tc.h>
2144d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/netlink.h>
2244d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/utils.h>
2344d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/rtnl.h>
2444d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/link.h>
2544d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/tc.h>
2644d362409d5469aed47d19e7908d19bd194493aThomas Graf
2744d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @cond SKIP */
2844d362409d5469aed47d19e7908d19bd194493aThomas Graf
2944d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nla_policy tc_policy[TCA_MAX+1] = {
3044d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_KIND]	= { .type = NLA_STRING,
3144d362409d5469aed47d19e7908d19bd194493aThomas Graf			    .maxlen = TCKINDSIZ },
3244d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_STATS]	= { .minlen = sizeof(struct tc_stats) },
3344d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_STATS2]	= { .type = NLA_NESTED },
3444d362409d5469aed47d19e7908d19bd194493aThomas Graf};
3544d362409d5469aed47d19e7908d19bd194493aThomas Graf
3644d362409d5469aed47d19e7908d19bd194493aThomas Grafint tca_parse(struct nlattr **tb, int maxattr, struct rtnl_tca *g,
3744d362409d5469aed47d19e7908d19bd194493aThomas Graf	      struct nla_policy *policy)
3844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
3944d362409d5469aed47d19e7908d19bd194493aThomas Graf
4044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (g->ce_mask & TCA_ATTR_OPTS)
4144d362409d5469aed47d19e7908d19bd194493aThomas Graf		return nla_parse(tb, maxattr,
4244d362409d5469aed47d19e7908d19bd194493aThomas Graf				 (struct nlattr *) g->tc_opts->d_data,
4344d362409d5469aed47d19e7908d19bd194493aThomas Graf				 g->tc_opts->d_size, policy);
4444d362409d5469aed47d19e7908d19bd194493aThomas Graf	else {
4544d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* Ugly but tb[] must be in a defined state even if no
4644d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * attributes can be found. */
4744d362409d5469aed47d19e7908d19bd194493aThomas Graf		memset(tb, 0, sizeof(struct nlattr *) * (maxattr + 1));
4844d362409d5469aed47d19e7908d19bd194493aThomas Graf		return 0;
4944d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
5044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
5144d362409d5469aed47d19e7908d19bd194493aThomas Graf
5244d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct nla_policy tc_stats2_policy[TCA_STATS_MAX+1] = {
5344d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_STATS_BASIC]    = { .minlen = sizeof(struct gnet_stats_basic) },
5444d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_STATS_RATE_EST] = { .minlen = sizeof(struct gnet_stats_rate_est) },
5544d362409d5469aed47d19e7908d19bd194493aThomas Graf	[TCA_STATS_QUEUE]    = { .minlen = sizeof(struct gnet_stats_queue) },
5644d362409d5469aed47d19e7908d19bd194493aThomas Graf};
5744d362409d5469aed47d19e7908d19bd194493aThomas Graf
5844d362409d5469aed47d19e7908d19bd194493aThomas Grafint tca_msg_parser(struct nlmsghdr *n, struct rtnl_tca *g)
5944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
6044d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nlattr *tb[TCA_MAX + 1];
6144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct tcmsg *tm;
6244d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
6344d362409d5469aed47d19e7908d19bd194493aThomas Graf
6444d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = nlmsg_parse(n, sizeof(*tm), tb, TCA_MAX, tc_policy);
6544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (err < 0)
6644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return err;
6744d362409d5469aed47d19e7908d19bd194493aThomas Graf
6844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_KIND] == NULL)
698a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_MISSING_ATTR;
7044d362409d5469aed47d19e7908d19bd194493aThomas Graf
7144d362409d5469aed47d19e7908d19bd194493aThomas Graf	nla_strlcpy(g->tc_kind, tb[TCA_KIND], TCKINDSIZ);
7244d362409d5469aed47d19e7908d19bd194493aThomas Graf
7344d362409d5469aed47d19e7908d19bd194493aThomas Graf	tm = nlmsg_data(n);
7444d362409d5469aed47d19e7908d19bd194493aThomas Graf	g->tc_family  = tm->tcm_family;
7544d362409d5469aed47d19e7908d19bd194493aThomas Graf	g->tc_ifindex = tm->tcm_ifindex;
7644d362409d5469aed47d19e7908d19bd194493aThomas Graf	g->tc_handle  = tm->tcm_handle;
7744d362409d5469aed47d19e7908d19bd194493aThomas Graf	g->tc_parent  = tm->tcm_parent;
7844d362409d5469aed47d19e7908d19bd194493aThomas Graf	g->tc_info    = tm->tcm_info;
7944d362409d5469aed47d19e7908d19bd194493aThomas Graf
8044d362409d5469aed47d19e7908d19bd194493aThomas Graf	g->ce_mask = (TCA_ATTR_FAMILY | TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE |
8144d362409d5469aed47d19e7908d19bd194493aThomas Graf		      TCA_ATTR_PARENT | TCA_ATTR_INFO | TCA_ATTR_KIND);
8244d362409d5469aed47d19e7908d19bd194493aThomas Graf
8344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_OPTIONS]) {
84eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		g->tc_opts = nl_data_alloc_attr(tb[TCA_OPTIONS]);
8544d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!g->tc_opts)
868a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_NOMEM;
8744d362409d5469aed47d19e7908d19bd194493aThomas Graf		g->ce_mask |= TCA_ATTR_OPTS;
8844d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
8944d362409d5469aed47d19e7908d19bd194493aThomas Graf
9044d362409d5469aed47d19e7908d19bd194493aThomas Graf
9144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tb[TCA_STATS2]) {
9244d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct nlattr *tbs[TCA_STATS_MAX + 1];
9344d362409d5469aed47d19e7908d19bd194493aThomas Graf
9444d362409d5469aed47d19e7908d19bd194493aThomas Graf		err = nla_parse_nested(tbs, TCA_STATS_MAX, tb[TCA_STATS2],
9544d362409d5469aed47d19e7908d19bd194493aThomas Graf				       tc_stats2_policy);
9644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (err < 0)
9744d362409d5469aed47d19e7908d19bd194493aThomas Graf			return err;
9844d362409d5469aed47d19e7908d19bd194493aThomas Graf
9944d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (tbs[TCA_STATS_BASIC]) {
10044d362409d5469aed47d19e7908d19bd194493aThomas Graf			struct gnet_stats_basic *bs;
10144d362409d5469aed47d19e7908d19bd194493aThomas Graf
10244d362409d5469aed47d19e7908d19bd194493aThomas Graf			bs = nla_data(tbs[TCA_STATS_BASIC]);
10344d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->tc_stats[RTNL_TC_BYTES]	= bs->bytes;
10444d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->tc_stats[RTNL_TC_PACKETS]	= bs->packets;
10544d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
10644d362409d5469aed47d19e7908d19bd194493aThomas Graf
10744d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (tbs[TCA_STATS_RATE_EST]) {
10844d362409d5469aed47d19e7908d19bd194493aThomas Graf			struct gnet_stats_rate_est *re;
10944d362409d5469aed47d19e7908d19bd194493aThomas Graf
11044d362409d5469aed47d19e7908d19bd194493aThomas Graf			re = nla_data(tbs[TCA_STATS_RATE_EST]);
11144d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->tc_stats[RTNL_TC_RATE_BPS]	= re->bps;
11244d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->tc_stats[RTNL_TC_RATE_PPS]	= re->pps;
11344d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
11444d362409d5469aed47d19e7908d19bd194493aThomas Graf
11544d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (tbs[TCA_STATS_QUEUE]) {
11644d362409d5469aed47d19e7908d19bd194493aThomas Graf			struct gnet_stats_queue *q;
11744d362409d5469aed47d19e7908d19bd194493aThomas Graf
11844d362409d5469aed47d19e7908d19bd194493aThomas Graf			q = nla_data(tbs[TCA_STATS_QUEUE]);
11944d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->tc_stats[RTNL_TC_QLEN]	= q->qlen;
12044d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->tc_stats[RTNL_TC_BACKLOG]	= q->backlog;
12144d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->tc_stats[RTNL_TC_DROPS]	= q->drops;
12244d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->tc_stats[RTNL_TC_REQUEUES]	= q->requeues;
12344d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->tc_stats[RTNL_TC_OVERLIMITS]	= q->overlimits;
12444d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
12544d362409d5469aed47d19e7908d19bd194493aThomas Graf
12644d362409d5469aed47d19e7908d19bd194493aThomas Graf		g->ce_mask |= TCA_ATTR_STATS;
12744d362409d5469aed47d19e7908d19bd194493aThomas Graf
12844d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (tbs[TCA_STATS_APP]) {
129eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			g->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]);
13044d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (g->tc_xstats == NULL)
1318a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				return -NLE_NOMEM;
13244d362409d5469aed47d19e7908d19bd194493aThomas Graf		} else
13344d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto compat_xstats;
13444d362409d5469aed47d19e7908d19bd194493aThomas Graf	} else {
13544d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (tb[TCA_STATS]) {
13644d362409d5469aed47d19e7908d19bd194493aThomas Graf			struct tc_stats *st = nla_data(tb[TCA_STATS]);
13744d362409d5469aed47d19e7908d19bd194493aThomas Graf
13844d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->tc_stats[RTNL_TC_BYTES]	= st->bytes;
13944d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->tc_stats[RTNL_TC_PACKETS]	= st->packets;
14044d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->tc_stats[RTNL_TC_RATE_BPS]	= st->bps;
14144d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->tc_stats[RTNL_TC_RATE_PPS]	= st->pps;
14244d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->tc_stats[RTNL_TC_QLEN]	= st->qlen;
14344d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->tc_stats[RTNL_TC_BACKLOG]	= st->backlog;
14444d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->tc_stats[RTNL_TC_DROPS]	= st->drops;
14544d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->tc_stats[RTNL_TC_OVERLIMITS]	= st->overlimits;
14644d362409d5469aed47d19e7908d19bd194493aThomas Graf
14744d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->ce_mask |= TCA_ATTR_STATS;
14844d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
14944d362409d5469aed47d19e7908d19bd194493aThomas Graf
15044d362409d5469aed47d19e7908d19bd194493aThomas Grafcompat_xstats:
15144d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (tb[TCA_XSTATS]) {
152eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			g->tc_xstats = nl_data_alloc_attr(tb[TCA_XSTATS]);
15344d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (g->tc_xstats == NULL)
1548a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				return -NLE_NOMEM;
15544d362409d5469aed47d19e7908d19bd194493aThomas Graf			g->ce_mask |= TCA_ATTR_XSTATS;
15644d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
15744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
15844d362409d5469aed47d19e7908d19bd194493aThomas Graf
15944d362409d5469aed47d19e7908d19bd194493aThomas Graf
16044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
16144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
16244d362409d5469aed47d19e7908d19bd194493aThomas Graf
16344d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid tca_free_data(struct rtnl_tca *tca)
16444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
16544d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_data_free(tca->tc_opts);
16644d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_data_free(tca->tc_xstats);
16744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
16844d362409d5469aed47d19e7908d19bd194493aThomas Graf
16944d362409d5469aed47d19e7908d19bd194493aThomas Grafint tca_clone(struct rtnl_tca *dst, struct rtnl_tca *src)
17044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
17144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (src->tc_opts) {
17244d362409d5469aed47d19e7908d19bd194493aThomas Graf		dst->tc_opts = nl_data_clone(src->tc_opts);
17344d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!dst->tc_opts)
1748a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_NOMEM;
17544d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
17644d362409d5469aed47d19e7908d19bd194493aThomas Graf
17744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (src->tc_xstats) {
17844d362409d5469aed47d19e7908d19bd194493aThomas Graf		dst->tc_xstats = nl_data_clone(src->tc_xstats);
17944d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!dst->tc_xstats)
1808a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_NOMEM;
18144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
18244d362409d5469aed47d19e7908d19bd194493aThomas Graf
18344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
18444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
18544d362409d5469aed47d19e7908d19bd194493aThomas Graf
186d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafvoid tca_dump_line(struct rtnl_tca *g, const char *type,
187d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		   struct nl_dump_params *p)
18844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
18944d362409d5469aed47d19e7908d19bd194493aThomas Graf	char handle[32], parent[32];
19044d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_cache *link_cache;
19144d362409d5469aed47d19e7908d19bd194493aThomas Graf
19244d362409d5469aed47d19e7908d19bd194493aThomas Graf	link_cache = nl_cache_mngt_require("route/link");
19344d362409d5469aed47d19e7908d19bd194493aThomas Graf
194d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "%s %s ", g->tc_kind, type);
19544d362409d5469aed47d19e7908d19bd194493aThomas Graf
19644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (link_cache) {
19744d362409d5469aed47d19e7908d19bd194493aThomas Graf		char buf[32];
198d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "dev %s ",
19944d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_link_i2name(link_cache, g->tc_ifindex,
20044d362409d5469aed47d19e7908d19bd194493aThomas Graf					 buf, sizeof(buf)));
20144d362409d5469aed47d19e7908d19bd194493aThomas Graf	} else
202d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf		nl_dump(p, "dev %u ", g->tc_ifindex);
20344d362409d5469aed47d19e7908d19bd194493aThomas Graf
204d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump(p, "handle %s parent %s",
20544d362409d5469aed47d19e7908d19bd194493aThomas Graf		rtnl_tc_handle2str(g->tc_handle, handle, sizeof(handle)),
20644d362409d5469aed47d19e7908d19bd194493aThomas Graf		rtnl_tc_handle2str(g->tc_parent, parent, sizeof(parent)));
20744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
20844d362409d5469aed47d19e7908d19bd194493aThomas Graf
209d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafvoid tca_dump_details(struct rtnl_tca *g, struct nl_dump_params *p)
21044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
211d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "  ");
21244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
21344d362409d5469aed47d19e7908d19bd194493aThomas Graf
214d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafvoid tca_dump_stats(struct rtnl_tca *g, struct nl_dump_params *p)
21544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
21644d362409d5469aed47d19e7908d19bd194493aThomas Graf	char *unit, fmt[64];
21744d362409d5469aed47d19e7908d19bd194493aThomas Graf	float res;
21844d362409d5469aed47d19e7908d19bd194493aThomas Graf	strcpy(fmt, "        %7.2f %s %10u %10u %10u %10u %10u\n");
21944d362409d5469aed47d19e7908d19bd194493aThomas Graf
220d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p,
22144d362409d5469aed47d19e7908d19bd194493aThomas Graf		"    Stats:    bytes    packets      drops overlimits" \
22244d362409d5469aed47d19e7908d19bd194493aThomas Graf		"       qlen    backlog\n");
22344d362409d5469aed47d19e7908d19bd194493aThomas Graf
22444d362409d5469aed47d19e7908d19bd194493aThomas Graf	res = nl_cancel_down_bytes(g->tc_stats[RTNL_TC_BYTES], &unit);
22544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (*unit == 'B')
22644d362409d5469aed47d19e7908d19bd194493aThomas Graf		fmt[11] = '9';
22744d362409d5469aed47d19e7908d19bd194493aThomas Graf
228d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, fmt, res, unit,
22944d362409d5469aed47d19e7908d19bd194493aThomas Graf		g->tc_stats[RTNL_TC_PACKETS],
23044d362409d5469aed47d19e7908d19bd194493aThomas Graf		g->tc_stats[RTNL_TC_DROPS],
23144d362409d5469aed47d19e7908d19bd194493aThomas Graf		g->tc_stats[RTNL_TC_OVERLIMITS],
23244d362409d5469aed47d19e7908d19bd194493aThomas Graf		g->tc_stats[RTNL_TC_QLEN],
23344d362409d5469aed47d19e7908d19bd194493aThomas Graf		g->tc_stats[RTNL_TC_BACKLOG]);
23444d362409d5469aed47d19e7908d19bd194493aThomas Graf
23544d362409d5469aed47d19e7908d19bd194493aThomas Graf	res = nl_cancel_down_bytes(g->tc_stats[RTNL_TC_RATE_BPS], &unit);
23644d362409d5469aed47d19e7908d19bd194493aThomas Graf
23744d362409d5469aed47d19e7908d19bd194493aThomas Graf	strcpy(fmt, "        %7.2f %s/s%9u pps");
23844d362409d5469aed47d19e7908d19bd194493aThomas Graf
23944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (*unit == 'B')
24044d362409d5469aed47d19e7908d19bd194493aThomas Graf		fmt[11] = '9';
24144d362409d5469aed47d19e7908d19bd194493aThomas Graf
242d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, fmt, res, unit, g->tc_stats[RTNL_TC_RATE_PPS]);
24344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
24444d362409d5469aed47d19e7908d19bd194493aThomas Graf
24544d362409d5469aed47d19e7908d19bd194493aThomas Grafint tca_compare(struct nl_object *_a, struct nl_object *_b,
24644d362409d5469aed47d19e7908d19bd194493aThomas Graf		uint32_t attrs, int flags)
24744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
24844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tca *a = (struct rtnl_tca *) _a;
24944d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_tca *b = (struct rtnl_tca *) _b;
25044d362409d5469aed47d19e7908d19bd194493aThomas Graf	int diff = 0;
25144d362409d5469aed47d19e7908d19bd194493aThomas Graf
25244d362409d5469aed47d19e7908d19bd194493aThomas Graf#define TC_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, TCA_ATTR_##ATTR, a, b, EXPR)
25344d362409d5469aed47d19e7908d19bd194493aThomas Graf
25444d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= TC_DIFF(HANDLE,		a->tc_handle != b->tc_handle);
25544d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= TC_DIFF(PARENT,		a->tc_parent != b->tc_parent);
25644d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= TC_DIFF(IFINDEX,	a->tc_ifindex != b->tc_ifindex);
25744d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= TC_DIFF(KIND,		strcmp(a->tc_kind, b->tc_kind));
25844d362409d5469aed47d19e7908d19bd194493aThomas Graf
25944d362409d5469aed47d19e7908d19bd194493aThomas Graf#undef TC_DIFF
26044d362409d5469aed47d19e7908d19bd194493aThomas Graf
26144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return diff;
26244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
26344d362409d5469aed47d19e7908d19bd194493aThomas Graf
26444d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid tca_set_ifindex(struct rtnl_tca *t, int ifindex)
26544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
26644d362409d5469aed47d19e7908d19bd194493aThomas Graf	t->tc_ifindex = ifindex;
26744d362409d5469aed47d19e7908d19bd194493aThomas Graf	t->ce_mask |= TCA_ATTR_IFINDEX;
26844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
26944d362409d5469aed47d19e7908d19bd194493aThomas Graf
27044d362409d5469aed47d19e7908d19bd194493aThomas Grafint tca_get_ifindex(struct rtnl_tca *t)
27144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
272b4fbe1d34d6f54045b5c6236d86aacd4340ec83dThomas Graf	return t->tc_ifindex;
27344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
27444d362409d5469aed47d19e7908d19bd194493aThomas Graf
27544d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid tca_set_handle(struct rtnl_tca *t, uint32_t handle)
27644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
27744d362409d5469aed47d19e7908d19bd194493aThomas Graf	t->tc_handle = handle;
27844d362409d5469aed47d19e7908d19bd194493aThomas Graf	t->ce_mask |= TCA_ATTR_HANDLE;
27944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
28044d362409d5469aed47d19e7908d19bd194493aThomas Graf
28144d362409d5469aed47d19e7908d19bd194493aThomas Grafuint32_t tca_get_handle(struct rtnl_tca *t)
28244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
28344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (t->ce_mask & TCA_ATTR_HANDLE)
28444d362409d5469aed47d19e7908d19bd194493aThomas Graf		return t->tc_handle;
28544d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
28644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return 0;
28744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
28844d362409d5469aed47d19e7908d19bd194493aThomas Graf
28944d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid tca_set_parent(struct rtnl_tca *t, uint32_t parent)
29044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
29144d362409d5469aed47d19e7908d19bd194493aThomas Graf	t->tc_parent = parent;
29244d362409d5469aed47d19e7908d19bd194493aThomas Graf	t->ce_mask |= TCA_ATTR_PARENT;
29344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
29444d362409d5469aed47d19e7908d19bd194493aThomas Graf
29544d362409d5469aed47d19e7908d19bd194493aThomas Grafuint32_t tca_get_parent(struct rtnl_tca *t)
29644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
29744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (t->ce_mask & TCA_ATTR_PARENT)
29844d362409d5469aed47d19e7908d19bd194493aThomas Graf		return t->tc_parent;
29944d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
30044d362409d5469aed47d19e7908d19bd194493aThomas Graf		return 0;
30144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
30244d362409d5469aed47d19e7908d19bd194493aThomas Graf
30344d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid tca_set_kind(struct rtnl_tca *t, const char *kind)
30444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
30544d362409d5469aed47d19e7908d19bd194493aThomas Graf	strncpy(t->tc_kind, kind, sizeof(t->tc_kind) - 1);
30644d362409d5469aed47d19e7908d19bd194493aThomas Graf	t->ce_mask |= TCA_ATTR_KIND;
30744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
30844d362409d5469aed47d19e7908d19bd194493aThomas Graf
30944d362409d5469aed47d19e7908d19bd194493aThomas Grafchar *tca_get_kind(struct rtnl_tca *t)
31044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
31144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (t->ce_mask & TCA_ATTR_KIND)
31244d362409d5469aed47d19e7908d19bd194493aThomas Graf		return t->tc_kind;
31344d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
31444d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
31544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
31644d362409d5469aed47d19e7908d19bd194493aThomas Graf
31744d362409d5469aed47d19e7908d19bd194493aThomas Grafuint64_t tca_get_stat(struct rtnl_tca *t, int id)
31844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
31944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (id < 0 || id > RTNL_TC_STATS_MAX)
32044d362409d5469aed47d19e7908d19bd194493aThomas Graf		return 0;
32144d362409d5469aed47d19e7908d19bd194493aThomas Graf
32244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return t->tc_stats[id];
32344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
32444d362409d5469aed47d19e7908d19bd194493aThomas Graf
3258a3efffa5b3fde252675239914118664d36a2c24Thomas Grafint tca_build_msg(struct rtnl_tca *tca, int type, int flags,
3268a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		  struct nl_msg **result)
32744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
32844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_msg *msg;
32944d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct tcmsg tchdr = {
33044d362409d5469aed47d19e7908d19bd194493aThomas Graf		.tcm_family = AF_UNSPEC,
33144d362409d5469aed47d19e7908d19bd194493aThomas Graf		.tcm_ifindex = tca->tc_ifindex,
33244d362409d5469aed47d19e7908d19bd194493aThomas Graf		.tcm_handle = tca->tc_handle,
33344d362409d5469aed47d19e7908d19bd194493aThomas Graf		.tcm_parent = tca->tc_parent,
33444d362409d5469aed47d19e7908d19bd194493aThomas Graf	};
33544d362409d5469aed47d19e7908d19bd194493aThomas Graf
33644d362409d5469aed47d19e7908d19bd194493aThomas Graf	msg = nlmsg_alloc_simple(type, flags);
33744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!msg)
3388a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
33944d362409d5469aed47d19e7908d19bd194493aThomas Graf
34044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0)
34144d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto nla_put_failure;
34244d362409d5469aed47d19e7908d19bd194493aThomas Graf
34344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (tca->ce_mask & TCA_ATTR_KIND)
34444d362409d5469aed47d19e7908d19bd194493aThomas Graf	    NLA_PUT_STRING(msg, TCA_KIND, tca->tc_kind);
34544d362409d5469aed47d19e7908d19bd194493aThomas Graf
3468a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	*result = msg;
3478a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return 0;
34844d362409d5469aed47d19e7908d19bd194493aThomas Graf
34944d362409d5469aed47d19e7908d19bd194493aThomas Grafnla_put_failure:
35044d362409d5469aed47d19e7908d19bd194493aThomas Graf	nlmsg_free(msg);
3518a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return -NLE_MSGSIZE;
35244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
35344d362409d5469aed47d19e7908d19bd194493aThomas Graf
35444d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @endcond */
35544d362409d5469aed47d19e7908d19bd194493aThomas Graf
35644d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
35744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Utilities
35844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
35944d362409d5469aed47d19e7908d19bd194493aThomas Graf */
36044d362409d5469aed47d19e7908d19bd194493aThomas Graf
36144d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
36244d362409d5469aed47d19e7908d19bd194493aThomas Graf * Calculate time required to transmit buffer at a specific rate
36344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg bufsize		Size of buffer to be transmited in bytes.
36444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg rate		Transmit rate in bytes per second.
36544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
36644d362409d5469aed47d19e7908d19bd194493aThomas Graf * Calculates the number of micro seconds required to transmit a
36744d362409d5469aed47d19e7908d19bd194493aThomas Graf * specific buffer at a specific transmit rate.
36844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
36944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @f[
37044d362409d5469aed47d19e7908d19bd194493aThomas Graf *   txtime=\frac{bufsize}{rate}10^6
37144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @f]
37244d362409d5469aed47d19e7908d19bd194493aThomas Graf *
37344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Required transmit time in micro seconds.
37444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
37544d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_tc_calc_txtime(int bufsize, int rate)
37644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
37744d362409d5469aed47d19e7908d19bd194493aThomas Graf	double tx_time_secs;
37844d362409d5469aed47d19e7908d19bd194493aThomas Graf
37944d362409d5469aed47d19e7908d19bd194493aThomas Graf	tx_time_secs = (double) bufsize / (double) rate;
38044d362409d5469aed47d19e7908d19bd194493aThomas Graf
38144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return tx_time_secs * 1000000.;
38244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
38344d362409d5469aed47d19e7908d19bd194493aThomas Graf
38444d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
38544d362409d5469aed47d19e7908d19bd194493aThomas Graf * Calculate buffer size able to transmit in a specific time and rate.
38644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg txtime		Available transmit time in micro seconds.
38744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg rate		Transmit rate in bytes per second.
38844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
38944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Calculates the size of the buffer that can be transmitted in a
39044d362409d5469aed47d19e7908d19bd194493aThomas Graf * specific time period at a specific transmit rate.
39144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
39244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @f[
39344d362409d5469aed47d19e7908d19bd194493aThomas Graf *   bufsize=\frac{{txtime} \times {rate}}{10^6}
39444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @f]
39544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
39644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Size of buffer in bytes.
39744d362409d5469aed47d19e7908d19bd194493aThomas Graf */
39844d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_tc_calc_bufsize(int txtime, int rate)
39944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
40044d362409d5469aed47d19e7908d19bd194493aThomas Graf	double bufsize;
40144d362409d5469aed47d19e7908d19bd194493aThomas Graf
40244d362409d5469aed47d19e7908d19bd194493aThomas Graf	bufsize = (double) txtime * (double) rate;
40344d362409d5469aed47d19e7908d19bd194493aThomas Graf
40444d362409d5469aed47d19e7908d19bd194493aThomas Graf	return bufsize / 1000000.;
40544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
40644d362409d5469aed47d19e7908d19bd194493aThomas Graf
40744d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
40844d362409d5469aed47d19e7908d19bd194493aThomas Graf * Calculate the binary logarithm for a specific cell size
40944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cell_size	Size of cell, must be a power of two.
41044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Binary logirhtm of cell size or a negative error code.
41144d362409d5469aed47d19e7908d19bd194493aThomas Graf */
41244d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_tc_calc_cell_log(int cell_size)
41344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
41444d362409d5469aed47d19e7908d19bd194493aThomas Graf	int i;
41544d362409d5469aed47d19e7908d19bd194493aThomas Graf
41644d362409d5469aed47d19e7908d19bd194493aThomas Graf	for (i = 0; i < 32; i++)
41744d362409d5469aed47d19e7908d19bd194493aThomas Graf		if ((1 << i) == cell_size)
41844d362409d5469aed47d19e7908d19bd194493aThomas Graf			return i;
41944d362409d5469aed47d19e7908d19bd194493aThomas Graf
4208a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return -NLE_INVAL;
42144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
42244d362409d5469aed47d19e7908d19bd194493aThomas Graf
42344d362409d5469aed47d19e7908d19bd194493aThomas Graf
42444d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
42544d362409d5469aed47d19e7908d19bd194493aThomas Graf
42644d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
42744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Rate Tables
42844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
42944d362409d5469aed47d19e7908d19bd194493aThomas Graf */
43044d362409d5469aed47d19e7908d19bd194493aThomas Graf
43144d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
43244d362409d5469aed47d19e7908d19bd194493aThomas Graf * Compute a transmission time lookup table
43344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg dst	 Destination buffer of RTNL_TC_RTABLE_SIZE uint32_t[].
43444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg mpu	 Minimal size of a packet at all times.
43544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg overhead Overhead to be added to each packet.
43644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cell	 Size of cell, i.e. size of step between entries in bytes.
43744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg rate	 Rate in bytes per second.
43844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
43944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Computes a table of RTNL_TC_RTABLE_SIZE entries specyfing the
44044d362409d5469aed47d19e7908d19bd194493aThomas Graf * transmission times for various packet sizes, e.g. the transmission
44144d362409d5469aed47d19e7908d19bd194493aThomas Graf * time for a packet of size \c pktsize could be looked up:
44244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
44344d362409d5469aed47d19e7908d19bd194493aThomas Graf * txtime = table[pktsize >> log2(cell)];
44444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
44544d362409d5469aed47d19e7908d19bd194493aThomas Graf */
44644d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_tc_build_rate_table(uint32_t *dst, uint8_t mpu, uint8_t overhead,
44744d362409d5469aed47d19e7908d19bd194493aThomas Graf			     int cell, int rate)
44844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
44944d362409d5469aed47d19e7908d19bd194493aThomas Graf	int i, size, cell_log;
45044d362409d5469aed47d19e7908d19bd194493aThomas Graf
45144d362409d5469aed47d19e7908d19bd194493aThomas Graf	cell_log = rtnl_tc_calc_cell_log(cell);
45244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (cell_log < 0)
45344d362409d5469aed47d19e7908d19bd194493aThomas Graf		return cell_log;
45444d362409d5469aed47d19e7908d19bd194493aThomas Graf
45544d362409d5469aed47d19e7908d19bd194493aThomas Graf	for (i = 0; i < RTNL_TC_RTABLE_SIZE; i++) {
45644d362409d5469aed47d19e7908d19bd194493aThomas Graf		size = (i << cell_log) + overhead;
45744d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (size < mpu)
45844d362409d5469aed47d19e7908d19bd194493aThomas Graf			size = mpu;
45944d362409d5469aed47d19e7908d19bd194493aThomas Graf
46044d362409d5469aed47d19e7908d19bd194493aThomas Graf		dst[i] = rtnl_tc_calc_txtime(size, rate);
46144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
46244d362409d5469aed47d19e7908d19bd194493aThomas Graf
46344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
46444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
46544d362409d5469aed47d19e7908d19bd194493aThomas Graf
46644d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
46744d362409d5469aed47d19e7908d19bd194493aThomas Graf
46844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
46944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Traffic Control Handle Translations
47044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
47144d362409d5469aed47d19e7908d19bd194493aThomas Graf */
47244d362409d5469aed47d19e7908d19bd194493aThomas Graf
47344d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
47444d362409d5469aed47d19e7908d19bd194493aThomas Graf * Convert a traffic control handle to a character string (Reentrant).
47544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg handle		traffic control handle
47644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg buf		destination buffer
47744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg len		buffer length
47844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
47944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Converts a tarffic control handle to a character string in the
48044d362409d5469aed47d19e7908d19bd194493aThomas Graf * form of \c MAJ:MIN and stores it in the specified destination buffer.
48144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
48244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return The destination buffer or the type encoded in hexidecimal
48344d362409d5469aed47d19e7908d19bd194493aThomas Graf *         form if no match was found.
48444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
48544d362409d5469aed47d19e7908d19bd194493aThomas Grafchar * rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
48644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
48744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (TC_H_ROOT == handle)
48844d362409d5469aed47d19e7908d19bd194493aThomas Graf		snprintf(buf, len, "root");
48944d362409d5469aed47d19e7908d19bd194493aThomas Graf	else if (TC_H_UNSPEC == handle)
49044d362409d5469aed47d19e7908d19bd194493aThomas Graf		snprintf(buf, len, "none");
49144d362409d5469aed47d19e7908d19bd194493aThomas Graf	else if (0 == TC_H_MAJ(handle))
49244d362409d5469aed47d19e7908d19bd194493aThomas Graf		snprintf(buf, len, ":%02x", TC_H_MIN(handle));
49344d362409d5469aed47d19e7908d19bd194493aThomas Graf	else if (0 == TC_H_MIN(handle))
49444d362409d5469aed47d19e7908d19bd194493aThomas Graf		snprintf(buf, len, "%02x:", TC_H_MAJ(handle) >> 16);
49544d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
49644d362409d5469aed47d19e7908d19bd194493aThomas Graf		snprintf(buf, len, "%02x:%02x",
49744d362409d5469aed47d19e7908d19bd194493aThomas Graf			TC_H_MAJ(handle) >> 16, TC_H_MIN(handle));
49844d362409d5469aed47d19e7908d19bd194493aThomas Graf
49944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return buf;
50044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
50144d362409d5469aed47d19e7908d19bd194493aThomas Graf
50244d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
50344d362409d5469aed47d19e7908d19bd194493aThomas Graf * Convert a charactering strint to a traffic control handle
50444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg name		traffic control handle as character string
50544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg res		destination buffer
50644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
50744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Converts the provided character string specifying a traffic
50844d362409d5469aed47d19e7908d19bd194493aThomas Graf * control handle to the corresponding numeric value.
50944d362409d5469aed47d19e7908d19bd194493aThomas Graf *
51044d362409d5469aed47d19e7908d19bd194493aThomas Graf * The handle must be provided in one of the following formats:
51144d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - root
51244d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - none
51344d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - XXXX:
51444d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - :YYYY
51544d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - XXXX:YYYY
51644d362409d5469aed47d19e7908d19bd194493aThomas Graf *  - XXXXYYYY
51744d362409d5469aed47d19e7908d19bd194493aThomas Graf *
51844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on success or a negative error code
51944d362409d5469aed47d19e7908d19bd194493aThomas Graf */
52044d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_tc_str2handle(const char *name, uint32_t *res)
52144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
52244d362409d5469aed47d19e7908d19bd194493aThomas Graf	char *colon, *end;
52344d362409d5469aed47d19e7908d19bd194493aThomas Graf	uint32_t h;
52444d362409d5469aed47d19e7908d19bd194493aThomas Graf
52544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!strcasecmp(name, "root")) {
52644d362409d5469aed47d19e7908d19bd194493aThomas Graf		*res = TC_H_ROOT;
52744d362409d5469aed47d19e7908d19bd194493aThomas Graf		return 0;
52844d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
52944d362409d5469aed47d19e7908d19bd194493aThomas Graf
53044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!strcasecmp(name, "none")) {
53144d362409d5469aed47d19e7908d19bd194493aThomas Graf		*res = TC_H_UNSPEC;
53244d362409d5469aed47d19e7908d19bd194493aThomas Graf		return 0;
53344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
53444d362409d5469aed47d19e7908d19bd194493aThomas Graf
53544d362409d5469aed47d19e7908d19bd194493aThomas Graf	h = strtoul(name, &colon, 16);
53644d362409d5469aed47d19e7908d19bd194493aThomas Graf
53744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (colon == name) {
53844d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* :YYYY */
53944d362409d5469aed47d19e7908d19bd194493aThomas Graf		h = 0;
54044d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (':' != *colon)
5418a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_INVAL;
54244d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
54344d362409d5469aed47d19e7908d19bd194493aThomas Graf
54444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (':' == *colon) {
54544d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* check if we would lose bits */
54644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (TC_H_MAJ(h))
5478a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_RANGE;
54844d362409d5469aed47d19e7908d19bd194493aThomas Graf		h <<= 16;
54944d362409d5469aed47d19e7908d19bd194493aThomas Graf
55044d362409d5469aed47d19e7908d19bd194493aThomas Graf		if ('\0' == colon[1]) {
55144d362409d5469aed47d19e7908d19bd194493aThomas Graf			/* XXXX: */
55244d362409d5469aed47d19e7908d19bd194493aThomas Graf			*res = h;
55344d362409d5469aed47d19e7908d19bd194493aThomas Graf		} else {
55444d362409d5469aed47d19e7908d19bd194493aThomas Graf			/* XXXX:YYYY */
55544d362409d5469aed47d19e7908d19bd194493aThomas Graf			uint32_t l = strtoul(colon+1, &end, 16);
55644d362409d5469aed47d19e7908d19bd194493aThomas Graf
55744d362409d5469aed47d19e7908d19bd194493aThomas Graf			/* check if we overlap with major part */
55844d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (TC_H_MAJ(l))
5598a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				return -NLE_RANGE;
56044d362409d5469aed47d19e7908d19bd194493aThomas Graf
56144d362409d5469aed47d19e7908d19bd194493aThomas Graf			if ('\0' != *end)
5628a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				return -NLE_INVAL;
56344d362409d5469aed47d19e7908d19bd194493aThomas Graf
56444d362409d5469aed47d19e7908d19bd194493aThomas Graf			*res = (h | l);
56544d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
56644d362409d5469aed47d19e7908d19bd194493aThomas Graf	} else if ('\0' == *colon) {
56744d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* XXXXYYYY */
56844d362409d5469aed47d19e7908d19bd194493aThomas Graf		*res = h;
56944d362409d5469aed47d19e7908d19bd194493aThomas Graf	} else
5708a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_INVAL;
57144d362409d5469aed47d19e7908d19bd194493aThomas Graf
57244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
57344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
57444d362409d5469aed47d19e7908d19bd194493aThomas Graf
57544d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
57644d362409d5469aed47d19e7908d19bd194493aThomas Graf
57744d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
578