]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] add support for RDP cookie load-balancing
authorEmeric Brun <ebrun@exceliance.fr>
Tue, 30 Jun 2009 15:56:00 +0000 (17:56 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 14 Jul 2009 10:50:39 +0000 (12:50 +0200)
This patch adds support for hashing RDP cookies in order to
use them as a load-balancing key. The new "rdp-cookie(name)"
load-balancing metric has to be used for this. It is still
mandatory to wait for an RDP cookie in the frontend, otherwise
it will randomly work.

doc/configuration.txt
include/types/backend.h
src/backend.c

index e8fd0903654991cb32d5a032c6815cf52f511183..3e0b7c34991ec5bcb564594cce46039f2a67a648 100644 (file)
@@ -956,6 +956,22 @@ balance url_param <param> [check_post [<max_wait>]]
                   specific headers such as 'Host'. For instance, in the Host
                   value "haproxy.1wt.eu", only "1wt" will be considered.
 
+      rdp-cookie
+      rdp-cookie(name)
+                  The RDP cookie <name> (or "mstshash" if omitted) will be
+                  looked up and hashed for each incoming TCP request. Just as
+                  with the equivalent ACL 'req_rdp_cookie()' function, the name
+                  is not case-sensitive. This mechanism is useful as a degraded
+                  persistence mode, as it makes it possible to always send the
+                  same user (or the same session ID) to the same server. If the
+                  cookie is not found, the normal round-robind algorithm is
+                  used instead.
+
+                  Note that for this to work, the frontend must ensure that an
+                  RDP cookie is already present in the request buffer. For this
+                  you must use 'tcp-request content accept' rule combined with
+                  a 'req_rdp_cookie_cnt' ACL.
+
     <arguments> is an optional list of arguments which may be needed by some
                 algorithms. Right now, only "url_param" and "uri" support an
                 optional argument.
index 9f15c08d75c357daf3d429364c502b48dd8de731..983d0099ae13bc9839b9a72322bb4d7e3dfe5154 100644 (file)
@@ -44,6 +44,7 @@
 #define BE_LB_ALGO_PH  (BE_LB_PROP_L7  | 0x04) /* balance on URL parameter hash */
 #define BE_LB_ALGO_LC  (BE_LB_PROP_DYN | 0x05) /* fast weighted leastconn mode (dynamic) */
 #define BE_LB_ALGO_HH  (BE_LB_PROP_L7  | 0x06) /* balance on Http Header value */
+#define BE_LB_ALGO_RCH (BE_LB_PROP_L4  | 0x07) /* balance on RDP Cookie value */
 
 /* various constants */
 
index bf9f78922f85d00c5ca0076ce11c4ddee409c810..d6d47faeeb22a740f4f4964b86786348e6e1763f 100644 (file)
@@ -1367,6 +1367,46 @@ struct server *get_server_hh(struct session *s)
        return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
 }
 
+struct server *get_server_rch(struct session *s)
+{
+       unsigned long    hash = 0;
+       struct proxy    *px   = s->be;
+       unsigned long    len;
+       const char      *p;
+       int              ret;
+       struct acl_expr  expr;
+       struct acl_test  test;
+
+       /* tot_weight appears to mean srv_count */
+       if (px->lbprm.tot_weight == 0)
+               return NULL;
+
+       if (px->lbprm.map.state & PR_MAP_RECALC)
+               recalc_server_map(px);
+
+       memset(&expr, 0, sizeof(expr));
+       memset(&test, 0, sizeof(test));
+
+       expr.arg.str = px->hh_name;
+       expr.arg_len = px->hh_len;
+
+       ret = acl_fetch_rdp_cookie(px, s, NULL, ACL_DIR_REQ, &expr, &test);
+       if (ret == 0 || (test.flags & ACL_TEST_F_MAY_CHANGE) || test.len == 0)
+               return NULL;
+
+       /* Found a the hh_name in the headers.
+        * we will compute the hash based on this value ctx.val.
+        */
+       len = test.len;
+       p = (char *)test.ptr;
+       while (len) {
+               hash = *p + (hash << 6) + (hash << 16) - hash;
+               len--;
+               p++;
+       }
+
+       return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
+}
  
 /*
  * This function applies the load-balancing algorithm to the session, as
@@ -1490,6 +1530,19 @@ int assign_server(struct session *s)
                        /* Header Parameter hashing */
                        s->srv = get_server_hh(s);
 
+                       if (!s->srv) {
+                               /* parameter not found, fall back to round robin on the map */
+                               s->srv = get_server_rr_with_conns(s->be, s->prev_srv);
+                               if (!s->srv) {
+                                       err = SRV_STATUS_FULL;
+                                       goto out;
+                               }
+                       }
+                       break;
+               case BE_LB_ALGO_RCH:
+                       /* RDP Cookie hashing */
+                       s->srv = get_server_rch(s);
+
                        if (!s->srv) {
                                /* parameter not found, fall back to round robin on the map */
                                s->srv = get_server_rr_with_conns(s->be, s->prev_srv);
@@ -2206,8 +2259,37 @@ int backend_parse_balance(const char **args, char *err, int errlen, struct proxy
                }
 
        }
+       else if (!strncmp(args[0], "rdp-cookie", 10)) {
+               curproxy->lbprm.algo &= ~BE_LB_ALGO;
+               curproxy->lbprm.algo |= BE_LB_ALGO_RCH;
+
+               if ( *(args[0] + 10 ) == '(' ) { /* cookie name */
+                       const char *beg, *end;
+
+                       beg = args[0] + 11;
+                       end = strchr(beg, ')');
+
+                       if (!end || end == beg) {
+                               snprintf(err, errlen, "'balance rdp-cookie(name)' requires an rdp cookie name.");
+                               return -1;
+                       }
+
+                       free(curproxy->hh_name);
+                       curproxy->hh_name = my_strndup(beg, end - beg);
+                       curproxy->hh_len  = end - beg;
+               }
+               else if ( *(args[0] + 10 ) == '\0' ) { /* default cookie name 'mstshash' */
+                       free(curproxy->hh_name);
+                       curproxy->hh_name = strdup("mstshash");
+                       curproxy->hh_len  = strlen(curproxy->hh_name);
+               }
+               else { /* syntax */
+                       snprintf(err, errlen, "'balance rdp-cookie(name)' requires an rdp cookie name.");
+                       return -1;
+               }
+       }
        else {
-               snprintf(err, errlen, "'balance' only supports 'roundrobin', 'leastconn', 'source', 'uri', 'url_param' and 'hdr(name)' options.");
+               snprintf(err, errlen, "'balance' only supports 'roundrobin', 'leastconn', 'source', 'uri', 'url_param', 'hdr(name)' and 'rdp-cookie(name)' options.");
                return -1;
        }
        return 0;