Message ID | 20250109-tun-v2-3-388d7d5a287a@daynix.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | tun: Unify vnet implementation and fill full vnet header | expand |
On Thu, Jan 09, 2025 at 03:58:45PM +0900, Akihiko Odaki wrote: > The specification says the device MUST set num_buffers to 1 if > VIRTIO_NET_F_MRG_RXBUF has not been negotiated. > > Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> How do we know this is v1 and not v0? Confused. > --- > drivers/net/tap.c | 2 +- > drivers/net/tun.c | 6 ++++-- > drivers/net/tun_vnet.c | 14 +++++++++----- > drivers/net/tun_vnet.h | 4 ++-- > 4 files changed, 16 insertions(+), 10 deletions(-) > > diff --git a/drivers/net/tap.c b/drivers/net/tap.c > index 60804855510b..fe9554ee5b8b 100644 > --- a/drivers/net/tap.c > +++ b/drivers/net/tap.c > @@ -713,7 +713,7 @@ static ssize_t tap_put_user(struct tap_queue *q, > int total; > > if (q->flags & IFF_VNET_HDR) { > - struct virtio_net_hdr vnet_hdr; > + struct virtio_net_hdr_v1 vnet_hdr; > > vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz); > > diff --git a/drivers/net/tun.c b/drivers/net/tun.c > index dbf0dee92e93..f211d0580887 100644 > --- a/drivers/net/tun.c > +++ b/drivers/net/tun.c > @@ -1991,7 +1991,9 @@ static ssize_t tun_put_user_xdp(struct tun_struct *tun, > size_t total; > > if (tun->flags & IFF_VNET_HDR) { > - struct virtio_net_hdr gso = { 0 }; > + struct virtio_net_hdr_v1 gso = { > + .num_buffers = __virtio16_to_cpu(true, 1) > + }; > > vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz); > ret = tun_vnet_hdr_put(vnet_hdr_sz, iter, &gso); > @@ -2044,7 +2046,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, > } > > if (vnet_hdr_sz) { > - struct virtio_net_hdr gso; > + struct virtio_net_hdr_v1 gso; > > ret = tun_vnet_hdr_from_skb(tun->flags, tun->dev, skb, &gso); > if (ret < 0) > diff --git a/drivers/net/tun_vnet.c b/drivers/net/tun_vnet.c > index ffb2186facd3..a7a7989fae56 100644 > --- a/drivers/net/tun_vnet.c > +++ b/drivers/net/tun_vnet.c > @@ -130,15 +130,17 @@ int tun_vnet_hdr_get(int sz, unsigned int flags, struct iov_iter *from, > EXPORT_SYMBOL_GPL(tun_vnet_hdr_get); > > int tun_vnet_hdr_put(int sz, struct iov_iter *iter, > - const struct virtio_net_hdr *hdr) > + const struct virtio_net_hdr_v1 *hdr) > { > + int content_sz = MIN(sizeof(*hdr), sz); > + > if (iov_iter_count(iter) < sz) > return -EINVAL; > > - if (copy_to_iter(hdr, sizeof(*hdr), iter) != sizeof(*hdr)) > + if (copy_to_iter(hdr, content_sz, iter) != content_sz) > return -EFAULT; > > - if (iov_iter_zero(sz - sizeof(*hdr), iter) != sz - sizeof(*hdr)) > + if (iov_iter_zero(sz - content_sz, iter) != sz - content_sz) > return -EFAULT; > > return 0; > @@ -154,11 +156,11 @@ EXPORT_SYMBOL_GPL(tun_vnet_hdr_to_skb); > > int tun_vnet_hdr_from_skb(unsigned int flags, const struct net_device *dev, > const struct sk_buff *skb, > - struct virtio_net_hdr *hdr) > + struct virtio_net_hdr_v1 *hdr) > { > int vlan_hlen = skb_vlan_tag_present(skb) ? VLAN_HLEN : 0; > > - if (virtio_net_hdr_from_skb(skb, hdr, > + if (virtio_net_hdr_from_skb(skb, (struct virtio_net_hdr *)hdr, > tun_vnet_is_little_endian(flags), true, > vlan_hlen)) { > struct skb_shared_info *sinfo = skb_shinfo(skb); > @@ -176,6 +178,8 @@ int tun_vnet_hdr_from_skb(unsigned int flags, const struct net_device *dev, > return -EINVAL; > } > > + hdr->num_buffers = 1; > + > return 0; > } > EXPORT_SYMBOL_GPL(tun_vnet_hdr_from_skb); > diff --git a/drivers/net/tun_vnet.h b/drivers/net/tun_vnet.h > index 2dfdbe92bb24..d8fd94094227 100644 > --- a/drivers/net/tun_vnet.h > +++ b/drivers/net/tun_vnet.h > @@ -12,13 +12,13 @@ int tun_vnet_hdr_get(int sz, unsigned int flags, struct iov_iter *from, > struct virtio_net_hdr *hdr); > > int tun_vnet_hdr_put(int sz, struct iov_iter *iter, > - const struct virtio_net_hdr *hdr); > + const struct virtio_net_hdr_v1 *hdr); > > int tun_vnet_hdr_to_skb(unsigned int flags, struct sk_buff *skb, > const struct virtio_net_hdr *hdr); > > int tun_vnet_hdr_from_skb(unsigned int flags, const struct net_device *dev, > const struct sk_buff *skb, > - struct virtio_net_hdr *hdr); > + struct virtio_net_hdr_v1 *hdr); > > #endif /* TUN_VNET_H */ > > -- > 2.47.1
On Thu, Jan 09, 2025 at 02:32:25AM -0500, Michael S. Tsirkin wrote: > On Thu, Jan 09, 2025 at 03:58:45PM +0900, Akihiko Odaki wrote: > > The specification says the device MUST set num_buffers to 1 if > > VIRTIO_NET_F_MRG_RXBUF has not been negotiated. > > > > Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> > > > How do we know this is v1 and not v0? Confused. Ah I got it, you assume userspace will over-write it if VIRTIO_NET_F_MRG_RXBUF is set. If we are leaving this up to userspace, why not let it do it always? > > --- > > drivers/net/tap.c | 2 +- > > drivers/net/tun.c | 6 ++++-- > > drivers/net/tun_vnet.c | 14 +++++++++----- > > drivers/net/tun_vnet.h | 4 ++-- > > 4 files changed, 16 insertions(+), 10 deletions(-) > > > > diff --git a/drivers/net/tap.c b/drivers/net/tap.c > > index 60804855510b..fe9554ee5b8b 100644 > > --- a/drivers/net/tap.c > > +++ b/drivers/net/tap.c > > @@ -713,7 +713,7 @@ static ssize_t tap_put_user(struct tap_queue *q, > > int total; > > > > if (q->flags & IFF_VNET_HDR) { > > - struct virtio_net_hdr vnet_hdr; > > + struct virtio_net_hdr_v1 vnet_hdr; > > > > vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz); > > > > diff --git a/drivers/net/tun.c b/drivers/net/tun.c > > index dbf0dee92e93..f211d0580887 100644 > > --- a/drivers/net/tun.c > > +++ b/drivers/net/tun.c > > @@ -1991,7 +1991,9 @@ static ssize_t tun_put_user_xdp(struct tun_struct *tun, > > size_t total; > > > > if (tun->flags & IFF_VNET_HDR) { > > - struct virtio_net_hdr gso = { 0 }; > > + struct virtio_net_hdr_v1 gso = { > > + .num_buffers = __virtio16_to_cpu(true, 1) > > + }; > > > > vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz); > > ret = tun_vnet_hdr_put(vnet_hdr_sz, iter, &gso); > > @@ -2044,7 +2046,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, > > } > > > > if (vnet_hdr_sz) { > > - struct virtio_net_hdr gso; > > + struct virtio_net_hdr_v1 gso; > > > > ret = tun_vnet_hdr_from_skb(tun->flags, tun->dev, skb, &gso); > > if (ret < 0) > > diff --git a/drivers/net/tun_vnet.c b/drivers/net/tun_vnet.c > > index ffb2186facd3..a7a7989fae56 100644 > > --- a/drivers/net/tun_vnet.c > > +++ b/drivers/net/tun_vnet.c > > @@ -130,15 +130,17 @@ int tun_vnet_hdr_get(int sz, unsigned int flags, struct iov_iter *from, > > EXPORT_SYMBOL_GPL(tun_vnet_hdr_get); > > > > int tun_vnet_hdr_put(int sz, struct iov_iter *iter, > > - const struct virtio_net_hdr *hdr) > > + const struct virtio_net_hdr_v1 *hdr) > > { > > + int content_sz = MIN(sizeof(*hdr), sz); > > + > > if (iov_iter_count(iter) < sz) > > return -EINVAL; > > > > - if (copy_to_iter(hdr, sizeof(*hdr), iter) != sizeof(*hdr)) > > + if (copy_to_iter(hdr, content_sz, iter) != content_sz) > > return -EFAULT; > > > > - if (iov_iter_zero(sz - sizeof(*hdr), iter) != sz - sizeof(*hdr)) > > + if (iov_iter_zero(sz - content_sz, iter) != sz - content_sz) > > return -EFAULT; > > > > return 0; > > @@ -154,11 +156,11 @@ EXPORT_SYMBOL_GPL(tun_vnet_hdr_to_skb); > > > > int tun_vnet_hdr_from_skb(unsigned int flags, const struct net_device *dev, > > const struct sk_buff *skb, > > - struct virtio_net_hdr *hdr) > > + struct virtio_net_hdr_v1 *hdr) > > { > > int vlan_hlen = skb_vlan_tag_present(skb) ? VLAN_HLEN : 0; > > > > - if (virtio_net_hdr_from_skb(skb, hdr, > > + if (virtio_net_hdr_from_skb(skb, (struct virtio_net_hdr *)hdr, > > tun_vnet_is_little_endian(flags), true, > > vlan_hlen)) { > > struct skb_shared_info *sinfo = skb_shinfo(skb); > > @@ -176,6 +178,8 @@ int tun_vnet_hdr_from_skb(unsigned int flags, const struct net_device *dev, > > return -EINVAL; > > } > > > > + hdr->num_buffers = 1; > > + > > return 0; > > } > > EXPORT_SYMBOL_GPL(tun_vnet_hdr_from_skb); > > diff --git a/drivers/net/tun_vnet.h b/drivers/net/tun_vnet.h > > index 2dfdbe92bb24..d8fd94094227 100644 > > --- a/drivers/net/tun_vnet.h > > +++ b/drivers/net/tun_vnet.h > > @@ -12,13 +12,13 @@ int tun_vnet_hdr_get(int sz, unsigned int flags, struct iov_iter *from, > > struct virtio_net_hdr *hdr); > > > > int tun_vnet_hdr_put(int sz, struct iov_iter *iter, > > - const struct virtio_net_hdr *hdr); > > + const struct virtio_net_hdr_v1 *hdr); > > > > int tun_vnet_hdr_to_skb(unsigned int flags, struct sk_buff *skb, > > const struct virtio_net_hdr *hdr); > > > > int tun_vnet_hdr_from_skb(unsigned int flags, const struct net_device *dev, > > const struct sk_buff *skb, > > - struct virtio_net_hdr *hdr); > > + struct virtio_net_hdr_v1 *hdr); > > > > #endif /* TUN_VNET_H */ > > > > -- > > 2.47.1
On 2025/01/09 16:40, Michael S. Tsirkin wrote: > On Thu, Jan 09, 2025 at 02:32:25AM -0500, Michael S. Tsirkin wrote: >> On Thu, Jan 09, 2025 at 03:58:45PM +0900, Akihiko Odaki wrote: >>> The specification says the device MUST set num_buffers to 1 if >>> VIRTIO_NET_F_MRG_RXBUF has not been negotiated. >>> >>> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> >> >> >> How do we know this is v1 and not v0? Confused. > > Ah I got it, you assume userspace will over-write it > if VIRTIO_NET_F_MRG_RXBUF is set. > If we are leaving this up to userspace, why not let it do > it always? tun may be used with vhost_net, which does not set the field. > >>> --- >>> drivers/net/tap.c | 2 +- >>> drivers/net/tun.c | 6 ++++-- >>> drivers/net/tun_vnet.c | 14 +++++++++----- >>> drivers/net/tun_vnet.h | 4 ++-- >>> 4 files changed, 16 insertions(+), 10 deletions(-) >>> >>> diff --git a/drivers/net/tap.c b/drivers/net/tap.c >>> index 60804855510b..fe9554ee5b8b 100644 >>> --- a/drivers/net/tap.c >>> +++ b/drivers/net/tap.c >>> @@ -713,7 +713,7 @@ static ssize_t tap_put_user(struct tap_queue *q, >>> int total; >>> >>> if (q->flags & IFF_VNET_HDR) { >>> - struct virtio_net_hdr vnet_hdr; >>> + struct virtio_net_hdr_v1 vnet_hdr; >>> >>> vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz); >>> >>> diff --git a/drivers/net/tun.c b/drivers/net/tun.c >>> index dbf0dee92e93..f211d0580887 100644 >>> --- a/drivers/net/tun.c >>> +++ b/drivers/net/tun.c >>> @@ -1991,7 +1991,9 @@ static ssize_t tun_put_user_xdp(struct tun_struct *tun, >>> size_t total; >>> >>> if (tun->flags & IFF_VNET_HDR) { >>> - struct virtio_net_hdr gso = { 0 }; >>> + struct virtio_net_hdr_v1 gso = { >>> + .num_buffers = __virtio16_to_cpu(true, 1) >>> + }; >>> >>> vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz); >>> ret = tun_vnet_hdr_put(vnet_hdr_sz, iter, &gso); >>> @@ -2044,7 +2046,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, >>> } >>> >>> if (vnet_hdr_sz) { >>> - struct virtio_net_hdr gso; >>> + struct virtio_net_hdr_v1 gso; >>> >>> ret = tun_vnet_hdr_from_skb(tun->flags, tun->dev, skb, &gso); >>> if (ret < 0) >>> diff --git a/drivers/net/tun_vnet.c b/drivers/net/tun_vnet.c >>> index ffb2186facd3..a7a7989fae56 100644 >>> --- a/drivers/net/tun_vnet.c >>> +++ b/drivers/net/tun_vnet.c >>> @@ -130,15 +130,17 @@ int tun_vnet_hdr_get(int sz, unsigned int flags, struct iov_iter *from, >>> EXPORT_SYMBOL_GPL(tun_vnet_hdr_get); >>> >>> int tun_vnet_hdr_put(int sz, struct iov_iter *iter, >>> - const struct virtio_net_hdr *hdr) >>> + const struct virtio_net_hdr_v1 *hdr) >>> { >>> + int content_sz = MIN(sizeof(*hdr), sz); >>> + >>> if (iov_iter_count(iter) < sz) >>> return -EINVAL; >>> >>> - if (copy_to_iter(hdr, sizeof(*hdr), iter) != sizeof(*hdr)) >>> + if (copy_to_iter(hdr, content_sz, iter) != content_sz) >>> return -EFAULT; >>> >>> - if (iov_iter_zero(sz - sizeof(*hdr), iter) != sz - sizeof(*hdr)) >>> + if (iov_iter_zero(sz - content_sz, iter) != sz - content_sz) >>> return -EFAULT; >>> >>> return 0; >>> @@ -154,11 +156,11 @@ EXPORT_SYMBOL_GPL(tun_vnet_hdr_to_skb); >>> >>> int tun_vnet_hdr_from_skb(unsigned int flags, const struct net_device *dev, >>> const struct sk_buff *skb, >>> - struct virtio_net_hdr *hdr) >>> + struct virtio_net_hdr_v1 *hdr) >>> { >>> int vlan_hlen = skb_vlan_tag_present(skb) ? VLAN_HLEN : 0; >>> >>> - if (virtio_net_hdr_from_skb(skb, hdr, >>> + if (virtio_net_hdr_from_skb(skb, (struct virtio_net_hdr *)hdr, >>> tun_vnet_is_little_endian(flags), true, >>> vlan_hlen)) { >>> struct skb_shared_info *sinfo = skb_shinfo(skb); >>> @@ -176,6 +178,8 @@ int tun_vnet_hdr_from_skb(unsigned int flags, const struct net_device *dev, >>> return -EINVAL; >>> } >>> >>> + hdr->num_buffers = 1; >>> + >>> return 0; >>> } >>> EXPORT_SYMBOL_GPL(tun_vnet_hdr_from_skb); >>> diff --git a/drivers/net/tun_vnet.h b/drivers/net/tun_vnet.h >>> index 2dfdbe92bb24..d8fd94094227 100644 >>> --- a/drivers/net/tun_vnet.h >>> +++ b/drivers/net/tun_vnet.h >>> @@ -12,13 +12,13 @@ int tun_vnet_hdr_get(int sz, unsigned int flags, struct iov_iter *from, >>> struct virtio_net_hdr *hdr); >>> >>> int tun_vnet_hdr_put(int sz, struct iov_iter *iter, >>> - const struct virtio_net_hdr *hdr); >>> + const struct virtio_net_hdr_v1 *hdr); >>> >>> int tun_vnet_hdr_to_skb(unsigned int flags, struct sk_buff *skb, >>> const struct virtio_net_hdr *hdr); >>> >>> int tun_vnet_hdr_from_skb(unsigned int flags, const struct net_device *dev, >>> const struct sk_buff *skb, >>> - struct virtio_net_hdr *hdr); >>> + struct virtio_net_hdr_v1 *hdr); >>> >>> #endif /* TUN_VNET_H */ >>> >>> -- >>> 2.47.1 >
On Thu, Jan 09, 2025 at 06:38:10PM +0900, Akihiko Odaki wrote: > On 2025/01/09 16:40, Michael S. Tsirkin wrote: > > On Thu, Jan 09, 2025 at 02:32:25AM -0500, Michael S. Tsirkin wrote: > > > On Thu, Jan 09, 2025 at 03:58:45PM +0900, Akihiko Odaki wrote: > > > > The specification says the device MUST set num_buffers to 1 if > > > > VIRTIO_NET_F_MRG_RXBUF has not been negotiated. > > > > > > > > Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> > > > > > > > > > How do we know this is v1 and not v0? Confused. > > > > Ah I got it, you assume userspace will over-write it > > if VIRTIO_NET_F_MRG_RXBUF is set. > > If we are leaving this up to userspace, why not let it do > > it always? > > tun may be used with vhost_net, which does not set the field. I'd fix that in vhost net. > > > > > > --- > > > > drivers/net/tap.c | 2 +- > > > > drivers/net/tun.c | 6 ++++-- > > > > drivers/net/tun_vnet.c | 14 +++++++++----- > > > > drivers/net/tun_vnet.h | 4 ++-- > > > > 4 files changed, 16 insertions(+), 10 deletions(-) > > > > > > > > diff --git a/drivers/net/tap.c b/drivers/net/tap.c > > > > index 60804855510b..fe9554ee5b8b 100644 > > > > --- a/drivers/net/tap.c > > > > +++ b/drivers/net/tap.c > > > > @@ -713,7 +713,7 @@ static ssize_t tap_put_user(struct tap_queue *q, > > > > int total; > > > > if (q->flags & IFF_VNET_HDR) { > > > > - struct virtio_net_hdr vnet_hdr; > > > > + struct virtio_net_hdr_v1 vnet_hdr; > > > > vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz); > > > > diff --git a/drivers/net/tun.c b/drivers/net/tun.c > > > > index dbf0dee92e93..f211d0580887 100644 > > > > --- a/drivers/net/tun.c > > > > +++ b/drivers/net/tun.c > > > > @@ -1991,7 +1991,9 @@ static ssize_t tun_put_user_xdp(struct tun_struct *tun, > > > > size_t total; > > > > if (tun->flags & IFF_VNET_HDR) { > > > > - struct virtio_net_hdr gso = { 0 }; > > > > + struct virtio_net_hdr_v1 gso = { > > > > + .num_buffers = __virtio16_to_cpu(true, 1) > > > > + }; > > > > vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz); > > > > ret = tun_vnet_hdr_put(vnet_hdr_sz, iter, &gso); > > > > @@ -2044,7 +2046,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, > > > > } > > > > if (vnet_hdr_sz) { > > > > - struct virtio_net_hdr gso; > > > > + struct virtio_net_hdr_v1 gso; > > > > ret = tun_vnet_hdr_from_skb(tun->flags, tun->dev, skb, &gso); > > > > if (ret < 0) > > > > diff --git a/drivers/net/tun_vnet.c b/drivers/net/tun_vnet.c > > > > index ffb2186facd3..a7a7989fae56 100644 > > > > --- a/drivers/net/tun_vnet.c > > > > +++ b/drivers/net/tun_vnet.c > > > > @@ -130,15 +130,17 @@ int tun_vnet_hdr_get(int sz, unsigned int flags, struct iov_iter *from, > > > > EXPORT_SYMBOL_GPL(tun_vnet_hdr_get); > > > > int tun_vnet_hdr_put(int sz, struct iov_iter *iter, > > > > - const struct virtio_net_hdr *hdr) > > > > + const struct virtio_net_hdr_v1 *hdr) > > > > { > > > > + int content_sz = MIN(sizeof(*hdr), sz); > > > > + > > > > if (iov_iter_count(iter) < sz) > > > > return -EINVAL; > > > > - if (copy_to_iter(hdr, sizeof(*hdr), iter) != sizeof(*hdr)) > > > > + if (copy_to_iter(hdr, content_sz, iter) != content_sz) > > > > return -EFAULT; > > > > - if (iov_iter_zero(sz - sizeof(*hdr), iter) != sz - sizeof(*hdr)) > > > > + if (iov_iter_zero(sz - content_sz, iter) != sz - content_sz) > > > > return -EFAULT; > > > > return 0; > > > > @@ -154,11 +156,11 @@ EXPORT_SYMBOL_GPL(tun_vnet_hdr_to_skb); > > > > int tun_vnet_hdr_from_skb(unsigned int flags, const struct net_device *dev, > > > > const struct sk_buff *skb, > > > > - struct virtio_net_hdr *hdr) > > > > + struct virtio_net_hdr_v1 *hdr) > > > > { > > > > int vlan_hlen = skb_vlan_tag_present(skb) ? VLAN_HLEN : 0; > > > > - if (virtio_net_hdr_from_skb(skb, hdr, > > > > + if (virtio_net_hdr_from_skb(skb, (struct virtio_net_hdr *)hdr, > > > > tun_vnet_is_little_endian(flags), true, > > > > vlan_hlen)) { > > > > struct skb_shared_info *sinfo = skb_shinfo(skb); > > > > @@ -176,6 +178,8 @@ int tun_vnet_hdr_from_skb(unsigned int flags, const struct net_device *dev, > > > > return -EINVAL; > > > > } > > > > + hdr->num_buffers = 1; > > > > + > > > > return 0; > > > > } > > > > EXPORT_SYMBOL_GPL(tun_vnet_hdr_from_skb); > > > > diff --git a/drivers/net/tun_vnet.h b/drivers/net/tun_vnet.h > > > > index 2dfdbe92bb24..d8fd94094227 100644 > > > > --- a/drivers/net/tun_vnet.h > > > > +++ b/drivers/net/tun_vnet.h > > > > @@ -12,13 +12,13 @@ int tun_vnet_hdr_get(int sz, unsigned int flags, struct iov_iter *from, > > > > struct virtio_net_hdr *hdr); > > > > int tun_vnet_hdr_put(int sz, struct iov_iter *iter, > > > > - const struct virtio_net_hdr *hdr); > > > > + const struct virtio_net_hdr_v1 *hdr); > > > > int tun_vnet_hdr_to_skb(unsigned int flags, struct sk_buff *skb, > > > > const struct virtio_net_hdr *hdr); > > > > int tun_vnet_hdr_from_skb(unsigned int flags, const struct net_device *dev, > > > > const struct sk_buff *skb, > > > > - struct virtio_net_hdr *hdr); > > > > + struct virtio_net_hdr_v1 *hdr); > > > > #endif /* TUN_VNET_H */ > > > > > > > > -- > > > > 2.47.1 > >
On 2025/01/09 19:54, Michael S. Tsirkin wrote: > On Thu, Jan 09, 2025 at 06:38:10PM +0900, Akihiko Odaki wrote: >> On 2025/01/09 16:40, Michael S. Tsirkin wrote: >>> On Thu, Jan 09, 2025 at 02:32:25AM -0500, Michael S. Tsirkin wrote: >>>> On Thu, Jan 09, 2025 at 03:58:45PM +0900, Akihiko Odaki wrote: >>>>> The specification says the device MUST set num_buffers to 1 if >>>>> VIRTIO_NET_F_MRG_RXBUF has not been negotiated. >>>>> >>>>> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> >>>> >>>> >>>> How do we know this is v1 and not v0? Confused. >>> >>> Ah I got it, you assume userspace will over-write it >>> if VIRTIO_NET_F_MRG_RXBUF is set. >>> If we are leaving this up to userspace, why not let it do >>> it always? >> >> tun may be used with vhost_net, which does not set the field. > > I'd fix that in vhost net. Let's see what filesystem and networking people will say for the earlier patch. We can fix num_buffers for free if the earlier patch is getting merged. We will need to come up with another solution otherwise. > > >>> >>>>> --- >>>>> drivers/net/tap.c | 2 +- >>>>> drivers/net/tun.c | 6 ++++-- >>>>> drivers/net/tun_vnet.c | 14 +++++++++----- >>>>> drivers/net/tun_vnet.h | 4 ++-- >>>>> 4 files changed, 16 insertions(+), 10 deletions(-) >>>>> >>>>> diff --git a/drivers/net/tap.c b/drivers/net/tap.c >>>>> index 60804855510b..fe9554ee5b8b 100644 >>>>> --- a/drivers/net/tap.c >>>>> +++ b/drivers/net/tap.c >>>>> @@ -713,7 +713,7 @@ static ssize_t tap_put_user(struct tap_queue *q, >>>>> int total; >>>>> if (q->flags & IFF_VNET_HDR) { >>>>> - struct virtio_net_hdr vnet_hdr; >>>>> + struct virtio_net_hdr_v1 vnet_hdr; >>>>> vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz); >>>>> diff --git a/drivers/net/tun.c b/drivers/net/tun.c >>>>> index dbf0dee92e93..f211d0580887 100644 >>>>> --- a/drivers/net/tun.c >>>>> +++ b/drivers/net/tun.c >>>>> @@ -1991,7 +1991,9 @@ static ssize_t tun_put_user_xdp(struct tun_struct *tun, >>>>> size_t total; >>>>> if (tun->flags & IFF_VNET_HDR) { >>>>> - struct virtio_net_hdr gso = { 0 }; >>>>> + struct virtio_net_hdr_v1 gso = { >>>>> + .num_buffers = __virtio16_to_cpu(true, 1) >>>>> + }; >>>>> vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz); >>>>> ret = tun_vnet_hdr_put(vnet_hdr_sz, iter, &gso); >>>>> @@ -2044,7 +2046,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, >>>>> } >>>>> if (vnet_hdr_sz) { >>>>> - struct virtio_net_hdr gso; >>>>> + struct virtio_net_hdr_v1 gso; >>>>> ret = tun_vnet_hdr_from_skb(tun->flags, tun->dev, skb, &gso); >>>>> if (ret < 0) >>>>> diff --git a/drivers/net/tun_vnet.c b/drivers/net/tun_vnet.c >>>>> index ffb2186facd3..a7a7989fae56 100644 >>>>> --- a/drivers/net/tun_vnet.c >>>>> +++ b/drivers/net/tun_vnet.c >>>>> @@ -130,15 +130,17 @@ int tun_vnet_hdr_get(int sz, unsigned int flags, struct iov_iter *from, >>>>> EXPORT_SYMBOL_GPL(tun_vnet_hdr_get); >>>>> int tun_vnet_hdr_put(int sz, struct iov_iter *iter, >>>>> - const struct virtio_net_hdr *hdr) >>>>> + const struct virtio_net_hdr_v1 *hdr) >>>>> { >>>>> + int content_sz = MIN(sizeof(*hdr), sz); >>>>> + >>>>> if (iov_iter_count(iter) < sz) >>>>> return -EINVAL; >>>>> - if (copy_to_iter(hdr, sizeof(*hdr), iter) != sizeof(*hdr)) >>>>> + if (copy_to_iter(hdr, content_sz, iter) != content_sz) >>>>> return -EFAULT; >>>>> - if (iov_iter_zero(sz - sizeof(*hdr), iter) != sz - sizeof(*hdr)) >>>>> + if (iov_iter_zero(sz - content_sz, iter) != sz - content_sz) >>>>> return -EFAULT; >>>>> return 0; >>>>> @@ -154,11 +156,11 @@ EXPORT_SYMBOL_GPL(tun_vnet_hdr_to_skb); >>>>> int tun_vnet_hdr_from_skb(unsigned int flags, const struct net_device *dev, >>>>> const struct sk_buff *skb, >>>>> - struct virtio_net_hdr *hdr) >>>>> + struct virtio_net_hdr_v1 *hdr) >>>>> { >>>>> int vlan_hlen = skb_vlan_tag_present(skb) ? VLAN_HLEN : 0; >>>>> - if (virtio_net_hdr_from_skb(skb, hdr, >>>>> + if (virtio_net_hdr_from_skb(skb, (struct virtio_net_hdr *)hdr, >>>>> tun_vnet_is_little_endian(flags), true, >>>>> vlan_hlen)) { >>>>> struct skb_shared_info *sinfo = skb_shinfo(skb); >>>>> @@ -176,6 +178,8 @@ int tun_vnet_hdr_from_skb(unsigned int flags, const struct net_device *dev, >>>>> return -EINVAL; >>>>> } >>>>> + hdr->num_buffers = 1; >>>>> + >>>>> return 0; >>>>> } >>>>> EXPORT_SYMBOL_GPL(tun_vnet_hdr_from_skb); >>>>> diff --git a/drivers/net/tun_vnet.h b/drivers/net/tun_vnet.h >>>>> index 2dfdbe92bb24..d8fd94094227 100644 >>>>> --- a/drivers/net/tun_vnet.h >>>>> +++ b/drivers/net/tun_vnet.h >>>>> @@ -12,13 +12,13 @@ int tun_vnet_hdr_get(int sz, unsigned int flags, struct iov_iter *from, >>>>> struct virtio_net_hdr *hdr); >>>>> int tun_vnet_hdr_put(int sz, struct iov_iter *iter, >>>>> - const struct virtio_net_hdr *hdr); >>>>> + const struct virtio_net_hdr_v1 *hdr); >>>>> int tun_vnet_hdr_to_skb(unsigned int flags, struct sk_buff *skb, >>>>> const struct virtio_net_hdr *hdr); >>>>> int tun_vnet_hdr_from_skb(unsigned int flags, const struct net_device *dev, >>>>> const struct sk_buff *skb, >>>>> - struct virtio_net_hdr *hdr); >>>>> + struct virtio_net_hdr_v1 *hdr); >>>>> #endif /* TUN_VNET_H */ >>>>> >>>>> -- >>>>> 2.47.1 >>> >
On Thu, Jan 9, 2025 at 2:59 PM Akihiko Odaki <akihiko.odaki@daynix.com> wrote: > > The specification says the device MUST set num_buffers to 1 if > VIRTIO_NET_F_MRG_RXBUF has not been negotiated. Have we agreed on how to fix the spec or not? As I replied in the spec patch, if we just remove this "MUST", it looks like we are all fine? Thanks
On 2025/01/10 12:27, Jason Wang wrote: > On Thu, Jan 9, 2025 at 2:59 PM Akihiko Odaki <akihiko.odaki@daynix.com> wrote: >> >> The specification says the device MUST set num_buffers to 1 if >> VIRTIO_NET_F_MRG_RXBUF has not been negotiated. > > Have we agreed on how to fix the spec or not? > > As I replied in the spec patch, if we just remove this "MUST", it > looks like we are all fine? My understanding is that we should fix the kernel and QEMU instead. There may be some driver implementations that assumes num_buffers is 1 so the kernel and QEMU should be fixed to be compatible with such potential implementations. It is also possible to make future drivers with existing kernels and QEMU by ensuring they will not read num_buffers when VIRTIO_NET_F_MRG_RXBUF has not negotiated, and that's what "[PATCH v3] virtio-net: Ignore num_buffers when unused" does. https://lore.kernel.org/r/20250110-reserved-v3-1-2ade0a5d2090@daynix.com Regards, Akihiko Odaki
On Fri, Jan 10, 2025 at 11:27:13AM +0800, Jason Wang wrote: > On Thu, Jan 9, 2025 at 2:59 PM Akihiko Odaki <akihiko.odaki@daynix.com> wrote: > > > > The specification says the device MUST set num_buffers to 1 if > > VIRTIO_NET_F_MRG_RXBUF has not been negotiated. > > Have we agreed on how to fix the spec or not? > > As I replied in the spec patch, if we just remove this "MUST", it > looks like we are all fine? > > Thanks We should replace MUST with SHOULD but it is not all fine, ignoring SHOULD is a quality of implementation issue.
On 2025/01/10 19:23, Michael S. Tsirkin wrote: > On Fri, Jan 10, 2025 at 11:27:13AM +0800, Jason Wang wrote: >> On Thu, Jan 9, 2025 at 2:59 PM Akihiko Odaki <akihiko.odaki@daynix.com> wrote: >>> >>> The specification says the device MUST set num_buffers to 1 if >>> VIRTIO_NET_F_MRG_RXBUF has not been negotiated. >> >> Have we agreed on how to fix the spec or not? >> >> As I replied in the spec patch, if we just remove this "MUST", it >> looks like we are all fine? >> >> Thanks > > We should replace MUST with SHOULD but it is not all fine, > ignoring SHOULD is a quality of implementation issue. > Should we really replace it? It would mean that a driver conformant with the current specification may not be compatible with a device conformant with the future specification. We are going to fix all implementations known to buggy (QEMU and Linux) anyway so I think it's just fine to leave that part of specification as is.
diff --git a/drivers/net/tap.c b/drivers/net/tap.c index 60804855510b..fe9554ee5b8b 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c @@ -713,7 +713,7 @@ static ssize_t tap_put_user(struct tap_queue *q, int total; if (q->flags & IFF_VNET_HDR) { - struct virtio_net_hdr vnet_hdr; + struct virtio_net_hdr_v1 vnet_hdr; vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz); diff --git a/drivers/net/tun.c b/drivers/net/tun.c index dbf0dee92e93..f211d0580887 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1991,7 +1991,9 @@ static ssize_t tun_put_user_xdp(struct tun_struct *tun, size_t total; if (tun->flags & IFF_VNET_HDR) { - struct virtio_net_hdr gso = { 0 }; + struct virtio_net_hdr_v1 gso = { + .num_buffers = __virtio16_to_cpu(true, 1) + }; vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz); ret = tun_vnet_hdr_put(vnet_hdr_sz, iter, &gso); @@ -2044,7 +2046,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, } if (vnet_hdr_sz) { - struct virtio_net_hdr gso; + struct virtio_net_hdr_v1 gso; ret = tun_vnet_hdr_from_skb(tun->flags, tun->dev, skb, &gso); if (ret < 0) diff --git a/drivers/net/tun_vnet.c b/drivers/net/tun_vnet.c index ffb2186facd3..a7a7989fae56 100644 --- a/drivers/net/tun_vnet.c +++ b/drivers/net/tun_vnet.c @@ -130,15 +130,17 @@ int tun_vnet_hdr_get(int sz, unsigned int flags, struct iov_iter *from, EXPORT_SYMBOL_GPL(tun_vnet_hdr_get); int tun_vnet_hdr_put(int sz, struct iov_iter *iter, - const struct virtio_net_hdr *hdr) + const struct virtio_net_hdr_v1 *hdr) { + int content_sz = MIN(sizeof(*hdr), sz); + if (iov_iter_count(iter) < sz) return -EINVAL; - if (copy_to_iter(hdr, sizeof(*hdr), iter) != sizeof(*hdr)) + if (copy_to_iter(hdr, content_sz, iter) != content_sz) return -EFAULT; - if (iov_iter_zero(sz - sizeof(*hdr), iter) != sz - sizeof(*hdr)) + if (iov_iter_zero(sz - content_sz, iter) != sz - content_sz) return -EFAULT; return 0; @@ -154,11 +156,11 @@ EXPORT_SYMBOL_GPL(tun_vnet_hdr_to_skb); int tun_vnet_hdr_from_skb(unsigned int flags, const struct net_device *dev, const struct sk_buff *skb, - struct virtio_net_hdr *hdr) + struct virtio_net_hdr_v1 *hdr) { int vlan_hlen = skb_vlan_tag_present(skb) ? VLAN_HLEN : 0; - if (virtio_net_hdr_from_skb(skb, hdr, + if (virtio_net_hdr_from_skb(skb, (struct virtio_net_hdr *)hdr, tun_vnet_is_little_endian(flags), true, vlan_hlen)) { struct skb_shared_info *sinfo = skb_shinfo(skb); @@ -176,6 +178,8 @@ int tun_vnet_hdr_from_skb(unsigned int flags, const struct net_device *dev, return -EINVAL; } + hdr->num_buffers = 1; + return 0; } EXPORT_SYMBOL_GPL(tun_vnet_hdr_from_skb); diff --git a/drivers/net/tun_vnet.h b/drivers/net/tun_vnet.h index 2dfdbe92bb24..d8fd94094227 100644 --- a/drivers/net/tun_vnet.h +++ b/drivers/net/tun_vnet.h @@ -12,13 +12,13 @@ int tun_vnet_hdr_get(int sz, unsigned int flags, struct iov_iter *from, struct virtio_net_hdr *hdr); int tun_vnet_hdr_put(int sz, struct iov_iter *iter, - const struct virtio_net_hdr *hdr); + const struct virtio_net_hdr_v1 *hdr); int tun_vnet_hdr_to_skb(unsigned int flags, struct sk_buff *skb, const struct virtio_net_hdr *hdr); int tun_vnet_hdr_from_skb(unsigned int flags, const struct net_device *dev, const struct sk_buff *skb, - struct virtio_net_hdr *hdr); + struct virtio_net_hdr_v1 *hdr); #endif /* TUN_VNET_H */
The specification says the device MUST set num_buffers to 1 if VIRTIO_NET_F_MRG_RXBUF has not been negotiated. Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> --- drivers/net/tap.c | 2 +- drivers/net/tun.c | 6 ++++-- drivers/net/tun_vnet.c | 14 +++++++++----- drivers/net/tun_vnet.h | 4 ++-- 4 files changed, 16 insertions(+), 10 deletions(-)