[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v4 1/3] xen netback: add a pseudo pps rate limit



This patch provides a new option to limit VMs maximum packets per second
emission rate.
It follows the same credits logic used for throughput shaping. For the
moment we have considered each "txreq" as a packet.
PPS limits is passed to VIF at connection time via xenstore.
PPS credit uses the same usecond period used by rate shaping check.

known limitations:
- by using the same usecond period, PPS shaping depends on throughput
  shaping.
- it is not always true that a "txreq" correspond to a packet
  (fragmentation cases) but as this shaping is meant to avoid DDOS
  (small packets) such an approximation should not impact the results.
- Some help on burst handling will be appreciated.

Signed-off-by: Ahmed Amamou <ahmed@xxxxxxxxx>
Signed-off-by: William Dauchy <william@xxxxxxxxx>
Signed-off-by: Kamel Haddadou <kamel@xxxxxxxxx>
---
 drivers/net/xen-netback/common.h    |    2 ++
 drivers/net/xen-netback/interface.c |    1 +
 drivers/net/xen-netback/netback.c   |   41 +++++++++++++++++++++++++++++++++++
 drivers/net/xen-netback/xenbus.c    |   35 ++++++++++++++++++++++++------
 4 files changed, 72 insertions(+), 7 deletions(-)

diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
index 8a4d77e..e1a2d4f 100644
--- a/drivers/net/xen-netback/common.h
+++ b/drivers/net/xen-netback/common.h
@@ -89,8 +89,10 @@ struct xenvif {
 
        /* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */
        unsigned long   credit_bytes;
+       unsigned long   credit_packets;
        unsigned long   credit_usec;
        unsigned long   remaining_credit;
+       unsigned long   remaining_packets;
        struct timer_list credit_timeout;
 
        /* Statistics */
diff --git a/drivers/net/xen-netback/interface.c 
b/drivers/net/xen-netback/interface.c
index 087d2db..43c2da7 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -295,6 +295,7 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t 
domid,
        INIT_LIST_HEAD(&vif->notify_list);
 
        vif->credit_bytes = vif->remaining_credit = ~0UL;
+       vif->credit_packets = vif->remaining_packets = ~0UL;
        vif->credit_usec  = 0UL;
        init_timer(&vif->credit_timeout);
        /* Initialize 'expires' now: it's used to track the credit window. */
diff --git a/drivers/net/xen-netback/netback.c 
b/drivers/net/xen-netback/netback.c
index 64828de..6ab3cb2 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -912,10 +912,16 @@ static void tx_add_credit(struct xenvif *vif)
        vif->remaining_credit = min(max_credit, max_burst);
 }
 
+static void tx_add_packets(struct xenvif *vif)
+{
+       vif->remaining_packets = vif->credit_packets;
+}
+
 static void tx_credit_callback(unsigned long data)
 {
        struct xenvif *vif = (struct xenvif *)data;
        tx_add_credit(vif);
+       tx_add_packets(vif);
        xen_netbk_check_rx_xenvif(vif);
 }
 
@@ -1426,6 +1432,34 @@ static bool tx_credit_exceeded(struct xenvif *vif, 
unsigned size)
        return false;
 }
 
+static bool tx_packets_exceeded(struct xenvif *vif)
+{
+       unsigned long now = jiffies;
+       unsigned long next_credit =
+               vif->credit_timeout.expires +
+               msecs_to_jiffies(vif->credit_usec / 1000);
+
+       /* Timer could already be pending in rare cases. */
+       if (timer_pending(&vif->credit_timeout))
+               return true;
+
+       /* Passed the point where we can replenish credit? */
+       if (time_after_eq(now, next_credit)) {
+               vif->credit_timeout.expires = now;
+               tx_add_packets(vif);
+       }
+
+       /* Not enough slot to send right now? Set a callback. */
+       if (vif->remaining_packets < 1) {
+               vif->credit_timeout.data = (unsigned long)vif;
+               vif->credit_timeout.function = tx_credit_callback;
+               mod_timer(&vif->credit_timeout, next_credit);
+               return true;
+       }
+
+       return false;
+}
+
 static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
 {
        struct gnttab_copy *gop = netbk->tx_copy_ops, *request_gop;
@@ -1477,6 +1511,12 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk 
*netbk)
                rmb(); /* Ensure that we see the request before we copy it. */
                memcpy(&txreq, RING_GET_REQUEST(&vif->tx, idx), sizeof(txreq));
 
+               /* pps-based scheduling. */
+               if(vif->remaining_packets < 1 && tx_packets_exceeded(vif)) {
+                       xenvif_put(vif);
+                       continue;
+               }
+
                /* Credit-based scheduling. */
                if (txreq.size > vif->remaining_credit &&
                    tx_credit_exceeded(vif, txreq.size)) {
@@ -1485,6 +1525,7 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk 
*netbk)
                }
 
                vif->remaining_credit -= txreq.size;
+               vif->remaining_packets--;
 
                work_to_do--;
                vif->tx.req_cons = ++idx;
diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
index 1fe48fe3..2b52a09 100644
--- a/drivers/net/xen-netback/xenbus.c
+++ b/drivers/net/xen-netback/xenbus.c
@@ -276,15 +276,18 @@ static void frontend_changed(struct xenbus_device *dev,
 
 
 static void xen_net_read_rate(struct xenbus_device *dev,
-                             unsigned long *bytes, unsigned long *usec)
+                             unsigned long *bytes,
+                             unsigned long *packets,
+                             unsigned long *usec)
 {
        char *s, *e;
-       unsigned long b, u;
-       char *ratestr;
+       unsigned long b, u, pps;
+       char *ratestr, *ppsstr;
 
        /* Default to unlimited bandwidth. */
        *bytes = ~0UL;
        *usec = 0;
+       *packets = ~0UL;
 
        ratestr = xenbus_read(XBT_NIL, dev->nodename, "rate", NULL);
        if (IS_ERR(ratestr))
@@ -293,22 +296,39 @@ static void xen_net_read_rate(struct xenbus_device *dev,
        s = ratestr;
        b = simple_strtoul(s, &e, 10);
        if ((s == e) || (*e != ','))
-               goto fail;
+               goto fail_ratestr;
 
        s = e + 1;
        u = simple_strtoul(s, &e, 10);
        if ((s == e) || (*e != '\0'))
-               goto fail;
+               goto fail_ratestr;
 
        *bytes = b;
        *usec = u;
 
+       ppsstr = xenbus_read(XBT_NIL, dev->nodename, "pps", NULL);
+       if (IS_ERR(ppsstr))
+               return;
+       s = ppsstr;
+       pps = simple_strtoul(s, &e, 10);
+       if ((s == e) || (*e != '\0'))
+               goto fail_ppsstr;
+       *packets = pps;
+
        kfree(ratestr);
+       kfree(ppsstr);
        return;
 
- fail:
+ fail_ppsstr:
+       pr_warn("Failed to parse network PPS limit. PPS unlimited.\n");
+       kfree(ppsstr);
+       goto free_ratestr;
+
+ fail_ratestr:
        pr_warn("Failed to parse network rate limit. Traffic unlimited.\n");
+ free_ratestr:
        kfree(ratestr);
+       return;
 }
 
 static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
@@ -379,8 +399,9 @@ static void connect(struct backend_info *be)
        }
 
        xen_net_read_rate(dev, &be->vif->credit_bytes,
-                         &be->vif->credit_usec);
+                         &be->vif->credit_packets, &be->vif->credit_usec);
        be->vif->remaining_credit = be->vif->credit_bytes;
+       be->vif->remaining_packets = be->vif->credit_packets;
 
        unregister_hotplug_status_watch(be);
        err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch,
-- 
1.7.9.5

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.