From mboxrd@z Thu Jan 1 00:00:00 1970 From: William Dauchy Subject: [PATCH v4 1/3] xen netback: add a pseudo pps rate limit Date: Mon, 5 Aug 2013 17:13:08 +0200 Message-ID: <1375715590-1539-2-git-send-email-william@gandi.net> References: <1375715590-1539-1-git-send-email-william@gandi.net> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1375715590-1539-1-git-send-email-william@gandi.net> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: Ian Campbell Cc: Ahmed Amamou , Kamel Haddadou , Wei Liu , William Dauchy , xen-devel List-Id: xen-devel@lists.xenproject.org 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 Signed-off-by: William Dauchy Signed-off-by: Kamel Haddadou --- 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