All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pablo Neira Ayuso <pablo@netfilter.org>
To: Julius Bairaktaris <julius@bairaktaris.de>
Cc: netfilter-devel@vger.kernel.org, fw@strlen.de, phil@nwl.cc,
	coreteam@netfilter.org, netdev@vger.kernel.org,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, horms@kernel.org, andrew+netdev@lunn.ch,
	shuah@kernel.org, linux-kselftest@vger.kernel.org,
	linux-kernel@vger.kernel.org, nbd@nbd.name
Subject: Re: [PATCH nf-next 2/3] netfilter: flowtable: update upper device stats in the fast path
Date: Sun, 18 Oct 2026 03:53:40 +0200	[thread overview]
Message-ID: <atQmpPlfT_DSd9dq@chamomile> (raw)
In-Reply-To: <20261004171616.3544880-3-julius@bairaktaris.de>

On Sun, Oct 04, 2026 at 07:16:15PM +0200, Julius Bairaktaris wrote:
> The software fast path receives and transmits on the lowest devices of
> the input and output stacks, so the bridge, VLAN, PPPoE and tunnel
> devices above them stop counting after the first packets of a
> connection.
> 
> Store the ifindexes of these devices from the forward path and update
> their counters from the fast path. Each device counts what it counts in
> the classic path: the IP packet plus the headers of the devices above it
> (PPPoE, outer IP, inner VLAN tag), plus the Ethernet header on transmit
> for Ethernet devices.
> 
> A GSO packet sent through a PPPoE device is counted once. The classic
> path segments it in front of the ppp device and counts every segment.
> 
> struct flow_offload grows from 296 to 328 bytes.
> 
> Assisted-by: Claude:claude-fable-5-1

This does not look very good...

I mentioned it is a feature that these counters are not bumped,
because packets are not passing through this devices in the bypass.

This allows users to see what packets follow classic path?

But if you insist, then explore a way to synchronize these counters
offline (ie. not from packet path) to see how it looks like.

Even though, I'm not sure lying to userspace that packets are going
through these devices via stats can be right.

> Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
> ---
>  include/net/netfilter/nf_flow_table.h |  8 +++-
>  net/netfilter/nf_flow_table_core.c    |  3 ++
>  net/netfilter/nf_flow_table_ip.c      | 53 +++++++++++++++++++++++++++
>  net/netfilter/nf_flow_table_path.c    |  9 +++++
>  4 files changed, 72 insertions(+), 1 deletion(-)
> 
> diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
> index f2e2771f188f..1f451fcf05d0 100644
> --- a/include/net/netfilter/nf_flow_table.h
> +++ b/include/net/netfilter/nf_flow_table.h
> @@ -106,6 +106,8 @@ enum flow_offload_xmit_type {
>  };
>  
>  #define NF_FLOW_TABLE_ENCAP_MAX		2
> +/* Devices above the flowtable device in a forward path. */
> +#define NF_FLOW_TABLE_UPPER_MAX		(NET_DEVICE_PATH_STACK_MAX - 1)
>  
>  struct flow_offload_tunnel {
>  	union {
> @@ -153,7 +155,8 @@ struct flow_offload_tuple {
>  					encap_num:2,
>  					needs_gso_segment:1,
>  					tun_num:2,
> -					in_vlan_ingress:2;
> +					in_vlan_ingress:2,
> +					num_uppers:3;
>  	u16				mtu;
>  	u32				dst_cookie;
>  	struct dst_entry		*dst_cache;
> @@ -171,6 +174,7 @@ struct flow_offload_tuple {
>  			u32		iifidx;
>  		} tc;
>  	};
> +	u32				upper_ifidx[NF_FLOW_TABLE_UPPER_MAX];
>  };
>  
>  struct flow_offload_tuple_rhash {
> @@ -228,6 +232,8 @@ struct nf_flow_route {
>  			u8			num_encaps:2,
>  						num_tuns:2,
>  						ingress_vlans:2;
> +			u32			upper_ifidx[NF_FLOW_TABLE_UPPER_MAX];
> +			u8			num_uppers;
>  		} in;
>  		struct {
>  			u32			ifindex;
> diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
> index 03241d4bfd5e..2c9a0d97c9fb 100644
> --- a/net/netfilter/nf_flow_table_core.c
> +++ b/net/netfilter/nf_flow_table_core.c
> @@ -122,6 +122,9 @@ static int flow_offload_fill_route(struct flow_offload *flow,
>  
>  	flow_tuple->tun = route->tuple[dir].in.tun;
>  	flow_tuple->encap_num = route->tuple[dir].in.num_encaps;
> +	memcpy(flow_tuple->upper_ifidx, route->tuple[dir].in.upper_ifidx,
> +	       sizeof(flow_tuple->upper_ifidx));
> +	flow_tuple->num_uppers = route->tuple[dir].in.num_uppers;
>  	flow_tuple->needs_gso_segment = route->tuple[dir].out.needs_gso_segment;
>  	flow_tuple->tun_num = route->tuple[dir].in.num_tuns;
>  
> diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
> index c8c29a9a1684..e1a3511d5f1f 100644
> --- a/net/netfilter/nf_flow_table_ip.c
> +++ b/net/netfilter/nf_flow_table_ip.c
> @@ -453,6 +453,49 @@ static void nf_flow_encap_pop(struct nf_flowtable_ctx *ctx,
>  		nf_flow_ip_tunnel_pop(ctx, skb);
>  }
>  
> +/* The fast path bypasses the devices above the flowtable device. */
> +static void nf_flow_upper_stats_add(struct net *net,
> +				    const struct flow_offload_tuple *tuple,
> +				    bool rx, unsigned int len)
> +{
> +	unsigned int n, vlan_hlen = 0;
> +	struct net_device *dev;
> +	int i;
> +
> +	for (i = 0; i < tuple->num_uppers; i++) {
> +		dev = dev_get_by_index_rcu(net, tuple->upper_ifidx[i]);
> +		if (!dev)
> +			continue;
> +
> +		n = len;
> +		if (!rx && dev->type == ARPHRD_ETHER)
> +			n += ETH_HLEN;
> +
> +		if (is_vlan_dev(dev)) {
> +			/* Q-in-Q: the outer VLAN device counts the inner tag. */
> +			n += vlan_hlen;
> +			if (rx)
> +				vlan_dev_sw_netstats_rx_add(dev, n);
> +			else
> +				vlan_dev_sw_netstats_tx_add(dev, 1, n);
> +			vlan_hlen += VLAN_HLEN;
> +		} else if (dev->pcpu_stat_type == NETDEV_PCPU_STAT_TSTATS) {
> +			if (rx)
> +				dev_sw_netstats_rx_add(dev, n);
> +			else
> +				dev_sw_netstats_tx_add(dev, 1, n);
> +		}
> +
> +		/* The devices below also count this device's header. */
> +		if (dev->type == ARPHRD_PPP)
> +			len += PPPOE_SES_HLEN;
> +		else if (dev->type == ARPHRD_TUNNEL)
> +			len += sizeof(struct iphdr);
> +		else if (dev->type == ARPHRD_TUNNEL6)
> +			len += sizeof(struct ipv6hdr);
> +	}
> +}
> +
>  static struct flow_offload_tuple_rhash *
>  nf_flow_offload_lookup(struct nf_flowtable_ctx *ctx,
>  		       struct nf_flowtable *flow_table, struct sk_buff *skb)
> @@ -512,6 +555,11 @@ static int nf_flow_offload_forward(struct nf_flowtable_ctx *ctx,
>  	if (flow_table->flags & NF_FLOWTABLE_COUNTER)
>  		nf_ct_acct_update(flow->ct, tuplehash->tuple.dir, skb->len);
>  
> +	nf_flow_upper_stats_add(dev_net(ctx->in), &tuplehash->tuple, true,
> +				skb->len);
> +	nf_flow_upper_stats_add(dev_net(ctx->in), &flow->tuplehash[!dir].tuple,
> +				false, skb->len);
> +
>  	return 1;
>  }
>  
> @@ -1107,6 +1155,11 @@ static int nf_flow_offload_ipv6_forward(struct nf_flowtable_ctx *ctx,
>  	if (flow_table->flags & NF_FLOWTABLE_COUNTER)
>  		nf_ct_acct_update(flow->ct, tuplehash->tuple.dir, skb->len);
>  
> +	nf_flow_upper_stats_add(dev_net(ctx->in), &tuplehash->tuple, true,
> +				skb->len);
> +	nf_flow_upper_stats_add(dev_net(ctx->in), &flow->tuplehash[!dir].tuple,
> +				false, skb->len);
> +
>  	return 1;
>  }
>  
> diff --git a/net/netfilter/nf_flow_table_path.c b/net/netfilter/nf_flow_table_path.c
> index 1e55644f2edb..ba5ac3ebe614 100644
> --- a/net/netfilter/nf_flow_table_path.c
> +++ b/net/netfilter/nf_flow_table_path.c
> @@ -83,6 +83,8 @@ static int nft_dev_fill_forward_path(const struct dst_entry *dst_cache,
>  
>  struct nft_forward_info {
>  	const struct net_device *dev;
> +	u32 upper_ifidx[NF_FLOW_TABLE_UPPER_MAX];
> +	u8 num_uppers;
>  	struct id {
>  		__u16	id;
>  		__be16	proto;
> @@ -187,6 +189,10 @@ static int nft_dev_path_info(struct net_device_path_stack *stack,
>  		}
>  	}
>  
> +	for (i = 0; info->dev && stack->path[i].dev != info->dev; i++)
> +		info->upper_ifidx[i] = stack->path[i].dev->ifindex;
> +	info->num_uppers = i;
> +
>  	if (nf_flowtable_hw_offload(&ft->data) &&
>  	    nft_is_valid_ether_device(info->dev))
>  		info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
> @@ -253,6 +259,9 @@ static int nft_dev_forward_path(const struct nft_pktinfo *pkt,
>  
>  	route->tuple[!dir].in.num_encaps = info.num_encaps;
>  	route->tuple[!dir].in.ingress_vlans = info.ingress_vlans;
> +	memcpy(route->tuple[!dir].in.upper_ifidx, info.upper_ifidx,
> +	       sizeof(info.upper_ifidx));
> +	route->tuple[!dir].in.num_uppers = info.num_uppers;
>  
>  	if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) {
>  		memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN);
> -- 
> 2.53.0
> 

  reply	other threads:[~2026-10-18  1:53 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-04 17:16 [PATCH nf-next 0/3] netfilter: flowtable: update upper device stats in the fast path Julius Bairaktaris
2026-10-04 17:16 ` [PATCH nf-next 1/3] 8021q: add vlan_dev_sw_netstats_rx_add() and vlan_dev_sw_netstats_tx_add() Julius Bairaktaris
2026-10-04 17:16 ` [PATCH nf-next 2/3] netfilter: flowtable: update upper device stats in the fast path Julius Bairaktaris
2026-10-18  1:53   ` Pablo Neira Ayuso [this message]
2026-10-18  2:53     ` Julius Bairaktaris
2026-10-04 17:16 ` [PATCH nf-next 3/3] selftests: netfilter: nft_flowtable.sh: check upper device counters Julius Bairaktaris
2026-10-17 10:37 ` [PATCH nf-next 0/3] netfilter: flowtable: update upper device stats in the fast path Julius Bairaktaris

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=atQmpPlfT_DSd9dq@chamomile \
    --to=pablo@netfilter.org \
    --cc=andrew+netdev@lunn.ch \
    --cc=coreteam@netfilter.org \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=fw@strlen.de \
    --cc=horms@kernel.org \
    --cc=julius@bairaktaris.de \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=nbd@nbd.name \
    --cc=netdev@vger.kernel.org \
    --cc=netfilter-devel@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=phil@nwl.cc \
    --cc=shuah@kernel.org \
    /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.