]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
vxlan: Add RCU read-side critical sections in the Tx path
authorIdo Schimmel <idosch@nvidia.com>
Tue, 15 Apr 2025 12:11:29 +0000 (15:11 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 9 Sep 2025 16:58:12 +0000 (18:58 +0200)
[ Upstream commit 804b09be09f8af4eda5346a72361459ba21fcf1b ]

The Tx path does not run from an RCU read-side critical section which
makes the current lockless accesses to FDB entries invalid. As far as I
am aware, this has not been a problem in practice, but traces will be
generated once we transition the FDB lookup to rhashtable_lookup().

Add rcu_read_{lock,unlock}() around the handling of FDB entries in the
Tx path. Remove the RCU read-side critical section from vxlan_xmit_nh()
as now the function is always called from an RCU read-side critical
section.

Reviewed-by: Petr Machata <petrm@nvidia.com>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20250415121143.345227-2-idosch@nvidia.com
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Stable-dep-of: 1f5d2fd1ca04 ("vxlan: Fix NPD in {arp,neigh}_reduce() when using nexthop objects")
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/vxlan/vxlan_core.c

index 8853fcb7eb7f2df814c1234311567123690bbc8f..1d431e3fc71ea7555526eb90153dfbdf9774e681 100644 (file)
@@ -1909,12 +1909,15 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
                        goto out;
                }
 
+               rcu_read_lock();
                f = vxlan_find_mac(vxlan, n->ha, vni);
                if (f && vxlan_addr_any(&(first_remote_rcu(f)->remote_ip))) {
                        /* bridge-local neighbor */
                        neigh_release(n);
+                       rcu_read_unlock();
                        goto out;
                }
+               rcu_read_unlock();
 
                reply = arp_create(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha,
                                n->ha, sha);
@@ -2632,14 +2635,10 @@ static void vxlan_xmit_nh(struct sk_buff *skb, struct net_device *dev,
        memset(&nh_rdst, 0, sizeof(struct vxlan_rdst));
        hash = skb_get_hash(skb);
 
-       rcu_read_lock();
        nh = rcu_dereference(f->nh);
-       if (!nh) {
-               rcu_read_unlock();
+       if (!nh)
                goto drop;
-       }
        do_xmit = vxlan_fdb_nh_path_select(nh, hash, &nh_rdst);
-       rcu_read_unlock();
 
        if (likely(do_xmit))
                vxlan_xmit_one(skb, dev, vni, &nh_rdst, did_rsc);
@@ -2766,6 +2765,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        eth = eth_hdr(skb);
+       rcu_read_lock();
        f = vxlan_find_mac(vxlan, eth->h_dest, vni);
        did_rsc = false;
 
@@ -2788,7 +2788,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
                        vxlan_vnifilter_count(vxlan, vni, NULL,
                                              VXLAN_VNI_STATS_TX_DROPS, 0);
                        kfree_skb_reason(skb, SKB_DROP_REASON_NO_TX_TARGET);
-                       return NETDEV_TX_OK;
+                       goto out;
                }
        }
 
@@ -2813,6 +2813,8 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
                        kfree_skb_reason(skb, SKB_DROP_REASON_NO_TX_TARGET);
        }
 
+out:
+       rcu_read_unlock();
        return NETDEV_TX_OK;
 }