Skip to content

Commit 9b7d4f4

Browse files
committed
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.
1 parent cfcafdd commit 9b7d4f4

File tree

1 file changed

+26
-10
lines changed

1 file changed

+26
-10
lines changed

src/netlink.c

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,20 @@
4141

4242
#ifndef NDA_RTA
4343
# define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
44-
#endif
44+
#endif
45+
46+
/* Used to request refresh of addresses or routes just once,
47+
* when multiple changes might be announced. */
48+
enum async_states {
49+
STATE_NEWADDR = (1 << 0),
50+
STATE_NEWROUTE = (1 << 1),
51+
};
4552

4653

4754
static struct iovec iov;
4855
static u32 netlink_pid;
4956

50-
static void nl_async(struct nlmsghdr *h);
57+
static unsigned nl_async(struct nlmsghdr *h, unsigned state);
5158

5259
char *netlink_init(void)
5360
{
@@ -159,6 +166,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
159166
ssize_t len;
160167
static unsigned int seq = 0;
161168
int callback_ok = 1;
169+
unsigned state = 0;
162170

163171
struct {
164172
struct nlmsghdr nlh;
@@ -207,7 +215,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
207215
if (h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
208216
{
209217
/* May be multicast arriving async */
210-
nl_async(h);
218+
state = nl_async(h, state);
211219
}
212220
else if (h->nlmsg_seq != seq)
213221
{
@@ -346,29 +354,30 @@ void netlink_multicast(void)
346354
ssize_t len;
347355
struct nlmsghdr *h;
348356
int flags;
357+
unsigned state = 0;
349358

350359
/* don't risk blocking reading netlink messages here. */
351360
if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
352361
fcntl(daemon->netlinkfd, F_SETFL, flags | O_NONBLOCK) == -1)
353362
return;
354363

355-
if ((len = netlink_recv()) != -1)
364+
while ((len = netlink_recv()) != -1)
356365
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
357-
nl_async(h);
366+
state = nl_async(h, state);
358367

359368
/* restore non-blocking status */
360369
fcntl(daemon->netlinkfd, F_SETFL, flags);
361370
}
362371

363-
static void nl_async(struct nlmsghdr *h)
372+
static unsigned nl_async(struct nlmsghdr *h, unsigned state)
364373
{
365374
if (h->nlmsg_type == NLMSG_ERROR)
366375
{
367376
struct nlmsgerr *err = NLMSG_DATA(h);
368377
if (err->error != 0)
369378
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
370379
}
371-
else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE)
380+
else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE && (state & STATE_NEWROUTE)==0)
372381
{
373382
/* We arrange to receive netlink multicast messages whenever the network route is added.
374383
If this happens and we still have a DNS packet in the buffer, we re-send it.
@@ -380,10 +389,17 @@ static void nl_async(struct nlmsghdr *h)
380389
if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK &&
381390
(rtm->rtm_table == RT_TABLE_MAIN ||
382391
rtm->rtm_table == RT_TABLE_LOCAL))
383-
queue_event(EVENT_NEWROUTE);
392+
{
393+
queue_event(EVENT_NEWROUTE);
394+
state |= STATE_NEWROUTE;
395+
}
396+
}
397+
else if ((state & STATE_NEWADDR)==0 && (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR))
398+
{
399+
queue_event(EVENT_NEWADDR);
400+
state |= STATE_NEWADDR;
384401
}
385-
else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
386-
queue_event(EVENT_NEWADDR);
402+
return state;
387403
}
388404
#endif
389405

0 commit comments

Comments
 (0)