Re: [RFC PATCH net-next v2 1/2] virtio-net: support zerocopy multi buffer XDP in mergeable

2025-06-03 Thread Bui Quang Minh

On 6/3/25 09:56, Jason Wang wrote:

On Thu, May 29, 2025 at 8:28 PM Bui Quang Minh  wrote:

On 5/29/25 12:59, Jason Wang wrote:

On Wed, May 28, 2025 at 12:19 AM Bui Quang Minh
 wrote:

Currently, in zerocopy mode with mergeable receive buffer, virtio-net
does not support multi buffer but a single buffer only. This commit adds
support for multi mergeable receive buffer in the zerocopy XDP path by
utilizing XDP buffer with frags.

Signed-off-by: Bui Quang Minh 
---
   drivers/net/virtio_net.c | 123 +--
   1 file changed, 66 insertions(+), 57 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index e53ba600605a..a9558650f205 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -45,6 +45,8 @@ module_param(napi_tx, bool, 0644);
   #define VIRTIO_XDP_TX  BIT(0)
   #define VIRTIO_XDP_REDIR   BIT(1)

+#define VIRTNET_MAX_ZC_SEGS8
+
   /* RX packet size EWMA. The average packet size is used to determine the 
packet
* buffer size when refilling RX rings. As the entire RX ring may be refilled
* at once, the weight is chosen so that the EWMA will be insensitive to 
short-
@@ -1232,65 +1234,53 @@ static void xsk_drop_follow_bufs(struct net_device *dev,
  }
   }

-static int xsk_append_merge_buffer(struct virtnet_info *vi,
-  struct receive_queue *rq,
-  struct sk_buff *head_skb,
-  u32 num_buf,
-  struct virtio_net_hdr_mrg_rxbuf *hdr,
-  struct virtnet_rq_stats *stats)
+static int virtnet_build_xsk_buff_mrg(struct virtnet_info *vi,
+ struct receive_queue *rq,
+ u32 num_buf,
+ struct xdp_buff *xdp,
+ struct virtnet_rq_stats *stats)
   {
-   struct sk_buff *curr_skb;
-   struct xdp_buff *xdp;
-   u32 len, truesize;
-   struct page *page;
+   unsigned int len;
  void *buf;

-   curr_skb = head_skb;
+   if (num_buf < 2)
+   return 0;
+
+   while (num_buf > 1) {
+   struct xdp_buff *new_xdp;

-   while (--num_buf) {
  buf = virtqueue_get_buf(rq->vq, &len);
-   if (unlikely(!buf)) {
-   pr_debug("%s: rx error: %d buffers out of %d missing\n",
-vi->dev->name, num_buf,
-virtio16_to_cpu(vi->vdev,
-hdr->num_buffers));
+   if (!unlikely(buf)) {
+   pr_debug("%s: rx error: %d buffers missing\n",
+vi->dev->name, num_buf);
  DEV_STATS_INC(vi->dev, rx_length_errors);
-   return -EINVAL;
-   }
-
-   u64_stats_add(&stats->bytes, len);
-
-   xdp = buf_to_xdp(vi, rq, buf, len);
-   if (!xdp)
-   goto err;
-
-   buf = napi_alloc_frag(len);
-   if (!buf) {
-   xsk_buff_free(xdp);
-   goto err;
+   return -1;
  }

-   memcpy(buf, xdp->data - vi->hdr_len, len);
-
-   xsk_buff_free(xdp);
+   new_xdp = buf_to_xdp(vi, rq, buf, len);
+   if (!new_xdp)
+   goto drop_bufs;

-   page = virt_to_page(buf);
+   /* In virtnet_add_recvbuf_xsk(), we ask the host to fill from
+* xdp->data - vi->hdr_len with both virtio_net_hdr and data.
+* However, only the first packet has the virtio_net_hdr, the
+* following ones do not. So we need to adjust the following

Typo here.

I'm sorry, could you clarify which word contains the typo?


+* packets' data pointer to the correct place.
+*/

I wonder what happens if we don't use this trick? I meant we don't
reuse the header room for the virtio-net header. This seems to be fine
for a mergeable buffer and can help to reduce the trick.

I don't think using the header room for virtio-net header creates this
case handling. In my opinion, it comes from the slightly difference in
the recvbuf between single buffer and multi-buffer. When we have n
single-buffer packets, each buffer will have its own virtio-net header.
But when we have 1 multi-buffer packet (which spans across n buffers),
only the first buffer has virtio-net header, the following buffers do not.

There 2 important pointers here. The pointer we announce to the vhost
side to fill the data, let's call it announced_addr, and xdp_buff->data
which is expected to point the the start of Ethernet frame. Currently,

  announced_addr = xdp_buff->data - hdr_len

The host side will write the 

Re: [RFC PATCH net-next v2 1/2] virtio-net: support zerocopy multi buffer XDP in mergeable

2025-06-02 Thread Lei Yang
Tested this patch with virtio-net regression tests, everything works fine.

Tested-by: Lei Yang 

On Tue, Jun 3, 2025 at 10:57 AM Jason Wang  wrote:
>
> On Thu, May 29, 2025 at 8:28 PM Bui Quang Minh  
> wrote:
> >
> > On 5/29/25 12:59, Jason Wang wrote:
> > > On Wed, May 28, 2025 at 12:19 AM Bui Quang Minh
> > >  wrote:
> > >> Currently, in zerocopy mode with mergeable receive buffer, virtio-net
> > >> does not support multi buffer but a single buffer only. This commit adds
> > >> support for multi mergeable receive buffer in the zerocopy XDP path by
> > >> utilizing XDP buffer with frags.
> > >>
> > >> Signed-off-by: Bui Quang Minh 
> > >> ---
> > >>   drivers/net/virtio_net.c | 123 +--
> > >>   1 file changed, 66 insertions(+), 57 deletions(-)
> > >>
> > >> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > >> index e53ba600605a..a9558650f205 100644
> > >> --- a/drivers/net/virtio_net.c
> > >> +++ b/drivers/net/virtio_net.c
> > >> @@ -45,6 +45,8 @@ module_param(napi_tx, bool, 0644);
> > >>   #define VIRTIO_XDP_TX  BIT(0)
> > >>   #define VIRTIO_XDP_REDIR   BIT(1)
> > >>
> > >> +#define VIRTNET_MAX_ZC_SEGS8
> > >> +
> > >>   /* RX packet size EWMA. The average packet size is used to determine 
> > >> the packet
> > >>* buffer size when refilling RX rings. As the entire RX ring may be 
> > >> refilled
> > >>* at once, the weight is chosen so that the EWMA will be insensitive 
> > >> to short-
> > >> @@ -1232,65 +1234,53 @@ static void xsk_drop_follow_bufs(struct 
> > >> net_device *dev,
> > >>  }
> > >>   }
> > >>
> > >> -static int xsk_append_merge_buffer(struct virtnet_info *vi,
> > >> -  struct receive_queue *rq,
> > >> -  struct sk_buff *head_skb,
> > >> -  u32 num_buf,
> > >> -  struct virtio_net_hdr_mrg_rxbuf *hdr,
> > >> -  struct virtnet_rq_stats *stats)
> > >> +static int virtnet_build_xsk_buff_mrg(struct virtnet_info *vi,
> > >> + struct receive_queue *rq,
> > >> + u32 num_buf,
> > >> + struct xdp_buff *xdp,
> > >> + struct virtnet_rq_stats *stats)
> > >>   {
> > >> -   struct sk_buff *curr_skb;
> > >> -   struct xdp_buff *xdp;
> > >> -   u32 len, truesize;
> > >> -   struct page *page;
> > >> +   unsigned int len;
> > >>  void *buf;
> > >>
> > >> -   curr_skb = head_skb;
> > >> +   if (num_buf < 2)
> > >> +   return 0;
> > >> +
> > >> +   while (num_buf > 1) {
> > >> +   struct xdp_buff *new_xdp;
> > >>
> > >> -   while (--num_buf) {
> > >>  buf = virtqueue_get_buf(rq->vq, &len);
> > >> -   if (unlikely(!buf)) {
> > >> -   pr_debug("%s: rx error: %d buffers out of %d 
> > >> missing\n",
> > >> -vi->dev->name, num_buf,
> > >> -virtio16_to_cpu(vi->vdev,
> > >> -hdr->num_buffers));
> > >> +   if (!unlikely(buf)) {
> > >> +   pr_debug("%s: rx error: %d buffers missing\n",
> > >> +vi->dev->name, num_buf);
> > >>  DEV_STATS_INC(vi->dev, rx_length_errors);
> > >> -   return -EINVAL;
> > >> -   }
> > >> -
> > >> -   u64_stats_add(&stats->bytes, len);
> > >> -
> > >> -   xdp = buf_to_xdp(vi, rq, buf, len);
> > >> -   if (!xdp)
> > >> -   goto err;
> > >> -
> > >> -   buf = napi_alloc_frag(len);
> > >> -   if (!buf) {
> > >> -   xsk_buff_free(xdp);
> > >> -   goto err;
> > >> +   return -1;
> > >>  }
> > >>
> > >> -   memcpy(buf, xdp->data - vi->hdr_len, len);
> > >> -
> > >> -   xsk_buff_free(xdp);
> > >> +   new_xdp = buf_to_xdp(vi, rq, buf, len);
> > >> +   if (!new_xdp)
> > >> +   goto drop_bufs;
> > >>
> > >> -   page = virt_to_page(buf);
> > >> +   /* In virtnet_add_recvbuf_xsk(), we ask the host to fill 
> > >> from
> > >> +* xdp->data - vi->hdr_len with both virtio_net_hdr and 
> > >> data.
> > >> +* However, only the first packet has the 
> > >> virtio_net_hdr, the
> > >> +* following ones do not. So we need to adjust the 
> > >> following
> > > Typo here.
> >
> > I'm sorry, could you clarify which word contains the typo?
> >
> > >
> > >> +* packets' data pointer to the correct place.
> > >> +*/
> > > I wonder what happens if we don't use this trick?

Re: [RFC PATCH net-next v2 1/2] virtio-net: support zerocopy multi buffer XDP in mergeable

2025-06-02 Thread Jason Wang
On Thu, May 29, 2025 at 8:28 PM Bui Quang Minh  wrote:
>
> On 5/29/25 12:59, Jason Wang wrote:
> > On Wed, May 28, 2025 at 12:19 AM Bui Quang Minh
> >  wrote:
> >> Currently, in zerocopy mode with mergeable receive buffer, virtio-net
> >> does not support multi buffer but a single buffer only. This commit adds
> >> support for multi mergeable receive buffer in the zerocopy XDP path by
> >> utilizing XDP buffer with frags.
> >>
> >> Signed-off-by: Bui Quang Minh 
> >> ---
> >>   drivers/net/virtio_net.c | 123 +--
> >>   1 file changed, 66 insertions(+), 57 deletions(-)
> >>
> >> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> >> index e53ba600605a..a9558650f205 100644
> >> --- a/drivers/net/virtio_net.c
> >> +++ b/drivers/net/virtio_net.c
> >> @@ -45,6 +45,8 @@ module_param(napi_tx, bool, 0644);
> >>   #define VIRTIO_XDP_TX  BIT(0)
> >>   #define VIRTIO_XDP_REDIR   BIT(1)
> >>
> >> +#define VIRTNET_MAX_ZC_SEGS8
> >> +
> >>   /* RX packet size EWMA. The average packet size is used to determine the 
> >> packet
> >>* buffer size when refilling RX rings. As the entire RX ring may be 
> >> refilled
> >>* at once, the weight is chosen so that the EWMA will be insensitive to 
> >> short-
> >> @@ -1232,65 +1234,53 @@ static void xsk_drop_follow_bufs(struct net_device 
> >> *dev,
> >>  }
> >>   }
> >>
> >> -static int xsk_append_merge_buffer(struct virtnet_info *vi,
> >> -  struct receive_queue *rq,
> >> -  struct sk_buff *head_skb,
> >> -  u32 num_buf,
> >> -  struct virtio_net_hdr_mrg_rxbuf *hdr,
> >> -  struct virtnet_rq_stats *stats)
> >> +static int virtnet_build_xsk_buff_mrg(struct virtnet_info *vi,
> >> + struct receive_queue *rq,
> >> + u32 num_buf,
> >> + struct xdp_buff *xdp,
> >> + struct virtnet_rq_stats *stats)
> >>   {
> >> -   struct sk_buff *curr_skb;
> >> -   struct xdp_buff *xdp;
> >> -   u32 len, truesize;
> >> -   struct page *page;
> >> +   unsigned int len;
> >>  void *buf;
> >>
> >> -   curr_skb = head_skb;
> >> +   if (num_buf < 2)
> >> +   return 0;
> >> +
> >> +   while (num_buf > 1) {
> >> +   struct xdp_buff *new_xdp;
> >>
> >> -   while (--num_buf) {
> >>  buf = virtqueue_get_buf(rq->vq, &len);
> >> -   if (unlikely(!buf)) {
> >> -   pr_debug("%s: rx error: %d buffers out of %d 
> >> missing\n",
> >> -vi->dev->name, num_buf,
> >> -virtio16_to_cpu(vi->vdev,
> >> -hdr->num_buffers));
> >> +   if (!unlikely(buf)) {
> >> +   pr_debug("%s: rx error: %d buffers missing\n",
> >> +vi->dev->name, num_buf);
> >>  DEV_STATS_INC(vi->dev, rx_length_errors);
> >> -   return -EINVAL;
> >> -   }
> >> -
> >> -   u64_stats_add(&stats->bytes, len);
> >> -
> >> -   xdp = buf_to_xdp(vi, rq, buf, len);
> >> -   if (!xdp)
> >> -   goto err;
> >> -
> >> -   buf = napi_alloc_frag(len);
> >> -   if (!buf) {
> >> -   xsk_buff_free(xdp);
> >> -   goto err;
> >> +   return -1;
> >>  }
> >>
> >> -   memcpy(buf, xdp->data - vi->hdr_len, len);
> >> -
> >> -   xsk_buff_free(xdp);
> >> +   new_xdp = buf_to_xdp(vi, rq, buf, len);
> >> +   if (!new_xdp)
> >> +   goto drop_bufs;
> >>
> >> -   page = virt_to_page(buf);
> >> +   /* In virtnet_add_recvbuf_xsk(), we ask the host to fill 
> >> from
> >> +* xdp->data - vi->hdr_len with both virtio_net_hdr and 
> >> data.
> >> +* However, only the first packet has the virtio_net_hdr, 
> >> the
> >> +* following ones do not. So we need to adjust the 
> >> following
> > Typo here.
>
> I'm sorry, could you clarify which word contains the typo?
>
> >
> >> +* packets' data pointer to the correct place.
> >> +*/
> > I wonder what happens if we don't use this trick? I meant we don't
> > reuse the header room for the virtio-net header. This seems to be fine
> > for a mergeable buffer and can help to reduce the trick.
>
> I don't think using the header room for virtio-net header creates this
> case handling. In my opinion, it comes from the slightly difference in
> the recvbuf between single buffer and multi-buffer. When we have n
> single-bu

Re: [RFC PATCH net-next v2 1/2] virtio-net: support zerocopy multi buffer XDP in mergeable

2025-05-29 Thread Bui Quang Minh

On 5/29/25 12:59, Jason Wang wrote:

On Wed, May 28, 2025 at 12:19 AM Bui Quang Minh
 wrote:

Currently, in zerocopy mode with mergeable receive buffer, virtio-net
does not support multi buffer but a single buffer only. This commit adds
support for multi mergeable receive buffer in the zerocopy XDP path by
utilizing XDP buffer with frags.

Signed-off-by: Bui Quang Minh 
---
  drivers/net/virtio_net.c | 123 +--
  1 file changed, 66 insertions(+), 57 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index e53ba600605a..a9558650f205 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -45,6 +45,8 @@ module_param(napi_tx, bool, 0644);
  #define VIRTIO_XDP_TX  BIT(0)
  #define VIRTIO_XDP_REDIR   BIT(1)

+#define VIRTNET_MAX_ZC_SEGS8
+
  /* RX packet size EWMA. The average packet size is used to determine the 
packet
   * buffer size when refilling RX rings. As the entire RX ring may be refilled
   * at once, the weight is chosen so that the EWMA will be insensitive to 
short-
@@ -1232,65 +1234,53 @@ static void xsk_drop_follow_bufs(struct net_device *dev,
 }
  }

-static int xsk_append_merge_buffer(struct virtnet_info *vi,
-  struct receive_queue *rq,
-  struct sk_buff *head_skb,
-  u32 num_buf,
-  struct virtio_net_hdr_mrg_rxbuf *hdr,
-  struct virtnet_rq_stats *stats)
+static int virtnet_build_xsk_buff_mrg(struct virtnet_info *vi,
+ struct receive_queue *rq,
+ u32 num_buf,
+ struct xdp_buff *xdp,
+ struct virtnet_rq_stats *stats)
  {
-   struct sk_buff *curr_skb;
-   struct xdp_buff *xdp;
-   u32 len, truesize;
-   struct page *page;
+   unsigned int len;
 void *buf;

-   curr_skb = head_skb;
+   if (num_buf < 2)
+   return 0;
+
+   while (num_buf > 1) {
+   struct xdp_buff *new_xdp;

-   while (--num_buf) {
 buf = virtqueue_get_buf(rq->vq, &len);
-   if (unlikely(!buf)) {
-   pr_debug("%s: rx error: %d buffers out of %d missing\n",
-vi->dev->name, num_buf,
-virtio16_to_cpu(vi->vdev,
-hdr->num_buffers));
+   if (!unlikely(buf)) {
+   pr_debug("%s: rx error: %d buffers missing\n",
+vi->dev->name, num_buf);
 DEV_STATS_INC(vi->dev, rx_length_errors);
-   return -EINVAL;
-   }
-
-   u64_stats_add(&stats->bytes, len);
-
-   xdp = buf_to_xdp(vi, rq, buf, len);
-   if (!xdp)
-   goto err;
-
-   buf = napi_alloc_frag(len);
-   if (!buf) {
-   xsk_buff_free(xdp);
-   goto err;
+   return -1;
 }

-   memcpy(buf, xdp->data - vi->hdr_len, len);
-
-   xsk_buff_free(xdp);
+   new_xdp = buf_to_xdp(vi, rq, buf, len);
+   if (!new_xdp)
+   goto drop_bufs;

-   page = virt_to_page(buf);
+   /* In virtnet_add_recvbuf_xsk(), we ask the host to fill from
+* xdp->data - vi->hdr_len with both virtio_net_hdr and data.
+* However, only the first packet has the virtio_net_hdr, the
+* following ones do not. So we need to adjust the following

Typo here.


I'm sorry, could you clarify which word contains the typo?




+* packets' data pointer to the correct place.
+*/

I wonder what happens if we don't use this trick? I meant we don't
reuse the header room for the virtio-net header. This seems to be fine
for a mergeable buffer and can help to reduce the trick.


I don't think using the header room for virtio-net header creates this 
case handling. In my opinion, it comes from the slightly difference in 
the recvbuf between single buffer and multi-buffer. When we have n 
single-buffer packets, each buffer will have its own virtio-net header. 
But when we have 1 multi-buffer packet (which spans across n buffers), 
only the first buffer has virtio-net header, the following buffers do not.


There 2 important pointers here. The pointer we announce to the vhost 
side to fill the data, let's call it announced_addr, and xdp_buff->data 
which is expected to point the the start of Ethernet frame. Currently,


    announced_addr = xdp_buff->data - hdr_len

The host side will write the virtio-net header to announced_addr then 
the Ethernet frame's data in the first buffer. In cas

Re: [RFC PATCH net-next v2 1/2] virtio-net: support zerocopy multi buffer XDP in mergeable

2025-05-28 Thread Jason Wang
On Wed, May 28, 2025 at 12:19 AM Bui Quang Minh
 wrote:
>
> Currently, in zerocopy mode with mergeable receive buffer, virtio-net
> does not support multi buffer but a single buffer only. This commit adds
> support for multi mergeable receive buffer in the zerocopy XDP path by
> utilizing XDP buffer with frags.
>
> Signed-off-by: Bui Quang Minh 
> ---
>  drivers/net/virtio_net.c | 123 +--
>  1 file changed, 66 insertions(+), 57 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index e53ba600605a..a9558650f205 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -45,6 +45,8 @@ module_param(napi_tx, bool, 0644);
>  #define VIRTIO_XDP_TX  BIT(0)
>  #define VIRTIO_XDP_REDIR   BIT(1)
>
> +#define VIRTNET_MAX_ZC_SEGS8
> +
>  /* RX packet size EWMA. The average packet size is used to determine the 
> packet
>   * buffer size when refilling RX rings. As the entire RX ring may be refilled
>   * at once, the weight is chosen so that the EWMA will be insensitive to 
> short-
> @@ -1232,65 +1234,53 @@ static void xsk_drop_follow_bufs(struct net_device 
> *dev,
> }
>  }
>
> -static int xsk_append_merge_buffer(struct virtnet_info *vi,
> -  struct receive_queue *rq,
> -  struct sk_buff *head_skb,
> -  u32 num_buf,
> -  struct virtio_net_hdr_mrg_rxbuf *hdr,
> -  struct virtnet_rq_stats *stats)
> +static int virtnet_build_xsk_buff_mrg(struct virtnet_info *vi,
> + struct receive_queue *rq,
> + u32 num_buf,
> + struct xdp_buff *xdp,
> + struct virtnet_rq_stats *stats)
>  {
> -   struct sk_buff *curr_skb;
> -   struct xdp_buff *xdp;
> -   u32 len, truesize;
> -   struct page *page;
> +   unsigned int len;
> void *buf;
>
> -   curr_skb = head_skb;
> +   if (num_buf < 2)
> +   return 0;
> +
> +   while (num_buf > 1) {
> +   struct xdp_buff *new_xdp;
>
> -   while (--num_buf) {
> buf = virtqueue_get_buf(rq->vq, &len);
> -   if (unlikely(!buf)) {
> -   pr_debug("%s: rx error: %d buffers out of %d 
> missing\n",
> -vi->dev->name, num_buf,
> -virtio16_to_cpu(vi->vdev,
> -hdr->num_buffers));
> +   if (!unlikely(buf)) {
> +   pr_debug("%s: rx error: %d buffers missing\n",
> +vi->dev->name, num_buf);
> DEV_STATS_INC(vi->dev, rx_length_errors);
> -   return -EINVAL;
> -   }
> -
> -   u64_stats_add(&stats->bytes, len);
> -
> -   xdp = buf_to_xdp(vi, rq, buf, len);
> -   if (!xdp)
> -   goto err;
> -
> -   buf = napi_alloc_frag(len);
> -   if (!buf) {
> -   xsk_buff_free(xdp);
> -   goto err;
> +   return -1;
> }
>
> -   memcpy(buf, xdp->data - vi->hdr_len, len);
> -
> -   xsk_buff_free(xdp);
> +   new_xdp = buf_to_xdp(vi, rq, buf, len);
> +   if (!new_xdp)
> +   goto drop_bufs;
>
> -   page = virt_to_page(buf);
> +   /* In virtnet_add_recvbuf_xsk(), we ask the host to fill from
> +* xdp->data - vi->hdr_len with both virtio_net_hdr and data.
> +* However, only the first packet has the virtio_net_hdr, the
> +* following ones do not. So we need to adjust the following

Typo here.

> +* packets' data pointer to the correct place.
> +*/

I wonder what happens if we don't use this trick? I meant we don't
reuse the header room for the virtio-net header. This seems to be fine
for a mergeable buffer and can help to reduce the trick.

> +   new_xdp->data -= vi->hdr_len;
> +   new_xdp->data_end = new_xdp->data + len;
>
> -   truesize = len;
> +   if (!xsk_buff_add_frag(xdp, new_xdp))
> +   goto drop_bufs;
>
> -   curr_skb  = virtnet_skb_append_frag(head_skb, curr_skb, page,
> -   buf, len, truesize);
> -   if (!curr_skb) {
> -   put_page(page);
> -   goto err;
> -   }
> +   num_buf--;
> }
>
> return 0;
>
> -err:
> +drop_bufs:
> xsk_drop_follow_bufs(vi->dev, rq, num_buf, stats);
> -   return -EINVAL;
> +   return -1;
>  }
>
>  static struc

Re: [RFC PATCH net-next v2 1/2] virtio-net: support zerocopy multi buffer XDP in mergeable

2025-05-28 Thread Bui Quang Minh

On 5/28/25 23:44, ALOK TIWARI wrote:



On 27-05-2025 21:49, Bui Quang Minh wrote:

Currently, in zerocopy mode with mergeable receive buffer, virtio-net
does not support multi buffer but a single buffer only. This commit adds
support for multi mergeable receive buffer in the zerocopy XDP path by
utilizing XDP buffer with frags.

Signed-off-by: Bui Quang Minh 
---
  drivers/net/virtio_net.c | 123 +--
  1 file changed, 66 insertions(+), 57 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index e53ba600605a..a9558650f205 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -45,6 +45,8 @@ module_param(napi_tx, bool, 0644);
  #define VIRTIO_XDP_TX    BIT(0)
  #define VIRTIO_XDP_REDIR    BIT(1)
  +#define VIRTNET_MAX_ZC_SEGS    8
+
  /* RX packet size EWMA. The average packet size is used to 
determine the packet
   * buffer size when refilling RX rings. As the entire RX ring may 
be refilled
   * at once, the weight is chosen so that the EWMA will be 
insensitive to short-
@@ -1232,65 +1234,53 @@ static void xsk_drop_follow_bufs(struct 
net_device *dev,

  }
  }
  -static int xsk_append_merge_buffer(struct virtnet_info *vi,
-   struct receive_queue *rq,
-   struct sk_buff *head_skb,
-   u32 num_buf,
-   struct virtio_net_hdr_mrg_rxbuf *hdr,
-   struct virtnet_rq_stats *stats)
+static int virtnet_build_xsk_buff_mrg(struct virtnet_info *vi,
+  struct receive_queue *rq,
+  u32 num_buf,
+  struct xdp_buff *xdp,
+  struct virtnet_rq_stats *stats)
  {
-    struct sk_buff *curr_skb;
-    struct xdp_buff *xdp;
-    u32 len, truesize;
-    struct page *page;
+    unsigned int len;
  void *buf;
  -    curr_skb = head_skb;
+    if (num_buf < 2)
+    return 0;
+
+    while (num_buf > 1) {
+    struct xdp_buff *new_xdp;
  -    while (--num_buf) {
  buf = virtqueue_get_buf(rq->vq, &len);
-    if (unlikely(!buf)) {
-    pr_debug("%s: rx error: %d buffers out of %d missing\n",
- vi->dev->name, num_buf,
- virtio16_to_cpu(vi->vdev,
- hdr->num_buffers));
+    if (!unlikely(buf)) {


if (unlikely(!buf)) { ?


Thanks, I'll fix this in the next version.




+    pr_debug("%s: rx error: %d buffers missing\n",
+ vi->dev->name, num_buf);
  DEV_STATS_INC(vi->dev, rx_length_errors);


Thanks,
Alok





Re: [RFC PATCH net-next v2 1/2] virtio-net: support zerocopy multi buffer XDP in mergeable

2025-05-28 Thread ALOK TIWARI




On 27-05-2025 21:49, Bui Quang Minh wrote:

Currently, in zerocopy mode with mergeable receive buffer, virtio-net
does not support multi buffer but a single buffer only. This commit adds
support for multi mergeable receive buffer in the zerocopy XDP path by
utilizing XDP buffer with frags.

Signed-off-by: Bui Quang Minh 
---
  drivers/net/virtio_net.c | 123 +--
  1 file changed, 66 insertions(+), 57 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index e53ba600605a..a9558650f205 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -45,6 +45,8 @@ module_param(napi_tx, bool, 0644);
  #define VIRTIO_XDP_TX BIT(0)
  #define VIRTIO_XDP_REDIR  BIT(1)
  
+#define VIRTNET_MAX_ZC_SEGS	8

+
  /* RX packet size EWMA. The average packet size is used to determine the 
packet
   * buffer size when refilling RX rings. As the entire RX ring may be refilled
   * at once, the weight is chosen so that the EWMA will be insensitive to 
short-
@@ -1232,65 +1234,53 @@ static void xsk_drop_follow_bufs(struct net_device *dev,
}
  }
  
-static int xsk_append_merge_buffer(struct virtnet_info *vi,

-  struct receive_queue *rq,
-  struct sk_buff *head_skb,
-  u32 num_buf,
-  struct virtio_net_hdr_mrg_rxbuf *hdr,
-  struct virtnet_rq_stats *stats)
+static int virtnet_build_xsk_buff_mrg(struct virtnet_info *vi,
+ struct receive_queue *rq,
+ u32 num_buf,
+ struct xdp_buff *xdp,
+ struct virtnet_rq_stats *stats)
  {
-   struct sk_buff *curr_skb;
-   struct xdp_buff *xdp;
-   u32 len, truesize;
-   struct page *page;
+   unsigned int len;
void *buf;
  
-	curr_skb = head_skb;

+   if (num_buf < 2)
+   return 0;
+
+   while (num_buf > 1) {
+   struct xdp_buff *new_xdp;
  
-	while (--num_buf) {

buf = virtqueue_get_buf(rq->vq, &len);
-   if (unlikely(!buf)) {
-   pr_debug("%s: rx error: %d buffers out of %d missing\n",
-vi->dev->name, num_buf,
-virtio16_to_cpu(vi->vdev,
-hdr->num_buffers));
+   if (!unlikely(buf)) {


if (unlikely(!buf)) { ?


+   pr_debug("%s: rx error: %d buffers missing\n",
+vi->dev->name, num_buf);
DEV_STATS_INC(vi->dev, rx_length_errors);


Thanks,
Alok