All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Michael S. Tsirkin" <mst@redhat.com>
To: "Björn Töpel" <bjorn@kernel.org>
Cc: linux-kernel@vger.kernel.org,
	"Willem de Bruijn" <willemdebruijn.kernel@gmail.com>,
	"Jason Wang" <jasowangio@gmail.com>,
	"Eugenio Pérez" <eperezma@redhat.com>,
	"Xuan Zhuo" <xuanzhuo@linux.alibaba.com>,
	"Andrew Lunn" <andrew+netdev@lunn.ch>,
	"David S. Miller" <davem@davemloft.net>,
	"Eric Dumazet" <edumazet@kernel.org>,
	"Jakub Kicinski" <kuba@kernel.org>,
	"Paolo Abeni" <pabeni@redhat.com>,
	netdev@vger.kernel.org, virtualization@lists.linux.dev,
	"Max Krasnyansky" <maxk@qualcomm.com>,
	"Rusty Russell" <rusty@rustcorp.com.au>,
	"Simon Horman" <horms@kernel.org>
Subject: Re: [PATCH net-next 4/4] net: account for ingress-resolved virtio net hdr state
Date: Tue, 13 Oct 2026 14:12:37 -0400	[thread overview]
Message-ID: <20261013141050-mutt-send-email-mst@kernel.org> (raw)
In-Reply-To: <87ld81a40i.fsf@all.your.base.are.belong.to.us>

On Tue, Oct 13, 2026 at 07:45:17PM +0200, Björn Töpel wrote:
> "Michael S. Tsirkin" <mst@redhat.com> writes:
> 
> > Ingress resolution of uncommon virtio net hdr checksum metadata
> > (software checksum completion at ingress) adds performance overhead but
> > is currently invisible: no counter tracks it, so a hypothetical workload
> > relying on uncommon metadata cannot be distinguished from none at all,
> > and packets quietly pay the host-CPU checksum overhead instead of offload.
> >
> > Have virtio_net_hdr_to_skb() return 1 when it completes an uncommon
> > checksum in software, and flip every converter call site to test for
> > negative errno.  Have tun count these events per device as
> > rx_csum_sw and expose the counter via ethtool -S.
> >
> > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > Assisted-by: LLM
> > Fixes: f43798c27684 ("tun: Allow GSO using virtio_net_hdr")
> >
> > ---
> >  drivers/net/tap.c          |  4 ++--
> >  drivers/net/tun.c          | 44 ++++++++++++++++++++++++++++++++++++--
> >  drivers/net/virtio_net.c   |  2 +-
> >  include/linux/virtio_net.h | 12 +++++++++--
> >  net/packet/af_packet.c     |  4 ++--
> >  5 files changed, 57 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/net/tap.c b/drivers/net/tap.c
> > index ff67d99deb39e..73e8833944463 100644
> > --- a/drivers/net/tap.c
> > +++ b/drivers/net/tap.c
> > @@ -649,7 +649,7 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
> >  
> >  	if (vnet_hdr_len) {
> >  		err = tun_vnet_hdr_to_skb(q->flags, skb, &vnet_hdr);
> > -		if (err) {
> > +		if (err < 0) {
> >  			rcu_read_unlock();
> >  			drop_reason = SKB_DROP_REASON_DEV_HDR;
> >  			goto err_kfree;
> > @@ -1084,7 +1084,7 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp)
> >  
> >  	if (vnet_hdr_len) {
> >  		err = tun_vnet_hdr_to_skb(q->flags, skb, gso);
> > -		if (err) {
> > +		if (err < 0) {
> >  			rcu_read_unlock();
> >  			goto err_kfree;
> >  		}
> > diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> > index 242899f7fd071..138ca8987dfc6 100644
> > --- a/drivers/net/tun.c
> > +++ b/drivers/net/tun.c
> > @@ -210,6 +210,7 @@ struct tun_struct {
> >  	u32 flow_count;
> >  	u32 rx_batched;
> >  	atomic_long_t rx_frame_errors;
> > +	atomic_long_t rx_csum_sw;
> >  	struct bpf_prog __rcu *xdp_prog;
> >  	struct tun_prog __rcu *steering_prog;
> >  	struct tun_prog __rcu *filter_prog;
> > @@ -1935,11 +1936,19 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
> >  		break;
> >  	}
> >  
> > -	if (tun_vnet_hdr_tnl_to_skb(tun->flags, features, skb, &hdr)) {
> > +	err = tun_vnet_hdr_tnl_to_skb(tun->flags, features, skb, &hdr);
> > +	if (err < 0) {
> >  		atomic_long_inc(&tun->rx_frame_errors);
> >  		err = -EINVAL;
> >  		goto free_skb;
> >  	}
> > +	if (err > 0)
> > +		atomic_long_inc(&tun->rx_csum_sw);
> > +	/* The status is consumed: keep err clear so later exit paths
> > +	 * (XDP drop via unlock_frags) do not return it to write() as
> > +	 * a short count.
> > +	 */
> > +	err = 0;
> >  
> >  	if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP)
> >  		skb->protocol = eth_type_trans(skb, tun->dev);
> > @@ -2605,12 +2614,15 @@ static int tun_xdp_one(struct tun_struct *tun,
> >  	tnl_hdr = (struct virtio_net_hdr_v1_hash_tunnel *)gso;
> >  	skb->dev = tun->dev;
> >  	skb_set_network_header(skb, ETH_HLEN);
> > -	if (tun_vnet_hdr_tnl_to_skb(tun->flags, features, skb, tnl_hdr)) {
> > +	ret = tun_vnet_hdr_tnl_to_skb(tun->flags, features, skb, tnl_hdr);
> > +	if (ret < 0) {
> >  		atomic_long_inc(&tun->rx_frame_errors);
> >  		kfree_skb(skb);
> >  		ret = -EINVAL;
> >  		goto out;
> >  	}
> > +	if (ret > 0)
> > +		atomic_long_inc(&tun->rx_csum_sw);
> >  
> >  	skb->protocol = eth_type_trans(skb, tun->dev);
> >  	skb_reset_network_header(skb);
> > @@ -3739,7 +3751,35 @@ static void tun_get_channels(struct net_device *dev,
> >  	channels->max_combined = tun->flags & IFF_MULTI_QUEUE ? MAX_TAP_QUEUES : 1;
> >  }
> >  
> > +#define TUN_STATS_LEN	1
> > +static const char tun_ethtool_strings[TUN_STATS_LEN][ETH_GSTRING_LEN] = {
> > +	"rx_csum_sw",
> > +};
> > +
> > +static int tun_get_sset_count(struct net_device *dev, int sset)
> > +{
> > +	return sset == ETH_SS_STATS ? TUN_STATS_LEN : -EOPNOTSUPP;
> > +}
> > +
> > +static void tun_get_strings(struct net_device *dev, u32 stringset, u8 *data)
> > +{
> > +	if (stringset == ETH_SS_STATS)
> > +		memcpy(data, tun_ethtool_strings,
> > +		       sizeof(tun_ethtool_strings));
> > +}
> > +
> > +static void tun_get_ethtool_stats(struct net_device *dev,
> > +				  struct ethtool_stats *stats, u64 *data)
> > +{
> > +	struct tun_struct *tun = netdev_priv(dev);
> > +
> > +	data[0] = atomic_long_read(&tun->rx_csum_sw);
> > +}
> > +
> >  static const struct ethtool_ops tun_ethtool_ops = {
> > +	.get_sset_count		= tun_get_sset_count,
> > +	.get_strings		= tun_get_strings,
> > +	.get_ethtool_stats	= tun_get_ethtool_stats,
> >  	.supported_coalesce_params = ETHTOOL_COALESCE_RX_MAX_FRAMES,
> >  	.get_drvinfo	= tun_get_drvinfo,
> >  	.get_msglevel	= tun_get_msglevel,
> > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > index daab43ac92ce4..2e6fd81df9c41 100644
> > --- a/drivers/net/virtio_net.c
> > +++ b/drivers/net/virtio_net.c
> > @@ -2519,7 +2519,7 @@ static void virtnet_receive_done(struct virtnet_info *vi, struct receive_queue *
> >  	skb_set_network_header(skb, ETH_HLEN);
> >  	if (virtio_net_hdr_tnl_to_skb(skb, &hdr->tnl_hdr, vi->rx_tnl,
> >  				      vi->rx_tnl_csum,
> > -				      virtio_is_little_endian(vi->vdev))) {
> > +				      virtio_is_little_endian(vi->vdev)) < 0) {
> >  		net_warn_ratelimited("%s: bad gso: type: %x, size: %u, flags %x tunnel %d tnl csum %d\n",
> >  				     dev->name, hdr->hdr.gso_type,
> >  				     hdr->hdr.gso_size, hdr->hdr.flags,
> > diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
> > index b181183118b3a..d8447db58ac83 100644
> > --- a/include/linux/virtio_net.h
> > +++ b/include/linux/virtio_net.h
> > @@ -14,6 +14,14 @@
> >  #include <uapi/linux/tcp.h>
> >  #include <uapi/linux/virtio_net.h>
> >  
> > +/*
> > + * virtio_net_hdr_to_skb() and virtio_net_hdr_tnl_to_skb() return 0 on
> > + * success and a negative errno on failure.  On success they may also
> > + * return 1, indicating that an uncommon checksum was completed in
> > + * software at ingress rather than deferred to the egress path;
> > + * drivers can use this to account for such packets.
> > + */
> > +
> >  static inline bool virtio_net_hdr_match_proto(__be16 protocol, __u8 gso_type)
> >  {
> >  	switch (gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
> > @@ -292,7 +300,7 @@ static inline int __virtio_net_hdr_to_skb(struct sk_buff *skb,
> >  
> >  		err = skb_checksum_help(skb);
> >  		skb->transport_header = old_transport;
> > -		return err;
> > +		return err ?: 1;
> >  	}
> >  
> >  	return 0;
> > @@ -441,7 +449,7 @@ virtio_net_hdr_tnl_to_skb(struct sk_buff *skb,
> >  	/* Let the basic parsing deal with plain GSO features. */
> >  	ret = __virtio_net_hdr_to_skb(skb, hdr, true,
> >  				      hdr->gso_type & ~gso_tunnel_type, false);
> > -	if (ret)
> > +	if (ret < 0)
> >  		return ret;
> >  
> >  	/* In case of USO, the inner protocol is still unknown and
> > diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
> > index 52ae3d875e971..e6aec9ecfa994 100644
> > --- a/net/packet/af_packet.c
> > +++ b/net/packet/af_packet.c
> > @@ -2913,7 +2913,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
> >  		}
> >  
> >  		if (has_vnet_hdr) {
> > -			if (virtio_net_hdr_to_skb(skb, &vnet_hdr, vio_le())) {
> > +			if (virtio_net_hdr_to_skb(skb, &vnet_hdr, vio_le()) < 0) {
> 
> nit: I don't know if we care, but this sort of breaks bisectability.
> Previous patch does return ret ?: 1, but it's this patch that does the
> if-statement fixup. (Same for tun/tap... ^^^)
> 

Oh ugh. You are right, I kept rebasing to tweak things and moved it
by chance. I'll fix it up in v2.


> Björn


  reply	other threads:[~2026-10-13 18:12 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-13 10:58 [PATCH net-next 0/4] more virtio-net csum hardening Michael S. Tsirkin
2026-10-13 10:58 ` [PATCH net-next 1/4] net: add ip4_parse() Michael S. Tsirkin
2026-10-13 11:15   ` sashiko-bot
2026-10-13 10:58 ` [PATCH net-next 2/4] net: use ip4_parse() in receive validation Michael S. Tsirkin
2026-10-13 11:15   ` sashiko-bot
2026-10-13 10:58 ` [PATCH net-next 3/4] net: resolve uncommon partial checksums at ingress Michael S. Tsirkin
2026-10-13 11:06   ` Michael S. Tsirkin
2026-10-13 15:03     ` Willem de Bruijn
2026-10-13 18:35       ` Michael S. Tsirkin
2026-10-13 11:15   ` sashiko-bot
2026-10-13 10:58 ` [PATCH net-next 4/4] net: account for ingress-resolved virtio net hdr state Michael S. Tsirkin
2026-10-13 11:15   ` sashiko-bot
2026-10-13 17:45   ` Björn Töpel
2026-10-13 18:12     ` Michael S. Tsirkin [this message]
2026-10-13 11:05 ` [PATCH net-next 0/4] more virtio-net csum hardening Michael S. Tsirkin
2026-10-13 18:51   ` Chris Arges
2026-10-13 14:41 ` Willem de Bruijn
2026-10-13 18:41   ` Michael S. Tsirkin

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=20261013141050-mutt-send-email-mst@kernel.org \
    --to=mst@redhat.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=bjorn@kernel.org \
    --cc=davem@davemloft.net \
    --cc=edumazet@kernel.org \
    --cc=eperezma@redhat.com \
    --cc=horms@kernel.org \
    --cc=jasowangio@gmail.com \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=maxk@qualcomm.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=rusty@rustcorp.com.au \
    --cc=virtualization@lists.linux.dev \
    --cc=willemdebruijn.kernel@gmail.com \
    --cc=xuanzhuo@linux.alibaba.com \
    /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.