LVS
lvs-devel
Google
 
Web LinuxVirtualServer.org

[PATCH net-next 5/8] ipvs: use adaptive pause in master thread

To: Simon Horman <horms@xxxxxxxxxxxx>
Subject: [PATCH net-next 5/8] ipvs: use adaptive pause in master thread
Cc: lvs-devel@xxxxxxxxxxxxxxx, Aleksey Chudov <aleksey.chudov@xxxxxxxxx>
From: Julian Anastasov <ja@xxxxxx>
Date: Tue, 6 Mar 2012 00:00:05 +0200
        High rate of sync messages in master can lead to
overflowing the socket buffer and dropping the messages.
Instead of using fixed pause try to adapt to the sync
rate, so that we do not wakeup too often while at the same
time staying below the socket buffer limit.

Signed-off-by: Julian Anastasov <ja@xxxxxx>
Tested-by: Aleksey Chudov <aleksey.chudov@xxxxxxxxx>
---
 net/netfilter/ipvs/ip_vs_sync.c |   60 +++++++++++++++++++++++++++++---------
 1 files changed, 46 insertions(+), 14 deletions(-)

diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index 0e36679..9201c43 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -1392,18 +1392,22 @@ ip_vs_send_async(struct socket *sock, const char 
*buffer, const size_t length)
        return len;
 }
 
-static void
+static int
 ip_vs_send_sync_msg(struct socket *sock, struct ip_vs_sync_mesg *msg)
 {
        int msize;
+       int ret;
 
        msize = msg->size;
 
        /* Put size in network byte order */
        msg->size = htons(msg->size);
 
-       if (ip_vs_send_async(sock, (char *)msg, msize) != msize)
-               pr_err("ip_vs_send_async error\n");
+       ret = ip_vs_send_async(sock, (char *)msg, msize);
+       if (ret >= 0 || ret == -EAGAIN)
+               return ret;
+       pr_err("ip_vs_send_async error %d\n", ret);
+       return 0;
 }
 
 static int
@@ -1428,33 +1432,61 @@ ip_vs_receive(struct socket *sock, char *buffer, const 
size_t buflen)
        return len;
 }
 
+/* Get next buffer to send */
+static inline struct ip_vs_sync_buff *
+next_sync_buff(struct netns_ipvs *ipvs)
+{
+       struct ip_vs_sync_buff *sb;
+
+       sb = sb_dequeue(ipvs);
+       if (sb)
+               return sb;
+       /* Do not delay entries in buffer for more than 2 seconds */
+       return get_curr_sync_buff(ipvs, 2 * HZ);
+}
 
 static int sync_thread_master(void *data)
 {
        struct ip_vs_sync_thread_data *tinfo = data;
        struct netns_ipvs *ipvs = net_ipvs(tinfo->net);
-       struct ip_vs_sync_buff *sb;
+       struct ip_vs_sync_buff *sb = NULL;
+       int pause = HZ / 10;
 
        pr_info("sync thread started: state = MASTER, mcast_ifn = %s, "
                "syncid = %d\n",
                ipvs->master_mcast_ifn, ipvs->master_syncid);
 
        while (!kthread_should_stop()) {
-               while ((sb = sb_dequeue(ipvs))) {
-                       ip_vs_send_sync_msg(tinfo->sock, sb->mesg);
-                       ip_vs_sync_buff_release(sb);
-               }
+               int count = 0;
 
-               /* check if entries stay in ipvs->sync_buff for 2 seconds */
-               sb = get_curr_sync_buff(ipvs, 2 * HZ);
-               if (sb) {
-                       ip_vs_send_sync_msg(tinfo->sock, sb->mesg);
-                       ip_vs_sync_buff_release(sb);
+               for (;;) {
+                       if (!sb) {
+                               sb = next_sync_buff(ipvs);
+                               if (!sb)
+                                       break;
+                       }
+                       if (ip_vs_send_sync_msg(tinfo->sock, sb->mesg) >= 0 ||
+                           pause == 1) {
+                               ip_vs_sync_buff_release(sb);
+                               sb = NULL;
+                               count++;
+                       } else {
+                               pause = max(1, (pause >> 1));
+                               break;
+                       }
                }
 
-               schedule_timeout_interruptible(HZ);
+               /* Max packets to send at once */
+               if (count > 200)
+                       pause = max(1, (pause - HZ / 20));
+               else if (count < 20)
+                       pause = min(HZ / 4, (pause + HZ / 20));
+               schedule_timeout_interruptible(sb ? 1 : pause);
        }
 
+       if (sb)
+               ip_vs_sync_buff_release(sb);
+
        /* clean up the sync_buff queue */
        while ((sb = sb_dequeue(ipvs)))
                ip_vs_sync_buff_release(sb);
-- 
1.7.3.4

--
To unsubscribe from this list: send the line "unsubscribe lvs-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

<Prev in Thread] Current Thread [Next in Thread>