Correct occasional --bind-dynamic synchronization break

Request only one re-read of addresses and/or routes

Previous implementation re-reads systemd addresses exactly the same
number of time equal number of notifications received.
This is not necessary, we need just notification of change, then re-read
the current state and adapt listeners. Repeated re-reading slows netlink
processing and highers CPU usage on mass interface changes.

Continue reading multicast events from netlink, even when ENOBUFS
arrive. Broadcasts are not trusted anyway and refresh would be done in
iface_enumerate. Save queued events sent again.

Remove sleeping on netlink ENOBUFS

With reduced number of written events netlink should receive ENOBUFS
rarely. It does not make sense to wait if it is received. It is just a
signal some packets got missing. Fast reading all pending packets is required,
seq checking ensures it already. Finishes changes by
commit 1d07667ac7.

Move restart from iface_enumerate to enumerate_interfaces

When ENOBUFS is received, restart of reading addresses is done. But
previously found addresses might not have been found this time. In order
to catch this, restart both IPv4 and IPv6 enumeration with clearing
found interfaces first. It should deliver up-to-date state also after
ENOBUFS.

Read all netlink messages before netlink restart

Before writing again into netlink socket, try fetching all pending
messages. They would be ignored, only might trigger new address
synchronization. Should ensure new try has better chance to succeed.

ENOBUFS error handling was improved. Netlink is correctly drained before
sending a new request again. It seems ENOBUFS supression is no longer
necessary or wanted. Let kernel tell us when it failed and handle it a
good way.
This commit is contained in:
Petr Menšík
2021-03-02 18:21:32 +00:00
committed by Simon Kelley
parent d556b8a5d5
commit 4c0aecc685
2 changed files with 58 additions and 28 deletions

View File

@@ -638,7 +638,8 @@ int enumerate_interfaces(int reset)
if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
return 0;
again:
/* Mark interfaces for garbage collection */
for (iface = daemon->interfaces; iface; iface = iface->next)
iface->found = 0;
@@ -690,9 +691,14 @@ int enumerate_interfaces(int reset)
param.spare = spare;
ret = iface_enumerate(AF_INET6, &param, iface_allowed_v6);
if (ret)
ret = iface_enumerate(AF_INET, &param, iface_allowed_v4);
if (ret < 0)
goto again;
else if (ret)
{
ret = iface_enumerate(AF_INET, &param, iface_allowed_v4);
if (ret < 0)
goto again;
}
errsave = errno;
close(param.fd);