Skip to content

Commit

Permalink
net: Move {l,t,d}stats allocation to core and convert veth & vrf
Browse files Browse the repository at this point in the history
[ Upstream commit 34d21de ]

Move {l,t,d}stats allocation to the core and let netdevs pick the stats
type they need. That way the driver doesn't have to bother with error
handling (allocation failure checking, making sure free happens in the
right spot, etc) - all happening in the core.

Co-developed-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
Cc: David Ahern <dsahern@kernel.org>
Link: https://lore.kernel.org/r/20231114004220.6495-3-daniel@iogearbox.net
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Stable-dep-of: 024ee93 ("bpf: Fix dev's rx stats for bpf_redirect_peer traffic")
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
borkmann authored and gregkh committed Dec 3, 2023
1 parent 95f068b commit 6ae7b3f
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 30 deletions.
16 changes: 2 additions & 14 deletions drivers/net/veth.c
Original file line number Diff line number Diff line change
Expand Up @@ -1499,25 +1499,12 @@ static void veth_free_queues(struct net_device *dev)

static int veth_dev_init(struct net_device *dev)
{
int err;

dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats);
if (!dev->lstats)
return -ENOMEM;

err = veth_alloc_queues(dev);
if (err) {
free_percpu(dev->lstats);
return err;
}

return 0;
return veth_alloc_queues(dev);
}

static void veth_dev_free(struct net_device *dev)
{
veth_free_queues(dev);
free_percpu(dev->lstats);
}

#ifdef CONFIG_NET_POLL_CONTROLLER
Expand Down Expand Up @@ -1789,6 +1776,7 @@ static void veth_setup(struct net_device *dev)
NETIF_F_HW_VLAN_STAG_RX);
dev->needs_free_netdev = true;
dev->priv_destructor = veth_dev_free;
dev->pcpu_stat_type = NETDEV_PCPU_STAT_LSTATS;
dev->max_mtu = ETH_MAX_MTU;

dev->hw_features = VETH_FEATURES;
Expand Down
14 changes: 3 additions & 11 deletions drivers/net/vrf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1164,22 +1164,15 @@ static void vrf_dev_uninit(struct net_device *dev)

vrf_rtable_release(dev, vrf);
vrf_rt6_release(dev, vrf);

free_percpu(dev->dstats);
dev->dstats = NULL;
}

static int vrf_dev_init(struct net_device *dev)
{
struct net_vrf *vrf = netdev_priv(dev);

dev->dstats = netdev_alloc_pcpu_stats(struct pcpu_dstats);
if (!dev->dstats)
goto out_nomem;

/* create the default dst which points back to us */
if (vrf_rtable_create(dev) != 0)
goto out_stats;
goto out_nomem;

if (vrf_rt6_create(dev) != 0)
goto out_rth;
Expand All @@ -1193,9 +1186,6 @@ static int vrf_dev_init(struct net_device *dev)

out_rth:
vrf_rtable_release(dev, vrf);
out_stats:
free_percpu(dev->dstats);
dev->dstats = NULL;
out_nomem:
return -ENOMEM;
}
Expand Down Expand Up @@ -1694,6 +1684,8 @@ static void vrf_setup(struct net_device *dev)
dev->min_mtu = IPV6_MIN_MTU;
dev->max_mtu = IP6_MAX_MTU;
dev->mtu = dev->max_mtu;

dev->pcpu_stat_type = NETDEV_PCPU_STAT_DSTATS;
}

static int vrf_validate(struct nlattr *tb[], struct nlattr *data[],
Expand Down
20 changes: 16 additions & 4 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -1774,6 +1774,13 @@ enum netdev_ml_priv_type {
ML_PRIV_CAN,
};

enum netdev_stat_type {
NETDEV_PCPU_STAT_NONE,
NETDEV_PCPU_STAT_LSTATS, /* struct pcpu_lstats */
NETDEV_PCPU_STAT_TSTATS, /* struct pcpu_sw_netstats */
NETDEV_PCPU_STAT_DSTATS, /* struct pcpu_dstats */
};

/**
* struct net_device - The DEVICE structure.
*
Expand Down Expand Up @@ -1968,10 +1975,14 @@ enum netdev_ml_priv_type {
*
* @ml_priv: Mid-layer private
* @ml_priv_type: Mid-layer private type
* @lstats: Loopback statistics
* @tstats: Tunnel statistics
* @dstats: Dummy statistics
* @vstats: Virtual ethernet statistics
*
* @pcpu_stat_type: Type of device statistics which the core should
* allocate/free: none, lstats, tstats, dstats. none
* means the driver is handling statistics allocation/
* freeing internally.
* @lstats: Loopback statistics: packets, bytes
* @tstats: Tunnel statistics: RX/TX packets, RX/TX bytes
* @dstats: Dummy statistics: RX/TX/drop packets, RX/TX bytes
*
* @garp_port: GARP
* @mrp_port: MRP
Expand Down Expand Up @@ -2328,6 +2339,7 @@ struct net_device {
void *ml_priv;
enum netdev_ml_priv_type ml_priv_type;

enum netdev_stat_type pcpu_stat_type:8;
union {
struct pcpu_lstats __percpu *lstats;
struct pcpu_sw_netstats __percpu *tstats;
Expand Down
49 changes: 48 additions & 1 deletion net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -10050,6 +10050,46 @@ 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;

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
Expand Down Expand Up @@ -10110,9 +10150,13 @@ int register_netdevice(struct net_device *dev)
goto err_uninit;
}

ret = netdev_do_alloc_pcpu_stats(dev);
if (ret)
goto err_uninit;

ret = dev_index_reserve(net, dev->ifindex);
if (ret < 0)
goto err_uninit;
goto err_free_pcpu;
dev->ifindex = ret;

/* Transfer changeable features to wanted_features and enable
Expand Down Expand Up @@ -10218,6 +10262,8 @@ int register_netdevice(struct net_device *dev)
call_netdevice_notifiers(NETDEV_PRE_UNINIT, dev);
err_ifindex_release:
dev_index_release(net, dev->ifindex);
err_free_pcpu:
netdev_do_free_pcpu_stats(dev);
err_uninit:
if (dev->netdev_ops->ndo_uninit)
dev->netdev_ops->ndo_uninit(dev);
Expand Down Expand Up @@ -10470,6 +10516,7 @@ void netdev_run_todo(void)
WARN_ON(rcu_access_pointer(dev->ip_ptr));
WARN_ON(rcu_access_pointer(dev->ip6_ptr));

netdev_do_free_pcpu_stats(dev);
if (dev->priv_destructor)
dev->priv_destructor(dev);
if (dev->needs_free_netdev)
Expand Down

0 comments on commit 6ae7b3f

Please sign in to comment.