All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nf-next 0/8] Add IPv4 over IPv6 and SIT flowtable SW acceleration
@ 2026-10-29 13:35 Lorenzo Bianconi
  2026-10-29 13:35 ` [PATCH nf-next 1/8] net: netfilter: nf_flow_table: recognize IPv4/IPv6 in tunnel proto matching Lorenzo Bianconi
                   ` (7 more replies)
  0 siblings, 8 replies; 11+ messages in thread
From: Lorenzo Bianconi @ 2026-10-29 13:35 UTC (permalink / raw)
  To: Pablo Neira Ayuso, Florian Westphal, Phil Sutter, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	David Ahern, Ido Schimmel, Shuah Khan
  Cc: netfilter-devel, coreteam, netdev, linux-kselftest,
	Lorenzo Bianconi

Similar to IPIP and IP6I6 tunnels, introduce sw acceleration for IPv4 over
IPv6 and SIT tunnels in the netfilter flowtable infrastructure.

---
Lorenzo Bianconi (8):
      net: netfilter: nf_flow_table: recognize IPv4/IPv6 in tunnel proto matching
      net: netfilter: nf_flow_table: refactor MTU check for tunnel offload
      net: ip6_tunnel: add IPv4 over IPv6 flowtable tunnel offload
      net: netfilter: nf_flow_table: use tunnel encap proto for route lookup
      net: netfilter: add IPv4 over IPv6 tunnel flowtable acceleration
      selftests: netfilter: nft_flowtable.sh: add IPv4 over IPv6 flowtable selftest
      net: netfilter: add SIT tunnel flowtable acceleration
      selftests: netfilter: nft_flowtable.sh: add SIT flowtable selftest

 net/ipv6/ip6_tunnel.c                              |  11 +-
 net/ipv6/sit.c                                     |  59 +++++++++
 net/netfilter/nf_flow_table_core.c                 |  18 ++-
 net/netfilter/nf_flow_table_ip.c                   | 133 ++++++++++++++++-----
 tools/testing/selftests/net/netfilter/config       |   1 +
 .../selftests/net/netfilter/nft_flowtable.sh       |  86 ++++++++++++-
 6 files changed, 269 insertions(+), 39 deletions(-)
---
base-commit: 734bef548a96e8774d6eef5dfa2026c6edc4e80b
change-id: 20261029-flowtable-sw-accel-ip6ip-sit-f3393772880e

Best regards,
-- 
Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH nf-next 1/8] net: netfilter: nf_flow_table: recognize IPv4/IPv6 in tunnel proto matching
  2026-10-29 13:35 [PATCH nf-next 0/8] Add IPv4 over IPv6 and SIT flowtable SW acceleration Lorenzo Bianconi
@ 2026-10-29 13:35 ` Lorenzo Bianconi
  2026-10-29 13:35 ` [PATCH nf-next 2/8] net: netfilter: nf_flow_table: refactor MTU check for tunnel offload Lorenzo Bianconi
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Lorenzo Bianconi @ 2026-10-29 13:35 UTC (permalink / raw)
  To: Pablo Neira Ayuso, Florian Westphal, Phil Sutter, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	David Ahern, Ido Schimmel, Shuah Khan
  Cc: netfilter-devel, coreteam, netdev, linux-kselftest,
	Lorenzo Bianconi

Allow the flowtable to parse IPv4-in-IPv6 and IPv6-in-IPv4 tunnels by
accepting both IPPROTO_IPIP and IPPROTO_IPV6 as the inner protocol when
walking the outer header in nf_flow_ip4_tunnel_proto() and
nf_flow_ip6_tunnel_proto(). This is a preliminary patch to support IPv4
over IPv6 and SIT tunnel flowtable offload.
Please note IPv4 over IPv6 and SIT tunnel flowtable offloading is not
enabled yet.

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
---
 net/netfilter/nf_flow_table_ip.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index 19cafae748ab..e07fa9327eb7 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -328,7 +328,7 @@ static bool nf_flow_ip4_tunnel_proto(struct nf_flowtable_ctx *ctx,
 	if (iph->ttl <= 1)
 		return false;
 
-	if (iph->protocol == IPPROTO_IPIP) {
+	if (iph->protocol == IPPROTO_IPIP || iph->protocol == IPPROTO_IPV6) {
 		ctx->tun.inner_proto = iph->protocol;
 		ctx->tun.hdr_size = size;
 		ctx->offset += ctx->tun.hdr_size;
@@ -353,7 +353,7 @@ static bool nf_flow_ip6_tunnel_proto(struct nf_flowtable_ctx *ctx,
 	if (ipv6_ext_hdr(ip6h->nexthdr))
 		return false;
 
-	if (ip6h->nexthdr == IPPROTO_IPV6) {
+	if (ip6h->nexthdr == IPPROTO_IPIP || ip6h->nexthdr == IPPROTO_IPV6) {
 		ctx->tun.inner_proto = ip6h->nexthdr;
 		ctx->tun.hdr_size = sizeof(*ip6h);
 		ctx->offset += ctx->tun.hdr_size;

-- 
2.56.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH nf-next 2/8] net: netfilter: nf_flow_table: refactor MTU check for tunnel offload
  2026-10-29 13:35 [PATCH nf-next 0/8] Add IPv4 over IPv6 and SIT flowtable SW acceleration Lorenzo Bianconi
  2026-10-29 13:35 ` [PATCH nf-next 1/8] net: netfilter: nf_flow_table: recognize IPv4/IPv6 in tunnel proto matching Lorenzo Bianconi
@ 2026-10-29 13:35 ` Lorenzo Bianconi
  2026-10-29 13:35 ` [PATCH nf-next 3/8] net: ip6_tunnel: add IPv4 over IPv6 flowtable " Lorenzo Bianconi
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Lorenzo Bianconi @ 2026-10-29 13:35 UTC (permalink / raw)
  To: Pablo Neira Ayuso, Florian Westphal, Phil Sutter, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	David Ahern, Ido Schimmel, Shuah Khan
  Cc: netfilter-devel, coreteam, netdev, linux-kselftest,
	Lorenzo Bianconi

Introduce nf_flow_offload_check_mtu() helper and use the encapsulated
protocol (tun.encap_proto) to compute the tunnel overhead instead of
relying on tun_num, so the correct inner header size (IPv4 vs IPv6) is
accounted for. Use it in both the IPv4 and IPv6 forward paths.
This is a preliminary patch to support IPv4 over IPv6 and SIT flowtable
tunnel offload.
Please note IPv4 over IPv6 and SIT tunnel flowtable offloading is not
enabled yet.

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
---
 net/netfilter/nf_flow_table_ip.c | 41 ++++++++++++++++++++++++++++------------
 1 file changed, 29 insertions(+), 12 deletions(-)

diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index e07fa9327eb7..902b9b595677 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -472,6 +472,31 @@ nf_flow_offload_lookup(struct nf_flowtable_ctx *ctx,
 	return flow_offload_lookup(flow_table, &tuple);
 }
 
+static int nf_flow_offload_check_mtu(struct nf_flowtable_ctx *ctx,
+				     struct flow_offload *flow,
+				     enum flow_offload_tuple_dir dir,
+				     struct sk_buff *skb)
+{
+	unsigned int mtu;
+
+	mtu = flow->tuplehash[dir].tuple.mtu + ctx->offset;
+	switch (flow->tuplehash[!dir].tuple.tun.encap_proto) {
+	case AF_INET:
+		mtu -= sizeof(struct iphdr);
+		break;
+	case AF_INET6:
+		mtu -= sizeof(struct ipv6hdr);
+		break;
+	default:
+		break;
+	}
+
+	if (unlikely(nf_flow_exceeds_mtu(skb, mtu)))
+		return -EINVAL;
+
+	return 0;
+}
+
 static int nf_flow_offload_forward(struct nf_flowtable_ctx *ctx,
 				   struct nf_flowtable *flow_table,
 				   struct flow_offload_tuple_rhash *tuplehash,
@@ -479,17 +504,13 @@ static int nf_flow_offload_forward(struct nf_flowtable_ctx *ctx,
 {
 	enum flow_offload_tuple_dir dir;
 	struct flow_offload *flow;
-	unsigned int thoff, mtu;
+	unsigned int thoff;
 	struct iphdr *iph;
 
 	dir = tuplehash->tuple.dir;
 	flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
 
-	mtu = flow->tuplehash[dir].tuple.mtu + ctx->offset;
-	if (flow->tuplehash[!dir].tuple.tun_num)
-		mtu -= sizeof(*iph);
-
-	if (unlikely(nf_flow_exceeds_mtu(skb, mtu)))
+	if (nf_flow_offload_check_mtu(ctx, flow, dir, skb))
 		return 0;
 
 	iph = (struct iphdr *)(skb_network_header(skb) + ctx->offset);
@@ -1108,17 +1129,13 @@ static int nf_flow_offload_ipv6_forward(struct nf_flowtable_ctx *ctx,
 {
 	enum flow_offload_tuple_dir dir;
 	struct flow_offload *flow;
-	unsigned int thoff, mtu;
 	struct ipv6hdr *ip6h;
+	unsigned int thoff;
 
 	dir = tuplehash->tuple.dir;
 	flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
 
-	mtu = flow->tuplehash[dir].tuple.mtu + ctx->offset;
-	if (flow->tuplehash[!dir].tuple.tun_num)
-		mtu -= sizeof(*ip6h);
-
-	if (unlikely(nf_flow_exceeds_mtu(skb, mtu)))
+	if (nf_flow_offload_check_mtu(ctx, flow, dir, skb))
 		return 0;
 
 	ip6h = (struct ipv6hdr *)(skb_network_header(skb) + ctx->offset);

-- 
2.56.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH nf-next 3/8] net: ip6_tunnel: add IPv4 over IPv6 flowtable tunnel offload
  2026-10-29 13:35 [PATCH nf-next 0/8] Add IPv4 over IPv6 and SIT flowtable SW acceleration Lorenzo Bianconi
  2026-10-29 13:35 ` [PATCH nf-next 1/8] net: netfilter: nf_flow_table: recognize IPv4/IPv6 in tunnel proto matching Lorenzo Bianconi
  2026-10-29 13:35 ` [PATCH nf-next 2/8] net: netfilter: nf_flow_table: refactor MTU check for tunnel offload Lorenzo Bianconi
@ 2026-10-29 13:35 ` Lorenzo Bianconi
  2026-10-29 13:35 ` [PATCH nf-next 4/8] net: netfilter: nf_flow_table: use tunnel encap proto for route lookup Lorenzo Bianconi
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Lorenzo Bianconi @ 2026-10-29 13:35 UTC (permalink / raw)
  To: Pablo Neira Ayuso, Florian Westphal, Phil Sutter, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	David Ahern, Ido Schimmel, Shuah Khan
  Cc: netfilter-devel, coreteam, netdev, linux-kselftest,
	Lorenzo Bianconi

Allow ip6_tnl_fill_forward_path() to set the inner protocol for IPv4
packets (IPPROTO_IPIP) in addition to IPv6 (IPPROTO_IPV6), so that the
flowtable can offload IPv4-in-IPv6 tunnels.

Return -EOPNOTSUPP for any other ethertype.

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
---
 net/ipv6/ip6_tunnel.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 64a184bca467..9ae14977c900 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1844,8 +1844,16 @@ static int ip6_tnl_fill_forward_path(struct net_device_path_ctx *ctx,
 	struct flowi6 fl6;
 	int err;
 
-	if (ctx->ether_type != cpu_to_be16(ETH_P_IPV6))
+	switch (ctx->ether_type) {
+	case cpu_to_be16(ETH_P_IP):
+		path->tun.inner_proto = IPPROTO_IPIP;
+		break;
+	case cpu_to_be16(ETH_P_IPV6):
+		path->tun.inner_proto = IPPROTO_IPV6;
+		break;
+	default:
 		return -EOPNOTSUPP;
+	}
 
 	if (t->parms.flags & (IP6_TNL_F_USE_ORIG_TCLASS |
 			      IP6_TNL_F_USE_ORIG_FLOWLABEL |
@@ -1867,7 +1875,6 @@ static int ip6_tnl_fill_forward_path(struct net_device_path_ctx *ctx,
 		path->type = DEV_PATH_TUN;
 		path->tun.src_v6 = fl6.saddr;
 		path->tun.dst_v6 = fl6.daddr;
-		path->tun.inner_proto = IPPROTO_IPV6;
 		path->tun.encap_proto = AF_INET6;
 		path->tun.dst = dst;
 		path->dev = ctx->dev;

-- 
2.56.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH nf-next 4/8] net: netfilter: nf_flow_table: use tunnel encap proto for route lookup
  2026-10-29 13:35 [PATCH nf-next 0/8] Add IPv4 over IPv6 and SIT flowtable SW acceleration Lorenzo Bianconi
                   ` (2 preceding siblings ...)
  2026-10-29 13:35 ` [PATCH nf-next 3/8] net: ip6_tunnel: add IPv4 over IPv6 flowtable " Lorenzo Bianconi
@ 2026-10-29 13:35 ` Lorenzo Bianconi
  2026-10-29 13:35 ` [PATCH nf-next 5/8] net: netfilter: add IPv4 over IPv6 tunnel flowtable acceleration Lorenzo Bianconi
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Lorenzo Bianconi @ 2026-10-29 13:35 UTC (permalink / raw)
  To: Pablo Neira Ayuso, Florian Westphal, Phil Sutter, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	David Ahern, Ido Schimmel, Shuah Khan
  Cc: netfilter-devel, coreteam, netdev, linux-kselftest,
	Lorenzo Bianconi

For IP tunnels, resolve the MTU and the dst cookie against the tunnel's
inner IP protocol (tun.encap_proto) instead of the flow's l3proto, so
the correct header size and route cookie are used when the flow is
carried over a tunnel.
This is a preliminary patch to support IPv4 over IPv6 and SIT tunnel
flowtable offload.

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
---
 net/netfilter/nf_flow_table_core.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
index 0d72dc8ae47a..aa8e3f42b23f 100644
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -76,9 +76,10 @@ struct flow_offload *flow_offload_alloc(struct nf_conn *ct)
 }
 EXPORT_SYMBOL_GPL(flow_offload_alloc);
 
-static u32 flow_offload_dst_cookie(struct flow_offload_tuple *flow_tuple)
+static u32 flow_offload_dst_cookie(struct flow_offload_tuple *flow_tuple,
+				   u8 l3_proto)
 {
-	if (flow_tuple->l3proto == NFPROTO_IPV6)
+	if (l3_proto == NFPROTO_IPV6)
 		return rt6_get_cookie(dst_rt6_info(flow_tuple->dst_cache));
 
 	return 0;
@@ -100,9 +101,15 @@ static int flow_offload_fill_route(struct flow_offload *flow,
 {
 	struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple;
 	struct dst_entry *dst = nft_route_dst_fetch(route, dir);
+	u8 l3_proto = flow_tuple->l3proto;
 	int i, j = 0;
 
-	switch (flow_tuple->l3proto) {
+	if (route->tuple[!dir].in.tun.encap_proto) {
+		/* For IP tunnels we need to consider tunnel IP protocol. */
+		l3_proto = route->tuple[!dir].in.tun.encap_proto;
+	}
+
+	switch (l3_proto) {
 	case NFPROTO_IPV4:
 		flow_tuple->mtu = ip_dst_mtu_maybe_forward(dst, true);
 		break;
@@ -130,7 +137,7 @@ static int flow_offload_fill_route(struct flow_offload *flow,
 		if (route->tuple[!dir].in.num_tuns) {
 			flow_tuple->dst_cache = dst;
 			flow_tuple->dst_cookie =
-				flow_offload_dst_cookie(flow_tuple);
+				flow_offload_dst_cookie(flow_tuple, l3_proto);
 		} else {
 			dst_release(dst);
 		}
@@ -144,7 +151,8 @@ static int flow_offload_fill_route(struct flow_offload *flow,
 	case FLOW_OFFLOAD_XMIT_NEIGH:
 		flow_tuple->ifidx = route->tuple[dir].out.ifindex;
 		flow_tuple->dst_cache = dst;
-		flow_tuple->dst_cookie = flow_offload_dst_cookie(flow_tuple);
+		flow_tuple->dst_cookie = flow_offload_dst_cookie(flow_tuple,
+								 l3_proto);
 		break;
 	default:
 		WARN_ON_ONCE(1);

-- 
2.56.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH nf-next 5/8] net: netfilter: add IPv4 over IPv6 tunnel flowtable acceleration
  2026-10-29 13:35 [PATCH nf-next 0/8] Add IPv4 over IPv6 and SIT flowtable SW acceleration Lorenzo Bianconi
                   ` (3 preceding siblings ...)
  2026-10-29 13:35 ` [PATCH nf-next 4/8] net: netfilter: nf_flow_table: use tunnel encap proto for route lookup Lorenzo Bianconi
@ 2026-10-29 13:35 ` Lorenzo Bianconi
  2026-10-30  4:33   ` kernel test robot
  2026-10-29 13:35 ` [PATCH nf-next 6/8] selftests: netfilter: nft_flowtable.sh: add IPv4 over IPv6 flowtable selftest Lorenzo Bianconi
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 11+ messages in thread
From: Lorenzo Bianconi @ 2026-10-29 13:35 UTC (permalink / raw)
  To: Pablo Neira Ayuso, Florian Westphal, Phil Sutter, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	David Ahern, Ido Schimmel, Shuah Khan
  Cc: netfilter-devel, coreteam, netdev, linux-kselftest,
	Lorenzo Bianconi

Introduce sw flowtable acceleration for the TX/RX paths of
IPv4 over IPv6 tunnels, relying on the netfilter flowtable
infrastructure.
The feature can be tested with a forwarding scenario between two
NICs (eth0 and eth1), where an IPv4 over IPv6 tunnel is used to
reach a remote site via eth1 as the underlay device:

    ETH0 -- TUN0 <==> ETH1 -- [IP network] -- TUN1 (2001:db8:2::2)

[IP configuration]

6: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 00:00:22:33:11:55 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.2/24 scope global eth0
       valid_lft forever preferred_lft forever
7: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 00:11:22:33:11:55 brd ff:ff:ff:ff:ff:ff
    inet6 2001:db8:2::1/64 scope global nodad
       valid_lft forever preferred_lft forever
8: tun0@NONE: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN group default qlen 1000
    link/tunnel6 2001:db8:2::1 peer 2001:db8:2::2 permaddr ce9c:2940:7dcc::
    inet 192.168.100.1/24 scope global tun0
       valid_lft forever preferred_lft forever

$ ip route show
default via 192.168.100.2 dev tun0
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.2
192.168.100.0/24 dev tun0 proto kernel scope link src 192.168.100.1

$ ip -6 route show
2001:db8:2::/64 dev eth1 proto kernel metric 256 pref medium

$ nft list ruleset
table inet filter {
    flowtable ft {
        hook ingress priority filter
        devices = { eth0, eth1 }
    }

    chain forward {
        type filter hook forward priority filter; policy accept;
        meta l4proto { tcp, udp } flow add @ft
    }
}

When reproducing this scenario using veth interfaces, the following
results were observed:

- TCP stream received from IPv4 over IPv6 tunnel:
  - net-next (baseline):                ~126 Gbps
  - net-next + IP6IP flowtable support: ~138 Gbps

- TCP stream transmitted to IPv4 over IPv6 tunnel:
  - net-next (baseline):                ~127 Gbps
  - net-next + IP6IP flowtable support: ~140 Gbps

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
---
 net/netfilter/nf_flow_table_ip.c | 66 ++++++++++++++++++++++++++++++++--------
 1 file changed, 54 insertions(+), 12 deletions(-)

diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index 902b9b595677..0ffa6470c46d 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -856,7 +856,8 @@ static unsigned int nf_flow_queue_xmit(struct net *net, struct sk_buff *skb,
 	return NF_STOLEN;
 }
 
-static int nf_flow_queue_xmit4(struct sk_buff *skb,
+static int nf_flow_queue_xmit4(struct nf_flowtable_ctx *ctx,
+			       struct sk_buff *skb,
 			       struct flow_offload_tuple_rhash *tuplehash,
 			       const struct nf_hook_state *state)
 {
@@ -886,14 +887,29 @@ static int nf_flow_queue_xmit4(struct sk_buff *skb,
 		return NF_DROP;
 
 	switch (tuplehash->tuple.xmit_type) {
-	case FLOW_OFFLOAD_XMIT_NEIGH:
-		rt = dst_rtable(tuplehash->tuple.dst_cache);
+	case FLOW_OFFLOAD_XMIT_NEIGH: {
+		struct dst_entry *dst;
+
 		xmit.outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.ifidx);
 		if (!xmit.outdev) {
 			flow_offload_teardown(flow);
 			return NF_DROP;
 		}
-		neigh = ip_neigh_gw4(rt->dst.dev, rt_nexthop(rt, ip_addr->ip));
+		if (other_tuple->tun.encap_proto ?
+		    other_tuple->tun.encap_proto == AF_INET6 :
+		    ctx->tun.inner_proto == IPPROTO_IPV6) {
+			struct rt6_info *rt6;
+
+			rt6 = dst_rt6_info(tuplehash->tuple.dst_cache);
+			neigh = ip_neigh_gw6(rt6->dst.dev,
+					     rt6_nexthop(rt6, &ip_addr->in6));
+			dst = &rt6->dst;
+		} else {
+			rt = dst_rtable(tuplehash->tuple.dst_cache);
+			neigh = ip_neigh_gw4(rt->dst.dev,
+					     rt_nexthop(rt, ip_addr->ip));
+			dst = &rt->dst;
+		}
 		if (IS_ERR(neigh)) {
 			flow_offload_teardown(flow);
 			return NF_DROP;
@@ -902,6 +918,7 @@ static int nf_flow_queue_xmit4(struct sk_buff *skb,
 		skb_dst_drop(skb);
 		skb_dst_set_noref(skb, &rt->dst);
 		break;
+	}
 	case FLOW_OFFLOAD_XMIT_DIRECT:
 		xmit.outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.out.ifidx);
 		if (!xmit.outdev) {
@@ -948,7 +965,7 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
 	else if (ret == 0)
 		return NF_ACCEPT;
 
-	return nf_flow_queue_xmit4(skb, tuplehash, state);
+	return nf_flow_queue_xmit4(&ctx, skb, tuplehash, state);
 }
 EXPORT_SYMBOL_GPL(nf_flow_offload_ip_hook);
 
@@ -1175,13 +1192,18 @@ nf_flow_offload_ipv6_lookup(struct nf_flowtable_ctx *ctx,
 {
 	struct flow_offload_tuple tuple = {};
 
-	if (nf_flow_tuple_ipv6(ctx, skb, &tuple) < 0)
+	if (ctx->tun.inner_proto == IPPROTO_IPIP) {
+		if (nf_flow_tuple_ip(ctx, skb, &tuple) < 0)
+			return NULL;
+	} else if (nf_flow_tuple_ipv6(ctx, skb, &tuple) < 0) {
 		return NULL;
+	}
 
 	return flow_offload_lookup(flow_table, &tuple);
 }
 
-static int nf_flow_queue_xmit6(struct sk_buff *skb,
+static int nf_flow_queue_xmit6(struct nf_flowtable_ctx *ctx,
+			       struct sk_buff *skb,
 			       struct flow_offload_tuple_rhash *tuplehash,
 			       const struct nf_hook_state *state)
 {
@@ -1211,14 +1233,29 @@ static int nf_flow_queue_xmit6(struct sk_buff *skb,
 		return NF_DROP;
 
 	switch (tuplehash->tuple.xmit_type) {
-	case FLOW_OFFLOAD_XMIT_NEIGH:
-		rt = dst_rt6_info(tuplehash->tuple.dst_cache);
+	case FLOW_OFFLOAD_XMIT_NEIGH: {
+		struct dst_entry *dst;
+
 		xmit.outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.ifidx);
 		if (!xmit.outdev) {
 			flow_offload_teardown(flow);
 			return NF_DROP;
 		}
-		neigh = ip_neigh_gw6(rt->dst.dev, rt6_nexthop(rt, &ip_addr->in6));
+		if (other_tuple->tun.encap_proto ?
+		    other_tuple->tun.encap_proto == AF_INET :
+		    ctx->tun.inner_proto == IPPROTO_IPIP) {
+			struct rtable *rt4;
+
+			rt4 = dst_rtable(tuplehash->tuple.dst_cache);
+			neigh = ip_neigh_gw4(rt4->dst.dev,
+					     rt_nexthop(rt4, ip_addr->ip));
+			dst = &rt4->dst;
+		} else {
+			rt = dst_rt6_info(tuplehash->tuple.dst_cache);
+			neigh = ip_neigh_gw6(rt->dst.dev,
+					     rt6_nexthop(rt, &ip_addr->in6));
+			dst = &rt->dst;
+		}
 		if (IS_ERR(neigh)) {
 			flow_offload_teardown(flow);
 			return NF_DROP;
@@ -1227,6 +1264,7 @@ static int nf_flow_queue_xmit6(struct sk_buff *skb,
 		skb_dst_drop(skb);
 		skb_dst_set_noref(skb, &rt->dst);
 		break;
+	}
 	case FLOW_OFFLOAD_XMIT_DIRECT:
 		xmit.outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.out.ifidx);
 		if (!xmit.outdev) {
@@ -1267,12 +1305,16 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
 	if (!tuplehash)
 		return NF_ACCEPT;
 
-	ret = nf_flow_offload_ipv6_forward(&ctx, flow_table, tuplehash, skb);
+	if (ctx.tun.inner_proto == IPPROTO_IPIP)
+		ret = nf_flow_offload_forward(&ctx, flow_table, tuplehash, skb);
+	else
+		ret = nf_flow_offload_ipv6_forward(&ctx, flow_table, tuplehash,
+						   skb);
 	if (ret < 0)
 		return NF_DROP;
 	else if (ret == 0)
 		return NF_ACCEPT;
 
-	return nf_flow_queue_xmit6(skb, tuplehash, state);
+	return nf_flow_queue_xmit6(&ctx, skb, tuplehash, state);
 }
 EXPORT_SYMBOL_GPL(nf_flow_offload_ipv6_hook);

-- 
2.56.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH nf-next 6/8] selftests: netfilter: nft_flowtable.sh: add IPv4 over IPv6 flowtable selftest
  2026-10-29 13:35 [PATCH nf-next 0/8] Add IPv4 over IPv6 and SIT flowtable SW acceleration Lorenzo Bianconi
                   ` (4 preceding siblings ...)
  2026-10-29 13:35 ` [PATCH nf-next 5/8] net: netfilter: add IPv4 over IPv6 tunnel flowtable acceleration Lorenzo Bianconi
@ 2026-10-29 13:35 ` Lorenzo Bianconi
  2026-10-29 13:35 ` [PATCH nf-next 7/8] net: netfilter: add SIT tunnel flowtable acceleration Lorenzo Bianconi
  2026-10-29 13:35 ` [PATCH nf-next 8/8] selftests: netfilter: nft_flowtable.sh: add SIT flowtable selftest Lorenzo Bianconi
  7 siblings, 0 replies; 11+ messages in thread
From: Lorenzo Bianconi @ 2026-10-29 13:35 UTC (permalink / raw)
  To: Pablo Neira Ayuso, Florian Westphal, Phil Sutter, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	David Ahern, Ido Schimmel, Shuah Khan
  Cc: netfilter-devel, coreteam, netdev, linux-kselftest,
	Lorenzo Bianconi

Similar to IPIP and IP6IP6, introduce specific selftest for IPv4 over IPv6
flowtable sw acceleration in nft_flowtable.sh

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
---
 .../selftests/net/netfilter/nft_flowtable.sh       | 33 +++++++++++++++++++---
 1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/net/netfilter/nft_flowtable.sh b/tools/testing/selftests/net/netfilter/nft_flowtable.sh
index 449c518bd947..dcbae9a3d92b 100755
--- a/tools/testing/selftests/net/netfilter/nft_flowtable.sh
+++ b/tools/testing/selftests/net/netfilter/nft_flowtable.sh
@@ -579,9 +579,8 @@ if ! test_tcp_forwarding_nat "$ns1" "$ns2" 1 ""; then
 	ip netns exec "$nsr1" nft list ruleset
 fi
 
-# IPIP tunnel test:
-# Add IPIP tunnel interfaces and check flowtable acceleration.
-test_ipip() {
+# IP tunnel tests:
+test_ip_tnls() {
 if ! ip -net "$nsr1" link add name tun0 type ipip \
      local 192.168.10.1 remote 192.168.10.2 >/dev/null;then
 	echo "SKIP: could not add ipip tunnel"
@@ -594,7 +593,9 @@ ip netns exec "$nsr1" sysctl net.ipv4.conf.tun0.forwarding=1 > /dev/null
 
 ip -net "$nsr1" link add name tun6 type ip6tnl local fee1:2::1 remote fee1:2::2 encaplimit none
 ip -net "$nsr1" link set tun6 up
+ip -net "$nsr1" addr add 192.168.210.1/24 dev tun6
 ip -net "$nsr1" addr add fee1:3::1/64 dev tun6 nodad
+ip netns exec "$nsr1" sysctl net.ipv4.conf.tun6.forwarding=1 > /dev/null
 
 ip -net "$nsr2" link add name tun0 type ipip local 192.168.10.2 remote 192.168.10.1
 ip -net "$nsr2" link set tun0 up
@@ -603,7 +604,9 @@ ip netns exec "$nsr2" sysctl net.ipv4.conf.tun0.forwarding=1 > /dev/null
 
 ip -net "$nsr2" link add name tun6 type ip6tnl local fee1:2::2 remote fee1:2::1 encaplimit none || ret=1
 ip -net "$nsr2" link set tun6 up
+ip -net "$nsr2" addr add 192.168.210.2/24 dev tun6
 ip -net "$nsr2" addr add fee1:3::2/64 dev tun6 nodad
+ip netns exec "$nsr2" sysctl net.ipv4.conf.tun6.forwarding=1 > /dev/null
 
 ip -net "$nsr1" route change default via 192.168.100.2
 ip -net "$nsr2" route change default via 192.168.100.1
@@ -640,6 +643,15 @@ else
 	ret=1
 fi
 
+ip -net "$nsr1" route change default via 192.168.210.2
+ip -net "$nsr2" route change default via 192.168.210.1
+
+if ! test_tcp_forwarding_nat "$ns1" "$ns2" 1 "IP4IP6 tunnel"; then
+	echo "FAIL: flow offload for ns1/ns2 with IP4IP6 tunnel" 1>&2
+	ip netns exec "$nsr1" nft list ruleset
+	ret=1
+fi
+
 # Create vlan tagged devices for IPIP traffic.
 ip -net "$nsr1" link add link veth1 name veth1.10 type vlan id 10
 ip -net "$nsr1" link set veth1.10 up
@@ -661,7 +673,9 @@ ip netns exec "$nsr1" nft -a insert rule inet filter forward 'meta oif tun0.10 a
 
 ip -net "$nsr1" link add name tun6.10 type ip6tnl local fee1:4::1 remote fee1:4::2 encaplimit none
 ip -net "$nsr1" link set tun6.10 up
+ip -net "$nsr1" addr add 192.168.220.1/24 dev tun6.10
 ip -net "$nsr1" addr add fee1:5::1/64 dev tun6.10 nodad
+ip netns exec "$nsr1" sysctl net.ipv4.conf.tun6/10.forwarding=1 > /dev/null
 ip -6 -net "$nsr1" route delete default
 ip -6 -net "$nsr1" route add default via fee1:5::2
 ip netns exec "$nsr1" nft -a insert rule inet filter forward \
@@ -682,7 +696,9 @@ ip netns exec "$nsr2" sysctl net.ipv4.conf.tun0/10.forwarding=1 > /dev/null
 
 ip -net "$nsr2" link add name tun6.10 type ip6tnl local fee1:4::2 remote fee1:4::1 encaplimit none || ret=1
 ip -net "$nsr2" link set tun6.10 up
+ip -net "$nsr2" addr add 192.168.220.2/24 dev tun6.10
 ip -net "$nsr2" addr add fee1:5::2/64 dev tun6.10 nodad
+ip netns exec "$nsr2" sysctl net.ipv4.conf.tun6/10.forwarding=1 > /dev/null
 ip -6 -net "$nsr2" route delete default
 ip -6 -net "$nsr2" route add default via fee1:5::1
 
@@ -700,6 +716,15 @@ else
 	ret=1
 fi
 
+ip -net "$nsr1" route change default via 192.168.220.2
+ip -net "$nsr2" route change default via 192.168.220.1
+
+if ! test_tcp_forwarding_nat "$ns1" "$ns2" 1 "IP4IP6 tunnel over vlan"; then
+	echo "FAIL: flow offload for ns1/ns2 with IP4IP6 tunnel over vlan" 1>&2
+	ip netns exec "$nsr1" nft list ruleset
+	ret=1
+fi
+
 # Restore the previous configuration
 ip -net "$nsr1" route change default via 192.168.10.2
 ip -net "$nsr2" route change default via 192.168.10.1
@@ -847,7 +872,7 @@ ip -net "$nsr1" addr add dead:1::1/64 dev veth0 nodad
 ip -net "$nsr1" link set up dev veth0
 }
 
-test_ipip
+test_ip_tnls
 
 test_bridge
 

-- 
2.56.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH nf-next 7/8] net: netfilter: add SIT tunnel flowtable acceleration
  2026-10-29 13:35 [PATCH nf-next 0/8] Add IPv4 over IPv6 and SIT flowtable SW acceleration Lorenzo Bianconi
                   ` (5 preceding siblings ...)
  2026-10-29 13:35 ` [PATCH nf-next 6/8] selftests: netfilter: nft_flowtable.sh: add IPv4 over IPv6 flowtable selftest Lorenzo Bianconi
@ 2026-10-29 13:35 ` Lorenzo Bianconi
  2026-10-29 13:35 ` [PATCH nf-next 8/8] selftests: netfilter: nft_flowtable.sh: add SIT flowtable selftest Lorenzo Bianconi
  7 siblings, 0 replies; 11+ messages in thread
From: Lorenzo Bianconi @ 2026-10-29 13:35 UTC (permalink / raw)
  To: Pablo Neira Ayuso, Florian Westphal, Phil Sutter, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	David Ahern, Ido Schimmel, Shuah Khan
  Cc: netfilter-devel, coreteam, netdev, linux-kselftest,
	Lorenzo Bianconi

Introduce sw flowtable acceleration for the TX/RX paths of
SIT tunnels, relying on the netfilter flowtable infrastructure.
The feature can be tested with a forwarding scenario between two
NICs (eth0 and eth1), where a SIT tunnel is used to reach a remote
site via eth1 as the underlay device:

    ETH0 -- TUN0 <==> ETH1 -- [IP network] -- TUN1 (192.168.2.2)

[IP configuration]

6: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 00:00:22:33:11:55 brd ff:ff:ff:ff:ff:ff
    inet6 2001:db8:1::2/64 scope global nodad
       valid_lft forever preferred_lft forever
7: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 00:11:22:33:11:55 brd ff:ff:ff:ff:ff:ff
    inet 192.168.2.1/24 scope global eth1
       valid_lft forever preferred_lft forever
8: tun0@NONE: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN group default qlen 1000
    link/sit 192.168.2.1 peer 192.168.2.2
    inet6 2001:db8:200::1/64 scope global nodad
       valid_lft forever preferred_lft forever

$ ip route show
192.168.2.0/24 dev eth1 proto kernel scope link src 192.168.2.1

$ ip -6 route show
2001:db8:1::/64 dev eth0 proto kernel metric 256 pref medium
2001:db8:200::/64 dev tun0 proto kernel metric 256 pref medium
default via 2001:db8:200::2 dev tun0 metric 1024 pref medium

$ nft list ruleset
table inet filter {
    flowtable ft {
        hook ingress priority filter
        devices = { eth0, eth1 }
    }

    chain forward {
        type filter hook forward priority filter; policy accept;
        meta l4proto { tcp, udp } flow add @ft
    }
}

When reproducing this scenario using veth interfaces, the following
results were observed:

- TCP stream received from SIT tunnel:
  - net-next (baseline):                ~118 Gbps
  - net-next + SIT flowtable support: ~148 Gbps

- TCP stream transmitted to SIT tunnel:
  - net-next (baseline):                ~131 Gbps
  - net-next + SIT flowtable support: ~147 Gbps

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
---
 net/ipv6/sit.c                   | 59 ++++++++++++++++++++++++++++++++++++++++
 net/netfilter/nf_flow_table_ip.c | 22 +++++++++++++--
 2 files changed, 79 insertions(+), 2 deletions(-)

diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index a7ec800216ad..ed66358ab644 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -29,6 +29,7 @@
 #include <linux/icmp.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
+#include <linux/inetdevice.h>
 #include <linux/init.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/if_ether.h>
@@ -1483,6 +1484,63 @@ ipip6_tunnel_ctl(struct net_device *dev, struct ip_tunnel_parm_kern *p,
 	}
 }
 
+static int ipip6_tunnel_fill_forward_path(struct net_device_path_ctx *ctx,
+					  struct net_device_path *path)
+{
+	struct ip_tunnel *tunnel = netdev_priv(ctx->dev);
+	const struct iphdr *tiph = &tunnel->parms.iph;
+	struct rtable *rt;
+
+	/* NBMA tunnels (ISATAP, 6to4, 6rd) resolve the outer destination
+	 * per-packet from the inner IPv6 address; not offloadable.
+	 */
+	if (ctx->dev->priv_flags & IFF_ISATAP)
+		return -EOPNOTSUPP;
+
+	if (!tiph->daddr)
+		return -EOPNOTSUPP;
+
+	/* FOU/GUE encapsulation is handled in the slow path by
+	 * ip_tunnel_encap(); the fast path only pushes a plain
+	 * IPv4 header and would skip the UDP encapsulation.
+	 */
+	if (tunnel->encap.type != TUNNEL_ENCAP_NONE)
+		return -EOPNOTSUPP;
+
+	rt = ip_route_output(dev_net(ctx->dev), tiph->daddr, tiph->saddr,
+			     inet_dsfield_to_dscp(tiph->tos),
+			     tunnel->parms.link, RT_SCOPE_UNIVERSE);
+	if (IS_ERR(rt))
+		return PTR_ERR(rt);
+
+	path->type = DEV_PATH_TUN;
+	if (tiph->saddr)
+		path->tun.src_v4.s_addr = tiph->saddr;
+	else
+		path->tun.src_v4.s_addr = inet_select_addr(rt->dst.dev,
+							   tiph->daddr,
+							   RT_SCOPE_UNIVERSE);
+	path->tun.dst_v4.s_addr = tiph->daddr;
+	path->tun.encap_proto = AF_INET;
+	path->dev = ctx->dev;
+	path->tun.dst = &rt->dst;
+
+	switch (ctx->ether_type) {
+	case cpu_to_be16(ETH_P_IP):
+		path->tun.inner_proto = IPPROTO_IPIP;
+		break;
+	case cpu_to_be16(ETH_P_IPV6):
+		path->tun.inner_proto = IPPROTO_IPV6;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	ctx->dev = rt->dst.dev;
+
+	return 0;
+}
+
 static int
 ipip6_tunnel_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
 			    void __user *data, int cmd)
@@ -1533,6 +1591,7 @@ static const struct net_device_ops ipip6_netdev_ops = {
 	.ndo_siocdevprivate = ipip6_tunnel_siocdevprivate,
 	.ndo_get_iflink = ipip6_get_iflink,
 	.ndo_tunnel_ctl = ipip6_tunnel_ctl,
+	.ndo_fill_forward_path = ipip6_tunnel_fill_forward_path,
 };
 
 static void ipip6_dev_free(struct net_device *dev)
diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index 0ffa6470c46d..876e3e87ef87 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -158,6 +158,16 @@ struct nf_flowtable_ctx {
 	} tun;
 };
 
+static int nf_flow_tuple_ipv6(struct nf_flowtable_ctx *ctx,
+			      struct sk_buff *skb,
+			      struct flow_offload_tuple *tuple);
+
+static int
+nf_flow_offload_ipv6_forward(struct nf_flowtable_ctx *ctx,
+			     struct nf_flowtable *flow_table,
+			     struct flow_offload_tuple_rhash *tuplehash,
+			     struct sk_buff *skb);
+
 static void nf_flow_tuple_encap(struct nf_flowtable_ctx *ctx,
 				struct sk_buff *skb,
 				struct flow_offload_tuple *tuple)
@@ -466,8 +476,12 @@ nf_flow_offload_lookup(struct nf_flowtable_ctx *ctx,
 {
 	struct flow_offload_tuple tuple = {};
 
-	if (nf_flow_tuple_ip(ctx, skb, &tuple) < 0)
+	if (ctx->tun.inner_proto == IPPROTO_IPV6) {
+		if (nf_flow_tuple_ipv6(ctx, skb, &tuple) < 0)
+			return NULL;
+	} else if (nf_flow_tuple_ip(ctx, skb, &tuple) < 0) {
 		return NULL;
+	}
 
 	return flow_offload_lookup(flow_table, &tuple);
 }
@@ -959,7 +973,11 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
 	if (!tuplehash)
 		return NF_ACCEPT;
 
-	ret = nf_flow_offload_forward(&ctx, flow_table, tuplehash, skb);
+	if (ctx.tun.inner_proto == IPPROTO_IPV6)
+		ret = nf_flow_offload_ipv6_forward(&ctx, flow_table, tuplehash,
+						   skb);
+	else
+		ret = nf_flow_offload_forward(&ctx, flow_table, tuplehash, skb);
 	if (ret < 0)
 		return NF_DROP;
 	else if (ret == 0)

-- 
2.56.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH nf-next 8/8] selftests: netfilter: nft_flowtable.sh: add SIT flowtable selftest
  2026-10-29 13:35 [PATCH nf-next 0/8] Add IPv4 over IPv6 and SIT flowtable SW acceleration Lorenzo Bianconi
                   ` (6 preceding siblings ...)
  2026-10-29 13:35 ` [PATCH nf-next 7/8] net: netfilter: add SIT tunnel flowtable acceleration Lorenzo Bianconi
@ 2026-10-29 13:35 ` Lorenzo Bianconi
  7 siblings, 0 replies; 11+ messages in thread
From: Lorenzo Bianconi @ 2026-10-29 13:35 UTC (permalink / raw)
  To: Pablo Neira Ayuso, Florian Westphal, Phil Sutter, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	David Ahern, Ido Schimmel, Shuah Khan
  Cc: netfilter-devel, coreteam, netdev, linux-kselftest,
	Lorenzo Bianconi

Similar to IPIP, IP6IP6 and IPv4 over IPv6, introduce specific selftest
for SIT flowtable sw acceleration in nft_flowtable.sh.

Also add tunnel-specific flow-add rules for sit1 and sit1.10 so that
check_counters() properly verifies offload occurred, and restore IPv6
default routes at cleanup to prevent tunnel routes leaking to subsequent
tests (e.g. IPsec).

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
---
 tools/testing/selftests/net/netfilter/config       |  1 +
 .../selftests/net/netfilter/nft_flowtable.sh       | 53 ++++++++++++++++++++++
 2 files changed, 54 insertions(+)

diff --git a/tools/testing/selftests/net/netfilter/config b/tools/testing/selftests/net/netfilter/config
index 629b2b29ed1a..930374aabec1 100644
--- a/tools/testing/selftests/net/netfilter/config
+++ b/tools/testing/selftests/net/netfilter/config
@@ -35,6 +35,7 @@ CONFIG_IP_SCTP=m
 CONFIG_IPV6=y
 CONFIG_IPV6_MULTIPLE_TABLES=y
 CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_SIT=m
 CONFIG_IP_VS=m
 CONFIG_IP_VS_PROTO_TCP=y
 CONFIG_IP_VS_RR=m
diff --git a/tools/testing/selftests/net/netfilter/nft_flowtable.sh b/tools/testing/selftests/net/netfilter/nft_flowtable.sh
index dcbae9a3d92b..3a393c8deab9 100755
--- a/tools/testing/selftests/net/netfilter/nft_flowtable.sh
+++ b/tools/testing/selftests/net/netfilter/nft_flowtable.sh
@@ -597,6 +597,10 @@ ip -net "$nsr1" addr add 192.168.210.1/24 dev tun6
 ip -net "$nsr1" addr add fee1:3::1/64 dev tun6 nodad
 ip netns exec "$nsr1" sysctl net.ipv4.conf.tun6.forwarding=1 > /dev/null
 
+ip -net "$nsr1" link add name sit1 type sit local 192.168.10.1 remote 192.168.10.2 ttl 255
+ip -net "$nsr1" link set sit1 up
+ip -net "$nsr1" addr add fe01:3::1/64 dev sit1 nodad
+
 ip -net "$nsr2" link add name tun0 type ipip local 192.168.10.2 remote 192.168.10.1
 ip -net "$nsr2" link set tun0 up
 ip -net "$nsr2" addr add 192.168.100.2/24 dev tun0
@@ -608,6 +612,10 @@ ip -net "$nsr2" addr add 192.168.210.2/24 dev tun6
 ip -net "$nsr2" addr add fee1:3::2/64 dev tun6 nodad
 ip netns exec "$nsr2" sysctl net.ipv4.conf.tun6.forwarding=1 > /dev/null
 
+ip -net "$nsr2" link add name sit1 type sit local 192.168.10.2 remote 192.168.10.1 ttl 255
+ip -net "$nsr2" link set sit1 up
+ip -net "$nsr2" addr add fe01:3::2/64 dev sit1 nodad
+
 ip -net "$nsr1" route change default via 192.168.100.2
 ip -net "$nsr2" route change default via 192.168.100.1
 
@@ -626,6 +634,9 @@ ip netns exec "$nsr1" nft -a insert rule inet filter forward 'meta oif tun0 acce
 ip netns exec "$nsr1" nft -a insert rule inet filter forward \
 	'meta oif tun6 tcp dport 12345 ct mark set 1 flow add @f1 counter name routed_orig accept'
 ip netns exec "$nsr1" nft -a insert rule inet filter forward 'meta oif tun6 accept'
+ip netns exec "$nsr1" nft -a insert rule inet filter forward \
+	'meta oif sit1 tcp dport 12345 ct mark set 1 flow add @f1 counter name routed_orig accept'
+ip netns exec "$nsr1" nft -a insert rule inet filter forward 'meta oif sit1 accept'
 ip netns exec "$nsr1" nft -a insert rule inet filter forward \
 	'meta oif "veth0" tcp sport 12345 ct mark set 1 flow add @f1 counter name routed_repl accept'
 
@@ -652,6 +663,19 @@ if ! test_tcp_forwarding_nat "$ns1" "$ns2" 1 "IP4IP6 tunnel"; then
 	ret=1
 fi
 
+ip -6 -net "$nsr1" route delete default
+ip -6 -net "$nsr1" route add default via fe01:3::2
+ip -6 -net "$nsr2" route delete default
+ip -6 -net "$nsr2" route add default via fe01:3::1
+
+if test_tcp_forwarding "$ns1" "$ns2" 1 6 "[dead:2::99]" 12345; then
+	check_counters "flow offload for ns1/ns2 SIT tunnel"
+else
+	echo "FAIL: flow offload for ns1/ns2 with SIT tunnel" 1>&2
+	ip netns exec "$nsr1" nft list ruleset
+	ret=1
+fi
+
 # Create vlan tagged devices for IPIP traffic.
 ip -net "$nsr1" link add link veth1 name veth1.10 type vlan id 10
 ip -net "$nsr1" link set veth1.10 up
@@ -682,6 +706,13 @@ ip netns exec "$nsr1" nft -a insert rule inet filter forward \
 	'meta oif tun6.10 tcp dport 12345 ct mark set 1 flow add @f1 counter name routed_orig accept'
 ip netns exec "$nsr1" nft -a insert rule inet filter forward 'meta oif tun6.10 accept'
 
+ip -net "$nsr1" link add name sit1.10 type sit local 192.168.20.1 remote 192.168.20.2 ttl 255
+ip -net "$nsr1" link set sit1.10 up
+ip -net "$nsr1" addr add fe01:5::1/64 dev sit1.10 nodad
+ip netns exec "$nsr1" nft -a insert rule inet filter forward \
+	'meta oif sit1.10 tcp dport 12345 ct mark set 1 flow add @f1 counter name routed_orig accept'
+ip netns exec "$nsr1" nft -a insert rule inet filter forward 'meta oif sit1.10 accept'
+
 ip -net "$nsr2" link add link veth0 name veth0.10 type vlan id 10
 ip -net "$nsr2" link set veth0.10 up
 ip -net "$nsr2" addr add 192.168.20.2/24 dev veth0.10
@@ -699,6 +730,11 @@ ip -net "$nsr2" link set tun6.10 up
 ip -net "$nsr2" addr add 192.168.220.2/24 dev tun6.10
 ip -net "$nsr2" addr add fee1:5::2/64 dev tun6.10 nodad
 ip netns exec "$nsr2" sysctl net.ipv4.conf.tun6/10.forwarding=1 > /dev/null
+
+ip -net "$nsr2" link add name sit1.10 type sit local 192.168.20.2 remote 192.168.20.1 ttl 255
+ip -net "$nsr2" link set sit1.10 up
+ip -net "$nsr2" addr add fe01:5::2/64 dev sit1.10 nodad
+
 ip -6 -net "$nsr2" route delete default
 ip -6 -net "$nsr2" route add default via fee1:5::1
 
@@ -725,11 +761,28 @@ if ! test_tcp_forwarding_nat "$ns1" "$ns2" 1 "IP4IP6 tunnel over vlan"; then
 	ret=1
 fi
 
+ip -6 -net "$nsr1" route delete default
+ip -6 -net "$nsr1" route add default via fe01:5::2
+ip -6 -net "$nsr2" route delete default
+ip -6 -net "$nsr2" route add default via fe01:5::1
+
+if test_tcp_forwarding "$ns1" "$ns2" 1 6 "[dead:2::99]" 12345; then
+	check_counters "flow offload for ns1/ns2 SIT tunnel over vlan"
+else
+	echo "FAIL: flow offload for ns1/ns2 with SIT tunnel over vlan" 1>&2
+	ip netns exec "$nsr1" nft list ruleset
+	ret=1
+fi
+
 # Restore the previous configuration
 ip -net "$nsr1" route change default via 192.168.10.2
 ip -net "$nsr2" route change default via 192.168.10.1
 ip -net "$ns2" route del default via 10.0.2.1
 ip -6 -net "$ns2" route del default via dead:2::1
+ip -6 -net "$nsr1" route delete default
+ip -6 -net "$nsr1" route add default via fee1:2::2
+ip -6 -net "$nsr2" route delete default
+ip -6 -net "$nsr2" route add default via fee1:2::1
 }
 
 # Another test:

-- 
2.56.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH nf-next 5/8] net: netfilter: add IPv4 over IPv6 tunnel flowtable acceleration
  2026-10-29 13:35 ` [PATCH nf-next 5/8] net: netfilter: add IPv4 over IPv6 tunnel flowtable acceleration Lorenzo Bianconi
@ 2026-10-30  4:33   ` kernel test robot
  2026-10-30  8:20     ` Lorenzo Bianconi
  0 siblings, 1 reply; 11+ messages in thread
From: kernel test robot @ 2026-10-30  4:33 UTC (permalink / raw)
  To: Lorenzo Bianconi, Pablo Neira Ayuso, Florian Westphal,
	Phil Sutter, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, David Ahern, Ido Schimmel, Shuah Khan
  Cc: oe-kbuild-all, netdev, netfilter-devel, coreteam, linux-kselftest,
	Lorenzo Bianconi

Hi Lorenzo,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 734bef548a96e8774d6eef5dfa2026c6edc4e80b]

url:    https://github.com/intel-lab-lkp/linux/commits/Lorenzo-Bianconi/net-netfilter-nf_flow_table-recognize-IPv4-IPv6-in-tunnel-proto-matching/20261029-143512
base:   734bef548a96e8774d6eef5dfa2026c6edc4e80b
patch link:    https://lore.kernel.org/r/20261029-flowtable-sw-accel-ip6ip-sit-v1-5-6a17c54f9fb7%40oss.qualcomm.com
patch subject: [PATCH nf-next 5/8] net: netfilter: add IPv4 over IPv6 tunnel flowtable acceleration
config: m68k-defconfig (https://download.01.org/0day-ci/archive/20261030/202610301255.BRNUBmqH-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 16.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261030/202610301255.BRNUBmqH-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202610301255.BRNUBmqH-lkp@intel.com/

All warnings (new ones prefixed by >>):

   net/netfilter/nf_flow_table_ip.c: In function 'nf_flow_queue_xmit4':
>> net/netfilter/nf_flow_table_ip.c:891:35: warning: variable 'dst' set but not used [-Wunused-but-set-variable=]
     891 |                 struct dst_entry *dst;
         |                                   ^~~
   net/netfilter/nf_flow_table_ip.c: In function 'nf_flow_queue_xmit6':
   net/netfilter/nf_flow_table_ip.c:1237:35: warning: variable 'dst' set but not used [-Wunused-but-set-variable=]
    1237 |                 struct dst_entry *dst;
         |                                   ^~~


vim +/dst +891 net/netfilter/nf_flow_table_ip.c

   858	
   859	static int nf_flow_queue_xmit4(struct nf_flowtable_ctx *ctx,
   860				       struct sk_buff *skb,
   861				       struct flow_offload_tuple_rhash *tuplehash,
   862				       const struct nf_hook_state *state)
   863	{
   864		struct flow_offload_tuple *other_tuple;
   865		enum flow_offload_tuple_dir dir;
   866		struct nf_flow_xmit xmit = {};
   867		union nf_inet_addr *ip_addr;
   868		struct flow_offload *flow;
   869		struct neighbour *neigh;
   870		struct rtable *rt;
   871	
   872		if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) {
   873			rt = dst_rtable(tuplehash->tuple.dst_cache);
   874			memset(skb->cb, 0, sizeof(struct inet_skb_parm));
   875			IPCB(skb)->iif = skb->dev->ifindex;
   876			IPCB(skb)->flags = IPSKB_FORWARDED;
   877			return nf_flow_xmit_xfrm(skb, state, &rt->dst);
   878		}
   879	
   880		dir = tuplehash->tuple.dir;
   881		flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
   882		other_tuple = &flow->tuplehash[!dir].tuple;
   883		ip_addr = (union nf_inet_addr *)&other_tuple->src_v4;
   884	
   885		if (nf_flow_tunnel_push(state->net, skb, other_tuple,
   886					tuplehash->tuple.dst_cache, &ip_addr) < 0)
   887			return NF_DROP;
   888	
   889		switch (tuplehash->tuple.xmit_type) {
   890		case FLOW_OFFLOAD_XMIT_NEIGH: {
 > 891			struct dst_entry *dst;
   892	
   893			xmit.outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.ifidx);
   894			if (!xmit.outdev) {
   895				flow_offload_teardown(flow);
   896				return NF_DROP;
   897			}
   898			if (other_tuple->tun.encap_proto ?
   899			    other_tuple->tun.encap_proto == AF_INET6 :
   900			    ctx->tun.inner_proto == IPPROTO_IPV6) {
   901				struct rt6_info *rt6;
   902	
   903				rt6 = dst_rt6_info(tuplehash->tuple.dst_cache);
   904				neigh = ip_neigh_gw6(rt6->dst.dev,
   905						     rt6_nexthop(rt6, &ip_addr->in6));
   906				dst = &rt6->dst;
   907			} else {
   908				rt = dst_rtable(tuplehash->tuple.dst_cache);
   909				neigh = ip_neigh_gw4(rt->dst.dev,
   910						     rt_nexthop(rt, ip_addr->ip));
   911				dst = &rt->dst;
   912			}
   913			if (IS_ERR(neigh)) {
   914				flow_offload_teardown(flow);
   915				return NF_DROP;
   916			}
   917			xmit.dest = neigh->ha;
   918			skb_dst_drop(skb);
   919			skb_dst_set_noref(skb, &rt->dst);
   920			break;
   921		}
   922		case FLOW_OFFLOAD_XMIT_DIRECT:
   923			xmit.outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.out.ifidx);
   924			if (!xmit.outdev) {
   925				flow_offload_teardown(flow);
   926				return NF_DROP;
   927			}
   928			xmit.dest = tuplehash->tuple.out.h_dest;
   929			xmit.source = tuplehash->tuple.out.h_source;
   930			break;
   931		default:
   932			WARN_ON_ONCE(1);
   933			return NF_DROP;
   934		}
   935		xmit.tuple = other_tuple;
   936		xmit.needs_gso_segment = tuplehash->tuple.needs_gso_segment;
   937	
   938		return nf_flow_queue_xmit(state->net, skb, &xmit);
   939	}
   940	

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH nf-next 5/8] net: netfilter: add IPv4 over IPv6 tunnel flowtable acceleration
  2026-10-30  4:33   ` kernel test robot
@ 2026-10-30  8:20     ` Lorenzo Bianconi
  0 siblings, 0 replies; 11+ messages in thread
From: Lorenzo Bianconi @ 2026-10-30  8:20 UTC (permalink / raw)
  To: kernel test robot
  Cc: Pablo Neira Ayuso, Florian Westphal, Phil Sutter, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	David Ahern, Ido Schimmel, Shuah Khan, oe-kbuild-all, netdev,
	netfilter-devel, coreteam, linux-kselftest

[-- Attachment #1: Type: text/plain, Size: 5246 bytes --]

> Hi Lorenzo,
> 
> kernel test robot noticed the following build warnings:
> 
> [auto build test WARNING on 734bef548a96e8774d6eef5dfa2026c6edc4e80b]
> 
> url:    https://github.com/intel-lab-lkp/linux/commits/Lorenzo-Bianconi/net-netfilter-nf_flow_table-recognize-IPv4-IPv6-in-tunnel-proto-matching/20261029-143512
> base:   734bef548a96e8774d6eef5dfa2026c6edc4e80b
> patch link:    https://lore.kernel.org/r/20261029-flowtable-sw-accel-ip6ip-sit-v1-5-6a17c54f9fb7%40oss.qualcomm.com
> patch subject: [PATCH nf-next 5/8] net: netfilter: add IPv4 over IPv6 tunnel flowtable acceleration
> config: m68k-defconfig (https://download.01.org/0day-ci/archive/20261030/202610301255.BRNUBmqH-lkp@intel.com/config)
> compiler: m68k-linux-gcc (GCC) 16.2.0
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261030/202610301255.BRNUBmqH-lkp@intel.com/reproduce)
> 
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202610301255.BRNUBmqH-lkp@intel.com/
> 
> All warnings (new ones prefixed by >>):
> 
>    net/netfilter/nf_flow_table_ip.c: In function 'nf_flow_queue_xmit4':
> >> net/netfilter/nf_flow_table_ip.c:891:35: warning: variable 'dst' set but not used [-Wunused-but-set-variable=]
>      891 |                 struct dst_entry *dst;
>          |                                   ^~~
>    net/netfilter/nf_flow_table_ip.c: In function 'nf_flow_queue_xmit6':
>    net/netfilter/nf_flow_table_ip.c:1237:35: warning: variable 'dst' set but not used [-Wunused-but-set-variable=]
>     1237 |                 struct dst_entry *dst;
>          |                                   ^~~

ack, I will fix it in v2.

Regards,
Lorenzo

> 
> 
> vim +/dst +891 net/netfilter/nf_flow_table_ip.c
> 
>    858	
>    859	static int nf_flow_queue_xmit4(struct nf_flowtable_ctx *ctx,
>    860				       struct sk_buff *skb,
>    861				       struct flow_offload_tuple_rhash *tuplehash,
>    862				       const struct nf_hook_state *state)
>    863	{
>    864		struct flow_offload_tuple *other_tuple;
>    865		enum flow_offload_tuple_dir dir;
>    866		struct nf_flow_xmit xmit = {};
>    867		union nf_inet_addr *ip_addr;
>    868		struct flow_offload *flow;
>    869		struct neighbour *neigh;
>    870		struct rtable *rt;
>    871	
>    872		if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) {
>    873			rt = dst_rtable(tuplehash->tuple.dst_cache);
>    874			memset(skb->cb, 0, sizeof(struct inet_skb_parm));
>    875			IPCB(skb)->iif = skb->dev->ifindex;
>    876			IPCB(skb)->flags = IPSKB_FORWARDED;
>    877			return nf_flow_xmit_xfrm(skb, state, &rt->dst);
>    878		}
>    879	
>    880		dir = tuplehash->tuple.dir;
>    881		flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
>    882		other_tuple = &flow->tuplehash[!dir].tuple;
>    883		ip_addr = (union nf_inet_addr *)&other_tuple->src_v4;
>    884	
>    885		if (nf_flow_tunnel_push(state->net, skb, other_tuple,
>    886					tuplehash->tuple.dst_cache, &ip_addr) < 0)
>    887			return NF_DROP;
>    888	
>    889		switch (tuplehash->tuple.xmit_type) {
>    890		case FLOW_OFFLOAD_XMIT_NEIGH: {
>  > 891			struct dst_entry *dst;
>    892	
>    893			xmit.outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.ifidx);
>    894			if (!xmit.outdev) {
>    895				flow_offload_teardown(flow);
>    896				return NF_DROP;
>    897			}
>    898			if (other_tuple->tun.encap_proto ?
>    899			    other_tuple->tun.encap_proto == AF_INET6 :
>    900			    ctx->tun.inner_proto == IPPROTO_IPV6) {
>    901				struct rt6_info *rt6;
>    902	
>    903				rt6 = dst_rt6_info(tuplehash->tuple.dst_cache);
>    904				neigh = ip_neigh_gw6(rt6->dst.dev,
>    905						     rt6_nexthop(rt6, &ip_addr->in6));
>    906				dst = &rt6->dst;
>    907			} else {
>    908				rt = dst_rtable(tuplehash->tuple.dst_cache);
>    909				neigh = ip_neigh_gw4(rt->dst.dev,
>    910						     rt_nexthop(rt, ip_addr->ip));
>    911				dst = &rt->dst;
>    912			}
>    913			if (IS_ERR(neigh)) {
>    914				flow_offload_teardown(flow);
>    915				return NF_DROP;
>    916			}
>    917			xmit.dest = neigh->ha;
>    918			skb_dst_drop(skb);
>    919			skb_dst_set_noref(skb, &rt->dst);
>    920			break;
>    921		}
>    922		case FLOW_OFFLOAD_XMIT_DIRECT:
>    923			xmit.outdev = dev_get_by_index_rcu(state->net, tuplehash->tuple.out.ifidx);
>    924			if (!xmit.outdev) {
>    925				flow_offload_teardown(flow);
>    926				return NF_DROP;
>    927			}
>    928			xmit.dest = tuplehash->tuple.out.h_dest;
>    929			xmit.source = tuplehash->tuple.out.h_source;
>    930			break;
>    931		default:
>    932			WARN_ON_ONCE(1);
>    933			return NF_DROP;
>    934		}
>    935		xmit.tuple = other_tuple;
>    936		xmit.needs_gso_segment = tuplehash->tuple.needs_gso_segment;
>    937	
>    938		return nf_flow_queue_xmit(state->net, skb, &xmit);
>    939	}
>    940	
> 
> --
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-10-30  8:20 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-29 13:35 [PATCH nf-next 0/8] Add IPv4 over IPv6 and SIT flowtable SW acceleration Lorenzo Bianconi
2026-10-29 13:35 ` [PATCH nf-next 1/8] net: netfilter: nf_flow_table: recognize IPv4/IPv6 in tunnel proto matching Lorenzo Bianconi
2026-10-29 13:35 ` [PATCH nf-next 2/8] net: netfilter: nf_flow_table: refactor MTU check for tunnel offload Lorenzo Bianconi
2026-10-29 13:35 ` [PATCH nf-next 3/8] net: ip6_tunnel: add IPv4 over IPv6 flowtable " Lorenzo Bianconi
2026-10-29 13:35 ` [PATCH nf-next 4/8] net: netfilter: nf_flow_table: use tunnel encap proto for route lookup Lorenzo Bianconi
2026-10-29 13:35 ` [PATCH nf-next 5/8] net: netfilter: add IPv4 over IPv6 tunnel flowtable acceleration Lorenzo Bianconi
2026-10-30  4:33   ` kernel test robot
2026-10-30  8:20     ` Lorenzo Bianconi
2026-10-29 13:35 ` [PATCH nf-next 6/8] selftests: netfilter: nft_flowtable.sh: add IPv4 over IPv6 flowtable selftest Lorenzo Bianconi
2026-10-29 13:35 ` [PATCH nf-next 7/8] net: netfilter: add SIT tunnel flowtable acceleration Lorenzo Bianconi
2026-10-29 13:35 ` [PATCH nf-next 8/8] selftests: netfilter: nft_flowtable.sh: add SIT flowtable selftest Lorenzo Bianconi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.