mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-23 06:41:32 +02:00
Some users are already hitting the 64k source port limit when connecting to servers. The system usually maintains a list of unused source ports, regardless of the source IP they're bound to. So in order to go beyond the 64k concurrent connections, we have to manage the source ip:port lists ourselves. The solution consists in assigning a source port range to each server and use a free port in that range when connecting to that server, either for a proxied connection or for a health check. The port must then be put back into the server's range when the connection is closed. This mechanism is used only when a port range is specified on a server. It makes it possible to reach 64k connections per server, possibly all from the same IP address. Right now it should be more than enough even for huge deployments.
178 lines
3.7 KiB
C
178 lines
3.7 KiB
C
/*
|
|
* File descriptors management functions.
|
|
*
|
|
* Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <common/compat.h>
|
|
#include <common/config.h>
|
|
|
|
#include <proto/fd.h>
|
|
#include <proto/port_range.h>
|
|
|
|
struct fdtab *fdtab = NULL; /* array of all the file descriptors */
|
|
int maxfd; /* # of the highest fd + 1 */
|
|
int totalconn; /* total # of terminated sessions */
|
|
int actconn; /* # of active sessions */
|
|
|
|
struct poller pollers[MAX_POLLERS];
|
|
struct poller cur_poller;
|
|
int nbpollers = 0;
|
|
|
|
|
|
/* Deletes an FD from the fdsets, and recomputes the maxfd limit.
|
|
* The file descriptor is also closed.
|
|
*/
|
|
void fd_delete(int fd)
|
|
{
|
|
EV_FD_CLO(fd);
|
|
port_range_release_port(fdtab[fd].port_range, fdtab[fd].local_port);
|
|
fdtab[fd].port_range = NULL;
|
|
close(fd);
|
|
fdtab[fd].state = FD_STCLOSE;
|
|
|
|
while ((maxfd-1 >= 0) && (fdtab[maxfd-1].state == FD_STCLOSE))
|
|
maxfd--;
|
|
}
|
|
|
|
|
|
/* disable the specified poller */
|
|
void disable_poller(const char *poller_name)
|
|
{
|
|
int p;
|
|
|
|
for (p = 0; p < nbpollers; p++)
|
|
if (strcmp(pollers[p].name, poller_name) == 0)
|
|
pollers[p].pref = 0;
|
|
}
|
|
|
|
/*
|
|
* Initialize the pollers till the best one is found.
|
|
* If none works, returns 0, otherwise 1.
|
|
*/
|
|
int init_pollers()
|
|
{
|
|
int p;
|
|
struct poller *bp;
|
|
|
|
|
|
do {
|
|
bp = NULL;
|
|
for (p = 0; p < nbpollers; p++)
|
|
if (!bp || (pollers[p].pref > bp->pref))
|
|
bp = &pollers[p];
|
|
|
|
if (!bp || bp->pref == 0)
|
|
break;
|
|
|
|
if (bp->init(bp)) {
|
|
memcpy(&cur_poller, bp, sizeof(*bp));
|
|
return 1;
|
|
}
|
|
} while (!bp || bp->pref == 0);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Deinitialize the pollers.
|
|
*/
|
|
void deinit_pollers() {
|
|
|
|
struct poller *bp;
|
|
int p;
|
|
|
|
for (p = 0; p < nbpollers; p++) {
|
|
bp = &pollers[p];
|
|
|
|
if (bp && bp->pref)
|
|
bp->term(bp);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Lists the known pollers on <out>.
|
|
* Should be performed only before initialization.
|
|
*/
|
|
int list_pollers(FILE *out)
|
|
{
|
|
int p;
|
|
int last, next;
|
|
int usable;
|
|
struct poller *bp;
|
|
|
|
fprintf(out, "Available polling systems :\n");
|
|
|
|
usable = 0;
|
|
bp = NULL;
|
|
last = next = -1;
|
|
while (1) {
|
|
for (p = 0; p < nbpollers; p++) {
|
|
if (!bp || (pollers[p].pref > bp->pref))
|
|
bp = &pollers[p];
|
|
if ((next < 0 || pollers[p].pref > next)
|
|
&& (last < 0 || pollers[p].pref < last))
|
|
next = pollers[p].pref;
|
|
}
|
|
|
|
if (next == -1)
|
|
break;
|
|
|
|
for (p = 0; p < nbpollers; p++) {
|
|
if (pollers[p].pref == next) {
|
|
fprintf(out, " %10s : ", pollers[p].name);
|
|
if (pollers[p].pref == 0)
|
|
fprintf(out, "disabled, ");
|
|
else
|
|
fprintf(out, "pref=%3d, ", pollers[p].pref);
|
|
if (pollers[p].test(&pollers[p])) {
|
|
fprintf(out, " test result OK");
|
|
if (next > 0)
|
|
usable++;
|
|
} else
|
|
fprintf(out, " test result FAILED");
|
|
fprintf(out, "\n");
|
|
}
|
|
}
|
|
last = next;
|
|
next = -1;
|
|
};
|
|
fprintf(out, "Total: %d (%d usable), will use %s.\n", nbpollers, usable, bp ? bp->name : "none");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Some pollers may lose their connection after a fork(). It may be necessary
|
|
* to create initialize part of them again. Returns 0 in case of failure,
|
|
* otherwise 1. The fork() function may be NULL if unused. In case of error,
|
|
* the the current poller is destroyed and the caller is responsible for trying
|
|
* another one by calling init_pollers() again.
|
|
*/
|
|
int fork_poller()
|
|
{
|
|
if (cur_poller.fork) {
|
|
if (cur_poller.fork(&cur_poller))
|
|
return 1;
|
|
cur_poller.term(&cur_poller);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* c-indent-level: 8
|
|
* c-basic-offset: 8
|
|
* End:
|
|
*/
|