DPDK mempools are freed when they are no longer needed.
This can happen when a port is removed or a port's mtu
is reconfigured so that a new mempool is used.
It is possible that an mbuf is attempted to be returned
to a freed mempool from NIC Tx queues and this can lead
to a segfault.
In order to prevent this, only free mempools when they
are not needed and have no in-use mbufs. As this might
not be possible immediately, create a free list of
mempools and sweep it anytime a port tries to get a
mempool.
Fixes: 8d38823bdf8b ("netdev-dpdk: fix memory leak")
Cc: [email protected]
Signed-off-by: Kevin Traynor <[email protected]>
---
lib/netdev-dpdk.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 63 insertions(+), 5 deletions(-)
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index ee39cbe..e6cd3f3 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -297,4 +297,14 @@ static struct ovs_mutex dpdk_mp_mutex
OVS_ACQ_AFTER(dpdk_mutex)
= OVS_MUTEX_INITIALIZER;
+/* Contains all 'struct dpdk_mp's. */
+static struct ovs_list dpdk_mp_free_list OVS_GUARDED_BY(dpdk_mp_mutex)
+ = OVS_LIST_INITIALIZER(&dpdk_mp_free_list);
+
+/* Wrapper for a mempool released but not yet freed. */
+struct dpdk_mp {
+ struct rte_mempool *mp;
+ struct ovs_list list_node OVS_GUARDED_BY(dpdk_mp_mutex);
+ };
+
/* There should be one 'struct dpdk_tx_queue' created for
* each cpu core. */
@@ -512,4 +522,38 @@ ovs_rte_pktmbuf_init(struct rte_mempool *mp OVS_UNUSED,
}
+/* Free unused mempools. */
+static void
+dpdk_mp_sweep(void)
+{
+ struct dpdk_mp *dmp, *next;
+
+ ovs_mutex_lock(&dpdk_mp_mutex);
+ LIST_FOR_EACH_SAFE (dmp, next, list_node, &dpdk_mp_free_list) {
+ if (rte_mempool_full(dmp->mp)) {
+ VLOG_DBG("Freeing mempool \"%s\"", dmp->mp->name);
+ ovs_list_remove(&dmp->list_node);
+ rte_mempool_free(dmp->mp);
+ rte_free(dmp);
+ }
+ }
+ ovs_mutex_unlock(&dpdk_mp_mutex);
+}
+
+/* Ensure a mempool will not be freed. */
+static void
+dpdk_mp_do_not_free(struct rte_mempool *mp) OVS_REQUIRES(dpdk_mp_mutex)
+{
+ struct dpdk_mp *dmp, *next;
+
+ LIST_FOR_EACH_SAFE (dmp, next, list_node, &dpdk_mp_free_list) {
+ if (dmp->mp == mp) {
+ VLOG_DBG("Removing mempool \"%s\" from free list", dmp->mp->name);
+ ovs_list_remove(&dmp->list_node);
+ rte_free(dmp);
+ break;
+ }
+ }
+}
+
/* Returns a valid pointer when either of the following is true:
* - a new mempool was just created;
@@ -578,4 +622,6 @@ dpdk_mp_create(struct netdev_dpdk *dev, int mtu)
VLOG_DBG("A mempool with name \"%s\" already exists at %p.",
mp_name, mp);
+ /* Ensure this reused mempool will not be freed. */
+ dpdk_mp_do_not_free(mp);
} else {
VLOG_ERR("Failed mempool \"%s\" create request of %u mbufs",
@@ -590,5 +636,5 @@ dpdk_mp_create(struct netdev_dpdk *dev, int mtu)
/* Release an existing mempool. */
static void
-dpdk_mp_free(struct rte_mempool *mp)
+dpdk_mp_release(struct rte_mempool *mp)
{
if (!mp) {
@@ -597,6 +643,16 @@ dpdk_mp_free(struct rte_mempool *mp)
ovs_mutex_lock(&dpdk_mp_mutex);
- VLOG_DBG("Releasing \"%s\" mempool", mp->name);
- rte_mempool_free(mp);
+ if (rte_mempool_full(mp)) {
+ VLOG_DBG("Freeing mempool \"%s\"", mp->name);
+ rte_mempool_free(mp);
+ } else {
+ struct dpdk_mp *dmp;
+
+ dmp = dpdk_rte_mzalloc(sizeof *dmp);
+ if (dmp) {
+ dmp->mp = mp;
+ ovs_list_push_back(&dpdk_mp_free_list, &dmp->list_node);
+ }
+ }
ovs_mutex_unlock(&dpdk_mp_mutex);
}
@@ -616,4 +672,6 @@ netdev_dpdk_mempool_configure(struct netdev_dpdk *dev)
int ret = 0;
+ dpdk_mp_sweep();
+
mp = dpdk_mp_create(dev, FRAME_LEN_TO_MTU(buf_size));
if (!mp) {
@@ -628,5 +686,5 @@ netdev_dpdk_mempool_configure(struct netdev_dpdk *dev)
if (dev->mp != mp) {
/* A new mempool was created, release the previous one. */
- dpdk_mp_free(dev->mp);
+ dpdk_mp_release(dev->mp);
} else {
ret = EEXIST;
@@ -1083,5 +1141,5 @@ common_destruct(struct netdev_dpdk *dev)
{
rte_free(dev->tx_q);
- dpdk_mp_free(dev->mp);
+ dpdk_mp_release(dev->mp);
ovs_list_remove(&dev->list_node);
--
1.8.3.1
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev