diff --git a/doc/configuration.txt b/doc/configuration.txt index 596f2abfd..f37981b04 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -3764,6 +3764,27 @@ nbsrv(backend) to handle some load. It is useful to report a failure when combined with "monitor fail". +connslots +connslots(backend) + The basic idea here is to be able to measure the number of connection "slots" + still available (connection, + queue) - so that anything beyond that (intended + usage; see "use_backend" keyword) can be redirected to a different backend. + + 'connslots' = number of available server connection slots, + number of available + server queue slots. + + *Note that while "dst_conn" may be used, "connslots" comes in especially useful + when you have a case of traffic going to one single ip, splitting into multiple + backends (perhaps using acls to do name-based load balancing) - and you want to + be able to differentiate between different backends, and their "connslots" + available. Also, whereas "nbsrv" only measures servers that are actually *down*, + this acl is more fine-grained - and looks into the number of conn slots available + as well. + + *OTHER CAVEATS AND NOTES: at this point in time, the code does not take care of + dynamic connections. Also, if any of the server maxconn, or maxqueue is 0, then + this acl clearly does not make sense - in which case the value returned will be -1. + 2.3.5.2) Matching contents at Layer 4 ------------------------------------- diff --git a/src/backend.c b/src/backend.c index 986c07072..c8a84beeb 100644 --- a/src/backend.c +++ b/src/backend.c @@ -2048,10 +2048,47 @@ acl_fetch_nbsrv(struct proxy *px, struct session *l4, void *l7, int dir, return 1; } +/* set test->i to the number of enabled servers on the proxy */ +static int +acl_fetch_connslots(struct proxy *px, struct session *l4, void *l7, int dir, + struct acl_expr *expr, struct acl_test *test) +{ + struct server *iterator; + test->flags = ACL_TEST_F_VOL_TEST; + if (expr->arg_len) { + /* another proxy was designated, we must look for it */ + for (px = proxy; px; px = px->next) + if ((px->cap & PR_CAP_BE) && !strcmp(px->id, expr->arg.str)) + break; + } + if (!px) + return 0; + + test->i = 0; + iterator = px->srv; + while (iterator) { + if ((iterator->state & 1) == 0) { + iterator = iterator->next; + continue; + } + if (iterator->maxconn == 0 || iterator->maxqueue == 0) { + test->i = -1; + return 1; + } + + test->i += (iterator->maxconn - iterator->cur_sess) + + (iterator->maxqueue - iterator->nbpend); + iterator = iterator->next; + } + + return 1; +} + /* Note: must not be declared as its list will be overwritten */ static struct acl_kw_list acl_kws = {{ },{ - { "nbsrv", acl_parse_int, acl_fetch_nbsrv, acl_match_int, ACL_USE_NOTHING }, + { "nbsrv", acl_parse_int, acl_fetch_nbsrv, acl_match_int, ACL_USE_NOTHING }, + { "connlots", acl_parse_int, acl_fetch_connslots, acl_match_int, ACL_USE_NOTHING }, { NULL, NULL, NULL, NULL }, }};