Re: [PATCH net-next v6 09/10] virtio_net: xsk: rx: support recv merge mode

2024-06-27 Thread Xuan Zhuo
On Fri, 28 Jun 2024 10:19:44 +0800, Jason Wang  wrote:
> On Tue, Jun 18, 2024 at 3:57 PM Xuan Zhuo  wrote:
> >
> > Support AF-XDP for merge mode.
> >
> > Signed-off-by: Xuan Zhuo 
> > ---
> >  drivers/net/virtio_net.c | 139 +++
> >  1 file changed, 139 insertions(+)
> >
> > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > index 06608d696e2e..cfa106aa8039 100644
> > --- a/drivers/net/virtio_net.c
> > +++ b/drivers/net/virtio_net.c
> > @@ -504,6 +504,10 @@ static int virtnet_xdp_handler(struct bpf_prog 
> > *xdp_prog, struct xdp_buff *xdp,
> >struct net_device *dev,
> >unsigned int *xdp_xmit,
> >struct virtnet_rq_stats *stats);
> > +static struct sk_buff *virtnet_skb_append_frag(struct sk_buff *head_skb,
> > +  struct sk_buff *curr_skb,
> > +  struct page *page, void *buf,
> > +  int len, int truesize);
> >
> >  static bool is_xdp_frame(void *ptr)
> >  {
> > @@ -1128,6 +1132,139 @@ static struct sk_buff 
> > *virtnet_receive_xsk_small(struct net_device *dev, struct
> > }
> >  }
> >
> > +static void xsk_drop_follow_bufs(struct net_device *dev,
> > +struct receive_queue *rq,
> > +u32 num_buf,
> > +struct virtnet_rq_stats *stats)
> > +{
> > +   struct xdp_buff *xdp;
> > +   u32 len;
> > +
> > +   while (num_buf-- > 1) {
> > +   xdp = virtqueue_get_buf(rq->vq, &len);
> > +   if (unlikely(!xdp)) {
> > +   pr_debug("%s: rx error: %d buffers missing\n",
> > +dev->name, num_buf);
> > +   DEV_STATS_INC(dev, rx_length_errors);
> > +   break;
> > +   }
> > +   u64_stats_add(&stats->bytes, len);
> > +   xsk_buff_free(xdp);
> > +   }
> > +}
> > +
> > +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)
> > +{
> > +   struct sk_buff *curr_skb;
> > +   struct xdp_buff *xdp;
> > +   u32 len, truesize;
> > +   struct page *page;
> > +   void *buf;
> > +
> > +   curr_skb = head_skb;
> > +
> > +   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));
> > +   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);
>
> So we don't do this for non xsk paths. Any reason we can't reuse the
> existing codes?

Do you mean this code:

while (--num_buf) {
int num_skb_frags;

->  buf = virtnet_rq_get_buf(rq, &len, &ctx);
if (unlikely(!buf)) {
pr_debug("%s: rx error: %d buffers out of %d missing\n",
 dev->name, num_buf,
 virtio16_to_cpu(vi->vdev,
 hdr->num_buffers));
DEV_STATS_INC(dev, rx_length_errors);
goto err_buf;
}

u64_stats_add(&stats->bytes, len);
page = virt_to_head_page(buf);

->  truesize = mergeable_ctx_to_truesize(ctx);
->  headroom = mergeable_ctx_to_headroom(ctx);
->  tailroom = headroom ? sizeof(struct skb_shared_info) : 0;
->  room = SKB_DATA_ALIGN(headroom + tailroom);
->  if (unlikely(len > truesize - room)) {
->  pr_debug("%s: rx error: len %u exceeds truesize %lu\n",
->   dev->name, len, (unsigned long)(truesize - 
room));
->  DEV_STATS_INC(dev, rx_length_errors);
->  goto err_skb;
->  }

curr_skb  = virtnet_skb_append_frag(head_skb, curr_skb, page,
buf

Re: [PATCH net-next v6 09/10] virtio_net: xsk: rx: support recv merge mode

2024-06-27 Thread Jason Wang
On Tue, Jun 18, 2024 at 3:57 PM Xuan Zhuo  wrote:
>
> Support AF-XDP for merge mode.
>
> Signed-off-by: Xuan Zhuo 
> ---
>  drivers/net/virtio_net.c | 139 +++
>  1 file changed, 139 insertions(+)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 06608d696e2e..cfa106aa8039 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -504,6 +504,10 @@ static int virtnet_xdp_handler(struct bpf_prog 
> *xdp_prog, struct xdp_buff *xdp,
>struct net_device *dev,
>unsigned int *xdp_xmit,
>struct virtnet_rq_stats *stats);
> +static struct sk_buff *virtnet_skb_append_frag(struct sk_buff *head_skb,
> +  struct sk_buff *curr_skb,
> +  struct page *page, void *buf,
> +  int len, int truesize);
>
>  static bool is_xdp_frame(void *ptr)
>  {
> @@ -1128,6 +1132,139 @@ static struct sk_buff 
> *virtnet_receive_xsk_small(struct net_device *dev, struct
> }
>  }
>
> +static void xsk_drop_follow_bufs(struct net_device *dev,
> +struct receive_queue *rq,
> +u32 num_buf,
> +struct virtnet_rq_stats *stats)
> +{
> +   struct xdp_buff *xdp;
> +   u32 len;
> +
> +   while (num_buf-- > 1) {
> +   xdp = virtqueue_get_buf(rq->vq, &len);
> +   if (unlikely(!xdp)) {
> +   pr_debug("%s: rx error: %d buffers missing\n",
> +dev->name, num_buf);
> +   DEV_STATS_INC(dev, rx_length_errors);
> +   break;
> +   }
> +   u64_stats_add(&stats->bytes, len);
> +   xsk_buff_free(xdp);
> +   }
> +}
> +
> +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)
> +{
> +   struct sk_buff *curr_skb;
> +   struct xdp_buff *xdp;
> +   u32 len, truesize;
> +   struct page *page;
> +   void *buf;
> +
> +   curr_skb = head_skb;
> +
> +   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));
> +   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);

So we don't do this for non xsk paths. Any reason we can't reuse the
existing codes?

Thanks




Re: [PATCH net-next v6 09/10] virtio_net: xsk: rx: support recv merge mode

2024-06-20 Thread Xuan Zhuo
On Thu, 20 Jun 2024 12:37:43 +0200, Paolo Abeni  wrote:
> On Tue, 2024-06-18 at 15:56 +0800, Xuan Zhuo wrote:
> > Support AF-XDP for merge mode.
> >
> > Signed-off-by: Xuan Zhuo 
> > ---
> >  drivers/net/virtio_net.c | 139 +++
> >  1 file changed, 139 insertions(+)
> >
> > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> > index 06608d696e2e..cfa106aa8039 100644
> > --- a/drivers/net/virtio_net.c
> > +++ b/drivers/net/virtio_net.c
> > @@ -504,6 +504,10 @@ static int virtnet_xdp_handler(struct bpf_prog 
> > *xdp_prog, struct xdp_buff *xdp,
> >struct net_device *dev,
> >unsigned int *xdp_xmit,
> >struct virtnet_rq_stats *stats);
> > +static struct sk_buff *virtnet_skb_append_frag(struct sk_buff *head_skb,
> > +  struct sk_buff *curr_skb,
> > +  struct page *page, void *buf,
> > +  int len, int truesize);
> >
> >  static bool is_xdp_frame(void *ptr)
> >  {
> > @@ -1128,6 +1132,139 @@ static struct sk_buff 
> > *virtnet_receive_xsk_small(struct net_device *dev, struct
> > }
> >  }
> >
> > +static void xsk_drop_follow_bufs(struct net_device *dev,
> > +struct receive_queue *rq,
> > +u32 num_buf,
> > +struct virtnet_rq_stats *stats)
> > +{
> > +   struct xdp_buff *xdp;
> > +   u32 len;
> > +
> > +   while (num_buf-- > 1) {
>
> Why do you skip the last buffer? I thought it should be dropped, too?!?


Here, we just need to drop the follow bufs (num_buf - 1). The first one have be
dropped.

Thanks.


>
> Thanks!
>
> Paolo
>



Re: [PATCH net-next v6 09/10] virtio_net: xsk: rx: support recv merge mode

2024-06-20 Thread Paolo Abeni
On Tue, 2024-06-18 at 15:56 +0800, Xuan Zhuo wrote:
> Support AF-XDP for merge mode.
> 
> Signed-off-by: Xuan Zhuo 
> ---
>  drivers/net/virtio_net.c | 139 +++
>  1 file changed, 139 insertions(+)
> 
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 06608d696e2e..cfa106aa8039 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -504,6 +504,10 @@ static int virtnet_xdp_handler(struct bpf_prog 
> *xdp_prog, struct xdp_buff *xdp,
>  struct net_device *dev,
>  unsigned int *xdp_xmit,
>  struct virtnet_rq_stats *stats);
> +static struct sk_buff *virtnet_skb_append_frag(struct sk_buff *head_skb,
> +struct sk_buff *curr_skb,
> +struct page *page, void *buf,
> +int len, int truesize);
>  
>  static bool is_xdp_frame(void *ptr)
>  {
> @@ -1128,6 +1132,139 @@ static struct sk_buff 
> *virtnet_receive_xsk_small(struct net_device *dev, struct
>   }
>  }
>  
> +static void xsk_drop_follow_bufs(struct net_device *dev,
> +  struct receive_queue *rq,
> +  u32 num_buf,
> +  struct virtnet_rq_stats *stats)
> +{
> + struct xdp_buff *xdp;
> + u32 len;
> +
> + while (num_buf-- > 1) {

Why do you skip the last buffer? I thought it should be dropped, too?!?

Thanks!

Paolo




[PATCH net-next v6 09/10] virtio_net: xsk: rx: support recv merge mode

2024-06-18 Thread Xuan Zhuo
Support AF-XDP for merge mode.

Signed-off-by: Xuan Zhuo 
---
 drivers/net/virtio_net.c | 139 +++
 1 file changed, 139 insertions(+)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 06608d696e2e..cfa106aa8039 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -504,6 +504,10 @@ static int virtnet_xdp_handler(struct bpf_prog *xdp_prog, 
struct xdp_buff *xdp,
   struct net_device *dev,
   unsigned int *xdp_xmit,
   struct virtnet_rq_stats *stats);
+static struct sk_buff *virtnet_skb_append_frag(struct sk_buff *head_skb,
+  struct sk_buff *curr_skb,
+  struct page *page, void *buf,
+  int len, int truesize);
 
 static bool is_xdp_frame(void *ptr)
 {
@@ -1128,6 +1132,139 @@ static struct sk_buff *virtnet_receive_xsk_small(struct 
net_device *dev, struct
}
 }
 
+static void xsk_drop_follow_bufs(struct net_device *dev,
+struct receive_queue *rq,
+u32 num_buf,
+struct virtnet_rq_stats *stats)
+{
+   struct xdp_buff *xdp;
+   u32 len;
+
+   while (num_buf-- > 1) {
+   xdp = virtqueue_get_buf(rq->vq, &len);
+   if (unlikely(!xdp)) {
+   pr_debug("%s: rx error: %d buffers missing\n",
+dev->name, num_buf);
+   DEV_STATS_INC(dev, rx_length_errors);
+   break;
+   }
+   u64_stats_add(&stats->bytes, len);
+   xsk_buff_free(xdp);
+   }
+}
+
+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)
+{
+   struct sk_buff *curr_skb;
+   struct xdp_buff *xdp;
+   u32 len, truesize;
+   struct page *page;
+   void *buf;
+
+   curr_skb = head_skb;
+
+   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));
+   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;
+   }
+
+   memcpy(buf, xdp->data - vi->hdr_len, len);
+
+   xsk_buff_free(xdp);
+
+   page = virt_to_page(buf);
+
+   truesize = len;
+
+   curr_skb  = virtnet_skb_append_frag(head_skb, curr_skb, page,
+   buf, len, truesize);
+   if (!curr_skb) {
+   put_page(page);
+   goto err;
+   }
+   }
+
+   return 0;
+
+err:
+   xsk_drop_follow_bufs(vi->dev, rq, num_buf, stats);
+   return -EINVAL;
+}
+
+static struct sk_buff *virtnet_receive_xsk_merge(struct net_device *dev, 
struct virtnet_info *vi,
+struct receive_queue *rq, 
struct xdp_buff *xdp,
+unsigned int *xdp_xmit,
+struct virtnet_rq_stats *stats)
+{
+   struct virtio_net_hdr_mrg_rxbuf *hdr;
+   struct bpf_prog *prog;
+   struct sk_buff *skb;
+   u32 ret, num_buf;
+
+   hdr = xdp->data - vi->hdr_len;
+   num_buf = virtio16_to_cpu(vi->vdev, hdr->num_buffers);
+
+   ret = XDP_PASS;
+   rcu_read_lock();
+   prog = rcu_dereference(rq->xdp_prog);
+   /* TODO: support multi buffer. */
+   if (prog && num_buf == 1)
+   ret = virtnet_xdp_handler(prog, xdp, dev, xdp_xmit, stats);
+   rcu_read_unlock();
+
+   switch (ret) {
+   case XDP_PASS:
+   skb = xdp_construct_skb(rq, xdp);
+   if (!skb)
+   goto drop_bufs;
+
+   if (xsk_append_merge_buffer(vi, rq, skb, num_buf, hdr, stats)) {
+   dev_kfree_skb(skb);
+   goto drop;
+   }
+