[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250902-netpoll_untangle_v3-v1-2-51a03d6411be@debian.org>
Date: Tue, 02 Sep 2025 07:36:24 -0700
From: Breno Leitao <leitao@...ian.org>
To: Andrew Lunn <andrew+netdev@...n.ch>,
"David S. Miller" <davem@...emloft.net>, Eric Dumazet <edumazet@...gle.com>,
Jakub Kicinski <kuba@...nel.org>, Paolo Abeni <pabeni@...hat.com>,
Simon Horman <horms@...nel.org>,
Sebastian Andrzej Siewior <bigeasy@...utronix.de>,
Clark Williams <clrkwllms@...nel.org>, Steven Rostedt <rostedt@...dmis.org>
Cc: netdev@...r.kernel.org, linux-kernel@...r.kernel.org,
linux-rt-devel@...ts.linux.dev, kernel-team@...a.com, efault@....de,
calvin@...nvd.org, Breno Leitao <leitao@...ian.org>
Subject: [PATCH 2/7] netpoll: move prepare skb functions to netconsole
Move the UDP packet preparation logic from netpoll core to netconsole
driver, consolidating network console-specific functionality.
Changes include:
- Move netpoll_prepare_skb() from net/core/netpoll.c to netconsole.c
- Move all UDP/IP header construction helpers (push_udp, push_ipv4,
push_ipv6, push_eth, netpoll_udp_checksum) to netconsole.c
- Add necessary network header includes to netconsole.c
- Export find_skb() from netpoll core to allow netconsole access
* This is temporary, given that skb pool management is a netconsole
thing. This will be removed in the upcoming change in this patchset.
With this in mind, netconsole become another usual netpoll user, by
calling it with SKBs instead of msgs and len.
Signed-off-by: Breno Leitao <leitao@...ian.org>
---
drivers/net/netconsole.c | 147 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/netpoll.h | 3 +-
net/core/netpoll.c | 151 +----------------------------------------------
3 files changed, 150 insertions(+), 151 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 5b8af2de719a2..30731711571be 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -40,6 +40,10 @@
#include <linux/utsname.h>
#include <linux/rtnetlink.h>
+#include <net/ip6_checksum.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+
MODULE_AUTHOR("Matt Mackall <mpm@...enic.com>");
MODULE_DESCRIPTION("Console driver for network interfaces");
MODULE_LICENSE("GPL");
@@ -1480,6 +1484,149 @@ static struct notifier_block netconsole_netdev_notifier = {
.notifier_call = netconsole_netdev_event,
};
+static void netpoll_udp_checksum(struct netpoll *np, struct sk_buff *skb,
+ int len)
+{
+ struct udphdr *udph;
+ int udp_len;
+
+ udp_len = len + sizeof(struct udphdr);
+ udph = udp_hdr(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,
+ udp_len, IPPROTO_UDP,
+ csum_partial(udph, udp_len, 0));
+ else
+ udph->check = csum_tcpudp_magic(np->local_ip.ip,
+ np->remote_ip.ip,
+ udp_len, IPPROTO_UDP,
+ csum_partial(udph, udp_len, 0));
+ if (udph->check == 0)
+ udph->check = CSUM_MANGLED_0;
+}
+
+static void push_ipv6(struct netpoll *np, struct sk_buff *skb, int len)
+{
+ struct ipv6hdr *ip6h;
+
+ skb_push(skb, sizeof(struct ipv6hdr));
+ skb_reset_network_header(skb);
+ ip6h = ipv6_hdr(skb);
+
+ /* ip6h->version = 6; ip6h->priority = 0; */
+ *(unsigned char *)ip6h = 0x60;
+ ip6h->flow_lbl[0] = 0;
+ ip6h->flow_lbl[1] = 0;
+ ip6h->flow_lbl[2] = 0;
+
+ 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;
+
+ skb->protocol = htons(ETH_P_IPV6);
+}
+
+static void push_ipv4(struct netpoll *np, struct sk_buff *skb, int len)
+{
+ static atomic_t ip_ident;
+ struct iphdr *iph;
+ int ip_len;
+
+ ip_len = len + sizeof(struct udphdr) + sizeof(struct iphdr);
+
+ skb_push(skb, sizeof(struct iphdr));
+ skb_reset_network_header(skb);
+ iph = ip_hdr(skb);
+
+ /* iph->version = 4; iph->ihl = 5; */
+ *(unsigned char *)iph = 0x45;
+ iph->tos = 0;
+ put_unaligned(htons(ip_len), &iph->tot_len);
+ iph->id = htons(atomic_inc_return(&ip_ident));
+ iph->frag_off = 0;
+ 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);
+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+ skb->protocol = htons(ETH_P_IP);
+}
+
+static void push_udp(struct netpoll *np, struct sk_buff *skb, int len)
+{
+ struct udphdr *udph;
+ int udp_len;
+
+ udp_len = len + sizeof(struct udphdr);
+
+ skb_push(skb, sizeof(struct udphdr));
+ skb_reset_transport_header(skb);
+
+ udph = udp_hdr(skb);
+ udph->source = htons(np->local_port);
+ udph->dest = htons(np->remote_port);
+ udph->len = htons(udp_len);
+
+ netpoll_udp_checksum(np, skb, len);
+}
+
+static void push_eth(struct netpoll *np, struct sk_buff *skb)
+{
+ 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);
+ if (np->ipv6)
+ eth->h_proto = htons(ETH_P_IPV6);
+ else
+ eth->h_proto = htons(ETH_P_IP);
+}
+
+static struct sk_buff *netpoll_prepare_skb(struct netpoll *np, const char *msg,
+ int len)
+{
+ int total_len, ip_len, udp_len;
+ struct sk_buff *skb;
+
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT))
+ WARN_ON_ONCE(!irqs_disabled());
+
+ udp_len = len + sizeof(struct udphdr);
+ if (np->ipv6)
+ ip_len = udp_len + sizeof(struct ipv6hdr);
+ else
+ ip_len = udp_len + sizeof(struct iphdr);
+
+ total_len = ip_len + LL_RESERVED_SPACE(np->dev);
+
+ skb = find_skb(np, total_len + np->dev->needed_tailroom,
+ total_len - len);
+ if (!skb)
+ return NULL;
+
+ skb_copy_to_linear_data(skb, msg, len);
+ skb_put(skb, len);
+
+ push_udp(np, skb, len);
+ if (np->ipv6)
+ push_ipv6(np, skb, len);
+ else
+ push_ipv4(np, skb, len);
+ push_eth(np, skb);
+ skb->dev = np->dev;
+
+ return skb;
+}
+
/**
* send_udp - Wrapper for netpoll_send_udp that counts errors
* @nt: target to send message to
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index ed74889e126c7..481ec474fa6b9 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -69,14 +69,13 @@ static inline void netpoll_poll_enable(struct net_device *dev) { return; }
#endif
int netpoll_send_udp(struct netpoll *np, const char *msg, int len);
-struct sk_buff *netpoll_prepare_skb(struct netpoll *np, const char *msg,
- int len);
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);
netdev_tx_t netpoll_send_skb(struct netpoll *np, struct sk_buff *skb);
+struct sk_buff *find_skb(struct netpoll *np, int len, int reserve);
#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 e2098c19987f4..b4634e91568e8 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -29,11 +29,8 @@
#include <linux/slab.h>
#include <linux/export.h>
#include <linux/if_vlan.h>
-#include <net/tcp.h>
-#include <net/udp.h>
#include <net/addrconf.h>
#include <net/ndisc.h>
-#include <net/ip6_checksum.h>
#include <linux/unaligned.h>
#include <trace/events/napi.h>
#include <linux/kconfig.h>
@@ -271,7 +268,7 @@ static void zap_completion_queue(void)
put_cpu_var(softnet_data);
}
-static struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)
+struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)
{
int count = 0;
struct sk_buff *skb;
@@ -297,6 +294,7 @@ static struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)
skb_reserve(skb, reserve);
return skb;
}
+EXPORT_SYMBOL_GPL(find_skb);
static int netpoll_owner_active(struct net_device *dev)
{
@@ -372,31 +370,6 @@ static netdev_tx_t __netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
return ret;
}
-static void netpoll_udp_checksum(struct netpoll *np, struct sk_buff *skb,
- int len)
-{
- struct udphdr *udph;
- int udp_len;
-
- udp_len = len + sizeof(struct udphdr);
- udph = udp_hdr(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,
- udp_len, IPPROTO_UDP,
- csum_partial(udph, udp_len, 0));
- else
- udph->check = csum_tcpudp_magic(np->local_ip.ip,
- np->remote_ip.ip,
- udp_len, IPPROTO_UDP,
- csum_partial(udph, udp_len, 0));
- if (udph->check == 0)
- udph->check = CSUM_MANGLED_0;
-}
-
netdev_tx_t netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
{
unsigned long flags;
@@ -414,126 +387,6 @@ netdev_tx_t netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
}
EXPORT_SYMBOL(netpoll_send_skb);
-static void push_ipv6(struct netpoll *np, struct sk_buff *skb, int len)
-{
- struct ipv6hdr *ip6h;
-
- skb_push(skb, sizeof(struct ipv6hdr));
- skb_reset_network_header(skb);
- ip6h = ipv6_hdr(skb);
-
- /* ip6h->version = 6; ip6h->priority = 0; */
- *(unsigned char *)ip6h = 0x60;
- ip6h->flow_lbl[0] = 0;
- ip6h->flow_lbl[1] = 0;
- ip6h->flow_lbl[2] = 0;
-
- 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;
-
- skb->protocol = htons(ETH_P_IPV6);
-}
-
-static void push_ipv4(struct netpoll *np, struct sk_buff *skb, int len)
-{
- static atomic_t ip_ident;
- struct iphdr *iph;
- int ip_len;
-
- ip_len = len + sizeof(struct udphdr) + sizeof(struct iphdr);
-
- skb_push(skb, sizeof(struct iphdr));
- skb_reset_network_header(skb);
- iph = ip_hdr(skb);
-
- /* iph->version = 4; iph->ihl = 5; */
- *(unsigned char *)iph = 0x45;
- iph->tos = 0;
- put_unaligned(htons(ip_len), &iph->tot_len);
- iph->id = htons(atomic_inc_return(&ip_ident));
- iph->frag_off = 0;
- 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);
- iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
- skb->protocol = htons(ETH_P_IP);
-}
-
-static void push_udp(struct netpoll *np, struct sk_buff *skb, int len)
-{
- struct udphdr *udph;
- int udp_len;
-
- udp_len = len + sizeof(struct udphdr);
-
- skb_push(skb, sizeof(struct udphdr));
- skb_reset_transport_header(skb);
-
- udph = udp_hdr(skb);
- udph->source = htons(np->local_port);
- udph->dest = htons(np->remote_port);
- udph->len = htons(udp_len);
-
- netpoll_udp_checksum(np, skb, len);
-}
-
-static void push_eth(struct netpoll *np, struct sk_buff *skb)
-{
- 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);
- if (np->ipv6)
- eth->h_proto = htons(ETH_P_IPV6);
- else
- eth->h_proto = htons(ETH_P_IP);
-}
-
-struct sk_buff *netpoll_prepare_skb(struct netpoll *np, const char *msg,
- int len)
-{
- int total_len, ip_len, udp_len;
- struct sk_buff *skb;
-
- if (!IS_ENABLED(CONFIG_PREEMPT_RT))
- WARN_ON_ONCE(!irqs_disabled());
-
- udp_len = len + sizeof(struct udphdr);
- if (np->ipv6)
- ip_len = udp_len + sizeof(struct ipv6hdr);
- else
- ip_len = udp_len + sizeof(struct iphdr);
-
- total_len = ip_len + LL_RESERVED_SPACE(np->dev);
-
- skb = find_skb(np, total_len + np->dev->needed_tailroom,
- total_len - len);
- if (!skb)
- return NULL;
-
- skb_copy_to_linear_data(skb, msg, len);
- skb_put(skb, len);
-
- push_udp(np, skb, len);
- if (np->ipv6)
- push_ipv6(np, skb, len);
- else
- push_ipv4(np, skb, len);
- push_eth(np, skb);
- skb->dev = np->dev;
-
- return skb;
-}
-EXPORT_SYMBOL(netpoll_prepare_skb);
-
-
static void skb_pool_flush(struct netpoll *np)
{
struct sk_buff_head *skb_pool;
--
2.47.3
Powered by blists - more mailing lists