]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
virnetdevbandwidth: Don't generate burst outside of boundaries
authorMichal Privoznik <mprivozn@redhat.com>
Fri, 5 Mar 2021 09:13:36 +0000 (10:13 +0100)
committerMichal Privoznik <mprivozn@redhat.com>
Tue, 9 Mar 2021 08:56:48 +0000 (09:56 +0100)
When generating TC rules for domain's outbound traffic, Libvirt
will use the 'average' as the default for 'burst' - it's been
this way since the feature introduction in v0.9.4-rc1~22. The
reason is that 'average' considers 'burst' for policing. However,
when parsing its command line TC uses an unsigned int (with
overflow detection) to store the 'burst' size. This means, that
the upper limit for the value is UINT_MAX, well UINT_MAX / 1024
because we are putting the value in KiB onto the command line.

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1912210
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Laine Stump <laine@redhat.com>
src/util/virnetdevbandwidth.c
tests/virnetdevbandwidthtest.c

index 612e8f985c02c255120e8772a52c5518c75e7dd8..77a97176b0d9002c44776a4f9a2eca07587e43a1 100644 (file)
@@ -358,7 +358,17 @@ virNetDevBandwidthSet(const char *ifname,
 
     if (rx) {
         average = g_strdup_printf("%llukbps", rx->average);
-        burst = g_strdup_printf("%llukb", rx->burst ? rx->burst : rx->average);
+
+        if (rx->burst) {
+            burst = g_strdup_printf("%llukb", rx->burst);
+        } else {
+            /* Internally, tc uses uint to store burst size (in bytes).
+             * Therefore, the largest value we can set is UINT_MAX bytes.
+             * We're outputting the vale in KiB though. */
+            unsigned long long avg = MIN(rx->average, UINT_MAX / 1024);
+
+            burst = g_strdup_printf("%llukb", avg);
+        }
 
         virCommandFree(cmd);
         cmd = virCommandNew(TC);
index 6d0443876c9e8b381df71c290dcd1f2d11267222..6f3cab27be0ce2301f1bac29486e0441fee2738e 100644 (file)
@@ -156,6 +156,21 @@ mymain(void)
                  TC " filter add dev eth0 parent ffff: protocol all u32 match u32 0 0 "
                  "police rate 5kbps burst 7kb mtu 64kb drop flowid :1\n"));
 
+    DO_TEST_SET(("<bandwidth>"
+                 "  <inbound average='4294967295'/>"
+                 "  <outbound average='4294967295'/>"
+                 "</bandwidth>"),
+                (TC " qdisc del dev eth0 root\n"
+                 TC " qdisc del dev eth0 ingress\n"
+                 TC " qdisc add dev eth0 root handle 1: htb default 1\n"
+                 TC " class add dev eth0 parent 1: classid 1:1 htb rate 4294967295kbps quantum 366503875\n"
+                 TC " qdisc add dev eth0 parent 1:1 handle 2: sfq perturb 10\n"
+                 TC " filter add dev eth0 parent 1:0 protocol all prio 1 handle 1 fw flowid 1\n"
+                 TC " qdisc add dev eth0 ingress\n"
+                 TC " filter add dev eth0 parent ffff: protocol all u32 match "
+                 "u32 0 0 police rate 4294967295kbps burst 4194303kb mtu 64kb "
+                 "drop flowid :1\n"));
+
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }