From 9ac23da1a7cf4fa194dc4f6f9415b0a47557b24b Mon Sep 17 00:00:00 2001 From: Joseph Reilly Date: Tue, 1 Aug 2023 12:42:48 +0000 Subject: [PATCH] af-xdp: detach XDP program early To mitigate a bug with AF_XDP sockets in high traffic scenarios, the XDP program must be detatched before the sockets are closed. This issue happens when large ammounts of traffic are sent to suricata and the XDP program is not removed before AF_XDP sockets are closed. I believe this is a race condition bug as detailed here: https://bugzilla.kernel.org/show_bug.cgi?id=217712 Further investigation shows this may be a bug exclusive to the driver/AMD processor combination. This commit addresses the bug by ensuring the first thread to run the deinit function removes the XDP program, which fixes the bug as detailed in the bugzilla link. Bug #6238 --- src/source-af-xdp.c | 63 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/src/source-af-xdp.c b/src/source-af-xdp.c index f68f7f5724e9..8f4b6071bd75 100644 --- a/src/source-af-xdp.c +++ b/src/source-af-xdp.c @@ -61,8 +61,10 @@ #include "util-validate.h" #ifdef HAVE_AF_XDP -#include #include +#include +#include +#include #endif #if HAVE_LINUX_IF_ETHER_H @@ -113,7 +115,9 @@ TmEcode NoAFXDPSupportExit(ThreadVars *tv, const void *initdata, void **data) #else /* We have AF_XDP support */ #define POLL_TIMEOUT 100 -#define NUM_FRAMES XSK_RING_PROD__DEFAULT_NUM_DESCS +#define NUM_FRAMES_PROD XSK_RING_PROD__DEFAULT_NUM_DESCS +#define NUM_FRAMES_CONS XSK_RING_CONS__DEFAULT_NUM_DESCS +#define NUM_FRAMES NUM_FRAMES_PROD #define FRAME_SIZE XSK_UMEM__DEFAULT_FRAME_SIZE #define MEM_BYTES (NUM_FRAMES * FRAME_SIZE * 2) #define RECONNECT_TIMEOUT 500000 @@ -636,14 +640,14 @@ static TmEcode ReceiveAFXDPThreadInit(ThreadVars *tv, const void *initdata, void ptv->threads = afxdpconfig->threads; /* Socket configuration */ - ptv->xsk.cfg.rx_size = XSK_RING_CONS__DEFAULT_NUM_DESCS; - ptv->xsk.cfg.tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS; + ptv->xsk.cfg.rx_size = NUM_FRAMES_CONS; + ptv->xsk.cfg.tx_size = NUM_FRAMES_PROD; ptv->xsk.cfg.xdp_flags = afxdpconfig->mode; ptv->xsk.cfg.bind_flags = afxdpconfig->bind_flags; /* UMEM configuration */ - ptv->umem.cfg.fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS * 2; - ptv->umem.cfg.comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS; + ptv->umem.cfg.fill_size = NUM_FRAMES_PROD * 2; + ptv->umem.cfg.comp_size = NUM_FRAMES_CONS; ptv->umem.cfg.frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE; ptv->umem.cfg.frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM; ptv->umem.cfg.flags = afxdpconfig->mem_alignment; @@ -824,15 +828,60 @@ static TmEcode ReceiveAFXDPLoop(ThreadVars *tv, void *data, void *slot) SCReturnInt(TM_ECODE_OK); } +/** + * \brief function to unload an AF_XDP program + * + */ +static void RunModeAFXDPRemoveProg(char *iface_name) +{ + unsigned int ifindex = if_nametoindex(iface_name); + + struct xdp_multiprog *progs = xdp_multiprog__get_from_ifindex(ifindex); + if (progs == NULL) { + return; + } + enum xdp_attach_mode mode = xdp_multiprog__attach_mode(progs); + + struct xdp_program *prog = NULL; + + // loop through the multiprogram struct, removing all the programs + for (prog = xdp_multiprog__next_prog(NULL, progs); prog; + prog = xdp_multiprog__next_prog(prog, progs)) { + int ret = xdp_program__detach(prog, ifindex, mode, 0); + if (ret) { + SCLogDebug("Error: cannot detatch XDP program: %s\n", strerror(errno)); + } + } + + prog = xdp_multiprog__main_prog(progs); + if (xdp_program__is_attached(prog, ifindex) != XDP_MODE_UNSPEC) { + int ret = xdp_program__detach(prog, ifindex, mode, 0); + if (ret) { + SCLogDebug("Error: cannot detatch XDP program: %s\n", strerror(errno)); + } + } +} + /** * \brief DeInit function closes af-xdp socket at exit. * \param tv pointer to ThreadVars * \param data pointer that gets cast into AFXDPPThreadVars for ptv */ +static SCMutex sync_deinit = SCMUTEX_INITIALIZER; + static TmEcode ReceiveAFXDPThreadDeinit(ThreadVars *tv, void *data) { AFXDPThreadVars *ptv = (AFXDPThreadVars *)data; + /* + * If AF_XDP is enabled, the program must be detached before the AF_XDP sockets + * are closed to mitigate a bug that causes an IO_PAGEFAULT in linux kernel + * version 5.19, unknown as of now what other versions this affects. + */ + SCMutexLock(&sync_deinit); + RunModeAFXDPRemoveProg(ptv->iface); + SCMutexUnlock(&sync_deinit); + if (ptv->xsk.xsk) { xsk_socket__delete(ptv->xsk.xsk); ptv->xsk.xsk = NULL; @@ -924,4 +973,4 @@ static TmEcode DecodeAFXDPThreadDeinit(ThreadVars *tv, void *data) /* eof */ /** * @} - */ + */ \ No newline at end of file