summaryrefslogtreecommitdiff
path: root/lib/route/qdisc/htb.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/route/qdisc/htb.c')
-rw-r--r--lib/route/qdisc/htb.c135
1 files changed, 113 insertions, 22 deletions
diff --git a/lib/route/qdisc/htb.c b/lib/route/qdisc/htb.c
index c1e32307..e426a149 100644
--- a/lib/route/qdisc/htb.c
+++ b/lib/route/qdisc/htb.c
@@ -45,6 +45,8 @@
static struct nla_policy htb_policy[TCA_HTB_MAX+1] = {
[TCA_HTB_INIT] = { .minlen = sizeof(struct tc_htb_glob) },
[TCA_HTB_PARMS] = { .minlen = sizeof(struct tc_htb_opt) },
+ [TCA_HTB_RATE64] = { .minlen = sizeof(uint64_t) },
+ [TCA_HTB_CEIL64] = { .minlen = sizeof(uint64_t) },
};
static int htb_qdisc_msg_parser(struct rtnl_tc *tc, void *data)
@@ -86,10 +88,16 @@ static int htb_class_msg_parser(struct rtnl_tc *tc, void *data)
htb->ch_prio = opts.prio;
rtnl_copy_ratespec(&htb->ch_rate, &opts.rate);
rtnl_copy_ratespec(&htb->ch_ceil, &opts.ceil);
- htb->ch_rbuffer = rtnl_tc_calc_bufsize(nl_ticks2us(opts.buffer),
- opts.rate.rate);
- htb->ch_cbuffer = rtnl_tc_calc_bufsize(nl_ticks2us(opts.cbuffer),
- opts.ceil.rate);
+
+ if (tb[TCA_HTB_RATE64])
+ nla_memcpy(&htb->ch_rate.rs_rate64, tb[TCA_HTB_RATE64], sizeof(uint64_t));
+ if (tb[TCA_HTB_CEIL64])
+ nla_memcpy(&htb->ch_ceil.rs_rate64, tb[TCA_HTB_CEIL64], sizeof(uint64_t));
+
+ htb->ch_rbuffer = rtnl_tc_calc_bufsize64(nl_ticks2us(opts.buffer),
+ htb->ch_rate.rs_rate64);
+ htb->ch_cbuffer = rtnl_tc_calc_bufsize64(nl_ticks2us(opts.cbuffer),
+ htb->ch_ceil.rs_rate64);
htb->ch_quantum = opts.quantum;
htb->ch_level = opts.level;
@@ -135,8 +143,8 @@ static void htb_class_dump_line(struct rtnl_tc *tc, void *data,
double r, rbit;
char *ru, *rubit;
- r = nl_cancel_down_bytes(htb->ch_rate.rs_rate, &ru);
- rbit = nl_cancel_down_bits(htb->ch_rate.rs_rate*8, &rubit);
+ r = nl_cancel_down_bytes(htb->ch_rate.rs_rate64, &ru);
+ rbit = nl_cancel_down_bits(htb->ch_rate.rs_rate64*8, &rubit);
nl_dump(p, " rate %.2f%s/s (%.0f%s) log %u",
r, ru, rbit, rubit, 1<<htb->ch_rate.rs_cell_log);
@@ -156,8 +164,8 @@ static void htb_class_dump_details(struct rtnl_tc *tc, void *data,
double r, rbit;
char *ru, *rubit;
- r = nl_cancel_down_bytes(htb->ch_ceil.rs_rate, &ru);
- rbit = nl_cancel_down_bits(htb->ch_ceil.rs_rate*8, &rubit);
+ r = nl_cancel_down_bytes(htb->ch_ceil.rs_rate64, &ru);
+ rbit = nl_cancel_down_bits(htb->ch_ceil.rs_rate64*8, &rubit);
nl_dump(p, " ceil %.2f%s/s (%.0f%s) log %u",
r, ru, rbit, rubit, 1<<htb->ch_ceil.rs_cell_log);
@@ -213,6 +221,8 @@ static int htb_class_msg_fill(struct rtnl_tc *tc, void *data,
uint32_t mtu, rtable[RTNL_TC_RTABLE_SIZE], ctable[RTNL_TC_RTABLE_SIZE];
struct tc_htb_opt opts;
int buffer, cbuffer;
+ uint64_t rate64;
+ uint64_t ceil64;
if (!htb || !(htb->ch_mask & SCH_HTB_HAS_RATE))
BUG();
@@ -227,36 +237,43 @@ static int htb_class_msg_fill(struct rtnl_tc *tc, void *data,
rtnl_tc_build_rate_table(tc, &htb->ch_rate, rtable);
rtnl_rcopy_ratespec(&opts.rate, &htb->ch_rate);
+ rate64 = htb->ch_rate.rs_rate64;
if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
rtnl_tc_build_rate_table(tc, &htb->ch_ceil, ctable);
rtnl_rcopy_ratespec(&opts.ceil, &htb->ch_ceil);
+ ceil64 = htb->ch_ceil.rs_rate64;
} else {
/*
* If not set, configured rate is used as ceil, which implies
* no borrowing.
*/
memcpy(&opts.ceil, &opts.rate, sizeof(struct tc_ratespec));
+ ceil64 = rate64;
}
if (htb->ch_mask & SCH_HTB_HAS_RBUFFER)
buffer = htb->ch_rbuffer;
else
- buffer = opts.rate.rate / nl_get_psched_hz() + mtu; /* XXX */
+ buffer = rate64 / nl_get_psched_hz() + mtu; /* XXX */
- opts.buffer = nl_us2ticks(rtnl_tc_calc_txtime(buffer, opts.rate.rate));
+ opts.buffer = nl_us2ticks(rtnl_tc_calc_txtime64(buffer, rate64));
if (htb->ch_mask & SCH_HTB_HAS_CBUFFER)
cbuffer = htb->ch_cbuffer;
else
- cbuffer = opts.ceil.rate / nl_get_psched_hz() + mtu; /* XXX */
+ cbuffer = ceil64 / nl_get_psched_hz() + mtu; /* XXX */
- opts.cbuffer = nl_us2ticks(rtnl_tc_calc_txtime(cbuffer, opts.ceil.rate));
+ opts.cbuffer = nl_us2ticks(rtnl_tc_calc_txtime64(cbuffer, ceil64));
if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
opts.quantum = htb->ch_quantum;
NLA_PUT(msg, TCA_HTB_PARMS, sizeof(opts), &opts);
+ if (rate64 > 0xFFFFFFFFull)
+ NLA_PUT(msg, TCA_HTB_RATE64, sizeof(uint64_t), &rate64);
+ if (ceil64 > 0xFFFFFFFFull)
+ NLA_PUT(msg, TCA_HTB_CEIL64, sizeof(uint64_t), &ceil64);
NLA_PUT(msg, TCA_HTB_RTAB, sizeof(rtable), &rtable);
NLA_PUT(msg, TCA_HTB_CTAB, sizeof(ctable), &ctable);
@@ -383,16 +400,41 @@ int rtnl_htb_set_prio(struct rtnl_class *class, uint32_t prio)
* Return rate of HTB class
* @arg class htb class object
*
- * @return Rate in bytes/s or 0 if unspecified.
+ * @return Rate in bytes/s or 0 if unspecified. If the value
+ * cannot be represented as 32 bit integer, (1<<32) is returned.
+ * Use rtnl_htb_get_rate64() instead.
*/
uint32_t rtnl_htb_get_rate(struct rtnl_class *class)
{
struct rtnl_htb_class *htb;
- if ((htb = htb_class_data(class, NULL)) &&
- (htb->ch_mask & SCH_HTB_HAS_RATE))
- return htb->ch_rate.rs_rate;
+ if ( !(htb = htb_class_data(class, NULL))
+ || !(htb->ch_mask & SCH_HTB_HAS_RATE))
+ return 0;
+
+ if (htb->ch_rate.rs_rate64 > 0xFFFFFFFFull)
+ return 0xFFFFFFFFull;
+ return htb->ch_rate.rs_rate64;
+}
+
+/**
+ * Return rate of HTB class
+ * @arg class htb class object
+ * @arg out_rate64 on success, the set rate.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_htb_get_rate64(struct rtnl_class *class, uint64_t *out_rate64)
+{
+ struct rtnl_htb_class *htb;
+
+ if (!(htb = htb_class_data(class, NULL)))
+ return -NLE_INVAL;
+ if (!(htb->ch_mask & SCH_HTB_HAS_RATE))
+ return -NLE_NOATTR;
+
+ *out_rate64 = htb->ch_rate.rs_rate64;
return 0;
}
@@ -405,6 +447,18 @@ uint32_t rtnl_htb_get_rate(struct rtnl_class *class)
*/
int rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate)
{
+ return rtnl_htb_set_rate64(class, rate);
+}
+
+/**
+ * Set rate of HTB class
+ * @arg class htb class object
+ * @arg rate new rate in bytes per second
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_htb_set_rate64(struct rtnl_class *class, uint64_t rate)
+{
struct rtnl_htb_class *htb;
int err;
@@ -412,7 +466,7 @@ int rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate)
return err;
htb->ch_rate.rs_cell_log = UINT8_MAX; /* use default value */
- htb->ch_rate.rs_rate = rate;
+ htb->ch_rate.rs_rate64 = rate;
htb->ch_mask |= SCH_HTB_HAS_RATE;
return 0;
@@ -422,16 +476,41 @@ int rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate)
* Return ceil rate of HTB class
* @arg class htb class object
*
- * @return Ceil rate in bytes/s or 0 if unspecified
+ * @return Ceil rate in bytes/s or 0 if unspecified. If the value
+ * cannot be represented as 32 bit integer, (1<<32) is returned.
+ * Use rtnl_htb_get_ceil64() instead.
*/
uint32_t rtnl_htb_get_ceil(struct rtnl_class *class)
{
struct rtnl_htb_class *htb;
- if ((htb = htb_class_data(class, NULL)) &&
- (htb->ch_mask & SCH_HTB_HAS_CEIL))
- return htb->ch_ceil.rs_rate;
+ if ( !(htb = htb_class_data(class, NULL))
+ || !(htb->ch_mask & SCH_HTB_HAS_CEIL))
+ return 0;
+
+ if (htb->ch_ceil.rs_rate64 > 0xFFFFFFFFull)
+ return 0xFFFFFFFFull;
+
+ return htb->ch_ceil.rs_rate64;
+}
+
+/**
+ * Return ceil rate of HTB class
+ * @arg class htb class object
+ * @arg out_ceil64 on success, the set ceil value.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_htb_get_ceil64(struct rtnl_class *class, uint64_t *out_ceil64)
+{
+ struct rtnl_htb_class *htb;
+
+ if (!(htb = htb_class_data(class, NULL)))
+ return -NLE_INVAL;
+ if (!(htb->ch_mask & SCH_HTB_HAS_CEIL))
+ return -NLE_NOATTR;
+ *out_ceil64 = htb->ch_ceil.rs_rate64;
return 0;
}
@@ -444,6 +523,18 @@ uint32_t rtnl_htb_get_ceil(struct rtnl_class *class)
*/
int rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil)
{
+ return rtnl_htb_set_ceil64(class, ceil);
+}
+
+/**
+ * Set ceil rate of HTB class
+ * @arg class htb class object
+ * @arg ceil64 new ceil rate number of bytes per second
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_htb_set_ceil64(struct rtnl_class *class, uint64_t ceil64)
+{
struct rtnl_htb_class *htb;
int err;
@@ -451,7 +542,7 @@ int rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil)
return err;
htb->ch_ceil.rs_cell_log = UINT8_MAX; /* use default value */
- htb->ch_ceil.rs_rate = ceil;
+ htb->ch_ceil.rs_rate64 = ceil64;
htb->ch_mask |= SCH_HTB_HAS_CEIL;
return 0;