[MEDIUM] config: automatically find unused IDs for proxies, servers and listeners

Until now it was required that every custom ID was above 1000 in order to
avoid conflicts. Now we have the list of all assigned IDs and can automatically
pick the first unused one. This means that it is perfectly possible to interleave
automatic IDs with persistent IDs and the parser will automatically allocate
unused values starting with 1.
This commit is contained in:
Willy Tarreau 2009-10-04 23:04:08 +02:00
parent 482b00d1b4
commit 53fb4ae261
6 changed files with 102 additions and 46 deletions

View File

@ -724,6 +724,7 @@ errorloc303 X X X X
fullconn X - X X
grace - X X X
http-check disable-on-404 X - X X
id - X X X
log X X X X
maxconn X X X -
mode X X X X
@ -1140,10 +1141,10 @@ bind [<address>]:<port> [, ...] name <name>
work on other operating systems. The commonly advertised
value on Ethernet networks is 1460 = 1500(MTU) - 40(IP+TCP).
<id> is a persistent value for socket ID. Must be unique and
larger than 1000, as smaller values are reserved for
auto-assigned ids. Can only be used when defining only
a single socket.
<id> is a persistent value for socket ID. Must be positive and
unique in the proxy. An unused value will automatically be
assigned if unset. Can only be used when defining only a
single socket.
<name> is an optional name provided for stats
@ -1748,8 +1749,14 @@ http-check disable-on-404
id <value>
Set a persistent value for proxy ID. Must be unique and larger than 1000, as
smaller values are reserved for auto-assigned ids.
Set a persistent ID to a proxy.
May be used in sections : defaults | frontend | listen | backend
no | yes | yes | yes
Arguments : none
Set a persistent ID for the proxy. This ID must be unique and positive.
An unused ID will automatically be assigned if unset. The first assigned
value will be 1. This ID is currently only returned in statistics.
log global
@ -4583,8 +4590,9 @@ fall <count>
unspecified. See also the "check", "inter" and "rise" parameters.
id <value>
Set a persistent value for server ID. Must be unique and larger than 1000, as
smaller values are reserved for auto-assigned ids.
Set a persistent ID for the server. This ID must be positive and unique for
the proxy. An unused ID will automatically be assigned if unset. The first
assigned value will be 1. This ID is currently only returned in statistics.
inter <delay>
fastinter <delay>

View File

@ -28,6 +28,7 @@
#include <sys/un.h>
#include <common/config.h>
#include <common/eb32tree.h>
#include <common/mini-clist.h>
#include <types/counters.h>
@ -108,6 +109,7 @@ struct listener {
struct {
const char *file; /* file where the section appears */
int line; /* line where the section appears */
struct eb32_node id; /* place in the tree of used IDs */
} conf; /* config information */
};

View File

@ -29,6 +29,7 @@
#include <common/appsession.h>
#include <common/config.h>
#include <common/eb32tree.h>
#include <common/mini-clist.h>
#include <common/regex.h>
#include <common/sessionhash.h>
@ -248,7 +249,6 @@ struct proxy {
int check_len; /* Length of the HTTP or SSL3 request */
struct chunk errmsg[HTTP_ERR_SIZE]; /* default or customized error messages for known errors */
int uuid; /* universally unique proxy ID, used for SNMP */
int next_svid, next_lid; /* next server-id and listener-id, used for SNMP */
unsigned int backlog; /* force the frontend's listen backlog */
unsigned int bind_proc; /* bitmask of processes using this proxy. 0 = all. */
struct error_snapshot invalid_req, invalid_rep; /* captures of last errors */
@ -262,6 +262,9 @@ struct proxy {
struct {
const char *file; /* file where the section appears */
int line; /* line where the section appears */
struct eb32_node id; /* place in the tree of used IDs */
struct eb_root used_listener_id;/* list of listener IDs in use */
struct eb_root used_server_id; /* list of server IDs in use */
} conf; /* config information */
};
@ -287,7 +290,7 @@ struct redirect_rule {
};
extern struct proxy *proxy;
extern int next_pxid;
extern struct eb_root used_proxy_id; /* list of proxy IDs in use */
#endif /* _TYPES_PROXY_H */

View File

@ -135,6 +135,7 @@ struct server {
struct {
const char *file; /* file where the section appears */
int line; /* line where the section appears */
struct eb32_node id; /* place in the tree of used IDs */
} conf; /* config information */
};

View File

@ -258,7 +258,6 @@ static int str2listener(char *str, struct proxy *curproxy)
tcpv4_add_listener(l);
}
l->luid = curproxy->next_lid++;
listeners++;
} /* end for(port) */
} /* end while(next) */
@ -1013,9 +1012,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
curproxy->loglev2 = defproxy.loglev2;
curproxy->minlvl2 = defproxy.minlvl2;
curproxy->grace = defproxy.grace;
curproxy->uuid = next_pxid++; /* generate a uuid for this proxy */
curproxy->next_svid = 1; /* server id 0 is reserved */
curproxy->next_lid = 1; /* listener id 0 is reserved */
curproxy->conf.used_listener_id = EB_ROOT;
curproxy->conf.used_server_id = EB_ROOT;
goto out;
}
@ -1172,6 +1170,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
}
if (!strcmp(args[cur_arg], "id")) {
struct eb32_node *node;
struct listener *l;
if (curproxy->listen->next != last_listen) {
@ -1189,21 +1188,25 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
}
curproxy->listen->luid = atol(args[cur_arg + 1]);
curproxy->listen->conf.id.key = curproxy->listen->luid;
if (curproxy->listen->luid < 1001) {
Alert("parsing [%s:%d]: custom id has to be > 1000\n",
if (curproxy->listen->luid <= 0) {
Alert("parsing [%s:%d]: custom id has to be > 0\n",
file, linenum);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
for (l = curproxy->listen; l; l = l->next)
if (curproxy->listen != l && l->luid == curproxy->listen->luid) {
Alert("parsing [%s:%d]: custom id %d for socket '%s' already used at %s:%d.\n",
file, linenum, l->luid, args[1], l->conf.file, l->conf.line);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
node = eb32_lookup(&curproxy->conf.used_listener_id, curproxy->listen->luid);
if (node) {
l = container_of(node, struct listener, conf.id);
Alert("parsing [%s:%d]: custom id %d for socket '%s' already used at %s:%d.\n",
file, linenum, l->luid, args[1], l->conf.file, l->conf.line);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
eb32_insert(&curproxy->conf.used_listener_id, &curproxy->listen->conf.id);
cur_arg += 2;
continue;
}
@ -1260,7 +1263,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
}
}
else if (!strcmp(args[0], "id")) {
struct proxy *target;
struct eb32_node *node;
if (curproxy == &defproxy) {
Alert("parsing [%s:%d]: '%s' not allowed in 'defaults' section.\n",
@ -1277,22 +1280,25 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
}
curproxy->uuid = atol(args[1]);
curproxy->conf.id.key = curproxy->uuid;
if (curproxy->uuid < 1001) {
Alert("parsing [%s:%d]: custom id has to be > 1000.\n",
if (curproxy->uuid <= 0) {
Alert("parsing [%s:%d]: custom id has to be > 0.\n",
file, linenum);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
for (target = proxy; target; target = target->next)
if (curproxy != target && curproxy->uuid == target->uuid) {
Alert("parsing [%s:%d]: %s %s reuses same custom id as %s %s (declared at %s:%d).\n",
file, linenum, proxy_type_str(curproxy), curproxy->id,
proxy_type_str(target), target->id, target->conf.file, target->conf.line);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
node = eb32_lookup(&used_proxy_id, curproxy->uuid);
if (node) {
struct proxy *target = container_of(node, struct proxy, conf.id);
Alert("parsing [%s:%d]: %s %s reuses same custom id as %s %s (declared at %s:%d).\n",
file, linenum, proxy_type_str(curproxy), curproxy->id,
proxy_type_str(target), target->id, target->conf.file, target->conf.line);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
eb32_insert(&used_proxy_id, &curproxy->conf.id);
}
else if (!strcmp(args[0], "description")) {
int i, len=0;
@ -2474,7 +2480,6 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
newsrv->next = curproxy->srv;
curproxy->srv = newsrv;
newsrv->proxy = curproxy;
newsrv->puid = curproxy->next_svid++;
newsrv->conf.file = file;
newsrv->conf.line = linenum;
@ -2521,7 +2526,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
cur_arg = 3;
while (*args[cur_arg]) {
if (!strcmp(args[cur_arg], "id")) {
struct server *target;
struct eb32_node *node;
if (!*args[cur_arg + 1]) {
Alert("parsing [%s:%d]: '%s' expects an integer argument.\n",
@ -2531,21 +2536,24 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
}
newsrv->puid = atol(args[cur_arg + 1]);
newsrv->conf.id.key = newsrv->puid;
if (newsrv->puid< 1001) {
Alert("parsing [%s:%d]: custom id has to be > 1000.\n",
if (newsrv->puid <= 0) {
Alert("parsing [%s:%d]: custom id has to be > 0.\n",
file, linenum);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
for (target = proxy->srv; target; target = target->next)
if (newsrv != target && newsrv->puid == target->puid) {
Alert("parsing [%s:%d]: server %s reuses same custom id as server %s (declared at %s:%d).\n",
file, linenum, newsrv->id, target->id, target->conf.file, target->conf.line);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
node = eb32_lookup(&curproxy->conf.used_server_id, newsrv->puid);
if (node) {
struct server *target = container_of(node, struct server, conf.id);
Alert("parsing [%s:%d]: server %s reuses same custom id as server %s (declared at %s:%d).\n",
file, linenum, newsrv->id, target->id, target->conf.file, target->conf.line);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
eb32_insert(&curproxy->conf.used_server_id, &newsrv->conf.id);
cur_arg += 2;
}
else if (!strcmp(args[cur_arg], "cookie")) {
@ -3986,6 +3994,7 @@ int check_config_validity()
struct proxy *curproxy = NULL;
struct server *newsrv = NULL;
int err_code = 0;
unsigned int next_pxid = 1;
/*
* Now, check for the integrity of all that we have collected.
@ -4016,6 +4025,17 @@ int check_config_validity()
while (curproxy != NULL) {
struct switching_rule *rule;
struct listener *listener;
unsigned int next_id;
if (!curproxy->uuid) {
/* proxy ID not set, use automatic numbering with first
* spare entry starting with next_pxid.
*/
next_pxid = get_next_id(&used_proxy_id, next_pxid);
curproxy->conf.id.key = curproxy->uuid = next_pxid;
eb32_insert(&used_proxy_id, &curproxy->conf.id);
next_pxid++;
}
if (curproxy->state == PR_STSTOPPED) {
/* ensure we don't keep listeners uselessly bound */
@ -4301,8 +4321,19 @@ int check_config_validity()
/*
* ensure that we're not cross-dressing a TCP server into HTTP.
*/
next_id = 1;
newsrv = curproxy->srv;
while (newsrv != NULL) {
if (!newsrv->puid) {
/* server ID not set, use automatic numbering with first
* spare entry starting with next_svid.
*/
next_id = get_next_id(&curproxy->conf.used_server_id, next_id);
newsrv->conf.id.key = newsrv->puid = next_id;
eb32_insert(&curproxy->conf.used_server_id, &newsrv->conf.id);
next_id++;
}
if ((curproxy->mode != PR_MODE_HTTP) && (newsrv->rdr_len || newsrv->cklen)) {
Alert("config : %s '%s' : server cannot have cookie or redirect prefix in non-HTTP mode.\n",
proxy_type_str(curproxy), curproxy->id);
@ -4440,8 +4471,19 @@ int check_config_validity()
}
/* adjust this proxy's listeners */
next_id = 1;
listener = curproxy->listen;
while (listener) {
if (!listener->luid) {
/* listener ID not set, use automatic numbering with first
* spare entry starting with next_luid.
*/
next_id = get_next_id(&curproxy->conf.used_listener_id, next_id);
listener->conf.id.key = listener->luid = next_id;
eb32_insert(&curproxy->conf.used_listener_id, &listener->conf.id);
next_id++;
}
/* enable separate counters */
if (curproxy->options2 & PR_O2_SOCKSTAT) {
listener->counters = (struct licounters *)calloc(1, sizeof(struct licounters));

View File

@ -39,7 +39,7 @@
int listeners; /* # of proxy listeners, set by cfgparse, unset by maintain_proxies */
struct proxy *proxy = NULL; /* list of all existing proxies */
int next_pxid = 1; /* UUID assigned to next new proxy, 0 reserved */
struct eb_root used_proxy_id = EB_ROOT; /* list of proxy IDs in use */
/*
* This function returns a string containing a name describing capabilities to