[PATCH net-next v2 1/5] net: Add netdev_config helpers

From: Björn Töpel

Date: Thu Sep 10 2026 - 14:20:13 EST


From: Jakub Kicinski <kuba@xxxxxxxxxx>

netdev_config manipulation will become slightly more complicated
soon and will be used by both ethtool and the queue API.
Encapsulate the logic in helper functions.

Signed-off-by: Jakub Kicinski <kuba@xxxxxxxxxx>
Signed-off-by: Björn Töpel <bjorn@xxxxxxxxxx>
---
net/core/dev.c | 7 ++-----
net/core/dev.h | 5 +++++
net/core/netdev_config.c | 37 +++++++++++++++++++++++++++++++++++++
net/ethtool/netlink.c | 15 +++++++--------
4 files changed, 51 insertions(+), 13 deletions(-)

diff --git a/net/core/dev.c b/net/core/dev.c
index 290e0f099e6b..4a7c5a5e48e5 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -12195,10 +12195,8 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
if (!dev->ethtool)
goto free_all;

- dev->cfg = kzalloc_obj(*dev->cfg, GFP_KERNEL_ACCOUNT);
- if (!dev->cfg)
+ if (netdev_alloc_config(dev))
goto free_all;
- dev->cfg_pending = dev->cfg;

dev->num_napi_configs = maxqs;
napi_config_sz = array_size(maxqs, sizeof(*dev->napi_config));
@@ -12270,8 +12268,7 @@ void free_netdev(struct net_device *dev)
return;
}

- WARN_ON(dev->cfg != dev->cfg_pending);
- kfree(dev->cfg);
+ netdev_free_config(dev);
kfree(dev->ethtool);
netif_free_tx_queues(dev);
netif_free_rx_queues(dev);
diff --git a/net/core/dev.h b/net/core/dev.h
index b757faead4d1..4b52ff779cba 100644
--- a/net/core/dev.h
+++ b/net/core/dev.h
@@ -102,6 +102,11 @@ extern struct rw_semaphore dev_addr_sem;
extern struct list_head net_todo_list;
void netdev_run_todo(void);

+int netdev_alloc_config(struct net_device *dev);
+void __netdev_free_config(struct netdev_config *cfg);
+void netdev_free_config(struct net_device *dev);
+int netdev_reconfig_start(struct net_device *dev);
+
int netdev_queue_config_validate(struct net_device *dev, int rxq_idx,
struct netdev_queue_config *qcfg,
struct netlink_ext_ack *extack);
diff --git a/net/core/netdev_config.c b/net/core/netdev_config.c
index f14af365d5cd..b101341e3251 100644
--- a/net/core/netdev_config.c
+++ b/net/core/netdev_config.c
@@ -6,6 +6,43 @@

#include "dev.h"

+int netdev_alloc_config(struct net_device *dev)
+{
+ struct netdev_config *cfg;
+
+ cfg = kzalloc_obj(*dev->cfg, GFP_KERNEL_ACCOUNT);
+ if (!cfg)
+ return -ENOMEM;
+
+ dev->cfg = cfg;
+ dev->cfg_pending = cfg;
+ return 0;
+}
+
+void __netdev_free_config(struct netdev_config *cfg)
+{
+ kfree(cfg);
+}
+
+void netdev_free_config(struct net_device *dev)
+{
+ WARN_ON(dev->cfg != dev->cfg_pending);
+ __netdev_free_config(dev->cfg);
+}
+
+int netdev_reconfig_start(struct net_device *dev)
+{
+ struct netdev_config *cfg;
+
+ WARN_ON(dev->cfg != dev->cfg_pending);
+ cfg = kmemdup(dev->cfg, sizeof(*dev->cfg), GFP_KERNEL_ACCOUNT);
+ if (!cfg)
+ return -ENOMEM;
+
+ dev->cfg_pending = cfg;
+ return 0;
+}
+
static int netdev_nop_validate_qcfg(struct net_device *dev,
struct netdev_queue_config *qcfg,
struct netlink_ext_ack *extack)
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 1af395b54330..383e911f50f7 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -11,6 +11,8 @@
#include "module_fw.h"
#include "netlink.h"

+#include "../core/dev.h"
+
static struct genl_family ethtool_genl_family;

static bool ethnl_ok __read_mostly;
@@ -934,12 +936,9 @@ static int ethnl_default_set_doit(struct sk_buff *skb, struct genl_info *info)
if (need_rtnl)
rtnl_lock();
netdev_lock_ops(dev);
- dev->cfg_pending = kmemdup(dev->cfg, sizeof(*dev->cfg),
- GFP_KERNEL_ACCOUNT);
- if (!dev->cfg_pending) {
- ret = -ENOMEM;
- goto out_tie_cfg;
- }
+ ret = netdev_reconfig_start(dev);
+ if (ret)
+ goto out_unlock;

ret = ethnl_ops_begin(dev);
if (ret < 0)
@@ -958,9 +957,9 @@ static int ethnl_default_set_doit(struct sk_buff *skb, struct genl_info *info)
out_ops:
ethnl_ops_complete(dev);
out_free_cfg:
- kfree(dev->cfg_pending);
-out_tie_cfg:
+ __netdev_free_config(dev->cfg_pending);
dev->cfg_pending = dev->cfg;
+out_unlock:
netdev_unlock_ops(dev);
if (need_rtnl)
rtnl_unlock();
--
2.55.0