Skip to content

Commit 7ca7b66

Browse files
peilin-yegregkh
authored andcommitted
veth: Use tstats per-CPU traffic counters
[ Upstream commit 6f2684bf2b4460c84d0d34612a939f78b96b03fc ] Currently veth devices use the lstats per-CPU traffic counters, which only cover TX traffic. veth_get_stats64() actually populates RX stats of a veth device from its peer's TX counters, based on the assumption that a veth device can _only_ receive packets from its peer, which is no longer true: For example, recent CNIs (like Cilium) can use the bpf_redirect_peer() BPF helper to redirect traffic from NIC's tc ingress to veth's tc ingress (in a different netns), skipping veth's peer device. Unfortunately, this kind of traffic isn't currently accounted for in veth's RX stats. In preparation for the fix, use tstats (instead of lstats) to maintain both RX and TX counters for each veth device. We'll use RX counters for bpf_redirect_peer() traffic, and keep using TX counters for the usual "peer-to-peer" traffic. In veth_get_stats64(), calculate RX stats by _adding_ RX count to peer's TX count, in order to cover both kinds of traffic. veth_stats_rx() might need a name change (perhaps to "veth_stats_xdp()") for less confusion, but let's leave it to another patch to keep the fix minimal. Signed-off-by: Peilin Ye <[email protected]> Co-developed-by: Daniel Borkmann <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Reviewed-by: Nikolay Aleksandrov <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Martin KaFai Lau <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 8e7b530 commit 7ca7b66

File tree

1 file changed

+11
-19
lines changed

1 file changed

+11
-19
lines changed

drivers/net/veth.c

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
342342
skb_tx_timestamp(skb);
343343
if (likely(veth_forward_skb(rcv, skb, rq, use_napi) == NET_RX_SUCCESS)) {
344344
if (!use_napi)
345-
dev_lstats_add(dev, length);
345+
dev_sw_netstats_tx_add(dev, 1, length);
346346
} else {
347347
drop:
348348
atomic64_inc(&priv->dropped);
@@ -357,14 +357,6 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
357357
return ret;
358358
}
359359

360-
static u64 veth_stats_tx(struct net_device *dev, u64 *packets, u64 *bytes)
361-
{
362-
struct veth_priv *priv = netdev_priv(dev);
363-
364-
dev_lstats_read(dev, packets, bytes);
365-
return atomic64_read(&priv->dropped);
366-
}
367-
368360
static void veth_stats_rx(struct veth_stats *result, struct net_device *dev)
369361
{
370362
struct veth_priv *priv = netdev_priv(dev);
@@ -402,24 +394,24 @@ static void veth_get_stats64(struct net_device *dev,
402394
struct veth_priv *priv = netdev_priv(dev);
403395
struct net_device *peer;
404396
struct veth_stats rx;
405-
u64 packets, bytes;
406397

407-
tot->tx_dropped = veth_stats_tx(dev, &packets, &bytes);
408-
tot->tx_bytes = bytes;
409-
tot->tx_packets = packets;
398+
tot->tx_dropped = atomic64_read(&priv->dropped);
399+
dev_fetch_sw_netstats(tot, dev->tstats);
410400

411401
veth_stats_rx(&rx, dev);
412402
tot->tx_dropped += rx.xdp_tx_err;
413403
tot->rx_dropped = rx.rx_drops + rx.peer_tq_xdp_xmit_err;
414-
tot->rx_bytes = rx.xdp_bytes;
415-
tot->rx_packets = rx.xdp_packets;
404+
tot->rx_bytes += rx.xdp_bytes;
405+
tot->rx_packets += rx.xdp_packets;
416406

417407
rcu_read_lock();
418408
peer = rcu_dereference(priv->peer);
419409
if (peer) {
420-
veth_stats_tx(peer, &packets, &bytes);
421-
tot->rx_bytes += bytes;
422-
tot->rx_packets += packets;
410+
struct rtnl_link_stats64 tot_peer = {};
411+
412+
dev_fetch_sw_netstats(&tot_peer, peer->tstats);
413+
tot->rx_bytes += tot_peer.tx_bytes;
414+
tot->rx_packets += tot_peer.tx_packets;
423415

424416
veth_stats_rx(&rx, peer);
425417
tot->tx_dropped += rx.peer_tq_xdp_xmit_err;
@@ -1612,7 +1604,7 @@ static void veth_setup(struct net_device *dev)
16121604
NETIF_F_HW_VLAN_STAG_RX);
16131605
dev->needs_free_netdev = true;
16141606
dev->priv_destructor = veth_dev_free;
1615-
dev->pcpu_stat_type = NETDEV_PCPU_STAT_LSTATS;
1607+
dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
16161608
dev->max_mtu = ETH_MAX_MTU;
16171609

16181610
dev->hw_features = VETH_FEATURES;

0 commit comments

Comments
 (0)