This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
---
net: sparx5: add neighbour event handling for L3 routing
Register a netevent notifier to handle NETEVENT_NEIGH_UPDATE events.
This completes the L3 unicast forwarding data path by updating hardware
ARP table entries and linked nexthops when neighbours are resolved.
> diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_router.c
> b/drivers/net/ethernet/microchip/sparx5/sparx5_router.c
> --- a/drivers/net/ethernet/microchip/sparx5/sparx5_router.c
> +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_router.c
[ ... ]
> @@ -2525,6 +2525,104 @@ static int sparx5_rr_fib_event(struct notifier_block
> *nb, unsigned long event,
> +static void sparx5_rr_neigh_event_work(struct work_struct *work)
> +{
[ ... ]
> + if (entry->connected && entry_connected &&
> + ether_addr_equal(entry->hwaddr, hwaddr))
> + goto out_mutex;
> +
> + ether_addr_copy(entry->hwaddr, hwaddr);
> + sparx5_rr_neigh_entry_update(sparx5, entry, entry_connected);
[Severity: High]
Does this code risk re-offloading an orphaned neighbour entry with a stale
VMID?
When a subnet route is deleted, the fib_entry is destroyed. This unlinks the
neigh_entries, sets neigh_entry->fib_entry to NULL, and un-offloads them.
However, if another nexthop still references this neighbour,
sparx5_rr_neigh_entry_put() skips destruction.
The interface's router leg might then be destroyed, freeing its VMID for
reuse.
If an ARP update arrives later, this code finds the orphaned neigh_entry and
calls sparx5_rr_neigh_entry_update() to offload it again. This could apply a
hardware VCAP rule using the potentially reassigned VMID.
Also, because this sets vrule_id_valid to true, when the referencing nexthop
is eventually deleted, sparx5_rr_neigh_entry_put() will refuse to destroy it.
Since fib_entry is NULL, it won't be found during module unload, permanently
leaking the memory and the netdevice tracker reference.
> + sparx5_rr_nexthops_update_notify(sparx5, entry, entry_connected);
> + if (!entry_connected)
> + sparx5_rr_neigh_entry_put(sparx5, entry);
> +
> +out_mutex:
> + mutex_unlock(&sparx5->router->lock);
> +out:
> + neigh_release(n);
> + kfree(net_work);
> +}
[ ... ]
> +static int sparx5_rr_netevent_event(struct notifier_block *nb,
> + unsigned long event, void *ptr)
> +{
[ ... ]
> + switch (event) {
> + case NETEVENT_NEIGH_UPDATE:
> + n = ptr;
> +
> + if (n->tbl->family != AF_INET && n->tbl->family != AF_INET6)
> + return NOTIFY_DONE;
> +
> + port = sparx5_port_dev_lower_find(n->dev);
> + if (!port)
> + return NOTIFY_DONE;
> +
> + net_work = kzalloc_obj(*net_work, GFP_ATOMIC);
> + if (!net_work)
> + return NOTIFY_BAD;
[Severity: High]
Could returning NOTIFY_BAD on allocation failure interrupt the global
notification chain?
The NETEVENT_NEIGH_UPDATE event is broadcast to all registered listeners via
the netevent_notif_chain atomic notifier chain. Returning NOTIFY_BAD from the
notifier callback prematurely aborts the chain traversal.
If this allocation fails, it appears this driver will silently prevent all
subsequent subsystems and drivers from receiving the neighbour update, which
might cause system-wide stale ARP/NDP caches.
Should this return NOTIFY_DONE instead?
> +
> + INIT_WORK(&net_work->work, sparx5_rr_neigh_event_work);
> + net_work->sparx5 = router->sparx5;
> + net_work->neigh = neigh_clone(n);