From: Petr Machata Date: Wed, 21 Jan 2026 16:43:42 +0000 (+0100) Subject: net: core: neighbour: Make another netlink notification atomically X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a00266969c8ecaa15d8170490e407131287d7a71;p=thirdparty%2Fkernel%2Flinux.git net: core: neighbour: Make another netlink notification atomically Similarly to the issue from the previous patch, neigh_timer_handler() also updates the neighbor separately from formatting and sending the netlink notification message. We have not seen reports to the effect of this causing trouble, but in theory, the same sort of issues could have come up: neigh_timer_handler() would make changes as necessary, but before formatting and sending a notification, is interrupted before sending by another thread, which makes a parallel change and sends its own message. The message send that is prompted by an earlier change thus contains information that does not reflect the change having been made. To solve this, the netlink notification needs to be in the same critical section that updates the neighbor. The critical section is ended by the neigh_probe() call which drops the lock before calling solicit. Stretching the critical section over the solicit call is problematic, because that can then involved all sorts of forwarding callbacks. Therefore, like in the previous patch, split the netlink notification away from the internal one and move it ahead of the probe call. Signed-off-by: Petr Machata Reviewed-by: Ido Schimmel Reviewed-by: Simon Horman Link: https://patch.msgid.link/e440118511cbdbe1d88eb0d71c9047116feb96e0.1769012464.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 1d7489f50b21b..e0897eb41c8d2 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1104,6 +1104,7 @@ static void neigh_timer_handler(struct timer_list *t) { unsigned long now, next; struct neighbour *neigh = timer_container_of(neigh, t, timer); + bool skip_probe = false; unsigned int state; int notify = 0; @@ -1171,9 +1172,15 @@ static void neigh_timer_handler(struct timer_list *t) neigh_invalidate(neigh); } notify = 1; - goto out; + skip_probe = true; } + if (notify) + __neigh_notify(neigh, RTM_NEWNEIGH, 0, 0); + + if (skip_probe) + goto out; + if (neigh->nud_state & NUD_IN_TIMER) { if (time_before(next, jiffies + HZ/100)) next = jiffies + HZ/100; @@ -1187,10 +1194,8 @@ out: write_unlock(&neigh->lock); } - if (notify) { - neigh_notify(neigh, RTM_NEWNEIGH, 0, 0); + if (notify) call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh); - } trace_neigh_timer_handler(neigh, 0);