]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: fd: add a new "exported" flag and use it for all regular listeners
authorWilly Tarreau <w@1wt.eu>
Wed, 19 Aug 2020 08:00:57 +0000 (10:00 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 26 Aug 2020 16:33:52 +0000 (18:33 +0200)
This new flag will be used to mark FDs that must be passed to any future
process across the CLI's "_getsocks" command.

The scheme here is quite complex and full of special cases:
  - FDs inherited from parent processes are *not* exported this way, as
    they are supposed to instead be passed by the master process itself
    across reloads. However such FDs ought never to be paused otherwise
    this would disrupt the socket in the parent process as well;

  - FDs resulting from a "bind" performed over a socket pair, which are
    in fact one side of a socket pair passed inside another control socket
    pair must not be passed either. Since all of them are used the same
    way, for now it's enough never to put this "exported" flag to FDs
    bound by the socketpair code.

  - FDs belonging to temporary listeners (e.g. a passive FTP data port)
    must not be passed either. Fortunately we don't have such FDs yet.

  - the rest of the listeners for now are made of TCP, UNIX stream, ABNS
    sockets and are exportable, so they get the flag.

  - UDP listeners were wrongly created as listeners and are not suitable
    here. Their FDs should be passed but for now they are not since the
    client doesn't even distinguish the SO_TYPE of the retrieved sockets.

In addition, it's important to keep in mind that:
  - inherited FDs may never be closed in master process but may be closed
    in worker processes if the service is shut down (useless since still
    bound, but technically possible) ;

  - inherited FDs may not be disabled ;

  - exported FDs may be disabled because the caller will perform the
    subsequent listen() on them. However that might not work for all OSes

  - exported FDs may be closed, it just means the service was shut down
    from the worker, and will be rebound in the new process. This implies
    that we have to disable exported on close().

=> as such, contrary to an apparently obvious equivalence, the "exported"
   status doesn't imply anything regarding the ability to close a
   listener's FD or not.

include/haproxy/fd-t.h
include/haproxy/fd.h
src/fd.c
src/proto_tcp.c
src/proto_uxst.c

index 6ff8ef135dfc749737729eb6734d8b683b211ce9..2b51125c929dcd3ed8972e47cb82753d81c719c7 100644 (file)
@@ -134,6 +134,7 @@ struct fdtab {
        unsigned char cloned:1;              /* 1 if a cloned socket, requires EPOLL_CTL_DEL on close */
        unsigned char initialized:1;         /* 1 if init phase was done on this fd (e.g. set non-blocking) */
        unsigned char et_possible:1;         /* 1 if edge-triggered is possible on this FD */
+       unsigned char exported:1;            /* 1 if the FD is exported and must not be closed */
 #ifdef DEBUG_FD
        unsigned int event_count;            /* number of events reported */
 #endif
index 240842a18d5e2e0d2c2ad29191fe81ccac060b03..6f0401e02c3f3eb937cc3c979e1477c4a5184633 100644 (file)
@@ -441,6 +441,7 @@ static inline void fd_insert(int fd, void *owner, void (*iocb)(int fd), unsigned
        fdtab[fd].linger_risk = 0;
        fdtab[fd].cloned = 0;
        fdtab[fd].et_possible = 0;
+       fdtab[fd].exported = 0;
 #ifdef DEBUG_FD
        fdtab[fd].event_count = 0;
 #endif
index 86c2d43598cedf97346e6e375aeb7aa8ee11cae7..c72dddd823516df19b04f7cff55d36f5cdf1f33a 100644 (file)
--- a/src/fd.c
+++ b/src/fd.c
@@ -329,6 +329,7 @@ void fd_delete(int fd)
        fdinfo[fd].port_range = NULL;
        fdtab[fd].owner = NULL;
        fdtab[fd].thread_mask = 0;
+       fdtab[fd].exported = 0;
        close(fd);
        _HA_ATOMIC_SUB(&ha_used_fds, 1);
        if (locked)
index 2f8ec22e8ef321db2a7ce010026e535f467e9250..98a6310d095b8457a9fc7a94c9a869ba20ab1d95 100644 (file)
@@ -1114,6 +1114,10 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
        fd_insert(fd, listener, listener->proto->accept,
                  thread_mask(listener->bind_conf->bind_thread) & all_threads_mask);
 
+       /* for now, all regularly bound TCP listeners are exportable */
+       if (!(listener->options & LI_O_INHERITED))
+               fdtab[fd].exported = 1;
+
  tcp_return:
        if (msg && errlen) {
                char pn[INET6_ADDRSTRLEN];
index 586b11931c32e2c2f6d11fed237c9409287f8967..2a4610f68a8014962eb203596a6ce49751b03894 100644 (file)
@@ -352,6 +352,10 @@ static int uxst_bind_listener(struct listener *listener, char *errmsg, int errle
        fd_insert(fd, listener, listener->proto->accept,
                  thread_mask(listener->bind_conf->bind_thread) & all_threads_mask);
 
+       /* for now, all regularly bound UNIX listeners are exportable */
+       if (!(listener->options & LI_O_INHERITED))
+               fdtab[fd].exported = 1;
+
        return err;
 
  err_rename: