Skip to content

Commit 34d21de

Browse files
borkmannMartin KaFai Lau
authored and
Martin KaFai Lau
committed
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>
1 parent 79e0c5b commit 34d21de

File tree

4 files changed

+69
-30
lines changed

4 files changed

+69
-30
lines changed

drivers/net/veth.c

+2-14
Original file line numberDiff line numberDiff line change
@@ -1506,25 +1506,12 @@ static void veth_free_queues(struct net_device *dev)
15061506

15071507
static int veth_dev_init(struct net_device *dev)
15081508
{
1509-
int err;
1510-
1511-
dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats);
1512-
if (!dev->lstats)
1513-
return -ENOMEM;
1514-
1515-
err = veth_alloc_queues(dev);
1516-
if (err) {
1517-
free_percpu(dev->lstats);
1518-
return err;
1519-
}
1520-
1521-
return 0;
1509+
return veth_alloc_queues(dev);
15221510
}
15231511

15241512
static void veth_dev_free(struct net_device *dev)
15251513
{
15261514
veth_free_queues(dev);
1527-
free_percpu(dev->lstats);
15281515
}
15291516

15301517
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1796,6 +1783,7 @@ static void veth_setup(struct net_device *dev)
17961783
NETIF_F_HW_VLAN_STAG_RX);
17971784
dev->needs_free_netdev = true;
17981785
dev->priv_destructor = veth_dev_free;
1786+
dev->pcpu_stat_type = NETDEV_PCPU_STAT_LSTATS;
17991787
dev->max_mtu = ETH_MAX_MTU;
18001788

18011789
dev->hw_features = VETH_FEATURES;

drivers/net/vrf.c

+3-11
Original file line numberDiff line numberDiff line change
@@ -1164,22 +1164,15 @@ static void vrf_dev_uninit(struct net_device *dev)
11641164

11651165
vrf_rtable_release(dev, vrf);
11661166
vrf_rt6_release(dev, vrf);
1167-
1168-
free_percpu(dev->dstats);
1169-
dev->dstats = NULL;
11701167
}
11711168

11721169
static int vrf_dev_init(struct net_device *dev)
11731170
{
11741171
struct net_vrf *vrf = netdev_priv(dev);
11751172

1176-
dev->dstats = netdev_alloc_pcpu_stats(struct pcpu_dstats);
1177-
if (!dev->dstats)
1178-
goto out_nomem;
1179-
11801173
/* create the default dst which points back to us */
11811174
if (vrf_rtable_create(dev) != 0)
1182-
goto out_stats;
1175+
goto out_nomem;
11831176

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

11941187
out_rth:
11951188
vrf_rtable_release(dev, vrf);
1196-
out_stats:
1197-
free_percpu(dev->dstats);
1198-
dev->dstats = NULL;
11991189
out_nomem:
12001190
return -ENOMEM;
12011191
}
@@ -1694,6 +1684,8 @@ static void vrf_setup(struct net_device *dev)
16941684
dev->min_mtu = IPV6_MIN_MTU;
16951685
dev->max_mtu = IP6_MAX_MTU;
16961686
dev->mtu = dev->max_mtu;
1687+
1688+
dev->pcpu_stat_type = NETDEV_PCPU_STAT_DSTATS;
16971689
}
16981690

16991691
static int vrf_validate(struct nlattr *tb[], struct nlattr *data[],

include/linux/netdevice.h

+16-4
Original file line numberDiff line numberDiff line change
@@ -1797,6 +1797,13 @@ enum netdev_ml_priv_type {
17971797
ML_PRIV_CAN,
17981798
};
17991799

1800+
enum netdev_stat_type {
1801+
NETDEV_PCPU_STAT_NONE,
1802+
NETDEV_PCPU_STAT_LSTATS, /* struct pcpu_lstats */
1803+
NETDEV_PCPU_STAT_TSTATS, /* struct pcpu_sw_netstats */
1804+
NETDEV_PCPU_STAT_DSTATS, /* struct pcpu_dstats */
1805+
};
1806+
18001807
/**
18011808
* struct net_device - The DEVICE structure.
18021809
*
@@ -1991,10 +1998,14 @@ enum netdev_ml_priv_type {
19911998
*
19921999
* @ml_priv: Mid-layer private
19932000
* @ml_priv_type: Mid-layer private type
1994-
* @lstats: Loopback statistics
1995-
* @tstats: Tunnel statistics
1996-
* @dstats: Dummy statistics
1997-
* @vstats: Virtual ethernet statistics
2001+
*
2002+
* @pcpu_stat_type: Type of device statistics which the core should
2003+
* allocate/free: none, lstats, tstats, dstats. none
2004+
* means the driver is handling statistics allocation/
2005+
* freeing internally.
2006+
* @lstats: Loopback statistics: packets, bytes
2007+
* @tstats: Tunnel statistics: RX/TX packets, RX/TX bytes
2008+
* @dstats: Dummy statistics: RX/TX/drop packets, RX/TX bytes
19982009
*
19992010
* @garp_port: GARP
20002011
* @mrp_port: MRP
@@ -2354,6 +2365,7 @@ struct net_device {
23542365
void *ml_priv;
23552366
enum netdev_ml_priv_type ml_priv_type;
23562367

2368+
enum netdev_stat_type pcpu_stat_type:8;
23572369
union {
23582370
struct pcpu_lstats __percpu *lstats;
23592371
struct pcpu_sw_netstats __percpu *tstats;

net/core/dev.c

+48-1
Original file line numberDiff line numberDiff line change
@@ -10051,6 +10051,46 @@ void netif_tx_stop_all_queues(struct net_device *dev)
1005110051
}
1005210052
EXPORT_SYMBOL(netif_tx_stop_all_queues);
1005310053

10054+
static int netdev_do_alloc_pcpu_stats(struct net_device *dev)
10055+
{
10056+
void __percpu *v;
10057+
10058+
switch (dev->pcpu_stat_type) {
10059+
case NETDEV_PCPU_STAT_NONE:
10060+
return 0;
10061+
case NETDEV_PCPU_STAT_LSTATS:
10062+
v = dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats);
10063+
break;
10064+
case NETDEV_PCPU_STAT_TSTATS:
10065+
v = dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
10066+
break;
10067+
case NETDEV_PCPU_STAT_DSTATS:
10068+
v = dev->dstats = netdev_alloc_pcpu_stats(struct pcpu_dstats);
10069+
break;
10070+
default:
10071+
return -EINVAL;
10072+
}
10073+
10074+
return v ? 0 : -ENOMEM;
10075+
}
10076+
10077+
static void netdev_do_free_pcpu_stats(struct net_device *dev)
10078+
{
10079+
switch (dev->pcpu_stat_type) {
10080+
case NETDEV_PCPU_STAT_NONE:
10081+
return;
10082+
case NETDEV_PCPU_STAT_LSTATS:
10083+
free_percpu(dev->lstats);
10084+
break;
10085+
case NETDEV_PCPU_STAT_TSTATS:
10086+
free_percpu(dev->tstats);
10087+
break;
10088+
case NETDEV_PCPU_STAT_DSTATS:
10089+
free_percpu(dev->dstats);
10090+
break;
10091+
}
10092+
}
10093+
1005410094
/**
1005510095
* register_netdevice() - register a network device
1005610096
* @dev: device to register
@@ -10111,9 +10151,13 @@ int register_netdevice(struct net_device *dev)
1011110151
goto err_uninit;
1011210152
}
1011310153

10154+
ret = netdev_do_alloc_pcpu_stats(dev);
10155+
if (ret)
10156+
goto err_uninit;
10157+
1011410158
ret = dev_index_reserve(net, dev->ifindex);
1011510159
if (ret < 0)
10116-
goto err_uninit;
10160+
goto err_free_pcpu;
1011710161
dev->ifindex = ret;
1011810162

1011910163
/* Transfer changeable features to wanted_features and enable
@@ -10219,6 +10263,8 @@ int register_netdevice(struct net_device *dev)
1021910263
call_netdevice_notifiers(NETDEV_PRE_UNINIT, dev);
1022010264
err_ifindex_release:
1022110265
dev_index_release(net, dev->ifindex);
10266+
err_free_pcpu:
10267+
netdev_do_free_pcpu_stats(dev);
1022210268
err_uninit:
1022310269
if (dev->netdev_ops->ndo_uninit)
1022410270
dev->netdev_ops->ndo_uninit(dev);
@@ -10471,6 +10517,7 @@ void netdev_run_todo(void)
1047110517
WARN_ON(rcu_access_pointer(dev->ip_ptr));
1047210518
WARN_ON(rcu_access_pointer(dev->ip6_ptr));
1047310519

10520+
netdev_do_free_pcpu_stats(dev);
1047410521
if (dev->priv_destructor)
1047510522
dev->priv_destructor(dev);
1047610523
if (dev->needs_free_netdev)

0 commit comments

Comments
 (0)