[RFC PATCH 8/9] virtio_net: transmit the multi-buffer xdp

Heng Qi
2022-11-22T07:44:27Z

This serves as the basis for XDP_TX and XDP_REDIRECT
to send a multi-buffer xdp_frame.

Signed-off-by: Heng Qi <hengqi@linux.alibaba.com>
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
---
drivers/net/virtio_net.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 260ce722c687..431f2126a2b5 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -543,22 +543,34 @@ static int __virtnet_xdp_xmit_one(struct virtnet_info *vi,
struct xdp_frame *xdpf)
{
struct virtio_net_hdr_mrg_rxbuf *hdr;
- int err;
+ struct skb_shared_info *shinfo;
+ int err, i;

if (unlikely(xdpf->headroom < vi->hdr_len))
return -EOVERFLOW;

- /* Make room for virtqueue hdr (also change xdpf->headroom?) */
+ shinfo = xdp_get_shared_info_from_frame(xdpf);
+ /* Need to adjust this to calculate the correct postion
+ * for shinfo of the xdpf.
+ */
+ xdpf->headroom -= vi->hdr_len;
xdpf->data -= vi->hdr_len;
/* Zero header and leave csum up to XDP layers */
hdr = xdpf->data;
memset(hdr, 0, vi->hdr_len);
xdpf->len += vi->hdr_len;

- sg_init_one(sq->sg, xdpf->data, xdpf->len);
+ sg_init_table(sq->sg, shinfo->nr_frags + 1);
+ sg_set_buf(sq->sg, xdpf->data, xdpf->len);
+ for (i = 0; i < shinfo->nr_frags; i++) {
+ skb_frag_t *frag = &shinfo->frags[i];
+
+ sg_set_page(&sq->sg[i + 1], skb_frag_page(frag),
+ skb_frag_size(frag), skb_frag_off(frag));
+ }

- err = virtqueue_add_outbuf(sq->vq, sq->sg, 1, xdp_to_ptr(xdpf),
- GFP_ATOMIC);
+ err = virtqueue_add_outbuf(sq->vq, sq->sg, shinfo->nr_frags + 1,
+ xdp_to_ptr(xdpf), GFP_ATOMIC);
if (unlikely(err))
return -ENOSPC; /* Caller handle free/refcnt */

--
2.19.1.6.gb485710b