neigh_table is now per-netns. tbl->managed_work is scheduled when netns is created and runs periodically even though the netns does not have any NTF_MANAGED entries. Let's delay scheduling the work for the first NTF_MANAGED entry and stop rescheduling if tbl->managed_list is empty. Suggested-by: Ido Schimmel Link: https://lore.kernel.org/netdev/20260902143023.GA3966681@shredder/ Signed-off-by: Kuniyuki Iwashima --- net/core/neighbour.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 90335895b415..6b0569aa5d64 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -184,6 +184,15 @@ static void neigh_update_gc_list(struct neighbour *n) } } +static void neigh_add_managed_list(struct neighbour *n) +{ + list_add_tail(&n->managed_list, &n->tbl->managed_list); + + if (list_is_singular(&n->tbl->managed_list)) + queue_delayed_work(system_power_efficient_wq, + &n->tbl->managed_work, 0); +} + static void neigh_update_managed_list(struct neighbour *n) { bool on_managed_list, add_to_managed; @@ -194,7 +203,7 @@ static void neigh_update_managed_list(struct neighbour *n) if (!add_to_managed && on_managed_list) list_del_init(&n->managed_list); else if (add_to_managed && !on_managed_list) - list_add_tail(&n->managed_list, &n->tbl->managed_list); + neigh_add_managed_list(n); } static void neigh_update_flags(struct neighbour *neigh, u32 flags, int *notify, @@ -708,7 +717,7 @@ ___neigh_create(struct neigh_table *tbl, const void *pkey, if (!exempt_from_gc) list_add_tail(&n->gc_list, &n->tbl->gc_list); if (n->flags & NTF_MANAGED) - list_add_tail(&n->managed_list, &n->tbl->managed_list); + neigh_add_managed_list(n); if (want_ref) neigh_hold(n); hlist_add_head_rcu(&n->hash, &nht->hash_heads[hash_val]); @@ -1670,10 +1679,14 @@ static void neigh_managed_work(struct work_struct *work) struct neighbour *neigh; spin_lock_bh(&tbl->lock); + list_for_each_entry(neigh, &tbl->managed_list, managed_list) neigh_event_send_probe(neigh, NULL, false); - queue_delayed_work(system_power_efficient_wq, &tbl->managed_work, - NEIGH_VAR(&tbl->parms, INTERVAL_PROBE_TIME_MS)); + + if (!list_empty(&tbl->managed_list)) + queue_delayed_work(system_power_efficient_wq, &tbl->managed_work, + NEIGH_VAR(&tbl->parms, INTERVAL_PROBE_TIME_MS)); + spin_unlock_bh(&tbl->lock); } @@ -1873,7 +1886,6 @@ static int neigh_table_init(struct net *net, struct neigh_table *tbl) INIT_LIST_HEAD(&tbl->managed_list); INIT_DEFERRABLE_WORK(&tbl->managed_work, neigh_managed_work); - queue_delayed_work(system_power_efficient_wq, &tbl->managed_work, 0); return 0; -- 2.56.0.385.gd3acb90ef8-goog