[MEDIUM] add support for RDP cookie load-balancing

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.
This commit is contained in:
Emeric Brun 2009-06-30 17:56:00 +02:00 committed by Willy Tarreau
parent bede3d0ef4
commit 736aa238a3
3 changed files with 100 additions and 1 deletions

View 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.

View 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 */

View 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;