]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
* added the 'source' load-balancing algorithm which uses the source IP(v4|v6)
authorwilly tarreau <willy@wtap.(none)>
Fri, 24 Mar 2006 20:03:20 +0000 (21:03 +0100)
committerwilly tarreau <willy@wtap.(none)>
Sat, 25 Mar 2006 19:33:17 +0000 (20:33 +0100)
haproxy.c
tests/active-sh.cfg [new file with mode: 0644]
tests/backup-all-sh.cfg [new file with mode: 0644]
tests/backup-second-sh.cfg [new file with mode: 0644]

index 0a935c0a10833f403224ee2a28b0a9d182b3f1b3..113d0b5f2de9957ac0af6eca1a5cc21109cf89bc 100644 (file)
--- a/haproxy.c
+++ b/haproxy.c
@@ -332,7 +332,6 @@ int strlcpy2(char *dst, const char *src, int size) {
 #define PR_O_COOK_PFX  0x00000020      /* rewrite all cookies by prefixing the right serverid */
 #define PR_O_COOK_ANY  (PR_O_COOK_RW | PR_O_COOK_IND | PR_O_COOK_INS | PR_O_COOK_PFX)
 #define PR_O_BALANCE_RR        0x00000040      /* balance in round-robin mode */
-#define PR_O_BALANCE   (PR_O_BALANCE_RR)
 #define        PR_O_KEEPALIVE  0x00000080      /* follow keep-alive sessions */
 #define        PR_O_FWDFOR     0x00000100      /* insert x-forwarded-for with client address */
 #define        PR_O_BIND_SRC   0x00000200      /* bind to a specific source address when connect()ing */
@@ -348,6 +347,8 @@ int strlcpy2(char *dst, const char *src, int size) {
 #define PR_O_TCP_SRV_KA        0x00080000      /* enable TCP keep-alive on server-side sessions */
 #define PR_O_USE_ALL_BK        0x00100000      /* load-balance between backup servers */
 #define PR_O_FORCE_CLO 0x00200000      /* enforce the connection close immediately after server response */
+#define PR_O_BALANCE_SH        0x00400000      /* balance on source IP hash */
+#define PR_O_BALANCE   (PR_O_BALANCE_RR | PR_O_BALANCE_SH)
 
 /* various session flags */
 #define SN_DIRECT      0x00000001      /* connection made on the server matching the client cookie */
@@ -1861,6 +1862,69 @@ static inline struct server *get_server_rr(struct proxy *px) {
 }
 
 
+/*
+ * This function tries to find a running server for the proxy <px> following
+ * the source hash method. Depending on the number of active/backup servers,
+ * it will either look for active servers, or for backup servers.
+ * If any server is found, it will be returned. If no valid server is found,
+ * NULL is returned.
+ */
+static inline struct server *get_server_sh(struct proxy *px, char *addr, int len) {
+    struct server *srv;
+
+    if (px->srv_act) {
+        unsigned int h, l;
+
+        l = h = 0;
+        if (px->srv_act > 1) {
+            while ((l + sizeof (int)) <= len) {
+                h ^= ntohl(*(unsigned int *)(&addr[l]));
+                l += sizeof (int);
+            }
+            h %= px->srv_act;
+        }
+
+        for (srv = px->srv; srv; srv = srv->next) {
+           if ((srv->state & (SRV_RUNNING | SRV_BACKUP)) == SRV_RUNNING) {
+                if (!h)
+                    return srv;
+                h--;
+            }
+       }
+        /* note that theorically we should not get there */
+    }
+
+    if (px->srv_bck) {
+        unsigned int h, l;
+
+       /* By default, we look for the first backup server if all others are
+        * DOWN. But in some cases, it may be desirable to load-balance across
+        * all backup servers.
+        */
+        l = h = 0;
+        if (px->srv_bck > 1 && px->options & PR_O_USE_ALL_BK) {
+            while ((l + sizeof (int)) <= len) {
+                h ^= ntohl(*(unsigned int *)(&addr[l]));
+                l += sizeof (int);
+            }
+            h %= px->srv_bck;
+        }
+
+        for (srv = px->srv; srv; srv = srv->next) {
+           if (srv->state & SRV_RUNNING) {
+                if (!h)
+                    return srv;
+                h--;
+            }
+       }
+        /* note that theorically we should not get there */
+    }
+
+    /* if we get there, it means there are no available servers at all */
+    return NULL;
+}
+
+
 /*
  * This function initiates a connection to the current server (s->srv) if (s->direct)
  * is set, or to the dispatch server if (s->direct) is 0.
@@ -1884,6 +1948,7 @@ int connect_server(struct session *s) {
        s->srv_addr = s->srv->addr;
     }
     else if (s->proxy->options & PR_O_BALANCE) {
+        /* Ensure that srv will not be NULL */
         if (!s->proxy->srv_act && !s->proxy->srv_bck)
             return SN_ERR_SRVTO;
 
@@ -1891,7 +1956,23 @@ int connect_server(struct session *s) {
            struct server *srv;
 
            srv = get_server_rr(s->proxy);
-            /* srv cannot be NULL */
+           s->srv_addr = srv->addr;
+           s->srv = srv;
+       }
+       else if (s->proxy->options & PR_O_BALANCE_SH) {
+           struct server *srv;
+            int len;
+
+            if (s->cli_addr.ss_family == AF_INET)
+                len = 4;
+            else if (s->cli_addr.ss_family == AF_INET6)
+                len = 16;
+            else /* unknown IP family */
+                return SN_ERR_INTERNAL;
+
+            srv = get_server_sh(s->proxy,
+                                (void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
+                                len);
            s->srv_addr = srv->addr;
            s->srv = srv;
        }
@@ -6846,8 +6927,11 @@ int cfg_parse_listen(char *file, int linenum, char **args) {
            if (!strcmp(args[1], "roundrobin")) {
                curproxy->options |= PR_O_BALANCE_RR;
            }
+           else if (!strcmp(args[1], "source")) {
+               curproxy->options |= PR_O_BALANCE_SH;
+           }
            else {
-               Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' option.\n", file, linenum, args[0]);
+               Alert("parsing [%s:%d] : '%s' only supports 'roundrobin' and 'source' options.\n", file, linenum, args[0]);
                return -1;
            }
        }
diff --git a/tests/active-sh.cfg b/tests/active-sh.cfg
new file mode 100644 (file)
index 0000000..20aa293
--- /dev/null
@@ -0,0 +1,29 @@
+# This is a test configuration.
+# It must load-balance across active servers. Check local apache logs to
+# verify :
+#
+#  tail /var/log/apache/access_log
+
+
+global
+       maxconn         100
+
+listen  sample1
+        mode            http
+        option         httplog
+        option          dontlognull
+        retries         1
+        redispatch
+        contimeout      1000
+        clitimeout      5000
+        srvtimeout      5000
+        maxconn 40000
+        bind :8081
+        balance source
+        server  srv1 127.0.0.1:80 cookie s1 check port 80 inter 1000 fall 1
+        server  srv2 127.0.0.2:80 cookie s2 check port 80 inter 1000 fall 1
+        server  srv3 127.0.0.3:80 cookie s3 check port 80 inter 1000 fall 1
+        #server  srv4 127.0.0.4:80 cookie s4 check port 80 inter 1000 fall 1
+        option  httpclose
+       errorloc 503 /503
+
diff --git a/tests/backup-all-sh.cfg b/tests/backup-all-sh.cfg
new file mode 100644 (file)
index 0000000..e89e556
--- /dev/null
@@ -0,0 +1,35 @@
+# This is a test configuration.
+# It must load-balance across backup servers depending on the souce hash.
+# Check local apache logs to verify :
+#
+#  tail /var/log/apache/access_log
+
+
+global
+       maxconn         100
+
+listen  sample1
+        mode            http
+        option         httplog
+        option          dontlognull
+        retries         1
+        redispatch
+        contimeout      1000
+        clitimeout      5000
+        srvtimeout      5000
+        maxconn 40000
+        bind :8081
+        balance source
+       option  allbackups
+        server  srv1 127.0.0.1:80 cookie s1 check port 81 inter 1000 fall 1
+        server  srv2 127.0.0.2:80 cookie s2 check port 81 inter 1000 fall 1
+        server  srv3 127.0.0.3:80 cookie s3 check port 81 inter 1000 fall 1
+        server  srv4 127.0.0.4:80 cookie s4 check port 81 inter 1000 fall 1
+        server  bck1 127.0.1.1:80 cookie b1 check port 80 inter 1000 fall 1 backup
+        server  bck2 127.0.1.2:80 cookie b2 check port 80 inter 1000 fall 1 backup
+        server  bck3 127.0.1.3:80 cookie b3 check port 80 inter 1000 fall 1 backup
+        server  bck4 127.0.1.4:80 cookie b4 check port 80 inter 1000 fall 1 backup
+        server  bck5 127.0.1.5:80 cookie b4 check port 80 inter 1000 fall 1 backup
+        option  httpclose
+       errorloc 503 /503
+
diff --git a/tests/backup-second-sh.cfg b/tests/backup-second-sh.cfg
new file mode 100644 (file)
index 0000000..084d2a4
--- /dev/null
@@ -0,0 +1,34 @@
+# This is a test configuration.
+# It must use only the first backup server. Check local apache logs to
+# verify :
+#
+#  tail /var/log/apache/access_log
+
+
+global
+       maxconn         100
+
+listen  sample1
+        mode            http
+        option         httplog
+        option          dontlognull
+        retries         1
+        redispatch
+        contimeout      1000
+        clitimeout      5000
+        srvtimeout      5000
+        maxconn 40000
+        bind :8081
+        balance source
+        server  srv1 127.0.0.1:80 cookie s1 check port 81 inter 1000 fall 1
+        server  srv2 127.0.0.2:80 cookie s2 check port 81 inter 1000 fall 1
+        server  srv3 127.0.0.3:80 cookie s3 check port 81 inter 1000 fall 1
+        server  srv4 127.0.0.4:80 cookie s4 check port 81 inter 1000 fall 1
+        server  bck1 127.0.1.1:80 cookie b1 check port 81 inter 1000 fall 1 backup
+        server  bck2 127.0.1.2:80 cookie b2 check port 80 inter 1000 fall 1 backup
+        server  bck3 127.0.1.3:80 cookie b3 check port 80 inter 1000 fall 1 backup
+        server  bck4 127.0.1.4:80 cookie b4 check port 80 inter 1000 fall 1 backup
+        server  bck5 127.0.1.5:80 cookie b5 check port 80 inter 1000 fall 1 backup
+        option  httpclose
+       errorloc 503 /503
+