summaryrefslogtreecommitdiffstats
path: root/lib/route/tc.c
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2010-10-26 10:54:33 (GMT)
committerThomas Graf <tgraf@suug.ch>2010-10-26 10:54:33 (GMT)
commit4c6d1c5dfb4f7e4a9392895f3da709b55c970e02 (patch)
tree9303851dcc87e2e3f9c25805ccf24f4a543fe23d /lib/route/tc.c
parentb9d965b01b42103389b2a2c0cc3133293447a64d (diff)
downloadlibnl-4c6d1c5dfb4f7e4a9392895f3da709b55c970e02.zip
libnl-4c6d1c5dfb4f7e4a9392895f3da709b55c970e02.tar.gz
libnl-4c6d1c5dfb4f7e4a9392895f3da709b55c970e02.tar.bz2
Unified TC attributes interface
So far all common tc atttributes were accessed via specific functions, i.e. rtnl_class_set_parent(), rtnl_qdisc_set_parent(), rtnl_cls_set_parent() which implied a lot of code duplication. Since all tc objects are derived from struct rtnl_tc and these common attributes are already stored in there this patch removes all type specific functions and makes rtnl_tc_* attribute functions public. rtnl_qdisc_set_parent(qdisc, 10); becomes: rtnl_tc_set_parent((struct rtnl_tc *) qdisc, 10); This patch also adds the following new attributes to tc objects therefore removing them as tc specific attributes: - mtu - mpu - overhead This allows for the rate table calculations to be unified as well taking into account the new kernel behavior to take care of overhead automatically.
Diffstat (limited to 'lib/route/tc.c')
-rw-r--r--lib/route/tc.c444
1 files changed, 363 insertions, 81 deletions
diff --git a/lib/route/tc.c b/lib/route/tc.c
index 1860c6f..6a0233a 100644
--- a/lib/route/tc.c
+++ b/lib/route/tc.c
@@ -6,13 +6,12 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
- * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2010 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup rtnl
* @defgroup tc Traffic Control
- * @brief
* @{
*/
@@ -33,7 +32,7 @@ static struct nla_policy tc_policy[TCA_MAX+1] = {
[TCA_STATS2] = { .type = NLA_NESTED },
};
-int tca_parse(struct nlattr **tb, int maxattr, struct rtnl_tca *g,
+int tca_parse(struct nlattr **tb, int maxattr, struct rtnl_tc *g,
struct nla_policy *policy)
{
@@ -55,7 +54,7 @@ static struct nla_policy tc_stats2_policy[TCA_STATS_MAX+1] = {
[TCA_STATS_QUEUE] = { .minlen = sizeof(struct gnet_stats_queue) },
};
-int tca_msg_parser(struct nlmsghdr *n, struct rtnl_tca *g)
+int tca_msg_parser(struct nlmsghdr *n, struct rtnl_tc *g)
{
struct nlattr *tb[TCA_MAX + 1];
struct tcmsg *tm;
@@ -160,14 +159,22 @@ compat_xstats:
return 0;
}
-void tca_free_data(struct rtnl_tca *tca)
+void tca_free_data(struct rtnl_tc *tca)
{
+ rtnl_link_put(tca->tc_link);
nl_data_free(tca->tc_opts);
nl_data_free(tca->tc_xstats);
}
-int tca_clone(struct rtnl_tca *dst, struct rtnl_tca *src)
+int tca_clone(struct rtnl_tc *dst, struct rtnl_tc *src)
{
+ if (src->tc_link) {
+ dst->tc_link = (struct rtnl_link *)
+ nl_object_clone(OBJ_CAST(src->tc_link));
+ if (!dst->tc_link)
+ return -NLE_NOMEM;
+ }
+
if (src->tc_opts) {
dst->tc_opts = nl_data_clone(src->tc_opts);
if (!dst->tc_opts)
@@ -183,7 +190,7 @@ int tca_clone(struct rtnl_tca *dst, struct rtnl_tca *src)
return 0;
}
-void tca_dump_line(struct rtnl_tca *g, const char *type,
+void tca_dump_line(struct rtnl_tc *g, const char *type,
struct nl_dump_params *p)
{
char handle[32], parent[32];
@@ -206,12 +213,21 @@ void tca_dump_line(struct rtnl_tca *g, const char *type,
rtnl_tc_handle2str(g->tc_parent, parent, sizeof(parent)));
}
-void tca_dump_details(struct rtnl_tca *g, struct nl_dump_params *p)
+void tca_dump_details(struct rtnl_tc *tc, struct nl_dump_params *p)
{
nl_dump_line(p, " ");
+
+ if (tc->ce_mask & TCA_ATTR_MTU)
+ nl_dump(p, " mtu %u", tc->tc_mtu);
+
+ if (tc->ce_mask & TCA_ATTR_MPU)
+ nl_dump(p, " mput %u", tc->tc_mpu);
+
+ if (tc->ce_mask & TCA_ATTR_OVERHEAD)
+ nl_dump(p, " overhead %u", tc->tc_overhead);
}
-void tca_dump_stats(struct rtnl_tca *g, struct nl_dump_params *p)
+void tca_dump_stats(struct rtnl_tc *g, struct nl_dump_params *p)
{
char *unit, fmt[64];
float res;
@@ -245,8 +261,8 @@ void tca_dump_stats(struct rtnl_tca *g, struct nl_dump_params *p)
int tca_compare(struct nl_object *_a, struct nl_object *_b,
uint32_t attrs, int flags)
{
- struct rtnl_tca *a = (struct rtnl_tca *) _a;
- struct rtnl_tca *b = (struct rtnl_tca *) _b;
+ struct rtnl_tc *a = (struct rtnl_tc *) _a;
+ struct rtnl_tc *b = (struct rtnl_tc *) _b;
int diff = 0;
#define TC_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, TCA_ATTR_##ATTR, a, b, EXPR)
@@ -261,97 +277,305 @@ int tca_compare(struct nl_object *_a, struct nl_object *_b,
return diff;
}
-void tca_set_ifindex(struct rtnl_tca *t, int ifindex)
+int tca_build_msg(struct rtnl_tc *tca, int type, int flags,
+ struct nl_msg **result)
+{
+ struct nl_msg *msg;
+ struct tcmsg tchdr = {
+ .tcm_family = AF_UNSPEC,
+ .tcm_ifindex = tca->tc_ifindex,
+ .tcm_handle = tca->tc_handle,
+ .tcm_parent = tca->tc_parent,
+ };
+
+ msg = nlmsg_alloc_simple(type, flags);
+ if (!msg)
+ return -NLE_NOMEM;
+
+ if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0)
+ goto nla_put_failure;
+
+ if (tca->ce_mask & TCA_ATTR_KIND)
+ NLA_PUT_STRING(msg, TCA_KIND, tca->tc_kind);
+
+ *result = msg;
+ return 0;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -NLE_MSGSIZE;
+}
+
+void tca_set_kind(struct rtnl_tc *t, const char *kind)
{
- t->tc_ifindex = ifindex;
- t->ce_mask |= TCA_ATTR_IFINDEX;
+ strncpy(t->tc_kind, kind, sizeof(t->tc_kind) - 1);
+ t->ce_mask |= TCA_ATTR_KIND;
}
-int tca_get_ifindex(struct rtnl_tca *t)
+
+/** @endcond */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+/**
+ * Set interface index of traffic control object
+ * @arg tc traffic control object
+ * @arg ifindex interface index.
+ *
+ * Sets the interface index of a traffic control object. The interface
+ * index defines the network device which this tc object is attached to.
+ * This function will overwrite any network device assigned with previous
+ * calls to rtnl_tc_set_ifindex() or rtnl_tc_set_link().
+ */
+void rtnl_tc_set_ifindex(struct rtnl_tc *tc, int ifindex)
{
- return t->tc_ifindex;
+ /* Obsolete possible old link reference */
+ rtnl_link_put(tc->tc_link);
+ tc->tc_link = NULL;
+ tc->ce_mask &= ~TCA_ATTR_LINK;
+
+ tc->tc_ifindex = ifindex;
+ tc->ce_mask |= TCA_ATTR_IFINDEX;
}
-void tca_set_handle(struct rtnl_tca *t, uint32_t handle)
+/**
+ * Return interface index of traffic control object
+ * @arg tc traffic control object
+ */
+int rtnl_tc_get_ifindex(struct rtnl_tc *tc)
{
- t->tc_handle = handle;
- t->ce_mask |= TCA_ATTR_HANDLE;
+ return tc->tc_ifindex;
}
-uint32_t tca_get_handle(struct rtnl_tca *t)
+/**
+ * Set link of traffic control object
+ * @arg tc traffic control object
+ * @arg link link object
+ *
+ * Sets the link of a traffic control object. This function serves
+ * the same purpose as rtnl_tc_set_ifindex() but due to the continued
+ * allowed access to the link object it gives it the possibility to
+ * retrieve sane default values for the the MTU and the linktype.
+ * Always prefer this function over rtnl_tc_set_ifindex() if you can
+ * spare to have an additional link object around.
+ */
+void rtnl_tc_set_link(struct rtnl_tc *tc, struct rtnl_link *link)
{
- if (t->ce_mask & TCA_ATTR_HANDLE)
- return t->tc_handle;
- else
- return 0;
+ rtnl_link_put(tc->tc_link);
+
+ if (!link)
+ return;
+
+ nl_object_get(OBJ_CAST(link));
+ tc->tc_link = link;
+ tc->tc_ifindex = link->l_index;
+ tc->ce_mask |= TCA_ATTR_LINK | TCA_ATTR_IFINDEX;
}
-void tca_set_parent(struct rtnl_tca *t, uint32_t parent)
+/**
+ * Set the Maximum Transmission Unit (MTU) of traffic control object
+ * @arg tc traffic control object
+ * @arg mtu largest packet size expected
+ *
+ * Sets the MTU of a traffic control object. Not all traffic control
+ * objects will make use of this but it helps while calculating rate
+ * tables. This value is typically derived directly from the link
+ * the tc object is attached to if the link has been assigned via
+ * rtnl_tc_set_link(). It is usually not necessary to set the MTU
+ * manually, this function is provided to allow overwriting the derived
+ * value.
+ */
+void rtnl_tc_set_mtu(struct rtnl_tc *tc, uint32_t mtu)
{
- t->tc_parent = parent;
- t->ce_mask |= TCA_ATTR_PARENT;
+ tc->tc_mtu = mtu;
+ tc->ce_mask |= TCA_ATTR_MTU;
}
-uint32_t tca_get_parent(struct rtnl_tca *t)
+/**
+ * Return the MTU of traffic control object
+ * @arg tc traffic control object
+ *
+ * Returns the MTU of a traffic control object which has been set via:
+ * -# User specified value set via rtnl_tc_set_mtu()
+ * -# Dervied from link set via rtnl_tc_set_link()
+ * -# Fall back to default: ethernet = 1600
+ */
+uint32_t rtnl_tc_get_mtu(struct rtnl_tc *tc)
{
- if (t->ce_mask & TCA_ATTR_PARENT)
- return t->tc_parent;
+ if (tc->ce_mask & TCA_ATTR_MTU)
+ return tc->tc_mtu;
+ else if (tc->ce_mask & TCA_ATTR_LINK)
+ return tc->tc_link->l_mtu;
else
- return 0;
+ return 1600; /* default to ethernet */
}
-void tca_set_kind(struct rtnl_tca *t, const char *kind)
+/**
+ * Set the Minimum Packet Unit (MPU) of a traffic control object
+ * @arg tc traffic control object
+ * @arg mpu minimum packet size expected
+ *
+ * Sets the MPU of a traffic contorl object. It specifies the minimum
+ * packet size to ever hit this traffic control object. Not all traffic
+ * control objects will make use of this but it helps while calculating
+ * rate tables.
+ */
+void rtnl_tc_set_mpu(struct rtnl_tc *tc, uint32_t mpu)
{
- strncpy(t->tc_kind, kind, sizeof(t->tc_kind) - 1);
- t->ce_mask |= TCA_ATTR_KIND;
+ tc->tc_mpu = mpu;
+ tc->ce_mask |= TCA_ATTR_MPU;
}
-char *tca_get_kind(struct rtnl_tca *t)
+/**
+ * Return the Minimum Packet Unit (MPU) of a traffic control object
+ * @arg tc traffic control object
+ *
+ * @return The MPU previously set via rtnl_tc_set_mpu() or 0.
+ */
+uint32_t rtnl_tc_get_mpu(struct rtnl_tc *tc)
{
- if (t->ce_mask & TCA_ATTR_KIND)
- return t->tc_kind;
- else
- return NULL;
+ return tc->tc_mpu;
}
-uint64_t tca_get_stat(struct rtnl_tca *t, int id)
+/**
+ * Set per packet overhead of a traffic control object
+ * @arg tc traffic control object
+ * @arg overhead overhead per packet in bytes
+ *
+ * Sets the per packet overhead in bytes occuring on the link not seen
+ * by the kernel. This value can be used to correct size calculations
+ * if the packet size on the wire does not match the packet sizes seen
+ * in the network stack. Not all traffic control objects will make use
+ * this but it helps while calculating accurate packet sizes in the
+ * kernel.
+ */
+void rtnl_tc_set_overhead(struct rtnl_tc *tc, uint32_t overhead)
{
- if (id < 0 || id > RTNL_TC_STATS_MAX)
- return 0;
+ tc->tc_overhead = overhead;
+ tc->ce_mask |= TCA_ATTR_OVERHEAD;
+}
- return t->tc_stats[id];
+/**
+ * Return per packet overhead of a traffic control object
+ * @arg tc traffic control object
+ *
+ * @return The overhead previously set by rtnl_tc_set_overhead() or 0.
+ */
+uint32_t rtnl_tc_get_overhead(struct rtnl_tc *tc)
+{
+ return tc->tc_overhead;
}
-int tca_build_msg(struct rtnl_tca *tca, int type, int flags,
- struct nl_msg **result)
+/**
+ * Set the linktype of a traffic control object
+ * @arg tc traffic control object
+ * @arg type type of link (e.g. ARPHRD_ATM, ARPHRD_ETHER)
+ *
+ * Overwrites the type of link this traffic control object is attached to.
+ * This value is typically derived from the link this tc object is attached
+ * if the link has been assigned via rtnl_tc_set_link(). It is usually not
+ * necessary to set the linktype manually. This function is provided to
+ * allow overwriting the linktype.
+ */
+void rtnl_tc_set_linktype(struct rtnl_tc *tc, uint32_t type)
{
- struct nl_msg *msg;
- struct tcmsg tchdr = {
- .tcm_family = AF_UNSPEC,
- .tcm_ifindex = tca->tc_ifindex,
- .tcm_handle = tca->tc_handle,
- .tcm_parent = tca->tc_parent,
- };
+ tc->tc_linktype = type;
+ tc->ce_mask |= TCA_ATTR_LINKTYPE;
+}
- msg = nlmsg_alloc_simple(type, flags);
- if (!msg)
- return -NLE_NOMEM;
+/**
+ * Return the linktype of a traffic control object
+ * @arg tc traffic control object
+ *
+ * Returns the linktype of the link the traffic control object is attached to:
+ * -# User specified value via rtnl_tc_set_linktype()
+ * -# Value derived from link set via rtnl_tc_set_link()
+ * -# Default fall-back: ARPHRD_ETHER
+ */
+uint32_t rtnl_tc_get_linktype(struct rtnl_tc *tc)
+{
+ if (tc->ce_mask & TCA_ATTR_LINKTYPE)
+ return tc->tc_linktype;
+ else if (tc->ce_mask & TCA_ATTR_LINK)
+ return tc->tc_link->l_arptype;
+ else
+ return ARPHRD_ETHER; /* default to ethernet */
+}
- if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0)
- goto nla_put_failure;
+/**
+ * Set identifier of traffic control object
+ * @arg tc traffic control object
+ * @arg id unique identifier
+ */
+void rtnl_tc_set_handle(struct rtnl_tc *tc, uint32_t id)
+{
+ tc->tc_handle = id;
+ tc->ce_mask |= TCA_ATTR_HANDLE;
+}
- if (tca->ce_mask & TCA_ATTR_KIND)
- NLA_PUT_STRING(msg, TCA_KIND, tca->tc_kind);
+/**
+ * Return identifier of a traffic control object
+ * @arg tc traffic control object
+ */
+uint32_t rtnl_tc_get_handle(struct rtnl_tc *tc)
+{
+ return tc->tc_handle;
+}
- *result = msg;
- return 0;
+/**
+ * Set the parent identifier of a traffic control object
+ * @arg tc traffic control object
+ * @arg parent identifier of parent traffif control object
+ *
+ */
+void rtnl_tc_set_parent(struct rtnl_tc *tc, uint32_t parent)
+{
+ tc->tc_parent = parent;
+ tc->ce_mask |= TCA_ATTR_PARENT;
+}
-nla_put_failure:
- nlmsg_free(msg);
- return -NLE_MSGSIZE;
+/**
+ * Return parent identifier of a traffic control object
+ * @arg tc traffic control object
+ */
+uint32_t rtnl_tc_get_parent(struct rtnl_tc *tc)
+{
+ return tc->tc_parent;
}
-/** @endcond */
+/**
+ * Return kind of traffic control object
+ * @arg tc traffic control object
+ *
+ * @return Kind of traffic control object or NULL if not set.
+ */
+char *rtnl_tc_get_kind(struct rtnl_tc *tc)
+{
+ if (tc->ce_mask & TCA_ATTR_KIND)
+ return tc->tc_kind;
+ else
+ return NULL;
+}
+
+/**
+ * Return value of a statistical counter of a traffic control object
+ * @arg tc traffic control object
+ * @arg id identifier of statistical counter
+ *
+ * @return Value of requested statistic counter or 0.
+ */
+uint64_t rtnl_tc_get_stat(struct rtnl_tc *tc, int id)
+{
+ if (id < 0 || id > RTNL_TC_STATS_MAX)
+ return 0;
+
+ return tc->tc_stats[id];
+}
+
+/** @} */
/**
* @name Utilities
@@ -428,36 +652,94 @@ int rtnl_tc_calc_cell_log(int cell_size)
* @{
*/
+/*
+ * COPYRIGHT NOTE:
+ * align_to_atm() and adjust_size() derived/coped from iproute2 source.
+ */
+
+/*
+ * The align to ATM cells is used for determining the (ATM) SAR
+ * alignment overhead at the ATM layer. (SAR = Segmentation And
+ * Reassembly). This is for example needed when scheduling packet on
+ * an ADSL connection. Note that the extra ATM-AAL overhead is _not_
+ * included in this calculation. This overhead is added in the kernel
+ * before doing the rate table lookup, as this gives better precision
+ * (as the table will always be aligned for 48 bytes).
+ * --Hawk, d.7/11-2004. <hawk@diku.dk>
+ */
+static unsigned int align_to_atm(unsigned int size)
+{
+ int linksize, cells;
+ cells = size / ATM_CELL_PAYLOAD;
+ if ((size % ATM_CELL_PAYLOAD) > 0)
+ cells++;
+
+ linksize = cells * ATM_CELL_SIZE; /* Use full cell size to add ATM tax */
+ return linksize;
+}
+
+static unsigned int adjust_size(unsigned int size, unsigned int mpu,
+ uint32_t linktype)
+{
+ if (size < mpu)
+ size = mpu;
+
+ switch (linktype) {
+ case ARPHRD_ATM:
+ return align_to_atm(size);
+
+ case ARPHRD_ETHER:
+ default:
+ return size;
+ }
+}
+
/**
* Compute a transmission time lookup table
- * @arg dst Destination buffer of RTNL_TC_RTABLE_SIZE uint32_t[].
- * @arg mpu Minimal size of a packet at all times.
- * @arg cell Size of cell, i.e. size of step between entries in bytes.
- * @arg rate Rate in bytes per second.
+ * @arg tc traffic control object
+ * @arg spec Rate specification
+ * @arg dst Destination buffer of RTNL_TC_RTABLE_SIZE uint32_t[].
*
* Computes a table of RTNL_TC_RTABLE_SIZE entries specyfing the
* transmission times for various packet sizes, e.g. the transmission
* time for a packet of size \c pktsize could be looked up:
* @code
- * txtime = table[pktsize >> log2(cell)];
+ * txtime = table[pktsize >> log2(mtu)];
* @endcode
*/
-int rtnl_tc_build_rate_table(uint32_t *dst, uint8_t mpu, int cell, int rate)
+int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *spec,
+ uint32_t *dst)
{
- int i, size, cell_log;
-
- cell_log = rtnl_tc_calc_cell_log(cell);
- if (cell_log < 0)
- return cell_log;
+ uint32_t mtu = rtnl_tc_get_mtu(tc);
+ uint32_t linktype = rtnl_tc_get_linktype(tc);
+ uint8_t cell_log = spec->rs_cell_log;
+ unsigned int size, i;
+
+ spec->rs_mpu = rtnl_tc_get_mpu(tc);
+ spec->rs_overhead = rtnl_tc_get_overhead(tc);
+
+ if (mtu == 0)
+ mtu = 2047;
+
+ if (cell_log == UINT8_MAX) {
+ /*
+ * cell_log not specified, calculate it. It has to specify the
+ * minimum number of rshifts required to break the MTU to below
+ * RTNL_TC_RTABLE_SIZE.
+ */
+ cell_log = 0;
+ while ((mtu >> cell_log) >= RTNL_TC_RTABLE_SIZE)
+ cell_log++;
+ }
for (i = 0; i < RTNL_TC_RTABLE_SIZE; i++) {
- size = (i << cell_log);
- if (size < mpu)
- size = mpu;
-
- dst[i] = rtnl_tc_calc_txtime(size, rate);
+ size = adjust_size((i + 1) << cell_log, spec->rs_mpu, linktype);
+ dst[i] = rtnl_tc_calc_txtime(size, spec->rs_rate);
}
+ spec->rs_cell_align = -1;
+ spec->rs_cell_log = cell_log;
+
return 0;
}