Skip to content

Commit

Permalink
Merge branch 'net-convert-some-udp-tunnel-drivers-to-netdev_pcpu_stat…
Browse files Browse the repository at this point in the history
…_dstats'

Guillaume Nault says:

====================
net: Convert some UDP tunnel drivers to NETDEV_PCPU_STAT_DSTATS.

VXLAN, Geneve and Bareudp use various device counters for managing
RX and TX statistics:

  * VXLAN uses the device core_stats for RX and TX drops, tstats for
    regular RX/TX counters and DEV_STATS_INC() for various types of
    RX/TX errors.

  * Geneve uses tstats for regular RX/TX counters and DEV_STATS_INC()
    for everything else, include RX/TX drops.

  * Bareudp, was recently converted to follow VXLAN behaviour, that is,
    device core_stats for RX and TX drops, tstats for regular RX/TX
    counters and DEV_STATS_INC() for other counter types.

Let's consolidate statistics management around the dstats counters
instead. This avoids using core_stats in VXLAN and Bareudp, as
core_stats is supposed to be used by core networking code only (and not
in drivers).  This also allows Geneve to avoid using atomic increments
when updating RX and TX drop counters, as dstats is per-cpu. Finally,
this also simplifies the code as all three modules now handle stats in
the same way and with only two different sets of counters (the per-cpu
dstats and the atomic DEV_STATS_INC()).

Patch 1 creates dstats helper functions that can be used outside of VRF
(until then, dstats was VRF-specific).
Then patches 2 to 4, convert VXLAN, Geneve and Bareudp, one by one.
====================

Link: https://patch.msgid.link/cover.1733313925.git.gnault@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Dec 7, 2024
2 parents 9ec780b + c77200c commit 860dbab
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 63 deletions.
16 changes: 8 additions & 8 deletions drivers/net/bareudp.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)

if (skb_copy_bits(skb, BAREUDP_BASE_HLEN, &ipversion,
sizeof(ipversion))) {
dev_core_stats_rx_dropped_inc(bareudp->dev);
dev_dstats_rx_dropped(bareudp->dev);
goto drop;
}
ipversion >>= 4;
Expand All @@ -94,7 +94,7 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
} else if (ipversion == 6 && bareudp->multi_proto_mode) {
proto = htons(ETH_P_IPV6);
} else {
dev_core_stats_rx_dropped_inc(bareudp->dev);
dev_dstats_rx_dropped(bareudp->dev);
goto drop;
}
} else if (bareudp->ethertype == htons(ETH_P_MPLS_UC)) {
Expand All @@ -108,7 +108,7 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
ipv4_is_multicast(tunnel_hdr->daddr)) {
proto = htons(ETH_P_MPLS_MC);
} else {
dev_core_stats_rx_dropped_inc(bareudp->dev);
dev_dstats_rx_dropped(bareudp->dev);
goto drop;
}
} else {
Expand All @@ -124,7 +124,7 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
(addr_type & IPV6_ADDR_MULTICAST)) {
proto = htons(ETH_P_MPLS_MC);
} else {
dev_core_stats_rx_dropped_inc(bareudp->dev);
dev_dstats_rx_dropped(bareudp->dev);
goto drop;
}
}
Expand All @@ -136,15 +136,15 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
proto,
!net_eq(bareudp->net,
dev_net(bareudp->dev)))) {
dev_core_stats_rx_dropped_inc(bareudp->dev);
dev_dstats_rx_dropped(bareudp->dev);
goto drop;
}

__set_bit(IP_TUNNEL_KEY_BIT, key);

tun_dst = udp_tun_rx_dst(skb, family, key, 0, 0);
if (!tun_dst) {
dev_core_stats_rx_dropped_inc(bareudp->dev);
dev_dstats_rx_dropped(bareudp->dev);
goto drop;
}
skb_dst_set(skb, &tun_dst->dst);
Expand Down Expand Up @@ -194,7 +194,7 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
len = skb->len;
err = gro_cells_receive(&bareudp->gro_cells, skb);
if (likely(err == NET_RX_SUCCESS))
dev_sw_netstats_rx_add(bareudp->dev, len);
dev_dstats_rx_add(bareudp->dev, len);

return 0;
drop:
Expand Down Expand Up @@ -589,7 +589,7 @@ static void bareudp_setup(struct net_device *dev)
dev->priv_flags |= IFF_NO_QUEUE;
dev->lltx = true;
dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
dev->pcpu_stat_type = NETDEV_PCPU_STAT_DSTATS;
}

static int bareudp_validate(struct nlattr *tb[], struct nlattr *data[],
Expand Down
12 changes: 6 additions & 6 deletions drivers/net/geneve.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
vni_to_tunnel_id(gnvh->vni),
gnvh->opt_len * 4);
if (!tun_dst) {
DEV_STATS_INC(geneve->dev, rx_dropped);
dev_dstats_rx_dropped(geneve->dev);
goto drop;
}
/* Update tunnel dst according to Geneve options. */
Expand Down Expand Up @@ -322,7 +322,7 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
len = skb->len;
err = gro_cells_receive(&geneve->gro_cells, skb);
if (likely(err == NET_RX_SUCCESS))
dev_sw_netstats_rx_add(geneve->dev, len);
dev_dstats_rx_add(geneve->dev, len);

return;
drop:
Expand Down Expand Up @@ -387,14 +387,14 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)

if (unlikely((!geneve->cfg.inner_proto_inherit &&
inner_proto != htons(ETH_P_TEB)))) {
DEV_STATS_INC(geneve->dev, rx_dropped);
dev_dstats_rx_dropped(geneve->dev);
goto drop;
}

opts_len = geneveh->opt_len * 4;
if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len, inner_proto,
!net_eq(geneve->net, dev_net(geneve->dev)))) {
DEV_STATS_INC(geneve->dev, rx_dropped);
dev_dstats_rx_dropped(geneve->dev);
goto drop;
}

Expand Down Expand Up @@ -1023,7 +1023,7 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) {
netdev_dbg(dev, "no tunnel metadata\n");
dev_kfree_skb(skb);
DEV_STATS_INC(dev, tx_dropped);
dev_dstats_tx_dropped(dev);
return NETDEV_TX_OK;
}
} else {
Expand Down Expand Up @@ -1202,7 +1202,7 @@ static void geneve_setup(struct net_device *dev)
dev->hw_features |= NETIF_F_RXCSUM;
dev->hw_features |= NETIF_F_GSO_SOFTWARE;

dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
dev->pcpu_stat_type = NETDEV_PCPU_STAT_DSTATS;
/* MTU range: 68 - (something less than 65535) */
dev->min_mtu = ETH_MIN_MTU;
/* The max_mtu calculation does not take account of GENEVE
Expand Down
49 changes: 14 additions & 35 deletions drivers/net/vrf.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,16 +122,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++;
Expand Down Expand Up @@ -369,7 +359,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);

Expand All @@ -382,15 +372,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;
}
Expand Down Expand Up @@ -578,20 +563,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;
}
Expand Down Expand Up @@ -1364,7 +1343,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;

Expand Down Expand Up @@ -1420,7 +1399,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;
Expand Down
28 changes: 14 additions & 14 deletions drivers/net/vxlan/vxlan_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1818,14 +1818,14 @@ 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);
reason = SKB_DROP_REASON_DEV_READY;
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);

Expand Down Expand Up @@ -1880,7 +1880,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;
Expand Down Expand Up @@ -1938,7 +1938,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);
}
Expand Down Expand Up @@ -2097,7 +2097,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);
}
Expand Down Expand Up @@ -2271,8 +2271,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;
Expand All @@ -2299,16 +2299,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);
}
Expand Down Expand Up @@ -2621,7 +2621,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);
kfree_skb_reason(skb, reason);
return;
Expand Down Expand Up @@ -2666,7 +2666,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);
Expand Down Expand Up @@ -2704,7 +2704,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);
Expand Down Expand Up @@ -2801,7 +2801,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_reason(skb, SKB_DROP_REASON_VXLAN_NO_REMOTE);
Expand Down Expand Up @@ -3371,7 +3371,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);
Expand Down
40 changes: 40 additions & 0 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -2854,6 +2854,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);\
Expand Down

0 comments on commit 860dbab

Please sign in to comment.