1

vxlan: Fix racy device stats updates.

VXLAN devices update their stats locklessly. Therefore these counters
should either be stored in per-cpu data structures or the updates
should be done using atomic increments.

Since the net_device_core_stats infrastructure is already used in
vxlan_rcv(), use it for the other rx_dropped and tx_dropped counter
updates. Update the other counters atomically using DEV_STATS_INC().

Fixes: d342894c5d ("vxlan: virtual extensible lan")
Signed-off-by: Guillaume Nault <gnault@redhat.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Guillaume Nault 2024-04-26 17:27:17 +02:00 committed by David S. Miller
parent b867247555
commit 6dee402dab

View File

@ -1766,8 +1766,8 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
skb_reset_network_header(skb); skb_reset_network_header(skb);
if (!vxlan_ecn_decapsulate(vs, oiph, skb)) { if (!vxlan_ecn_decapsulate(vs, oiph, skb)) {
++vxlan->dev->stats.rx_frame_errors; DEV_STATS_INC(vxlan->dev, rx_frame_errors);
++vxlan->dev->stats.rx_errors; DEV_STATS_INC(vxlan->dev, rx_errors);
vxlan_vnifilter_count(vxlan, vni, vninode, vxlan_vnifilter_count(vxlan, vni, vninode,
VXLAN_VNI_STATS_RX_ERRORS, 0); VXLAN_VNI_STATS_RX_ERRORS, 0);
goto drop; goto drop;
@ -1837,7 +1837,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
goto out; goto out;
if (!pskb_may_pull(skb, arp_hdr_len(dev))) { if (!pskb_may_pull(skb, arp_hdr_len(dev))) {
dev->stats.tx_dropped++; dev_core_stats_tx_dropped_inc(dev);
goto out; goto out;
} }
parp = arp_hdr(skb); parp = arp_hdr(skb);
@ -1893,7 +1893,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
reply->pkt_type = PACKET_HOST; reply->pkt_type = PACKET_HOST;
if (netif_rx(reply) == NET_RX_DROP) { if (netif_rx(reply) == NET_RX_DROP) {
dev->stats.rx_dropped++; dev_core_stats_rx_dropped_inc(dev);
vxlan_vnifilter_count(vxlan, vni, NULL, vxlan_vnifilter_count(vxlan, vni, NULL,
VXLAN_VNI_STATS_RX_DROPS, 0); VXLAN_VNI_STATS_RX_DROPS, 0);
} }
@ -2052,7 +2052,7 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
goto out; goto out;
if (netif_rx(reply) == NET_RX_DROP) { if (netif_rx(reply) == NET_RX_DROP) {
dev->stats.rx_dropped++; dev_core_stats_rx_dropped_inc(dev);
vxlan_vnifilter_count(vxlan, vni, NULL, vxlan_vnifilter_count(vxlan, vni, NULL,
VXLAN_VNI_STATS_RX_DROPS, 0); VXLAN_VNI_STATS_RX_DROPS, 0);
} }
@ -2263,7 +2263,7 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
len); len);
} else { } else {
drop: drop:
dev->stats.rx_dropped++; dev_core_stats_rx_dropped_inc(dev);
vxlan_vnifilter_count(dst_vxlan, vni, NULL, vxlan_vnifilter_count(dst_vxlan, vni, NULL,
VXLAN_VNI_STATS_RX_DROPS, 0); VXLAN_VNI_STATS_RX_DROPS, 0);
} }
@ -2295,7 +2295,7 @@ static int encap_bypass_if_local(struct sk_buff *skb, struct net_device *dev,
addr_family, dst_port, addr_family, dst_port,
vxlan->cfg.flags); vxlan->cfg.flags);
if (!dst_vxlan) { if (!dst_vxlan) {
dev->stats.tx_errors++; DEV_STATS_INC(dev, tx_errors);
vxlan_vnifilter_count(vxlan, vni, NULL, vxlan_vnifilter_count(vxlan, vni, NULL,
VXLAN_VNI_STATS_TX_ERRORS, 0); VXLAN_VNI_STATS_TX_ERRORS, 0);
kfree_skb(skb); kfree_skb(skb);
@ -2559,7 +2559,7 @@ out_unlock:
return; return;
drop: drop:
dev->stats.tx_dropped++; dev_core_stats_tx_dropped_inc(dev);
vxlan_vnifilter_count(vxlan, vni, NULL, VXLAN_VNI_STATS_TX_DROPS, 0); vxlan_vnifilter_count(vxlan, vni, NULL, VXLAN_VNI_STATS_TX_DROPS, 0);
dev_kfree_skb(skb); dev_kfree_skb(skb);
return; return;
@ -2567,11 +2567,11 @@ drop:
tx_error: tx_error:
rcu_read_unlock(); rcu_read_unlock();
if (err == -ELOOP) if (err == -ELOOP)
dev->stats.collisions++; DEV_STATS_INC(dev, collisions);
else if (err == -ENETUNREACH) else if (err == -ENETUNREACH)
dev->stats.tx_carrier_errors++; DEV_STATS_INC(dev, tx_carrier_errors);
dst_release(ndst); dst_release(ndst);
dev->stats.tx_errors++; DEV_STATS_INC(dev, tx_errors);
vxlan_vnifilter_count(vxlan, vni, NULL, VXLAN_VNI_STATS_TX_ERRORS, 0); vxlan_vnifilter_count(vxlan, vni, NULL, VXLAN_VNI_STATS_TX_ERRORS, 0);
kfree_skb(skb); kfree_skb(skb);
} }
@ -2604,7 +2604,7 @@ static void vxlan_xmit_nh(struct sk_buff *skb, struct net_device *dev,
return; return;
drop: drop:
dev->stats.tx_dropped++; dev_core_stats_tx_dropped_inc(dev);
vxlan_vnifilter_count(netdev_priv(dev), vni, NULL, vxlan_vnifilter_count(netdev_priv(dev), vni, NULL,
VXLAN_VNI_STATS_TX_DROPS, 0); VXLAN_VNI_STATS_TX_DROPS, 0);
dev_kfree_skb(skb); dev_kfree_skb(skb);
@ -2642,7 +2642,7 @@ static netdev_tx_t vxlan_xmit_nhid(struct sk_buff *skb, struct net_device *dev,
return NETDEV_TX_OK; return NETDEV_TX_OK;
drop: drop:
dev->stats.tx_dropped++; dev_core_stats_tx_dropped_inc(dev);
vxlan_vnifilter_count(netdev_priv(dev), vni, NULL, vxlan_vnifilter_count(netdev_priv(dev), vni, NULL,
VXLAN_VNI_STATS_TX_DROPS, 0); VXLAN_VNI_STATS_TX_DROPS, 0);
dev_kfree_skb(skb); dev_kfree_skb(skb);
@ -2739,7 +2739,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
!is_multicast_ether_addr(eth->h_dest)) !is_multicast_ether_addr(eth->h_dest))
vxlan_fdb_miss(vxlan, eth->h_dest); vxlan_fdb_miss(vxlan, eth->h_dest);
dev->stats.tx_dropped++; dev_core_stats_tx_dropped_inc(dev);
vxlan_vnifilter_count(vxlan, vni, NULL, vxlan_vnifilter_count(vxlan, vni, NULL,
VXLAN_VNI_STATS_TX_DROPS, 0); VXLAN_VNI_STATS_TX_DROPS, 0);
kfree_skb(skb); kfree_skb(skb);