* [PATCH net-next 0/9] netpoll: finish untangling netconsole from netpoll
@ 2026-07-24 15:04 Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 1/9] netpoll: export carrier_timeout via netpoll_get_carrier_timeout() Breno Leitao
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Breno Leitao @ 2026-07-24 15:04 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn
Cc: netdev, linux-kernel, gustavold, asantostc, Breno Leitao,
kernel-team
This is the final series moving the netconsole-specific functions out of
netpoll and into netconsole.
There is nothing else left except struct netpoll ->name and ->dev_mac
fields, which are netconsole-specific fields, but they are still in
netpoll structure (no other netpoll user uses these two fields).
netpoll is now left simpler and with a clearer role: an API that takes
an skb and transmits it. The device setup and the local/remote address
handling that only netconsole needs no longer sit in the generic netpoll
code, but in netconsole (which was the only user).
struct netpoll gets leaner too. The netconsole-only fields are gone, so
the other netpoll users (bonding, team, bridge, vlan, macvlan, dsa) no
longer carry fields they never touch. (except ->name and ->dev_mac)
Signed-off-by: Breno Leitao <leitao@debian.org>
---
Breno Leitao (9):
netpoll: export carrier_timeout via netpoll_get_carrier_timeout()
netpoll: export the netpoll_setup() helpers for netconsole
netconsole: take over netpoll_setup() from netpoll
netconsole: move netpoll_local_ip_unset() as netcons_local_ip_unset()
netconsole: move netpoll_take_ipv4() as netcons_take_ipv4()
netconsole: move netpoll_take_ipv6() as netcons_take_ipv6()
netconsole: move egress_dev() as netcons_egress_dev()
netconsole: move local_ip/remote_ip/ipv6 to netconsole_target
netconsole: move netpoll_wait_carrier() as netcons_wait_carrier()
drivers/net/netconsole.c | 301 +++++++++++++++++++++++++++++++++++++++--------
include/linux/netpoll.h | 5 +-
net/core/netpoll.c | 210 ++-------------------------------
3 files changed, 267 insertions(+), 249 deletions(-)
---
base-commit: 9eebf259d5352b87080d67758f483583d9e763d7
change-id: 20260721-netconsole_move_more_final-6ebdc01ecc19
Best regards,
--
Breno Leitao <leitao@debian.org>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH net-next 1/9] netpoll: export carrier_timeout via netpoll_get_carrier_timeout()
2026-07-24 15:04 [PATCH net-next 0/9] netpoll: finish untangling netconsole from netpoll Breno Leitao
@ 2026-07-24 15:04 ` Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 2/9] netpoll: export the netpoll_setup() helpers for netconsole Breno Leitao
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Breno Leitao @ 2026-07-24 15:04 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn
Cc: netdev, linux-kernel, gustavold, asantostc, Breno Leitao,
kernel-team
netpoll_wait_carrier() is only used in netconsole, and it will move to
netconsole.
The carrier_timeout module parameter has to stay in netpoll so the
existing netpoll.carrier_timeout kernel parameter keeps working for
current users, and we don't break user compatibility.
Add a netpoll_get_carrier_timeout() accessor and export it so netconsole
can read the value once the carrier wait lives there. Drop the now
redundant timeout argument from netpoll_wait_carrier() (its only caller
passed carrier_timeout) and read the parameter directly while the helper
still lives here.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
include/linux/netpoll.h | 1 +
net/core/netpoll.c | 18 ++++++++++++++----
2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 79315461a7b1e..d426d1844cac7 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -72,6 +72,7 @@ void netpoll_cleanup(struct netpoll *np);
void do_netpoll_cleanup(struct netpoll *np);
netdev_tx_t netpoll_send_skb(struct netpoll *np, struct sk_buff *skb);
void netpoll_zap_completion_queue(void);
+unsigned int netpoll_get_carrier_timeout(void);
#ifdef CONFIG_NETPOLL
static inline void *netpoll_poll_lock(struct napi_struct *napi)
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index f8da1048ea3ab..9b9fcc307958f 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -38,9 +38,20 @@
#define USEC_PER_POLL 50
+/*
+ * carrier_timeout is netconsole-specific and only kept here to preserve the
+ * netpoll.carrier_timeout module-parameter ABI. Its value is exposed to
+ * netconsole through netpoll_get_carrier_timeout().
+ */
static unsigned int carrier_timeout = 4;
module_param(carrier_timeout, uint, 0644);
+unsigned int netpoll_get_carrier_timeout(void)
+{
+ return carrier_timeout;
+}
+EXPORT_SYMBOL_GPL(netpoll_get_carrier_timeout);
+
static netdev_tx_t netpoll_start_xmit(struct sk_buff *skb,
struct net_device *dev,
struct netdev_queue *txq)
@@ -397,12 +408,11 @@ static char *egress_dev(struct netpoll *np, char *buf, size_t bufsz)
return buf;
}
-static void netpoll_wait_carrier(struct netpoll *np, struct net_device *ndev,
- unsigned int timeout)
+static void netpoll_wait_carrier(struct netpoll *np, struct net_device *ndev)
{
unsigned long atmost;
- atmost = jiffies + timeout * HZ;
+ atmost = jiffies + carrier_timeout * HZ;
while (!netif_carrier_ok(ndev)) {
if (time_after(jiffies, atmost)) {
np_notice(np, "timeout waiting for carrier\n");
@@ -539,7 +549,7 @@ int netpoll_setup(struct netpoll *np)
}
rtnl_unlock();
- netpoll_wait_carrier(np, ndev, carrier_timeout);
+ netpoll_wait_carrier(np, ndev);
rtnl_lock();
}
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 2/9] netpoll: export the netpoll_setup() helpers for netconsole
2026-07-24 15:04 [PATCH net-next 0/9] netpoll: finish untangling netconsole from netpoll Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 1/9] netpoll: export carrier_timeout via netpoll_get_carrier_timeout() Breno Leitao
@ 2026-07-24 15:04 ` Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 3/9] netconsole: take over netpoll_setup() from netpoll Breno Leitao
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Breno Leitao @ 2026-07-24 15:04 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn
Cc: netdev, linux-kernel, gustavold, asantostc, Breno Leitao,
kernel-team
Temporarily export leaf functions that will be moved to netconsole.
The upcoming patch will move the setup function to netconsole, and
continue to call these leaf functions here in netpoll, then other
patches will move these exports functions to netconsole (and make them
statics).
In summary, these exports are temporary in order to make the patchset
digestible.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
include/linux/netpoll.h | 5 +++++
net/core/netpoll.c | 15 ++++++++++-----
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index d426d1844cac7..0877515fa7442 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -73,6 +73,11 @@ void do_netpoll_cleanup(struct netpoll *np);
netdev_tx_t netpoll_send_skb(struct netpoll *np, struct sk_buff *skb);
void netpoll_zap_completion_queue(void);
unsigned int netpoll_get_carrier_timeout(void);
+void netpoll_wait_carrier(struct netpoll *np, struct net_device *ndev);
+char *egress_dev(struct netpoll *np, char *buf, size_t bufsz);
+int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev);
+int netpoll_take_ipv6(struct netpoll *np, struct net_device *ndev);
+bool netpoll_local_ip_unset(const struct netpoll *np);
#ifdef CONFIG_NETPOLL
static inline void *netpoll_poll_lock(struct napi_struct *napi)
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 9b9fcc307958f..6a545063223ba 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -399,7 +399,7 @@ EXPORT_SYMBOL_GPL(__netpoll_setup);
* be at least MAC_ADDR_STR_LEN + 1 to fit the formatted MAC address
* and its NUL terminator.
*/
-static char *egress_dev(struct netpoll *np, char *buf, size_t bufsz)
+char *egress_dev(struct netpoll *np, char *buf, size_t bufsz)
{
if (np->dev_name[0])
return np->dev_name;
@@ -407,8 +407,9 @@ static char *egress_dev(struct netpoll *np, char *buf, size_t bufsz)
snprintf(buf, bufsz, "%pM", np->dev_mac);
return buf;
}
+EXPORT_SYMBOL_GPL(egress_dev);
-static void netpoll_wait_carrier(struct netpoll *np, struct net_device *ndev)
+void netpoll_wait_carrier(struct netpoll *np, struct net_device *ndev)
{
unsigned long atmost;
@@ -421,11 +422,12 @@ static void netpoll_wait_carrier(struct netpoll *np, struct net_device *ndev)
msleep(1);
}
}
+EXPORT_SYMBOL_GPL(netpoll_wait_carrier);
/*
* Take the IPv6 from ndev and populate local_ip structure in netpoll
*/
-static int netpoll_take_ipv6(struct netpoll *np, struct net_device *ndev)
+int netpoll_take_ipv6(struct netpoll *np, struct net_device *ndev)
{
char buf[MAC_ADDR_STR_LEN + 1];
int err = -EDESTADDRREQ;
@@ -462,11 +464,12 @@ static int netpoll_take_ipv6(struct netpoll *np, struct net_device *ndev)
np_info(np, "local IPv6 %pI6c\n", &np->local_ip.in6);
return 0;
}
+EXPORT_SYMBOL_GPL(netpoll_take_ipv6);
/*
* Take the IPv4 from ndev and populate local_ip structure in netpoll
*/
-static int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev)
+int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev)
{
char buf[MAC_ADDR_STR_LEN + 1];
const struct in_ifaddr *ifa;
@@ -491,6 +494,7 @@ static int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev)
return 0;
}
+EXPORT_SYMBOL_GPL(netpoll_take_ipv4);
/*
* Test whether the caller left np->local_ip unset, so that
@@ -502,12 +506,13 @@ static int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev)
* doing so would misclassify a caller-supplied address as unset and
* silently overwrite it with whatever address the device exposes.
*/
-static bool netpoll_local_ip_unset(const struct netpoll *np)
+bool netpoll_local_ip_unset(const struct netpoll *np)
{
if (np->ipv6)
return ipv6_addr_any(&np->local_ip.in6);
return !np->local_ip.ip;
}
+EXPORT_SYMBOL_GPL(netpoll_local_ip_unset);
int netpoll_setup(struct netpoll *np)
{
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 3/9] netconsole: take over netpoll_setup() from netpoll
2026-07-24 15:04 [PATCH net-next 0/9] netpoll: finish untangling netconsole from netpoll Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 1/9] netpoll: export carrier_timeout via netpoll_get_carrier_timeout() Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 2/9] netpoll: export the netpoll_setup() helpers for netconsole Breno Leitao
@ 2026-07-24 15:04 ` Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 4/9] netconsole: move netpoll_local_ip_unset() as netcons_local_ip_unset() Breno Leitao
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Breno Leitao @ 2026-07-24 15:04 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn
Cc: netdev, linux-kernel, gustavold, asantostc, Breno Leitao,
kernel-team
netpoll_setup() is only used by netconsole. All the other users use
__netpoll_setup().
Move netpoll_setup() to netconsole, and rename it to
netcons_netpoll_setup().
Pure code motion: the body is unchanged.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
drivers/net/netconsole.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++--
include/linux/netpoll.h | 1 -
net/core/netpoll.c | 81 ---------------------------------------------
3 files changed, 83 insertions(+), 85 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 7f8851a734fcd..3a7a2cafc6276 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -351,6 +351,86 @@ static void netconsole_skb_pool_flush(struct netconsole_target *nt)
skb_queue_purge_reason(&nt->skb_pool, SKB_CONSUMED);
}
+static int netcons_netpoll_setup(struct netpoll *np)
+{
+ struct net *net = current->nsproxy->net_ns;
+ char buf[MAC_ADDR_STR_LEN + 1];
+ struct net_device *ndev = NULL;
+ bool ip_overwritten = false;
+ int err;
+
+ rtnl_lock();
+ if (np->dev_name[0])
+ ndev = __dev_get_by_name(net, np->dev_name);
+ else if (is_valid_ether_addr(np->dev_mac))
+ ndev = dev_getbyhwaddr(net, ARPHRD_ETHER, np->dev_mac);
+
+ if (!ndev) {
+ np_err(np, "%s doesn't exist, aborting\n",
+ egress_dev(np, buf, sizeof(buf)));
+ err = -ENODEV;
+ goto unlock;
+ }
+ netdev_hold(ndev, &np->dev_tracker, GFP_KERNEL);
+
+ if (netdev_master_upper_dev_get(ndev)) {
+ np_err(np, "%s is a slave device, aborting\n",
+ egress_dev(np, buf, sizeof(buf)));
+ err = -EBUSY;
+ goto put;
+ }
+
+ if (!netif_running(ndev)) {
+ np_info(np, "device %s not up yet, forcing it\n",
+ egress_dev(np, buf, sizeof(buf)));
+
+ err = dev_open(ndev, NULL);
+ if (err) {
+ np_err(np, "failed to open %s\n", ndev->name);
+ goto put;
+ }
+
+ rtnl_unlock();
+ netpoll_wait_carrier(np, ndev);
+ rtnl_lock();
+ }
+
+ if (netpoll_local_ip_unset(np)) {
+ if (!np->ipv6) {
+ err = netpoll_take_ipv4(np, ndev);
+ if (err)
+ goto put;
+ } else {
+ err = netpoll_take_ipv6(np, ndev);
+ if (err)
+ goto put;
+ }
+ ip_overwritten = true;
+ }
+
+ err = __netpoll_setup(np, ndev);
+ if (err)
+ goto put;
+ rtnl_unlock();
+
+ /* Make sure all NAPI polls which started before dev->npinfo
+ * was visible have exited before we start calling NAPI poll.
+ * NAPI skips locking if dev->npinfo is NULL.
+ */
+ synchronize_rcu();
+
+ return 0;
+
+put:
+ DEBUG_NET_WARN_ON_ONCE(np->dev);
+ if (ip_overwritten)
+ memset(&np->local_ip, 0, sizeof(np->local_ip));
+ netdev_put(ndev, &np->dev_tracker);
+unlock:
+ rtnl_unlock();
+ return err;
+}
+
/* Attempts to resume logging to a deactivated target. */
static void resume_target(struct netconsole_target *nt)
{
@@ -361,7 +441,7 @@ static void resume_target(struct netconsole_target *nt)
*/
netconsole_skb_pool_init(nt);
- if (netpoll_setup(&nt->np)) {
+ if (netcons_netpoll_setup(&nt->np)) {
/* netpoll fails setup once, do not try again. */
netconsole_skb_pool_flush(nt);
nt->state = STATE_DISABLED;
@@ -840,7 +920,7 @@ static ssize_t enabled_store(struct config_item *item,
*/
netconsole_skb_pool_init(nt);
- ret = netpoll_setup(&nt->np);
+ ret = netcons_netpoll_setup(&nt->np);
if (ret) {
netconsole_skb_pool_flush(nt);
goto out_unlock;
@@ -2430,7 +2510,7 @@ static struct netconsole_target *alloc_param_target(char *target_config,
*/
netconsole_skb_pool_init(nt);
- err = netpoll_setup(&nt->np);
+ err = netcons_netpoll_setup(&nt->np);
if (err) {
pr_err("Not enabling netconsole for %s%d. Netpoll setup failed\n",
NETCONSOLE_PARAM_TARGET_PREFIX, cmdline_count);
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 0877515fa7442..cd455a5a013d2 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -66,7 +66,6 @@ static inline void netpoll_poll_enable(struct net_device *dev) { return; }
#endif
int __netpoll_setup(struct netpoll *np, struct net_device *ndev);
-int netpoll_setup(struct netpoll *np);
void __netpoll_free(struct netpoll *np);
void netpoll_cleanup(struct netpoll *np);
void do_netpoll_cleanup(struct netpoll *np);
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 6a545063223ba..d50d48a82def6 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -514,87 +514,6 @@ bool netpoll_local_ip_unset(const struct netpoll *np)
}
EXPORT_SYMBOL_GPL(netpoll_local_ip_unset);
-int netpoll_setup(struct netpoll *np)
-{
- struct net *net = current->nsproxy->net_ns;
- char buf[MAC_ADDR_STR_LEN + 1];
- struct net_device *ndev = NULL;
- bool ip_overwritten = false;
- int err;
-
- rtnl_lock();
- if (np->dev_name[0])
- ndev = __dev_get_by_name(net, np->dev_name);
- else if (is_valid_ether_addr(np->dev_mac))
- ndev = dev_getbyhwaddr(net, ARPHRD_ETHER, np->dev_mac);
-
- if (!ndev) {
- np_err(np, "%s doesn't exist, aborting\n",
- egress_dev(np, buf, sizeof(buf)));
- err = -ENODEV;
- goto unlock;
- }
- netdev_hold(ndev, &np->dev_tracker, GFP_KERNEL);
-
- if (netdev_master_upper_dev_get(ndev)) {
- np_err(np, "%s is a slave device, aborting\n",
- egress_dev(np, buf, sizeof(buf)));
- err = -EBUSY;
- goto put;
- }
-
- if (!netif_running(ndev)) {
- np_info(np, "device %s not up yet, forcing it\n",
- egress_dev(np, buf, sizeof(buf)));
-
- err = dev_open(ndev, NULL);
- if (err) {
- np_err(np, "failed to open %s\n", ndev->name);
- goto put;
- }
-
- rtnl_unlock();
- netpoll_wait_carrier(np, ndev);
- rtnl_lock();
- }
-
- if (netpoll_local_ip_unset(np)) {
- if (!np->ipv6) {
- err = netpoll_take_ipv4(np, ndev);
- if (err)
- goto put;
- } else {
- err = netpoll_take_ipv6(np, ndev);
- if (err)
- goto put;
- }
- ip_overwritten = true;
- }
-
- err = __netpoll_setup(np, ndev);
- if (err)
- goto put;
- rtnl_unlock();
-
- /* Make sure all NAPI polls which started before dev->npinfo
- * was visible have exited before we start calling NAPI poll.
- * NAPI skips locking if dev->npinfo is NULL.
- */
- synchronize_rcu();
-
- return 0;
-
-put:
- DEBUG_NET_WARN_ON_ONCE(np->dev);
- if (ip_overwritten)
- memset(&np->local_ip, 0, sizeof(np->local_ip));
- netdev_put(ndev, &np->dev_tracker);
-unlock:
- rtnl_unlock();
- return err;
-}
-EXPORT_SYMBOL(netpoll_setup);
-
static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
{
struct netpoll_info *npinfo =
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 4/9] netconsole: move netpoll_local_ip_unset() as netcons_local_ip_unset()
2026-07-24 15:04 [PATCH net-next 0/9] netpoll: finish untangling netconsole from netpoll Breno Leitao
` (2 preceding siblings ...)
2026-07-24 15:04 ` [PATCH net-next 3/9] netconsole: take over netpoll_setup() from netpoll Breno Leitao
@ 2026-07-24 15:04 ` Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 5/9] netconsole: move netpoll_take_ipv4() as netcons_take_ipv4() Breno Leitao
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Breno Leitao @ 2026-07-24 15:04 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn
Cc: netdev, linux-kernel, gustavold, asantostc, Breno Leitao,
kernel-team
Move netpoll_local_ip_unset() from netpoll to netconsole and rename it
to netcons_local_ip_unset();
The body is otherwise unchanged, only the comment's setup-function
reference is updated.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
drivers/net/netconsole.c | 19 ++++++++++++++++++-
include/linux/netpoll.h | 1 -
net/core/netpoll.c | 18 ------------------
3 files changed, 18 insertions(+), 20 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 3a7a2cafc6276..70f9c5bfb3720 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -351,6 +351,23 @@ static void netconsole_skb_pool_flush(struct netconsole_target *nt)
skb_queue_purge_reason(&nt->skb_pool, SKB_CONSUMED);
}
+/*
+ * Test whether the caller left np->local_ip unset, so that
+ * netcons_netpoll_setup() should auto-populate it from the egress device.
+ *
+ * np->local_ip is a union of __be32 (IPv4) and struct in6_addr (IPv6),
+ * so an IPv6 address whose first 4 bytes are zero (e.g. ::1, ::2,
+ * IPv4-mapped ::ffff:a.b.c.d) must not be tested via the IPv4 arm —
+ * doing so would misclassify a caller-supplied address as unset and
+ * silently overwrite it with whatever address the device exposes.
+ */
+static bool netcons_local_ip_unset(const struct netpoll *np)
+{
+ if (np->ipv6)
+ return ipv6_addr_any(&np->local_ip.in6);
+ return !np->local_ip.ip;
+}
+
static int netcons_netpoll_setup(struct netpoll *np)
{
struct net *net = current->nsproxy->net_ns;
@@ -395,7 +412,7 @@ static int netcons_netpoll_setup(struct netpoll *np)
rtnl_lock();
}
- if (netpoll_local_ip_unset(np)) {
+ if (netcons_local_ip_unset(np)) {
if (!np->ipv6) {
err = netpoll_take_ipv4(np, ndev);
if (err)
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index cd455a5a013d2..da05884f876e5 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -76,7 +76,6 @@ void netpoll_wait_carrier(struct netpoll *np, struct net_device *ndev);
char *egress_dev(struct netpoll *np, char *buf, size_t bufsz);
int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev);
int netpoll_take_ipv6(struct netpoll *np, struct net_device *ndev);
-bool netpoll_local_ip_unset(const struct netpoll *np);
#ifdef CONFIG_NETPOLL
static inline void *netpoll_poll_lock(struct napi_struct *napi)
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index d50d48a82def6..f4b110cb04167 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -496,24 +496,6 @@ int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev)
}
EXPORT_SYMBOL_GPL(netpoll_take_ipv4);
-/*
- * Test whether the caller left np->local_ip unset, so that
- * netpoll_setup() should auto-populate it from the egress device.
- *
- * np->local_ip is a union of __be32 (IPv4) and struct in6_addr (IPv6),
- * so an IPv6 address whose first 4 bytes are zero (e.g. ::1, ::2,
- * IPv4-mapped ::ffff:a.b.c.d) must not be tested via the IPv4 arm —
- * doing so would misclassify a caller-supplied address as unset and
- * silently overwrite it with whatever address the device exposes.
- */
-bool netpoll_local_ip_unset(const struct netpoll *np)
-{
- if (np->ipv6)
- return ipv6_addr_any(&np->local_ip.in6);
- return !np->local_ip.ip;
-}
-EXPORT_SYMBOL_GPL(netpoll_local_ip_unset);
-
static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
{
struct netpoll_info *npinfo =
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 5/9] netconsole: move netpoll_take_ipv4() as netcons_take_ipv4()
2026-07-24 15:04 [PATCH net-next 0/9] netpoll: finish untangling netconsole from netpoll Breno Leitao
` (3 preceding siblings ...)
2026-07-24 15:04 ` [PATCH net-next 4/9] netconsole: move netpoll_local_ip_unset() as netcons_local_ip_unset() Breno Leitao
@ 2026-07-24 15:04 ` Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 6/9] netconsole: move netpoll_take_ipv6() as netcons_take_ipv6() Breno Leitao
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Breno Leitao @ 2026-07-24 15:04 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn
Cc: netdev, linux-kernel, gustavold, asantostc, Breno Leitao,
kernel-team
Move netpoll_take_ipv4() to netconsole, which is the only user. Rename
it to netcons_take_ipv4() for the netcons_ prefix. The body is
unchanged.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
drivers/net/netconsole.c | 32 +++++++++++++++++++++++++++++++-
include/linux/netpoll.h | 1 -
net/core/netpoll.c | 30 ------------------------------
3 files changed, 31 insertions(+), 32 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 70f9c5bfb3720..9506b1e1193fd 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -37,6 +37,7 @@
#include <linux/udp.h>
#include <linux/netpoll.h>
#include <linux/inet.h>
+#include <linux/inetdevice.h>
#include <linux/unaligned.h>
#include <net/ip6_checksum.h>
#include <linux/configfs.h>
@@ -351,6 +352,35 @@ static void netconsole_skb_pool_flush(struct netconsole_target *nt)
skb_queue_purge_reason(&nt->skb_pool, SKB_CONSUMED);
}
+/*
+ * Take the IPv4 from ndev and populate local_ip structure in netpoll
+ */
+static int netcons_take_ipv4(struct netpoll *np, struct net_device *ndev)
+{
+ char buf[MAC_ADDR_STR_LEN + 1];
+ const struct in_ifaddr *ifa;
+ struct in_device *in_dev;
+
+ in_dev = __in_dev_get_rtnl(ndev);
+ if (!in_dev) {
+ np_err(np, "no IP address for %s, aborting\n",
+ egress_dev(np, buf, sizeof(buf)));
+ return -EDESTADDRREQ;
+ }
+
+ ifa = rtnl_dereference(in_dev->ifa_list);
+ if (!ifa) {
+ np_err(np, "no IP address for %s, aborting\n",
+ egress_dev(np, buf, sizeof(buf)));
+ return -EDESTADDRREQ;
+ }
+
+ np->local_ip.ip = ifa->ifa_local;
+ np_info(np, "local IP %pI4\n", &np->local_ip.ip);
+
+ return 0;
+}
+
/*
* Test whether the caller left np->local_ip unset, so that
* netcons_netpoll_setup() should auto-populate it from the egress device.
@@ -414,7 +444,7 @@ static int netcons_netpoll_setup(struct netpoll *np)
if (netcons_local_ip_unset(np)) {
if (!np->ipv6) {
- err = netpoll_take_ipv4(np, ndev);
+ err = netcons_take_ipv4(np, ndev);
if (err)
goto put;
} else {
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index da05884f876e5..e212cb86a9429 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -74,7 +74,6 @@ void netpoll_zap_completion_queue(void);
unsigned int netpoll_get_carrier_timeout(void);
void netpoll_wait_carrier(struct netpoll *np, struct net_device *ndev);
char *egress_dev(struct netpoll *np, char *buf, size_t bufsz);
-int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev);
int netpoll_take_ipv6(struct netpoll *np, struct net_device *ndev);
#ifdef CONFIG_NETPOLL
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index f4b110cb04167..60c3faf9ea944 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -466,36 +466,6 @@ int netpoll_take_ipv6(struct netpoll *np, struct net_device *ndev)
}
EXPORT_SYMBOL_GPL(netpoll_take_ipv6);
-/*
- * Take the IPv4 from ndev and populate local_ip structure in netpoll
- */
-int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev)
-{
- char buf[MAC_ADDR_STR_LEN + 1];
- const struct in_ifaddr *ifa;
- struct in_device *in_dev;
-
- in_dev = __in_dev_get_rtnl(ndev);
- if (!in_dev) {
- np_err(np, "no IP address for %s, aborting\n",
- egress_dev(np, buf, sizeof(buf)));
- return -EDESTADDRREQ;
- }
-
- ifa = rtnl_dereference(in_dev->ifa_list);
- if (!ifa) {
- np_err(np, "no IP address for %s, aborting\n",
- egress_dev(np, buf, sizeof(buf)));
- return -EDESTADDRREQ;
- }
-
- np->local_ip.ip = ifa->ifa_local;
- np_info(np, "local IP %pI4\n", &np->local_ip.ip);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(netpoll_take_ipv4);
-
static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
{
struct netpoll_info *npinfo =
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 6/9] netconsole: move netpoll_take_ipv6() as netcons_take_ipv6()
2026-07-24 15:04 [PATCH net-next 0/9] netpoll: finish untangling netconsole from netpoll Breno Leitao
` (4 preceding siblings ...)
2026-07-24 15:04 ` [PATCH net-next 5/9] netconsole: move netpoll_take_ipv4() as netcons_take_ipv4() Breno Leitao
@ 2026-07-24 15:04 ` Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 7/9] netconsole: move egress_dev() as netcons_egress_dev() Breno Leitao
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Breno Leitao @ 2026-07-24 15:04 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn
Cc: netdev, linux-kernel, gustavold, asantostc, Breno Leitao,
kernel-team
Move netpoll_take_ipv6() to netconsole, and add netcons_ prefix.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
drivers/net/netconsole.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
include/linux/netpoll.h | 1 -
net/core/netpoll.c | 42 ------------------------------------------
3 files changed, 43 insertions(+), 44 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 9506b1e1193fd..b6cbda4722d5b 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -40,6 +40,7 @@
#include <linux/inetdevice.h>
#include <linux/unaligned.h>
#include <net/ip6_checksum.h>
+#include <net/addrconf.h>
#include <linux/configfs.h>
#include <linux/etherdevice.h>
#include <linux/hex.h>
@@ -352,6 +353,47 @@ static void netconsole_skb_pool_flush(struct netconsole_target *nt)
skb_queue_purge_reason(&nt->skb_pool, SKB_CONSUMED);
}
+/*
+ * Take the IPv6 from ndev and populate local_ip structure in netpoll
+ */
+static int netcons_take_ipv6(struct netpoll *np, struct net_device *ndev)
+{
+ char buf[MAC_ADDR_STR_LEN + 1];
+ int err = -EDESTADDRREQ;
+ struct inet6_dev *idev;
+
+ if (!IS_ENABLED(CONFIG_IPV6)) {
+ np_err(np, "IPv6 is not supported %s, aborting\n",
+ egress_dev(np, buf, sizeof(buf)));
+ return -EINVAL;
+ }
+
+ idev = __in6_dev_get(ndev);
+ if (idev) {
+ struct inet6_ifaddr *ifp;
+
+ read_lock_bh(&idev->lock);
+ list_for_each_entry(ifp, &idev->addr_list, if_list) {
+ if (!!(ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL) !=
+ !!(ipv6_addr_type(&np->remote_ip.in6) & IPV6_ADDR_LINKLOCAL))
+ continue;
+ /* Got the IP, let's return */
+ np->local_ip.in6 = ifp->addr;
+ err = 0;
+ break;
+ }
+ read_unlock_bh(&idev->lock);
+ }
+ if (err) {
+ np_err(np, "no IPv6 address for %s, aborting\n",
+ egress_dev(np, buf, sizeof(buf)));
+ return err;
+ }
+
+ np_info(np, "local IPv6 %pI6c\n", &np->local_ip.in6);
+ return 0;
+}
+
/*
* Take the IPv4 from ndev and populate local_ip structure in netpoll
*/
@@ -448,7 +490,7 @@ static int netcons_netpoll_setup(struct netpoll *np)
if (err)
goto put;
} else {
- err = netpoll_take_ipv6(np, ndev);
+ err = netcons_take_ipv6(np, ndev);
if (err)
goto put;
}
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index e212cb86a9429..7736339f9880e 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -74,7 +74,6 @@ void netpoll_zap_completion_queue(void);
unsigned int netpoll_get_carrier_timeout(void);
void netpoll_wait_carrier(struct netpoll *np, struct net_device *ndev);
char *egress_dev(struct netpoll *np, char *buf, size_t bufsz);
-int netpoll_take_ipv6(struct netpoll *np, struct net_device *ndev);
#ifdef CONFIG_NETPOLL
static inline void *netpoll_poll_lock(struct napi_struct *napi)
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 60c3faf9ea944..246aa2bfd7805 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -424,48 +424,6 @@ void netpoll_wait_carrier(struct netpoll *np, struct net_device *ndev)
}
EXPORT_SYMBOL_GPL(netpoll_wait_carrier);
-/*
- * Take the IPv6 from ndev and populate local_ip structure in netpoll
- */
-int netpoll_take_ipv6(struct netpoll *np, struct net_device *ndev)
-{
- char buf[MAC_ADDR_STR_LEN + 1];
- int err = -EDESTADDRREQ;
- struct inet6_dev *idev;
-
- if (!IS_ENABLED(CONFIG_IPV6)) {
- np_err(np, "IPv6 is not supported %s, aborting\n",
- egress_dev(np, buf, sizeof(buf)));
- return -EINVAL;
- }
-
- idev = __in6_dev_get(ndev);
- if (idev) {
- struct inet6_ifaddr *ifp;
-
- read_lock_bh(&idev->lock);
- list_for_each_entry(ifp, &idev->addr_list, if_list) {
- if (!!(ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL) !=
- !!(ipv6_addr_type(&np->remote_ip.in6) & IPV6_ADDR_LINKLOCAL))
- continue;
- /* Got the IP, let's return */
- np->local_ip.in6 = ifp->addr;
- err = 0;
- break;
- }
- read_unlock_bh(&idev->lock);
- }
- if (err) {
- np_err(np, "no IPv6 address for %s, aborting\n",
- egress_dev(np, buf, sizeof(buf)));
- return err;
- }
-
- np_info(np, "local IPv6 %pI6c\n", &np->local_ip.in6);
- return 0;
-}
-EXPORT_SYMBOL_GPL(netpoll_take_ipv6);
-
static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
{
struct netpoll_info *npinfo =
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 7/9] netconsole: move egress_dev() as netcons_egress_dev()
2026-07-24 15:04 [PATCH net-next 0/9] netpoll: finish untangling netconsole from netpoll Breno Leitao
` (5 preceding siblings ...)
2026-07-24 15:04 ` [PATCH net-next 6/9] netconsole: move netpoll_take_ipv6() as netcons_take_ipv6() Breno Leitao
@ 2026-07-24 15:04 ` Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 8/9] netconsole: move local_ip/remote_ip/ipv6 to netconsole_target Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 9/9] netconsole: move netpoll_wait_carrier() as netcons_wait_carrier() Breno Leitao
8 siblings, 0 replies; 10+ messages in thread
From: Breno Leitao @ 2026-07-24 15:04 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn
Cc: netdev, linux-kernel, gustavold, asantostc, Breno Leitao,
kernel-team
move egress_dev() from netpoll to netconsole, and append netcons_
prefix.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
drivers/net/netconsole.c | 30 +++++++++++++++++++++++-------
include/linux/netpoll.h | 1 -
net/core/netpoll.c | 17 -----------------
3 files changed, 23 insertions(+), 25 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index b6cbda4722d5b..fc575adc29bd7 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -353,6 +353,22 @@ static void netconsole_skb_pool_flush(struct netconsole_target *nt)
skb_queue_purge_reason(&nt->skb_pool, SKB_CONSUMED);
}
+/*
+ * Returns a pointer to a string representation of the identifier used
+ * to select the egress interface for the given netpoll instance. buf
+ * is used to format np->dev_mac when np->dev_name is empty; bufsz must
+ * be at least MAC_ADDR_STR_LEN + 1 to fit the formatted MAC address
+ * and its NUL terminator.
+ */
+static char *netcons_egress_dev(struct netpoll *np, char *buf, size_t bufsz)
+{
+ if (np->dev_name[0])
+ return np->dev_name;
+
+ snprintf(buf, bufsz, "%pM", np->dev_mac);
+ return buf;
+}
+
/*
* Take the IPv6 from ndev and populate local_ip structure in netpoll
*/
@@ -364,7 +380,7 @@ static int netcons_take_ipv6(struct netpoll *np, struct net_device *ndev)
if (!IS_ENABLED(CONFIG_IPV6)) {
np_err(np, "IPv6 is not supported %s, aborting\n",
- egress_dev(np, buf, sizeof(buf)));
+ netcons_egress_dev(np, buf, sizeof(buf)));
return -EINVAL;
}
@@ -386,7 +402,7 @@ static int netcons_take_ipv6(struct netpoll *np, struct net_device *ndev)
}
if (err) {
np_err(np, "no IPv6 address for %s, aborting\n",
- egress_dev(np, buf, sizeof(buf)));
+ netcons_egress_dev(np, buf, sizeof(buf)));
return err;
}
@@ -406,14 +422,14 @@ static int netcons_take_ipv4(struct netpoll *np, struct net_device *ndev)
in_dev = __in_dev_get_rtnl(ndev);
if (!in_dev) {
np_err(np, "no IP address for %s, aborting\n",
- egress_dev(np, buf, sizeof(buf)));
+ netcons_egress_dev(np, buf, sizeof(buf)));
return -EDESTADDRREQ;
}
ifa = rtnl_dereference(in_dev->ifa_list);
if (!ifa) {
np_err(np, "no IP address for %s, aborting\n",
- egress_dev(np, buf, sizeof(buf)));
+ netcons_egress_dev(np, buf, sizeof(buf)));
return -EDESTADDRREQ;
}
@@ -456,7 +472,7 @@ static int netcons_netpoll_setup(struct netpoll *np)
if (!ndev) {
np_err(np, "%s doesn't exist, aborting\n",
- egress_dev(np, buf, sizeof(buf)));
+ netcons_egress_dev(np, buf, sizeof(buf)));
err = -ENODEV;
goto unlock;
}
@@ -464,14 +480,14 @@ static int netcons_netpoll_setup(struct netpoll *np)
if (netdev_master_upper_dev_get(ndev)) {
np_err(np, "%s is a slave device, aborting\n",
- egress_dev(np, buf, sizeof(buf)));
+ netcons_egress_dev(np, buf, sizeof(buf)));
err = -EBUSY;
goto put;
}
if (!netif_running(ndev)) {
np_info(np, "device %s not up yet, forcing it\n",
- egress_dev(np, buf, sizeof(buf)));
+ netcons_egress_dev(np, buf, sizeof(buf)));
err = dev_open(ndev, NULL);
if (err) {
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 7736339f9880e..dac8dc2529de0 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -73,7 +73,6 @@ netdev_tx_t netpoll_send_skb(struct netpoll *np, struct sk_buff *skb);
void netpoll_zap_completion_queue(void);
unsigned int netpoll_get_carrier_timeout(void);
void netpoll_wait_carrier(struct netpoll *np, struct net_device *ndev);
-char *egress_dev(struct netpoll *np, char *buf, size_t bufsz);
#ifdef CONFIG_NETPOLL
static inline void *netpoll_poll_lock(struct napi_struct *napi)
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 246aa2bfd7805..f385ae4b70f5c 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -392,23 +392,6 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
}
EXPORT_SYMBOL_GPL(__netpoll_setup);
-/*
- * Returns a pointer to a string representation of the identifier used
- * to select the egress interface for the given netpoll instance. buf
- * is used to format np->dev_mac when np->dev_name is empty; bufsz must
- * be at least MAC_ADDR_STR_LEN + 1 to fit the formatted MAC address
- * and its NUL terminator.
- */
-char *egress_dev(struct netpoll *np, char *buf, size_t bufsz)
-{
- if (np->dev_name[0])
- return np->dev_name;
-
- snprintf(buf, bufsz, "%pM", np->dev_mac);
- return buf;
-}
-EXPORT_SYMBOL_GPL(egress_dev);
-
void netpoll_wait_carrier(struct netpoll *np, struct net_device *ndev)
{
unsigned long atmost;
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 8/9] netconsole: move local_ip/remote_ip/ipv6 to netconsole_target
2026-07-24 15:04 [PATCH net-next 0/9] netpoll: finish untangling netconsole from netpoll Breno Leitao
` (6 preceding siblings ...)
2026-07-24 15:04 ` [PATCH net-next 7/9] netconsole: move egress_dev() as netcons_egress_dev() Breno Leitao
@ 2026-07-24 15:04 ` Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 9/9] netconsole: move netpoll_wait_carrier() as netcons_wait_carrier() Breno Leitao
8 siblings, 0 replies; 10+ messages in thread
From: Breno Leitao @ 2026-07-24 15:04 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn
Cc: netdev, linux-kernel, gustavold, asantostc, Breno Leitao,
kernel-team
With netpoll_setup() and the packet-building path now living in
netconsole, local_ip, remote_ip and ipv6 in struct netpoll are read
and written only by netconsole. No other netpoll user touches them.
Move the three fields into netconsole_target and switch the packet
builders and setup helpers to take the target instead of the netpoll
handle. struct netpoll is left holding only the device-binding state
that the shared netpoll transport needs.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
drivers/net/netconsole.c | 143 +++++++++++++++++++++++++----------------------
include/linux/netpoll.h | 3 -
2 files changed, 76 insertions(+), 70 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index fc575adc29bd7..199d0e1ac17b2 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -177,9 +177,10 @@ enum target_state {
* @np: The netpoll structure for this target.
* Contains the other userspace visible parameters:
* dev_name (read-write)
- * local_ip (read-write)
- * remote_ip (read-write)
* local_mac (read-only)
+ * @local_ip: Source IP address of the target (read-write).
+ * @remote_ip: Destination IP address of the target (read-write).
+ * @ipv6: Whether the target addresses are IPv6 (read-write).
* @local_port: Source UDP port of the target (read-write).
* @remote_port: Destination UDP port of the target (read-write).
* @remote_mac: Destination ethernet address of the target (read-write).
@@ -210,6 +211,8 @@ struct netconsole_target {
bool extended;
bool release;
struct netpoll np;
+ union inet_addr local_ip, remote_ip;
+ bool ipv6;
u16 local_port, remote_port;
u8 remote_mac[ETH_ALEN];
/* protected by target_list_lock; +1 gives scnprintf() room for its
@@ -370,11 +373,13 @@ static char *netcons_egress_dev(struct netpoll *np, char *buf, size_t bufsz)
}
/*
- * Take the IPv6 from ndev and populate local_ip structure in netpoll
+ * Populate the target's local_ip with the IPv6 address from ndev.
*/
-static int netcons_take_ipv6(struct netpoll *np, struct net_device *ndev)
+static int netcons_take_ipv6(struct netconsole_target *nt,
+ struct net_device *ndev)
{
char buf[MAC_ADDR_STR_LEN + 1];
+ struct netpoll *np = &nt->np;
int err = -EDESTADDRREQ;
struct inet6_dev *idev;
@@ -391,10 +396,10 @@ static int netcons_take_ipv6(struct netpoll *np, struct net_device *ndev)
read_lock_bh(&idev->lock);
list_for_each_entry(ifp, &idev->addr_list, if_list) {
if (!!(ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL) !=
- !!(ipv6_addr_type(&np->remote_ip.in6) & IPV6_ADDR_LINKLOCAL))
+ !!(ipv6_addr_type(&nt->remote_ip.in6) & IPV6_ADDR_LINKLOCAL))
continue;
/* Got the IP, let's return */
- np->local_ip.in6 = ifp->addr;
+ nt->local_ip.in6 = ifp->addr;
err = 0;
break;
}
@@ -406,16 +411,18 @@ static int netcons_take_ipv6(struct netpoll *np, struct net_device *ndev)
return err;
}
- np_info(np, "local IPv6 %pI6c\n", &np->local_ip.in6);
+ np_info(np, "local IPv6 %pI6c\n", &nt->local_ip.in6);
return 0;
}
/*
- * Take the IPv4 from ndev and populate local_ip structure in netpoll
+ * Populate the target's local_ip with the IPv4 address from ndev.
*/
-static int netcons_take_ipv4(struct netpoll *np, struct net_device *ndev)
+static int netcons_take_ipv4(struct netconsole_target *nt,
+ struct net_device *ndev)
{
char buf[MAC_ADDR_STR_LEN + 1];
+ struct netpoll *np = &nt->np;
const struct in_ifaddr *ifa;
struct in_device *in_dev;
@@ -433,34 +440,35 @@ static int netcons_take_ipv4(struct netpoll *np, struct net_device *ndev)
return -EDESTADDRREQ;
}
- np->local_ip.ip = ifa->ifa_local;
- np_info(np, "local IP %pI4\n", &np->local_ip.ip);
+ nt->local_ip.ip = ifa->ifa_local;
+ np_info(np, "local IP %pI4\n", &nt->local_ip.ip);
return 0;
}
/*
- * Test whether the caller left np->local_ip unset, so that
+ * Test whether the caller left nt->local_ip unset, so that
* netcons_netpoll_setup() should auto-populate it from the egress device.
*
- * np->local_ip is a union of __be32 (IPv4) and struct in6_addr (IPv6),
+ * nt->local_ip is a union of __be32 (IPv4) and struct in6_addr (IPv6),
* so an IPv6 address whose first 4 bytes are zero (e.g. ::1, ::2,
* IPv4-mapped ::ffff:a.b.c.d) must not be tested via the IPv4 arm —
* doing so would misclassify a caller-supplied address as unset and
* silently overwrite it with whatever address the device exposes.
*/
-static bool netcons_local_ip_unset(const struct netpoll *np)
+static bool netcons_local_ip_unset(const struct netconsole_target *nt)
{
- if (np->ipv6)
- return ipv6_addr_any(&np->local_ip.in6);
- return !np->local_ip.ip;
+ if (nt->ipv6)
+ return ipv6_addr_any(&nt->local_ip.in6);
+ return !nt->local_ip.ip;
}
-static int netcons_netpoll_setup(struct netpoll *np)
+static int netcons_netpoll_setup(struct netconsole_target *nt)
{
struct net *net = current->nsproxy->net_ns;
char buf[MAC_ADDR_STR_LEN + 1];
struct net_device *ndev = NULL;
+ struct netpoll *np = &nt->np;
bool ip_overwritten = false;
int err;
@@ -500,13 +508,13 @@ static int netcons_netpoll_setup(struct netpoll *np)
rtnl_lock();
}
- if (netcons_local_ip_unset(np)) {
- if (!np->ipv6) {
- err = netcons_take_ipv4(np, ndev);
+ if (netcons_local_ip_unset(nt)) {
+ if (!nt->ipv6) {
+ err = netcons_take_ipv4(nt, ndev);
if (err)
goto put;
} else {
- err = netcons_take_ipv6(np, ndev);
+ err = netcons_take_ipv6(nt, ndev);
if (err)
goto put;
}
@@ -529,7 +537,7 @@ static int netcons_netpoll_setup(struct netpoll *np)
put:
DEBUG_NET_WARN_ON_ONCE(np->dev);
if (ip_overwritten)
- memset(&np->local_ip, 0, sizeof(np->local_ip));
+ memset(&nt->local_ip, 0, sizeof(nt->local_ip));
netdev_put(ndev, &np->dev_tracker);
unlock:
rtnl_unlock();
@@ -546,7 +554,7 @@ static void resume_target(struct netconsole_target *nt)
*/
netconsole_skb_pool_init(nt);
- if (netcons_netpoll_setup(&nt->np)) {
+ if (netcons_netpoll_setup(nt)) {
/* netpoll fails setup once, do not try again. */
netconsole_skb_pool_flush(nt);
nt->state = STATE_DISABLED;
@@ -691,17 +699,17 @@ static void netconsole_print_banner(struct netconsole_target *nt)
struct netpoll *np = &nt->np;
np_info(np, "local port %d\n", nt->local_port);
- if (np->ipv6)
- np_info(np, "local IPv6 address %pI6c\n", &np->local_ip.in6);
+ if (nt->ipv6)
+ np_info(np, "local IPv6 address %pI6c\n", &nt->local_ip.in6);
else
- np_info(np, "local IPv4 address %pI4\n", &np->local_ip.ip);
+ np_info(np, "local IPv4 address %pI4\n", &nt->local_ip.ip);
np_info(np, "interface name '%s'\n", np->dev_name);
np_info(np, "local ethernet address '%pM'\n", np->dev_mac);
np_info(np, "remote port %d\n", nt->remote_port);
- if (np->ipv6)
- np_info(np, "remote IPv6 address %pI6c\n", &np->remote_ip.in6);
+ if (nt->ipv6)
+ np_info(np, "remote IPv6 address %pI6c\n", &nt->remote_ip.in6);
else
- np_info(np, "remote IPv4 address %pI4\n", &np->remote_ip.ip);
+ np_info(np, "remote IPv4 address %pI4\n", &nt->remote_ip.ip);
np_info(np, "remote ethernet address %pM\n", nt->remote_mac);
}
@@ -832,20 +840,20 @@ static ssize_t local_ip_show(struct config_item *item, char *buf)
{
struct netconsole_target *nt = to_target(item);
- if (nt->np.ipv6)
- return sysfs_emit(buf, "%pI6c\n", &nt->np.local_ip.in6);
+ if (nt->ipv6)
+ return sysfs_emit(buf, "%pI6c\n", &nt->local_ip.in6);
else
- return sysfs_emit(buf, "%pI4\n", &nt->np.local_ip);
+ return sysfs_emit(buf, "%pI4\n", &nt->local_ip);
}
static ssize_t remote_ip_show(struct config_item *item, char *buf)
{
struct netconsole_target *nt = to_target(item);
- if (nt->np.ipv6)
- return sysfs_emit(buf, "%pI6c\n", &nt->np.remote_ip.in6);
+ if (nt->ipv6)
+ return sysfs_emit(buf, "%pI6c\n", &nt->remote_ip.in6);
else
- return sysfs_emit(buf, "%pI4\n", &nt->np.remote_ip);
+ return sysfs_emit(buf, "%pI4\n", &nt->remote_ip);
}
static ssize_t local_mac_show(struct config_item *item, char *buf)
@@ -1025,7 +1033,7 @@ static ssize_t enabled_store(struct config_item *item,
*/
netconsole_skb_pool_init(nt);
- ret = netcons_netpoll_setup(&nt->np);
+ ret = netcons_netpoll_setup(nt);
if (ret) {
netconsole_skb_pool_flush(nt);
goto out_unlock;
@@ -1199,10 +1207,10 @@ static ssize_t local_ip_store(struct config_item *item, const char *buf,
goto out_unlock;
}
- ipv6 = netpoll_parse_ip_addr(buf, &nt->np.local_ip);
+ ipv6 = netpoll_parse_ip_addr(buf, &nt->local_ip);
if (ipv6 == -1)
goto out_unlock;
- nt->np.ipv6 = !!ipv6;
+ nt->ipv6 = !!ipv6;
ret = count;
out_unlock:
@@ -1224,10 +1232,10 @@ static ssize_t remote_ip_store(struct config_item *item, const char *buf,
goto out_unlock;
}
- ipv6 = netpoll_parse_ip_addr(buf, &nt->np.remote_ip);
+ ipv6 = netpoll_parse_ip_addr(buf, &nt->remote_ip);
if (ipv6 == -1)
goto out_unlock;
- nt->np.ipv6 = !!ipv6;
+ nt->ipv6 = !!ipv6;
ret = count;
out_unlock:
@@ -2027,8 +2035,8 @@ static struct sk_buff *find_skb(struct netconsole_target *nt, int len,
return skb;
}
-static void netpoll_udp_checksum(struct netpoll *np, struct sk_buff *skb,
- int len)
+static void netpoll_udp_checksum(struct netconsole_target *nt,
+ struct sk_buff *skb, int len)
{
struct udphdr *udph;
int udp_len;
@@ -2038,14 +2046,14 @@ static void netpoll_udp_checksum(struct netpoll *np, struct sk_buff *skb,
/* check needs to be set, since it will be consumed in csum_partial */
udph->check = 0;
- if (np->ipv6)
- udph->check = csum_ipv6_magic(&np->local_ip.in6,
- &np->remote_ip.in6,
+ if (nt->ipv6)
+ udph->check = csum_ipv6_magic(&nt->local_ip.in6,
+ &nt->remote_ip.in6,
udp_len, IPPROTO_UDP,
csum_partial(udph, udp_len, 0));
else
- udph->check = csum_tcpudp_magic(np->local_ip.ip,
- np->remote_ip.ip,
+ udph->check = csum_tcpudp_magic(nt->local_ip.ip,
+ nt->remote_ip.ip,
udp_len, IPPROTO_UDP,
csum_partial(udph, udp_len, 0));
if (udph->check == 0)
@@ -2054,7 +2062,6 @@ static void netpoll_udp_checksum(struct netpoll *np, struct sk_buff *skb,
static void push_udp(struct netconsole_target *nt, struct sk_buff *skb, int len)
{
- struct netpoll *np = &nt->np;
struct udphdr *udph;
int udp_len;
@@ -2068,7 +2075,7 @@ static void push_udp(struct netconsole_target *nt, struct sk_buff *skb, int len)
udph->dest = htons(nt->remote_port);
udp_set_len_short(udph, udp_len);
- netpoll_udp_checksum(np, skb, len);
+ netpoll_udp_checksum(nt, skb, len);
}
static void push_eth(struct netconsole_target *nt, struct sk_buff *skb)
@@ -2080,13 +2087,14 @@ static void push_eth(struct netconsole_target *nt, struct sk_buff *skb)
skb_reset_mac_header(skb);
ether_addr_copy(eth->h_source, np->dev->dev_addr);
ether_addr_copy(eth->h_dest, nt->remote_mac);
- if (np->ipv6)
+ if (nt->ipv6)
eth->h_proto = htons(ETH_P_IPV6);
else
eth->h_proto = htons(ETH_P_IP);
}
-static void push_ipv4(struct netpoll *np, struct sk_buff *skb, int len)
+static void push_ipv4(struct netconsole_target *nt, struct sk_buff *skb,
+ int len)
{
static atomic_t ip_ident;
struct iphdr *iph;
@@ -2107,13 +2115,14 @@ static void push_ipv4(struct netpoll *np, struct sk_buff *skb, int len)
iph->ttl = 64;
iph->protocol = IPPROTO_UDP;
iph->check = 0;
- put_unaligned(np->local_ip.ip, &iph->saddr);
- put_unaligned(np->remote_ip.ip, &iph->daddr);
+ put_unaligned(nt->local_ip.ip, &iph->saddr);
+ put_unaligned(nt->remote_ip.ip, &iph->daddr);
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
skb->protocol = htons(ETH_P_IP);
}
-static void push_ipv6(struct netpoll *np, struct sk_buff *skb, int len)
+static void push_ipv6(struct netconsole_target *nt, struct sk_buff *skb,
+ int len)
{
struct ipv6hdr *ip6h;
@@ -2130,8 +2139,8 @@ static void push_ipv6(struct netpoll *np, struct sk_buff *skb, int len)
ip6h->payload_len = htons(sizeof(struct udphdr) + len);
ip6h->nexthdr = IPPROTO_UDP;
ip6h->hop_limit = 32;
- ip6h->saddr = np->local_ip.in6;
- ip6h->daddr = np->remote_ip.in6;
+ ip6h->saddr = nt->local_ip.in6;
+ ip6h->daddr = nt->remote_ip.in6;
skb->protocol = htons(ETH_P_IPV6);
}
@@ -2147,7 +2156,7 @@ static int netpoll_send_udp(struct netconsole_target *nt, const char *msg,
WARN_ON_ONCE(!irqs_disabled());
udp_len = len + sizeof(struct udphdr);
- if (np->ipv6)
+ if (nt->ipv6)
ip_len = udp_len + sizeof(struct ipv6hdr);
else
ip_len = udp_len + sizeof(struct iphdr);
@@ -2163,10 +2172,10 @@ static int netpoll_send_udp(struct netconsole_target *nt, const char *msg,
skb_put(skb, len);
push_udp(nt, skb, len);
- if (np->ipv6)
- push_ipv6(np, skb, len);
+ if (nt->ipv6)
+ push_ipv6(nt, skb, len);
else
- push_ipv4(np, skb, len);
+ push_ipv4(nt, skb, len);
push_eth(nt, skb);
skb->dev = np->dev;
@@ -2505,11 +2514,11 @@ static int netconsole_parser_cmdline(struct netconsole_target *nt, char *opt)
if (!delim)
goto parse_failed;
*delim = 0;
- ipv6 = netpoll_parse_ip_addr(cur, &np->local_ip);
+ ipv6 = netpoll_parse_ip_addr(cur, &nt->local_ip);
if (ipv6 < 0)
goto parse_failed;
else
- np->ipv6 = (bool)ipv6;
+ nt->ipv6 = (bool)ipv6;
cur = delim;
}
cur++;
@@ -2551,13 +2560,13 @@ static int netconsole_parser_cmdline(struct netconsole_target *nt, char *opt)
if (!delim)
goto parse_failed;
*delim = 0;
- ipv6 = netpoll_parse_ip_addr(cur, &np->remote_ip);
+ ipv6 = netpoll_parse_ip_addr(cur, &nt->remote_ip);
if (ipv6 < 0)
goto parse_failed;
- else if (ipversion_set && np->ipv6 != (bool)ipv6)
+ else if (ipversion_set && nt->ipv6 != (bool)ipv6)
goto parse_failed;
else
- np->ipv6 = (bool)ipv6;
+ nt->ipv6 = (bool)ipv6;
cur = delim + 1;
if (*cur != 0) {
@@ -2615,7 +2624,7 @@ static struct netconsole_target *alloc_param_target(char *target_config,
*/
netconsole_skb_pool_init(nt);
- err = netcons_netpoll_setup(&nt->np);
+ err = netcons_netpoll_setup(nt);
if (err) {
pr_err("Not enabling netconsole for %s%d. Netpoll setup failed\n",
NETCONSOLE_PARAM_TARGET_PREFIX, cmdline_count);
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index dac8dc2529de0..ef88a30b11f40 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -32,9 +32,6 @@ struct netpoll {
char dev_name[IFNAMSIZ];
u8 dev_mac[ETH_ALEN];
const char *name;
-
- union inet_addr local_ip, remote_ip;
- bool ipv6;
};
#define np_info(np, fmt, ...) \
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 9/9] netconsole: move netpoll_wait_carrier() as netcons_wait_carrier()
2026-07-24 15:04 [PATCH net-next 0/9] netpoll: finish untangling netconsole from netpoll Breno Leitao
` (7 preceding siblings ...)
2026-07-24 15:04 ` [PATCH net-next 8/9] netconsole: move local_ip/remote_ip/ipv6 to netconsole_target Breno Leitao
@ 2026-07-24 15:04 ` Breno Leitao
8 siblings, 0 replies; 10+ messages in thread
From: Breno Leitao @ 2026-07-24 15:04 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Andrew Lunn
Cc: netdev, linux-kernel, gustavold, asantostc, Breno Leitao,
kernel-team
netpoll_wait_carrier() waits for the egress device carrier during
netconsole setup. Its only caller, netcons_netpoll_setup(), already
lives in netconsole. Move the function into drivers/net/netconsole.c,
drop EXPORT_SYMBOL_GPL() and remove the prototype from <linux/netpoll.h>.
Rename it to netcons_wait_carrier() for the netcons_ prefix. It now reads
the timeout through netpoll_get_carrier_timeout(), since carrier_timeout
stays in netpoll to keep the netpoll.carrier_timeout parameter.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
drivers/net/netconsole.c | 17 ++++++++++++++++-
include/linux/netpoll.h | 1 -
net/core/netpoll.c | 15 ---------------
3 files changed, 16 insertions(+), 17 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 199d0e1ac17b2..03913302328cc 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -48,6 +48,7 @@
#include <linux/utsname.h>
#include <linux/rtnetlink.h>
#include <linux/workqueue.h>
+#include <linux/delay.h>
MODULE_AUTHOR("Matt Mackall <mpm@selenic.com>");
MODULE_DESCRIPTION("Console driver for network interfaces");
@@ -356,6 +357,20 @@ static void netconsole_skb_pool_flush(struct netconsole_target *nt)
skb_queue_purge_reason(&nt->skb_pool, SKB_CONSUMED);
}
+static void netcons_wait_carrier(struct netpoll *np, struct net_device *ndev)
+{
+ unsigned long atmost;
+
+ atmost = jiffies + netpoll_get_carrier_timeout() * HZ;
+ while (!netif_carrier_ok(ndev)) {
+ if (time_after(jiffies, atmost)) {
+ np_notice(np, "timeout waiting for carrier\n");
+ break;
+ }
+ msleep(1);
+ }
+}
+
/*
* Returns a pointer to a string representation of the identifier used
* to select the egress interface for the given netpoll instance. buf
@@ -504,7 +519,7 @@ static int netcons_netpoll_setup(struct netconsole_target *nt)
}
rtnl_unlock();
- netpoll_wait_carrier(np, ndev);
+ netcons_wait_carrier(np, ndev);
rtnl_lock();
}
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index ef88a30b11f40..1c6b1eec5efd6 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -69,7 +69,6 @@ void do_netpoll_cleanup(struct netpoll *np);
netdev_tx_t netpoll_send_skb(struct netpoll *np, struct sk_buff *skb);
void netpoll_zap_completion_queue(void);
unsigned int netpoll_get_carrier_timeout(void);
-void netpoll_wait_carrier(struct netpoll *np, struct net_device *ndev);
#ifdef CONFIG_NETPOLL
static inline void *netpoll_poll_lock(struct napi_struct *napi)
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index f385ae4b70f5c..fe1e0cda5d6bf 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -392,21 +392,6 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
}
EXPORT_SYMBOL_GPL(__netpoll_setup);
-void netpoll_wait_carrier(struct netpoll *np, struct net_device *ndev)
-{
- unsigned long atmost;
-
- atmost = jiffies + carrier_timeout * HZ;
- while (!netif_carrier_ok(ndev)) {
- if (time_after(jiffies, atmost)) {
- np_notice(np, "timeout waiting for carrier\n");
- break;
- }
- msleep(1);
- }
-}
-EXPORT_SYMBOL_GPL(netpoll_wait_carrier);
-
static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
{
struct netpoll_info *npinfo =
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-07-24 15:05 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-24 15:04 [PATCH net-next 0/9] netpoll: finish untangling netconsole from netpoll Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 1/9] netpoll: export carrier_timeout via netpoll_get_carrier_timeout() Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 2/9] netpoll: export the netpoll_setup() helpers for netconsole Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 3/9] netconsole: take over netpoll_setup() from netpoll Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 4/9] netconsole: move netpoll_local_ip_unset() as netcons_local_ip_unset() Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 5/9] netconsole: move netpoll_take_ipv4() as netcons_take_ipv4() Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 6/9] netconsole: move netpoll_take_ipv6() as netcons_take_ipv6() Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 7/9] netconsole: move egress_dev() as netcons_egress_dev() Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 8/9] netconsole: move local_ip/remote_ip/ipv6 to netconsole_target Breno Leitao
2026-07-24 15:04 ` [PATCH net-next 9/9] netconsole: move netpoll_wait_carrier() as netcons_wait_carrier() Breno Leitao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox