[RFC net-next v2 02/18] ipv4/ipv6: add LWT receive helpers
From: Ralf Lici
Date: Sat Oct 24 2026 - 05:28:42 EST
Cross-family LWT translation constructs a validated target-family
packet and needs to enter its receive path at PRE_ROUTING. Add helpers
that invoke the hook and continue with normal input routing.
The continuation remains in IP core, so it stays valid if NFQUEUE holds
a packet after the selecting LWT dst has been dropped.
Signed-off-by: Ralf Lici <ralf@xxxxxxxxxxxxx>
---
New patch in RFC v2.
include/net/ip.h | 1 +
include/net/ipv6.h | 1 +
net/ipv4/ip_input.c | 10 ++++++++++
net/ipv6/ip6_input.c | 11 +++++++++++
4 files changed, 23 insertions(+)
diff --git a/include/net/ip.h b/include/net/ip.h
index 618b9806c10b..761b6b0d48f7 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -170,6 +170,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, const struct sock *sk,
struct ip_options_rcu *opt, u8 tos);
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt,
struct net_device *orig_dev);
+int ip_rcv_lwt(struct sk_buff *skb);
void ip_list_rcv(struct list_head *head, struct packet_type *pt,
struct net_device *orig_dev);
int ip_local_deliver(struct sk_buff *skb);
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 3de07e738538..e3f245d640ac 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -1016,6 +1016,7 @@ static inline __be32 flowi6_get_flowlabel(const struct flowi6 *fl6)
int ipv6_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev);
+int ip6_rcv_lwt(struct sk_buff *skb);
void ipv6_list_rcv(struct list_head *head, struct packet_type *pt,
struct net_device *orig_dev);
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 9860178752b8..f679e38a1a1c 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -493,6 +493,16 @@ static int ip_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
return ret;
}
+/* enter IPv4 PRE_ROUTING with a validated LWT packet */
+int ip_rcv_lwt(struct sk_buff *skb)
+{
+ struct net *net = dev_net(skb->dev);
+
+ return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, net, NULL, skb,
+ skb->dev, NULL, ip_rcv_finish);
+}
+EXPORT_SYMBOL_GPL(ip_rcv_lwt);
+
/*
* Main IP Receive routine.
*/
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index d332ec60f915..47aaa1fcf82b 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -26,6 +26,7 @@
#include <linux/mroute6.h>
#include <linux/slab.h>
#include <linux/indirect_call_wrapper.h>
+#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv6.h>
@@ -119,6 +120,16 @@ int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
return dst_input(skb);
}
+/* enter IPv6 PRE_ROUTING with a validated LWT packet */
+int ip6_rcv_lwt(struct sk_buff *skb)
+{
+ struct net *net = dev_net(skb->dev);
+
+ return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, net, NULL, skb,
+ skb->dev, NULL, ip6_rcv_finish);
+}
+EXPORT_SYMBOL_GPL(ip6_rcv_lwt);
+
static void ip6_sublist_rcv_finish(struct list_head *head)
{
struct sk_buff *skb, *next;
--
2.55.0