net/af_xdp: support need wakeup feature

This patch enables need_wakeup flag for Tx and fill rings, when this
flag is set by the driver, it means that the userspace application has
to explicitly wake up the kernel Rx or kernel Tx processing by issuing
a syscall. Poll() can wake up both and sendto() or its alternatives
will wake up Tx processing only.

This feature is to provide efficient support for case that application
and driver executing on the same core.

Signed-off-by: Xiaolong Ye <xiaolong.ye@intel.com>
Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
This commit is contained in:
Xiaolong Ye 2019-06-28 18:07:04 +08:00 committed by Ferruh Yigit
parent 39a9429919
commit 45bba02c95
3 changed files with 38 additions and 10 deletions

View File

@ -21,6 +21,12 @@ be added later.
Note that MTU of AF_XDP PMD is limited due to XDP lacks support for
fragmentation.
AF_XDP PMD enables need_wakeup flag by default if it is supported. This
need_wakeup feature is used to support executing application and driver on the
same core efficiently. This feature not only has a large positive performance
impact for the one core case, but also does not degrade 2 core performance and
actually improves it for Tx heavy workloads.
Options
-------
@ -41,6 +47,7 @@ This is a Linux-specific PMD, thus the following prerequisites apply:
User can install libbpf via `make install_lib` && `make install_headers` in
<kernel src tree>/tools/lib/bpf;
* A Kernel bound interface to attach to;
* For need_wakeup feature, it requires kernel version later than v5.3-rc1;
Set up an af_xdp interface
-----------------------------

View File

@ -113,6 +113,8 @@ New Features
high performance
* Added multi-queue support to allow one af_xdp vdev with multiple netdev
queues
* Enabled need_wakeup feature which can provide efficient support for case
that application and driver executing on the same core.
* **Updated telemetry library for global metrics support.**

View File

@ -5,6 +5,7 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/socket.h>
@ -90,6 +91,7 @@ struct pkt_rx_queue {
struct rx_stats stats;
struct pkt_tx_queue *pair;
struct pollfd fds[1];
int xsk_queue_idx;
};
@ -206,8 +208,14 @@ eth_af_xdp_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
return 0;
rcvd = xsk_ring_cons__peek(rx, nb_pkts, &idx_rx);
if (rcvd == 0)
if (rcvd == 0) {
#if defined(XDP_USE_NEED_WAKEUP)
if (xsk_ring_prod__needs_wakeup(fq))
(void)poll(rxq->fds, 1, 1000);
#endif
goto out;
}
if (xsk_prod_nb_free(fq, free_thresh) >= free_thresh)
(void)reserve_fill_queue(umem, ETH_AF_XDP_RX_BATCH_SIZE);
@ -279,16 +287,19 @@ kick_tx(struct pkt_tx_queue *txq)
{
struct xsk_umem_info *umem = txq->pair->umem;
while (send(xsk_socket__fd(txq->pair->xsk), NULL,
0, MSG_DONTWAIT) < 0) {
/* some thing unexpected */
if (errno != EBUSY && errno != EAGAIN && errno != EINTR)
break;
#if defined(XDP_USE_NEED_WAKEUP)
if (xsk_ring_prod__needs_wakeup(&txq->tx))
#endif
while (send(xsk_socket__fd(txq->pair->xsk), NULL,
0, MSG_DONTWAIT) < 0) {
/* some thing unexpected */
if (errno != EBUSY && errno != EAGAIN && errno != EINTR)
break;
/* pull from completion queue to leave more space */
if (errno == EAGAIN)
pull_umem_cq(umem, ETH_AF_XDP_TX_BATCH_SIZE);
}
/* pull from completion queue to leave more space */
if (errno == EAGAIN)
pull_umem_cq(umem, ETH_AF_XDP_TX_BATCH_SIZE);
}
pull_umem_cq(umem, ETH_AF_XDP_TX_BATCH_SIZE);
}
@ -622,6 +633,11 @@ xsk_configure(struct pmd_internals *internals, struct pkt_rx_queue *rxq,
cfg.libbpf_flags = 0;
cfg.xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
cfg.bind_flags = 0;
#if defined(XDP_USE_NEED_WAKEUP)
cfg.bind_flags |= XDP_USE_NEED_WAKEUP;
#endif
ret = xsk_socket__create(&rxq->xsk, internals->if_name,
rxq->xsk_queue_idx, rxq->umem->umem, &rxq->rx,
&txq->tx, &cfg);
@ -683,6 +699,9 @@ eth_rx_queue_setup(struct rte_eth_dev *dev,
goto err;
}
rxq->fds[0].fd = xsk_socket__fd(rxq->xsk);
rxq->fds[0].events = POLLIN;
rxq->umem->pmd_zc = internals->pmd_zc;
dev->data->rx_queues[rx_queue_id] = rxq;