Skip to content

Commit

Permalink
virtio-net: transmit the multi-buffer xdp
Browse files Browse the repository at this point in the history
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>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Heng Qi authored and David S. Miller committed Jan 16, 2023
1 parent 22174f7 commit 97717e8
Showing 1 changed file with 26 additions and 5 deletions.
31 changes: 26 additions & 5 deletions drivers/net/virtio_net.c
Original file line number Diff line number Diff line change
@@ -570,22 +570,43 @@ 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;
u8 nr_frags = 0;
int err, i;

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

/* Make room for virtqueue hdr (also change xdpf->headroom?) */
if (unlikely(xdp_frame_has_frags(xdpf))) {
shinfo = xdp_get_shared_info_from_frame(xdpf);
nr_frags = shinfo->nr_frags;
}

/* In wrapping function virtnet_xdp_xmit(), we need to free
* up the pending old buffers, where we need to calculate the
* position of skb_shared_info in xdp_get_frame_len() and
* xdp_return_frame(), which will involve to xdpf->data and
* xdpf->headroom. Therefore, we need to update the value of
* headroom synchronously here.
*/
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, nr_frags + 1);
sg_set_buf(sq->sg, xdpf->data, xdpf->len);
for (i = 0; i < 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, nr_frags + 1,
xdp_to_ptr(xdpf), GFP_ATOMIC);
if (unlikely(err))
return -ENOSPC; /* Caller handle free/refcnt */

0 comments on commit 97717e8

Please sign in to comment.