net: Move {l,t,d}stats allocation to core and convert veth & vrf

JIRA: https://issues.redhat.com/browse/RHEL-57740

Conflicts:
- include/linux/netdevice.h:
  context conflict due to backported commit c353c7b7ffb7a ("net-device:
  move lstats in net_device_read_txrx")
- drivers/net/veth.c:
  modified due to backported commit 0bef512012b1c ("net: add
  netdev_lockdep_set_classes() to virtual drivers")
- net/core/dev.c:
  context conflict due to missing commit 1202cdd665315 ("Remove DECnet
  support from kernel")

commit 34d21de99cea9cb17967874313e5b0262527833c
Author: Daniel Borkmann <daniel@iogearbox.net>
Date:   Tue Nov 14 01:42:14 2023 +0100

    net: Move {l,t,d}stats allocation to core and convert veth & vrf

    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>

Signed-off-by: Ivan Vecera <ivecera@redhat.com>
This commit is contained in:
Ivan Vecera 2024-09-06 10:10:23 +02:00
parent 5d16900145
commit 28e56919a1
4 changed files with 71 additions and 30 deletions

View File

@ -1430,26 +1430,13 @@ 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;
netdev_lockdep_set_classes(dev);
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
@ -1738,6 +1725,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;

View File

@ -1166,22 +1166,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;
@ -1195,9 +1188,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;
}
@ -1696,6 +1686,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[],

View File

@ -1769,6 +1769,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.
*
@ -1964,10 +1971,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
@ -2355,6 +2366,8 @@ struct net_device {
void *ml_priv;
enum netdev_ml_priv_type ml_priv_type;
enum netdev_stat_type pcpu_stat_type:8;
#if IS_ENABLED(CONFIG_GARP)
struct garp_port __rcu *garp_port;
#endif

View File

@ -9962,6 +9962,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
@ -10030,9 +10070,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
@ -10138,6 +10182,8 @@ err_uninit_notify:
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);
@ -10392,6 +10438,8 @@ void netdev_run_todo(void)
#if IS_ENABLED(CONFIG_DECNET)
WARN_ON(dev->dn_ptr);
#endif
netdev_do_free_pcpu_stats(dev);
if (dev->priv_destructor)
dev->priv_destructor(dev);
if (dev->needs_free_netdev)