bpf: Fix dev's rx stats for bpf_redirect_peer traffic
PATCH 1/1 bpf: Fix dev's rx stats for bpf_redirect_peer traffic
From: Peilin Ye <[email protected]>
commit 024ee930cb3c9ae49e4266aee89cfde0ebb407e1 upstream
Traffic redirected by bpf_redirect_peer() (used by recent CNIs like Cilium) is not accounted for in the RX stats of supported devices (that is, veth and netkit), confusing user space metrics collectors such as cAdvisor [0], as reported by Youlun.
Fix it by calling dev_sw_netstats_rx_add() in skb_do_redirect(), to update RX traffic counters. Devices that support ndo_get_peer_dev _must_ use the @tstats per-CPU counters (instead of @lstats, or @dstats).
To make this more fool-proof, error out when ndo_get_peer_dev is set but @tstats are not selected.
[0] Specifically, the "container_network_receive_{byte,packet}s_total" counters are affected.
--- net/core/dev.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++ net/core/filter.c | 1 + 2 files changed, 49 insertions(+)
net/core/dev.c +48 -0
@@ -9983,6 +9983,54 @@ void netif_tx_stop_all_queues(struct net_device *dev) }EXPORT_SYMBOL (netif_tx_stop_all_queues); +static int netdev_do_alloc_pcpu_stats (struct net_device *dev) +{ +void __percpu *v; + +/* Drivers implementing ndo_get_peer_dev must support tstat +* accounting, so that skb_do_redirect() can bump the dev's +* RX stats upon network namespace switch. +*/ +if (dev->netdev_ops->ndo_get_peer_dev && + dev->pcpu_stat_type !=NETDEV_PCPU_STAT_TSTATS ) +return -EOPNOTSUPP ; + +switch (dev->pcpu_stat_type) { +case NETDEV_PCPU_STAT_NONE : +return 0 ; +case NETDEV_PCPU_STAT_LSTATS : + v = dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats); +break ; +case NETDEV_PCPU_STAT_TSTATS : + v = dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); +break ; +case NETDEV_PCPU_STAT_DSTATS : + v = dev->dstats = netdev_alloc_pcpu_stats(struct pcpu_dstats); +break ; +default : +return -EINVAL ; + } + +return v ?0 : -ENOMEM ; +} + +static void netdev_do_free_pcpu_stats (struct net_device *dev) +{ +switch (dev->pcpu_stat_type) { +case NETDEV_PCPU_STAT_NONE : +return ; +case NETDEV_PCPU_STAT_LSTATS : +free_percpu (dev->lstats); +break ; +case NETDEV_PCPU_STAT_TSTATS : +free_percpu (dev->tstats); +break ; +case NETDEV_PCPU_STAT_DSTATS : +free_percpu (dev->dstats); +break ; + } +} +/** * register_netdevice() - register a network device * @dev: device to register
net/core/filter.c +1 -0
@@ -2489,6 +2489,7 @@ int skb_do_redirect(struct sk_buff *skb) net_eq(net, dev_net(dev)))) goto out_drop; skb->dev = dev; +dev_sw_netstats_rx_add (dev, skb->len);return -EAGAIN ; } return flags & BPF_F_NEIGH ?
Signature · 1 line
2.45.2
net/core/dev.c void netif_tx_stop_all_queues(struct net_device *dev) · line 9987
Quoted 10 lines
net/core/dev.c +2
-0@@ -9983,6 +9983,54 @@ void netif_tx_stop_all_queues(struct net_device *dev) }EXPORT_SYMBOL (netif_tx_stop_all_queues); +static int netdev_do_alloc_pcpu_stats (struct net_device *dev) +{
I submitted this prematurely, this needs a few more changes that this commit depends upon. I'll work on getting the full patchset ready for backporting to 6.1.y.