I am trying to have systemd start up a daemon and pass it 8,192 listening sockets. I have a .service
and .socket
file that work reliably with a more "normal" number of listening sockets, like this:
# a-daemon.socket
[Unit]
Description=A Daemon (sockets)
After=network.target
[Socket]
Accept=no
ListenStream=8192
# a-daemon.service
[Unit]
Description=A Daemon
After=network.target
Requires=a-daemon.socket
[Install]
WantedBy=multi-user.target
[Service]
Type=notify
ExecStart=/usr/local/sbin/a-daemon
But if I swap out a-daemon.socket
for a version with 8,192 ListenStream
lines, one for each TCP port from 8192 through 16383 inclusive, then the daemon won't start any more. The socket unit can be started just fine, but the service unit fails; the only error message I get is
systemd[17563]: a-daemon.service: Failed to execute command: Argument list too long
systemd[17563]: a-daemon.service: Failed at step EXEC spawning /usr/local/sbin/a-daemon: Argument list too long
As I understand it, this can't actually be a problem with the argument list, because systemd doesn't put the socket fd numbers on the daemon's command line or anything like that. I guessed it was instead a problem with a limit on the number of simultaneous open files, so I set DefaultLimitNOFILE=32768
in /etc/systemd/system.conf
and an equivalent setting in /etc/security/limits.conf
and rebooted. No change. Then I put ExecStartPre=/usr/sbin/prlimit -n
in the .service file and tried to restart it, which confirmed that the increased limit had taken effect:
prlimit[18134]: RESOURCE DESCRIPTION SOFT HARD UNITS
prlimit[18134]: NOFILE max number of open files 32768 32768 files
But the service still fails, the same way. And now I'm out of ideas. Can you suggest anything I could try doing to make this work?
(I am aware that listening on 8,192 consecutive TCP ports is a weird thing to do. Please take my word for it that I have a good reason which I cannot share.)
Upon staring at the systemd manpages some more, I realized that there is something systemd puts in the
argv
area whose size is proportional to the number of listening sockets:(boldface - my emphasis) What this means is, if you have 8192
ListenStream
entries in a socket unit file, systemd will try to putLISTEN_FDNAMES=[name]:[name]:...
, with 8192 repeats, wherename
is theFileDescriptorName
setting, into the environment for the service.FileDescriptorName
defaults to the full basename of the socket unit file. This can easily overflow Linux's fairly low, fixed limit on the length of a single environment variable name+value (MAX_ARG_STRLEN
, usually 128k), and thus causeexecve(2)
to fail withE2BIG
.For a daemon that doesn't care about the names, the cure is to put
in the service file (
[Service]
section). This eliminates the problem environment variable and makes the kernel happy.I don't know what you do if you actually need the fd names for something and you hit this limit.