From a42c41be4eed3e1ce2a42038b07ce1d3420891cd Mon Sep 17 00:00:00 2001 From: Benoît Ganne Date: Thu, 29 Apr 2021 18:24:24 +0200 Subject: af_xdp: workaround kernel race between poll() and sendmsg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior to Linux 5.6 there is a race condition between poll() and sendmsg() in the kernel. This patch protects the syscalls with a lock to prevent it, unless the NO_SYSCALL_LOCK flag is set at create time. See https://lore.kernel.org/bpf/BYAPR11MB365382C5DB1E5FCC53242609C1549@BYAPR11MB3653.namprd11.prod.outlook.com/ Type: fix Change-Id: Ie7d4f5cb41f697b11a09b6046e54d190430d76df Signed-off-by: Benoît Ganne --- src/plugins/af_xdp/input.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) (limited to 'src/plugins/af_xdp/input.c') diff --git a/src/plugins/af_xdp/input.c b/src/plugins/af_xdp/input.c index da422bdccaf..dcbf5a4b587 100644 --- a/src/plugins/af_xdp/input.c +++ b/src/plugins/af_xdp/input.c @@ -24,9 +24,9 @@ #include #include "af_xdp.h" -#define foreach_af_xdp_input_error \ - _(POLL_REQUIRED, "poll required") \ - _(POLL_FAILURES, "poll failures") +#define foreach_af_xdp_input_error \ + _ (SYSCALL_REQUIRED, "syscall required") \ + _ (SYSCALL_FAILURES, "syscall failures") typedef enum { @@ -77,25 +77,28 @@ af_xdp_device_input_refill_db (vlib_main_t * vm, af_xdp_device_t * ad, af_xdp_rxq_t * rxq, const u32 n_alloc) { - int ret; - xsk_ring_prod__submit (&rxq->fq, n_alloc); - if (!xsk_ring_prod__needs_wakeup (&rxq->fq)) + if (AF_XDP_RXQ_MODE_INTERRUPT == rxq->mode || + !xsk_ring_prod__needs_wakeup (&rxq->fq)) return; - vlib_error_count (vm, node->node_index, AF_XDP_INPUT_ERROR_POLL_REQUIRED, + vlib_error_count (vm, node->node_index, AF_XDP_INPUT_ERROR_SYSCALL_REQUIRED, 1); - struct pollfd fd = {.fd = rxq->xsk_fd,.events = POLLIN }; - ret = poll (&fd, 1, 0); - if (PREDICT_TRUE (ret >= 0)) - return; - - /* something bad is happening */ - vlib_error_count (vm, node->node_index, AF_XDP_INPUT_ERROR_POLL_FAILURES, - 1); - af_xdp_device_error (ad, "poll() failed"); + if (clib_spinlock_trylock_if_init (&rxq->syscall_lock)) + { + struct pollfd fd = { .fd = rxq->xsk_fd, .events = POLLIN | POLLOUT }; + int ret = poll (&fd, 1, 0); + clib_spinlock_unlock_if_init (&rxq->syscall_lock); + if (PREDICT_FALSE (ret < 0)) + { + /* something bad is happening */ + vlib_error_count (vm, node->node_index, + AF_XDP_INPUT_ERROR_SYSCALL_FAILURES, 1); + af_xdp_device_error (ad, "rx poll() failed"); + } + } } static_always_inline void -- cgit 1.2.3-korg