From 4e0092280e93362d689ddc4914ea76d743153d4e Mon Sep 17 00:00:00 2001 From: Lukas Sismis Date: Tue, 24 Feb 2026 18:00:29 +0100 Subject: [PATCH] dpdk: scale mempool size to the number of bond members DPDK interface which were added to bond and had auto-calculated mempool size didn't have enough space as the configured descriptors and the derived mempool only considered one interface per YAML node entry. DPDK Bonding PMD allows for multiple interface to cooperate and therefore, needs more space. Ticket: 8216 (cherry picked from commit ecd15a6c7e1b0c88b230dd42f88789e1386c82b8) --- src/runmode-dpdk.c | 33 +++++++++++-------- src/source-dpdk.h | 2 +- src/util-dpdk-bonding.c | 73 +++++++++++++++++++++++++++++++++++++++++ src/util-dpdk-bonding.h | 3 ++ src/util-dpdk-common.h | 1 + 5 files changed, 97 insertions(+), 15 deletions(-) diff --git a/src/runmode-dpdk.c b/src/runmode-dpdk.c index 27ee1d836b..8f66c947ab 100644 --- a/src/runmode-dpdk.c +++ b/src/runmode-dpdk.c @@ -81,7 +81,8 @@ static int ConfigSetThreads(DPDKIfaceConfig *iconf, const char *entry_str); static int ConfigSetRxQueues(DPDKIfaceConfig *iconf, uint16_t nb_queues, uint16_t max_queues); static int ConfigSetTxQueues( DPDKIfaceConfig *iconf, uint16_t nb_queues, uint16_t max_queues, bool iface_sends_pkts); -static int ConfigSetMempoolSize(DPDKIfaceConfig *iconf, const char *entry_str); +static int ConfigSetMempoolSize( + DPDKIfaceConfig *iconf, const char *entry_str, const struct rte_eth_dev_info *dev_info); static int ConfigSetMempoolCacheSize(DPDKIfaceConfig *iconf, const char *entry_str); static int ConfigSetRxDescriptors(DPDKIfaceConfig *iconf, const char *entry_str, uint16_t max_desc); static int ConfigSetTxDescriptors( @@ -530,16 +531,23 @@ static int ConfigSetTxQueues( } static uint32_t MempoolSizeCalculate( - uint32_t rx_queues, uint32_t rx_desc, uint32_t tx_queues, uint32_t tx_desc) + const DPDKIfaceConfig *iconf, const struct rte_eth_dev_info *dev_info) { - uint32_t sz = rx_queues * rx_desc + tx_queues * tx_desc; - if (!tx_queues || !tx_desc) + uint32_t sz = iconf->nb_rx_queues * iconf->nb_rx_desc + iconf->nb_tx_queues * iconf->nb_tx_desc; + if (!iconf->nb_tx_queues || !iconf->nb_tx_desc) sz *= 2; // double to have enough space for RX descriptors + if (dev_info != NULL) { + if (strcmp(dev_info->driver_name, "net_bonding") == 0) { + sz = BondingMempoolSizeCalculate(iconf->port_id, dev_info, sz); + } + } + return sz; } -static int ConfigSetMempoolSize(DPDKIfaceConfig *iconf, const char *entry_str) +static int ConfigSetMempoolSize( + DPDKIfaceConfig *iconf, const char *entry_str, const struct rte_eth_dev_info *dev_info) { SCEnter(); if (entry_str == NULL || entry_str[0] == '\0' || strcmp(entry_str, "auto") == 0) { @@ -563,8 +571,7 @@ static int ConfigSetMempoolSize(DPDKIfaceConfig *iconf, const char *entry_str) SCReturnInt(-EINVAL); } - iconf->mempool_size = MempoolSizeCalculate( - iconf->nb_rx_queues, iconf->nb_rx_desc, iconf->nb_tx_queues, iconf->nb_tx_desc); + iconf->mempool_size = MempoolSizeCalculate(iconf, dev_info); SCReturnInt(0); } @@ -574,15 +581,13 @@ static int ConfigSetMempoolSize(DPDKIfaceConfig *iconf, const char *entry_str) SCReturnInt(-EINVAL); } - if (MempoolSizeCalculate( - iconf->nb_rx_queues, iconf->nb_rx_desc, iconf->nb_tx_queues, iconf->nb_tx_desc) > + uint32_t required_mp_size = MempoolSizeCalculate(iconf, dev_info); + if (required_mp_size > iconf->mempool_size + 1) { // +1 to mask mempool size advice given in Suricata 7.0.x - // mp_size should be n = (2^q - 1) SCLogError("%s: mempool size is likely too small for the number of descriptors and queues, " "set to \"auto\" or adjust to the value of \"%" PRIu32 "\"", - iconf->iface, - MempoolSizeCalculate(iconf->nb_rx_queues, iconf->nb_rx_desc, iconf->nb_tx_queues, - iconf->nb_tx_desc)); + iconf->iface, required_mp_size); SCReturnInt(-ERANGE); } @@ -950,8 +955,8 @@ static int ConfigLoad(DPDKIfaceConfig *iconf, const char *iface) retval = SCConfGetChildValueWithDefault( if_root, if_default, dpdk_yaml.mempool_size, &entry_str) != 1 - ? ConfigSetMempoolSize(iconf, DPDK_CONFIG_DEFAULT_MEMPOOL_SIZE) - : ConfigSetMempoolSize(iconf, entry_str); + ? ConfigSetMempoolSize(iconf, DPDK_CONFIG_DEFAULT_MEMPOOL_SIZE, &dev_info) + : ConfigSetMempoolSize(iconf, entry_str, &dev_info); if (retval < 0) SCReturnInt(retval); diff --git a/src/source-dpdk.h b/src/source-dpdk.h index 3a2f690860..da6fec2c4d 100644 --- a/src/source-dpdk.h +++ b/src/source-dpdk.h @@ -73,7 +73,7 @@ typedef struct DPDKIfaceConfig_ { uint16_t nb_tx_desc; uint32_t mempool_size; uint32_t mempool_cache_size; - bool mempool_cache_size_auto; + bool mempool_cache_size_auto; // auto cache size based on mempool size DPDKDeviceResources *pkt_mempools; uint16_t linkup_timeout; // in seconds how long to wait for link to come up SC_ATOMIC_DECLARE(uint16_t, ref); diff --git a/src/util-dpdk-bonding.c b/src/util-dpdk-bonding.c index 7a78239411..991d68fd34 100644 --- a/src/util-dpdk-bonding.c +++ b/src/util-dpdk-bonding.c @@ -81,6 +81,79 @@ uint16_t BondingMemberDevicesGet( #endif } +/** + * \brief Callback for rte_kvargs_process that increments a counter. + */ +static int BondingMemberCountCb( + const char *key __rte_unused, const char *value __rte_unused, void *opaque) +{ + uint16_t *cnt = opaque; + (*cnt)++; + return 0; +} + +/** + * \brief Count bonding member devices from the device's devargs. + * + * Bonding members are only attached when rte_eth_dev_configure() is called + * (inside bond_ethdev_configure), so rte_eth_bond_members_get() returns 0 + * during early config. Instead, parse the devargs stored during device probe + * to count member/slave entries. + * + * \param dev_info device info (must be non-NULL) + * \return number of member devices found, 0 on any failure + */ +static uint16_t BondingMemberDevCountFromDevargs(const struct rte_eth_dev_info *dev_info) +{ + if (dev_info->device == NULL) { + return 0; + } + +#if RTE_VERSION >= RTE_VERSION_NUM(22, 11, 0, 0) + const struct rte_devargs *devargs = rte_dev_devargs(dev_info->device); +#else + const struct rte_devargs *devargs = dev_info->device->devargs; +#endif + if (devargs == NULL || devargs->args == NULL) { + return 0; + } + + struct rte_kvargs *kvargs = rte_kvargs_parse(devargs->args, NULL); + if (kvargs == NULL) { + return 0; + } + + uint16_t count = 0; + int ret; +#if RTE_VERSION >= RTE_VERSION_NUM(23, 11, 0, 0) + ret = rte_kvargs_process(kvargs, "member", BondingMemberCountCb, &count); +#else + ret = rte_kvargs_process(kvargs, "slave", BondingMemberCountCb, &count); +#endif + + rte_kvargs_free(kvargs); + return ret == 0 ? count : 0; +} + +uint32_t BondingMempoolSizeCalculate( + uint16_t bond_pid, const struct rte_eth_dev_info *dev_info, uint32_t curr_mempool_size) +{ + if (curr_mempool_size == 0) { + return 0; + } + + uint16_t cnt = BondingMemberDevCountFromDevargs(dev_info); + if (cnt == 0) { + // don't adjust if unable to determine the number of bonded devices + return curr_mempool_size; + } else if (curr_mempool_size > UINT32_MAX / cnt) { + FatalError("%s: mempool size too large to adjust for %u bonded devices", + DPDKGetPortNameByPortID(bond_pid), cnt); + } + + return curr_mempool_size * cnt; +} + int32_t BondingAllDevicesSameDriver(uint16_t bond_pid) { uint16_t bonded_devs[RTE_MAX_ETHPORTS] = { 0 }; diff --git a/src/util-dpdk-bonding.h b/src/util-dpdk-bonding.h index f7fad5e648..7e998278c4 100644 --- a/src/util-dpdk-bonding.h +++ b/src/util-dpdk-bonding.h @@ -25,12 +25,15 @@ #define UTIL_DPDK_BONDING_H #include "suricata-common.h" +#include "util-dpdk-common.h" #ifdef HAVE_DPDK int32_t BondingIsBond(uint16_t pid); uint16_t BondingMemberDevicesGet( uint16_t bond_pid, uint16_t bonded_devs[], uint16_t bonded_devs_length); +uint32_t BondingMempoolSizeCalculate( + uint16_t bond_pid, const struct rte_eth_dev_info *dev_info, uint32_t mempool_size); int32_t BondingAllDevicesSameDriver(uint16_t bond_pid); const char *BondingDeviceDriverGet(uint16_t bond_pid); diff --git a/src/util-dpdk-common.h b/src/util-dpdk-common.h index 0caa2ac371..269ebc195c 100644 --- a/src/util-dpdk-common.h +++ b/src/util-dpdk-common.h @@ -37,6 +37,7 @@ #include #include #include +#include #include #if RTE_VERSION < RTE_VERSION_NUM(22, 0, 0, 0)