No send queues will be allocated for XDP filters. Attempts to transmit
packets when no XDP send queues exist will fail with EOPNOTSUPP.

Signed-off-by: Charlie Somerville <char...@charlie.bz>
---
 drivers/net/virtio_net.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 508408fbe78f..ed08998765e0 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -485,6 +485,10 @@ static struct send_queue *virtnet_xdp_sq(struct 
virtnet_info *vi)
 {
        unsigned int qp;
 
+       /* If no queue pairs are allocated for XDP use, return NULL */
+       if (vi->xdp_queue_pairs == 0)
+               return NULL;
+
        qp = vi->curr_queue_pairs - vi->xdp_queue_pairs + smp_processor_id();
        return &vi->sq[qp];
 }
@@ -514,6 +518,11 @@ static int virtnet_xdp_xmit(struct net_device *dev,
 
        sq = virtnet_xdp_sq(vi);
 
+       /* No send queue exists if program was attached with XDP_NO_TX */
+       if (unlikely(!sq)) {
+               return -EOPNOTSUPP;
+       }
+
        if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) {
                ret = -EINVAL;
                drops = n;
@@ -1464,7 +1473,7 @@ static int virtnet_poll(struct napi_struct *napi, int 
budget)
 
        if (xdp_xmit & VIRTIO_XDP_TX) {
                sq = virtnet_xdp_sq(vi);
-               if (virtqueue_kick_prepare(sq->vq) && virtqueue_notify(sq->vq)) 
{
+               if (sq && virtqueue_kick_prepare(sq->vq) && 
virtqueue_notify(sq->vq)) {
                        u64_stats_update_begin(&sq->stats.syncp);
                        sq->stats.kicks++;
                        u64_stats_update_end(&sq->stats.syncp);
@@ -2388,7 +2397,7 @@ static int virtnet_restore_guest_offloads(struct 
virtnet_info *vi)
 }
 
 static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
-                          struct netlink_ext_ack *extack)
+                          struct netlink_ext_ack *extack, u32 flags)
 {
        unsigned long int max_sz = PAGE_SIZE - sizeof(struct padded_vnet_hdr);
        struct virtnet_info *vi = netdev_priv(dev);
@@ -2418,7 +2427,7 @@ static int virtnet_xdp_set(struct net_device *dev, struct 
bpf_prog *prog,
        }
 
        curr_qp = vi->curr_queue_pairs - vi->xdp_queue_pairs;
-       if (prog)
+       if (prog && !(flags & XDP_FLAGS_NO_TX))
                xdp_qp = nr_cpu_ids;
 
        /* XDP requires extra queues for XDP_TX */
@@ -2502,7 +2511,7 @@ static int virtnet_xdp(struct net_device *dev, struct 
netdev_bpf *xdp)
 {
        switch (xdp->command) {
        case XDP_SETUP_PROG:
-               return virtnet_xdp_set(dev, xdp->prog, xdp->extack);
+               return virtnet_xdp_set(dev, xdp->prog, xdp->extack, xdp->flags);
        default:
                return -EINVAL;
        }
-- 
2.30.0

Reply via email to