diff mbox series

[ovs-dev,ovs,1/2] dpif-netdev: Fix the meter buckets overflow.

Message ID 20210112113308.48307-1-xiangxia.m.yue@gmail.com
State Changes Requested
Headers show
Series [ovs-dev,ovs,1/2] dpif-netdev: Fix the meter buckets overflow. | expand

Commit Message

Tonghao Zhang Jan. 12, 2021, 11:33 a.m. UTC
From: Tonghao Zhang <xiangxia.m.yue@gmail.com>

When setting the meter rate to 4.3+Gbps, there is an overflow, the
meters don't work as expected.

$ ovs-ofctl -O OpenFlow13 add-meter br-int "meter=1 kbps stats bands=type=drop rate=4294968"

Before the patch, the buckets of meters was stored in its burst_size
of ofputil_meter_band. It was overflow when we set the rate to 4294968.
This patch don't change the public API and structure. This patch remove
the "up" from dp_meter_band, and introduce the type, rate to datapath's
meter bands. Then datapath don't depend upper layer.

Signed-off-by: Tonghao Zhang <xiangxia.m.yue@gmail.com>
---
 lib/dpif-netdev.c | 42 ++++++++++++++++++++----------------------
 1 file changed, 20 insertions(+), 22 deletions(-)

Comments

0-day Robot Jan. 12, 2021, 12:12 p.m. UTC | #1
Bleep bloop.  Greetings Tonghao Zhang, I am a robot and I have tried out your patch.
Thanks for your contribution.

I encountered some error that I wasn't expecting.  See the details below.


checkpatch:
ERROR: Inappropriate spacing around cast
#52 FILE: lib/dpif-netdev.c:6166:
        band->bucket += (uint64_t)delta_t * band->rate;

Lines checked: 110, Warnings: 0, Errors: 1


Please check this out.  If you feel there has been an error, please email aconole@redhat.com

Thanks,
0-day Robot
Ilya Maximets Jan. 13, 2021, 11:30 p.m. UTC | #2
On 1/12/21 12:33 PM, xiangxia.m.yue@gmail.com wrote:
> From: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> 
> When setting the meter rate to 4.3+Gbps, there is an overflow, the
> meters don't work as expected.
> 
> $ ovs-ofctl -O OpenFlow13 add-meter br-int "meter=1 kbps stats bands=type=drop rate=4294968"
> 
> Before the patch, the buckets of meters was stored in its burst_size
> of ofputil_meter_band. It was overflow when we set the rate to 4294968.
> This patch don't change the public API and structure. This patch remove
> the "up" from dp_meter_band, and introduce the type, rate to datapath's
> meter bands. Then datapath don't depend upper layer.
> 
> Signed-off-by: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> ---

Hi.  Unit tests are failing with these patches applied:

990: dpif-netdev - meters                            FAILED (dpif-netdev.at:319)

Please, check them.

Best regards, Ilya Maximets.
Tonghao Zhang Jan. 14, 2021, 4:06 a.m. UTC | #3
On Thu, Jan 14, 2021 at 7:30 AM Ilya Maximets <i.maximets@ovn.org> wrote:
>
> On 1/12/21 12:33 PM, xiangxia.m.yue@gmail.com wrote:
> > From: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> >
> > When setting the meter rate to 4.3+Gbps, there is an overflow, the
> > meters don't work as expected.
> >
> > $ ovs-ofctl -O OpenFlow13 add-meter br-int "meter=1 kbps stats bands=type=drop rate=4294968"
> >
> > Before the patch, the buckets of meters was stored in its burst_size
> > of ofputil_meter_band. It was overflow when we set the rate to 4294968.
> > This patch don't change the public API and structure. This patch remove
> > the "up" from dp_meter_band, and introduce the type, rate to datapath's
> > meter bands. Then datapath don't depend upper layer.
> >
> > Signed-off-by: Tonghao Zhang <xiangxia.m.yue@gmail.com>
> > ---
>
> Hi.  Unit tests are failing with these patches applied:
>
> 990: dpif-netdev - meters                            FAILED (dpif-netdev.at:319)
Hi Ilya
Before the patch, dpif-netdev meter uses the burst_size*1000 as the
real buckets, if users don't specify the burst_size, buckets = rate
*1000 as buckets.
I think that  is not the proper way. we should
the max buckets:
buckets = (burst_size + rate) * 1000.
and when update buckets:
band->bucket += (uint64_t)delta_t * band->rate;

The test suite will be change:
diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at
index 2862a3c9b..9d7c092fc 100644
--- a/tests/dpif-netdev.at
+++ b/tests/dpif-netdev.at
@@ -282,7 +282,7 @@ OVS_VSWITCHD_START(
 AT_CHECK([ovs-appctl vlog/set dpif:dbg dpif_netdev:dbg])

 AT_CHECK([ovs-ofctl -O OpenFlow13 add-meter br0 'meter=1 pktps burst
stats bands=type=drop rate=1 burst_size=1'])
-AT_CHECK([ovs-ofctl -O OpenFlow13 add-meter br0 'meter=2 kbps burst
stats bands=type=drop rate=1 burst_size=2'])
+AT_CHECK([ovs-ofctl -O OpenFlow13 add-meter br0 'meter=2 kbps burst
stats bands=type=drop rate=1 burst_size=1'])
 AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 'in_port=1 action=meter:1,7'])
 AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 'in_port=7 action=meter:2,1'])
 AT_CHECK([ovs-ofctl add-flow br1 'in_port=2 action=8'])
@@ -295,7 +295,7 @@ meter=1 pktps burst stats bands=
 type=drop rate=1 burst_size=1

 meter=2 kbps burst stats bands=
-type=drop rate=1 burst_size=2
+type=drop rate=1 burst_size=1
 ])

 ovs-appctl time/warp 5000
@@ -312,14 +312,14 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p8
'in_port(8),packet_type(ns=0,id=0),
 sleep 1  # wait for forwarders process packets

 # Meter 1 is measuring packets, allowing one packet per second with
-# bursts of one packet, so 4 out of 5 packets should hit the drop
+# bursts of one packet, so 3 out of 5 packets should hit the drop
 # band.
-# Meter 2 is measuring kbps, with burst size 2 (== 2000 bits). 4 packets
-# (240 bytes == 1920 bits) pass, but the last packet should hit the drop band.
+# Meter 2 is measuring kbps, with burst size 1 (= 2000bits). 4 packets
+# (120 bytes == 1920 bits) pass, but the last packet should hit the drop band.
 AT_CHECK([ovs-ofctl -O OpenFlow13 meter-stats br0 | strip_timers], [0], [dnl
 OFPST_METER reply (OF1.3) (xid=0x2):
 meter:1 flow_count:1 packet_in_count:5 byte_in_count:300 duration:0.0s bands:
-0: packet_count:4 byte_count:240
+0: packet_count:3 byte_count:180

 meter:2 flow_count:1 packet_in_count:5 byte_in_count:300 duration:0.0s bands:
 0: packet_count:1 byte_count:60
@@ -343,13 +343,13 @@ sleep 1  # wait for forwarders process packets
 # Meter 1 is measuring packets, allowing one packet per second with
 # bursts of one packet, so all 5 of the new packets should hit the drop
 # band.
-# Meter 2 is measuring kbps, with burst size 2 (== 2000 bits). After 500ms
+# Meter 2 is measuring kbps, with burst size 1 (== 2000 bits). After 500ms
 # there should be space for 80 + 500 bits, so one new 60 byte (480 bit) packet
 # should pass, remaining 4 should hit the drop band.
 AT_CHECK([ovs-ofctl -O OpenFlow13 meter-stats br0 | strip_timers], [0], [dnl
 OFPST_METER reply (OF1.3) (xid=0x2):
 meter:1 flow_count:1 packet_in_count:10 byte_in_count:600 duration:0.0s bands:
-0: packet_count:9 byte_count:540
+0: packet_count:8 byte_count:480

 meter:2 flow_count:1 packet_in_count:10 byte_in_count:600 duration:0.0s bands:
 0: packet_count:5 byte_count:300

> Please, check them.
>
> Best regards, Ilya Maximets.
diff mbox series

Patch

diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 300861ca5..3ad737248 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -279,8 +279,10 @@  static bool dpcls_lookup(struct dpcls *cls,
     ( 1 << OFPMBT13_DROP )
 
 struct dp_meter_band {
-    struct ofputil_meter_band up; /* type, prec_level, pad, rate, burst_size */
-    uint32_t bucket; /* In 1/1000 packets (for PKTPS), or in bits (for KBPS) */
+    uint16_t type;
+    uint32_t rate;
+    uint32_t burst_size;
+    uint64_t bucket; /* In 1/1000 packets (for PKTPS), or in bits (for KBPS) */
     uint64_t packet_count;
     uint64_t byte_count;
 };
@@ -6156,12 +6158,14 @@  dp_netdev_run_meter(struct dp_netdev *dp, struct dp_packet_batch *packets_,
     /* Update all bands and find the one hit with the highest rate for each
      * packet (if any). */
     for (int m = 0; m < meter->n_bands; ++m) {
-        band = &meter->bands[m];
+        uint64_t max_bucket_size;
 
+        band = &meter->bands[m];
         /* Update band's bucket. */
-        band->bucket += delta_t * band->up.rate;
-        if (band->bucket > band->up.burst_size) {
-            band->bucket = band->up.burst_size;
+        max_bucket_size = band->rate * 1000ULL;
+        band->bucket += (uint64_t)delta_t * band->rate;
+        if (band->bucket > max_bucket_size) {
+            band->bucket = max_bucket_size;
         }
 
         /* Drain the bucket for all the packets, if possible. */
@@ -6179,8 +6183,8 @@  dp_netdev_run_meter(struct dp_netdev *dp, struct dp_packet_batch *packets_,
                  * (Only one band will be fired by a packet, and that
                  * can be different for each packet.) */
                 for (int i = band_exceeded_pkt; i < cnt; i++) {
-                    if (band->up.rate > exceeded_rate[i]) {
-                        exceeded_rate[i] = band->up.rate;
+                    if (band->rate > exceeded_rate[i]) {
+                        exceeded_rate[i] = band->rate;
                         exceeded_band[i] = m;
                     }
                 }
@@ -6199,8 +6203,8 @@  dp_netdev_run_meter(struct dp_netdev *dp, struct dp_packet_batch *packets_,
                         /* Update the exceeding band for the exceeding packet.
                          * (Only one band will be fired by a packet, and that
                          * can be different for each packet.) */
-                        if (band->up.rate > exceeded_rate[i]) {
-                            exceeded_rate[i] = band->up.rate;
+                        if (band->rate > exceeded_rate[i]) {
+                            exceeded_rate[i] = band->rate;
                             exceeded_band[i] = m;
                         }
                     }
@@ -6277,21 +6281,15 @@  dpif_netdev_meter_set(struct dpif *dpif, ofproto_meter_id meter_id,
     for (i = 0; i < config->n_bands; ++i) {
         uint32_t band_max_delta_t;
 
-        /* Set burst size to a workable value if none specified. */
-        if (config->bands[i].burst_size == 0) {
-            config->bands[i].burst_size = config->bands[i].rate;
-        }
-
-        meter->bands[i].up = config->bands[i];
-        /* Convert burst size to the bucket units: */
-        /* pkts => 1/1000 packets, kilobits => bits. */
-        meter->bands[i].up.burst_size *= 1000;
-        /* Initialize bucket to empty. */
-        meter->bands[i].bucket = 0;
+        meter->bands[i].type = config->bands[i].type;
+        meter->bands[i].rate = config->bands[i].rate;
+        meter->bands[i].burst_size = config->bands[i].burst_size;
+        /* Start with a full bucket. */
+        meter->bands[i].bucket = meter->bands[i].rate * 1000ULL;
 
         /* Figure out max delta_t that is enough to fill any bucket. */
         band_max_delta_t
-            = meter->bands[i].up.burst_size / meter->bands[i].up.rate;
+            = meter->bands[i].bucket / meter->bands[i].rate;
         if (band_max_delta_t > meter->max_delta_t) {
             meter->max_delta_t = band_max_delta_t;
         }