* [PATCH 6.6.y 2/5] net: core,vrf: Change pcpu_dstat fields to u64_stats_t
2026-08-12 9:11 ` [PATCH 6.6.y 1/5] vxlan: Do not alloc tstats manually Sasha Levin
@ 2026-08-12 9:11 ` Sasha Levin
2026-08-12 9:11 ` [PATCH 6.6.y 3/5] vrf: Make pcpu_dstats update functions available to other modules Sasha Levin
` (2 subsequent siblings)
3 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2026-08-12 9:11 UTC (permalink / raw)
To: stable; +Cc: Jeremy Kerr, Simon Horman, David Ahern, Jakub Kicinski,
Sasha Levin
From: Jeremy Kerr <jk@codeconstruct.com.au>
[ Upstream commit fa59dc2f6fc616fde3941f62ccd4adcaa21ccd47 ]
The pcpu_sw_netstats and pcpu_lstats structs both contain a set of
u64_stats_t fields for individual stats, but pcpu_dstats uses u64s
instead.
Make this consistent by using u64_stats_t across all stats types.
The per-cpu dstats are only used by the vrf driver at present, so update
that driver as part of this change.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: David Ahern <dsahern@kernel.org>
Link: https://lore.kernel.org/r/20240607-dstats-v3-1-cc781fe116f7@codeconstruct.com.au
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: b9553558b48d ("vxlan: use pskb_network_may_pull() for transmit path header pulls")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/vrf.c | 38 ++++++++++++++++++++++----------------
include/linux/netdevice.h | 12 ++++++------
2 files changed, 28 insertions(+), 22 deletions(-)
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index bce55ad2bcd99..98140bff0e314 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -126,8 +126,8 @@ static void vrf_rx_stats(struct net_device *dev, int len)
struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
u64_stats_update_begin(&dstats->syncp);
- dstats->rx_packets++;
- dstats->rx_bytes += len;
+ u64_stats_inc(&dstats->rx_packets);
+ u64_stats_add(&dstats->rx_bytes, len);
u64_stats_update_end(&dstats->syncp);
}
@@ -150,11 +150,11 @@ static void vrf_get_stats64(struct net_device *dev,
dstats = per_cpu_ptr(dev->dstats, i);
do {
start = u64_stats_fetch_begin(&dstats->syncp);
- tbytes = dstats->tx_bytes;
- tpkts = dstats->tx_packets;
- tdrops = dstats->tx_drops;
- rbytes = dstats->rx_bytes;
- rpkts = dstats->rx_packets;
+ tbytes = u64_stats_read(&dstats->tx_bytes);
+ tpkts = u64_stats_read(&dstats->tx_packets);
+ tdrops = u64_stats_read(&dstats->tx_drops);
+ rbytes = u64_stats_read(&dstats->rx_bytes);
+ rpkts = u64_stats_read(&dstats->rx_packets);
} while (u64_stats_fetch_retry(&dstats->syncp, start));
stats->tx_bytes += tbytes;
stats->tx_packets += tpkts;
@@ -408,10 +408,15 @@ static int vrf_local_xmit(struct sk_buff *skb, struct net_device *dev,
skb->protocol = eth_type_trans(skb, dev);
- if (likely(__netif_rx(skb) == NET_RX_SUCCESS))
+ if (likely(__netif_rx(skb) == NET_RX_SUCCESS)) {
vrf_rx_stats(dev, len);
- else
- this_cpu_inc(dev->dstats->rx_drops);
+ } else {
+ struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
+
+ u64_stats_update_begin(&dstats->syncp);
+ u64_stats_inc(&dstats->rx_drops);
+ u64_stats_update_end(&dstats->syncp);
+ }
return NETDEV_TX_OK;
}
@@ -599,19 +604,20 @@ static netdev_tx_t is_ip_tx_frame(struct sk_buff *skb, struct net_device *dev)
static netdev_tx_t vrf_xmit(struct sk_buff *skb, struct net_device *dev)
{
+ struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
+
int len = skb->len;
netdev_tx_t ret = is_ip_tx_frame(skb, dev);
+ u64_stats_update_begin(&dstats->syncp);
if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
- struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
- u64_stats_update_begin(&dstats->syncp);
- dstats->tx_packets++;
- dstats->tx_bytes += len;
- u64_stats_update_end(&dstats->syncp);
+ u64_stats_inc(&dstats->tx_packets);
+ u64_stats_add(&dstats->tx_bytes, len);
} else {
- this_cpu_inc(dev->dstats->tx_drops);
+ u64_stats_inc(&dstats->tx_drops);
}
+ u64_stats_update_end(&dstats->syncp);
return ret;
}
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 74474139fb9ac..dfba3cec76b49 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2746,12 +2746,12 @@ struct pcpu_sw_netstats {
} __aligned(4 * sizeof(u64));
struct pcpu_dstats {
- u64 rx_packets;
- u64 rx_bytes;
- u64 rx_drops;
- u64 tx_packets;
- u64 tx_bytes;
- u64 tx_drops;
+ u64_stats_t rx_packets;
+ u64_stats_t rx_bytes;
+ u64_stats_t rx_drops;
+ u64_stats_t tx_packets;
+ u64_stats_t tx_bytes;
+ u64_stats_t tx_drops;
struct u64_stats_sync syncp;
} __aligned(8 * sizeof(u64));
--
2.53.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 6.6.y 3/5] vrf: Make pcpu_dstats update functions available to other modules.
2026-08-12 9:11 ` [PATCH 6.6.y 1/5] vxlan: Do not alloc tstats manually Sasha Levin
2026-08-12 9:11 ` [PATCH 6.6.y 2/5] net: core,vrf: Change pcpu_dstat fields to u64_stats_t Sasha Levin
@ 2026-08-12 9:11 ` Sasha Levin
2026-08-12 9:11 ` [PATCH 6.6.y 4/5] vxlan: Handle stats using NETDEV_PCPU_STAT_DSTATS Sasha Levin
2026-08-12 9:11 ` [PATCH 6.6.y 5/5] vxlan: use pskb_network_may_pull() for transmit path header pulls Sasha Levin
3 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2026-08-12 9:11 UTC (permalink / raw)
To: stable; +Cc: Guillaume Nault, Jakub Kicinski, Sasha Levin
From: Guillaume Nault <gnault@redhat.com>
[ Upstream commit 18eabadd73ae60023ab05e376246bd725fb0c113 ]
Currently vrf is the only module that uses NETDEV_PCPU_STAT_DSTATS.
In order to make this kind of statistics available to other modules,
we need to define the update functions in netdevice.h.
Therefore, let's define dev_dstats_*() functions for RX and TX packet
updates (packets, bytes and drops). Use these new functions in vrf.c
instead of vrf_rx_stats() and the other manual counter updates.
While there, update the type of the "len" variables to "unsigned int",
so that there're aligned with both skb->len and the new dstats update
functions.
Signed-off-by: Guillaume Nault <gnault@redhat.com>
Link: https://patch.msgid.link/d7a552ee382c79f4854e7fcc224cf176cd21150d.1733313925.git.gnault@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: b9553558b48d ("vxlan: use pskb_network_may_pull() for transmit path header pulls")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/vrf.c | 49 +++++++++++----------------------------
include/linux/netdevice.h | 40 ++++++++++++++++++++++++++++++++
2 files changed, 54 insertions(+), 35 deletions(-)
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 98140bff0e314..8f435f58a8886 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -121,16 +121,6 @@ struct net_vrf {
int ifindex;
};
-static void vrf_rx_stats(struct net_device *dev, int len)
-{
- struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
-
- u64_stats_update_begin(&dstats->syncp);
- u64_stats_inc(&dstats->rx_packets);
- u64_stats_add(&dstats->rx_bytes, len);
- u64_stats_update_end(&dstats->syncp);
-}
-
static void vrf_tx_error(struct net_device *vrf_dev, struct sk_buff *skb)
{
vrf_dev->stats.tx_errors++;
@@ -395,7 +385,7 @@ static bool qdisc_tx_is_default(const struct net_device *dev)
static int vrf_local_xmit(struct sk_buff *skb, struct net_device *dev,
struct dst_entry *dst)
{
- int len = skb->len;
+ unsigned int len = skb->len;
skb_orphan(skb);
@@ -408,15 +398,10 @@ static int vrf_local_xmit(struct sk_buff *skb, struct net_device *dev,
skb->protocol = eth_type_trans(skb, dev);
- if (likely(__netif_rx(skb) == NET_RX_SUCCESS)) {
- vrf_rx_stats(dev, len);
- } else {
- struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
-
- u64_stats_update_begin(&dstats->syncp);
- u64_stats_inc(&dstats->rx_drops);
- u64_stats_update_end(&dstats->syncp);
- }
+ if (likely(__netif_rx(skb) == NET_RX_SUCCESS))
+ dev_dstats_rx_add(dev, len);
+ else
+ dev_dstats_rx_dropped(dev);
return NETDEV_TX_OK;
}
@@ -604,20 +589,14 @@ static netdev_tx_t is_ip_tx_frame(struct sk_buff *skb, struct net_device *dev)
static netdev_tx_t vrf_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
-
- int len = skb->len;
- netdev_tx_t ret = is_ip_tx_frame(skb, dev);
-
- u64_stats_update_begin(&dstats->syncp);
- if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
+ unsigned int len = skb->len;
+ netdev_tx_t ret;
- u64_stats_inc(&dstats->tx_packets);
- u64_stats_add(&dstats->tx_bytes, len);
- } else {
- u64_stats_inc(&dstats->tx_drops);
- }
- u64_stats_update_end(&dstats->syncp);
+ ret = is_ip_tx_frame(skb, dev);
+ if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN))
+ dev_dstats_tx_add(dev, len);
+ else
+ dev_dstats_tx_dropped(dev);
return ret;
}
@@ -1400,7 +1379,7 @@ static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev,
if (!is_ndisc) {
struct net_device *orig_dev = skb->dev;
- vrf_rx_stats(vrf_dev, skb->len);
+ dev_dstats_rx_add(vrf_dev, skb->len);
skb->dev = vrf_dev;
skb->skb_iif = vrf_dev->ifindex;
@@ -1456,7 +1435,7 @@ static struct sk_buff *vrf_ip_rcv(struct net_device *vrf_dev,
goto out;
}
- vrf_rx_stats(vrf_dev, skb->len);
+ dev_dstats_rx_add(vrf_dev, skb->len);
if (!list_empty(&vrf_dev->ptype_all)) {
int err;
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index dfba3cec76b49..76191644aa0b5 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2795,6 +2795,46 @@ static inline void dev_lstats_add(struct net_device *dev, unsigned int len)
u64_stats_update_end(&lstats->syncp);
}
+static inline void dev_dstats_rx_add(struct net_device *dev,
+ unsigned int len)
+{
+ struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
+
+ u64_stats_update_begin(&dstats->syncp);
+ u64_stats_inc(&dstats->rx_packets);
+ u64_stats_add(&dstats->rx_bytes, len);
+ u64_stats_update_end(&dstats->syncp);
+}
+
+static inline void dev_dstats_rx_dropped(struct net_device *dev)
+{
+ struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
+
+ u64_stats_update_begin(&dstats->syncp);
+ u64_stats_inc(&dstats->rx_drops);
+ u64_stats_update_end(&dstats->syncp);
+}
+
+static inline void dev_dstats_tx_add(struct net_device *dev,
+ unsigned int len)
+{
+ struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
+
+ u64_stats_update_begin(&dstats->syncp);
+ u64_stats_inc(&dstats->tx_packets);
+ u64_stats_add(&dstats->tx_bytes, len);
+ u64_stats_update_end(&dstats->syncp);
+}
+
+static inline void dev_dstats_tx_dropped(struct net_device *dev)
+{
+ struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
+
+ u64_stats_update_begin(&dstats->syncp);
+ u64_stats_inc(&dstats->tx_drops);
+ u64_stats_update_end(&dstats->syncp);
+}
+
#define __netdev_alloc_pcpu_stats(type, gfp) \
({ \
typeof(type) __percpu *pcpu_stats = alloc_percpu_gfp(type, gfp);\
--
2.53.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 6.6.y 4/5] vxlan: Handle stats using NETDEV_PCPU_STAT_DSTATS.
2026-08-12 9:11 ` [PATCH 6.6.y 1/5] vxlan: Do not alloc tstats manually Sasha Levin
2026-08-12 9:11 ` [PATCH 6.6.y 2/5] net: core,vrf: Change pcpu_dstat fields to u64_stats_t Sasha Levin
2026-08-12 9:11 ` [PATCH 6.6.y 3/5] vrf: Make pcpu_dstats update functions available to other modules Sasha Levin
@ 2026-08-12 9:11 ` Sasha Levin
2026-09-25 18:08 ` Grische
2026-08-12 9:11 ` [PATCH 6.6.y 5/5] vxlan: use pskb_network_may_pull() for transmit path header pulls Sasha Levin
3 siblings, 1 reply; 12+ messages in thread
From: Sasha Levin @ 2026-08-12 9:11 UTC (permalink / raw)
To: stable; +Cc: Guillaume Nault, Jakub Kicinski, Sasha Levin
From: Guillaume Nault <gnault@redhat.com>
[ Upstream commit be226352e8dc77d3313c096b2d8e7f69bf6980fc ]
VXLAN uses the TSTATS infrastructure (dev_sw_netstats_*()) for RX and
TX packet counters. It also uses the device core stats
(dev_core_stats_*()) for RX and TX drops.
Let's consolidate that using the DSTATS infrastructure, which can
handle both packet counters and packet drops. Statistics that don't
fit DSTATS are still updated atomically with DEV_STATS_INC().
While there, convert the "len" variable of vxlan_encap_bypass() to
unsigned int, to respect the types of skb->len and
dev_dstats_[rt]x_add().
Signed-off-by: Guillaume Nault <gnault@redhat.com>
Link: https://patch.msgid.link/145558b184b3cda77911ca5682b6eb83c3ffed8e.1733313925.git.gnault@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: b9553558b48d ("vxlan: use pskb_network_may_pull() for transmit path header pulls")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/vxlan/vxlan_core.c | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 752015accf586..d27f3ef2a0fb2 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -1798,13 +1798,13 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
if (unlikely(!(vxlan->dev->flags & IFF_UP))) {
rcu_read_unlock();
- dev_core_stats_rx_dropped_inc(vxlan->dev);
+ dev_dstats_rx_dropped(vxlan->dev);
vxlan_vnifilter_count(vxlan, vni, vninode,
VXLAN_VNI_STATS_RX_DROPS, 0);
goto drop;
}
- dev_sw_netstats_rx_add(vxlan->dev, skb->len);
+ dev_dstats_rx_add(vxlan->dev, skb->len);
vxlan_vnifilter_count(vxlan, vni, vninode, VXLAN_VNI_STATS_RX, skb->len);
gro_cells_receive(&vxlan->gro_cells, skb);
@@ -1858,7 +1858,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
goto out;
if (!pskb_may_pull(skb, arp_hdr_len(dev))) {
- dev_core_stats_tx_dropped_inc(dev);
+ dev_dstats_tx_dropped(dev);
vxlan_vnifilter_count(vxlan, vni, NULL,
VXLAN_VNI_STATS_TX_DROPS, 0);
goto out;
@@ -1916,7 +1916,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
reply->pkt_type = PACKET_HOST;
if (netif_rx(reply) == NET_RX_DROP) {
- dev_core_stats_rx_dropped_inc(dev);
+ dev_dstats_rx_dropped(dev);
vxlan_vnifilter_count(vxlan, vni, NULL,
VXLAN_VNI_STATS_RX_DROPS, 0);
}
@@ -2077,7 +2077,7 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
goto out;
if (netif_rx(reply) == NET_RX_DROP) {
- dev_core_stats_rx_dropped_inc(dev);
+ dev_dstats_rx_dropped(dev);
vxlan_vnifilter_count(vxlan, vni, NULL,
VXLAN_VNI_STATS_RX_DROPS, 0);
}
@@ -2370,8 +2370,8 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
{
union vxlan_addr loopback;
union vxlan_addr *remote_ip = &dst_vxlan->default_dst.remote_ip;
+ unsigned int len = skb->len;
struct net_device *dev;
- int len = skb->len;
skb->pkt_type = PACKET_HOST;
skb->encapsulation = 0;
@@ -2398,16 +2398,16 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
if ((dst_vxlan->cfg.flags & VXLAN_F_LEARN) && snoop)
vxlan_snoop(dev, &loopback, eth_hdr(skb)->h_source, 0, vni);
- dev_sw_netstats_tx_add(src_vxlan->dev, 1, len);
+ dev_dstats_tx_add(src_vxlan->dev, len);
vxlan_vnifilter_count(src_vxlan, vni, NULL, VXLAN_VNI_STATS_TX, len);
if (__netif_rx(skb) == NET_RX_SUCCESS) {
- dev_sw_netstats_rx_add(dst_vxlan->dev, len);
+ dev_dstats_rx_add(dst_vxlan->dev, len);
vxlan_vnifilter_count(dst_vxlan, vni, NULL, VXLAN_VNI_STATS_RX,
len);
} else {
drop:
- dev_core_stats_rx_dropped_inc(dev);
+ dev_dstats_rx_dropped(dev);
vxlan_vnifilter_count(dst_vxlan, vni, NULL,
VXLAN_VNI_STATS_RX_DROPS, 0);
}
@@ -2700,7 +2700,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
return;
drop:
- dev_core_stats_tx_dropped_inc(dev);
+ dev_dstats_tx_dropped(dev);
vxlan_vnifilter_count(vxlan, vni, NULL, VXLAN_VNI_STATS_TX_DROPS, 0);
dev_kfree_skb(skb);
return;
@@ -2745,7 +2745,7 @@ static void vxlan_xmit_nh(struct sk_buff *skb, struct net_device *dev,
return;
drop:
- dev_core_stats_tx_dropped_inc(dev);
+ dev_dstats_tx_dropped(dev);
vxlan_vnifilter_count(netdev_priv(dev), vni, NULL,
VXLAN_VNI_STATS_TX_DROPS, 0);
dev_kfree_skb(skb);
@@ -2783,7 +2783,7 @@ static netdev_tx_t vxlan_xmit_nhid(struct sk_buff *skb, struct net_device *dev,
return NETDEV_TX_OK;
drop:
- dev_core_stats_tx_dropped_inc(dev);
+ dev_dstats_tx_dropped(dev);
vxlan_vnifilter_count(netdev_priv(dev), vni, NULL,
VXLAN_VNI_STATS_TX_DROPS, 0);
dev_kfree_skb(skb);
@@ -2881,7 +2881,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
!is_multicast_ether_addr(eth->h_dest))
vxlan_fdb_miss(vxlan, eth->h_dest);
- dev_core_stats_tx_dropped_inc(dev);
+ dev_dstats_tx_dropped(dev);
vxlan_vnifilter_count(vxlan, vni, NULL,
VXLAN_VNI_STATS_TX_DROPS, 0);
kfree_skb(skb);
@@ -3259,7 +3259,7 @@ static void vxlan_setup(struct net_device *dev)
dev->min_mtu = ETH_MIN_MTU;
dev->max_mtu = ETH_MAX_MTU;
- dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
+ dev->pcpu_stat_type = NETDEV_PCPU_STAT_DSTATS;
INIT_LIST_HEAD(&vxlan->next);
timer_setup(&vxlan->age_timer, vxlan_cleanup, TIMER_DEFERRABLE);
--
2.53.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [PATCH 6.6.y 4/5] vxlan: Handle stats using NETDEV_PCPU_STAT_DSTATS.
2026-08-12 9:11 ` [PATCH 6.6.y 4/5] vxlan: Handle stats using NETDEV_PCPU_STAT_DSTATS Sasha Levin
@ 2026-09-25 18:08 ` Grische
2026-09-26 15:26 ` Sasha Levin
0 siblings, 1 reply; 12+ messages in thread
From: Grische @ 2026-09-25 18:08 UTC (permalink / raw)
To: Sasha Levin
Cc: stable, Guillaume Nault, Jakub Kicinski, Greg Kroah-Hartman,
Eric Dumazet
Hi Sasha,
The backport went into 6.6.153 together with "net: harmonize tstats and
dstats", but without the later fix for the same conversion,
8431c602f551 ("ip_tunnel: adapt iptunnel_xmit_stats() to NETDEV_PCPU_STAT_DSTATS")
which went to 6.12.105, 6.18.50 and 6.19.10 and is tracked as
CVE-2026-23459.
Without it, iptunnel_xmit_stats() keeps bumping the tstats syncp,
which overlaps rx_drops in struct pcpu_dstats, so VXLAN's rx_dropped is
corrupted on 32-bit kernels.
The netdevice.h hunk does not cleanly apply to 6.6, as 6.6 has no
net_device_read_txrx group, and it only moves pcpu_stat_type.
The ip_tunnels.h hunk doesn't seem to work directly in 6.6 either. In
6.6, wireguard, ip_tunnel, ip6_tunnel, ip6_vti, sit, geneve, bareudp,
gtp and amt still allocate dev->tstats themselves and leave
pcpu_stat_type unset.
I can try to send a 6.6.y backport with the above in mind if that's easier.
Cheers,
Grische
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH 6.6.y 4/5] vxlan: Handle stats using NETDEV_PCPU_STAT_DSTATS.
2026-09-25 18:08 ` Grische
@ 2026-09-26 15:26 ` Sasha Levin
2026-11-08 16:19 ` [PATCH 6.6.y 0/3] vxlan: fix stats reads after the dstats conversion Christian Schmidbauer
0 siblings, 1 reply; 12+ messages in thread
From: Sasha Levin @ 2026-09-26 15:26 UTC (permalink / raw)
To: Grische
Cc: Sasha Levin, stable, Guillaume Nault, Jakub Kicinski,
Greg Kroah-Hartman, Eric Dumazet
> Without it, iptunnel_xmit_stats() keeps bumping the tstats syncp,
> which overlaps rx_drops in struct pcpu_dstats, so VXLAN's rx_dropped is
> corrupted on 32-bit kernels.
The reader side is missing too. 6.6 vxlan still uses dev_get_tstats64()
for .ndo_get_stats64, and 6.6 core has no dstats collection, so vxlan
drop counters always read 0. On 32-bit the tstats seqcount sits on
dstats->rx_drops, so once rx_drops is odd a stats read can spin forever.
> I can try to send a 6.6.y backport with the above in mind if that's easier.
Yes please.
--
Thanks,
Sasha
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 6.6.y 0/3] vxlan: fix stats reads after the dstats conversion
2026-09-26 15:26 ` Sasha Levin
@ 2026-11-08 16:19 ` Christian Schmidbauer
2026-11-08 16:19 ` [PATCH 6.6.y 1/3] net: get stats64 if device if driver is configured Christian Schmidbauer
` (2 more replies)
0 siblings, 3 replies; 12+ messages in thread
From: Christian Schmidbauer @ 2026-11-08 16:19 UTC (permalink / raw)
To: stable, Sasha Levin
Cc: Christian Schmidbauer, Greg Kroah-Hartman, Breno Leitao,
Jeremy Kerr, Guillaume Nault, Eric Dumazet, Jakub Kicinski
Hi Sasha,
This series backports the vxlan dstats reader side:
3e2f544dd8a3 ("net: get stats64 if device if driver is configured")
94b601bc4f85 ("net: core: Implement dstats-type stats collections")
195f88c57737 ("vxlan: Remove generic .ndo_get_stats64")
3e2f544dd8a3 has no effect on 6.6 by itself, but is needed by
94b601bc4f85 to apply cleanly.
Tested on 6.6.161 with and without the series on two 32-bit boards, a
little-endian ARMv7 Aruba AP-325 and a big-endian PowerPC Enterasys
WS-AP3715i.
Both boards miss the vxlan drops without the series and count them with
it. On the AP-325 a stats read also hangs once rx_drops is odd, and the
series fixes that as well.
Breno Leitao (2):
net: get stats64 if device if driver is configured
vxlan: Remove generic .ndo_get_stats64
Jeremy Kerr (1):
net: core: Implement dstats-type stats collections
drivers/net/vxlan/vxlan_core.c | 2 --
net/core/dev.c | 52 ++++++++++++++++++++++++++++++++++
2 files changed, 52 insertions(+), 2 deletions(-)
base-commit: b5a1dc3ad4822c6edfb53429e9a3759c9b0ac2be
--
2.54.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH 6.6.y 1/3] net: get stats64 if device if driver is configured
2026-11-08 16:19 ` [PATCH 6.6.y 0/3] vxlan: fix stats reads after the dstats conversion Christian Schmidbauer
@ 2026-11-08 16:19 ` Christian Schmidbauer
2026-11-08 16:19 ` [PATCH 6.6.y 2/3] net: core: Implement dstats-type stats collections Christian Schmidbauer
2026-11-08 16:19 ` [PATCH 6.6.y 3/3] vxlan: Remove generic .ndo_get_stats64 Christian Schmidbauer
2 siblings, 0 replies; 12+ messages in thread
From: Christian Schmidbauer @ 2026-11-08 16:19 UTC (permalink / raw)
To: stable, Sasha Levin
Cc: Christian Schmidbauer, Greg Kroah-Hartman, Breno Leitao,
Jeremy Kerr, Guillaume Nault, Eric Dumazet, Jakub Kicinski,
Simon Horman, Paolo Abeni
From: Breno Leitao <leitao@debian.org>
[ Upstream commit 3e2f544dd8a33b2f650b32920b9bef103da2a7cd ]
If the network driver is relying in the net core to do stats allocation,
then we want to dev_get_tstats64() instead of netdev_stats_to_stats64(),
since there are per-cpu stats that needs to be taken in consideration.
This will also simplify the drivers in regard to statistics. Once the
driver sets NETDEV_PCPU_STAT_TSTATS, it doesn't not need to allocate the
stacks, neither it needs to set `.ndo_get_stats64 = dev_get_tstats64`
for the generic stats collection function anymore.
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Stable-dep-of: 94b601bc4f85 ("net: core: Implement dstats-type stats collections")
Signed-off-by: Christian Schmidbauer <opensource@grische.xyz>
---
net/core/dev.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/core/dev.c b/net/core/dev.c
index f9436563a2e8..f55b7e5ea3a6 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -10784,6 +10784,8 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
ops->ndo_get_stats64(dev, storage);
} else if (ops->ndo_get_stats) {
netdev_stats_to_stats64(storage, ops->ndo_get_stats(dev));
+ } else if (dev->pcpu_stat_type == NETDEV_PCPU_STAT_TSTATS) {
+ dev_get_tstats64(dev, storage);
} else {
netdev_stats_to_stats64(storage, &dev->stats);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 6.6.y 2/3] net: core: Implement dstats-type stats collections
2026-11-08 16:19 ` [PATCH 6.6.y 0/3] vxlan: fix stats reads after the dstats conversion Christian Schmidbauer
2026-11-08 16:19 ` [PATCH 6.6.y 1/3] net: get stats64 if device if driver is configured Christian Schmidbauer
@ 2026-11-08 16:19 ` Christian Schmidbauer
2026-11-08 16:19 ` [PATCH 6.6.y 3/3] vxlan: Remove generic .ndo_get_stats64 Christian Schmidbauer
2 siblings, 0 replies; 12+ messages in thread
From: Christian Schmidbauer @ 2026-11-08 16:19 UTC (permalink / raw)
To: stable, Sasha Levin
Cc: Christian Schmidbauer, Greg Kroah-Hartman, Breno Leitao,
Jeremy Kerr, Guillaume Nault, Eric Dumazet, Jakub Kicinski,
Simon Horman, David Ahern
From: Jeremy Kerr <jk@codeconstruct.com.au>
[ Upstream commit 94b601bc4f8528262b2b83194b7fd3fc2a6da75a ]
We currently have dev_get_tstats64() for collecting per-cpu stats of
type pcpu_sw_netstats ("tstats"). However, tstats doesn't allow for
accounting tx/rx drops. We do have a stats variant that does have stats
for dropped packets: struct pcpu_dstats, but there are no core helpers
for using those stats.
The VRF driver uses dstats, by providing its own collation/fetch
functions to do so.
This change adds a common implementation for dstats-type collection,
used when pcpu_stat_type == NETDEV_PCPU_STAT_DSTAT. This is based on the
VRF driver's existing stats collator (plus the unused tx_drops stat from
there). We will switch the VRF driver to use this in the next change.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: David Ahern <dsahern@kernel.org>
Link: https://lore.kernel.org/r/20240607-dstats-v3-2-cc781fe116f7@codeconstruct.com.au
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Christian Schmidbauer <opensource@grische.xyz>
---
net/core/dev.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/net/core/dev.c b/net/core/dev.c
index f55b7e5ea3a6..d989a21a72fd 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -10713,6 +10713,54 @@ void netdev_run_todo(void)
}
}
+/* Collate per-cpu network dstats statistics
+ *
+ * Read per-cpu network statistics from dev->dstats and populate the related
+ * fields in @s.
+ */
+static void dev_fetch_dstats(struct rtnl_link_stats64 *s,
+ const struct pcpu_dstats __percpu *dstats)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ u64 rx_packets, rx_bytes, rx_drops;
+ u64 tx_packets, tx_bytes, tx_drops;
+ const struct pcpu_dstats *stats;
+ unsigned int start;
+
+ stats = per_cpu_ptr(dstats, cpu);
+ do {
+ start = u64_stats_fetch_begin(&stats->syncp);
+ rx_packets = u64_stats_read(&stats->rx_packets);
+ rx_bytes = u64_stats_read(&stats->rx_bytes);
+ rx_drops = u64_stats_read(&stats->rx_drops);
+ tx_packets = u64_stats_read(&stats->tx_packets);
+ tx_bytes = u64_stats_read(&stats->tx_bytes);
+ tx_drops = u64_stats_read(&stats->tx_drops);
+ } while (u64_stats_fetch_retry(&stats->syncp, start));
+
+ s->rx_packets += rx_packets;
+ s->rx_bytes += rx_bytes;
+ s->rx_dropped += rx_drops;
+ s->tx_packets += tx_packets;
+ s->tx_bytes += tx_bytes;
+ s->tx_dropped += tx_drops;
+ }
+}
+
+/* ndo_get_stats64 implementation for dtstats-based accounting.
+ *
+ * Populate @s from dev->stats and dev->dstats. This is used internally by the
+ * core for NETDEV_PCPU_STAT_DSTAT-type stats collection.
+ */
+static void dev_get_dstats64(const struct net_device *dev,
+ struct rtnl_link_stats64 *s)
+{
+ netdev_stats_to_stats64(s, &dev->stats);
+ dev_fetch_dstats(s, dev->dstats);
+}
+
/* Convert net_device_stats to rtnl_link_stats64. rtnl_link_stats64 has
* all the same fields in the same order as net_device_stats, with only
* the type differing, but rtnl_link_stats64 may have additional fields
@@ -10786,6 +10834,8 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
netdev_stats_to_stats64(storage, ops->ndo_get_stats(dev));
} else if (dev->pcpu_stat_type == NETDEV_PCPU_STAT_TSTATS) {
dev_get_tstats64(dev, storage);
+ } else if (dev->pcpu_stat_type == NETDEV_PCPU_STAT_DSTATS) {
+ dev_get_dstats64(dev, storage);
} else {
netdev_stats_to_stats64(storage, &dev->stats);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 6.6.y 3/3] vxlan: Remove generic .ndo_get_stats64
2026-11-08 16:19 ` [PATCH 6.6.y 0/3] vxlan: fix stats reads after the dstats conversion Christian Schmidbauer
2026-11-08 16:19 ` [PATCH 6.6.y 1/3] net: get stats64 if device if driver is configured Christian Schmidbauer
2026-11-08 16:19 ` [PATCH 6.6.y 2/3] net: core: Implement dstats-type stats collections Christian Schmidbauer
@ 2026-11-08 16:19 ` Christian Schmidbauer
2 siblings, 0 replies; 12+ messages in thread
From: Christian Schmidbauer @ 2026-11-08 16:19 UTC (permalink / raw)
To: stable, Sasha Levin
Cc: Christian Schmidbauer, Greg Kroah-Hartman, Breno Leitao,
Jeremy Kerr, Guillaume Nault, Eric Dumazet, Jakub Kicinski,
Subbaraya Sundeep
From: Breno Leitao <leitao@debian.org>
[ Upstream commit 195f88c57737f16217b5dece054a4cfd74c33550 ]
Commit 3e2f544dd8a33 ("net: get stats64 if device if driver is
configured") moved the callback to dev_get_tstats64() to net core, so,
unless the driver is doing some custom stats collection, it does not
need to set .ndo_get_stats64.
Since this driver is now relying in NETDEV_PCPU_STAT_TSTATS, then, it
doesn't need to set the dev_get_tstats64() generic .ndo_get_stats64
function pointer.
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Subbaraya Sundeep <sbhatta@marvell.com>
Link: https://lore.kernel.org/r/20240311112437.3813987-2-leitao@debian.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Christian Schmidbauer <opensource@grische.xyz>
---
drivers/net/vxlan/vxlan_core.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 355337d428e5..c3e2d78d2dd1 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -3195,7 +3195,6 @@ static const struct net_device_ops vxlan_netdev_ether_ops = {
.ndo_open = vxlan_open,
.ndo_stop = vxlan_stop,
.ndo_start_xmit = vxlan_xmit,
- .ndo_get_stats64 = dev_get_tstats64,
.ndo_set_rx_mode = vxlan_set_multicast_list,
.ndo_change_mtu = vxlan_change_mtu,
.ndo_validate_addr = eth_validate_addr,
@@ -3218,7 +3217,6 @@ static const struct net_device_ops vxlan_netdev_raw_ops = {
.ndo_open = vxlan_open,
.ndo_stop = vxlan_stop,
.ndo_start_xmit = vxlan_xmit,
- .ndo_get_stats64 = dev_get_tstats64,
.ndo_change_mtu = vxlan_change_mtu,
.ndo_fill_metadata_dst = vxlan_fill_metadata_dst,
};
--
2.54.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 6.6.y 5/5] vxlan: use pskb_network_may_pull() for transmit path header pulls
2026-08-12 9:11 ` [PATCH 6.6.y 1/5] vxlan: Do not alloc tstats manually Sasha Levin
` (2 preceding siblings ...)
2026-08-12 9:11 ` [PATCH 6.6.y 4/5] vxlan: Handle stats using NETDEV_PCPU_STAT_DSTATS Sasha Levin
@ 2026-08-12 9:11 ` Sasha Levin
3 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2026-08-12 9:11 UTC (permalink / raw)
To: stable
Cc: Eric Dumazet, Vadim Fedorenko, Ido Schimmel, Jakub Kicinski,
Sasha Levin
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit b9553558b48db54ac9273e6b98d7263ef5c1a329 ]
In vxlan_xmit(), arp_reduce(), and vxlan_mdb_entry_skb_get(), pskb_may_pull() was
being called to verify the availability of network layer headers (ARP, IPv6/ND,
IP/IPv6 MDB keys).
However, during transmit skb->data points to the MAC header, so skb_network_offset(skb)
is ETH_HLEN (14 bytes). Using pskb_may_pull(skb, len) only checks len bytes from skb->data
rather than skb_network_offset(skb) + len, which can leave part of the network header
in non-linear frags.
Replace these remaining pskb_may_pull() calls with pskb_network_may_pull() to properly
account for the MAC header offset.
Fixes: e4f67addf158 ("add DOVE extensions for VXLAN")
Fixes: f564f45c4518 ("vxlan: add ipv6 proxy support")
Fixes: 0f83e69f44bf ("vxlan: Add MDB data path support")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: stable@vger.kernel.org
Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20260723144249.759100-6-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/net/vxlan/vxlan_core.c | 6 +++---
drivers/net/vxlan/vxlan_mdb.c | 4 ++--
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index d27f3ef2a0fb2..5718433862af0 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -1857,7 +1857,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb, __be32 vni)
if (dev->flags & IFF_NOARP)
goto out;
- if (!pskb_may_pull(skb, arp_hdr_len(dev))) {
+ if (!pskb_network_may_pull(skb, arp_hdr_len(dev))) {
dev_dstats_tx_dropped(dev);
vxlan_vnifilter_count(vxlan, vni, NULL,
VXLAN_VNI_STATS_TX_DROPS, 0);
@@ -2831,8 +2831,8 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
return arp_reduce(dev, skb, vni);
#if IS_ENABLED(CONFIG_IPV6)
else if (ntohs(eth->h_proto) == ETH_P_IPV6 &&
- pskb_may_pull(skb, sizeof(struct ipv6hdr) +
- sizeof(struct nd_msg)) &&
+ pskb_network_may_pull(skb, sizeof(struct ipv6hdr) +
+ sizeof(struct nd_msg)) &&
ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) {
struct nd_msg *m = (struct nd_msg *)(ipv6_hdr(skb) + 1);
diff --git a/drivers/net/vxlan/vxlan_mdb.c b/drivers/net/vxlan/vxlan_mdb.c
index 73c128c3d90de..eb919fc05cdf9 100644
--- a/drivers/net/vxlan/vxlan_mdb.c
+++ b/drivers/net/vxlan/vxlan_mdb.c
@@ -1326,7 +1326,7 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan,
switch (skb->protocol) {
case htons(ETH_P_IP):
- if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+ if (!pskb_network_may_pull(skb, sizeof(struct iphdr)))
return NULL;
group.dst.sa.sa_family = AF_INET;
group.dst.sin.sin_addr.s_addr = ip_hdr(skb)->daddr;
@@ -1335,7 +1335,7 @@ struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan,
break;
#if IS_ENABLED(CONFIG_IPV6)
case htons(ETH_P_IPV6):
- if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+ if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
return NULL;
group.dst.sa.sa_family = AF_INET6;
group.dst.sin6.sin6_addr = ipv6_hdr(skb)->daddr;
--
2.53.0
^ permalink raw reply related [flat|nested] 12+ messages in thread