* [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state
@ 2026-05-24 16:12 Breno Leitao
2026-05-24 16:12 ` [PATCH 1/9] netpoll: export refill_skbs(), refill_skbs_work_handler(), skb_pool_flush() Breno Leitao
` (9 more replies)
0 siblings, 10 replies; 13+ messages in thread
From: Breno Leitao @ 2026-05-24 16:12 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
struct netpoll is shared by every netpoll consumer in the tree:
bonding, bridge, team, vlan, macvlan, dsa and netconsole. The non-
netconsole users only need a per-port handle that lets them transmit
SKBs.
Yet struct netpoll has accumulated a pile of fields that exist only
to serve netconsole's printk path:
- skb_pool / refill_wq: the fallback skb pool find_skb() falls
back on when alloc_skb() returns NULL, plus the workqueue that
refills it.
- local_port / remote_port / remote_mac: the source and destination
UDP ports and the destination ethernet address used to build
outgoing log packets.
- local_ip / remote_ip / ipv6: the source and destination IP
addresses and the family selector for the same packets.
Every netpoll user that allocates a struct netpoll and pays for all of
these fields, even though it never queues a single skb on the pool,
never sends a UDP frame and never looks at any of the addressing.
The fix is to move netconsole-only state out of the shared struct
into struct netconsole_target, where its only consumer already lives.
After the series, every passive netpoll consumer drops
sizeof(sk_buff_head) + sizeof(work_struct) + 2 * sizeof(u16) +
ETH_ALEN bytes per port (plus padding), and struct netpoll keeps
only what genuinely belongs to the generic poll/transmit
abstraction or what netpoll core still has to read itself.
Follow-ups
----------
local_ip, remote_ip and ipv6 are still in struct netpoll, as they are
left for a follow-up posting to keep each series focused on a single
responsibility transfer.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
Breno Leitao (9):
netpoll: export refill_skbs(), refill_skbs_work_handler(), skb_pool_flush()
netconsole: take over skb pool lifecycle from netpoll
netconsole: move refill_skbs_work_handler() from netpoll
netconsole: move refill_skbs() and skb-pool sizing macros from netpoll
netconsole: move skb_pool_flush() from netpoll
netconsole: move skb_pool / refill_wq from struct netpoll to netconsole_target
netconsole: move local_port from struct netpoll to netconsole_target
netconsole: move remote_port from struct netpoll to netconsole_target
netconsole: move remote_mac from struct netpoll to netconsole_target
drivers/net/netconsole.c | 188 ++++++++++++++++++++++++++++++++++++-----------
include/linux/netpoll.h | 4 -
net/core/netpoll.c | 58 +--------------
3 files changed, 145 insertions(+), 105 deletions(-)
---
base-commit: 150061a2065192d77a4f6518b6238be81dfb8321
change-id: 20260514-netconsole_move_more-888fde03dfc7
Best regards,
--
Breno Leitao <leitao@debian.org>
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 1/9] netpoll: export refill_skbs(), refill_skbs_work_handler(), skb_pool_flush()
2026-05-24 16:12 [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state Breno Leitao
@ 2026-05-24 16:12 ` Breno Leitao
2026-05-24 16:12 ` [PATCH 2/9] netconsole: take over skb pool lifecycle from netpoll Breno Leitao
` (8 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Breno Leitao @ 2026-05-24 16:12 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
These three helpers manage the per-netpoll fallback skb pool. They
are file-static today because all of their callers live in
net/core/netpoll.c. Subsequent patches relocate the pool's owner
from struct netpoll to the only consumer that actually uses it
(netconsole), and that work needs netconsole to drive the helpers
directly while the function bodies still live here.
Drop static, add prototypes in <linux/netpoll.h>, and
EXPORT_SYMBOL_GPL() each. No behaviour change.
The exports are transitional. Each helper is moved into
drivers/net/netconsole.c later in this series, and at that point
its EXPORT_SYMBOL_GPL() and prototype are dropped. By the end of
the series no symbol introduced here remains exported.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
include/linux/netpoll.h | 3 +++
net/core/netpoll.c | 9 ++++++---
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index e4b8f1f91e54..9fa4deed0bff 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -74,6 +74,9 @@ 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);
+void refill_skbs(struct netpoll *np);
+void refill_skbs_work_handler(struct work_struct *work);
+void skb_pool_flush(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 33ab3d827a42..84cbfa85028a 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -220,7 +220,7 @@ void netpoll_poll_enable(struct net_device *dev)
up(&ni->dev_lock);
}
-static void refill_skbs(struct netpoll *np)
+void refill_skbs(struct netpoll *np)
{
struct sk_buff_head *skb_pool;
struct sk_buff *skb;
@@ -235,6 +235,7 @@ static void refill_skbs(struct netpoll *np)
skb_queue_tail(skb_pool, skb);
}
}
+EXPORT_SYMBOL_GPL(refill_skbs);
void netpoll_zap_completion_queue(void)
{
@@ -356,7 +357,7 @@ netdev_tx_t netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
}
EXPORT_SYMBOL(netpoll_send_skb);
-static void skb_pool_flush(struct netpoll *np)
+void skb_pool_flush(struct netpoll *np)
{
struct sk_buff_head *skb_pool;
@@ -364,14 +365,16 @@ static void skb_pool_flush(struct netpoll *np)
skb_pool = &np->skb_pool;
skb_queue_purge_reason(skb_pool, SKB_CONSUMED);
}
+EXPORT_SYMBOL_GPL(skb_pool_flush);
-static void refill_skbs_work_handler(struct work_struct *work)
+void refill_skbs_work_handler(struct work_struct *work)
{
struct netpoll *np =
container_of(work, struct netpoll, refill_wq);
refill_skbs(np);
}
+EXPORT_SYMBOL_GPL(refill_skbs_work_handler);
int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
{
--
2.54.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 2/9] netconsole: take over skb pool lifecycle from netpoll
2026-05-24 16:12 [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state Breno Leitao
2026-05-24 16:12 ` [PATCH 1/9] netpoll: export refill_skbs(), refill_skbs_work_handler(), skb_pool_flush() Breno Leitao
@ 2026-05-24 16:12 ` Breno Leitao
2026-05-24 16:12 ` [PATCH 3/9] netconsole: move refill_skbs_work_handler() " Breno Leitao
` (7 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Breno Leitao @ 2026-05-24 16:12 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
The fallback skb pool fronted by find_skb() is netconsole's only
client: every other netpoll consumer (bonding, team, vlan, bridge,
macvlan, dsa) goes through __netpoll_setup() / netpoll_send_skb()
without ever touching np->skb_pool. Today __netpoll_setup() and
__netpoll_cleanup() create and destroy the pool for everyone, paying
~48 KB of pre-allocated skbs per netpoll instance that almost
nobody uses.
Move the responsibility to netconsole. Add netconsole-side
netconsole_skb_pool_{init,flush}() wrappers that call the (now
exported) refill_skbs(), refill_skbs_work_handler() and
skb_pool_flush() helpers, and wire them at the same three netpoll
setup paths (resume_target, enabled_store, alloc_param_target) and
matching teardowns (netconsole_process_cleanups_core,
drop_netconsole_target, free_param_target).
Init runs *before* netpoll_setup(), and the failure path flushes
before returning. netpoll_setup() makes nt->np.dev visible to
target_list walkers (notably netconsole_netdev_event); if a
NETDEV_UNREGISTER / NETDEV_RELEASE / NETDEV_JOIN raced and moved
the target to target_cleanup_list before init had run,
netconsole_process_cleanups_core() would call
netconsole_skb_pool_flush() on an uninitialised refill_wq /
skb_pool, splatting WARN_ON(!work->func) in flush_work() and
acquiring an uninitialised spinlock in skb_queue_purge_reason().
Doing init first preserves the pre-series invariant that the pool
is valid whenever nt->np.dev is observable.
Drop the corresponding init/flush from __netpoll_setup(),
__netpoll_cleanup() and the netpoll_setup() error path; the now
empty 'flush' label is also removed. The fields and helpers stay
in struct netpoll for now; subsequent patches relocate the helper
functions and then the fields themselves.
For non-netconsole consumers, np->skb_pool / np->refill_wq are
never initialised, never refilled and never flushed by netpoll
itself, but they are also never read by anyone, so the change is a
no-op for them.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
drivers/net/netconsole.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++--
net/core/netpoll.c | 12 +-----------
2 files changed, 50 insertions(+), 13 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index d804d44af87c..b84de3ba44c3 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -283,11 +283,35 @@ static bool bound_by_mac(struct netconsole_target *nt)
return is_valid_ether_addr(nt->np.dev_mac);
}
+/* Initialise the per-target skb pool that find_skb() falls back to and
+ * seed it. Pair with netconsole_skb_pool_flush() at the matching
+ * netpoll teardown.
+ */
+static void netconsole_skb_pool_init(struct netconsole_target *nt)
+{
+ skb_queue_head_init(&nt->np.skb_pool);
+ INIT_WORK(&nt->np.refill_wq, refill_skbs_work_handler);
+ refill_skbs(&nt->np);
+}
+
+static void netconsole_skb_pool_flush(struct netconsole_target *nt)
+{
+ skb_pool_flush(&nt->np);
+}
+
/* Attempts to resume logging to a deactivated target. */
static void resume_target(struct netconsole_target *nt)
{
+ /* Initialise the skb pool before netpoll_setup() makes nt->np.dev
+ * visible to target_list walkers (e.g. netconsole_netdev_event),
+ * which otherwise may move the target to the cleanup list and
+ * call netconsole_skb_pool_flush() on uninitialised state.
+ */
+ netconsole_skb_pool_init(nt);
+
if (netpoll_setup(&nt->np)) {
/* netpoll fails setup once, do not try again. */
+ netconsole_skb_pool_flush(nt);
nt->state = STATE_DISABLED;
return;
}
@@ -389,6 +413,7 @@ static void netconsole_process_cleanups_core(void)
list_for_each_entry_safe(nt, tmp, &target_cleanup_list, list) {
/* all entries in the cleanup_list needs to be disabled */
WARN_ON_ONCE(nt->state == STATE_ENABLED);
+ netconsole_skb_pool_flush(nt);
do_netpoll_cleanup(&nt->np);
if (bound_by_mac(nt))
memset(&nt->np.dev_name, 0, IFNAMSIZ);
@@ -732,9 +757,19 @@ static ssize_t enabled_store(struct config_item *item,
*/
netconsole_print_banner(&nt->np);
+ /* Initialise the skb pool before netpoll_setup() so the pool
+ * is valid as soon as nt->np.dev becomes visible to
+ * target_list walkers (netconsole_netdev_event), which would
+ * otherwise call netconsole_skb_pool_flush() on uninitialised
+ * state.
+ */
+ netconsole_skb_pool_init(nt);
+
ret = netpoll_setup(&nt->np);
- if (ret)
+ if (ret) {
+ netconsole_skb_pool_flush(nt);
goto out_unlock;
+ }
nt->state = STATE_ENABLED;
pr_info("network logging started\n");
@@ -1474,8 +1509,10 @@ static void drop_netconsole_target(struct config_group *group,
* The target may have never been enabled, or was manually disabled
* before being removed so netpoll may have already been cleaned up.
*/
- if (nt->state == STATE_ENABLED)
+ if (nt->state == STATE_ENABLED) {
+ netconsole_skb_pool_flush(nt);
netpoll_cleanup(&nt->np);
+ }
config_item_put(&nt->group.cg_item);
}
@@ -2257,10 +2294,18 @@ static struct netconsole_target *alloc_param_target(char *target_config,
if (err)
goto fail;
+ /* Initialise the skb pool before netpoll_setup() so the pool is
+ * valid as soon as nt->np.dev becomes visible. The target is not
+ * yet on target_list, so a netdev event cannot reach it here, but
+ * mirror the configfs path for symmetry.
+ */
+ netconsole_skb_pool_init(nt);
+
err = netpoll_setup(&nt->np);
if (err) {
pr_err("Not enabling netconsole for %s%d. Netpoll setup failed\n",
NETCONSOLE_PARAM_TARGET_PREFIX, cmdline_count);
+ netconsole_skb_pool_flush(nt);
if (!IS_ENABLED(CONFIG_NETCONSOLE_DYNAMIC))
/* only fail if dynamic reconfiguration is set,
* otherwise, keep the target in the list, but disabled.
@@ -2282,6 +2327,8 @@ static struct netconsole_target *alloc_param_target(char *target_config,
static void free_param_target(struct netconsole_target *nt)
{
cancel_work_sync(&nt->resume_wq);
+ if (nt->state == STATE_ENABLED)
+ netconsole_skb_pool_flush(nt);
netpoll_cleanup(&nt->np);
#ifdef CONFIG_NETCONSOLE_DYNAMIC
kfree(nt->userdata);
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 84cbfa85028a..a4d176ff9376 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -382,9 +382,6 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
const struct net_device_ops *ops;
int err;
- skb_queue_head_init(&np->skb_pool);
- INIT_WORK(&np->refill_wq, refill_skbs_work_handler);
-
if (ndev->priv_flags & IFF_DISABLE_NETPOLL) {
np_err(np, "%s doesn't support polling, aborting\n",
ndev->name);
@@ -419,9 +416,6 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
np->dev = ndev;
strscpy(np->dev_name, ndev->name, IFNAMSIZ);
- /* fill up the skb queue */
- refill_skbs(np);
-
/* last thing to do is link it to the net device structure */
rcu_assign_pointer(ndev->npinfo, npinfo);
@@ -611,7 +605,7 @@ int netpoll_setup(struct netpoll *np)
err = __netpoll_setup(np, ndev);
if (err)
- goto flush;
+ goto put;
rtnl_unlock();
/* Make sure all NAPI polls which started before dev->npinfo
@@ -622,8 +616,6 @@ int netpoll_setup(struct netpoll *np)
return 0;
-flush:
- skb_pool_flush(np);
put:
DEBUG_NET_WARN_ON_ONCE(np->dev);
if (ip_overwritten)
@@ -674,8 +666,6 @@ static void __netpoll_cleanup(struct netpoll *np)
RCU_INIT_POINTER(np->dev->npinfo, NULL);
call_rcu(&npinfo->rcu, rcu_cleanup_netpoll_info);
}
-
- skb_pool_flush(np);
}
void __netpoll_free(struct netpoll *np)
--
2.54.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 3/9] netconsole: move refill_skbs_work_handler() from netpoll
2026-05-24 16:12 [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state Breno Leitao
2026-05-24 16:12 ` [PATCH 1/9] netpoll: export refill_skbs(), refill_skbs_work_handler(), skb_pool_flush() Breno Leitao
2026-05-24 16:12 ` [PATCH 2/9] netconsole: take over skb pool lifecycle from netpoll Breno Leitao
@ 2026-05-24 16:12 ` Breno Leitao
2026-05-24 16:12 ` [PATCH 4/9] netconsole: move refill_skbs() and skb-pool sizing macros " Breno Leitao
` (6 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Breno Leitao @ 2026-05-24 16:12 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
The work handler is wired via INIT_WORK() in
netconsole_skb_pool_init() and has no other callers since the
previous patch took the skb pool lifecycle out of __netpoll_setup().
Move the function body into drivers/net/netconsole.c as a
file-static helper, drop EXPORT_SYMBOL_GPL() and remove the
prototype from <linux/netpoll.h>.
Pure code motion: the body is unchanged and still calls the
exported refill_skbs() in net/core/netpoll.c.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
drivers/net/netconsole.c | 8 ++++++++
include/linux/netpoll.h | 1 -
net/core/netpoll.c | 9 ---------
3 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index b84de3ba44c3..3d7d17c59902 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -283,6 +283,14 @@ static bool bound_by_mac(struct netconsole_target *nt)
return is_valid_ether_addr(nt->np.dev_mac);
}
+static void refill_skbs_work_handler(struct work_struct *work)
+{
+ struct netpoll *np =
+ container_of(work, struct netpoll, refill_wq);
+
+ refill_skbs(np);
+}
+
/* Initialise the per-target skb pool that find_skb() falls back to and
* seed it. Pair with netconsole_skb_pool_flush() at the matching
* netpoll teardown.
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 9fa4deed0bff..1a497d12f336 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -75,7 +75,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);
void refill_skbs(struct netpoll *np);
-void refill_skbs_work_handler(struct work_struct *work);
void skb_pool_flush(struct netpoll *np);
#ifdef CONFIG_NETPOLL
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index a4d176ff9376..4111d6ee8d4b 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -367,15 +367,6 @@ void skb_pool_flush(struct netpoll *np)
}
EXPORT_SYMBOL_GPL(skb_pool_flush);
-void refill_skbs_work_handler(struct work_struct *work)
-{
- struct netpoll *np =
- container_of(work, struct netpoll, refill_wq);
-
- refill_skbs(np);
-}
-EXPORT_SYMBOL_GPL(refill_skbs_work_handler);
-
int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
{
struct netpoll_info *npinfo;
--
2.54.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 4/9] netconsole: move refill_skbs() and skb-pool sizing macros from netpoll
2026-05-24 16:12 [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state Breno Leitao
` (2 preceding siblings ...)
2026-05-24 16:12 ` [PATCH 3/9] netconsole: move refill_skbs_work_handler() " Breno Leitao
@ 2026-05-24 16:12 ` Breno Leitao
2026-05-24 16:12 ` [PATCH 5/9] netconsole: move skb_pool_flush() " Breno Leitao
` (5 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Breno Leitao @ 2026-05-24 16:12 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
refill_skbs() is now only called from netconsole (directly via
netconsole_skb_pool_init() and indirectly via the just-moved
refill_skbs_work_handler()), and the MAX_UDP_CHUNK / MAX_SKBS /
MAX_SKB_SIZE macros are private to it. Move them all into
drivers/net/netconsole.c.
Drop EXPORT_SYMBOL_GPL(refill_skbs) and remove its prototype from
<linux/netpoll.h>; the macros only ever lived as file-static defines
in netpoll.c. Pure code motion: bodies and pool sizing semantics are
unchanged.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
drivers/net/netconsole.c | 29 +++++++++++++++++++++++++++++
include/linux/netpoll.h | 1 -
net/core/netpoll.c | 30 ------------------------------
3 files changed, 29 insertions(+), 31 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 3d7d17c59902..76a569d487db 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -61,6 +61,19 @@ MODULE_IMPORT_NS("NETDEV_INTERNAL");
#define MAX_USERDATA_ITEMS 256
#define MAX_PRINT_CHUNK 1000
+/*
+ * Sizing for the per-target fallback skb pool consulted by find_skb()
+ * when its GFP_ATOMIC allocation fails so messages still get out under
+ * memory pressure.
+ */
+#define MAX_UDP_CHUNK 1460
+#define MAX_SKBS 32
+#define MAX_SKB_SIZE \
+ (sizeof(struct ethhdr) + \
+ sizeof(struct iphdr) + \
+ sizeof(struct udphdr) + \
+ MAX_UDP_CHUNK)
+
static char config[MAX_PARAM_LENGTH];
module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0);
MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]");
@@ -283,6 +296,22 @@ static bool bound_by_mac(struct netconsole_target *nt)
return is_valid_ether_addr(nt->np.dev_mac);
}
+static void refill_skbs(struct netpoll *np)
+{
+ struct sk_buff_head *skb_pool;
+ struct sk_buff *skb;
+
+ skb_pool = &np->skb_pool;
+
+ while (READ_ONCE(skb_pool->qlen) < MAX_SKBS) {
+ skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC);
+ if (!skb)
+ break;
+
+ skb_queue_tail(skb_pool, skb);
+ }
+}
+
static void refill_skbs_work_handler(struct work_struct *work)
{
struct netpoll *np =
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 1a497d12f336..bc491f600a71 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -74,7 +74,6 @@ 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);
-void refill_skbs(struct netpoll *np);
void skb_pool_flush(struct netpoll *np);
#ifdef CONFIG_NETPOLL
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 4111d6ee8d4b..2fca74b4ea75 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -36,21 +36,8 @@
#include <trace/events/napi.h>
#include <linux/kconfig.h>
-/*
- * We maintain a small pool of fully-sized skbs, to make sure the
- * message gets out even in extreme OOM situations.
- */
-
-#define MAX_UDP_CHUNK 1460
-#define MAX_SKBS 32
#define USEC_PER_POLL 50
-#define MAX_SKB_SIZE \
- (sizeof(struct ethhdr) + \
- sizeof(struct iphdr) + \
- sizeof(struct udphdr) + \
- MAX_UDP_CHUNK)
-
static unsigned int carrier_timeout = 4;
module_param(carrier_timeout, uint, 0644);
@@ -220,23 +207,6 @@ void netpoll_poll_enable(struct net_device *dev)
up(&ni->dev_lock);
}
-void refill_skbs(struct netpoll *np)
-{
- struct sk_buff_head *skb_pool;
- struct sk_buff *skb;
-
- skb_pool = &np->skb_pool;
-
- while (READ_ONCE(skb_pool->qlen) < MAX_SKBS) {
- skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC);
- if (!skb)
- break;
-
- skb_queue_tail(skb_pool, skb);
- }
-}
-EXPORT_SYMBOL_GPL(refill_skbs);
-
void netpoll_zap_completion_queue(void)
{
unsigned long flags;
--
2.54.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 5/9] netconsole: move skb_pool_flush() from netpoll
2026-05-24 16:12 [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state Breno Leitao
` (3 preceding siblings ...)
2026-05-24 16:12 ` [PATCH 4/9] netconsole: move refill_skbs() and skb-pool sizing macros " Breno Leitao
@ 2026-05-24 16:12 ` Breno Leitao
2026-05-24 16:12 ` [PATCH 6/9] netconsole: move skb_pool / refill_wq from struct netpoll to netconsole_target Breno Leitao
` (4 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Breno Leitao @ 2026-05-24 16:12 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
skb_pool_flush() has no callers left in net/core/netpoll.c after
netconsole took over the pool lifecycle. Inline its body into
netconsole_skb_pool_flush() (the only caller) and drop the function
and its export from netpoll. The prototype goes from
<linux/netpoll.h>.
Pure code motion: cancel_work_sync() + skb_queue_purge_reason()
semantics are unchanged.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
drivers/net/netconsole.c | 5 ++++-
include/linux/netpoll.h | 1 -
net/core/netpoll.c | 10 ----------
3 files changed, 4 insertions(+), 12 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 76a569d487db..a8ced60bef7a 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -333,7 +333,10 @@ static void netconsole_skb_pool_init(struct netconsole_target *nt)
static void netconsole_skb_pool_flush(struct netconsole_target *nt)
{
- skb_pool_flush(&nt->np);
+ struct netpoll *np = &nt->np;
+
+ cancel_work_sync(&np->refill_wq);
+ skb_queue_purge_reason(&np->skb_pool, SKB_CONSUMED);
}
/* Attempts to resume logging to a deactivated target. */
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index bc491f600a71..e4b8f1f91e54 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -74,7 +74,6 @@ 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);
-void skb_pool_flush(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 2fca74b4ea75..796aab90e26e 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -327,16 +327,6 @@ netdev_tx_t netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
}
EXPORT_SYMBOL(netpoll_send_skb);
-void skb_pool_flush(struct netpoll *np)
-{
- struct sk_buff_head *skb_pool;
-
- cancel_work_sync(&np->refill_wq);
- skb_pool = &np->skb_pool;
- skb_queue_purge_reason(skb_pool, SKB_CONSUMED);
-}
-EXPORT_SYMBOL_GPL(skb_pool_flush);
-
int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
{
struct netpoll_info *npinfo;
--
2.54.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 6/9] netconsole: move skb_pool / refill_wq from struct netpoll to netconsole_target
2026-05-24 16:12 [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state Breno Leitao
` (4 preceding siblings ...)
2026-05-24 16:12 ` [PATCH 5/9] netconsole: move skb_pool_flush() " Breno Leitao
@ 2026-05-24 16:12 ` Breno Leitao
2026-05-24 16:12 ` [PATCH 7/9] netconsole: move local_port " Breno Leitao
` (3 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Breno Leitao @ 2026-05-24 16:12 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
These two fields back the fallback skb pool that find_skb() uses.
Every helper that touches them lives in netconsole now (refill_skbs,
refill_skbs_work_handler, netconsole_skb_pool_init,
netconsole_skb_pool_flush, find_skb), so the data can move alongside
its only consumer.
Add skb_pool and refill_wq to struct netconsole_target, drop them
from struct netpoll, and update the helpers and find_skb() to take
a struct netconsole_target * and reach the pool through nt-> rather
than np->. Thread nt through netpoll_send_udp() so its only caller
in send_udp() can pass nt directly.
struct netpoll shrinks by sizeof(sk_buff_head) + sizeof(work_struct)
for every consumer, including bonding, bridge, team, vlan, macvlan
and dsa, which carried the fields as dead weight.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
drivers/net/netconsole.c | 47 +++++++++++++++++++++++++++--------------------
include/linux/netpoll.h | 2 --
2 files changed, 27 insertions(+), 22 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index a8ced60bef7a..b8b1608d09e9 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -183,6 +183,11 @@ enum target_state {
* remote_mac (read-write)
* @buf: The buffer used to send the full msg to the network stack
* @resume_wq: Workqueue to resume deactivated target
+ * @skb_pool: Per-target fallback skb pool consulted by find_skb() when
+ * its GFP_ATOMIC allocation fails. Lifetime brackets a
+ * successful netpoll_setup() / netpoll_cleanup() pair on @np.
+ * @refill_wq: Work item that asynchronously tops @skb_pool back up to
+ * MAX_SKBS after find_skb() drains an entry.
*/
struct netconsole_target {
struct list_head list;
@@ -206,6 +211,8 @@ struct netconsole_target {
/* protected by target_list_lock */
char buf[MAX_PRINT_CHUNK];
struct work_struct resume_wq;
+ struct sk_buff_head skb_pool;
+ struct work_struct refill_wq;
};
#ifdef CONFIG_NETCONSOLE_DYNAMIC
@@ -296,13 +303,11 @@ static bool bound_by_mac(struct netconsole_target *nt)
return is_valid_ether_addr(nt->np.dev_mac);
}
-static void refill_skbs(struct netpoll *np)
+static void refill_skbs(struct netconsole_target *nt)
{
- struct sk_buff_head *skb_pool;
+ struct sk_buff_head *skb_pool = &nt->skb_pool;
struct sk_buff *skb;
- skb_pool = &np->skb_pool;
-
while (READ_ONCE(skb_pool->qlen) < MAX_SKBS) {
skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC);
if (!skb)
@@ -314,10 +319,10 @@ static void refill_skbs(struct netpoll *np)
static void refill_skbs_work_handler(struct work_struct *work)
{
- struct netpoll *np =
- container_of(work, struct netpoll, refill_wq);
+ struct netconsole_target *nt =
+ container_of(work, struct netconsole_target, refill_wq);
- refill_skbs(np);
+ refill_skbs(nt);
}
/* Initialise the per-target skb pool that find_skb() falls back to and
@@ -326,17 +331,15 @@ static void refill_skbs_work_handler(struct work_struct *work)
*/
static void netconsole_skb_pool_init(struct netconsole_target *nt)
{
- skb_queue_head_init(&nt->np.skb_pool);
- INIT_WORK(&nt->np.refill_wq, refill_skbs_work_handler);
- refill_skbs(&nt->np);
+ skb_queue_head_init(&nt->skb_pool);
+ INIT_WORK(&nt->refill_wq, refill_skbs_work_handler);
+ refill_skbs(nt);
}
static void netconsole_skb_pool_flush(struct netconsole_target *nt)
{
- struct netpoll *np = &nt->np;
-
- cancel_work_sync(&np->refill_wq);
- skb_queue_purge_reason(&np->skb_pool, SKB_CONSUMED);
+ cancel_work_sync(&nt->refill_wq);
+ skb_queue_purge_reason(&nt->skb_pool, SKB_CONSUMED);
}
/* Attempts to resume logging to a deactivated target. */
@@ -1731,8 +1734,10 @@ static struct notifier_block netconsole_netdev_notifier = {
.notifier_call = netconsole_netdev_event,
};
-static struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)
+static struct sk_buff *find_skb(struct netconsole_target *nt, int len,
+ int reserve)
{
+ struct netpoll *np = &nt->np;
int count = 0;
struct sk_buff *skb;
@@ -1741,8 +1746,8 @@ static struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)
skb = alloc_skb(len, GFP_ATOMIC);
if (!skb) {
- skb = skb_dequeue(&np->skb_pool);
- schedule_work(&np->refill_wq);
+ skb = skb_dequeue(&nt->skb_pool);
+ schedule_work(&nt->refill_wq);
}
if (!skb) {
@@ -1865,8 +1870,10 @@ static void push_ipv6(struct netpoll *np, struct sk_buff *skb, int len)
skb->protocol = htons(ETH_P_IPV6);
}
-static int netpoll_send_udp(struct netpoll *np, const char *msg, int len)
+static int netpoll_send_udp(struct netconsole_target *nt, const char *msg,
+ int len)
{
+ struct netpoll *np = &nt->np;
int total_len, ip_len, udp_len;
struct sk_buff *skb;
@@ -1881,7 +1888,7 @@ static int netpoll_send_udp(struct netpoll *np, const char *msg, int len)
total_len = ip_len + LL_RESERVED_SPACE(np->dev);
- skb = find_skb(np, total_len + np->dev->needed_tailroom,
+ skb = find_skb(nt, total_len + np->dev->needed_tailroom,
total_len - len);
if (!skb)
return -ENOMEM;
@@ -1912,7 +1919,7 @@ static int netpoll_send_udp(struct netpoll *np, const char *msg, int len)
*/
static void send_udp(struct netconsole_target *nt, const char *msg, int len)
{
- int result = netpoll_send_udp(&nt->np, msg, len);
+ int result = netpoll_send_udp(nt, msg, len);
if (IS_ENABLED(CONFIG_NETCONSOLE_DYNAMIC)) {
if (result == NET_XMIT_DROP) {
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index e4b8f1f91e54..8344454df05d 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -35,8 +35,6 @@ struct netpoll {
bool ipv6;
u16 local_port, remote_port;
u8 remote_mac[ETH_ALEN];
- struct sk_buff_head skb_pool;
- struct work_struct refill_wq;
};
#define np_info(np, fmt, ...) \
--
2.54.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 7/9] netconsole: move local_port from struct netpoll to netconsole_target
2026-05-24 16:12 [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state Breno Leitao
` (5 preceding siblings ...)
2026-05-24 16:12 ` [PATCH 6/9] netconsole: move skb_pool / refill_wq from struct netpoll to netconsole_target Breno Leitao
@ 2026-05-24 16:12 ` Breno Leitao
2026-05-24 16:12 ` [PATCH 8/9] netconsole: move remote_port " Breno Leitao
` (2 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Breno Leitao @ 2026-05-24 16:12 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
The UDP source port used to build outgoing log packets is pure
netconsole configuration. net/core/netpoll.c never reads it, and
no other struct netpoll consumer (bonding, bridge, team, vlan,
macvlan, dsa) touches it either.
Add local_port to struct netconsole_target, drop it from struct
netpoll, and update alloc_and_init(), the local_port_show /
local_port_store configfs handlers, push_udp(),
netconsole_print_banner() and netconsole_parser_cmdline() to read
it from nt-> rather than np->.
netconsole_print_banner(), push_udp() and netconsole_parser_cmdline()
gain a struct netconsole_target * parameter so they can reach the
new home; subsequent patches that move remote_port and remote_mac
reuse the same plumbing.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
drivers/net/netconsole.c | 45 +++++++++++++++++++++++----------------------
include/linux/netpoll.h | 2 +-
2 files changed, 24 insertions(+), 23 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index b8b1608d09e9..a4f34560cee5 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -172,15 +172,11 @@ enum target_state {
* @extended: Denotes whether console is extended or not.
* @release: Denotes whether kernel release version should be prepended
* to the message. Depends on extended console.
- * @np: The netpoll structure for this target.
- * Contains the other userspace visible parameters:
- * dev_name (read-write)
- * local_port (read-write)
- * remote_port (read-write)
- * local_ip (read-write)
- * remote_ip (read-write)
- * local_mac (read-only)
- * remote_mac (read-write)
+ * @np: The netpoll structure for this target. Holds the
+ * underlying net_device handle and the addressing fields
+ * that netpoll core still reads (local_ip, remote_ip, ipv6,
+ * dev_name, dev_mac).
+ * @local_port: UDP source port used to build outgoing log packets.
* @buf: The buffer used to send the full msg to the network stack
* @resume_wq: Workqueue to resume deactivated target
* @skb_pool: Per-target fallback skb pool consulted by find_skb() when
@@ -208,6 +204,7 @@ struct netconsole_target {
bool extended;
bool release;
struct netpoll np;
+ u16 local_port;
/* protected by target_list_lock */
char buf[MAX_PRINT_CHUNK];
struct work_struct resume_wq;
@@ -432,7 +429,7 @@ static struct netconsole_target *alloc_and_init(void)
nt->np.name = "netconsole";
strscpy(nt->np.dev_name, "eth0", IFNAMSIZ);
- nt->np.local_port = 6665;
+ nt->local_port = 6665;
nt->np.remote_port = 6666;
eth_broadcast_addr(nt->np.remote_mac);
nt->state = STATE_DISABLED;
@@ -471,9 +468,11 @@ static void netconsole_process_cleanups_core(void)
mutex_unlock(&target_cleanup_list_lock);
}
-static void netconsole_print_banner(struct netpoll *np)
+static void netconsole_print_banner(struct netconsole_target *nt)
{
- np_info(np, "local port %d\n", np->local_port);
+ 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);
else
@@ -603,7 +602,7 @@ static ssize_t dev_name_show(struct config_item *item, char *buf)
static ssize_t local_port_show(struct config_item *item, char *buf)
{
- return sysfs_emit(buf, "%d\n", to_target(item)->np.local_port);
+ return sysfs_emit(buf, "%d\n", to_target(item)->local_port);
}
static ssize_t remote_port_show(struct config_item *item, char *buf)
@@ -798,7 +797,7 @@ static ssize_t enabled_store(struct config_item *item,
* Skip netconsole_parser_cmdline() -- all the attributes are
* already configured via configfs. Just print them out.
*/
- netconsole_print_banner(&nt->np);
+ netconsole_print_banner(nt);
/* Initialise the skb pool before netpoll_setup() so the pool
* is valid as soon as nt->np.dev becomes visible to
@@ -937,7 +936,7 @@ static ssize_t local_port_store(struct config_item *item, const char *buf,
goto out_unlock;
}
- ret = kstrtou16(buf, 10, &nt->np.local_port);
+ ret = kstrtou16(buf, 10, &nt->local_port);
if (ret < 0)
goto out_unlock;
ret = count;
@@ -1788,8 +1787,9 @@ static void netpoll_udp_checksum(struct netpoll *np, struct sk_buff *skb,
udph->check = CSUM_MANGLED_0;
}
-static void push_udp(struct netpoll *np, struct sk_buff *skb, int len)
+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;
@@ -1799,7 +1799,7 @@ static void push_udp(struct netpoll *np, struct sk_buff *skb, int len)
skb_reset_transport_header(skb);
udph = udp_hdr(skb);
- udph->source = htons(np->local_port);
+ udph->source = htons(nt->local_port);
udph->dest = htons(np->remote_port);
udph->len = htons(udp_len);
@@ -1896,7 +1896,7 @@ static int netpoll_send_udp(struct netconsole_target *nt, const char *msg,
skb_copy_to_linear_data(skb, msg, len);
skb_put(skb, len);
- push_udp(np, skb, len);
+ push_udp(nt, skb, len);
if (np->ipv6)
push_ipv6(np, skb, len);
else
@@ -2214,8 +2214,9 @@ __releases(&target_list_lock)
spin_unlock_irqrestore(&target_list_lock, flags);
}
-static int netconsole_parser_cmdline(struct netpoll *np, char *opt)
+static int netconsole_parser_cmdline(struct netconsole_target *nt, char *opt)
{
+ struct netpoll *np = &nt->np;
bool ipversion_set = false;
char *cur = opt;
char *delim;
@@ -2226,7 +2227,7 @@ static int netconsole_parser_cmdline(struct netpoll *np, char *opt)
if (!delim)
goto parse_failed;
*delim = 0;
- if (kstrtou16(cur, 10, &np->local_port))
+ if (kstrtou16(cur, 10, &nt->local_port))
goto parse_failed;
cur = delim;
}
@@ -2299,7 +2300,7 @@ static int netconsole_parser_cmdline(struct netpoll *np, char *opt)
goto parse_failed;
}
- netconsole_print_banner(np);
+ netconsole_print_banner(nt);
return 0;
@@ -2337,7 +2338,7 @@ static struct netconsole_target *alloc_param_target(char *target_config,
}
/* Parse parameters and setup netpoll */
- err = netconsole_parser_cmdline(&nt->np, target_config);
+ err = netconsole_parser_cmdline(nt, target_config);
if (err)
goto fail;
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 8344454df05d..dcea36713720 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -33,7 +33,7 @@ struct netpoll {
union inet_addr local_ip, remote_ip;
bool ipv6;
- u16 local_port, remote_port;
+ u16 remote_port;
u8 remote_mac[ETH_ALEN];
};
--
2.54.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 8/9] netconsole: move remote_port from struct netpoll to netconsole_target
2026-05-24 16:12 [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state Breno Leitao
` (6 preceding siblings ...)
2026-05-24 16:12 ` [PATCH 7/9] netconsole: move local_port " Breno Leitao
@ 2026-05-24 16:12 ` Breno Leitao
2026-05-24 16:12 ` [PATCH 9/9] netconsole: move remote_mac " Breno Leitao
2026-05-27 2:00 ` [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state Jakub Kicinski
9 siblings, 0 replies; 13+ messages in thread
From: Breno Leitao @ 2026-05-24 16:12 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
The UDP destination port used to build outgoing log packets is pure
netconsole configuration. net/core/netpoll.c never reads it, and
no other struct netpoll consumer touches it.
Add remote_port to struct netconsole_target, drop it from struct
netpoll, and update alloc_and_init(), the remote_port_show /
remote_port_store configfs handlers, push_udp(),
netconsole_print_banner() and netconsole_parser_cmdline() to read
it from nt-> rather than np->. The struct netconsole_target *
parameter threaded through these helpers by the previous patch
already gives them access to the new home.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
drivers/net/netconsole.c | 14 ++++++++------
include/linux/netpoll.h | 1 -
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index a4f34560cee5..32e2a925f915 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -177,6 +177,7 @@ enum target_state {
* that netpoll core still reads (local_ip, remote_ip, ipv6,
* dev_name, dev_mac).
* @local_port: UDP source port used to build outgoing log packets.
+ * @remote_port: UDP destination port used to build outgoing log packets.
* @buf: The buffer used to send the full msg to the network stack
* @resume_wq: Workqueue to resume deactivated target
* @skb_pool: Per-target fallback skb pool consulted by find_skb() when
@@ -205,6 +206,7 @@ struct netconsole_target {
bool release;
struct netpoll np;
u16 local_port;
+ u16 remote_port;
/* protected by target_list_lock */
char buf[MAX_PRINT_CHUNK];
struct work_struct resume_wq;
@@ -430,7 +432,7 @@ static struct netconsole_target *alloc_and_init(void)
nt->np.name = "netconsole";
strscpy(nt->np.dev_name, "eth0", IFNAMSIZ);
nt->local_port = 6665;
- nt->np.remote_port = 6666;
+ nt->remote_port = 6666;
eth_broadcast_addr(nt->np.remote_mac);
nt->state = STATE_DISABLED;
INIT_WORK(&nt->resume_wq, process_resume_target);
@@ -479,7 +481,7 @@ static void netconsole_print_banner(struct netconsole_target *nt)
np_info(np, "local IPv4 address %pI4\n", &np->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", np->remote_port);
+ 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);
else
@@ -607,7 +609,7 @@ static ssize_t local_port_show(struct config_item *item, char *buf)
static ssize_t remote_port_show(struct config_item *item, char *buf)
{
- return sysfs_emit(buf, "%d\n", to_target(item)->np.remote_port);
+ return sysfs_emit(buf, "%d\n", to_target(item)->remote_port);
}
static ssize_t local_ip_show(struct config_item *item, char *buf)
@@ -958,7 +960,7 @@ static ssize_t remote_port_store(struct config_item *item,
goto out_unlock;
}
- ret = kstrtou16(buf, 10, &nt->np.remote_port);
+ ret = kstrtou16(buf, 10, &nt->remote_port);
if (ret < 0)
goto out_unlock;
ret = count;
@@ -1800,7 +1802,7 @@ static void push_udp(struct netconsole_target *nt, struct sk_buff *skb, int len)
udph = udp_hdr(skb);
udph->source = htons(nt->local_port);
- udph->dest = htons(np->remote_port);
+ udph->dest = htons(nt->remote_port);
udph->len = htons(udp_len);
netpoll_udp_checksum(np, skb, len);
@@ -2274,7 +2276,7 @@ static int netconsole_parser_cmdline(struct netconsole_target *nt, char *opt)
*delim = 0;
if (*cur == ' ' || *cur == '\t')
np_info(np, "warning: whitespace is not allowed\n");
- if (kstrtou16(cur, 10, &np->remote_port))
+ if (kstrtou16(cur, 10, &nt->remote_port))
goto parse_failed;
cur = delim;
}
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index dcea36713720..12467a45929e 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -33,7 +33,6 @@ struct netpoll {
union inet_addr local_ip, remote_ip;
bool ipv6;
- u16 remote_port;
u8 remote_mac[ETH_ALEN];
};
--
2.54.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 9/9] netconsole: move remote_mac from struct netpoll to netconsole_target
2026-05-24 16:12 [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state Breno Leitao
` (7 preceding siblings ...)
2026-05-24 16:12 ` [PATCH 8/9] netconsole: move remote_port " Breno Leitao
@ 2026-05-24 16:12 ` Breno Leitao
2026-05-27 2:00 ` [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state Jakub Kicinski
9 siblings, 0 replies; 13+ messages in thread
From: Breno Leitao @ 2026-05-24 16:12 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
The destination ethernet address used to build outgoing log packets
is pure netconsole configuration. net/core/netpoll.c never reads
it, and no other struct netpoll consumer touches it.
Add remote_mac to struct netconsole_target, drop it from struct
netpoll, and update alloc_and_init(), the remote_mac_show /
remote_mac_store configfs handlers, push_eth(),
netconsole_print_banner() and netconsole_parser_cmdline() to read
it from nt-> rather than np->. push_eth() gains a struct
netconsole_target * parameter to reach the new home; its only
caller in netpoll_send_udp() already has nt available.
After this patch struct netpoll keeps only what genuinely belongs
to the generic poll/transmit abstraction (dev, dev_tracker,
dev_name, dev_mac, name) plus the IP addressing fields that
netpoll_setup() and netpoll_take_ipv6() still read themselves
(local_ip, remote_ip, ipv6).
Signed-off-by: Breno Leitao <leitao@debian.org>
---
drivers/net/netconsole.c | 19 +++++++++++--------
include/linux/netpoll.h | 1 -
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 32e2a925f915..29a6c13e9cfd 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -178,6 +178,7 @@ enum target_state {
* dev_name, dev_mac).
* @local_port: UDP source port used to build outgoing log packets.
* @remote_port: UDP destination port used to build outgoing log packets.
+ * @remote_mac: Destination ethernet address used to build outgoing log packets.
* @buf: The buffer used to send the full msg to the network stack
* @resume_wq: Workqueue to resume deactivated target
* @skb_pool: Per-target fallback skb pool consulted by find_skb() when
@@ -207,6 +208,7 @@ struct netconsole_target {
struct netpoll np;
u16 local_port;
u16 remote_port;
+ u8 remote_mac[ETH_ALEN];
/* protected by target_list_lock */
char buf[MAX_PRINT_CHUNK];
struct work_struct resume_wq;
@@ -433,7 +435,7 @@ static struct netconsole_target *alloc_and_init(void)
strscpy(nt->np.dev_name, "eth0", IFNAMSIZ);
nt->local_port = 6665;
nt->remote_port = 6666;
- eth_broadcast_addr(nt->np.remote_mac);
+ eth_broadcast_addr(nt->remote_mac);
nt->state = STATE_DISABLED;
INIT_WORK(&nt->resume_wq, process_resume_target);
@@ -486,7 +488,7 @@ static void netconsole_print_banner(struct netconsole_target *nt)
np_info(np, "remote IPv6 address %pI6c\n", &np->remote_ip.in6);
else
np_info(np, "remote IPv4 address %pI4\n", &np->remote_ip.ip);
- np_info(np, "remote ethernet address %pM\n", np->remote_mac);
+ np_info(np, "remote ethernet address %pM\n", nt->remote_mac);
}
/* Parse the string and populate the `inet_addr` union. Return 0 if IPv4 is
@@ -642,7 +644,7 @@ static ssize_t local_mac_show(struct config_item *item, char *buf)
static ssize_t remote_mac_show(struct config_item *item, char *buf)
{
- return sysfs_emit(buf, "%pM\n", to_target(item)->np.remote_mac);
+ return sysfs_emit(buf, "%pM\n", to_target(item)->remote_mac);
}
static ssize_t transmit_errors_show(struct config_item *item, char *buf)
@@ -1047,7 +1049,7 @@ static ssize_t remote_mac_store(struct config_item *item, const char *buf,
goto out_unlock;
if (buf[MAC_ADDR_STR_LEN] && buf[MAC_ADDR_STR_LEN] != '\n')
goto out_unlock;
- memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN);
+ memcpy(nt->remote_mac, remote_mac, ETH_ALEN);
ret = count;
out_unlock:
@@ -1808,14 +1810,15 @@ static void push_udp(struct netconsole_target *nt, struct sk_buff *skb, int len)
netpoll_udp_checksum(np, skb, len);
}
-static void push_eth(struct netpoll *np, struct sk_buff *skb)
+static void push_eth(struct netconsole_target *nt, struct sk_buff *skb)
{
+ struct netpoll *np = &nt->np;
struct ethhdr *eth;
eth = skb_push(skb, ETH_HLEN);
skb_reset_mac_header(skb);
ether_addr_copy(eth->h_source, np->dev->dev_addr);
- ether_addr_copy(eth->h_dest, np->remote_mac);
+ ether_addr_copy(eth->h_dest, nt->remote_mac);
if (np->ipv6)
eth->h_proto = htons(ETH_P_IPV6);
else
@@ -1903,7 +1906,7 @@ static int netpoll_send_udp(struct netconsole_target *nt, const char *msg,
push_ipv6(np, skb, len);
else
push_ipv4(np, skb, len);
- push_eth(np, skb);
+ push_eth(nt, skb);
skb->dev = np->dev;
return (int)netpoll_send_skb(np, skb);
@@ -2298,7 +2301,7 @@ static int netconsole_parser_cmdline(struct netconsole_target *nt, char *opt)
if (*cur != 0) {
/* MAC address */
- if (!mac_pton(cur, np->remote_mac))
+ if (!mac_pton(cur, nt->remote_mac))
goto parse_failed;
}
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 12467a45929e..9f4236557ffe 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -33,7 +33,6 @@ struct netpoll {
union inet_addr local_ip, remote_ip;
bool ipv6;
- u8 remote_mac[ETH_ALEN];
};
#define np_info(np, fmt, ...) \
--
2.54.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state
2026-05-24 16:12 [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state Breno Leitao
` (8 preceding siblings ...)
2026-05-24 16:12 ` [PATCH 9/9] netconsole: move remote_mac " Breno Leitao
@ 2026-05-27 2:00 ` Jakub Kicinski
2026-05-27 9:07 ` Breno Leitao
9 siblings, 1 reply; 13+ messages in thread
From: Jakub Kicinski @ 2026-05-27 2:00 UTC (permalink / raw)
To: Breno Leitao
Cc: David S. Miller, Eric Dumazet, Paolo Abeni, Simon Horman,
Andrew Lunn, netdev, linux-kernel, gustavold, asantostc,
kernel-team
On Sun, 24 May 2026 09:12:16 -0700 Breno Leitao wrote:
> struct netpoll is shared by every netpoll consumer in the tree:
> bonding, bridge, team, vlan, macvlan, dsa and netconsole. The non-
> netconsole users only need a per-port handle that lets them transmit
> SKBs.
Are any of the Sashiko reports real?
At least one seems legit (parallel device and target removal).
If yes we should probably try to fix them before we shuffle the code
around?
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state
2026-05-27 2:00 ` [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state Jakub Kicinski
@ 2026-05-27 9:07 ` Breno Leitao
2026-05-27 13:22 ` Breno Leitao
0 siblings, 1 reply; 13+ messages in thread
From: Breno Leitao @ 2026-05-27 9:07 UTC (permalink / raw)
To: Jakub Kicinski
Cc: David S. Miller, Eric Dumazet, Paolo Abeni, Simon Horman,
Andrew Lunn, netdev, linux-kernel, gustavold, asantostc,
kernel-team
On Tue, May 26, 2026 at 07:00:53PM +0000, Jakub Kicinski wrote:
> On Sun, 24 May 2026 09:12:16 -0700 Breno Leitao wrote:
> > struct netpoll is shared by every netpoll consumer in the tree:
> > bonding, bridge, team, vlan, macvlan, dsa and netconsole. The non-
> > netconsole users only need a per-port handle that lets them transmit
> > SKBs.
>
> Are any of the Sashiko reports real?
Yes, there are real pre-existent issues reported by Sashiko.
> At least one seems legit (parallel device and target removal).
> If yes we should probably try to fix them before we shuffle the code
> around?
Ack, I will get them fixed and them move them around.
Thanks,
--breno
--
pw-bot: cr
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state
2026-05-27 9:07 ` Breno Leitao
@ 2026-05-27 13:22 ` Breno Leitao
0 siblings, 0 replies; 13+ messages in thread
From: Breno Leitao @ 2026-05-27 13:22 UTC (permalink / raw)
To: Jakub Kicinski
Cc: David S. Miller, Eric Dumazet, Paolo Abeni, Simon Horman,
Andrew Lunn, netdev, linux-kernel, gustavold, asantostc,
kernel-team
Jakub and netdev maintainers,
On Wed, May 27, 2026 at 10:07:16AM +0100, Breno Leitao wrote:
> On Tue, May 26, 2026 at 07:00:53PM +0000, Jakub Kicinski wrote:
> > On Sun, 24 May 2026 09:12:16 -0700 Breno Leitao wrote:
> > > struct netpoll is shared by every netpoll consumer in the tree:
> > > bonding, bridge, team, vlan, macvlan, dsa and netconsole. The non-
> > > netconsole users only need a per-port handle that lets them transmit
> > > SKBs.
> >
> > Are any of the Sashiko reports real?
>
> Yes, there are real pre-existent issues reported by Sashiko.
>
> > At least one seems legit (parallel device and target removal).
> > If yes we should probably try to fix them before we shuffle the code
> > around?
>
> Ack, I will get them fixed and them move them around.
I was reading Linus' Linux 7.1-rc5 email[1], and I am wondering if these
type of "fixes" should go to net or are you planning to change it to net-next.
"""
These things are "fixes", sure, but at the same time a lot of them
are simply so irrelevant that I think they'd be better off in
a linux-next tree and get merged during the merge window.
""" --linus
Link: https://lore.kernel.org/all/CAHk-=wjt1NiKOdyAMz_DT7NmZ++SizPOhRSi492ukdTnpDzHQw@mail.gmail.com/ [1]
Thanks
--breno
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-05-27 13:22 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-24 16:12 [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state Breno Leitao
2026-05-24 16:12 ` [PATCH 1/9] netpoll: export refill_skbs(), refill_skbs_work_handler(), skb_pool_flush() Breno Leitao
2026-05-24 16:12 ` [PATCH 2/9] netconsole: take over skb pool lifecycle from netpoll Breno Leitao
2026-05-24 16:12 ` [PATCH 3/9] netconsole: move refill_skbs_work_handler() " Breno Leitao
2026-05-24 16:12 ` [PATCH 4/9] netconsole: move refill_skbs() and skb-pool sizing macros " Breno Leitao
2026-05-24 16:12 ` [PATCH 5/9] netconsole: move skb_pool_flush() " Breno Leitao
2026-05-24 16:12 ` [PATCH 6/9] netconsole: move skb_pool / refill_wq from struct netpoll to netconsole_target Breno Leitao
2026-05-24 16:12 ` [PATCH 7/9] netconsole: move local_port " Breno Leitao
2026-05-24 16:12 ` [PATCH 8/9] netconsole: move remote_port " Breno Leitao
2026-05-24 16:12 ` [PATCH 9/9] netconsole: move remote_mac " Breno Leitao
2026-05-27 2:00 ` [PATCH 0/9] netconsole: stop charging every netpoll user for netconsole-only state Jakub Kicinski
2026-05-27 9:07 ` Breno Leitao
2026-05-27 13:22 ` Breno Leitao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox