All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pablo Neira Ayuso <pablo@netfilter.org>
To: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
Cc: Florian Westphal <fw@strlen.de>, Phil Sutter <phil@nwl.cc>,
	"David S. Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@google.com>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
	Simon Horman <horms@kernel.org>,
	Andrew Lunn <andrew+netdev@lunn.ch>,
	David Ahern <dsahern@kernel.org>,
	Ido Schimmel <idosch@nvidia.com>,
	netfilter-devel@vger.kernel.org, coreteam@netfilter.org,
	netdev@vger.kernel.org
Subject: Re: [PATCH nf-next v2 6/6] net: netfilter: nf_flow_table: unify tunnel push for IPv4 and IPv6
Date: Thu, 17 Sep 2026 00:14:04 +0200	[thread overview]
Message-ID: <aqsUrDjTeQBzW6gy@chamomile> (raw)
In-Reply-To: <20260907-nf-flowtable-sw-accel-ip6ip-sit-preliminary-v2-6-7c6ac1750725@oss.qualcomm.com>

On Mon, Sep 07, 2026 at 09:33:41AM +0200, Lorenzo Bianconi wrote:
> Refactor nf_flow_tunnel_ipip_push() and nf_flow_tunnel_ip6ip6_push()
> into nf_flow_tunnel_ip_push() and nf_flow_tunnel_ip6_push(), keying the
> inner header handling off tuple->tun.inner_proto so both IP-in-IP and
> IPv6-in-IPv6 inner protocols are supported regardless of the outer
> address family. Replace nf_flow_tunnel_v4_push() and
> nf_flow_tunnel_v6_push() with a single nf_flow_tunnel_push() that
> dispatches on tuple->tun.encap_proto, and set skb->protocol explicitly
> after pushing the outer header.
> 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 | 129 ++++++++++++++++++++++++---------------
>  1 file changed, 81 insertions(+), 48 deletions(-)
> 
> diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
> index 96dbdadba4e7..25875cc97bda 100644
> --- a/net/netfilter/nf_flow_table_ip.c
> +++ b/net/netfilter/nf_flow_table_ip.c
> @@ -608,23 +608,41 @@ static int nf_flow_pppoe_push(struct sk_buff *skb, u16 id,
>  	return 0;
>  }
>  
> -static int nf_flow_tunnel_ipip_push(struct net *net, struct sk_buff *skb,
> -				    struct flow_offload_tuple *tuple,
> -				    struct dst_entry *dst, __be32 *ip_daddr)
> +static int nf_flow_tunnel_ip_push(struct net *net, struct sk_buff *skb,
> +				  struct flow_offload_tuple *tuple,
> +				  struct dst_entry *dst, __be32 *ip_daddr)
>  {
> -	struct iphdr *iph = (struct iphdr *)skb_network_header(skb);
> -	struct rtable *rt = dst_rtable(dst);
> -	u8 tos = iph->tos, ttl = iph->ttl;
> -	__be16 frag_off = iph->frag_off;
> -	u32 headroom = sizeof(*iph);
> +	__be16 frag_off = 0;
> +	struct iphdr *iph;
> +	u8 tos = 0, ttl;
> +	u32 headroom;
>  	int err;
>  
> +	switch (tuple->tun.inner_proto) {
> +	case IPPROTO_IPV6: {
> +		struct ipv6hdr *ip6h;
> +
> +		ip6h = (struct ipv6hdr *)skb_network_header(skb);
> +		tos = ipv6_get_dsfield(ip6h);
> +		ttl = ip6h->hop_limit;
> +		frag_off = htons(IP_DF);
> +		break;
> +	}
> +	default:

Please add an explicit case to check for IPv4 here, ie. no default:

> +		iph = (struct iphdr *)skb_network_header(skb);
> +		frag_off = iph->frag_off;
> +		tos = iph->tos;
> +		ttl = iph->ttl;
> +		break;
> +	}
> +
>  	err = iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4);
>  	if (err)
>  		return err;
>  
> -	skb_set_inner_ipproto(skb, IPPROTO_IPIP);
> -	headroom += LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len;
> +	skb_set_inner_ipproto(skb, tuple->tun.inner_proto);
> +	headroom = sizeof(*iph) + LL_RESERVED_SPACE(dst->dev) +
> +		   dst->header_len;
>  	err = skb_cow_head(skb, headroom);
>  	if (err)
>  		return err;
> @@ -635,11 +653,12 @@ static int nf_flow_tunnel_ipip_push(struct net *net, struct sk_buff *skb,
>  	/* Push down and install the IP header. */
>  	skb_push(skb, sizeof(*iph));
>  	skb_reset_network_header(skb);
> +	skb->protocol = htons(ETH_P_IP);
>  
>  	iph = ip_hdr(skb);
>  	iph->version	= 4;
>  	iph->ihl	= sizeof(*iph) >> 2;
> -	iph->frag_off	= ip_mtu_locked(&rt->dst) ? 0 : frag_off;
> +	iph->frag_off	= ip_mtu_locked(dst) ? 0 : frag_off;
>  	iph->protocol	= tuple->tun.inner_proto;
>  	iph->tos	= tos;
>  	iph->daddr	= tuple->tun.src_v4.s_addr;
> @@ -654,57 +673,61 @@ static int nf_flow_tunnel_ipip_push(struct net *net, struct sk_buff *skb,
>  	return 0;
>  }
>  
> -static int nf_flow_tunnel_v4_push(struct net *net, struct sk_buff *skb,
> -				  struct flow_offload_tuple *tuple,
> -				  struct dst_entry *dst,  __be32 *ip_daddr)
> +static int nf_flow_tunnel_ip6_push(struct net *net, struct sk_buff *skb,
> +				   struct flow_offload_tuple *tuple,
> +				   struct dst_entry *dst,
> +				   struct in6_addr **ip6_daddr)
>  {
> -	if (tuple->tun_num)
> -		return nf_flow_tunnel_ipip_push(net, skb, tuple, dst, ip_daddr);
> -
> -	return 0;
> -}
> -
> -static int nf_flow_tunnel_ip6ip6_push(struct net *net, struct sk_buff *skb,
> -				      struct flow_offload_tuple *tuple,
> -				      struct dst_entry *dst,
> -				      struct in6_addr **ip6_daddr)
> -{
> -	struct ipv6hdr *ip6h = (struct ipv6hdr *)skb_network_header(skb);
> -	__u8 dsfield = ipv6_get_dsfield(ip6h);
> -	struct rtable *rt = dst_rtable(dst);
>  	struct flowi6 fl6 = {
>  		.daddr = tuple->tun.src_v6,
>  		.saddr = tuple->tun.dst_v6,
> -		.flowi6_proto = IPPROTO_IPV6,
> +		.flowi6_proto = tuple->tun.inner_proto,
>  	};
> -	u8 hop_limit = ip6h->hop_limit;
> +	u8 hop_limit, dsfield;
> +	struct ipv6hdr *ip6h;
>  	int err, mtu;
>  	u32 headroom;
>  
> +	switch (tuple->tun.inner_proto) {
> +	case IPPROTO_IPIP: {
> +		struct iphdr *iph = (struct iphdr *)skb_network_header(skb);
> +
> +		dsfield = ipv4_get_dsfield(iph);
> +		hop_limit = iph->ttl;
> +		break;
> +	}
> +	default:

Same here.

> +		ip6h = (struct ipv6hdr *)skb_network_header(skb);
> +		dsfield = ipv6_get_dsfield(ip6h);
> +		hop_limit = ip6h->hop_limit;
> +		break;
> +	}
> +
>  	err = iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6);
>  	if (err)
>  		return err;
>  
> -	skb_set_inner_ipproto(skb, IPPROTO_IPV6);
> -	headroom = sizeof(*ip6h) + LL_RESERVED_SPACE(rt->dst.dev) +
> -		   rt->dst.header_len;
> +	skb_set_inner_ipproto(skb, tuple->tun.inner_proto);
> +	headroom = sizeof(*ip6h) + LL_RESERVED_SPACE(dst->dev) +
> +		   dst->header_len;
>  	err = skb_cow_head(skb, headroom);
>  	if (err)
>  		return err;
>  
>  	skb_scrub_packet(skb, true);
> -	mtu = dst_mtu(&rt->dst) - sizeof(*ip6h);
> +	mtu = dst_mtu(dst) - sizeof(*ip6h);
>  	mtu = max(mtu, IPV6_MIN_MTU);
>  	skb_dst_update_pmtu_no_confirm(skb, mtu);
>  
>  	skb_push(skb, sizeof(*ip6h));
>  	skb_reset_network_header(skb);
> +	skb->protocol = htons(ETH_P_IPV6);
>  
>  	ip6h = ipv6_hdr(skb);
>  	ip6_flow_hdr(ip6h, dsfield,
>  		     ip6_make_flowlabel(net, skb, fl6.flowlabel, true, &fl6));
>  	ip6h->hop_limit = hop_limit;
> -	ip6h->nexthdr = IPPROTO_IPV6;
> +	ip6h->nexthdr = tuple->tun.inner_proto;
>  	ip6h->daddr = tuple->tun.src_v6;
>  	ip6h->saddr = tuple->tun.dst_v6;
>  	ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(*ip6h));
> @@ -715,15 +738,20 @@ static int nf_flow_tunnel_ip6ip6_push(struct net *net, struct sk_buff *skb,
>  	return 0;
>  }
>  
> -static int nf_flow_tunnel_v6_push(struct net *net, struct sk_buff *skb,
> -				  struct flow_offload_tuple *tuple,
> -				  struct dst_entry *dst,
> -				  struct in6_addr **ip6_daddr)
> +static int nf_flow_tunnel_push(struct net *net, struct sk_buff *skb,
> +			       struct flow_offload_tuple *tuple,
> +			       struct dst_entry *dst, __be32 *ip_daddr,
> +			       struct in6_addr **ip6_daddr)
>  {
> -	if (tuple->tun_num)
> -		return nf_flow_tunnel_ip6ip6_push(net, skb, tuple, dst, ip6_daddr);
> -
> -	return 0;
> +	switch (tuple->tun.encap_proto) {
> +	case AF_INET:
> +		return nf_flow_tunnel_ip_push(net, skb, tuple, dst, ip_daddr);
> +	case AF_INET6:
> +		return nf_flow_tunnel_ip6_push(net, skb, tuple, dst,
> +					       ip6_daddr);
> +	default:
> +		return 0;
> +	}
>  }
>  
>  static int nf_flow_encap_push(struct sk_buff *skb,
> @@ -830,6 +858,7 @@ static int nf_flow_queue_xmit4(struct sk_buff *skb,
>  	struct flow_offload_tuple *other_tuple;
>  	enum flow_offload_tuple_dir dir;
>  	struct nf_flow_xmit xmit = {};
> +	struct in6_addr *ip6_daddr;
>  	struct flow_offload *flow;
>  	struct neighbour *neigh;
>  	struct rtable *rt;
> @@ -847,9 +876,11 @@ static int nf_flow_queue_xmit4(struct sk_buff *skb,
>  	flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
>  	other_tuple = &flow->tuplehash[!dir].tuple;
>  	ip_daddr = other_tuple->src_v4.s_addr;
> +	ip6_daddr = &other_tuple->src_v6;
>  
> -	if (nf_flow_tunnel_v4_push(state->net, skb, other_tuple,
> -				   tuplehash->tuple.dst_cache, &ip_daddr) < 0)
> +	if (nf_flow_tunnel_push(state->net, skb, other_tuple,
> +				tuplehash->tuple.dst_cache,
> +				&ip_daddr, &ip6_daddr) < 0)

See comment below regarding this.

>  		return NF_DROP;
>  
>  	switch (tuplehash->tuple.xmit_type) {
> @@ -1158,6 +1189,7 @@ static int nf_flow_queue_xmit6(struct sk_buff *skb,
>  	struct flow_offload *flow;
>  	struct neighbour *neigh;
>  	struct rt6_info *rt;
> +	__be32 ip_daddr;
>  
>  	if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) {
>  		rt = dst_rt6_info(tuplehash->tuple.dst_cache);
> @@ -1170,11 +1202,12 @@ static int nf_flow_queue_xmit6(struct sk_buff *skb,
>  	dir = tuplehash->tuple.dir;
>  	flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
>  	other_tuple = &flow->tuplehash[!dir].tuple;
> +	ip_daddr = other_tuple->src_v4.s_addr;
>  	ip6_daddr = &other_tuple->src_v6;

IIRC this is pointing to the same address, it is a double fetch of the
same pointer? See below:

>  
> -	if (nf_flow_tunnel_v6_push(state->net, skb, other_tuple,
> -				   tuplehash->tuple.dst_cache,
> -				   &ip6_daddr) < 0)
> +	if (nf_flow_tunnel_push(state->net, skb, other_tuple,
> +				tuplehash->tuple.dst_cache,
> +				&ip_daddr, &ip6_daddr) < 0)

... time to use union nf_inet_addr here instead of these two ip_daddr
and ip6_daddr?

>  		return NF_DROP;
>  
>  	switch (tuplehash->tuple.xmit_type) {
> 
> -- 
> 2.55.0
> 
> 

  reply	other threads:[~2026-09-16 22:14 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-07  7:33 [PATCH nf-next v2 0/6] net: netfilter: preliminary support for IPv4 over IPv6 and SIT flowtable offload Lorenzo Bianconi
2026-09-07  7:33 ` [PATCH nf-next v2 1/6] net: netfilter: nf_flow_table: recognize IPv4/IPv6 in tunnel proto matching Lorenzo Bianconi
2026-09-07  7:33 ` [PATCH nf-next v2 2/6] net: netfilter: nf_flow_table: set inner protocol when popping tunnel header Lorenzo Bianconi
2026-09-07  7:33 ` [PATCH nf-next v2 3/6] net: netfilter: nf_flow_table: populate tunnel tuple regardless of inner protocol Lorenzo Bianconi
2026-09-07  7:33 ` [PATCH nf-next v2 4/6] net: netfilter: add encap_proto to flow_offload_tunnel Lorenzo Bianconi
2026-09-07  7:33 ` [PATCH nf-next v2 5/6] net: netfilter: nf_flow_table: refactor MTU check for tunnel offload Lorenzo Bianconi
2026-09-07  7:33 ` [PATCH nf-next v2 6/6] net: netfilter: nf_flow_table: unify tunnel push for IPv4 and IPv6 Lorenzo Bianconi
2026-09-16 22:14   ` Pablo Neira Ayuso [this message]
2026-09-17  8:26     ` Lorenzo Bianconi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aqsUrDjTeQBzW6gy@chamomile \
    --to=pablo@netfilter.org \
    --cc=andrew+netdev@lunn.ch \
    --cc=coreteam@netfilter.org \
    --cc=davem@davemloft.net \
    --cc=dsahern@kernel.org \
    --cc=edumazet@google.com \
    --cc=fw@strlen.de \
    --cc=horms@kernel.org \
    --cc=idosch@nvidia.com \
    --cc=kuba@kernel.org \
    --cc=lorenzo.bianconi@oss.qualcomm.com \
    --cc=netdev@vger.kernel.org \
    --cc=netfilter-devel@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=phil@nwl.cc \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.