Skip to content

Commit 186b3c9

Browse files
jasowangdavem330
authored andcommitted
virtio-net: support XDP_REDIRECT
This patch tries to add XDP_REDIRECT for virtio-net. The changes are not complex as we could use exist XDP_TX helpers for most of the work. The rest is passing the XDP_TX to NAPI handler for implementing batching. Cc: John Fastabend <[email protected]> Signed-off-by: Jason Wang <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 3124034 commit 186b3c9

File tree

2 files changed

+62
-15
lines changed

2 files changed

+62
-15
lines changed

drivers/net/virtio_net.

Whitespace-only changes.

drivers/net/virtio_net.c

Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <linux/slab.h>
3030
#include <linux/cpu.h>
3131
#include <linux/average.h>
32+
#include <linux/filter.h>
3233
#include <net/route.h>
3334

3435
static int napi_weight = NAPI_POLL_WEIGHT;
@@ -372,8 +373,20 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
372373
return skb;
373374
}
374375

375-
static bool virtnet_xdp_xmit(struct virtnet_info *vi,
376-
struct xdp_buff *xdp)
376+
static void virtnet_xdp_flush(struct net_device *dev)
377+
{
378+
struct virtnet_info *vi = netdev_priv(dev);
379+
struct send_queue *sq;
380+
unsigned int qp;
381+
382+
qp = vi->curr_queue_pairs - vi->xdp_queue_pairs + smp_processor_id();
383+
sq = &vi->sq[qp];
384+
385+
virtqueue_kick(sq->vq);
386+
}
387+
388+
static bool __virtnet_xdp_xmit(struct virtnet_info *vi,
389+
struct xdp_buff *xdp)
377390
{
378391
struct virtio_net_hdr_mrg_rxbuf *hdr;
379392
unsigned int len;
@@ -407,10 +420,19 @@ static bool virtnet_xdp_xmit(struct virtnet_info *vi,
407420
return false;
408421
}
409422

410-
virtqueue_kick(sq->vq);
411423
return true;
412424
}
413425

426+
static int virtnet_xdp_xmit(struct net_device *dev, struct xdp_buff *xdp)
427+
{
428+
struct virtnet_info *vi = netdev_priv(dev);
429+
bool sent = __virtnet_xdp_xmit(vi, xdp);
430+
431+
if (!sent)
432+
return -ENOSPC;
433+
return 0;
434+
}
435+
414436
static unsigned int virtnet_get_headroom(struct virtnet_info *vi)
415437
{
416438
return vi->xdp_queue_pairs ? VIRTIO_XDP_HEADROOM : 0;
@@ -483,7 +505,8 @@ static struct sk_buff *receive_small(struct net_device *dev,
483505
struct virtnet_info *vi,
484506
struct receive_queue *rq,
485507
void *buf, void *ctx,
486-
unsigned int len)
508+
unsigned int len,
509+
bool *xdp_xmit)
487510
{
488511
struct sk_buff *skb;
489512
struct bpf_prog *xdp_prog;
@@ -493,7 +516,7 @@ static struct sk_buff *receive_small(struct net_device *dev,
493516
unsigned int buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) +
494517
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
495518
struct page *page = virt_to_head_page(buf);
496-
unsigned int delta = 0;
519+
unsigned int delta = 0, err;
497520
struct page *xdp_page;
498521
len -= vi->hdr_len;
499522

@@ -541,8 +564,16 @@ static struct sk_buff *receive_small(struct net_device *dev,
541564
delta = orig_data - xdp.data;
542565
break;
543566
case XDP_TX:
544-
if (unlikely(!virtnet_xdp_xmit(vi, &xdp)))
567+
if (unlikely(!__virtnet_xdp_xmit(vi, &xdp)))
545568
trace_xdp_exception(vi->dev, xdp_prog, act);
569+
else
570+
*xdp_xmit = true;
571+
rcu_read_unlock();
572+
goto xdp_xmit;
573+
case XDP_REDIRECT:
574+
err = xdp_do_redirect(dev, &xdp, xdp_prog);
575+
if (!err)
576+
*xdp_xmit = true;
546577
rcu_read_unlock();
547578
goto xdp_xmit;
548579
default:
@@ -603,7 +634,8 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
603634
struct receive_queue *rq,
604635
void *buf,
605636
void *ctx,
606-
unsigned int len)
637+
unsigned int len,
638+
bool *xdp_xmit)
607639
{
608640
struct virtio_net_hdr_mrg_rxbuf *hdr = buf;
609641
u16 num_buf = virtio16_to_cpu(vi->vdev, hdr->num_buffers);
@@ -613,6 +645,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
613645
struct bpf_prog *xdp_prog;
614646
unsigned int truesize;
615647
unsigned int headroom = mergeable_ctx_to_headroom(ctx);
648+
int err;
616649

617650
head_skb = NULL;
618651

@@ -678,12 +711,20 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
678711
}
679712
break;
680713
case XDP_TX:
681-
if (unlikely(!virtnet_xdp_xmit(vi, &xdp)))
714+
if (unlikely(!__virtnet_xdp_xmit(vi, &xdp)))
682715
trace_xdp_exception(vi->dev, xdp_prog, act);
716+
else
717+
*xdp_xmit = true;
683718
if (unlikely(xdp_page != page))
684719
goto err_xdp;
685720
rcu_read_unlock();
686721
goto xdp_xmit;
722+
case XDP_REDIRECT:
723+
err = xdp_do_redirect(dev, &xdp, xdp_prog);
724+
if (err)
725+
*xdp_xmit = true;
726+
rcu_read_unlock();
727+
goto xdp_xmit;
687728
default:
688729
bpf_warn_invalid_xdp_action(act);
689730
case XDP_ABORTED:
@@ -788,7 +829,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
788829
}
789830

790831
static int receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
791-
void *buf, unsigned int len, void **ctx)
832+
void *buf, unsigned int len, void **ctx, bool *xdp_xmit)
792833
{
793834
struct net_device *dev = vi->dev;
794835
struct sk_buff *skb;
@@ -809,11 +850,11 @@ static int receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
809850
}
810851

811852
if (vi->mergeable_rx_bufs)
812-
skb = receive_mergeable(dev, vi, rq, buf, ctx, len);
853+
skb = receive_mergeable(dev, vi, rq, buf, ctx, len, xdp_xmit);
813854
else if (vi->big_packets)
814855
skb = receive_big(dev, vi, rq, buf, len);
815856
else
816-
skb = receive_small(dev, vi, rq, buf, ctx, len);
857+
skb = receive_small(dev, vi, rq, buf, ctx, len, xdp_xmit);
817858

818859
if (unlikely(!skb))
819860
return 0;
@@ -1071,7 +1112,7 @@ static void refill_work(struct work_struct *work)
10711112
}
10721113
}
10731114

1074-
static int virtnet_receive(struct receive_queue *rq, int budget)
1115+
static int virtnet_receive(struct receive_queue *rq, int budget, bool *xdp_xmit)
10751116
{
10761117
struct virtnet_info *vi = rq->vq->vdev->priv;
10771118
unsigned int len, received = 0, bytes = 0;
@@ -1083,13 +1124,13 @@ static int virtnet_receive(struct receive_queue *rq, int budget)
10831124

10841125
while (received < budget &&
10851126
(buf = virtqueue_get_buf_ctx(rq->vq, &len, &ctx))) {
1086-
bytes += receive_buf(vi, rq, buf, len, ctx);
1127+
bytes += receive_buf(vi, rq, buf, len, ctx, xdp_xmit);
10871128
received++;
10881129
}
10891130
} else {
10901131
while (received < budget &&
10911132
(buf = virtqueue_get_buf(rq->vq, &len)) != NULL) {
1092-
bytes += receive_buf(vi, rq, buf, len, NULL);
1133+
bytes += receive_buf(vi, rq, buf, len, NULL, xdp_xmit);
10931134
received++;
10941135
}
10951136
}
@@ -1161,15 +1202,19 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
11611202
struct receive_queue *rq =
11621203
container_of(napi, struct receive_queue, napi);
11631204
unsigned int received;
1205+
bool xdp_xmit = false;
11641206

11651207
virtnet_poll_cleantx(rq);
11661208

1167-
received = virtnet_receive(rq, budget);
1209+
received = virtnet_receive(rq, budget, &xdp_xmit);
11681210

11691211
/* Out of packets? */
11701212
if (received < budget)
11711213
virtqueue_napi_complete(napi, rq->vq, received);
11721214

1215+
if (xdp_xmit)
1216+
xdp_do_flush_map();
1217+
11731218
return received;
11741219
}
11751220

@@ -2069,6 +2114,8 @@ static const struct net_device_ops virtnet_netdev = {
20692114
.ndo_poll_controller = virtnet_netpoll,
20702115
#endif
20712116
.ndo_xdp = virtnet_xdp,
2117+
.ndo_xdp_xmit = virtnet_xdp_xmit,
2118+
.ndo_xdp_flush = virtnet_xdp_flush,
20722119
.ndo_features_check = passthru_features_check,
20732120
};
20742121

0 commit comments

Comments
 (0)