diff options
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_txrx.c | 26 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_txrx.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 21 | ||||
-rw-r--r-- | drivers/net/tun.c | 37 | ||||
-rw-r--r-- | drivers/net/virtio_net.c | 66 | ||||
-rw-r--r-- | include/linux/netdevice.h | 14 | ||||
-rw-r--r-- | kernel/bpf/devmap.c | 29 | ||||
-rw-r--r-- | net/core/filter.c | 8 |
8 files changed, 139 insertions, 64 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 5efa68de935b..9b698c5acd05 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c | |||
@@ -3664,14 +3664,19 @@ netdev_tx_t i40e_lan_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | |||
3664 | * @dev: netdev | 3664 | * @dev: netdev |
3665 | * @xdp: XDP buffer | 3665 | * @xdp: XDP buffer |
3666 | * | 3666 | * |
3667 | * Returns Zero if sent, else an error code | 3667 | * Returns number of frames successfully sent. Frames that fail are |
3668 | * free'ed via XDP return API. | ||
3669 | * | ||
3670 | * For error cases, a negative errno code is returned and no-frames | ||
3671 | * are transmitted (caller must handle freeing frames). | ||
3668 | **/ | 3672 | **/ |
3669 | int i40e_xdp_xmit(struct net_device *dev, struct xdp_frame *xdpf) | 3673 | int i40e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames) |
3670 | { | 3674 | { |
3671 | struct i40e_netdev_priv *np = netdev_priv(dev); | 3675 | struct i40e_netdev_priv *np = netdev_priv(dev); |
3672 | unsigned int queue_index = smp_processor_id(); | 3676 | unsigned int queue_index = smp_processor_id(); |
3673 | struct i40e_vsi *vsi = np->vsi; | 3677 | struct i40e_vsi *vsi = np->vsi; |
3674 | int err; | 3678 | int drops = 0; |
3679 | int i; | ||
3675 | 3680 | ||
3676 | if (test_bit(__I40E_VSI_DOWN, vsi->state)) | 3681 | if (test_bit(__I40E_VSI_DOWN, vsi->state)) |
3677 | return -ENETDOWN; | 3682 | return -ENETDOWN; |
@@ -3679,11 +3684,18 @@ int i40e_xdp_xmit(struct net_device *dev, struct xdp_frame *xdpf) | |||
3679 | if (!i40e_enabled_xdp_vsi(vsi) || queue_index >= vsi->num_queue_pairs) | 3684 | if (!i40e_enabled_xdp_vsi(vsi) || queue_index >= vsi->num_queue_pairs) |
3680 | return -ENXIO; | 3685 | return -ENXIO; |
3681 | 3686 | ||
3682 | err = i40e_xmit_xdp_ring(xdpf, vsi->xdp_rings[queue_index]); | 3687 | for (i = 0; i < n; i++) { |
3683 | if (err != I40E_XDP_TX) | 3688 | struct xdp_frame *xdpf = frames[i]; |
3684 | return -ENOSPC; | 3689 | int err; |
3685 | 3690 | ||
3686 | return 0; | 3691 | err = i40e_xmit_xdp_ring(xdpf, vsi->xdp_rings[queue_index]); |
3692 | if (err != I40E_XDP_TX) { | ||
3693 | xdp_return_frame_rx_napi(xdpf); | ||
3694 | drops++; | ||
3695 | } | ||
3696 | } | ||
3697 | |||
3698 | return n - drops; | ||
3687 | } | 3699 | } |
3688 | 3700 | ||
3689 | /** | 3701 | /** |
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index fdd2c55f03a6..eb8804b3d7b6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h | |||
@@ -487,7 +487,7 @@ u32 i40e_get_tx_pending(struct i40e_ring *ring, bool in_sw); | |||
487 | void i40e_detect_recover_hung(struct i40e_vsi *vsi); | 487 | void i40e_detect_recover_hung(struct i40e_vsi *vsi); |
488 | int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size); | 488 | int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size); |
489 | bool __i40e_chk_linearize(struct sk_buff *skb); | 489 | bool __i40e_chk_linearize(struct sk_buff *skb); |
490 | int i40e_xdp_xmit(struct net_device *dev, struct xdp_frame *xdpf); | 490 | int i40e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames); |
491 | void i40e_xdp_flush(struct net_device *dev); | 491 | void i40e_xdp_flush(struct net_device *dev); |
492 | 492 | ||
493 | /** | 493 | /** |
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 6652b201df5b..9645619f7729 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | |||
@@ -10017,11 +10017,13 @@ static int ixgbe_xdp(struct net_device *dev, struct netdev_bpf *xdp) | |||
10017 | } | 10017 | } |
10018 | } | 10018 | } |
10019 | 10019 | ||
10020 | static int ixgbe_xdp_xmit(struct net_device *dev, struct xdp_frame *xdpf) | 10020 | static int ixgbe_xdp_xmit(struct net_device *dev, int n, |
10021 | struct xdp_frame **frames) | ||
10021 | { | 10022 | { |
10022 | struct ixgbe_adapter *adapter = netdev_priv(dev); | 10023 | struct ixgbe_adapter *adapter = netdev_priv(dev); |
10023 | struct ixgbe_ring *ring; | 10024 | struct ixgbe_ring *ring; |
10024 | int err; | 10025 | int drops = 0; |
10026 | int i; | ||
10025 | 10027 | ||
10026 | if (unlikely(test_bit(__IXGBE_DOWN, &adapter->state))) | 10028 | if (unlikely(test_bit(__IXGBE_DOWN, &adapter->state))) |
10027 | return -ENETDOWN; | 10029 | return -ENETDOWN; |
@@ -10033,11 +10035,18 @@ static int ixgbe_xdp_xmit(struct net_device *dev, struct xdp_frame *xdpf) | |||
10033 | if (unlikely(!ring)) | 10035 | if (unlikely(!ring)) |
10034 | return -ENXIO; | 10036 | return -ENXIO; |
10035 | 10037 | ||
10036 | err = ixgbe_xmit_xdp_ring(adapter, xdpf); | 10038 | for (i = 0; i < n; i++) { |
10037 | if (err != IXGBE_XDP_TX) | 10039 | struct xdp_frame *xdpf = frames[i]; |
10038 | return -ENOSPC; | 10040 | int err; |
10039 | 10041 | ||
10040 | return 0; | 10042 | err = ixgbe_xmit_xdp_ring(adapter, xdpf); |
10043 | if (err != IXGBE_XDP_TX) { | ||
10044 | xdp_return_frame_rx_napi(xdpf); | ||
10045 | drops++; | ||
10046 | } | ||
10047 | } | ||
10048 | |||
10049 | return n - drops; | ||
10041 | } | 10050 | } |
10042 | 10051 | ||
10043 | static void ixgbe_xdp_flush(struct net_device *dev) | 10052 | static void ixgbe_xdp_flush(struct net_device *dev) |
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 44d4f3d25350..d3dcfcb1c4b3 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -70,6 +70,7 @@ | |||
70 | #include <net/netns/generic.h> | 70 | #include <net/netns/generic.h> |
71 | #include <net/rtnetlink.h> | 71 | #include <net/rtnetlink.h> |
72 | #include <net/sock.h> | 72 | #include <net/sock.h> |
73 | #include <net/xdp.h> | ||
73 | #include <linux/seq_file.h> | 74 | #include <linux/seq_file.h> |
74 | #include <linux/uio.h> | 75 | #include <linux/uio.h> |
75 | #include <linux/skb_array.h> | 76 | #include <linux/skb_array.h> |
@@ -1290,34 +1291,44 @@ static const struct net_device_ops tun_netdev_ops = { | |||
1290 | .ndo_get_stats64 = tun_net_get_stats64, | 1291 | .ndo_get_stats64 = tun_net_get_stats64, |
1291 | }; | 1292 | }; |
1292 | 1293 | ||
1293 | static int tun_xdp_xmit(struct net_device *dev, struct xdp_frame *frame) | 1294 | static int tun_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames) |
1294 | { | 1295 | { |
1295 | struct tun_struct *tun = netdev_priv(dev); | 1296 | struct tun_struct *tun = netdev_priv(dev); |
1296 | struct tun_file *tfile; | 1297 | struct tun_file *tfile; |
1297 | u32 numqueues; | 1298 | u32 numqueues; |
1298 | int ret = 0; | 1299 | int drops = 0; |
1300 | int cnt = n; | ||
1301 | int i; | ||
1299 | 1302 | ||
1300 | rcu_read_lock(); | 1303 | rcu_read_lock(); |
1301 | 1304 | ||
1302 | numqueues = READ_ONCE(tun->numqueues); | 1305 | numqueues = READ_ONCE(tun->numqueues); |
1303 | if (!numqueues) { | 1306 | if (!numqueues) { |
1304 | ret = -ENOSPC; | 1307 | rcu_read_unlock(); |
1305 | goto out; | 1308 | return -ENXIO; /* Caller will free/return all frames */ |
1306 | } | 1309 | } |
1307 | 1310 | ||
1308 | tfile = rcu_dereference(tun->tfiles[smp_processor_id() % | 1311 | tfile = rcu_dereference(tun->tfiles[smp_processor_id() % |
1309 | numqueues]); | 1312 | numqueues]); |
1310 | /* Encode the XDP flag into lowest bit for consumer to differ | 1313 | |
1311 | * XDP buffer from sk_buff. | 1314 | spin_lock(&tfile->tx_ring.producer_lock); |
1312 | */ | 1315 | for (i = 0; i < n; i++) { |
1313 | if (ptr_ring_produce(&tfile->tx_ring, tun_xdp_to_ptr(frame))) { | 1316 | struct xdp_frame *xdp = frames[i]; |
1314 | this_cpu_inc(tun->pcpu_stats->tx_dropped); | 1317 | /* Encode the XDP flag into lowest bit for consumer to differ |
1315 | ret = -ENOSPC; | 1318 | * XDP buffer from sk_buff. |
1319 | */ | ||
1320 | void *frame = tun_xdp_to_ptr(xdp); | ||
1321 | |||
1322 | if (__ptr_ring_produce(&tfile->tx_ring, frame)) { | ||
1323 | this_cpu_inc(tun->pcpu_stats->tx_dropped); | ||
1324 | xdp_return_frame_rx_napi(xdp); | ||
1325 | drops++; | ||
1326 | } | ||
1316 | } | 1327 | } |
1328 | spin_unlock(&tfile->tx_ring.producer_lock); | ||
1317 | 1329 | ||
1318 | out: | ||
1319 | rcu_read_unlock(); | 1330 | rcu_read_unlock(); |
1320 | return ret; | 1331 | return cnt - drops; |
1321 | } | 1332 | } |
1322 | 1333 | ||
1323 | static int tun_xdp_tx(struct net_device *dev, struct xdp_buff *xdp) | 1334 | static int tun_xdp_tx(struct net_device *dev, struct xdp_buff *xdp) |
@@ -1327,7 +1338,7 @@ static int tun_xdp_tx(struct net_device *dev, struct xdp_buff *xdp) | |||
1327 | if (unlikely(!frame)) | 1338 | if (unlikely(!frame)) |
1328 | return -EOVERFLOW; | 1339 | return -EOVERFLOW; |
1329 | 1340 | ||
1330 | return tun_xdp_xmit(dev, frame); | 1341 | return tun_xdp_xmit(dev, 1, &frame); |
1331 | } | 1342 | } |
1332 | 1343 | ||
1333 | static void tun_xdp_flush(struct net_device *dev) | 1344 | static void tun_xdp_flush(struct net_device *dev) |
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index f34794a76c4d..39a0783d1cde 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
@@ -419,23 +419,13 @@ static void virtnet_xdp_flush(struct net_device *dev) | |||
419 | virtqueue_kick(sq->vq); | 419 | virtqueue_kick(sq->vq); |
420 | } | 420 | } |
421 | 421 | ||
422 | static int __virtnet_xdp_xmit(struct virtnet_info *vi, | 422 | static int __virtnet_xdp_xmit_one(struct virtnet_info *vi, |
423 | struct xdp_frame *xdpf) | 423 | struct send_queue *sq, |
424 | struct xdp_frame *xdpf) | ||
424 | { | 425 | { |
425 | struct virtio_net_hdr_mrg_rxbuf *hdr; | 426 | struct virtio_net_hdr_mrg_rxbuf *hdr; |
426 | struct xdp_frame *xdpf_sent; | ||
427 | struct send_queue *sq; | ||
428 | unsigned int len; | ||
429 | unsigned int qp; | ||
430 | int err; | 427 | int err; |
431 | 428 | ||
432 | qp = vi->curr_queue_pairs - vi->xdp_queue_pairs + smp_processor_id(); | ||
433 | sq = &vi->sq[qp]; | ||
434 | |||
435 | /* Free up any pending old buffers before queueing new ones. */ | ||
436 | while ((xdpf_sent = virtqueue_get_buf(sq->vq, &len)) != NULL) | ||
437 | xdp_return_frame(xdpf_sent); | ||
438 | |||
439 | /* virtqueue want to use data area in-front of packet */ | 429 | /* virtqueue want to use data area in-front of packet */ |
440 | if (unlikely(xdpf->metasize > 0)) | 430 | if (unlikely(xdpf->metasize > 0)) |
441 | return -EOPNOTSUPP; | 431 | return -EOPNOTSUPP; |
@@ -459,11 +449,40 @@ static int __virtnet_xdp_xmit(struct virtnet_info *vi, | |||
459 | return 0; | 449 | return 0; |
460 | } | 450 | } |
461 | 451 | ||
462 | static int virtnet_xdp_xmit(struct net_device *dev, struct xdp_frame *xdpf) | 452 | static int __virtnet_xdp_tx_xmit(struct virtnet_info *vi, |
453 | struct xdp_frame *xdpf) | ||
454 | { | ||
455 | struct xdp_frame *xdpf_sent; | ||
456 | struct send_queue *sq; | ||
457 | unsigned int len; | ||
458 | unsigned int qp; | ||
459 | |||
460 | qp = vi->curr_queue_pairs - vi->xdp_queue_pairs + smp_processor_id(); | ||
461 | sq = &vi->sq[qp]; | ||
462 | |||
463 | /* Free up any pending old buffers before queueing new ones. */ | ||
464 | while ((xdpf_sent = virtqueue_get_buf(sq->vq, &len)) != NULL) | ||
465 | xdp_return_frame(xdpf_sent); | ||
466 | |||
467 | return __virtnet_xdp_xmit_one(vi, sq, xdpf); | ||
468 | } | ||
469 | |||
470 | static int virtnet_xdp_xmit(struct net_device *dev, | ||
471 | int n, struct xdp_frame **frames) | ||
463 | { | 472 | { |
464 | struct virtnet_info *vi = netdev_priv(dev); | 473 | struct virtnet_info *vi = netdev_priv(dev); |
465 | struct receive_queue *rq = vi->rq; | 474 | struct receive_queue *rq = vi->rq; |
475 | struct xdp_frame *xdpf_sent; | ||
466 | struct bpf_prog *xdp_prog; | 476 | struct bpf_prog *xdp_prog; |
477 | struct send_queue *sq; | ||
478 | unsigned int len; | ||
479 | unsigned int qp; | ||
480 | int drops = 0; | ||
481 | int err; | ||
482 | int i; | ||
483 | |||
484 | qp = vi->curr_queue_pairs - vi->xdp_queue_pairs + smp_processor_id(); | ||
485 | sq = &vi->sq[qp]; | ||
467 | 486 | ||
468 | /* Only allow ndo_xdp_xmit if XDP is loaded on dev, as this | 487 | /* Only allow ndo_xdp_xmit if XDP is loaded on dev, as this |
469 | * indicate XDP resources have been successfully allocated. | 488 | * indicate XDP resources have been successfully allocated. |
@@ -472,7 +491,20 @@ static int virtnet_xdp_xmit(struct net_device *dev, struct xdp_frame *xdpf) | |||
472 | if (!xdp_prog) | 491 | if (!xdp_prog) |
473 | return -ENXIO; | 492 | return -ENXIO; |
474 | 493 | ||
475 | return __virtnet_xdp_xmit(vi, xdpf); | 494 | /* Free up any pending old buffers before queueing new ones. */ |
495 | while ((xdpf_sent = virtqueue_get_buf(sq->vq, &len)) != NULL) | ||
496 | xdp_return_frame(xdpf_sent); | ||
497 | |||
498 | for (i = 0; i < n; i++) { | ||
499 | struct xdp_frame *xdpf = frames[i]; | ||
500 | |||
501 | err = __virtnet_xdp_xmit_one(vi, sq, xdpf); | ||
502 | if (err) { | ||
503 | xdp_return_frame_rx_napi(xdpf); | ||
504 | drops++; | ||
505 | } | ||
506 | } | ||
507 | return n - drops; | ||
476 | } | 508 | } |
477 | 509 | ||
478 | static unsigned int virtnet_get_headroom(struct virtnet_info *vi) | 510 | static unsigned int virtnet_get_headroom(struct virtnet_info *vi) |
@@ -616,7 +648,7 @@ static struct sk_buff *receive_small(struct net_device *dev, | |||
616 | xdpf = convert_to_xdp_frame(&xdp); | 648 | xdpf = convert_to_xdp_frame(&xdp); |
617 | if (unlikely(!xdpf)) | 649 | if (unlikely(!xdpf)) |
618 | goto err_xdp; | 650 | goto err_xdp; |
619 | err = __virtnet_xdp_xmit(vi, xdpf); | 651 | err = __virtnet_xdp_tx_xmit(vi, xdpf); |
620 | if (unlikely(err)) { | 652 | if (unlikely(err)) { |
621 | trace_xdp_exception(vi->dev, xdp_prog, act); | 653 | trace_xdp_exception(vi->dev, xdp_prog, act); |
622 | goto err_xdp; | 654 | goto err_xdp; |
@@ -779,7 +811,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, | |||
779 | xdpf = convert_to_xdp_frame(&xdp); | 811 | xdpf = convert_to_xdp_frame(&xdp); |
780 | if (unlikely(!xdpf)) | 812 | if (unlikely(!xdpf)) |
781 | goto err_xdp; | 813 | goto err_xdp; |
782 | err = __virtnet_xdp_xmit(vi, xdpf); | 814 | err = __virtnet_xdp_tx_xmit(vi, xdpf); |
783 | if (unlikely(err)) { | 815 | if (unlikely(err)) { |
784 | trace_xdp_exception(vi->dev, xdp_prog, act); | 816 | trace_xdp_exception(vi->dev, xdp_prog, act); |
785 | if (unlikely(xdp_page != page)) | 817 | if (unlikely(xdp_page != page)) |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 03ed492c4e14..debdb6286170 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -1185,9 +1185,13 @@ struct dev_ifalias { | |||
1185 | * This function is used to set or query state related to XDP on the | 1185 | * This function is used to set or query state related to XDP on the |
1186 | * netdevice and manage BPF offload. See definition of | 1186 | * netdevice and manage BPF offload. See definition of |
1187 | * enum bpf_netdev_command for details. | 1187 | * enum bpf_netdev_command for details. |
1188 | * int (*ndo_xdp_xmit)(struct net_device *dev, struct xdp_frame *xdp); | 1188 | * int (*ndo_xdp_xmit)(struct net_device *dev, int n, struct xdp_frame **xdp); |
1189 | * This function is used to submit a XDP packet for transmit on a | 1189 | * This function is used to submit @n XDP packets for transmit on a |
1190 | * netdevice. | 1190 | * netdevice. Returns number of frames successfully transmitted, frames |
1191 | * that got dropped are freed/returned via xdp_return_frame(). | ||
1192 | * Returns negative number, means general error invoking ndo, meaning | ||
1193 | * no frames were xmit'ed and core-caller will free all frames. | ||
1194 | * TODO: Consider add flag to allow sending flush operation. | ||
1191 | * void (*ndo_xdp_flush)(struct net_device *dev); | 1195 | * void (*ndo_xdp_flush)(struct net_device *dev); |
1192 | * This function is used to inform the driver to flush a particular | 1196 | * This function is used to inform the driver to flush a particular |
1193 | * xdp tx queue. Must be called on same CPU as xdp_xmit. | 1197 | * xdp tx queue. Must be called on same CPU as xdp_xmit. |
@@ -1375,8 +1379,8 @@ struct net_device_ops { | |||
1375 | int needed_headroom); | 1379 | int needed_headroom); |
1376 | int (*ndo_bpf)(struct net_device *dev, | 1380 | int (*ndo_bpf)(struct net_device *dev, |
1377 | struct netdev_bpf *bpf); | 1381 | struct netdev_bpf *bpf); |
1378 | int (*ndo_xdp_xmit)(struct net_device *dev, | 1382 | int (*ndo_xdp_xmit)(struct net_device *dev, int n, |
1379 | struct xdp_frame *xdp); | 1383 | struct xdp_frame **xdp); |
1380 | void (*ndo_xdp_flush)(struct net_device *dev); | 1384 | void (*ndo_xdp_flush)(struct net_device *dev); |
1381 | }; | 1385 | }; |
1382 | 1386 | ||
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c index a9cd5c93dd2b..77908311ec98 100644 --- a/kernel/bpf/devmap.c +++ b/kernel/bpf/devmap.c | |||
@@ -232,24 +232,31 @@ static int bq_xmit_all(struct bpf_dtab_netdev *obj, | |||
232 | prefetch(xdpf); | 232 | prefetch(xdpf); |
233 | } | 233 | } |
234 | 234 | ||
235 | for (i = 0; i < bq->count; i++) { | 235 | sent = dev->netdev_ops->ndo_xdp_xmit(dev, bq->count, bq->q); |
236 | struct xdp_frame *xdpf = bq->q[i]; | 236 | if (sent < 0) { |
237 | int err; | 237 | sent = 0; |
238 | 238 | goto error; | |
239 | err = dev->netdev_ops->ndo_xdp_xmit(dev, xdpf); | ||
240 | if (err) { | ||
241 | drops++; | ||
242 | xdp_return_frame_rx_napi(xdpf); | ||
243 | } else { | ||
244 | sent++; | ||
245 | } | ||
246 | } | 239 | } |
240 | drops = bq->count - sent; | ||
241 | out: | ||
247 | bq->count = 0; | 242 | bq->count = 0; |
248 | 243 | ||
249 | trace_xdp_devmap_xmit(&obj->dtab->map, obj->bit, | 244 | trace_xdp_devmap_xmit(&obj->dtab->map, obj->bit, |
250 | sent, drops, bq->dev_rx, dev); | 245 | sent, drops, bq->dev_rx, dev); |
251 | bq->dev_rx = NULL; | 246 | bq->dev_rx = NULL; |
252 | return 0; | 247 | return 0; |
248 | error: | ||
249 | /* If ndo_xdp_xmit fails with an errno, no frames have been | ||
250 | * xmit'ed and it's our responsibility to them free all. | ||
251 | */ | ||
252 | for (i = 0; i < bq->count; i++) { | ||
253 | struct xdp_frame *xdpf = bq->q[i]; | ||
254 | |||
255 | /* RX path under NAPI protection, can return frames faster */ | ||
256 | xdp_return_frame_rx_napi(xdpf); | ||
257 | drops++; | ||
258 | } | ||
259 | goto out; | ||
253 | } | 260 | } |
254 | 261 | ||
255 | /* __dev_map_flush is called from xdp_do_flush_map() which _must_ be signaled | 262 | /* __dev_map_flush is called from xdp_do_flush_map() which _must_ be signaled |
diff --git a/net/core/filter.c b/net/core/filter.c index 36cf2f87d742..1d75f9322275 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -3039,7 +3039,7 @@ static int __bpf_tx_xdp(struct net_device *dev, | |||
3039 | u32 index) | 3039 | u32 index) |
3040 | { | 3040 | { |
3041 | struct xdp_frame *xdpf; | 3041 | struct xdp_frame *xdpf; |
3042 | int err; | 3042 | int sent; |
3043 | 3043 | ||
3044 | if (!dev->netdev_ops->ndo_xdp_xmit) { | 3044 | if (!dev->netdev_ops->ndo_xdp_xmit) { |
3045 | return -EOPNOTSUPP; | 3045 | return -EOPNOTSUPP; |
@@ -3049,9 +3049,9 @@ static int __bpf_tx_xdp(struct net_device *dev, | |||
3049 | if (unlikely(!xdpf)) | 3049 | if (unlikely(!xdpf)) |
3050 | return -EOVERFLOW; | 3050 | return -EOVERFLOW; |
3051 | 3051 | ||
3052 | err = dev->netdev_ops->ndo_xdp_xmit(dev, xdpf); | 3052 | sent = dev->netdev_ops->ndo_xdp_xmit(dev, 1, &xdpf); |
3053 | if (err) | 3053 | if (sent <= 0) |
3054 | return err; | 3054 | return sent; |
3055 | dev->netdev_ops->ndo_xdp_flush(dev); | 3055 | dev->netdev_ops->ndo_xdp_flush(dev); |
3056 | return 0; | 3056 | return 0; |
3057 | } | 3057 | } |