]> git.ipfire.org Git - thirdparty/libnl.git/commitdiff
correct HTB rtable/HZ calculations
authorAndrew Collins <bsderandrew@gmail.com>
Sat, 26 May 2012 00:08:06 +0000 (18:08 -0600)
committerThomas Graf <tgraf@redhat.com>
Tue, 29 May 2012 09:42:48 +0000 (11:42 +0200)
The HTB implementation in libnl uses units of microseconds in a number
of places where it seems TC is expecting time in units of ticks, which
causes actual rates much higher than requested.  Additionally, libnl
uses USER_HZ for calculating buffer and cbuffer sizes, which can
result in much larger buffers than necessary on systems with high
resolution timers.

Note that the TBF qdisc uses microseconds incorrectly in two spots as
well, I fixed this but did not test.

include/netlink/utils.h
lib/route/qdisc/htb.c
lib/route/qdisc/tbf.c
lib/route/tc.c
lib/utils.c

index 4d7b969d44946b61edd9f32d53d165e714453af9..502341a872d2fd5fa11df14a5396381c8c6514fb 100644 (file)
@@ -56,6 +56,7 @@ extern long   nl_prob2int(const char *);
 
 /* time translations */
 extern int     nl_get_user_hz(void);
+extern int     nl_get_psched_hz(void);
 extern uint32_t        nl_us2ticks(uint32_t);
 extern uint32_t        nl_ticks2us(uint32_t);
 extern int     nl_str2msec(const char *, uint64_t *);
index f1d0e758fab67ac9ecc52483ccdd6054c0b74b5c..42985808bc177f56be5c92da69dbe9139128c4f8 100644 (file)
@@ -86,9 +86,9 @@ 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(opts.buffer,
+               htb->ch_rbuffer = rtnl_tc_calc_bufsize(nl_ticks2us(opts.buffer),
                                                       opts.rate.rate);
-               htb->ch_cbuffer = rtnl_tc_calc_bufsize(opts.cbuffer,
+               htb->ch_cbuffer = rtnl_tc_calc_bufsize(nl_ticks2us(opts.cbuffer),
                                                       opts.ceil.rate);
                htb->ch_quantum = opts.quantum;
                htb->ch_level = opts.level;
@@ -242,16 +242,16 @@ static int htb_class_msg_fill(struct rtnl_tc *tc, void *data,
        if (htb->ch_mask & SCH_HTB_HAS_RBUFFER)
                buffer = htb->ch_rbuffer;
        else
-               buffer = opts.rate.rate / nl_get_user_hz() + mtu; /* XXX */
+               buffer = opts.rate.rate / nl_get_psched_hz() + mtu; /* XXX */
 
-       opts.buffer = rtnl_tc_calc_txtime(buffer, opts.rate.rate);
+       opts.buffer = nl_us2ticks(rtnl_tc_calc_txtime(buffer, opts.rate.rate));
 
        if (htb->ch_mask & SCH_HTB_HAS_CBUFFER)
                cbuffer = htb->ch_cbuffer;
        else
-               cbuffer = opts.ceil.rate / nl_get_user_hz() + mtu; /* XXX */
+               cbuffer = opts.ceil.rate / nl_get_psched_hz() + mtu; /* XXX */
 
-       opts.cbuffer = rtnl_tc_calc_txtime(cbuffer, opts.ceil.rate);
+       opts.cbuffer = nl_us2ticks(rtnl_tc_calc_txtime(cbuffer, opts.ceil.rate));
 
        if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
                opts.quantum = htb->ch_quantum;
index 8a6c4006220e31ef667a61706e256811f45e2a85..81bd84c173734cc17c31979e026e5345b1fbb801 100644 (file)
@@ -290,7 +290,7 @@ void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket,
        tbf->qt_rate.rs_rate = rate;
        tbf->qt_rate_bucket = bucket;
        tbf->qt_rate.rs_cell_log = cell_log;
-       tbf->qt_rate_txtime = rtnl_tc_calc_txtime(bucket, rate);
+       tbf->qt_rate_txtime = nl_us2ticks(rtnl_tc_calc_txtime(bucket, rate));
        tbf->qt_mask |= TBF_ATTR_RATE;
 }
 
@@ -372,7 +372,7 @@ int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket,
        tbf->qt_peakrate.rs_rate = rate;
        tbf->qt_peakrate_bucket = bucket;
        tbf->qt_peakrate.rs_cell_log = cell_log;
-       tbf->qt_peakrate_txtime = rtnl_tc_calc_txtime(bucket, rate);
+       tbf->qt_peakrate_txtime = nl_us2ticks(rtnl_tc_calc_txtime(bucket, rate));
        
        tbf->qt_mask |= TBF_ATTR_PEAKRATE;
 
index 6826a05ef874c7e059bcef2c227bea314c39c4a6..6c72c158f40f65327f20123de3370134e39f266d 100644 (file)
@@ -710,7 +710,7 @@ int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *spec,
 
        for (i = 0; i < RTNL_TC_RTABLE_SIZE; i++) {
                size = adjust_size((i + 1) << cell_log, spec->rs_mpu, linktype);
-               dst[i] = rtnl_tc_calc_txtime(size, spec->rs_rate);
+               dst[i] = nl_us2ticks(rtnl_tc_calc_txtime(size, spec->rs_rate));
        }
 
        spec->rs_cell_align = -1;
index 36b6292fd47ff9c3b04a90bcb889289fcc95cf3a..efb2cf46c36a12feff9437c0b5cfb151eb76a995 100644 (file)
@@ -359,12 +359,13 @@ long nl_prob2int(const char *str)
  * @{
  */
 
-#ifdef USER_HZ
-static uint32_t user_hz = USER_HZ;
-#else
-static uint32_t user_hz = 100;
+#ifndef USER_HZ
+#define USER_HZ 100
 #endif
 
+static uint32_t user_hz = USER_HZ;
+static uint32_t psched_hz = USER_HZ;
+
 static double ticks_per_usec = 1.0f;
 
 /* Retrieves the configured HZ and ticks/us value in the kernel.
@@ -394,6 +395,8 @@ static void __init get_psched_settings(void)
        if (!got_hz)
                user_hz = sysconf(_SC_CLK_TCK);
 
+       psched_hz = user_hz;
+
        if (getenv("TICKS_PER_USEC")) {
                double t = strtod(getenv("TICKS_PER_USEC"), NULL);
                ticks_per_usec = t;
@@ -408,14 +411,16 @@ static void __init get_psched_settings(void)
                        strncpy(name, "/proc/net/psched", sizeof(name) - 1);
                
                if ((fd = fopen(name, "r"))) {
-                       uint32_t ns_per_usec, ns_per_tick;
-                       /* the file contains 4 hexadecimals, but we just use
-                          the first two of them */
-                       fscanf(fd, "%08x %08x", &ns_per_usec, &ns_per_tick);
+                       uint32_t ns_per_usec, ns_per_tick, nom, denom;
+
+                       fscanf(fd, "%08x %08x %08x %08x",
+                              &ns_per_usec, &ns_per_tick, &nom, &denom);
 
                        ticks_per_usec = (double) ns_per_usec / 
                                         (double) ns_per_tick;
 
+                       if (nom == 1000000)
+                               psched_hz = denom;
 
                        fclose(fd);
                }
@@ -431,6 +436,13 @@ int nl_get_user_hz(void)
        return user_hz;
 }
 
+/**
+ * Return the value of packet scheduler HZ
+ */
+int nl_get_psched_hz(void)
+{
+       return psched_hz;
+}
 
 /**
  * Convert micro seconds to ticks