All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nf-next 0/7] flowtable preparation for IPv4 over IPv6 and SIT
@ 2026-08-06 22:35 Pablo Neira Ayuso
  2026-08-06 22:35 ` [PATCH nf-next 1/7] net: pass net_device_path_ctx to dev_fill_forward_path() Pablo Neira Ayuso
                   ` (6 more replies)
  0 siblings, 7 replies; 14+ messages in thread
From: Pablo Neira Ayuso @ 2026-08-06 22:35 UTC (permalink / raw)
  To: netfilter-devel; +Cc: lorenzo.bianconi, lorenzo

Hi Lorenzo,

After reading your v6 series to add IPv4 over IPv6 and SIT support for
the flowtable, and also considering more recent preparation work that
went into net-next, I made this new series to explore easier integration
of your work.

Patch #1 is your update for dev_fill_forward_path() rebased on top
of nf-next.

Then, patches #2 to #7 revisit and consolidate existing infrastructure
to prepare for the IPv4 over IPv6 and SIT support.

From the flowtable datapath, the idea is to parse initially the layer 2
encapsulation and layer 3 tunnel with nf_flow_skb_encap_protocol().
Then, call the IPv4 or IPv6 flowtable lookup+forward function according
to the (inner, if any) IP header. Finally, there is another check
according on the (outer, if any) IP header to call the nf_flow_queue_xmit{4,6}
function according to the ctx->ether_type, which can be updated by the
forward function.

Let me know if I am missing anything, thanks!

Lorenzo Bianconi (1):
  net: pass net_device_path_ctx to dev_fill_forward_path()

Pablo Neira Ayuso (6):
  net: netfilter: add ether_type to net_device_path_ctx and use it
  netfilter: flowtable: rename tun.l3_proto to tun.inner_proto
  netfilter: flowtable: rename ctx.tun.proto to ctx.tun.inner_proto
  netfilter: flowtable: store ethertype in flowtable context
  netfilter: flowtable: move ipv4 and ipv6 xmit path to function
  netfilter: flowtable: detach layer 2 encapsulation parser from lookup

 drivers/net/ethernet/airoha/airoha_ppe.c      |   7 +-
 .../net/ethernet/mediatek/mtk_ppe_offload.c   |   7 +-
 include/linux/netdevice.h                     |   5 +-
 include/net/netfilter/nf_flow_table.h         |   2 +-
 net/core/dev.c                                |  18 +-
 net/ipv4/ipip.c                               |   5 +-
 net/ipv6/ip6_tunnel.c                         |   5 +-
 net/netfilter/nf_flow_table_ip.c              | 167 ++++++++++--------
 net/netfilter/nf_flow_table_path.c            |  17 +-
 9 files changed, 139 insertions(+), 94 deletions(-)

-- 
2.47.3


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

* [PATCH nf-next 1/7] net: pass net_device_path_ctx to dev_fill_forward_path()
  2026-08-06 22:35 [PATCH nf-next 0/7] flowtable preparation for IPv4 over IPv6 and SIT Pablo Neira Ayuso
@ 2026-08-06 22:35 ` Pablo Neira Ayuso
  2026-08-06 22:35 ` [PATCH nf-next 2/7] net: netfilter: add ether_type to net_device_path_ctx and use it Pablo Neira Ayuso
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 14+ messages in thread
From: Pablo Neira Ayuso @ 2026-08-06 22:35 UTC (permalink / raw)
  To: netfilter-devel; +Cc: lorenzo.bianconi, lorenzo

From: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>

Refactor dev_fill_forward_path() to take a struct net_device_path_ctx
pointer instead of a (dev, daddr) pair, so the caller can build and
populate the context up front and keep it after the forward path walk.

This allows additional fields (e.g. vlan and ether_type) to be carried
in the context and shared with ndo_fill_forward_path implementations,
instead of being reconstructed on the stack inside the core helper.

Update the mtk_ppe_offload, airoha_ppe and nf_flow_table_path callers to
allocate and fill the context before invoking dev_fill_forward_path().
The network topology resolution behaviour is unchanged.

This is a preliminary patch to enable HW flowtable offload for IPv4
over IPv6 tunnels.

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: Just a rebase on top of current nf-next.git

 drivers/net/ethernet/airoha/airoha_ppe.c       |  7 ++++++-
 .../net/ethernet/mediatek/mtk_ppe_offload.c    |  7 ++++++-
 include/linux/netdevice.h                      |  2 +-
 net/core/dev.c                                 | 18 +++++++-----------
 net/netfilter/nf_flow_table_path.c             |  7 ++++++-
 5 files changed, 26 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c
index a03af9750573..92611802801e 100644
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -283,14 +283,19 @@ static int airoha_ppe_get_wdma_info(struct net_device *dev, const u8 *addr,
 				    struct airoha_wdma_info *info)
 {
 	struct net_device_path_stack stack;
+	struct net_device_path_ctx ctx = {
+		.dev = dev,
+	};
 	struct net_device_path *path;
 	int err;
 
 	if (!dev)
 		return -ENODEV;
 
+	ether_addr_copy(ctx.daddr, addr);
+
 	rcu_read_lock();
-	err = dev_fill_forward_path(dev, addr, &stack);
+	err = dev_fill_forward_path(&ctx, &stack);
 	rcu_read_unlock();
 	if (err)
 		return err;
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
index 771d9118f94a..99b28aaa7cc4 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
@@ -92,6 +92,9 @@ static int
 mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_info *info)
 {
 	struct net_device_path_stack stack;
+	struct net_device_path_ctx ctx = {
+		.dev = dev,
+	};
 	struct net_device_path *path;
 	int err;
 
@@ -101,8 +104,10 @@ mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_i
 	if (!IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED))
 		return -1;
 
+	ether_addr_copy(ctx.daddr, addr);
+
 	rcu_read_lock();
-	err = dev_fill_forward_path(dev, addr, &stack);
+	err = dev_fill_forward_path(&ctx, &stack);
 	rcu_read_unlock();
 	if (err)
 		return err;
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 62cfad7e6b79..4319b949f405 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3426,7 +3426,7 @@ void dev_remove_offload(struct packet_offload *po);
 
 int dev_get_iflink(const struct net_device *dev);
 int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
-int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
+int dev_fill_forward_path(struct net_device_path_ctx *ctx,
 			  struct net_device_path_stack *stack);
 void dev_fill_forward_path_release(struct net_device_path_stack *stack);
 struct net_device *dev_get_by_name(struct net *net, const char *name);
diff --git a/net/core/dev.c b/net/core/dev.c
index e50ed677de72..13dfd2113a5a 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -769,35 +769,31 @@ void dev_fill_forward_path_release(struct net_device_path_stack *stack)
 }
 EXPORT_SYMBOL_GPL(dev_fill_forward_path_release);
 
-int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
+int dev_fill_forward_path(struct net_device_path_ctx *ctx,
 			  struct net_device_path_stack *stack)
 {
 	const struct net_device *last_dev;
-	struct net_device_path_ctx ctx = {
-		.dev	= dev,
-	};
 	struct net_device_path *path;
 	int ret = 0;
 
-	memcpy(ctx.daddr, daddr, sizeof(ctx.daddr));
 	stack->num_paths = 0;
-	while (ctx.dev && ctx.dev->netdev_ops->ndo_fill_forward_path) {
-		last_dev = ctx.dev;
+	while (ctx->dev && ctx->dev->netdev_ops->ndo_fill_forward_path) {
+		last_dev = ctx->dev;
 		path = dev_fwd_path(stack);
 		if (!path)
 			goto err_out;
 
 		memset(path, 0, sizeof(struct net_device_path));
-		ret = ctx.dev->netdev_ops->ndo_fill_forward_path(&ctx, path);
+		ret = ctx->dev->netdev_ops->ndo_fill_forward_path(ctx, path);
 		if (ret < 0)
 			goto err_out;
 
 		stack->num_paths++;
-		if (WARN_ON_ONCE(last_dev == ctx.dev))
+		if (WARN_ON_ONCE(last_dev == ctx->dev))
 			goto err_out;
 	}
 
-	if (!ctx.dev)
+	if (!ctx->dev)
 		return ret;
 
 	path = dev_fwd_path(stack);
@@ -805,7 +801,7 @@ int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
 		goto err_out;
 
 	path->type = DEV_PATH_ETHERNET;
-	path->dev = ctx.dev;
+	path->dev = ctx->dev;
 	stack->num_paths++;
 
 	return 0;
diff --git a/net/netfilter/nf_flow_table_path.c b/net/netfilter/nf_flow_table_path.c
index 56219b02e122..0cbde535b8ba 100644
--- a/net/netfilter/nf_flow_table_path.c
+++ b/net/netfilter/nf_flow_table_path.c
@@ -49,6 +49,9 @@ static int nft_dev_fill_forward_path(const struct dst_entry *dst_cache,
 {
 	const void *daddr = &ct->tuplehash[!dir].tuple.src.u3;
 	struct net_device *dev = dst_cache->dev;
+	struct net_device_path_ctx ctx = {
+		.dev = dev,
+	};
 	struct neighbour *n;
 	u8 nud_state;
 
@@ -71,7 +74,9 @@ static int nft_dev_fill_forward_path(const struct dst_entry *dst_cache,
 		return -1;
 
 out:
-	return dev_fill_forward_path(dev, ha, stack);
+	ether_addr_copy(ctx.daddr, ha);
+
+	return dev_fill_forward_path(&ctx, stack);
 }
 
 struct nft_forward_info {
-- 
2.47.3


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

* [PATCH nf-next 2/7] net: netfilter: add ether_type to net_device_path_ctx and use it
  2026-08-06 22:35 [PATCH nf-next 0/7] flowtable preparation for IPv4 over IPv6 and SIT Pablo Neira Ayuso
  2026-08-06 22:35 ` [PATCH nf-next 1/7] net: pass net_device_path_ctx to dev_fill_forward_path() Pablo Neira Ayuso
@ 2026-08-06 22:35 ` Pablo Neira Ayuso
  2026-08-07  9:00   ` Lorenzo Bianconi
  2026-08-06 22:35 ` [PATCH nf-next 3/7] netfilter: flowtable: rename tun.l3_proto to tun.inner_proto Pablo Neira Ayuso
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 14+ messages in thread
From: Pablo Neira Ayuso @ 2026-08-06 22:35 UTC (permalink / raw)
  To: netfilter-devel; +Cc: lorenzo.bianconi, lorenzo

Add an ether_type field to struct net_device_path_ctx to reject IPv4
over IPv6 and vice-versa, this is currently not support. Otherwise,
incorrect dst_entry family can be reached from datapath.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/linux/netdevice.h          | 1 +
 net/ipv4/ipip.c                    | 3 +++
 net/ipv6/ip6_tunnel.c              | 3 +++
 net/netfilter/nf_flow_table_path.c | 6 ++++--
 4 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 4319b949f405..d9962c50bd60 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -939,6 +939,7 @@ struct net_device_path_stack {
 struct net_device_path_ctx {
 	const struct net_device *dev;
 	u8			daddr[ETH_ALEN];
+	__be16			ether_type;
 
 	int			num_vlans;
 	struct {
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index fb7d96f99b06..62a374079bfc 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -360,6 +360,9 @@ static int ipip_fill_forward_path(struct net_device_path_ctx *ctx,
 	const struct iphdr *tiph = &tunnel->parms.iph;
 	struct rtable *rt;
 
+	if (ctx->ether_type != cpu_to_be16(ETH_P_IP))
+		return -EOPNOTSUPP;
+
 	if (tunnel->collect_md)
 		return -EOPNOTSUPP;
 
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index d80020bc2620..3bfaa98e7f33 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1849,6 +1849,9 @@ 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))
+		return -EOPNOTSUPP;
+
 	if (t->parms.flags & (IP6_TNL_F_USE_ORIG_TCLASS |
 			      IP6_TNL_F_USE_ORIG_FLOWLABEL |
 			      IP6_TNL_F_USE_ORIG_FWMARK))
diff --git a/net/netfilter/nf_flow_table_path.c b/net/netfilter/nf_flow_table_path.c
index 0cbde535b8ba..5f166da3b09b 100644
--- a/net/netfilter/nf_flow_table_path.c
+++ b/net/netfilter/nf_flow_table_path.c
@@ -44,13 +44,15 @@ static bool nft_is_valid_ether_device(const struct net_device *dev)
 
 static int nft_dev_fill_forward_path(const struct dst_entry *dst_cache,
 				     const struct nf_conn *ct,
-				     enum ip_conntrack_dir dir, u8 *ha,
+				     enum ip_conntrack_dir dir,
+				     u8 *ha, __be16 ether_type,
 				     struct net_device_path_stack *stack)
 {
 	const void *daddr = &ct->tuplehash[!dir].tuple.src.u3;
 	struct net_device *dev = dst_cache->dev;
 	struct net_device_path_ctx ctx = {
 		.dev = dev,
+		.ether_type = ether_type,
 	};
 	struct neighbour *n;
 	u8 nud_state;
@@ -228,7 +230,7 @@ static int nft_dev_forward_path(const struct nft_pktinfo *pkt,
 	unsigned char ha[ETH_ALEN];
 	int i;
 
-	if (nft_dev_fill_forward_path(dst, ct, dir, ha, &stack) < 0 ||
+	if (nft_dev_fill_forward_path(dst, ct, dir, ha, pkt->ethertype, &stack) < 0 ||
 	    nft_dev_path_info(&stack, &info, ha, ft) < 0)
 		return -ENOENT;
 
-- 
2.47.3


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

* [PATCH nf-next 3/7] netfilter: flowtable: rename tun.l3_proto to tun.inner_proto
  2026-08-06 22:35 [PATCH nf-next 0/7] flowtable preparation for IPv4 over IPv6 and SIT Pablo Neira Ayuso
  2026-08-06 22:35 ` [PATCH nf-next 1/7] net: pass net_device_path_ctx to dev_fill_forward_path() Pablo Neira Ayuso
  2026-08-06 22:35 ` [PATCH nf-next 2/7] net: netfilter: add ether_type to net_device_path_ctx and use it Pablo Neira Ayuso
@ 2026-08-06 22:35 ` Pablo Neira Ayuso
  2026-08-07  9:01   ` Lorenzo Bianconi
  2026-08-06 22:35 ` [PATCH nf-next 4/7] netfilter: flowtable: rename ctx.tun.proto to ctx.tun.inner_proto Pablo Neira Ayuso
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 14+ messages in thread
From: Pablo Neira Ayuso @ 2026-08-06 22:35 UTC (permalink / raw)
  To: netfilter-devel; +Cc: lorenzo.bianconi, lorenzo

This field refers to the inner protocol that is encapsulated by the
tunnel header, just a comestic change. No functional changes are
expected.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/linux/netdevice.h             | 2 +-
 include/net/netfilter/nf_flow_table.h | 2 +-
 net/ipv4/ipip.c                       | 2 +-
 net/ipv6/ip6_tunnel.c                 | 2 +-
 net/netfilter/nf_flow_table_ip.c      | 6 +++---
 net/netfilter/nf_flow_table_path.c    | 4 ++--
 6 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index d9962c50bd60..68ccb5868070 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -902,7 +902,7 @@ struct net_device_path {
 				struct in6_addr	dst_v6;
 			};
 
-			u8	l3_proto;
+			u8	inner_proto;
 		} tun;
 		struct {
 			enum {
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
index a090ec3ffef2..f2e2771f188f 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -117,7 +117,7 @@ struct flow_offload_tunnel {
 		struct in6_addr	dst_v6;
 	};
 
-	u8	l3_proto;
+	u8	inner_proto;
 };
 
 struct flow_offload_tuple {
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 62a374079bfc..1630325c77d3 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -378,7 +378,7 @@ static int ipip_fill_forward_path(struct net_device_path_ctx *ctx,
 	path->type = DEV_PATH_TUN;
 	path->tun.src_v4.s_addr = tiph->saddr;
 	path->tun.dst_v4.s_addr = tiph->daddr;
-	path->tun.l3_proto = IPPROTO_IPIP;
+	path->tun.inner_proto = IPPROTO_IPIP;
 	path->tun.dst = &rt->dst;
 	path->dev = ctx->dev;
 
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 3bfaa98e7f33..7b54919232ba 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1872,7 +1872,7 @@ 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.l3_proto = IPPROTO_IPV6;
+		path->tun.inner_proto = IPPROTO_IPV6;
 		path->tun.dst = dst;
 		path->dev = ctx->dev;
 		ctx->dev = dst->dev;
diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index 0b314b10e705..e1aa01763f33 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -197,7 +197,7 @@ static void nf_flow_tuple_encap(struct nf_flowtable_ctx *ctx,
 		if (ctx->tun.proto == IPPROTO_IPIP) {
 			tuple->tun.dst_v4.s_addr = iph->daddr;
 			tuple->tun.src_v4.s_addr = iph->saddr;
-			tuple->tun.l3_proto = IPPROTO_IPIP;
+			tuple->tun.inner_proto = IPPROTO_IPIP;
 		}
 		break;
 	case htons(ETH_P_IPV6):
@@ -205,7 +205,7 @@ static void nf_flow_tuple_encap(struct nf_flowtable_ctx *ctx,
 		if (ctx->tun.proto == IPPROTO_IPV6) {
 			tuple->tun.dst_v6 = ip6h->daddr;
 			tuple->tun.src_v6 = ip6h->saddr;
-			tuple->tun.l3_proto = IPPROTO_IPV6;
+			tuple->tun.inner_proto = IPPROTO_IPV6;
 		}
 		break;
 	default:
@@ -611,7 +611,7 @@ static int nf_flow_tunnel_ipip_push(struct net *net, struct sk_buff *skb,
 	iph->version	= 4;
 	iph->ihl	= sizeof(*iph) >> 2;
 	iph->frag_off	= ip_mtu_locked(&rt->dst) ? 0 : frag_off;
-	iph->protocol	= tuple->tun.l3_proto;
+	iph->protocol	= tuple->tun.inner_proto;
 	iph->tos	= tos;
 	iph->daddr	= tuple->tun.src_v4.s_addr;
 	iph->saddr	= tuple->tun.dst_v4.s_addr;
diff --git a/net/netfilter/nf_flow_table_path.c b/net/netfilter/nf_flow_table_path.c
index 5f166da3b09b..1e55644f2edb 100644
--- a/net/netfilter/nf_flow_table_path.c
+++ b/net/netfilter/nf_flow_table_path.c
@@ -133,7 +133,7 @@ static int nft_dev_path_info(struct net_device_path_stack *stack,
 
 				info->tun.src_v6 = path->tun.src_v6;
 				info->tun.dst_v6 = path->tun.dst_v6;
-				info->tun.l3_proto = path->tun.l3_proto;
+				info->tun.inner_proto = path->tun.inner_proto;
 				info->tun_dst = path->tun.dst;
 				info->num_tuns++;
 			} else {
@@ -245,7 +245,7 @@ static int nft_dev_forward_path(const struct nft_pktinfo *pkt,
 	if (info.num_tuns) {
 		route->tuple[!dir].in.tun.src_v6 = info.tun.dst_v6;
 		route->tuple[!dir].in.tun.dst_v6 = info.tun.src_v6;
-		route->tuple[!dir].in.tun.l3_proto = info.tun.l3_proto;
+		route->tuple[!dir].in.tun.inner_proto = info.tun.inner_proto;
 		route->tuple[!dir].in.num_tuns = info.num_tuns;
 		dst_release(route->tuple[dir].dst);
 		route->tuple[dir].dst = info.tun_dst;
-- 
2.47.3


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

* [PATCH nf-next 4/7] netfilter: flowtable: rename ctx.tun.proto to ctx.tun.inner_proto
  2026-08-06 22:35 [PATCH nf-next 0/7] flowtable preparation for IPv4 over IPv6 and SIT Pablo Neira Ayuso
                   ` (2 preceding siblings ...)
  2026-08-06 22:35 ` [PATCH nf-next 3/7] netfilter: flowtable: rename tun.l3_proto to tun.inner_proto Pablo Neira Ayuso
@ 2026-08-06 22:35 ` Pablo Neira Ayuso
  2026-08-07  9:02   ` Lorenzo Bianconi
  2026-08-06 22:35 ` [PATCH nf-next 5/7] netfilter: flowtable: store ethertype in flowtable context Pablo Neira Ayuso
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 14+ messages in thread
From: Pablo Neira Ayuso @ 2026-08-06 22:35 UTC (permalink / raw)
  To: netfilter-devel; +Cc: lorenzo.bianconi, lorenzo

For consistency with the tun.l3proto rename, use same name field.
No functional changes are intended.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 net/netfilter/nf_flow_table_ip.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index e1aa01763f33..ed90809b206e 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -153,7 +153,7 @@ struct nf_flowtable_ctx {
 		/* Tunnel IP header size */
 		u32 hdr_size;
 		/* IP tunnel protocol */
-		u8 proto;
+		u8 inner_proto;
 	} tun;
 };
 
@@ -194,7 +194,7 @@ static void nf_flow_tuple_encap(struct nf_flowtable_ctx *ctx,
 	switch (inner_proto) {
 	case htons(ETH_P_IP):
 		iph = (struct iphdr *)(skb_network_header(skb) + offset);
-		if (ctx->tun.proto == IPPROTO_IPIP) {
+		if (ctx->tun.inner_proto == IPPROTO_IPIP) {
 			tuple->tun.dst_v4.s_addr = iph->daddr;
 			tuple->tun.src_v4.s_addr = iph->saddr;
 			tuple->tun.inner_proto = IPPROTO_IPIP;
@@ -202,7 +202,7 @@ static void nf_flow_tuple_encap(struct nf_flowtable_ctx *ctx,
 		break;
 	case htons(ETH_P_IPV6):
 		ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
-		if (ctx->tun.proto == IPPROTO_IPV6) {
+		if (ctx->tun.inner_proto == IPPROTO_IPV6) {
 			tuple->tun.dst_v6 = ip6h->daddr;
 			tuple->tun.src_v6 = ip6h->saddr;
 			tuple->tun.inner_proto = IPPROTO_IPV6;
@@ -328,7 +328,7 @@ static bool nf_flow_ip4_tunnel_proto(struct nf_flowtable_ctx *ctx,
 		return false;
 
 	if (iph->protocol == IPPROTO_IPIP) {
-		ctx->tun.proto = iph->protocol;
+		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,
 		return false;
 
 	if (ip6h->nexthdr == IPPROTO_IPV6) {
-		ctx->tun.proto = ip6h->nexthdr;
+		ctx->tun.inner_proto = ip6h->nexthdr;
 		ctx->tun.hdr_size = sizeof(*ip6h);
 		ctx->offset += ctx->tun.hdr_size;
 	}
@@ -367,8 +367,8 @@ static bool nf_flow_ip6_tunnel_proto(struct nf_flowtable_ctx *ctx,
 static void nf_flow_ip_tunnel_pop(struct nf_flowtable_ctx *ctx,
 				  struct sk_buff *skb)
 {
-	if (ctx->tun.proto != IPPROTO_IPIP &&
-	    ctx->tun.proto != IPPROTO_IPV6)
+	if (ctx->tun.inner_proto != IPPROTO_IPIP &&
+	    ctx->tun.inner_proto != IPPROTO_IPV6)
 		return;
 
 	skb_pull(skb, ctx->tun.hdr_size);
-- 
2.47.3


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

* [PATCH nf-next 5/7] netfilter: flowtable: store ethertype in flowtable context
  2026-08-06 22:35 [PATCH nf-next 0/7] flowtable preparation for IPv4 over IPv6 and SIT Pablo Neira Ayuso
                   ` (3 preceding siblings ...)
  2026-08-06 22:35 ` [PATCH nf-next 4/7] netfilter: flowtable: rename ctx.tun.proto to ctx.tun.inner_proto Pablo Neira Ayuso
@ 2026-08-06 22:35 ` Pablo Neira Ayuso
  2026-08-07  9:10   ` Lorenzo Bianconi
  2026-08-06 22:35 ` [PATCH nf-next 6/7] netfilter: flowtable: move ipv4 and ipv6 xmit path to function Pablo Neira Ayuso
  2026-08-06 22:35 ` [PATCH nf-next 7/7] netfilter: flowtable: detach layer 2 encapsulation parser from lookup Pablo Neira Ayuso
  6 siblings, 1 reply; 14+ messages in thread
From: Pablo Neira Ayuso @ 2026-08-06 22:35 UTC (permalink / raw)
  To: netfilter-devel; +Cc: lorenzo.bianconi, lorenzo

Add a new field to store the ethertype of the packet, skipping layer 2
encapsulation. Store the ether_type in the context after parsing the
layer 2 header for the first time and then use it later on.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 net/netfilter/nf_flow_table_ip.c | 47 +++++++++++++++++++-------------
 1 file changed, 28 insertions(+), 19 deletions(-)

diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index ed90809b206e..4437f3a13cb2 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -147,6 +147,7 @@ static bool ip_has_options(unsigned int thoff)
 
 struct nf_flowtable_ctx {
 	const struct net_device	*in;
+	__be16			ether_type;
 	u32			offset;
 	u32			hdrsize;
 	struct {
@@ -161,7 +162,6 @@ static void nf_flow_tuple_encap(struct nf_flowtable_ctx *ctx,
 				struct sk_buff *skb,
 				struct flow_offload_tuple *tuple)
 {
-	__be16 inner_proto = skb->protocol;
 	struct vlan_ethhdr *veth;
 	struct pppoe_hdr *phdr;
 	struct ipv6hdr *ip6h;
@@ -179,19 +179,17 @@ static void nf_flow_tuple_encap(struct nf_flowtable_ctx *ctx,
 		veth = (struct vlan_ethhdr *)skb_mac_header(skb);
 		tuple->encap[i].id = ntohs(veth->h_vlan_TCI);
 		tuple->encap[i].proto = skb->protocol;
-		inner_proto = veth->h_vlan_encapsulated_proto;
 		offset += VLAN_HLEN;
 		break;
 	case htons(ETH_P_PPP_SES):
 		phdr = (struct pppoe_hdr *)skb_network_header(skb);
 		tuple->encap[i].id = ntohs(phdr->sid);
 		tuple->encap[i].proto = skb->protocol;
-		inner_proto = *((__be16 *)(phdr + 1));
 		offset += PPPOE_SES_HLEN;
 		break;
 	}
 
-	switch (inner_proto) {
+	switch (ctx->ether_type) {
 	case htons(ETH_P_IP):
 		iph = (struct iphdr *)(skb_network_header(skb) + offset);
 		if (ctx->tun.inner_proto == IPPROTO_IPIP) {
@@ -376,10 +374,10 @@ static void nf_flow_ip_tunnel_pop(struct nf_flowtable_ctx *ctx,
 }
 
 static bool nf_flow_skb_encap_protocol(struct nf_flowtable_ctx *ctx,
-				       struct sk_buff *skb, __be16 proto)
+				       struct sk_buff *skb)
 {
-	__be16 inner_proto = skb->protocol;
 	struct vlan_ethhdr *veth;
+	__be16 ether_type;
 	bool ret = false;
 
 	switch (skb->protocol) {
@@ -388,22 +386,27 @@ static bool nf_flow_skb_encap_protocol(struct nf_flowtable_ctx *ctx,
 			return false;
 
 		veth = (struct vlan_ethhdr *)skb_mac_header(skb);
-		if (veth->h_vlan_encapsulated_proto == proto) {
-			ctx->offset += VLAN_HLEN;
-			inner_proto = proto;
-			ret = true;
-		}
+		ctx->ether_type = veth->h_vlan_encapsulated_proto;
+		ctx->offset += VLAN_HLEN;
+		ret = true;
 		break;
 	case htons(ETH_P_PPP_SES):
-		if (nf_flow_pppoe_proto(skb, &inner_proto) &&
-		    inner_proto == proto) {
-			ctx->offset += PPPOE_SES_HLEN;
-			ret = true;
-		}
+		if (!nf_flow_pppoe_proto(skb, &ether_type))
+			return false;
+
+		ctx->ether_type = ether_type;
+		ctx->offset += PPPOE_SES_HLEN;
+		ret = true;
+		break;
+	case htons(ETH_P_IP):
+	case htons(ETH_P_IPV6):
+		ctx->ether_type = skb->protocol;
 		break;
+	default:
+		return false;
 	}
 
-	switch (inner_proto) {
+	switch (ctx->ether_type) {
 	case htons(ETH_P_IP):
 		ret = nf_flow_ip4_tunnel_proto(ctx, skb);
 		break;
@@ -455,7 +458,10 @@ nf_flow_offload_lookup(struct nf_flowtable_ctx *ctx,
 {
 	struct flow_offload_tuple tuple = {};
 
-	if (!nf_flow_skb_encap_protocol(ctx, skb, htons(ETH_P_IP)))
+	if (!nf_flow_skb_encap_protocol(ctx, skb))
+		return NULL;
+
+	if (unlikely(ctx->ether_type != htons(ETH_P_IP)))
 		return NULL;
 
 	if (nf_flow_tuple_ip(ctx, skb, &tuple) < 0)
@@ -1101,7 +1107,10 @@ nf_flow_offload_ipv6_lookup(struct nf_flowtable_ctx *ctx,
 {
 	struct flow_offload_tuple tuple = {};
 
-	if (!nf_flow_skb_encap_protocol(ctx, skb, htons(ETH_P_IPV6)))
+	if (!nf_flow_skb_encap_protocol(ctx, skb))
+		return NULL;
+
+	if (unlikely(ctx->ether_type != htons(ETH_P_IPV6)))
 		return NULL;
 
 	if (nf_flow_tuple_ipv6(ctx, skb, &tuple) < 0)
-- 
2.47.3


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

* [PATCH nf-next 6/7] netfilter: flowtable: move ipv4 and ipv6 xmit path to function
  2026-08-06 22:35 [PATCH nf-next 0/7] flowtable preparation for IPv4 over IPv6 and SIT Pablo Neira Ayuso
                   ` (4 preceding siblings ...)
  2026-08-06 22:35 ` [PATCH nf-next 5/7] netfilter: flowtable: store ethertype in flowtable context Pablo Neira Ayuso
@ 2026-08-06 22:35 ` Pablo Neira Ayuso
  2026-08-07  9:13   ` Lorenzo Bianconi
  2026-08-06 22:35 ` [PATCH nf-next 7/7] netfilter: flowtable: detach layer 2 encapsulation parser from lookup Pablo Neira Ayuso
  6 siblings, 1 reply; 14+ messages in thread
From: Pablo Neira Ayuso @ 2026-08-06 22:35 UTC (permalink / raw)
  To: netfilter-devel; +Cc: lorenzo.bianconi, lorenzo

Move the existing ipv4 and ipv6 transmit path to functions in
preparation of the IPv4 over IPv6 and SIT support.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 net/netfilter/nf_flow_table_ip.c | 92 +++++++++++++++++++-------------
 1 file changed, 54 insertions(+), 38 deletions(-)

diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index 4437f3a13cb2..18febca1dcef 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -800,33 +800,17 @@ static unsigned int nf_flow_queue_xmit(struct net *net, struct sk_buff *skb,
 	return NF_STOLEN;
 }
 
-unsigned int
-nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
-			const struct nf_hook_state *state)
+static int nf_flow_queue_xmit4(struct sk_buff *skb,
+			       struct flow_offload_tuple_rhash *tuplehash,
+			       const struct nf_hook_state *state)
 {
-	struct flow_offload_tuple_rhash *tuplehash;
-	struct nf_flowtable *flow_table = priv;
 	struct flow_offload_tuple *other_tuple;
 	enum flow_offload_tuple_dir dir;
-	struct nf_flowtable_ctx ctx = {
-		.in	= state->in,
-	};
 	struct nf_flow_xmit xmit = {};
 	struct flow_offload *flow;
 	struct neighbour *neigh;
 	struct rtable *rt;
 	__be32 ip_daddr;
-	int ret;
-
-	tuplehash = nf_flow_offload_lookup(&ctx, flow_table, skb);
-	if (!tuplehash)
-		return NF_ACCEPT;
-
-	ret = nf_flow_offload_forward(&ctx, flow_table, tuplehash, skb);
-	if (ret < 0)
-		return NF_DROP;
-	else if (ret == 0)
-		return NF_ACCEPT;
 
 	if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) {
 		rt = dst_rtable(tuplehash->tuple.dst_cache);
@@ -879,6 +863,30 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
 
 	return nf_flow_queue_xmit(state->net, skb, &xmit);
 }
+
+unsigned int
+nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
+			const struct nf_hook_state *state)
+{
+	struct flow_offload_tuple_rhash *tuplehash;
+	struct nf_flowtable *flow_table = priv;
+	struct nf_flowtable_ctx ctx = {
+		.in	= state->in,
+	};
+	int ret;
+
+	tuplehash = nf_flow_offload_lookup(&ctx, flow_table, skb);
+	if (!tuplehash)
+		return NF_ACCEPT;
+
+	ret = nf_flow_offload_forward(&ctx, flow_table, tuplehash, skb);
+	if (ret < 0)
+		return NF_DROP;
+	else if (ret == 0)
+		return NF_ACCEPT;
+
+	return nf_flow_queue_xmit4(skb, tuplehash, state);
+}
 EXPORT_SYMBOL_GPL(nf_flow_offload_ip_hook);
 
 static void nf_flow_nat_ipv6_tcp(struct sk_buff *skb, unsigned int thoff,
@@ -1119,33 +1127,17 @@ nf_flow_offload_ipv6_lookup(struct nf_flowtable_ctx *ctx,
 	return flow_offload_lookup(flow_table, &tuple);
 }
 
-unsigned int
-nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
-			  const struct nf_hook_state *state)
+static int nf_flow_queue_xmit6(struct sk_buff *skb,
+			       struct flow_offload_tuple_rhash *tuplehash,
+			       const struct nf_hook_state *state)
 {
-	struct flow_offload_tuple_rhash *tuplehash;
-	struct nf_flowtable *flow_table = priv;
 	struct flow_offload_tuple *other_tuple;
 	enum flow_offload_tuple_dir dir;
-	struct nf_flowtable_ctx ctx = {
-		.in	= state->in,
-	};
 	struct nf_flow_xmit xmit = {};
 	struct in6_addr *ip6_daddr;
 	struct flow_offload *flow;
 	struct neighbour *neigh;
 	struct rt6_info *rt;
-	int ret;
-
-	tuplehash = nf_flow_offload_ipv6_lookup(&ctx, flow_table, skb);
-	if (tuplehash == NULL)
-		return NF_ACCEPT;
-
-	ret = nf_flow_offload_ipv6_forward(&ctx, flow_table, tuplehash, skb);
-	if (ret < 0)
-		return NF_DROP;
-	else if (ret == 0)
-		return NF_ACCEPT;
 
 	if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) {
 		rt = dst_rt6_info(tuplehash->tuple.dst_cache);
@@ -1199,4 +1191,28 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
 
 	return nf_flow_queue_xmit(state->net, skb, &xmit);
 }
+
+unsigned int
+nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
+			  const struct nf_hook_state *state)
+{
+	struct flow_offload_tuple_rhash *tuplehash;
+	struct nf_flowtable *flow_table = priv;
+	struct nf_flowtable_ctx ctx = {
+		.in	= state->in,
+	};
+	int ret;
+
+	tuplehash = nf_flow_offload_ipv6_lookup(&ctx, flow_table, skb);
+	if (!tuplehash)
+		return NF_ACCEPT;
+
+	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);
+}
 EXPORT_SYMBOL_GPL(nf_flow_offload_ipv6_hook);
-- 
2.47.3


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

* [PATCH nf-next 7/7] netfilter: flowtable: detach layer 2 encapsulation parser from lookup
  2026-08-06 22:35 [PATCH nf-next 0/7] flowtable preparation for IPv4 over IPv6 and SIT Pablo Neira Ayuso
                   ` (5 preceding siblings ...)
  2026-08-06 22:35 ` [PATCH nf-next 6/7] netfilter: flowtable: move ipv4 and ipv6 xmit path to function Pablo Neira Ayuso
@ 2026-08-06 22:35 ` Pablo Neira Ayuso
  2026-08-07  9:15   ` Lorenzo Bianconi
  6 siblings, 1 reply; 14+ messages in thread
From: Pablo Neira Ayuso @ 2026-08-06 22:35 UTC (permalink / raw)
  To: netfilter-devel; +Cc: lorenzo.bianconi, lorenzo

Move the layer 2 encapsulation header parser out of the lookup function
to prepare for IPv4 over IPv6 and SIT.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 net/netfilter/nf_flow_table_ip.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index 18febca1dcef..af534000a287 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -458,12 +458,6 @@ nf_flow_offload_lookup(struct nf_flowtable_ctx *ctx,
 {
 	struct flow_offload_tuple tuple = {};
 
-	if (!nf_flow_skb_encap_protocol(ctx, skb))
-		return NULL;
-
-	if (unlikely(ctx->ether_type != htons(ETH_P_IP)))
-		return NULL;
-
 	if (nf_flow_tuple_ip(ctx, skb, &tuple) < 0)
 		return NULL;
 
@@ -875,6 +869,12 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
 	};
 	int ret;
 
+	if (!nf_flow_skb_encap_protocol(&ctx, skb))
+		return NF_ACCEPT;
+
+	if (unlikely(ctx.ether_type != htons(ETH_P_IP)))
+		return NF_ACCEPT;
+
 	tuplehash = nf_flow_offload_lookup(&ctx, flow_table, skb);
 	if (!tuplehash)
 		return NF_ACCEPT;
@@ -1115,12 +1115,6 @@ nf_flow_offload_ipv6_lookup(struct nf_flowtable_ctx *ctx,
 {
 	struct flow_offload_tuple tuple = {};
 
-	if (!nf_flow_skb_encap_protocol(ctx, skb))
-		return NULL;
-
-	if (unlikely(ctx->ether_type != htons(ETH_P_IPV6)))
-		return NULL;
-
 	if (nf_flow_tuple_ipv6(ctx, skb, &tuple) < 0)
 		return NULL;
 
@@ -1203,6 +1197,12 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
 	};
 	int ret;
 
+	if (!nf_flow_skb_encap_protocol(&ctx, skb))
+		return NF_ACCEPT;
+
+	if (unlikely(ctx.ether_type != htons(ETH_P_IPV6)))
+		return NF_ACCEPT;
+
 	tuplehash = nf_flow_offload_ipv6_lookup(&ctx, flow_table, skb);
 	if (!tuplehash)
 		return NF_ACCEPT;
-- 
2.47.3


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

* Re: [PATCH nf-next 2/7] net: netfilter: add ether_type to net_device_path_ctx and use it
  2026-08-06 22:35 ` [PATCH nf-next 2/7] net: netfilter: add ether_type to net_device_path_ctx and use it Pablo Neira Ayuso
@ 2026-08-07  9:00   ` Lorenzo Bianconi
  0 siblings, 0 replies; 14+ messages in thread
From: Lorenzo Bianconi @ 2026-08-07  9:00 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel, lorenzo.bianconi

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

> Add an ether_type field to struct net_device_path_ctx to reject IPv4
> over IPv6 and vice-versa, this is currently not support. Otherwise,
> incorrect dst_entry family can be reached from datapath.
> 
> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>

> ---
>  include/linux/netdevice.h          | 1 +
>  net/ipv4/ipip.c                    | 3 +++
>  net/ipv6/ip6_tunnel.c              | 3 +++
>  net/netfilter/nf_flow_table_path.c | 6 ++++--
>  4 files changed, 11 insertions(+), 2 deletions(-)
> 
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index 4319b949f405..d9962c50bd60 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -939,6 +939,7 @@ struct net_device_path_stack {
>  struct net_device_path_ctx {
>  	const struct net_device *dev;
>  	u8			daddr[ETH_ALEN];
> +	__be16			ether_type;
>  
>  	int			num_vlans;
>  	struct {
> diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
> index fb7d96f99b06..62a374079bfc 100644
> --- a/net/ipv4/ipip.c
> +++ b/net/ipv4/ipip.c
> @@ -360,6 +360,9 @@ static int ipip_fill_forward_path(struct net_device_path_ctx *ctx,
>  	const struct iphdr *tiph = &tunnel->parms.iph;
>  	struct rtable *rt;
>  
> +	if (ctx->ether_type != cpu_to_be16(ETH_P_IP))
> +		return -EOPNOTSUPP;
> +
>  	if (tunnel->collect_md)
>  		return -EOPNOTSUPP;
>  
> diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
> index d80020bc2620..3bfaa98e7f33 100644
> --- a/net/ipv6/ip6_tunnel.c
> +++ b/net/ipv6/ip6_tunnel.c
> @@ -1849,6 +1849,9 @@ 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))
> +		return -EOPNOTSUPP;
> +
>  	if (t->parms.flags & (IP6_TNL_F_USE_ORIG_TCLASS |
>  			      IP6_TNL_F_USE_ORIG_FLOWLABEL |
>  			      IP6_TNL_F_USE_ORIG_FWMARK))
> diff --git a/net/netfilter/nf_flow_table_path.c b/net/netfilter/nf_flow_table_path.c
> index 0cbde535b8ba..5f166da3b09b 100644
> --- a/net/netfilter/nf_flow_table_path.c
> +++ b/net/netfilter/nf_flow_table_path.c
> @@ -44,13 +44,15 @@ static bool nft_is_valid_ether_device(const struct net_device *dev)
>  
>  static int nft_dev_fill_forward_path(const struct dst_entry *dst_cache,
>  				     const struct nf_conn *ct,
> -				     enum ip_conntrack_dir dir, u8 *ha,
> +				     enum ip_conntrack_dir dir,
> +				     u8 *ha, __be16 ether_type,
>  				     struct net_device_path_stack *stack)
>  {
>  	const void *daddr = &ct->tuplehash[!dir].tuple.src.u3;
>  	struct net_device *dev = dst_cache->dev;
>  	struct net_device_path_ctx ctx = {
>  		.dev = dev,
> +		.ether_type = ether_type,
>  	};
>  	struct neighbour *n;
>  	u8 nud_state;
> @@ -228,7 +230,7 @@ static int nft_dev_forward_path(const struct nft_pktinfo *pkt,
>  	unsigned char ha[ETH_ALEN];
>  	int i;
>  
> -	if (nft_dev_fill_forward_path(dst, ct, dir, ha, &stack) < 0 ||
> +	if (nft_dev_fill_forward_path(dst, ct, dir, ha, pkt->ethertype, &stack) < 0 ||
>  	    nft_dev_path_info(&stack, &info, ha, ft) < 0)
>  		return -ENOENT;
>  
> -- 
> 2.47.3
> 

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

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

* Re: [PATCH nf-next 3/7] netfilter: flowtable: rename tun.l3_proto to tun.inner_proto
  2026-08-06 22:35 ` [PATCH nf-next 3/7] netfilter: flowtable: rename tun.l3_proto to tun.inner_proto Pablo Neira Ayuso
@ 2026-08-07  9:01   ` Lorenzo Bianconi
  0 siblings, 0 replies; 14+ messages in thread
From: Lorenzo Bianconi @ 2026-08-07  9:01 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel, lorenzo.bianconi

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

> This field refers to the inner protocol that is encapsulated by the
> tunnel header, just a comestic change. No functional changes are
> expected.
> 
> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>

> ---
>  include/linux/netdevice.h             | 2 +-
>  include/net/netfilter/nf_flow_table.h | 2 +-
>  net/ipv4/ipip.c                       | 2 +-
>  net/ipv6/ip6_tunnel.c                 | 2 +-
>  net/netfilter/nf_flow_table_ip.c      | 6 +++---
>  net/netfilter/nf_flow_table_path.c    | 4 ++--
>  6 files changed, 9 insertions(+), 9 deletions(-)
> 
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index d9962c50bd60..68ccb5868070 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -902,7 +902,7 @@ struct net_device_path {
>  				struct in6_addr	dst_v6;
>  			};
>  
> -			u8	l3_proto;
> +			u8	inner_proto;
>  		} tun;
>  		struct {
>  			enum {
> diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
> index a090ec3ffef2..f2e2771f188f 100644
> --- a/include/net/netfilter/nf_flow_table.h
> +++ b/include/net/netfilter/nf_flow_table.h
> @@ -117,7 +117,7 @@ struct flow_offload_tunnel {
>  		struct in6_addr	dst_v6;
>  	};
>  
> -	u8	l3_proto;
> +	u8	inner_proto;
>  };
>  
>  struct flow_offload_tuple {
> diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
> index 62a374079bfc..1630325c77d3 100644
> --- a/net/ipv4/ipip.c
> +++ b/net/ipv4/ipip.c
> @@ -378,7 +378,7 @@ static int ipip_fill_forward_path(struct net_device_path_ctx *ctx,
>  	path->type = DEV_PATH_TUN;
>  	path->tun.src_v4.s_addr = tiph->saddr;
>  	path->tun.dst_v4.s_addr = tiph->daddr;
> -	path->tun.l3_proto = IPPROTO_IPIP;
> +	path->tun.inner_proto = IPPROTO_IPIP;
>  	path->tun.dst = &rt->dst;
>  	path->dev = ctx->dev;
>  
> diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
> index 3bfaa98e7f33..7b54919232ba 100644
> --- a/net/ipv6/ip6_tunnel.c
> +++ b/net/ipv6/ip6_tunnel.c
> @@ -1872,7 +1872,7 @@ 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.l3_proto = IPPROTO_IPV6;
> +		path->tun.inner_proto = IPPROTO_IPV6;
>  		path->tun.dst = dst;
>  		path->dev = ctx->dev;
>  		ctx->dev = dst->dev;
> diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
> index 0b314b10e705..e1aa01763f33 100644
> --- a/net/netfilter/nf_flow_table_ip.c
> +++ b/net/netfilter/nf_flow_table_ip.c
> @@ -197,7 +197,7 @@ static void nf_flow_tuple_encap(struct nf_flowtable_ctx *ctx,
>  		if (ctx->tun.proto == IPPROTO_IPIP) {
>  			tuple->tun.dst_v4.s_addr = iph->daddr;
>  			tuple->tun.src_v4.s_addr = iph->saddr;
> -			tuple->tun.l3_proto = IPPROTO_IPIP;
> +			tuple->tun.inner_proto = IPPROTO_IPIP;
>  		}
>  		break;
>  	case htons(ETH_P_IPV6):
> @@ -205,7 +205,7 @@ static void nf_flow_tuple_encap(struct nf_flowtable_ctx *ctx,
>  		if (ctx->tun.proto == IPPROTO_IPV6) {
>  			tuple->tun.dst_v6 = ip6h->daddr;
>  			tuple->tun.src_v6 = ip6h->saddr;
> -			tuple->tun.l3_proto = IPPROTO_IPV6;
> +			tuple->tun.inner_proto = IPPROTO_IPV6;
>  		}
>  		break;
>  	default:
> @@ -611,7 +611,7 @@ static int nf_flow_tunnel_ipip_push(struct net *net, struct sk_buff *skb,
>  	iph->version	= 4;
>  	iph->ihl	= sizeof(*iph) >> 2;
>  	iph->frag_off	= ip_mtu_locked(&rt->dst) ? 0 : frag_off;
> -	iph->protocol	= tuple->tun.l3_proto;
> +	iph->protocol	= tuple->tun.inner_proto;
>  	iph->tos	= tos;
>  	iph->daddr	= tuple->tun.src_v4.s_addr;
>  	iph->saddr	= tuple->tun.dst_v4.s_addr;
> diff --git a/net/netfilter/nf_flow_table_path.c b/net/netfilter/nf_flow_table_path.c
> index 5f166da3b09b..1e55644f2edb 100644
> --- a/net/netfilter/nf_flow_table_path.c
> +++ b/net/netfilter/nf_flow_table_path.c
> @@ -133,7 +133,7 @@ static int nft_dev_path_info(struct net_device_path_stack *stack,
>  
>  				info->tun.src_v6 = path->tun.src_v6;
>  				info->tun.dst_v6 = path->tun.dst_v6;
> -				info->tun.l3_proto = path->tun.l3_proto;
> +				info->tun.inner_proto = path->tun.inner_proto;
>  				info->tun_dst = path->tun.dst;
>  				info->num_tuns++;
>  			} else {
> @@ -245,7 +245,7 @@ static int nft_dev_forward_path(const struct nft_pktinfo *pkt,
>  	if (info.num_tuns) {
>  		route->tuple[!dir].in.tun.src_v6 = info.tun.dst_v6;
>  		route->tuple[!dir].in.tun.dst_v6 = info.tun.src_v6;
> -		route->tuple[!dir].in.tun.l3_proto = info.tun.l3_proto;
> +		route->tuple[!dir].in.tun.inner_proto = info.tun.inner_proto;
>  		route->tuple[!dir].in.num_tuns = info.num_tuns;
>  		dst_release(route->tuple[dir].dst);
>  		route->tuple[dir].dst = info.tun_dst;
> -- 
> 2.47.3
> 

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

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

* Re: [PATCH nf-next 4/7] netfilter: flowtable: rename ctx.tun.proto to ctx.tun.inner_proto
  2026-08-06 22:35 ` [PATCH nf-next 4/7] netfilter: flowtable: rename ctx.tun.proto to ctx.tun.inner_proto Pablo Neira Ayuso
@ 2026-08-07  9:02   ` Lorenzo Bianconi
  0 siblings, 0 replies; 14+ messages in thread
From: Lorenzo Bianconi @ 2026-08-07  9:02 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel, lorenzo.bianconi

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

> For consistency with the tun.l3proto rename, use same name field.
> No functional changes are intended.
> 
> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>

> ---
>  net/netfilter/nf_flow_table_ip.c | 14 +++++++-------
>  1 file changed, 7 insertions(+), 7 deletions(-)
> 
> diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
> index e1aa01763f33..ed90809b206e 100644
> --- a/net/netfilter/nf_flow_table_ip.c
> +++ b/net/netfilter/nf_flow_table_ip.c
> @@ -153,7 +153,7 @@ struct nf_flowtable_ctx {
>  		/* Tunnel IP header size */
>  		u32 hdr_size;
>  		/* IP tunnel protocol */
> -		u8 proto;
> +		u8 inner_proto;
>  	} tun;
>  };
>  
> @@ -194,7 +194,7 @@ static void nf_flow_tuple_encap(struct nf_flowtable_ctx *ctx,
>  	switch (inner_proto) {
>  	case htons(ETH_P_IP):
>  		iph = (struct iphdr *)(skb_network_header(skb) + offset);
> -		if (ctx->tun.proto == IPPROTO_IPIP) {
> +		if (ctx->tun.inner_proto == IPPROTO_IPIP) {
>  			tuple->tun.dst_v4.s_addr = iph->daddr;
>  			tuple->tun.src_v4.s_addr = iph->saddr;
>  			tuple->tun.inner_proto = IPPROTO_IPIP;
> @@ -202,7 +202,7 @@ static void nf_flow_tuple_encap(struct nf_flowtable_ctx *ctx,
>  		break;
>  	case htons(ETH_P_IPV6):
>  		ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
> -		if (ctx->tun.proto == IPPROTO_IPV6) {
> +		if (ctx->tun.inner_proto == IPPROTO_IPV6) {
>  			tuple->tun.dst_v6 = ip6h->daddr;
>  			tuple->tun.src_v6 = ip6h->saddr;
>  			tuple->tun.inner_proto = IPPROTO_IPV6;
> @@ -328,7 +328,7 @@ static bool nf_flow_ip4_tunnel_proto(struct nf_flowtable_ctx *ctx,
>  		return false;
>  
>  	if (iph->protocol == IPPROTO_IPIP) {
> -		ctx->tun.proto = iph->protocol;
> +		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,
>  		return false;
>  
>  	if (ip6h->nexthdr == IPPROTO_IPV6) {
> -		ctx->tun.proto = ip6h->nexthdr;
> +		ctx->tun.inner_proto = ip6h->nexthdr;
>  		ctx->tun.hdr_size = sizeof(*ip6h);
>  		ctx->offset += ctx->tun.hdr_size;
>  	}
> @@ -367,8 +367,8 @@ static bool nf_flow_ip6_tunnel_proto(struct nf_flowtable_ctx *ctx,
>  static void nf_flow_ip_tunnel_pop(struct nf_flowtable_ctx *ctx,
>  				  struct sk_buff *skb)
>  {
> -	if (ctx->tun.proto != IPPROTO_IPIP &&
> -	    ctx->tun.proto != IPPROTO_IPV6)
> +	if (ctx->tun.inner_proto != IPPROTO_IPIP &&
> +	    ctx->tun.inner_proto != IPPROTO_IPV6)
>  		return;
>  
>  	skb_pull(skb, ctx->tun.hdr_size);
> -- 
> 2.47.3
> 

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

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

* Re: [PATCH nf-next 5/7] netfilter: flowtable: store ethertype in flowtable context
  2026-08-06 22:35 ` [PATCH nf-next 5/7] netfilter: flowtable: store ethertype in flowtable context Pablo Neira Ayuso
@ 2026-08-07  9:10   ` Lorenzo Bianconi
  0 siblings, 0 replies; 14+ messages in thread
From: Lorenzo Bianconi @ 2026-08-07  9:10 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel, lorenzo.bianconi

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

> Add a new field to store the ethertype of the packet, skipping layer 2
> encapsulation. Store the ether_type in the context after parsing the
> layer 2 header for the first time and then use it later on.
> 
> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>

> ---
>  net/netfilter/nf_flow_table_ip.c | 47 +++++++++++++++++++-------------
>  1 file changed, 28 insertions(+), 19 deletions(-)
> 
> diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
> index ed90809b206e..4437f3a13cb2 100644
> --- a/net/netfilter/nf_flow_table_ip.c
> +++ b/net/netfilter/nf_flow_table_ip.c
> @@ -147,6 +147,7 @@ static bool ip_has_options(unsigned int thoff)
>  
>  struct nf_flowtable_ctx {
>  	const struct net_device	*in;
> +	__be16			ether_type;
>  	u32			offset;
>  	u32			hdrsize;
>  	struct {
> @@ -161,7 +162,6 @@ static void nf_flow_tuple_encap(struct nf_flowtable_ctx *ctx,
>  				struct sk_buff *skb,
>  				struct flow_offload_tuple *tuple)
>  {
> -	__be16 inner_proto = skb->protocol;
>  	struct vlan_ethhdr *veth;
>  	struct pppoe_hdr *phdr;
>  	struct ipv6hdr *ip6h;
> @@ -179,19 +179,17 @@ static void nf_flow_tuple_encap(struct nf_flowtable_ctx *ctx,
>  		veth = (struct vlan_ethhdr *)skb_mac_header(skb);
>  		tuple->encap[i].id = ntohs(veth->h_vlan_TCI);
>  		tuple->encap[i].proto = skb->protocol;
> -		inner_proto = veth->h_vlan_encapsulated_proto;
>  		offset += VLAN_HLEN;
>  		break;
>  	case htons(ETH_P_PPP_SES):
>  		phdr = (struct pppoe_hdr *)skb_network_header(skb);
>  		tuple->encap[i].id = ntohs(phdr->sid);
>  		tuple->encap[i].proto = skb->protocol;
> -		inner_proto = *((__be16 *)(phdr + 1));
>  		offset += PPPOE_SES_HLEN;
>  		break;
>  	}
>  
> -	switch (inner_proto) {
> +	switch (ctx->ether_type) {
>  	case htons(ETH_P_IP):
>  		iph = (struct iphdr *)(skb_network_header(skb) + offset);
>  		if (ctx->tun.inner_proto == IPPROTO_IPIP) {
> @@ -376,10 +374,10 @@ static void nf_flow_ip_tunnel_pop(struct nf_flowtable_ctx *ctx,
>  }
>  
>  static bool nf_flow_skb_encap_protocol(struct nf_flowtable_ctx *ctx,
> -				       struct sk_buff *skb, __be16 proto)
> +				       struct sk_buff *skb)
>  {
> -	__be16 inner_proto = skb->protocol;
>  	struct vlan_ethhdr *veth;
> +	__be16 ether_type;
>  	bool ret = false;
>  
>  	switch (skb->protocol) {
> @@ -388,22 +386,27 @@ static bool nf_flow_skb_encap_protocol(struct nf_flowtable_ctx *ctx,
>  			return false;
>  
>  		veth = (struct vlan_ethhdr *)skb_mac_header(skb);
> -		if (veth->h_vlan_encapsulated_proto == proto) {
> -			ctx->offset += VLAN_HLEN;
> -			inner_proto = proto;
> -			ret = true;
> -		}
> +		ctx->ether_type = veth->h_vlan_encapsulated_proto;
> +		ctx->offset += VLAN_HLEN;
> +		ret = true;
>  		break;
>  	case htons(ETH_P_PPP_SES):
> -		if (nf_flow_pppoe_proto(skb, &inner_proto) &&
> -		    inner_proto == proto) {
> -			ctx->offset += PPPOE_SES_HLEN;
> -			ret = true;
> -		}
> +		if (!nf_flow_pppoe_proto(skb, &ether_type))
> +			return false;
> +
> +		ctx->ether_type = ether_type;
> +		ctx->offset += PPPOE_SES_HLEN;
> +		ret = true;
> +		break;
> +	case htons(ETH_P_IP):
> +	case htons(ETH_P_IPV6):
> +		ctx->ether_type = skb->protocol;
>  		break;
> +	default:
> +		return false;
>  	}
>  
> -	switch (inner_proto) {
> +	switch (ctx->ether_type) {
>  	case htons(ETH_P_IP):
>  		ret = nf_flow_ip4_tunnel_proto(ctx, skb);
>  		break;
> @@ -455,7 +458,10 @@ nf_flow_offload_lookup(struct nf_flowtable_ctx *ctx,
>  {
>  	struct flow_offload_tuple tuple = {};
>  
> -	if (!nf_flow_skb_encap_protocol(ctx, skb, htons(ETH_P_IP)))
> +	if (!nf_flow_skb_encap_protocol(ctx, skb))
> +		return NULL;
> +
> +	if (unlikely(ctx->ether_type != htons(ETH_P_IP)))
>  		return NULL;
>  
>  	if (nf_flow_tuple_ip(ctx, skb, &tuple) < 0)
> @@ -1101,7 +1107,10 @@ nf_flow_offload_ipv6_lookup(struct nf_flowtable_ctx *ctx,
>  {
>  	struct flow_offload_tuple tuple = {};
>  
> -	if (!nf_flow_skb_encap_protocol(ctx, skb, htons(ETH_P_IPV6)))
> +	if (!nf_flow_skb_encap_protocol(ctx, skb))
> +		return NULL;
> +
> +	if (unlikely(ctx->ether_type != htons(ETH_P_IPV6)))
>  		return NULL;
>  
>  	if (nf_flow_tuple_ipv6(ctx, skb, &tuple) < 0)
> -- 
> 2.47.3
> 

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

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

* Re: [PATCH nf-next 6/7] netfilter: flowtable: move ipv4 and ipv6 xmit path to function
  2026-08-06 22:35 ` [PATCH nf-next 6/7] netfilter: flowtable: move ipv4 and ipv6 xmit path to function Pablo Neira Ayuso
@ 2026-08-07  9:13   ` Lorenzo Bianconi
  0 siblings, 0 replies; 14+ messages in thread
From: Lorenzo Bianconi @ 2026-08-07  9:13 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel, lorenzo.bianconi

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

> Move the existing ipv4 and ipv6 transmit path to functions in
> preparation of the IPv4 over IPv6 and SIT support.
> 
> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

Nice :)

Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>

> ---
>  net/netfilter/nf_flow_table_ip.c | 92 +++++++++++++++++++-------------
>  1 file changed, 54 insertions(+), 38 deletions(-)
> 
> diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
> index 4437f3a13cb2..18febca1dcef 100644
> --- a/net/netfilter/nf_flow_table_ip.c
> +++ b/net/netfilter/nf_flow_table_ip.c
> @@ -800,33 +800,17 @@ static unsigned int nf_flow_queue_xmit(struct net *net, struct sk_buff *skb,
>  	return NF_STOLEN;
>  }
>  
> -unsigned int
> -nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
> -			const struct nf_hook_state *state)
> +static int nf_flow_queue_xmit4(struct sk_buff *skb,
> +			       struct flow_offload_tuple_rhash *tuplehash,
> +			       const struct nf_hook_state *state)
>  {
> -	struct flow_offload_tuple_rhash *tuplehash;
> -	struct nf_flowtable *flow_table = priv;
>  	struct flow_offload_tuple *other_tuple;
>  	enum flow_offload_tuple_dir dir;
> -	struct nf_flowtable_ctx ctx = {
> -		.in	= state->in,
> -	};
>  	struct nf_flow_xmit xmit = {};
>  	struct flow_offload *flow;
>  	struct neighbour *neigh;
>  	struct rtable *rt;
>  	__be32 ip_daddr;
> -	int ret;
> -
> -	tuplehash = nf_flow_offload_lookup(&ctx, flow_table, skb);
> -	if (!tuplehash)
> -		return NF_ACCEPT;
> -
> -	ret = nf_flow_offload_forward(&ctx, flow_table, tuplehash, skb);
> -	if (ret < 0)
> -		return NF_DROP;
> -	else if (ret == 0)
> -		return NF_ACCEPT;
>  
>  	if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) {
>  		rt = dst_rtable(tuplehash->tuple.dst_cache);
> @@ -879,6 +863,30 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
>  
>  	return nf_flow_queue_xmit(state->net, skb, &xmit);
>  }
> +
> +unsigned int
> +nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
> +			const struct nf_hook_state *state)
> +{
> +	struct flow_offload_tuple_rhash *tuplehash;
> +	struct nf_flowtable *flow_table = priv;
> +	struct nf_flowtable_ctx ctx = {
> +		.in	= state->in,
> +	};
> +	int ret;
> +
> +	tuplehash = nf_flow_offload_lookup(&ctx, flow_table, skb);
> +	if (!tuplehash)
> +		return NF_ACCEPT;
> +
> +	ret = nf_flow_offload_forward(&ctx, flow_table, tuplehash, skb);
> +	if (ret < 0)
> +		return NF_DROP;
> +	else if (ret == 0)
> +		return NF_ACCEPT;
> +
> +	return nf_flow_queue_xmit4(skb, tuplehash, state);
> +}
>  EXPORT_SYMBOL_GPL(nf_flow_offload_ip_hook);
>  
>  static void nf_flow_nat_ipv6_tcp(struct sk_buff *skb, unsigned int thoff,
> @@ -1119,33 +1127,17 @@ nf_flow_offload_ipv6_lookup(struct nf_flowtable_ctx *ctx,
>  	return flow_offload_lookup(flow_table, &tuple);
>  }
>  
> -unsigned int
> -nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
> -			  const struct nf_hook_state *state)
> +static int nf_flow_queue_xmit6(struct sk_buff *skb,
> +			       struct flow_offload_tuple_rhash *tuplehash,
> +			       const struct nf_hook_state *state)
>  {
> -	struct flow_offload_tuple_rhash *tuplehash;
> -	struct nf_flowtable *flow_table = priv;
>  	struct flow_offload_tuple *other_tuple;
>  	enum flow_offload_tuple_dir dir;
> -	struct nf_flowtable_ctx ctx = {
> -		.in	= state->in,
> -	};
>  	struct nf_flow_xmit xmit = {};
>  	struct in6_addr *ip6_daddr;
>  	struct flow_offload *flow;
>  	struct neighbour *neigh;
>  	struct rt6_info *rt;
> -	int ret;
> -
> -	tuplehash = nf_flow_offload_ipv6_lookup(&ctx, flow_table, skb);
> -	if (tuplehash == NULL)
> -		return NF_ACCEPT;
> -
> -	ret = nf_flow_offload_ipv6_forward(&ctx, flow_table, tuplehash, skb);
> -	if (ret < 0)
> -		return NF_DROP;
> -	else if (ret == 0)
> -		return NF_ACCEPT;
>  
>  	if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) {
>  		rt = dst_rt6_info(tuplehash->tuple.dst_cache);
> @@ -1199,4 +1191,28 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
>  
>  	return nf_flow_queue_xmit(state->net, skb, &xmit);
>  }
> +
> +unsigned int
> +nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
> +			  const struct nf_hook_state *state)
> +{
> +	struct flow_offload_tuple_rhash *tuplehash;
> +	struct nf_flowtable *flow_table = priv;
> +	struct nf_flowtable_ctx ctx = {
> +		.in	= state->in,
> +	};
> +	int ret;
> +
> +	tuplehash = nf_flow_offload_ipv6_lookup(&ctx, flow_table, skb);
> +	if (!tuplehash)
> +		return NF_ACCEPT;
> +
> +	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);
> +}
>  EXPORT_SYMBOL_GPL(nf_flow_offload_ipv6_hook);
> -- 
> 2.47.3
> 

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

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

* Re: [PATCH nf-next 7/7] netfilter: flowtable: detach layer 2 encapsulation parser from lookup
  2026-08-06 22:35 ` [PATCH nf-next 7/7] netfilter: flowtable: detach layer 2 encapsulation parser from lookup Pablo Neira Ayuso
@ 2026-08-07  9:15   ` Lorenzo Bianconi
  0 siblings, 0 replies; 14+ messages in thread
From: Lorenzo Bianconi @ 2026-08-07  9:15 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel, lorenzo.bianconi

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

> Move the layer 2 encapsulation header parser out of the lookup function
> to prepare for IPv4 over IPv6 and SIT.
> 
> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>

> ---
>  net/netfilter/nf_flow_table_ip.c | 24 ++++++++++++------------
>  1 file changed, 12 insertions(+), 12 deletions(-)
> 
> diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
> index 18febca1dcef..af534000a287 100644
> --- a/net/netfilter/nf_flow_table_ip.c
> +++ b/net/netfilter/nf_flow_table_ip.c
> @@ -458,12 +458,6 @@ nf_flow_offload_lookup(struct nf_flowtable_ctx *ctx,
>  {
>  	struct flow_offload_tuple tuple = {};
>  
> -	if (!nf_flow_skb_encap_protocol(ctx, skb))
> -		return NULL;
> -
> -	if (unlikely(ctx->ether_type != htons(ETH_P_IP)))
> -		return NULL;
> -
>  	if (nf_flow_tuple_ip(ctx, skb, &tuple) < 0)
>  		return NULL;
>  
> @@ -875,6 +869,12 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
>  	};
>  	int ret;
>  
> +	if (!nf_flow_skb_encap_protocol(&ctx, skb))
> +		return NF_ACCEPT;
> +
> +	if (unlikely(ctx.ether_type != htons(ETH_P_IP)))
> +		return NF_ACCEPT;
> +
>  	tuplehash = nf_flow_offload_lookup(&ctx, flow_table, skb);
>  	if (!tuplehash)
>  		return NF_ACCEPT;
> @@ -1115,12 +1115,6 @@ nf_flow_offload_ipv6_lookup(struct nf_flowtable_ctx *ctx,
>  {
>  	struct flow_offload_tuple tuple = {};
>  
> -	if (!nf_flow_skb_encap_protocol(ctx, skb))
> -		return NULL;
> -
> -	if (unlikely(ctx->ether_type != htons(ETH_P_IPV6)))
> -		return NULL;
> -
>  	if (nf_flow_tuple_ipv6(ctx, skb, &tuple) < 0)
>  		return NULL;
>  
> @@ -1203,6 +1197,12 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
>  	};
>  	int ret;
>  
> +	if (!nf_flow_skb_encap_protocol(&ctx, skb))
> +		return NF_ACCEPT;
> +
> +	if (unlikely(ctx.ether_type != htons(ETH_P_IPV6)))
> +		return NF_ACCEPT;
> +
>  	tuplehash = nf_flow_offload_ipv6_lookup(&ctx, flow_table, skb);
>  	if (!tuplehash)
>  		return NF_ACCEPT;
> -- 
> 2.47.3
> 

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

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

end of thread, other threads:[~2026-08-07  9:15 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-06 22:35 [PATCH nf-next 0/7] flowtable preparation for IPv4 over IPv6 and SIT Pablo Neira Ayuso
2026-08-06 22:35 ` [PATCH nf-next 1/7] net: pass net_device_path_ctx to dev_fill_forward_path() Pablo Neira Ayuso
2026-08-06 22:35 ` [PATCH nf-next 2/7] net: netfilter: add ether_type to net_device_path_ctx and use it Pablo Neira Ayuso
2026-08-07  9:00   ` Lorenzo Bianconi
2026-08-06 22:35 ` [PATCH nf-next 3/7] netfilter: flowtable: rename tun.l3_proto to tun.inner_proto Pablo Neira Ayuso
2026-08-07  9:01   ` Lorenzo Bianconi
2026-08-06 22:35 ` [PATCH nf-next 4/7] netfilter: flowtable: rename ctx.tun.proto to ctx.tun.inner_proto Pablo Neira Ayuso
2026-08-07  9:02   ` Lorenzo Bianconi
2026-08-06 22:35 ` [PATCH nf-next 5/7] netfilter: flowtable: store ethertype in flowtable context Pablo Neira Ayuso
2026-08-07  9:10   ` Lorenzo Bianconi
2026-08-06 22:35 ` [PATCH nf-next 6/7] netfilter: flowtable: move ipv4 and ipv6 xmit path to function Pablo Neira Ayuso
2026-08-07  9:13   ` Lorenzo Bianconi
2026-08-06 22:35 ` [PATCH nf-next 7/7] netfilter: flowtable: detach layer 2 encapsulation parser from lookup Pablo Neira Ayuso
2026-08-07  9:15   ` 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.