[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:
parent
bede3d0ef4
commit
736aa238a3
|
@ -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.
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue