MEDIUM: config: limit nbproc to the machine's word size

Some consistency checks cannot be performed between frontends, backends
and peers at the moment because there is no way to check for intersection
between processes bound to some processes when the number of processes is
higher than the number of bits in a word.

So first, let's limit the number of processes to the machine's word size.
This means nbproc will be limited to 32 on 32-bit machines and 64 on 64-bit
machines. This is far more than enough considering that configs rarely go
above 16 processes due to scalability and management issues, so 32 or 64
should be fine.

This way we'll ensure we can always build a mask of all the processes a
section is bound to.
This commit is contained in:
Willy Tarreau 2013-01-18 11:29:29 +01:00
parent 3507d5d096
commit a9db57ec5c
7 changed files with 79 additions and 66 deletions

View File

@ -525,16 +525,16 @@ cpu-map <"all"|"odd"|"even"|process_num> <cpu-set>...
On Linux 2.6 and above, it is possible to bind a process to a specific CPU
set. This means that the process will never run on other CPUs. The "cpu-map"
directive specifies CPU sets for process sets. The first argument is the
process number to bind. This process must have a number between 1 and 32,
and any process IDs above nbproc are ignored. It is possible to specify all
processes at once using "all", only odd numbers using "odd" or even numbers
using "even", just like with the "bind-process" directive. The second and
forthcoming arguments are CPU sets. Each CPU set is either a unique number
between 0 and 31 or a range with two such numbers delimited by a dash ('-').
Multiple CPU numbers or ranges may be specified, and the processes will be
allowed to bind to all of them. Obviously, multiple "cpu-map" directives may
be specified. Each "cpu-map" directive will replace the previous ones when
they overlap.
process number to bind. This process must have a number between 1 and 32 or
64, depending on the machine's word size, and any process IDs above nbproc
are ignored. It is possible to specify all processes at once using "all",
only odd numbers using "odd" or even numbers using "even", just like with the
"bind-process" directive. The second and forthcoming arguments are CPU sets.
Each CPU set is either a unique number between 0 and 31 or 63 or a range with
two such numbers delimited by a dash ('-'). Multiple CPU numbers or ranges
may be specified, and the processes will be allowed to bind to all of them.
Obviously, multiple "cpu-map" directives may be specified. Each "cpu-map"
directive will replace the previous ones when they overlap.
crt-base <dir>
Assigns a default directory to fetch SSL certificates from when a relative
@ -624,14 +624,15 @@ pidfile <pidfile>
the "-p" command line argument. The file must be accessible to the user
starting the process. See also "daemon".
stats bind-process [ all | odd | even | <number 1-32>[-<number 1-32>] ] ...
stats bind-process [ all | odd | even | <number 1-64>[-<number 1-64>] ] ...
Limits the stats socket to a certain set of processes numbers. By default the
stats socket is bound to all processes, causing a warning to be emitted when
nbproc is greater than 1 because there is no way to select the target process
when connecting. However, by using this setting, it becomes possible to pin
the stats socket to a specific set of processes, typically the first one. The
warning will automatically be disabled when this setting is used, whatever
the number of processes used.
the number of processes used. The maximum process ID depends on the machine's
word size (32 or 64).
ssl-default-bind-ciphers <ciphers>
This setting is only available when support for OpenSSL was built in. It sets
@ -1830,7 +1831,7 @@ bind /<path> [, ...] [param*]
documentation, and section 5 about bind options.
bind-process [ all | odd | even | <number 1-32>[-<number 1-32>] ] ...
bind-process [ all | odd | even | <number 1-64>[-<number 1-64>] ] ...
Limit visibility of an instance to a certain set of processes numbers.
May be used in sections : defaults | frontend | listen | backend
yes | yes | yes | yes
@ -1838,19 +1839,19 @@ bind-process [ all | odd | even | <number 1-32>[-<number 1-32>] ] ...
all All process will see this instance. This is the default. It
may be used to override a default value.
odd This instance will be enabled on processes 1,3,5,...31. This
odd This instance will be enabled on processes 1,3,5,...63. This
option may be combined with other numbers.
even This instance will be enabled on processes 2,4,6,...32. This
even This instance will be enabled on processes 2,4,6,...64. This
option may be combined with other numbers. Do not use it
with less than 2 processes otherwise some instances might be
missing from all processes.
number The instance will be enabled on this process number or range,
whose values must all be between 1 and 32. You must be
careful not to reference a process number greater than the
configured global.nbproc, otherwise some instances might be
missing from all processes.
whose values must all be between 1 and 32 or 64 depending on
the machine's word size. You must be careful not to reference
a process number greater than the configured global.nbproc,
otherwise some instances might be missing from all processes.
This keyword limits binding of certain instances to certain processes. This
is useful in order not to have too many processes listening to the same
@ -1858,10 +1859,10 @@ bind-process [ all | odd | even | <number 1-32>[-<number 1-32>] ] ...
'nbproc 2' in the global section, then distributes the listeners among 'odd'
and 'even' instances.
At the moment, it is not possible to reference more than 32 processes using
this keyword, but this should be more than enough for most setups. Please
note that 'all' really means all processes and is not limited to the first
32.
At the moment, it is not possible to reference more than 32 or 64 processes
using this keyword, but this should be more than enough for most setups.
Please note that 'all' really means all processes regardless of the machine's
word size, and is not limited to the first 32 or 64.
If some backends are referenced by frontends bound to other processes, the
backend automatically inherits the frontend's processes.

View File

@ -42,6 +42,10 @@
# define ULLONG_MAX (LLONG_MAX * 2ULL + 1)
#endif
#ifndef LONGBITS
#define LONGBITS ((unsigned int)sizeof(long) * 8)
#endif
/* size used for max length of decimal representation of long long int. */
#define NB_LLMAX_STR (sizeof("-9223372036854775807")-1)
@ -527,7 +531,7 @@ static inline unsigned int div64_32(unsigned long long o1, unsigned int o2)
}
/* Simple popcount implementation. It returns the number of ones in a word */
static inline unsigned int popcount(unsigned int a)
static inline unsigned int popcount(unsigned long a)
{
unsigned int cnt;
for (cnt = 0; a; a >>= 1) {
@ -537,6 +541,15 @@ static inline unsigned int popcount(unsigned int a)
return cnt;
}
/* Build a word with the <bits> lower bits set (reverse of popcount) */
static inline unsigned long nbits(int bits)
{
if (--bits < 0)
return 0;
else
return (2UL << bits) - 1;
}
/*
* Parse binary string written in hexadecimal (source) and store the decoded
* result into binstr and set binstrlen to the lengh of binstr. Memory for

View File

@ -149,7 +149,7 @@ struct global {
} ux;
} unix_bind;
#ifdef USE_CPU_AFFINITY
unsigned long cpu_map[32]; /* list of CPU masks for the 32 first processes */
unsigned long cpu_map[LONGBITS]; /* list of CPU masks for the 32/64 first processes */
#endif
struct proxy *stats_fe; /* the frontend holding the stats settings */
};

View File

@ -345,7 +345,7 @@ struct proxy {
struct chunk errmsg[HTTP_ERR_SIZE]; /* default or customized error messages for known errors */
int uuid; /* universally unique proxy 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. */
unsigned long bind_proc; /* bitmask of processes using this proxy */
/* warning: these structs are huge, keep them at the bottom */
struct sockaddr_storage dispatch_addr; /* the default address to connect to */

View File

@ -886,6 +886,12 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
goto out;
}
global.nbproc = atol(args[1]);
if (global.nbproc < 1 || global.nbproc > LONGBITS) {
Alert("parsing [%s:%d] : '%s' must be between 1 and %d (was %d).\n",
file, linenum, args[0], LONGBITS, global.nbproc);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
}
else if (!strcmp(args[0], "maxconn")) {
if (global.maxconn != 0) {
@ -1369,24 +1375,24 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
else if (strcmp(args[0], "cpu-map") == 0) { /* map a process list to a CPU set */
#ifdef USE_CPU_AFFINITY
int cur_arg, i;
unsigned int proc = 0;
unsigned long proc = 0;
unsigned long cpus = 0;
if (strcmp(args[1], "all") == 0)
proc = 0xFFFFFFFF;
proc = ~0UL;
else if (strcmp(args[1], "odd") == 0)
proc = 0x55555555;
proc = ~0UL/3UL; /* 0x555....555 */
else if (strcmp(args[1], "even") == 0)
proc = 0xAAAAAAAA;
proc = (~0UL/3UL) << 1; /* 0xAAA...AAA */
else {
proc = atoi(args[1]);
if (proc >= 1 && proc <= 32)
proc = 1 << (proc - 1);
proc = atol(args[1]);
if (proc >= 1 && proc <= LONGBITS)
proc = 1UL << (proc - 1);
}
if (!proc || !*args[2]) {
Alert("parsing [%s:%d]: %s expects a process number including 'all', 'odd', 'even', or a number from 1 to 32, followed by a list of CPU ranges with numbers from 0 to 31.\n",
file, linenum, args[0]);
Alert("parsing [%s:%d]: %s expects a process number including 'all', 'odd', 'even', or a number from 1 to %d, followed by a list of CPU ranges with numbers from 0 to %d.\n",
file, linenum, args[0], LONGBITS, LONGBITS - 1);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
@ -1408,9 +1414,9 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
high = swap;
}
if (high >= sizeof(long) * 8) {
if (high >= LONGBITS) {
Alert("parsing [%s:%d]: %s supports CPU numbers from 0 to %d.\n",
file, linenum, args[0], (int)(sizeof(long) * 8 - 1));
file, linenum, args[0], LONGBITS - 1);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
@ -1426,8 +1432,8 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
}
cur_arg++;
}
for (i = 0; i < 32; i++)
if (proc & (1 << i))
for (i = 0; i < LONGBITS; i++)
if (proc & (1UL << i))
global.cpu_map[i] = cpus;
#else
Alert("parsing [%s:%d] : '%s' is not enabled, please check build options for USE_CPU_AFFINITY.\n", file, linenum, args[0]);
@ -2350,7 +2356,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
}
else if (!strcmp(args[0], "bind-process")) { /* enable this proxy only on some processes */
int cur_arg = 1;
unsigned int set = 0;
unsigned long set = 0;
while (*args[cur_arg]) {
unsigned int low, high;
@ -2360,10 +2366,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
break;
}
else if (strcmp(args[cur_arg], "odd") == 0) {
set |= 0x55555555;
set |= ~0UL/3UL; /* 0x555....555 */
}
else if (strcmp(args[cur_arg], "even") == 0) {
set |= 0xAAAAAAAA;
set |= (~0UL/3UL) << 1; /* 0xAAA...AAA */
}
else if (isdigit((int)*args[cur_arg])) {
char *dash = strchr(args[cur_arg], '-');
@ -2378,24 +2384,18 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
high = swap;
}
if (low < 1 || high > 32) {
Alert("parsing [%s:%d]: %s supports process numbers from 1 to 32.\n",
file, linenum, args[0]);
if (low < 1 || high > LONGBITS) {
Alert("parsing [%s:%d]: %s supports process numbers from 1 to %d.\n",
file, linenum, args[0], LONGBITS);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
if (high > global.nbproc) {
Warning("parsing [%s:%d]: %s references process number %d which is higher than global.nbproc (%d).\n",
file, linenum, args[0], high, global.nbproc);
err_code |= ERR_WARN;
}
while (low <= high)
set |= 1 << (low++ - 1);
set |= 1UL << (low++ - 1);
}
else {
Alert("parsing [%s:%d]: %s expects 'all', 'odd', 'even', or a list of process ranges with numbers from 1 to 32.\n",
file, linenum, args[0]);
Alert("parsing [%s:%d]: %s expects 'all', 'odd', 'even', or a list of process ranges with numbers from 1 to %d.\n",
file, linenum, args[0], LONGBITS);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
@ -6860,7 +6860,7 @@ out_uri_auth_compat:
if (curproxy->bind_proc) {
int proc;
for (proc = 0; proc < global.nbproc; proc++) {
if (curproxy->bind_proc & (1 << proc)) {
if (curproxy->bind_proc & (1UL << proc)) {
nbproc++;
}
}

View File

@ -372,7 +372,7 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx
}
else if (!strcmp(args[1], "bind-process")) { /* enable the socket only on some processes */
int cur_arg = 2;
unsigned int set = 0;
unsigned long set = 0;
if (!global.stats_fe) {
if ((global.stats_fe = alloc_stats_fe("GLOBAL", file, line)) == NULL) {
@ -389,10 +389,10 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx
break;
}
else if (strcmp(args[cur_arg], "odd") == 0) {
set |= 0x55555555;
set |= ~0UL/3UL; /* 0x555....555 */
}
else if (strcmp(args[cur_arg], "even") == 0) {
set |= 0xAAAAAAAA;
set |= (~0UL/3UL) << 1; /* 0xAAA...AAA */
}
else if (isdigit((int)*args[cur_arg])) {
char *dash = strchr(args[cur_arg], '-');
@ -407,19 +407,18 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx
high = swap;
}
if (low < 1 || high > 32) {
memprintf(err, "'%s %s' supports process numbers from 1 to 32.\n",
args[0], args[1]);
if (low < 1 || high > LONGBITS) {
memprintf(err, "'%s %s' supports process numbers from 1 to %d.\n",
args[0], args[1], LONGBITS);
return -1;
}
while (low <= high)
set |= 1 << (low++ - 1);
set |= 1UL << (low++ - 1);
}
else {
memprintf(err,
"'%s %s' expects 'all', 'odd', 'even', or a list of process ranges with numbers from 1 to 32.\n",
args[0], args[1]);
"'%s %s' expects 'all', 'odd', 'even', or a list of process ranges with numbers from 1 to %d.\n",
args[0], args[1], LONGBITS);
return -1;
}
cur_arg++;

View File

@ -1596,7 +1596,7 @@ int main(int argc, char **argv)
px = proxy;
while (px != NULL) {
if (px->bind_proc && px->state != PR_STSTOPPED) {
if (!(px->bind_proc & (1 << proc)))
if (!(px->bind_proc & (1UL << proc)))
stop_proxy(px);
}
px = px->next;