MEDIUM: reload: pass all exportable FDs, not just listeners
Now we don't limit ourselves to listeners found in proxies nor peers anymore, we're instead scanning all known FDs for those marked with ".exported=1". Just doing so has significantly simplified the code, and will later allow to yield while sending FDs if desired. When it comes to retrieving a possible namespace name or interface name, for now this is only performed on listeners since these are the only ones carrying such info. Once this moves somewhere else, we'll be able to also pass these info for UDP receivers for example, with only tiny changes.
This commit is contained in:
parent
bb1caff70f
commit
b5a1f9e495
203
src/cli.c
203
src/cli.c
@ -1598,82 +1598,6 @@ static int bind_parse_severity_output(char **args, int cur_arg, struct proxy *px
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For one proxy, fill the iov and send the msghdr. Also update fd_it and offset.
|
||||
* Return -1 upon error, otherwise 0.
|
||||
*
|
||||
* This function is only meant to deduplicate the code between the peers and
|
||||
* the proxy list in _getsocks(), not to be used anywhere else.
|
||||
*/
|
||||
inline static int _getsocks_gen_send(struct proxy *px, int sendfd, int *tmpfd, struct iovec *iov,
|
||||
int tot_fd_nb, int *fd_it, int *offset, struct msghdr *msghdr)
|
||||
{
|
||||
int i = *fd_it;
|
||||
int curoff = *offset;
|
||||
struct listener *l;
|
||||
unsigned char *tmpbuf = iov->iov_base;
|
||||
|
||||
list_for_each_entry(l, &px->conf.listeners, by_fe) {
|
||||
int ret;
|
||||
/* Only transfer IPv4/IPv6 sockets */
|
||||
if (l->state >= LI_ZOMBIE &&
|
||||
(l->proto->sock_family == AF_INET ||
|
||||
l->proto->sock_family == AF_INET6 ||
|
||||
l->proto->sock_family == AF_UNIX)) {
|
||||
memcpy(&tmpfd[i % MAX_SEND_FD], &l->fd, sizeof(l->fd));
|
||||
if (!l->netns)
|
||||
tmpbuf[curoff++] = 0;
|
||||
#ifdef USE_NS
|
||||
else {
|
||||
char *name = l->netns->node.key;
|
||||
unsigned char len = l->netns->name_len;
|
||||
tmpbuf[curoff++] = len;
|
||||
memcpy(tmpbuf + curoff, name, len);
|
||||
curoff += len;
|
||||
}
|
||||
#endif
|
||||
if (l->interface) {
|
||||
unsigned char len = strlen(l->interface);
|
||||
tmpbuf[curoff++] = len;
|
||||
memcpy(tmpbuf + curoff, l->interface, len);
|
||||
curoff += len;
|
||||
} else
|
||||
tmpbuf[curoff++] = 0;
|
||||
|
||||
/* we used to send the listener options here before 2.3 */
|
||||
memset(tmpbuf + curoff, 0, sizeof(int));
|
||||
curoff += sizeof(int);
|
||||
|
||||
i++;
|
||||
} else
|
||||
continue;
|
||||
/* if it reaches the max number of fd per msghdr */
|
||||
if ((!(i % MAX_SEND_FD))) {
|
||||
iov->iov_len = curoff;
|
||||
if (sendmsg(sendfd, msghdr, 0) != curoff) {
|
||||
ha_warning("Failed to transfer sockets\n");
|
||||
return -1;
|
||||
}
|
||||
/* Wait for an ack */
|
||||
do {
|
||||
ret = recv(sendfd, &tot_fd_nb,
|
||||
sizeof(tot_fd_nb), 0);
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
if (ret <= 0) {
|
||||
ha_warning("Unexpected error while transferring sockets\n");
|
||||
return -1;
|
||||
}
|
||||
curoff = 0;
|
||||
}
|
||||
}
|
||||
|
||||
*fd_it = i;
|
||||
*offset = curoff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Send all the bound sockets, always returns 1 */
|
||||
static int _getsocks(char **args, char *payload, struct appctx *appctx, void *private)
|
||||
{
|
||||
@ -1686,11 +1610,12 @@ static int _getsocks(char **args, char *payload, struct appctx *appctx, void *pr
|
||||
struct msghdr msghdr;
|
||||
struct iovec iov;
|
||||
struct timeval tv = { .tv_sec = 1, .tv_usec = 0 };
|
||||
const char *ns_name, *if_name;
|
||||
unsigned char ns_nlen, if_nlen;
|
||||
int nb_queued;
|
||||
int cur_fd = 0;
|
||||
int *tmpfd;
|
||||
int tot_fd_nb = 0;
|
||||
struct proxy *px;
|
||||
struct peers *prs;
|
||||
int i = 0;
|
||||
int fd = -1;
|
||||
int curoff = 0;
|
||||
int old_fcntl = -1;
|
||||
@ -1728,36 +1653,9 @@ static int _getsocks(char **args, char *payload, struct appctx *appctx, void *pr
|
||||
* First, calculates the total number of FD, so that we can let
|
||||
* the caller know how much it should expect.
|
||||
*/
|
||||
px = proxies_list;
|
||||
while (px) {
|
||||
struct listener *l;
|
||||
for (cur_fd = 0;cur_fd < global.maxsock; cur_fd++)
|
||||
tot_fd_nb += fdtab[cur_fd].exported;
|
||||
|
||||
list_for_each_entry(l, &px->conf.listeners, by_fe) {
|
||||
/* Only transfer IPv4/IPv6/UNIX sockets */
|
||||
if (l->state >= LI_ZOMBIE &&
|
||||
(l->proto->sock_family == AF_INET ||
|
||||
l->proto->sock_family == AF_INET6 ||
|
||||
l->proto->sock_family == AF_UNIX))
|
||||
tot_fd_nb++;
|
||||
}
|
||||
px = px->next;
|
||||
}
|
||||
prs = cfg_peers;
|
||||
while (prs) {
|
||||
if (prs->peers_fe) {
|
||||
struct listener *l;
|
||||
|
||||
list_for_each_entry(l, &prs->peers_fe->conf.listeners, by_fe) {
|
||||
/* Only transfer IPv4/IPv6/UNIX sockets */
|
||||
if (l->state >= LI_ZOMBIE &&
|
||||
(l->proto->sock_family == AF_INET ||
|
||||
l->proto->sock_family == AF_INET6 ||
|
||||
l->proto->sock_family == AF_UNIX))
|
||||
tot_fd_nb++;
|
||||
}
|
||||
}
|
||||
prs = prs->next;
|
||||
}
|
||||
if (tot_fd_nb == 0)
|
||||
goto out;
|
||||
|
||||
@ -1796,28 +1694,81 @@ static int _getsocks(char **args, char *payload, struct appctx *appctx, void *pr
|
||||
ha_warning("Failed to allocate memory to transfer socket information\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
nb_queued = 0;
|
||||
iov.iov_base = tmpbuf;
|
||||
px = proxies_list;
|
||||
while (px) {
|
||||
if (_getsocks_gen_send(px, fd, tmpfd, &iov,
|
||||
tot_fd_nb, &i, &curoff, &msghdr) < 0)
|
||||
goto out;
|
||||
px = px->next;
|
||||
}
|
||||
/* should be done for peers too */
|
||||
prs = cfg_peers;
|
||||
while (prs) {
|
||||
if (prs->peers_fe)
|
||||
if (_getsocks_gen_send(prs->peers_fe, fd, tmpfd, &iov,
|
||||
tot_fd_nb, &i, &curoff, &msghdr) < 0)
|
||||
goto out;
|
||||
prs = prs->next;
|
||||
for (cur_fd = 0; cur_fd < global.maxsock; cur_fd++) {
|
||||
if (!(fdtab[cur_fd].exported))
|
||||
continue;
|
||||
|
||||
ns_name = if_name = "";
|
||||
ns_nlen = if_nlen = 0;
|
||||
|
||||
/* for now we can only retrieve namespaces and interfaces from
|
||||
* pure listeners.
|
||||
*/
|
||||
if (fdtab[cur_fd].iocb == listener_accept) {
|
||||
const struct listener *l = fdtab[cur_fd].owner;
|
||||
|
||||
if (l->interface) {
|
||||
if_name = l->interface;
|
||||
if_nlen = strlen(if_name);
|
||||
}
|
||||
|
||||
#ifdef USE_NS
|
||||
if (l->netns) {
|
||||
ns_name = l->netns->node.key;
|
||||
ns_nlen = l->netns->name_len;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* put the FD into the CMSG_DATA */
|
||||
tmpfd[nb_queued++] = cur_fd;
|
||||
|
||||
/* first block is <ns_name_len> <ns_name> */
|
||||
tmpbuf[curoff++] = ns_nlen;
|
||||
if (ns_nlen)
|
||||
memcpy(tmpbuf + curoff, ns_name, ns_nlen);
|
||||
curoff += ns_nlen;
|
||||
|
||||
/* second block is <if_name_len> <if_name> */
|
||||
tmpbuf[curoff++] = if_nlen;
|
||||
if (if_nlen)
|
||||
memcpy(tmpbuf + curoff, if_name, if_nlen);
|
||||
curoff += if_nlen;
|
||||
|
||||
/* we used to send the listener options here before 2.3 */
|
||||
memset(tmpbuf + curoff, 0, sizeof(int));
|
||||
curoff += sizeof(int);
|
||||
|
||||
/* there's a limit to how many FDs may be sent at once */
|
||||
if (nb_queued == MAX_SEND_FD) {
|
||||
iov.iov_len = curoff;
|
||||
if (sendmsg(fd, &msghdr, 0) != curoff) {
|
||||
ha_warning("Failed to transfer sockets\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Wait for an ack */
|
||||
do {
|
||||
ret = recv(fd, &tot_fd_nb, sizeof(tot_fd_nb), 0);
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
|
||||
if (ret <= 0) {
|
||||
ha_warning("Unexpected error while transferring sockets\n");
|
||||
return -1;
|
||||
}
|
||||
curoff = 0;
|
||||
nb_queued = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (i % MAX_SEND_FD) {
|
||||
/* flush pending stuff */
|
||||
if (nb_queued) {
|
||||
iov.iov_len = curoff;
|
||||
cmsg->cmsg_len = CMSG_LEN((i % MAX_SEND_FD) * sizeof(int));
|
||||
msghdr.msg_controllen = CMSG_SPACE(sizeof(int) * (i % MAX_SEND_FD));
|
||||
cmsg->cmsg_len = CMSG_LEN(nb_queued * sizeof(int));
|
||||
msghdr.msg_controllen = CMSG_SPACE(nb_queued * sizeof(int));
|
||||
if (sendmsg(fd, &msghdr, 0) != curoff) {
|
||||
ha_warning("Failed to transfer sockets\n");
|
||||
goto out;
|
||||
|
Loading…
x
Reference in New Issue
Block a user