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)