Skip to content

Commit 214e47b

Browse files
Lukas Sismisvictorjulien
authored andcommitted
dpdk: move to native queue-sized mempools
As a legacy from Suricata 7, mempool size was kept even internally as a global size. Since in Suricata 8, mempool allocation moved to per queue model, it makes sense to calculate the correct size right when loading the configuration. The previous implementation misscalculated in some scenarios the size of the mempool which prevented Suricata starting successfully. This happened, e.g. when there were 32k RX descriptors and 64 TX descs. The resulting mempool was incorrectly deduced as 32767 (2^n-1), which didn't even hold all RX descriptors. Instead, it should result to 65535. Ticket: 8370
1 parent c7cd3b1 commit 214e47b

3 files changed

Lines changed: 91 additions & 36 deletions

File tree

qa/live/dpdk/dpdk-testsuite.sh

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,31 +36,31 @@ run_test "IDS: auto mempool, auto cache (1 thread)" \
3636
--interface-cfg-set net_null0.threads=1 \
3737
--interface-cfg-set net_null0.mempool-size=auto \
3838
--interface-cfg-set net_null0.mempool-cache-size=auto \
39-
--suricata-log-check-grep "1 packet mempools of size 31, cache size 1" \
39+
--suricata-log-check-grep "1 packet mempools of size 63, cache size 21" \
4040
--expect-start \
4141
"$IDS_YAML"
4242

4343
run_test "IDS: auto mempool, auto cache (2 threads)" \
4444
--interface-cfg-set net_null0.threads=2 \
4545
--interface-cfg-set net_null0.mempool-size=auto \
4646
--interface-cfg-set net_null0.mempool-cache-size=auto \
47-
--suricata-log-check-grep "2 packet mempools of size 31, cache size 1" \
47+
--suricata-log-check-grep "2 packet mempools of size 63, cache size 21" \
4848
--expect-start \
4949
"$IDS_YAML"
5050

5151
run_test "IDS: auto mempool, static cache=1 (1 thread)" \
5252
--interface-cfg-set net_null0.threads=1 \
5353
--interface-cfg-set net_null0.mempool-size=auto \
5454
--interface-cfg-set net_null0.mempool-cache-size=1 \
55-
--suricata-log-check-grep "1 packet mempools of size 31, cache size 1" \
55+
--suricata-log-check-grep "1 packet mempools of size 63, cache size 1" \
5656
--expect-start \
5757
"$IDS_YAML"
5858

5959
run_test "IDS: auto mempool, static cache=1 (2 threads)" \
6060
--interface-cfg-set net_null0.threads=2 \
6161
--interface-cfg-set net_null0.mempool-size=auto \
6262
--interface-cfg-set net_null0.mempool-cache-size=1 \
63-
--suricata-log-check-grep "2 packet mempools of size 31, cache size 1" \
63+
--suricata-log-check-grep "2 packet mempools of size 63, cache size 1" \
6464
--expect-start \
6565
"$IDS_YAML"
6666

@@ -105,6 +105,29 @@ run_test "IDS: mempool too small (fail)" \
105105
--expect-fail \
106106
"$IDS_YAML"
107107

108+
run_test "IDS: mempool too small for queues (fail)" \
109+
--interface-cfg-set net_null0.threads=2 \
110+
--interface-cfg-set net_null0.mempool-size=1 \
111+
--suricata-log-check-grep "mempool size is likely too small" \
112+
--expect-fail \
113+
"$IDS_YAML"
114+
115+
# power-of-two boundary: 32 is exactly nb_rx_desc + nb_tx_desc, must not undercount
116+
run_test "IDS: static mempool=32, power-of-two boundary (fail)" \
117+
--interface-cfg-set net_null0.threads=1 \
118+
--interface-cfg-set net_null0.mempool-size=32 \
119+
--suricata-log-check-grep "mempool size is likely too small" \
120+
--expect-fail \
121+
"$IDS_YAML"
122+
123+
run_test "IDS: static mempool=64, power-of-two boundary (1 thread)" \
124+
--interface-cfg-set net_null0.threads=1 \
125+
--interface-cfg-set net_null0.mempool-size=64 \
126+
--interface-cfg-set net_null0.mempool-cache-size=auto \
127+
--suricata-log-check-grep "1 packet mempools of size 63, cache size 21" \
128+
--expect-start \
129+
"$IDS_YAML"
130+
108131
run_test "IDS: auto descriptors, auto mempool (OOM expected with nohuge)" \
109132
--interface-cfg-set net_null0.threads=1 \
110133
--interface-cfg-set net_null0.mempool-size=auto \
@@ -122,31 +145,31 @@ run_test "Bond: auto mempool, auto cache (1 thread)" \
122145
--interface-cfg-set net_bonding0.threads=1 \
123146
--interface-cfg-set net_bonding0.mempool-size=auto \
124147
--interface-cfg-set net_bonding0.mempool-cache-size=auto \
125-
--suricata-log-check-grep "1 packet mempools of size 63, cache size 21" \
148+
--suricata-log-check-grep "1 packet mempools of size 127, cache size 1" \
126149
--expect-start \
127150
"$BOND_YAML"
128151

129152
run_test "Bond: auto mempool, auto cache (2 threads)" \
130153
--interface-cfg-set net_bonding0.threads=2 \
131154
--interface-cfg-set net_bonding0.mempool-size=auto \
132155
--interface-cfg-set net_bonding0.mempool-cache-size=auto \
133-
--suricata-log-check-grep "2 packet mempools of size 63, cache size 21" \
156+
--suricata-log-check-grep "2 packet mempools of size 127, cache size 1" \
134157
--expect-start \
135158
"$BOND_YAML"
136159

137160
run_test "Bond: auto mempool, static cache=7 (1 thread)" \
138161
--interface-cfg-set net_bonding0.threads=1 \
139162
--interface-cfg-set net_bonding0.mempool-size=auto \
140163
--interface-cfg-set net_bonding0.mempool-cache-size=7 \
141-
--suricata-log-check-grep "1 packet mempools of size 63, cache size 7" \
164+
--suricata-log-check-grep "1 packet mempools of size 127, cache size 7" \
142165
--expect-start \
143166
"$BOND_YAML"
144167

145168
run_test "Bond: auto mempool, static cache=7 (2 threads)" \
146169
--interface-cfg-set net_bonding0.threads=2 \
147170
--interface-cfg-set net_bonding0.mempool-size=auto \
148171
--interface-cfg-set net_bonding0.mempool-cache-size=7 \
149-
--suricata-log-check-grep "2 packet mempools of size 63, cache size 7" \
172+
--suricata-log-check-grep "2 packet mempools of size 127, cache size 7" \
150173
--expect-start \
151174
"$BOND_YAML"
152175

src/runmode-dpdk.c

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -530,20 +530,53 @@ static int ConfigSetTxQueues(
530530
SCReturnInt(0);
531531
}
532532

533-
static uint32_t MempoolSizeCalculate(
533+
static uint32_t MempoolSizeCalculateAutosize(
534534
const DPDKIfaceConfig *iconf, const struct rte_eth_dev_info *dev_info)
535535
{
536-
uint32_t sz = iconf->nb_rx_queues * iconf->nb_rx_desc + iconf->nb_tx_queues * iconf->nb_tx_desc;
537-
if (!iconf->nb_tx_queues || !iconf->nb_tx_desc)
538-
sz *= 2; // double to have enough space for RX descriptors
536+
uint32_t next_p2 =
537+
rte_align32pow2(iconf->nb_rx_desc + iconf->nb_tx_desc +
538+
1); // + 1 in case number of descriptors is already a power of 2
539539

540+
uint32_t mp_size = next_p2;
540541
if (dev_info != NULL) {
541542
if (strcmp(dev_info->driver_name, "net_bonding") == 0) {
542-
sz = BondingMempoolSizeCalculate(iconf->port_id, dev_info, sz);
543+
mp_size = BondingMempoolSizeCalculate(iconf->port_id, dev_info, mp_size);
543544
}
544545
}
545546

546-
return sz;
547+
return mp_size -
548+
1; // mempool size should be n = (2^q - 1) to have all descriptors available for use
549+
}
550+
551+
static uint32_t MempoolSizeDistributeToQueues(uint32_t global_mp_size, uint16_t nic_queues)
552+
{
553+
if (nic_queues == 0) {
554+
return 0;
555+
}
556+
557+
uint32_t mp_size_per_queue = global_mp_size / nic_queues;
558+
if (mp_size_per_queue == 0) {
559+
return 0;
560+
}
561+
562+
uint32_t next_p2 = rte_align32pow2(mp_size_per_queue);
563+
return (mp_size_per_queue == next_p2 || mp_size_per_queue == next_p2 - 1)
564+
? next_p2 - 1
565+
: (next_p2 >> 1) - 1; // we must fit in the globally specified mempool size
566+
}
567+
568+
static uint32_t MempoolSizeCalculateMinimal(
569+
const DPDKIfaceConfig *iconf, const struct rte_eth_dev_info *dev_info)
570+
{
571+
uint32_t mp_size =
572+
rte_align32pow2(iconf->nb_rx_desc + iconf->nb_tx_desc +
573+
1); // + 1 in case number of descriptors is already a power of 2
574+
if (dev_info != NULL) {
575+
if (strcmp(dev_info->driver_name, "net_bonding") == 0) {
576+
mp_size = BondingMempoolSizeCalculate(iconf->port_id, dev_info, mp_size);
577+
}
578+
}
579+
return mp_size - 1;
547580
}
548581

549582
static int ConfigSetMempoolSize(
@@ -571,27 +604,30 @@ static int ConfigSetMempoolSize(
571604
SCReturnInt(-EINVAL);
572605
}
573606

574-
iconf->mempool_size = MempoolSizeCalculate(iconf, dev_info);
607+
iconf->queue_mempool_size = MempoolSizeCalculateAutosize(iconf, dev_info);
575608
SCReturnInt(0);
576609
}
577610

578-
if (StringParseUint32(&iconf->mempool_size, 10, 0, entry_str) < 0) {
611+
uint32_t global_mempool_size;
612+
if (StringParseUint32(&global_mempool_size, 10, 0, entry_str) < 0) {
579613
SCLogError("%s: mempool size entry contain non-numerical characters - \"%s\"", iconf->iface,
580614
entry_str);
581615
SCReturnInt(-EINVAL);
582616
}
583617

584-
uint32_t required_mp_size = MempoolSizeCalculate(iconf, dev_info);
585-
if (required_mp_size >
586-
iconf->mempool_size + 1) { // +1 to mask mempool size advice given in Suricata 7.0.x -
587-
// mp_size should be n = (2^q - 1)
618+
iconf->queue_mempool_size =
619+
MempoolSizeDistributeToQueues(global_mempool_size, iconf->nb_rx_queues);
620+
uint32_t required_mp_size = MempoolSizeCalculateMinimal(iconf, dev_info);
621+
if (required_mp_size > iconf->queue_mempool_size) {
622+
uint32_t required_global_mp_size =
623+
required_mp_size * iconf->nb_rx_queues + iconf->nb_rx_queues - 1;
588624
SCLogError("%s: mempool size is likely too small for the number of descriptors and queues, "
589625
"set to \"auto\" or adjust to the value of \"%" PRIu32 "\"",
590-
iconf->iface, required_mp_size);
626+
iconf->iface, required_global_mp_size);
591627
SCReturnInt(-ERANGE);
592628
}
593629

594-
if (iconf->mempool_size == 0) {
630+
if (iconf->queue_mempool_size == 0) {
595631
SCLogError("%s: mempool size requires a positive integer", iconf->iface);
596632
SCReturnInt(-ERANGE);
597633
}
@@ -613,9 +649,9 @@ static int ConfigSetMempoolCacheSize(DPDKIfaceConfig *iconf, const char *entry_s
613649
SCEnter();
614650
if (entry_str == NULL || entry_str[0] == '\0' || strcmp(entry_str, "auto") == 0) {
615651
// calculate the mempool size based on the mempool size (it needs to be already filled in)
616-
if (iconf->mempool_size == 0) {
617-
SCLogError("%s: cannot calculate mempool cache size of a mempool with size %d",
618-
iconf->iface, iconf->mempool_size);
652+
if (iconf->queue_mempool_size == 0) {
653+
SCLogError("%s: cannot calculate mempool cache size of a mempool with size %" PRIu32,
654+
iconf->iface, iconf->queue_mempool_size);
619655
SCReturnInt(-EINVAL);
620656
}
621657

@@ -1459,20 +1495,16 @@ static int DeviceConfigureQueues(DPDKIfaceConfig *iconf, const struct rte_eth_de
14591495
// +4 for VLAN header
14601496
uint16_t mtu_size = iconf->mtu + RTE_ETHER_CRC_LEN + RTE_ETHER_HDR_LEN + 4;
14611497
uint16_t mbuf_size = ROUNDUP(mtu_size, 1024) + RTE_PKTMBUF_HEADROOM;
1462-
// Follows DPDK recommendation of having a mempool size that is a power of 2 minus one.
1463-
// So e.g. mp_size of 262144 and 262143 both lead to 65535 on 4 rx queues
1464-
uint32_t raw = iconf->mempool_size / iconf->nb_rx_queues;
1465-
uint32_t next_p2 = rte_align32pow2(raw + 1);
1466-
uint32_t q_mp_sz = (next_p2 == raw + 1) ? raw : (next_p2 >> 1) - 1;
1467-
uint32_t q_mp_cache_sz = iconf->mempool_cache_size_auto ? MempoolCacheSizeCalculate(q_mp_sz)
1468-
: iconf->mempool_cache_size;
1498+
uint32_t q_mp_cache_sz = iconf->mempool_cache_size_auto
1499+
? MempoolCacheSizeCalculate(iconf->queue_mempool_size)
1500+
: iconf->mempool_cache_size;
14691501
SCLogInfo("%s: creating %u packet mempools of size %u, cache size %u, mbuf size %u",
1470-
iconf->iface, iconf->nb_rx_queues, q_mp_sz, q_mp_cache_sz, mbuf_size);
1502+
iconf->iface, iconf->nb_rx_queues, iconf->queue_mempool_size, q_mp_cache_sz, mbuf_size);
14711503
for (int i = 0; i < iconf->nb_rx_queues; i++) {
14721504
char mempool_name[64];
14731505
snprintf(mempool_name, sizeof(mempool_name), "mp_%d_%.20s", i, iconf->iface);
1474-
iconf->pkt_mempools->pkt_mp[i] = rte_pktmbuf_pool_create(
1475-
mempool_name, q_mp_sz, q_mp_cache_sz, 0, mbuf_size, (int)iconf->socket_id);
1506+
iconf->pkt_mempools->pkt_mp[i] = rte_pktmbuf_pool_create(mempool_name,
1507+
iconf->queue_mempool_size, q_mp_cache_sz, 0, mbuf_size, (int)iconf->socket_id);
14761508
if (iconf->pkt_mempools->pkt_mp[i] == NULL) {
14771509
retval = -rte_errno;
14781510
SCLogError("%s: rte_pktmbuf_pool_create failed with code %d (mempool: %s) - %s",

src/source-dpdk.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ typedef struct DPDKIfaceConfig_ {
7171
uint16_t nb_rx_desc;
7272
uint16_t nb_tx_queues;
7373
uint16_t nb_tx_desc;
74-
uint32_t mempool_size;
74+
uint32_t queue_mempool_size;
7575
uint32_t mempool_cache_size;
7676
bool mempool_cache_size_auto; // auto cache size based on mempool size
7777
DPDKDeviceResources *pkt_mempools;

0 commit comments

Comments
 (0)