From: Emeric Brun Date: Tue, 30 Jun 2009 15:56:00 +0000 (+0200) Subject: [MEDIUM] add support for RDP cookie load-balancing X-Git-Tag: v1.4-dev1~22 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=736aa238a369edf5089bb50e7661576f270fd9b1;p=thirdparty%2Fhaproxy.git [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. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index e8fd090365..3e0b7c3499 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -956,6 +956,22 @@ balance url_param [check_post []] 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 (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. + is an optional list of arguments which may be needed by some algorithms. Right now, only "url_param" and "uri" support an optional argument. diff --git a/include/types/backend.h b/include/types/backend.h index 9f15c08d75..983d0099ae 100644 --- a/include/types/backend.h +++ b/include/types/backend.h @@ -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 */ diff --git a/src/backend.c b/src/backend.c index bf9f78922f..d6d47faeeb 100644 --- a/src/backend.c +++ b/src/backend.c @@ -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;