Skip to contentSkip to conversation

Support running DPDK without hugetlbfs mountpoint

PATCH Superseded Anatoly Burakov 2 participants 35 messages Jun 1, 2018 – Jul 13, 2018

lore
Share & tools
lore
#0 lore raw

cover Support running DPDK without hugetlbfs mountpoint

This patchset adds a new command-line option "--in-memory", which takes old debug options "--huge-unlink" and "--no-shconf", and enhances them with additional functionality. This will allow DPDK to reserve hugepages anonymously instead of using hugetlbfs mountpoints. Coupled with the fact that this option also effectively enables both "--no-shconf" and "--huge-unlink" modes, DPDK will be able to run entirely in memory and not create any shared files while running - neither hugepages nor any runtime data.

This will, of course, disable secondary processes, but for use-cases this is targeted at (containers etc.), this is not a problem.

Older revisions had kernel support at 4.14+ and also required a fairly new glibc, but now due to not using memfd and using mmap() instead, minimum supported kernel version has dropped to 3.8.

RFC->v1 changes:
- Dropped memfd, using anonymous mmap() instead
- Do not deprecate old command-line parameters, instead use them as they are, and add a deprecation notice to remove them in the next release.

Anatoly Burakov (9):
fbarray: support no-shconf mode
ipc: add support for no-shconf mode
eal: add support for no-shconf for hugepage info
eal: add support for no-shconf in hugepage data file
eal: do not create runtime dir in no-shconf mode
mem: add support for hugepage-unlink mode
eal: add --in-memory option
doc: add deprecation notice for EAL command line options
mem: support in-memory mode

 doc/guides/rel_notes/deprecation.rst          |   5 +
 lib/librte_eal/bsdapp/eal/eal.c               |   3 +-
 lib/librte_eal/bsdapp/eal/eal_hugepage_info.c |   4 +
 lib/librte_eal/common/eal_common_fbarray.c    |  71 +++++----
 lib/librte_eal/common/eal_common_options.c    |  21 ++-
 lib/librte_eal/common/eal_common_proc.c       |  25 ++++
 lib/librte_eal/common/eal_internal_cfg.h      |   4 +
 lib/librte_eal/common/eal_options.h           |   2 +
 lib/librte_eal/linuxapp/eal/eal.c             |   3 +-
 .../linuxapp/eal/eal_hugepage_info.c          |  95 ++++++++----
 lib/librte_eal/linuxapp/eal/eal_memalloc.c    | 140 ++++++++++++------
 lib/librte_eal/linuxapp/eal/eal_memory.c      |  16 +-
 12 files changed, 272 insertions(+), 117 deletions(-)
Signature · 1 line
2.17.0
#1 lore raw

PATCH 1/9 fbarray: support no-shconf mode

When using --no-shconf option, the expectation is that no multiprocess will be supported as no shared files are created. However, fbarray still creates some shared files that prevent multiple processes with the same prefix from starting.

Fix this by avoiding creating shared files whenever noshconf option is specified. Since virtual areas we get from eal_get_virtual_area() are read-only, remap them as writable.

---

Notes:
RFC->v1:
- Use --no-shconf only

 lib/librte_eal/common/eal_common_fbarray.c | 71 +++++++++++++---------
 1 file changed, 42 insertions(+), 29 deletions(-)
lib/librte_eal/common/eal_common_fbarray.c +42 -29
index 019f84c18..2c8b2c218 100644
@@ -434,39 +434,52 @@ rte_fbarray_init(struct rte_fbarray *arr, const char *name, unsigned int len,
 	if (data == NULL)
 		goto fail;
 
-	eal_get_fbarray_path(path, sizeof(path), name);
+	if (internal_config.no_shconf) {
+		/* remap virtual area as writable */
+		void *new_data = mmap(data, mmap_len, PROT_READ | PROT_WRITE,
+				MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+		if (new_data == MAP_FAILED) {
+			RTE_LOG(DEBUG, EAL, "%s(): couldn't remap anonymous memory: %s\n",
+					__func__, strerror(errno));
+			goto fail;
+		}
+	} else {
+		eal_get_fbarray_path(path, sizeof(path), name);
 
-	/*
-	 * Each fbarray is unique to process namespace, i.e. the filename
-	 * depends on process prefix. Try to take out a lock and see if we
-	 * succeed. If we don't, someone else is using it already.
-	 */
-	fd = open(path, O_CREAT | O_RDWR, 0600);
-	if (fd < 0) {
-		RTE_LOG(DEBUG, EAL, "%s(): couldn't open %s: %s\n", __func__,
-				path, strerror(errno));
-		rte_errno = errno;
-		goto fail;
-	} else if (flock(fd, LOCK_EX | LOCK_NB)) {
-		RTE_LOG(DEBUG, EAL, "%s(): couldn't lock %s: %s\n", __func__,
-				path, strerror(errno));
-		rte_errno = EBUSY;
-		goto fail;
-	}
+		/*
+		 * Each fbarray is unique to process namespace, i.e. the
+		 * filename depends on process prefix. Try to take out a lock
+		 * and see if we succeed. If we don't, someone else is using it
+		 * already.
+		 */
+		fd = open(path, O_CREAT | O_RDWR, 0600);
+		if (fd < 0) {
+			RTE_LOG(DEBUG, EAL, "%s(): couldn't open %s: %s\n",
+					__func__, path, strerror(errno));
+			rte_errno = errno;
+			goto fail;
+		} else if (flock(fd, LOCK_EX | LOCK_NB)) {
+			RTE_LOG(DEBUG, EAL, "%s(): couldn't lock %s: %s\n",
+					__func__, path, strerror(errno));
+			rte_errno = EBUSY;
+			goto fail;
+		}
 
-	/* take out a non-exclusive lock, so that other processes could still
-	 * attach to it, but no other process could reinitialize it.
-	 */
-	if (flock(fd, LOCK_SH | LOCK_NB)) {
-		rte_errno = errno;
-		goto fail;
-	}
+		/* take out a non-exclusive lock, so that other processes could
+		 * still attach to it, but no other process could reinitialize
+		 * it.
+		 */
+		if (flock(fd, LOCK_SH | LOCK_NB)) {
+			rte_errno = errno;
+			goto fail;
+		}
 
-	if (resize_and_map(fd, data, mmap_len))
-		goto fail;
+		if (resize_and_map(fd, data, mmap_len))
+			goto fail;
 
-	/* we've mmap'ed the file, we can now close the fd */
-	close(fd);
+		/* we've mmap'ed the file, we can now close the fd */
+		close(fd);
+	}
 
 	/* initialize the data */
 	memset(data, 0, mmap_len);
Signature · 1 line
2.17.0
#2 lore raw

PATCH 2/9 ipc: add support for no-shconf mode

In reply to Anatoly Burakov

IPC is an inter-process communication mechanism. Since no secondaries can ever be expected to run in no-shconf mode, IPC will be useless, so do not enable it in the first place. In the interests of API usage convenience, we will still allow registering callbacks, but obviously they won't ever be triggered.

---

Notes:
RFC->v1:
- Use --no-shconf only

 lib/librte_eal/common/eal_common_proc.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)
lib/librte_eal/common/eal_common_proc.c +25 -0
index 707d8ab30..31b5394cc 100644
@@ -626,6 +626,14 @@ rte_mp_channel_init(void)
 	int dir_fd;
 	pthread_t mp_handle_tid, async_reply_handle_tid;
 
+	/* in no shared files mode, we do not have secondary processes support,
+	 * so no need to initialize IPC.
+	 */
+	if (internal_config.no_shconf) {
+		RTE_LOG(DEBUG, EAL, "No shared files mode enabled, IPC will be disabled\n");
+		return 0;
+	}
+
 	/* create filter path */
 	create_socket_path("*", path, sizeof(path));
 	strlcpy(mp_filter, basename(path), sizeof(mp_filter));
@@ -988,6 +996,12 @@ rte_mp_request_sync(struct rte_mp_msg *req, struct rte_mp_reply *reply,
 
 	if (check_input(req) == false)
 		return -1;
+
+	if (internal_config.no_shconf) {
+		RTE_LOG(DEBUG, EAL, "No shared files mode enabled, IPC is disabled\n");
+		return 0;
+	}
+
 	if (gettimeofday(&now, NULL) < 0) {
 		RTE_LOG(ERR, EAL, "Faile to get current time\n");
 		rte_errno = errno;
@@ -1072,6 +1086,12 @@ rte_mp_request_async(struct rte_mp_msg *req, const struct timespec *ts,
 
 	if (check_input(req) == false)
 		return -1;
+
+	if (internal_config.no_shconf) {
+		RTE_LOG(DEBUG, EAL, "No shared files mode enabled, IPC is disabled\n");
+		return 0;
+	}
+
 	if (gettimeofday(&now, NULL) < 0) {
 		RTE_LOG(ERR, EAL, "Faile to get current time\n");
 		rte_errno = errno;
@@ -1213,5 +1233,10 @@ rte_mp_reply(struct rte_mp_msg *msg, const char *peer)
 		return -1;
 	}
 
+	if (internal_config.no_shconf) {
+		RTE_LOG(DEBUG, EAL, "No shared files mode enabled, IPC is disabled\n");
+		return 0;
+	}
+
 	return mp_send(msg, peer, MP_REP);
 }
Signature · 1 line
2.17.0
#3 lore raw

PATCH 3/9 eal: add support for no-shconf for hugepage info

In reply to Anatoly Burakov

Do not create any shared hugepage size info files if we were asked to not create any shared files.

---

Notes:
RFC->v1:
- Use --no-shconf only

 lib/librte_eal/bsdapp/eal/eal_hugepage_info.c   | 4 ++++
 lib/librte_eal/linuxapp/eal/eal_hugepage_info.c | 4 ++++
 2 files changed, 8 insertions(+)
lib/librte_eal/bsdapp/eal/eal_hugepage_info.c +4 -0
index 836feb672..1e8f5df23 100644
@@ -101,6 +101,10 @@ eal_hugepage_info_init(void)
 	hpi->num_pages[0] = num_buffers;
 	hpi->lock_descriptor = fd;
 
+	/* for no shared files mode, do not create shared memory config */
+	if (internal_config.no_shconf)
+		return 0;
+
 	tmp_hpi = create_shared_memory(eal_hugepage_info_path(),
 			sizeof(internal_config.hugepage_info));
 	if (tmp_hpi == NULL ) {
lib/librte_eal/linuxapp/eal/eal_hugepage_info.c +4 -0
index 7eca711ba..7f8e2fd9c 100644
@@ -446,6 +446,10 @@ eal_hugepage_info_init(void)
 	if (hugepage_info_init() < 0)
 		return -1;
 
+	/* for no shared files mode, we're done */
+	if (internal_config.no_shconf)
+		return 0;
+
 	hpi = &internal_config.hugepage_info[0];
 
 	tmp_hpi = create_shared_memory(eal_hugepage_info_path(),
Signature · 1 line
2.17.0
#4 lore raw

PATCH 4/9 eal: add support for no-shconf in hugepage data file

In reply to Anatoly Burakov

Do not create a shared hugepage data file if we were asked to not create any shared files.

---

Notes:
RFC->v1:
- Use --no-shconf only

 lib/librte_eal/linuxapp/eal/eal_memory.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)
lib/librte_eal/linuxapp/eal/eal_memory.c +12 -1
index c917de1c2..cb784e1c3 100644
@@ -521,7 +521,18 @@ static void *
 create_shared_memory(const char *filename, const size_t mem_size)
 {
 	void *retval;
-	int fd = open(filename, O_CREAT | O_RDWR, 0666);
+	int fd;
+
+	/* if no shared files mode is used, create anonymous memory instead */
+	if (internal_config.no_shconf) {
+		retval = mmap(NULL, mem_size, PROT_READ | PROT_WRITE,
+				MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+		if (retval == MAP_FAILED)
+			return NULL;
+		return retval;
+	}
+
+	fd = open(filename, O_CREAT | O_RDWR, 0666);
 	if (fd < 0)
 		return NULL;
 	if (ftruncate(fd, mem_size) < 0) {
Signature · 1 line
2.17.0
#5 lore raw

PATCH 5/9 eal: do not create runtime dir in no-shconf mode

In reply to Anatoly Burakov

Now that the rest of the EAL is adjusted to not create any shared files, prevent runtime directory from ever being created.

---

Notes:
RFC->v1:
- Use --no-shconf only

 lib/librte_eal/bsdapp/eal/eal.c   | 3 ++-
 lib/librte_eal/linuxapp/eal/eal.c | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)
lib/librte_eal/bsdapp/eal/eal.c +2 -1
index dc279542d..13b6f8ae1 100644
@@ -601,7 +601,8 @@ rte_eal_init(int argc, char **argv)
 	}
 
 	/* create runtime data directory */
-	if (eal_create_runtime_dir() < 0) {
+	if (internal_config.no_shconf == 0 &&
+			eal_create_runtime_dir() < 0) {
 		rte_eal_init_alert("Cannot create runtime directory\n");
 		rte_errno = EACCES;
 		return -1;
lib/librte_eal/linuxapp/eal/eal.c +2 -1
index 8655b8691..a8d291520 100644
@@ -818,7 +818,8 @@ rte_eal_init(int argc, char **argv)
 	}
 
 	/* create runtime data directory */
-	if (eal_create_runtime_dir() < 0) {
+	if (internal_config.no_shconf == 0 &&
+			eal_create_runtime_dir() < 0) {
 		rte_eal_init_alert("Cannot create runtime directory\n");
 		rte_errno = EACCES;
 		return -1;
Signature · 1 line
2.17.0
#6 lore raw

PATCH 6/9 mem: add support for hugepage-unlink mode

In reply to Anatoly Burakov

Unlink hugepages after creating them, to honor the hugepage-unlink mode. We cannot resize non-existing files, so make single file segments explicitly unsupported.

---

Notes:
RFC->v1:
- Use --huge-unlink only

 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)
lib/librte_eal/linuxapp/eal/eal_memalloc.c +15 -1
index 8c11f98c9..f1b6d9744 100644
@@ -512,6 +512,13 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
 				__func__, strerror(errno));
 			goto resized;
 		}
+		if (internal_config.hugepage_unlink) {
+			if (unlink(path)) {
+				RTE_LOG(DEBUG, EAL, "%s(): unlink() failed: %s\n",
+					__func__, strerror(errno));
+				goto resized;
+			}
+		}
 	}
 
 	/*
@@ -592,7 +599,8 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
 		/* ignore failure, can't make it any worse */
 	} else {
 		/* only remove file if we can take out a write lock */
-		if (lock(fd, LOCK_EX) == 1)
+		if (internal_config.hugepage_unlink == 0 &&
+				lock(fd, LOCK_EX) == 1)
 			unlink(path);
 		close(fd);
 	}
@@ -617,6 +625,12 @@ free_seg(struct rte_memseg *ms, struct hugepage_info *hi,
 		return -1;
 	}
 
+	/* if we've already unlinked the page, nothing needs to be done */
+	if (internal_config.hugepage_unlink) {
+		memset(ms, 0, sizeof(*ms));
+		return 0;
+	}
+
 	/* if we are not in single file segments mode, we're going to unmap the
 	 * segment and thus drop the lock on original fd, but hugepage dir is
 	 * now locked so we can take out another one without races.
Signature · 1 line
2.17.0
#7 lore raw

PATCH 7/9 eal: add --in-memory option

In reply to Anatoly Burakov

This command-line option will cause DPDK to operate entirely in memory and not create any shared files at runtime, including any shared configuration or hugetlbfs files. This is useful for debug purposes, as well as for certain use cases like containers or automatic memory cleanup.

Currently, this option acts as a strict superset of --no-shconf and --huge-unlink commands.

---

Notes:
RFC->v1:
- Do not deprecate old options, instead just coopt them

 lib/librte_eal/common/eal_common_options.c | 21 +++++++++++++++++++--
 lib/librte_eal/common/eal_internal_cfg.h   |  4 ++++
 lib/librte_eal/common/eal_options.h        |  2 ++
 3 files changed, 25 insertions(+), 2 deletions(-)
lib/librte_eal/common/eal_common_options.c +19 -2
index ecebb2923..b175b1446 100644
@@ -66,6 +66,7 @@ eal_long_options[] = {
 	{OPT_NO_HUGE,           0, NULL, OPT_NO_HUGE_NUM          },
 	{OPT_NO_PCI,            0, NULL, OPT_NO_PCI_NUM           },
 	{OPT_NO_SHCONF,         0, NULL, OPT_NO_SHCONF_NUM        },
+	{OPT_IN_MEMORY,         0, NULL, OPT_IN_MEMORY_NUM        },
 	{OPT_PCI_BLACKLIST,     1, NULL, OPT_PCI_BLACKLIST_NUM    },
 	{OPT_PCI_WHITELIST,     1, NULL, OPT_PCI_WHITELIST_NUM    },
 	{OPT_PROC_TYPE,         1, NULL, OPT_PROC_TYPE_NUM        },
@@ -1165,6 +1166,13 @@ eal_parse_common_option(int opt, const char *optarg,
 		conf->no_shconf = 1;
 		break;
 
+	case OPT_IN_MEMORY_NUM:
+		conf->in_memory = 1;
+		/* in-memory is a superset of noshconf and huge-unlink */
+		conf->no_shconf = 1;
+		conf->hugepage_unlink = 1;
+		break;
+
 	case OPT_PROC_TYPE_NUM:
 		conf->process_type = eal_parse_proc_type(optarg);
 		break;
@@ -1316,12 +1324,19 @@ eal_check_common_options(struct internal_config *internal_cfg)
 			"be specified together with --"OPT_NO_HUGE"\n");
 		return -1;
 	}
-
-	if (internal_cfg->no_hugetlbfs && internal_cfg->hugepage_unlink) {
+	if (internal_cfg->no_hugetlbfs && internal_cfg->hugepage_unlink &&
+			!internal_cfg->in_memory) {
 		RTE_LOG(ERR, EAL, "Option --"OPT_HUGE_UNLINK" cannot "
 			"be specified together with --"OPT_NO_HUGE"\n");
 		return -1;
 	}
+	if (internal_cfg->single_file_segments &&
+			internal_cfg->hugepage_unlink) {
+		RTE_LOG(ERR, EAL, "Option --"OPT_SINGLE_FILE_SEGMENTS" is "
+			"not compatible with neither --"OPT_IN_MEMORY" nor "
+			"--"OPT_HUGE_UNLINK"\n");
+		return -1;
+	}
 
 	return 0;
 }
@@ -1370,6 +1385,8 @@ eal_common_usage(void)
 	       "                      Set specific log level\n"
 	       "  -v                  Display version information on startup\n"
 	       "  -h, --help          This help\n"
+	       "  --"OPT_IN_MEMORY"   Operate entirely in memory. This will \n"
+	       "                      disable secondary process support\n"
 	       "\nEAL options for DEBUG use only:\n"
 	       "  --"OPT_HUGE_UNLINK"       Unlink hugepage files after init\n"
 	       "  --"OPT_NO_HUGE"           Use malloc instead of hugetlbfs\n"
lib/librte_eal/common/eal_internal_cfg.h +4 -0
index c4cbf3acd..f90d94206 100644
@@ -41,6 +41,10 @@ struct internal_config {
 	volatile unsigned vmware_tsc_map; /**< true to use VMware TSC mapping
 										* instead of native TSC */
 	volatile unsigned no_shconf;      /**< true if there is no shared config */
+	volatile unsigned in_memory;
+	/**< true if DPDK should operate entirely in-memory and not create any
+	 * shared files or runtime data.
+	 */
 	volatile unsigned create_uio_dev; /**< true to create /dev/uioX devices */
 	volatile enum rte_proc_type_t process_type; /**< multi-process proc type */
 	/** true to try allocating memory on specific sockets */
lib/librte_eal/common/eal_options.h +2 -0
index 211ae06ae..dcde4054e 100644
@@ -45,6 +45,8 @@ enum {
 	OPT_NO_PCI_NUM,
 #define OPT_NO_SHCONF         "no-shconf"
 	OPT_NO_SHCONF_NUM,
+#define OPT_IN_MEMORY         "in-memory"
+	OPT_IN_MEMORY_NUM,
 #define OPT_SOCKET_MEM        "socket-mem"
 	OPT_SOCKET_MEM_NUM,
 #define OPT_SYSLOG            "syslog"
Signature · 1 line
2.17.0
#8 lore raw

PATCH 8/9 doc: add deprecation notice for EAL command line options

In reply to Anatoly Burakov

Options --no-shconf and --huge-unlink will be removed, and replaced with --in-memory option, which will be a superset of these two, and an offially support method to run DPDK entirely in memory.

---

Notes:
RFC->v1:
- Add this patch

 doc/guides/rel_notes/deprecation.rst | 5 +++++
 1 file changed, 5 insertions(+)
doc/guides/rel_notes/deprecation.rst +5 -0
index 1ce692eac..c8344f42f 100644
@@ -8,6 +8,11 @@ API and ABI deprecation notices are to be posted here.
 Deprecation Notices
 -------------------
 
+* eal: command-line options ``--no-shconf`` and ``--huge-unlink`` will be
+    removed, and replaced with a single option ``--in-memory``, which will
+    enable DPDK to operate entirely in memory, without creating any files on any
+    filesystems.
+
 * eal: DPDK runtime configuration file (located at
   ``/var/run/.<prefix>_config``) will be moved. The new path will be as follows:
 
Signature · 1 line
2.17.0
#9 lore raw

PATCH 9/9 mem: support in-memory mode

In reply to Anatoly Burakov

Implement the final piece of the in-memory mode puzzle - enable running DPDK entirely in memory, without creating any files.

To do it, use mmap with MAP_HUGETLB and size flags to enable DPDK to work without hugetlbfs mountpoints. In order to enable this, a few things needed to be changed.

First of all, we need to allow empty hugetlbfs mountpoints in hugepage_info, and handle them correctly (by not trying to create any files and lock any directories).

Next, we need to reorder the mapping sequence, because the page is not really allocated until the page fault, and we cannot get its IOVA address before we trigger the page fault.

Finally, decide at compile time whether we are going to be supporting anonymous hugepages or not, because we cannot check for it at runtime.

---

Notes:
RFC->v1:
- Drop memfd and instead use mmap() with MAP_HUGETLB. This will drop the kernel requirements down to 3.8, and does not impose any restrictions glibc (as far as i known).

Unfortunately, there's a bit of an issue with this approach, because mmap() is stupid and will happily ignore unsupported arguments. This means that if the binary were to be compiled on a 3.8+ kernel but run on a pre-3.8 kernel (such as currently supported minimum of 3.2), then most likely the memory would be allocated using regular pages, causing unthinkable performance degradation. No solution to this problem is currently known to me.

 .../linuxapp/eal/eal_hugepage_info.c          |  91 +++++++-----
 lib/librte_eal/linuxapp/eal/eal_memalloc.c    | 130 +++++++++++-------
 lib/librte_eal/linuxapp/eal/eal_memory.c      |   3 +-
 3 files changed, 139 insertions(+), 85 deletions(-)
lib/librte_eal/linuxapp/eal/eal_hugepage_info.c +59 -32
index 7f8e2fd9c..3a7d4b222 100644
@@ -18,6 +18,8 @@
 #include <sys/queue.h>
 #include <sys/stat.h>
 
+#include <linux/mman.h> /* for hugetlb-related flags */
+
 #include <rte_memory.h>
 #include <rte_eal.h>
 #include <rte_launch.h>
@@ -313,11 +315,49 @@ compare_hpi(const void *a, const void *b)
 	return hpi_b->hugepage_sz - hpi_a->hugepage_sz;
 }
 
+static void
+calc_num_pages(struct hugepage_info *hpi, struct dirent *dirent)
+{
+	uint64_t total_pages = 0;
+	unsigned int i;
+
+	/*
+	 * first, try to put all hugepages into relevant sockets, but
+	 * if first attempts fails, fall back to collecting all pages
+	 * in one socket and sorting them later
+	 */
+	total_pages = 0;
+	/* we also don't want to do this for legacy init */
+	if (!internal_config.legacy_mem)
+		for (i = 0; i < rte_socket_count(); i++) {
+			int socket = rte_socket_id_by_idx(i);
+			unsigned int num_pages =
+					get_num_hugepages_on_node(
+						dirent->d_name, socket);
+			hpi->num_pages[socket] = num_pages;
+			total_pages += num_pages;
+		}
+	/*
+	 * we failed to sort memory from the get go, so fall
+	 * back to old way
+	 */
+	if (total_pages == 0) {
+		hpi->num_pages[0] = get_num_hugepages(dirent->d_name);
+
+#ifndef RTE_ARCH_64
+		/* for 32-bit systems, limit number of hugepages to
+		 * 1GB per page size */
+		hpi->num_pages[0] = RTE_MIN(hpi->num_pages[0],
+				RTE_PGSIZE_1G / hpi->hugepage_sz);
+#endif
+	}
+}
+
 static int
 hugepage_info_init(void)
 {	const char dirent_start_text[] = "hugepages-";
 	const size_t dirent_start_len = sizeof(dirent_start_text) - 1;
-	unsigned int i, total_pages, num_sizes = 0;
+	unsigned int i, num_sizes = 0;
 	DIR *dir;
 	struct dirent *dirent;
 
@@ -355,6 +395,22 @@ hugepage_info_init(void)
 					"%" PRIu64 " reserved, but no mounted "
 					"hugetlbfs found for that size\n",
 					num_pages, hpi->hugepage_sz);
+			/* if we have kernel support for reserving hugepages
+			 * through mmap, and we're in in-memory mode, treat this
+			 * page size as valid. we cannot be in legacy mode at
+			 * this point because we've checked this earlier in the
+			 * init process.
+			 */
+#ifdef MAP_HUGE_SHIFT
+			if (internal_config.in_memory) {
+				RTE_LOG(DEBUG, EAL, "In-memory mode enabled, "
+					"hugepages of size %" PRIu64 " bytes "
+					"will be allocated anonymously\n",
+					hpi->hugepage_sz);
+				calc_num_pages(hpi, dirent);
+				num_sizes++;
+			}
+#endif
 			continue;
 		}
 
@@ -371,35 +427,7 @@ hugepage_info_init(void)
 		if (clear_hugedir(hpi->hugedir) == -1)
 			break;
 
-		/*
-		 * first, try to put all hugepages into relevant sockets, but
-		 * if first attempts fails, fall back to collecting all pages
-		 * in one socket and sorting them later
-		 */
-		total_pages = 0;
-		/* we also don't want to do this for legacy init */
-		if (!internal_config.legacy_mem)
-			for (i = 0; i < rte_socket_count(); i++) {
-				int socket = rte_socket_id_by_idx(i);
-				unsigned int num_pages =
-						get_num_hugepages_on_node(
-							dirent->d_name, socket);
-				hpi->num_pages[socket] = num_pages;
-				total_pages += num_pages;
-			}
-		/*
-		 * we failed to sort memory from the get go, so fall
-		 * back to old way
-		 */
-		if (total_pages == 0)
-			hpi->num_pages[0] = get_num_hugepages(dirent->d_name);
-
-#ifndef RTE_ARCH_64
-		/* for 32-bit systems, limit number of hugepages to
-		 * 1GB per page size */
-		hpi->num_pages[0] = RTE_MIN(hpi->num_pages[0],
-					    RTE_PGSIZE_1G / hpi->hugepage_sz);
-#endif
+		calc_num_pages(hpi, dirent);
 
 		num_sizes++;
 	}
@@ -423,8 +451,7 @@ hugepage_info_init(void)
 
 		for (j = 0; j < RTE_MAX_NUMA_NODES; j++)
 			num_pages += hpi->num_pages[j];
-		if (strnlen(hpi->hugedir, sizeof(hpi->hugedir)) != 0 &&
-				num_pages > 0)
+		if (num_pages > 0)
 			return 0;
 	}
 
lib/librte_eal/linuxapp/eal/eal_memalloc.c +79 -51

197 lines not on this page · raw message

lib/librte_eal/linuxapp/eal/eal_memory.c +1 -2
index cb784e1c3..a98d8c036 100644
@@ -1060,8 +1060,7 @@ get_socket_mem_size(int socket)
 
 	for (i = 0; i < internal_config.num_hugepage_sizes; i++){
 		struct hugepage_info *hpi = &internal_config.hugepage_info[i];
-		if (strnlen(hpi->hugedir, sizeof(hpi->hugedir)) != 0)
-			size += hpi->hugepage_sz * hpi->num_pages[socket];
+		size += hpi->hugepage_sz * hpi->num_pages[socket];
 	}
 
 	return size;
Signature · 1 line
2.17.0
#10 lore raw

v2 cover Support running DPDK without hugetlbfs mountpoint

In reply to Anatoly Burakov

This patchset adds a new command-line option "--in-memory", which takes old debug options "--huge-unlink" and "--no-shconf", and enhances them with additional functionality. This will allow DPDK to reserve hugepages anonymously instead of using hugetlbfs mountpoints. Coupled with the fact that this option also effectively enables both "--no-shconf" and "--huge-unlink" modes, DPDK will be able to run entirely in memory and not create any shared files while running - neither hugepages nor any runtime data.

This will, of course, disable secondary processes, but for use-cases this is targeted at (containers etc.), this is not a problem.

Older revisions had kernel support at 4.14+ and also required a fairly new glibc, but now due to not using memfd and using mmap() instead, minimum supported kernel version has dropped to 3.8.

v1->v2 changes:
- Rebase on latest master
- Fix patch 5 to include check from patch 6 as commit message states

RFC->v1 changes:
- Dropped memfd, using anonymous mmap() instead
- Do not deprecate old command-line parameters, instead use them as they are, and add a deprecation notice to remove them in the next release.

Anatoly Burakov (9):
fbarray: support no-shconf mode
ipc: add support for no-shconf mode
eal: add support for no-shconf for hugepage info
eal: add support for no-shconf in hugepage data file
eal: do not create runtime dir in no-shconf mode
mem: add support for hugepage-unlink mode
eal: add --in-memory option
doc: add deprecation notice for EAL command line options
mem: support in-memory mode

 doc/guides/rel_notes/deprecation.rst          |   5 +
 lib/librte_eal/bsdapp/eal/eal.c               |   3 +-
 lib/librte_eal/bsdapp/eal/eal_hugepage_info.c |   4 +
 lib/librte_eal/common/eal_common_fbarray.c    |  71 +++++----
 lib/librte_eal/common/eal_common_options.c    |  20 ++-
 lib/librte_eal/common/eal_common_proc.c       |  25 ++++
 lib/librte_eal/common/eal_internal_cfg.h      |   4 +
 lib/librte_eal/common/eal_options.h           |   2 +
 lib/librte_eal/linuxapp/eal/eal.c             |   3 +-
 .../linuxapp/eal/eal_hugepage_info.c          |  95 ++++++++----
 lib/librte_eal/linuxapp/eal/eal_memalloc.c    | 140 ++++++++++++------
 lib/librte_eal/linuxapp/eal/eal_memory.c      |  16 +-
 12 files changed, 271 insertions(+), 117 deletions(-)
Signature · 1 line
2.17.1
#11 lore raw

PATCH v2 1/9 fbarray: support no-shconf mode

When using --no-shconf option, the expectation is that no multiprocess will be supported as no shared files are created. However, fbarray still creates some shared files that prevent multiple processes with the same prefix from starting.

Fix this by avoiding creating shared files whenever noshconf option is specified. Since virtual areas we get from eal_get_virtual_area() are read-only, remap them as writable.

---

Notes:
RFC->v1:
- Use --no-shconf only

 lib/librte_eal/common/eal_common_fbarray.c | 71 +++++++++++++---------
 1 file changed, 42 insertions(+), 29 deletions(-)
lib/librte_eal/common/eal_common_fbarray.c +42 -29
index 977174c4f..43caf3ced 100644
@@ -705,39 +705,52 @@ rte_fbarray_init(struct rte_fbarray *arr, const char *name, unsigned int len,
 	if (data == NULL)
 		goto fail;
 
-	eal_get_fbarray_path(path, sizeof(path), name);
+	if (internal_config.no_shconf) {
+		/* remap virtual area as writable */
+		void *new_data = mmap(data, mmap_len, PROT_READ | PROT_WRITE,
+				MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+		if (new_data == MAP_FAILED) {
+			RTE_LOG(DEBUG, EAL, "%s(): couldn't remap anonymous memory: %s\n",
+					__func__, strerror(errno));
+			goto fail;
+		}
+	} else {
+		eal_get_fbarray_path(path, sizeof(path), name);
 
-	/*
-	 * Each fbarray is unique to process namespace, i.e. the filename
-	 * depends on process prefix. Try to take out a lock and see if we
-	 * succeed. If we don't, someone else is using it already.
-	 */
-	fd = open(path, O_CREAT | O_RDWR, 0600);
-	if (fd < 0) {
-		RTE_LOG(DEBUG, EAL, "%s(): couldn't open %s: %s\n", __func__,
-				path, strerror(errno));
-		rte_errno = errno;
-		goto fail;
-	} else if (flock(fd, LOCK_EX | LOCK_NB)) {
-		RTE_LOG(DEBUG, EAL, "%s(): couldn't lock %s: %s\n", __func__,
-				path, strerror(errno));
-		rte_errno = EBUSY;
-		goto fail;
-	}
+		/*
+		 * Each fbarray is unique to process namespace, i.e. the
+		 * filename depends on process prefix. Try to take out a lock
+		 * and see if we succeed. If we don't, someone else is using it
+		 * already.
+		 */
+		fd = open(path, O_CREAT | O_RDWR, 0600);
+		if (fd < 0) {
+			RTE_LOG(DEBUG, EAL, "%s(): couldn't open %s: %s\n",
+					__func__, path, strerror(errno));
+			rte_errno = errno;
+			goto fail;
+		} else if (flock(fd, LOCK_EX | LOCK_NB)) {
+			RTE_LOG(DEBUG, EAL, "%s(): couldn't lock %s: %s\n",
+					__func__, path, strerror(errno));
+			rte_errno = EBUSY;
+			goto fail;
+		}
 
-	/* take out a non-exclusive lock, so that other processes could still
-	 * attach to it, but no other process could reinitialize it.
-	 */
-	if (flock(fd, LOCK_SH | LOCK_NB)) {
-		rte_errno = errno;
-		goto fail;
-	}
+		/* take out a non-exclusive lock, so that other processes could
+		 * still attach to it, but no other process could reinitialize
+		 * it.
+		 */
+		if (flock(fd, LOCK_SH | LOCK_NB)) {
+			rte_errno = errno;
+			goto fail;
+		}
 
-	if (resize_and_map(fd, data, mmap_len))
-		goto fail;
+		if (resize_and_map(fd, data, mmap_len))
+			goto fail;
 
-	/* we've mmap'ed the file, we can now close the fd */
-	close(fd);
+		/* we've mmap'ed the file, we can now close the fd */
+		close(fd);
+	}
 
 	/* initialize the data */
 	memset(data, 0, mmap_len);
Signature · 1 line
2.17.1
#12 lore raw

PATCH v2 2/9 ipc: add support for no-shconf mode

In reply to Anatoly Burakov

IPC is an inter-process communication mechanism. Since no secondaries can ever be expected to run in no-shconf mode, IPC will be useless, so do not enable it in the first place. In the interests of API usage convenience, we will still allow registering callbacks, but obviously they won't ever be triggered.

---

Notes:
RFC->v1:
- Use --no-shconf only

 lib/librte_eal/common/eal_common_proc.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)
lib/librte_eal/common/eal_common_proc.c +25 -0
index f010ef59e..c19b4b406 100644
@@ -626,6 +626,14 @@ rte_mp_channel_init(void)
 	int dir_fd;
 	pthread_t mp_handle_tid, async_reply_handle_tid;
 
+	/* in no shared files mode, we do not have secondary processes support,
+	 * so no need to initialize IPC.
+	 */
+	if (internal_config.no_shconf) {
+		RTE_LOG(DEBUG, EAL, "No shared files mode enabled, IPC will be disabled\n");
+		return 0;
+	}
+
 	/* create filter path */
 	create_socket_path("*", path, sizeof(path));
 	strlcpy(mp_filter, basename(path), sizeof(mp_filter));
@@ -988,6 +996,12 @@ rte_mp_request_sync(struct rte_mp_msg *req, struct rte_mp_reply *reply,
 
 	if (check_input(req) == false)
 		return -1;
+
+	if (internal_config.no_shconf) {
+		RTE_LOG(DEBUG, EAL, "No shared files mode enabled, IPC is disabled\n");
+		return 0;
+	}
+
 	if (gettimeofday(&now, NULL) < 0) {
 		RTE_LOG(ERR, EAL, "Faile to get current time\n");
 		rte_errno = errno;
@@ -1072,6 +1086,12 @@ rte_mp_request_async(struct rte_mp_msg *req, const struct timespec *ts,
 
 	if (check_input(req) == false)
 		return -1;
+
+	if (internal_config.no_shconf) {
+		RTE_LOG(DEBUG, EAL, "No shared files mode enabled, IPC is disabled\n");
+		return 0;
+	}
+
 	if (gettimeofday(&now, NULL) < 0) {
 		RTE_LOG(ERR, EAL, "Faile to get current time\n");
 		rte_errno = errno;
@@ -1213,5 +1233,10 @@ rte_mp_reply(struct rte_mp_msg *msg, const char *peer)
 		return -1;
 	}
 
+	if (internal_config.no_shconf) {
+		RTE_LOG(DEBUG, EAL, "No shared files mode enabled, IPC is disabled\n");
+		return 0;
+	}
+
 	return mp_send(msg, peer, MP_REP);
 }
Signature · 1 line
2.17.1
#13 lore raw

PATCH v2 3/9 eal: add support for no-shconf for hugepage info

In reply to Anatoly Burakov

Do not create any shared hugepage size info files if we were asked to not create any shared files.

---

Notes:
RFC->v1:
- Use --no-shconf only

 lib/librte_eal/bsdapp/eal/eal_hugepage_info.c   | 4 ++++
 lib/librte_eal/linuxapp/eal/eal_hugepage_info.c | 4 ++++
 2 files changed, 8 insertions(+)
lib/librte_eal/bsdapp/eal/eal_hugepage_info.c +4 -0
index 836feb672..1e8f5df23 100644
@@ -101,6 +101,10 @@ eal_hugepage_info_init(void)
 	hpi->num_pages[0] = num_buffers;
 	hpi->lock_descriptor = fd;
 
+	/* for no shared files mode, do not create shared memory config */
+	if (internal_config.no_shconf)
+		return 0;
+
 	tmp_hpi = create_shared_memory(eal_hugepage_info_path(),
 			sizeof(internal_config.hugepage_info));
 	if (tmp_hpi == NULL ) {
lib/librte_eal/linuxapp/eal/eal_hugepage_info.c +4 -0
index 7eca711ba..7f8e2fd9c 100644
@@ -446,6 +446,10 @@ eal_hugepage_info_init(void)
 	if (hugepage_info_init() < 0)
 		return -1;
 
+	/* for no shared files mode, we're done */
+	if (internal_config.no_shconf)
+		return 0;
+
 	hpi = &internal_config.hugepage_info[0];
 
 	tmp_hpi = create_shared_memory(eal_hugepage_info_path(),
Signature · 1 line
2.17.1
#14 lore raw

PATCH v2 4/9 eal: add support for no-shconf in hugepage data file

In reply to Anatoly Burakov

Do not create a shared hugepage data file if we were asked to not create any shared files.

---

Notes:
RFC->v1:
- Use --no-shconf only

 lib/librte_eal/linuxapp/eal/eal_memory.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)
lib/librte_eal/linuxapp/eal/eal_memory.c +12 -1
index 5d3c8831b..ddfa8b133 100644
@@ -521,7 +521,18 @@ static void *
 create_shared_memory(const char *filename, const size_t mem_size)
 {
 	void *retval;
-	int fd = open(filename, O_CREAT | O_RDWR, 0666);
+	int fd;
+
+	/* if no shared files mode is used, create anonymous memory instead */
+	if (internal_config.no_shconf) {
+		retval = mmap(NULL, mem_size, PROT_READ | PROT_WRITE,
+				MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+		if (retval == MAP_FAILED)
+			return NULL;
+		return retval;
+	}
+
+	fd = open(filename, O_CREAT | O_RDWR, 0666);
 	if (fd < 0)
 		return NULL;
 	if (ftruncate(fd, mem_size) < 0) {
Signature · 1 line
2.17.1
#15 lore raw

PATCH v2 5/9 eal: do not create runtime dir in no-shconf mode

In reply to Anatoly Burakov

Now that the rest of the EAL is adjusted to not create any shared files, prevent runtime directory from ever being created.

---

Notes:
RFC->v1:
- Use --no-shconf only

 lib/librte_eal/bsdapp/eal/eal.c   | 3 ++-
 lib/librte_eal/linuxapp/eal/eal.c | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)
lib/librte_eal/bsdapp/eal/eal.c +2 -1
index dc279542d..13b6f8ae1 100644
@@ -601,7 +601,8 @@ rte_eal_init(int argc, char **argv)
 	}
 
 	/* create runtime data directory */
-	if (eal_create_runtime_dir() < 0) {
+	if (internal_config.no_shconf == 0 &&
+			eal_create_runtime_dir() < 0) {
 		rte_eal_init_alert("Cannot create runtime directory\n");
 		rte_errno = EACCES;
 		return -1;
lib/librte_eal/linuxapp/eal/eal.c +2 -1
index ec7cea55d..191960caa 100644
@@ -832,7 +832,8 @@ rte_eal_init(int argc, char **argv)
 	}
 
 	/* create runtime data directory */
-	if (eal_create_runtime_dir() < 0) {
+	if (internal_config.no_shconf == 0 &&
+			eal_create_runtime_dir() < 0) {
 		rte_eal_init_alert("Cannot create runtime directory\n");
 		rte_errno = EACCES;
 		return -1;
Signature · 1 line
2.17.1
#16 lore raw

PATCH v2 6/9 mem: add support for hugepage-unlink mode

In reply to Anatoly Burakov

Unlink hugepages after creating them, to honor the hugepage-unlink mode. We cannot resize non-existing files, so make single file segments explicitly unsupported.

---

Notes:
v1->v2:
- Move check for hugepage unlink into this patch, to be consistent with commit message

RFC->v1:
- Use --huge-unlink only

RFC->v1:
- Use --huge-unlink only

 lib/librte_eal/common/eal_common_options.c |  6 ++++++
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 16 +++++++++++++++-
 2 files changed, 21 insertions(+), 1 deletion(-)
lib/librte_eal/common/eal_common_options.c +6 -0
index 45ea01a8b..df5d53648 100644
@@ -1332,6 +1332,12 @@ eal_check_common_options(struct internal_config *internal_cfg)
 			" is only supported in non-legacy memory mode\n");
 		return -1;
 	}
+	if (internal_cfg->single_file_segments &&
+			internal_cfg->hugepage_unlink) {
+		RTE_LOG(ERR, EAL, "Option --"OPT_SINGLE_FILE_SEGMENTS" is "
+			"not compatible with --"OPT_HUGE_UNLINK"\n");
+		return -1;
+	}
 
 	return 0;
 }
lib/librte_eal/linuxapp/eal/eal_memalloc.c +15 -1
index 69604f823..d610923b8 100644
@@ -489,6 +489,13 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
 				__func__, strerror(errno));
 			goto resized;
 		}
+		if (internal_config.hugepage_unlink) {
+			if (unlink(path)) {
+				RTE_LOG(DEBUG, EAL, "%s(): unlink() failed: %s\n",
+					__func__, strerror(errno));
+				goto resized;
+			}
+		}
 	}
 
 	/*
@@ -587,7 +594,8 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
 		/* ignore failure, can't make it any worse */
 	} else {
 		/* only remove file if we can take out a write lock */
-		if (lock(fd, LOCK_EX) == 1)
+		if (internal_config.hugepage_unlink == 0 &&
+				lock(fd, LOCK_EX) == 1)
 			unlink(path);
 		close(fd);
 	}
@@ -612,6 +620,12 @@ free_seg(struct rte_memseg *ms, struct hugepage_info *hi,
 		return -1;
 	}
 
+	/* if we've already unlinked the page, nothing needs to be done */
+	if (internal_config.hugepage_unlink) {
+		memset(ms, 0, sizeof(*ms));
+		return 0;
+	}
+
 	/* if we are not in single file segments mode, we're going to unmap the
 	 * segment and thus drop the lock on original fd, but hugepage dir is
 	 * now locked so we can take out another one without races.
Signature · 1 line
2.17.1
#17 lore raw

PATCH v2 7/9 eal: add --in-memory option

In reply to Anatoly Burakov

This command-line option will cause DPDK to operate entirely in memory and not create any shared files at runtime, including any shared configuration or hugetlbfs files. This is useful for debug purposes, as well as for certain use cases like containers or automatic memory cleanup.

Currently, this option acts as a strict superset of --no-shconf and --huge-unlink commands.

---

Notes:
RFC->v1:
- Do not deprecate old options, instead just coopt them

 lib/librte_eal/common/eal_common_options.c | 18 ++++++++++++++----
 lib/librte_eal/common/eal_internal_cfg.h   |  4 ++++
 lib/librte_eal/common/eal_options.h        |  2 ++
 3 files changed, 20 insertions(+), 4 deletions(-)
lib/librte_eal/common/eal_common_options.c +14 -4
index df5d53648..f308b57c3 100644
@@ -66,6 +66,7 @@ eal_long_options[] = {
 	{OPT_NO_HUGE,           0, NULL, OPT_NO_HUGE_NUM          },
 	{OPT_NO_PCI,            0, NULL, OPT_NO_PCI_NUM           },
 	{OPT_NO_SHCONF,         0, NULL, OPT_NO_SHCONF_NUM        },
+	{OPT_IN_MEMORY,         0, NULL, OPT_IN_MEMORY_NUM        },
 	{OPT_PCI_BLACKLIST,     1, NULL, OPT_PCI_BLACKLIST_NUM    },
 	{OPT_PCI_WHITELIST,     1, NULL, OPT_PCI_WHITELIST_NUM    },
 	{OPT_PROC_TYPE,         1, NULL, OPT_PROC_TYPE_NUM        },
@@ -1170,6 +1171,13 @@ eal_parse_common_option(int opt, const char *optarg,
 		conf->no_shconf = 1;
 		break;
 
+	case OPT_IN_MEMORY_NUM:
+		conf->in_memory = 1;
+		/* in-memory is a superset of noshconf and huge-unlink */
+		conf->no_shconf = 1;
+		conf->hugepage_unlink = 1;
+		break;
+
 	case OPT_PROC_TYPE_NUM:
 		conf->process_type = eal_parse_proc_type(optarg);
 		break;
@@ -1321,8 +1329,8 @@ eal_check_common_options(struct internal_config *internal_cfg)
 			"be specified together with --"OPT_NO_HUGE"\n");
 		return -1;
 	}
-
-	if (internal_cfg->no_hugetlbfs && internal_cfg->hugepage_unlink) {
+	if (internal_cfg->no_hugetlbfs && internal_cfg->hugepage_unlink &&
+			!internal_cfg->in_memory) {
 		RTE_LOG(ERR, EAL, "Option --"OPT_HUGE_UNLINK" cannot "
 			"be specified together with --"OPT_NO_HUGE"\n");
 		return -1;
@@ -1330,12 +1338,12 @@ eal_check_common_options(struct internal_config *internal_cfg)
 	if (internal_config.force_socket_limits && internal_config.legacy_mem) {
 		RTE_LOG(ERR, EAL, "Option --"OPT_SOCKET_LIMIT
 			" is only supported in non-legacy memory mode\n");
-		return -1;
 	}
 	if (internal_cfg->single_file_segments &&
 			internal_cfg->hugepage_unlink) {
 		RTE_LOG(ERR, EAL, "Option --"OPT_SINGLE_FILE_SEGMENTS" is "
-			"not compatible with --"OPT_HUGE_UNLINK"\n");
+			"not compatible with neither --"OPT_IN_MEMORY" nor "
+			"--"OPT_HUGE_UNLINK"\n");
 		return -1;
 	}
 
@@ -1386,6 +1394,8 @@ eal_common_usage(void)
 	       "                      Set specific log level\n"
 	       "  -v                  Display version information on startup\n"
 	       "  -h, --help          This help\n"
+	       "  --"OPT_IN_MEMORY"   Operate entirely in memory. This will \n"
+	       "                      disable secondary process support\n"
 	       "\nEAL options for DEBUG use only:\n"
 	       "  --"OPT_HUGE_UNLINK"       Unlink hugepage files after init\n"
 	       "  --"OPT_NO_HUGE"           Use malloc instead of hugetlbfs\n"
lib/librte_eal/common/eal_internal_cfg.h +4 -0
index d66cd0313..00ee6e06e 100644
@@ -41,6 +41,10 @@ struct internal_config {
 	volatile unsigned vmware_tsc_map; /**< true to use VMware TSC mapping
 										* instead of native TSC */
 	volatile unsigned no_shconf;      /**< true if there is no shared config */
+	volatile unsigned in_memory;
+	/**< true if DPDK should operate entirely in-memory and not create any
+	 * shared files or runtime data.
+	 */
 	volatile unsigned create_uio_dev; /**< true to create /dev/uioX devices */
 	volatile enum rte_proc_type_t process_type; /**< multi-process proc type */
 	/** true to try allocating memory on specific sockets */
lib/librte_eal/common/eal_options.h +2 -0
index 6d92f64a8..96e166787 100644
@@ -45,6 +45,8 @@ enum {
 	OPT_NO_PCI_NUM,
 #define OPT_NO_SHCONF         "no-shconf"
 	OPT_NO_SHCONF_NUM,
+#define OPT_IN_MEMORY         "in-memory"
+	OPT_IN_MEMORY_NUM,
 #define OPT_SOCKET_MEM        "socket-mem"
 	OPT_SOCKET_MEM_NUM,
 #define OPT_SOCKET_LIMIT        "socket-limit"
Signature · 1 line
2.17.1
#18 lore raw

Re: [PATCH v2 7/9] eal: add --in-memory option

13/07/2018 12:27, Anatoly Burakov:

Quoted 10 lines

This command-line option will cause DPDK to operate entirely in memory and not create any shared files at runtime, including any shared configuration or hugetlbfs files. This is useful for debug purposes, as well as for certain use cases like containers or automatic memory cleanup.

Currently, this option acts as a strict superset of --no-shconf and --huge-unlink commands.

I would like to see some support or review for this feature.

#19 lore raw

Re: [PATCH v2 7/9] eal: add --in-memory option

Quoted 7 lines · Thomas Monjalon

13/07/2018 12:27, Anatoly Burakov:

Quoted 6 lines

This command-line option will cause DPDK to operate entirely in memory and not create any shared files at runtime, including any shared configuration or hugetlbfs files. This is useful for debug purposes, as well as for certain use cases like containers or automatic memory cleanup.

Quoted 7 lines
Quoted 4 lines

Currently, this option acts as a strict superset of --no-shconf and --huge-unlink commands.

I would like to see some support or review for this feature.

While the justification for it can be use-cases like running a DPDK process without worrying about cleaning up its hugepages afterwards (somewhat less of a concern since 18.05 but still a concern if primary crashes), it is really fixing the no-shconf/huge-unlink options to not be half-measures.

Both of these options effectively disable secondary processes, but don't do it in a consistent way - huge-unlink cleans up hugepages after allocating them, but leaves shared config on. No-shconf disables shared config, but leaves hugepages in place. Since 18.05, huge-unlink didn't work anyway (wasn't implemented, which was my omission), and due to EAL now relying on fbarray's to store some data, no-shconf wasn't working correctly either because even though shared config wasn't created, two primaries still couldn't share a prefix with --no-shconf (see the first patch).

So, this patchset is really an acknowledgement of the fact that both huge-unlink and no-shconf options are really there to disable secondary processes and stop leaving files on the file system. I just went one step further, and instead of allocating-and-then-removing hugepages we're not creating them in the first place, and map them anonymously instead.

Signature · 2 lines
Thanks,
Anatoly
#20 lore raw

PATCH v2 8/9 doc: add deprecation notice for EAL command line options

In reply to Anatoly Burakov

Options --no-shconf and --huge-unlink will be removed, and replaced with --in-memory option, which will be a superset of these two, and an offially support method to run DPDK entirely in memory.

---

Notes:
RFC->v1:
- Add this patch

 doc/guides/rel_notes/deprecation.rst | 5 +++++
 1 file changed, 5 insertions(+)
doc/guides/rel_notes/deprecation.rst +5 -0
index 5de59833d..dd1b5c5d8 100644
@@ -8,6 +8,11 @@ API and ABI deprecation notices are to be posted here.
 Deprecation Notices
 -------------------
 
+* eal: command-line options ``--no-shconf`` and ``--huge-unlink`` will be
+    removed, and replaced with a single option ``--in-memory``, which will
+    enable DPDK to operate entirely in memory, without creating any files on any
+    filesystems.
+
 * eal: DPDK runtime configuration file (located at
   ``/var/run/.<prefix>_config``) will be moved. The new path will be as follows:
 
Signature · 1 line
2.17.1
#21 lore raw

Re: [PATCH v2 8/9] doc: add deprecation notice for EAL command line options

13/07/2018 12:27, Anatoly Burakov:

Quoted 6 lines

Options --no-shconf and --huge-unlink will be removed, and replaced with --in-memory option, which will be a superset of these two, and an offially support method to run DPDK entirely in memory.

The deprecation notice should be sent separately in order to wait for enough agreement.

#22 lore raw

Re: [PATCH v2 8/9] doc: add deprecation notice for EAL command line options

Quoted 11 lines · Thomas Monjalon

13/07/2018 12:27, Anatoly Burakov:

Quoted 6 lines

Options --no-shconf and --huge-unlink will be removed, and replaced with --in-memory option, which will be a superset of these two, and an offially support method to run DPDK entirely in memory.

The deprecation notice should be sent separately in order to wait for enough agreement.

Really, we don't have to deprecate old options. It would be nice to remove them as half-measures and replace them with a proper implementation, but it's not strictly necessary, so i'll make it a separate patch.

Signature · 2 lines
Thanks,
Anatoly
#23 lore raw

PATCH v2 9/9 mem: support in-memory mode

In reply to Anatoly Burakov

Implement the final piece of the in-memory mode puzzle - enable running DPDK entirely in memory, without creating any files.

To do it, use mmap with MAP_HUGETLB and size flags to enable DPDK to work without hugetlbfs mountpoints. In order to enable this, a few things needed to be changed.

First of all, we need to allow empty hugetlbfs mountpoints in hugepage_info, and handle them correctly (by not trying to create any files and lock any directories).

Next, we need to reorder the mapping sequence, because the page is not really allocated until the page fault, and we cannot get its IOVA address before we trigger the page fault.

Finally, decide at compile time whether we are going to be supporting anonymous hugepages or not, because we cannot check for it at runtime.

---

Notes:
RFC->v1:
- Drop memfd and instead use mmap() with MAP_HUGETLB. This will drop the kernel requirements down to 3.8, and does not impose any restrictions glibc (as far as i known).

Unfortunately, there's a bit of an issue with this approach, because mmap() is stupid and will happily ignore unsupported arguments. This means that if the binary were to be compiled on a 3.8+ kernel but run on a pre-3.8 kernel (such as currently supported minimum of 3.2), then most likely the memory would be allocated using regular pages, causing unthinkable performance degradation. No solution to this problem is currently known to me.

 .../linuxapp/eal/eal_hugepage_info.c          |  91 +++++++-----
 lib/librte_eal/linuxapp/eal/eal_memalloc.c    | 130 +++++++++++-------
 lib/librte_eal/linuxapp/eal/eal_memory.c      |   3 +-
 3 files changed, 139 insertions(+), 85 deletions(-)
lib/librte_eal/linuxapp/eal/eal_hugepage_info.c +59 -32
index 7f8e2fd9c..3a7d4b222 100644
@@ -18,6 +18,8 @@
 #include <sys/queue.h>
 #include <sys/stat.h>
 
+#include <linux/mman.h> /* for hugetlb-related flags */
+
 #include <rte_memory.h>
 #include <rte_eal.h>
 #include <rte_launch.h>
@@ -313,11 +315,49 @@ compare_hpi(const void *a, const void *b)
 	return hpi_b->hugepage_sz - hpi_a->hugepage_sz;
 }
 
+static void
+calc_num_pages(struct hugepage_info *hpi, struct dirent *dirent)
+{
+	uint64_t total_pages = 0;
+	unsigned int i;
+
+	/*
+	 * first, try to put all hugepages into relevant sockets, but
+	 * if first attempts fails, fall back to collecting all pages
+	 * in one socket and sorting them later
+	 */
+	total_pages = 0;
+	/* we also don't want to do this for legacy init */
+	if (!internal_config.legacy_mem)
+		for (i = 0; i < rte_socket_count(); i++) {
+			int socket = rte_socket_id_by_idx(i);
+			unsigned int num_pages =
+					get_num_hugepages_on_node(
+						dirent->d_name, socket);
+			hpi->num_pages[socket] = num_pages;
+			total_pages += num_pages;
+		}
+	/*
+	 * we failed to sort memory from the get go, so fall
+	 * back to old way
+	 */
+	if (total_pages == 0) {
+		hpi->num_pages[0] = get_num_hugepages(dirent->d_name);
+
+#ifndef RTE_ARCH_64
+		/* for 32-bit systems, limit number of hugepages to
+		 * 1GB per page size */
+		hpi->num_pages[0] = RTE_MIN(hpi->num_pages[0],
+				RTE_PGSIZE_1G / hpi->hugepage_sz);
+#endif
+	}
+}
+
 static int
 hugepage_info_init(void)
 {	const char dirent_start_text[] = "hugepages-";
 	const size_t dirent_start_len = sizeof(dirent_start_text) - 1;
-	unsigned int i, total_pages, num_sizes = 0;
+	unsigned int i, num_sizes = 0;
 	DIR *dir;
 	struct dirent *dirent;
 
@@ -355,6 +395,22 @@ hugepage_info_init(void)
 					"%" PRIu64 " reserved, but no mounted "
 					"hugetlbfs found for that size\n",
 					num_pages, hpi->hugepage_sz);
+			/* if we have kernel support for reserving hugepages
+			 * through mmap, and we're in in-memory mode, treat this
+			 * page size as valid. we cannot be in legacy mode at
+			 * this point because we've checked this earlier in the
+			 * init process.
+			 */
+#ifdef MAP_HUGE_SHIFT
+			if (internal_config.in_memory) {
+				RTE_LOG(DEBUG, EAL, "In-memory mode enabled, "
+					"hugepages of size %" PRIu64 " bytes "
+					"will be allocated anonymously\n",
+					hpi->hugepage_sz);
+				calc_num_pages(hpi, dirent);
+				num_sizes++;
+			}
+#endif
 			continue;
 		}
 
@@ -371,35 +427,7 @@ hugepage_info_init(void)
 		if (clear_hugedir(hpi->hugedir) == -1)
 			break;
 
-		/*
-		 * first, try to put all hugepages into relevant sockets, but
-		 * if first attempts fails, fall back to collecting all pages
-		 * in one socket and sorting them later
-		 */
-		total_pages = 0;
-		/* we also don't want to do this for legacy init */
-		if (!internal_config.legacy_mem)
-			for (i = 0; i < rte_socket_count(); i++) {
-				int socket = rte_socket_id_by_idx(i);
-				unsigned int num_pages =
-						get_num_hugepages_on_node(
-							dirent->d_name, socket);
-				hpi->num_pages[socket] = num_pages;
-				total_pages += num_pages;
-			}
-		/*
-		 * we failed to sort memory from the get go, so fall
-		 * back to old way
-		 */
-		if (total_pages == 0)
-			hpi->num_pages[0] = get_num_hugepages(dirent->d_name);
-
-#ifndef RTE_ARCH_64
-		/* for 32-bit systems, limit number of hugepages to
-		 * 1GB per page size */
-		hpi->num_pages[0] = RTE_MIN(hpi->num_pages[0],
-					    RTE_PGSIZE_1G / hpi->hugepage_sz);
-#endif
+		calc_num_pages(hpi, dirent);
 
 		num_sizes++;
 	}
@@ -423,8 +451,7 @@ hugepage_info_init(void)
 
 		for (j = 0; j < RTE_MAX_NUMA_NODES; j++)
 			num_pages += hpi->num_pages[j];
-		if (strnlen(hpi->hugedir, sizeof(hpi->hugedir)) != 0 &&
-				num_pages > 0)
+		if (num_pages > 0)
 			return 0;
 	}
 
lib/librte_eal/linuxapp/eal/eal_memalloc.c +79 -51

199 lines not on this page · raw message

lib/librte_eal/linuxapp/eal/eal_memory.c +1 -2
index ddfa8b133..dbf19499e 100644
@@ -1088,8 +1088,7 @@ get_socket_mem_size(int socket)
 
 	for (i = 0; i < internal_config.num_hugepage_sizes; i++){
 		struct hugepage_info *hpi = &internal_config.hugepage_info[i];
-		if (strnlen(hpi->hugedir, sizeof(hpi->hugedir)) != 0)
-			size += hpi->hugepage_sz * hpi->num_pages[socket];
+		size += hpi->hugepage_sz * hpi->num_pages[socket];
 	}
 
 	return size;
Signature · 1 line
2.17.1
#24 lore raw

Re: [PATCH v2 9/9] mem: support in-memory mode

There is a compilation error:

../lib/librte_eal/linuxapp/eal/eal_memalloc.c: In function ‘alloc_seg’:
../lib/librte_eal/linuxapp/eal/eal_memalloc.c:619:3: error:
‘map_offset’ may be used uninitialized in this function

13/07/2018 12:27, Anatoly Burakov:

Quoted 34 lines

Implement the final piece of the in-memory mode puzzle - enable running DPDK entirely in memory, without creating any files.

To do it, use mmap with MAP_HUGETLB and size flags to enable DPDK to work without hugetlbfs mountpoints. In order to enable this, a few things needed to be changed.

First of all, we need to allow empty hugetlbfs mountpoints in hugepage_info, and handle them correctly (by not trying to create any files and lock any directories).

Next, we need to reorder the mapping sequence, because the page is not really allocated until the page fault, and we cannot get its IOVA address before we trigger the page fault.

Finally, decide at compile time whether we are going to be supporting anonymous hugepages or not, because we cannot check for it at runtime.

---

Notes:
RFC->v1:
- Drop memfd and instead use mmap() with MAP_HUGETLB. This will drop the kernel requirements down to 3.8, and does not impose any restrictions glibc (as far as i known).

Unfortunately, there's a bit of an issue with this approach, because mmap() is stupid and will happily ignore unsupported arguments. This means that if the binary were to be compiled on a 3.8+ kernel but run on a pre-3.8 kernel (such as currently supported minimum of 3.2), then most likely the memory would be allocated using regular pages, causing unthinkable performance degradation. No solution to this problem is currently known to me.

#25 lore raw

v3 cover Support running DPDK without hugetlbfs mountpoint

In reply to Anatoly Burakov

This patchset adds a new command-line option "--in-memory", which takes old debug options "--huge-unlink" and "--no-shconf", and enhances them with additional functionality. This will allow DPDK to reserve hugepages anonymously instead of using hugetlbfs mountpoints. Coupled with the fact that this option also effectively enables both "--no-shconf" and "--huge-unlink" modes, DPDK will be able to run entirely in memory and not create any shared files while running - neither hugepages nor any runtime data.

This will, of course, disable secondary processes, but for use-cases this is targeted at (containers etc.), this is not a problem.

Older revisions had kernel support at 4.14+ and also required a fairly new glibc, but now due to not using memfd and using mmap() instead, minimum supported kernel version has dropped to 3.8.

v2->v3 changes:
- Fix compile issue in patch 9 (now 8)
- Drop deprecation notice (will be sent separately)

v1->v2 changes:
- Rebase on latest master
- Fix patch 5 to include check from patch 6 as commit message states

RFC->v1 changes:
- Dropped memfd, using anonymous mmap() instead
- Do not deprecate old command-line parameters, instead use them as they are, and add a deprecation notice to remove them in the next release.

Anatoly Burakov (8):
fbarray: support no-shconf mode
ipc: add support for no-shconf mode
eal: add support for no-shconf for hugepage info
eal: add support for no-shconf in hugepage data file
eal: do not create runtime dir in no-shconf mode
mem: add support for hugepage-unlink mode
eal: add --in-memory option
mem: support in-memory mode

 lib/librte_eal/bsdapp/eal/eal.c               |   3 +-
 lib/librte_eal/bsdapp/eal/eal_hugepage_info.c |   4 +
 lib/librte_eal/common/eal_common_fbarray.c    |  71 +++++----
 lib/librte_eal/common/eal_common_options.c    |  20 ++-
 lib/librte_eal/common/eal_common_proc.c       |  25 +++
 lib/librte_eal/common/eal_internal_cfg.h      |   4 +
 lib/librte_eal/common/eal_options.h           |   2 +
 lib/librte_eal/linuxapp/eal/eal.c             |   3 +-
 .../linuxapp/eal/eal_hugepage_info.c          |  95 +++++++----
 lib/librte_eal/linuxapp/eal/eal_memalloc.c    | 150 ++++++++++++------
 lib/librte_eal/linuxapp/eal/eal_memory.c      |  16 +-
 11 files changed, 276 insertions(+), 117 deletions(-)
Signature · 1 line
2.17.1
#26 lore raw

PATCH v3 1/8 fbarray: support no-shconf mode

When using --no-shconf option, the expectation is that no multiprocess will be supported as no shared files are created. However, fbarray still creates some shared files that prevent multiple processes with the same prefix from starting.

Fix this by avoiding creating shared files whenever noshconf option is specified. Since virtual areas we get from eal_get_virtual_area() are read-only, remap them as writable.

---

Notes:
RFC->v1:
- Use --no-shconf only

 lib/librte_eal/common/eal_common_fbarray.c | 71 +++++++++++++---------
 1 file changed, 42 insertions(+), 29 deletions(-)
lib/librte_eal/common/eal_common_fbarray.c +42 -29
index 977174c4f..43caf3ced 100644
@@ -705,39 +705,52 @@ rte_fbarray_init(struct rte_fbarray *arr, const char *name, unsigned int len,
 	if (data == NULL)
 		goto fail;
 
-	eal_get_fbarray_path(path, sizeof(path), name);
+	if (internal_config.no_shconf) {
+		/* remap virtual area as writable */
+		void *new_data = mmap(data, mmap_len, PROT_READ | PROT_WRITE,
+				MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+		if (new_data == MAP_FAILED) {
+			RTE_LOG(DEBUG, EAL, "%s(): couldn't remap anonymous memory: %s\n",
+					__func__, strerror(errno));
+			goto fail;
+		}
+	} else {
+		eal_get_fbarray_path(path, sizeof(path), name);
 
-	/*
-	 * Each fbarray is unique to process namespace, i.e. the filename
-	 * depends on process prefix. Try to take out a lock and see if we
-	 * succeed. If we don't, someone else is using it already.
-	 */
-	fd = open(path, O_CREAT | O_RDWR, 0600);
-	if (fd < 0) {
-		RTE_LOG(DEBUG, EAL, "%s(): couldn't open %s: %s\n", __func__,
-				path, strerror(errno));
-		rte_errno = errno;
-		goto fail;
-	} else if (flock(fd, LOCK_EX | LOCK_NB)) {
-		RTE_LOG(DEBUG, EAL, "%s(): couldn't lock %s: %s\n", __func__,
-				path, strerror(errno));
-		rte_errno = EBUSY;
-		goto fail;
-	}
+		/*
+		 * Each fbarray is unique to process namespace, i.e. the
+		 * filename depends on process prefix. Try to take out a lock
+		 * and see if we succeed. If we don't, someone else is using it
+		 * already.
+		 */
+		fd = open(path, O_CREAT | O_RDWR, 0600);
+		if (fd < 0) {
+			RTE_LOG(DEBUG, EAL, "%s(): couldn't open %s: %s\n",
+					__func__, path, strerror(errno));
+			rte_errno = errno;
+			goto fail;
+		} else if (flock(fd, LOCK_EX | LOCK_NB)) {
+			RTE_LOG(DEBUG, EAL, "%s(): couldn't lock %s: %s\n",
+					__func__, path, strerror(errno));
+			rte_errno = EBUSY;
+			goto fail;
+		}
 
-	/* take out a non-exclusive lock, so that other processes could still
-	 * attach to it, but no other process could reinitialize it.
-	 */
-	if (flock(fd, LOCK_SH | LOCK_NB)) {
-		rte_errno = errno;
-		goto fail;
-	}
+		/* take out a non-exclusive lock, so that other processes could
+		 * still attach to it, but no other process could reinitialize
+		 * it.
+		 */
+		if (flock(fd, LOCK_SH | LOCK_NB)) {
+			rte_errno = errno;
+			goto fail;
+		}
 
-	if (resize_and_map(fd, data, mmap_len))
-		goto fail;
+		if (resize_and_map(fd, data, mmap_len))
+			goto fail;
 
-	/* we've mmap'ed the file, we can now close the fd */
-	close(fd);
+		/* we've mmap'ed the file, we can now close the fd */
+		close(fd);
+	}
 
 	/* initialize the data */
 	memset(data, 0, mmap_len);
Signature · 1 line
2.17.1
#27 lore raw

PATCH v3 2/8 ipc: add support for no-shconf mode

In reply to Anatoly Burakov

IPC is an inter-process communication mechanism. Since no secondaries can ever be expected to run in no-shconf mode, IPC will be useless, so do not enable it in the first place. In the interests of API usage convenience, we will still allow registering callbacks, but obviously they won't ever be triggered.

---

Notes:
RFC->v1:
- Use --no-shconf only

 lib/librte_eal/common/eal_common_proc.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)
lib/librte_eal/common/eal_common_proc.c +25 -0
index f010ef59e..c19b4b406 100644
@@ -626,6 +626,14 @@ rte_mp_channel_init(void)
 	int dir_fd;
 	pthread_t mp_handle_tid, async_reply_handle_tid;
 
+	/* in no shared files mode, we do not have secondary processes support,
+	 * so no need to initialize IPC.
+	 */
+	if (internal_config.no_shconf) {
+		RTE_LOG(DEBUG, EAL, "No shared files mode enabled, IPC will be disabled\n");
+		return 0;
+	}
+
 	/* create filter path */
 	create_socket_path("*", path, sizeof(path));
 	strlcpy(mp_filter, basename(path), sizeof(mp_filter));
@@ -988,6 +996,12 @@ rte_mp_request_sync(struct rte_mp_msg *req, struct rte_mp_reply *reply,
 
 	if (check_input(req) == false)
 		return -1;
+
+	if (internal_config.no_shconf) {
+		RTE_LOG(DEBUG, EAL, "No shared files mode enabled, IPC is disabled\n");
+		return 0;
+	}
+
 	if (gettimeofday(&now, NULL) < 0) {
 		RTE_LOG(ERR, EAL, "Faile to get current time\n");
 		rte_errno = errno;
@@ -1072,6 +1086,12 @@ rte_mp_request_async(struct rte_mp_msg *req, const struct timespec *ts,
 
 	if (check_input(req) == false)
 		return -1;
+
+	if (internal_config.no_shconf) {
+		RTE_LOG(DEBUG, EAL, "No shared files mode enabled, IPC is disabled\n");
+		return 0;
+	}
+
 	if (gettimeofday(&now, NULL) < 0) {
 		RTE_LOG(ERR, EAL, "Faile to get current time\n");
 		rte_errno = errno;
@@ -1213,5 +1233,10 @@ rte_mp_reply(struct rte_mp_msg *msg, const char *peer)
 		return -1;
 	}
 
+	if (internal_config.no_shconf) {
+		RTE_LOG(DEBUG, EAL, "No shared files mode enabled, IPC is disabled\n");
+		return 0;
+	}
+
 	return mp_send(msg, peer, MP_REP);
 }
Signature · 1 line
2.17.1
#28 lore raw

PATCH v3 3/8 eal: add support for no-shconf for hugepage info

In reply to Anatoly Burakov

Do not create any shared hugepage size info files if we were asked to not create any shared files.

---

Notes:
RFC->v1:
- Use --no-shconf only

 lib/librte_eal/bsdapp/eal/eal_hugepage_info.c   | 4 ++++
 lib/librte_eal/linuxapp/eal/eal_hugepage_info.c | 4 ++++
 2 files changed, 8 insertions(+)
lib/librte_eal/bsdapp/eal/eal_hugepage_info.c +4 -0
index 836feb672..1e8f5df23 100644
@@ -101,6 +101,10 @@ eal_hugepage_info_init(void)
 	hpi->num_pages[0] = num_buffers;
 	hpi->lock_descriptor = fd;
 
+	/* for no shared files mode, do not create shared memory config */
+	if (internal_config.no_shconf)
+		return 0;
+
 	tmp_hpi = create_shared_memory(eal_hugepage_info_path(),
 			sizeof(internal_config.hugepage_info));
 	if (tmp_hpi == NULL ) {
lib/librte_eal/linuxapp/eal/eal_hugepage_info.c +4 -0
index 7eca711ba..7f8e2fd9c 100644
@@ -446,6 +446,10 @@ eal_hugepage_info_init(void)
 	if (hugepage_info_init() < 0)
 		return -1;
 
+	/* for no shared files mode, we're done */
+	if (internal_config.no_shconf)
+		return 0;
+
 	hpi = &internal_config.hugepage_info[0];
 
 	tmp_hpi = create_shared_memory(eal_hugepage_info_path(),
Signature · 1 line
2.17.1
#29 lore raw

PATCH v3 4/8 eal: add support for no-shconf in hugepage data file

In reply to Anatoly Burakov

Do not create a shared hugepage data file if we were asked to not create any shared files.

---

Notes:
RFC->v1:
- Use --no-shconf only

 lib/librte_eal/linuxapp/eal/eal_memory.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)
lib/librte_eal/linuxapp/eal/eal_memory.c +12 -1
index 5d3c8831b..ddfa8b133 100644
@@ -521,7 +521,18 @@ static void *
 create_shared_memory(const char *filename, const size_t mem_size)
 {
 	void *retval;
-	int fd = open(filename, O_CREAT | O_RDWR, 0666);
+	int fd;
+
+	/* if no shared files mode is used, create anonymous memory instead */
+	if (internal_config.no_shconf) {
+		retval = mmap(NULL, mem_size, PROT_READ | PROT_WRITE,
+				MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+		if (retval == MAP_FAILED)
+			return NULL;
+		return retval;
+	}
+
+	fd = open(filename, O_CREAT | O_RDWR, 0666);
 	if (fd < 0)
 		return NULL;
 	if (ftruncate(fd, mem_size) < 0) {
Signature · 1 line
2.17.1
#30 lore raw

PATCH v3 5/8 eal: do not create runtime dir in no-shconf mode

In reply to Anatoly Burakov

Now that the rest of the EAL is adjusted to not create any shared files, prevent runtime directory from ever being created.

---

Notes:
RFC->v1:
- Use --no-shconf only

 lib/librte_eal/bsdapp/eal/eal.c   | 3 ++-
 lib/librte_eal/linuxapp/eal/eal.c | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)
lib/librte_eal/bsdapp/eal/eal.c +2 -1
index dc279542d..13b6f8ae1 100644
@@ -601,7 +601,8 @@ rte_eal_init(int argc, char **argv)
 	}
 
 	/* create runtime data directory */
-	if (eal_create_runtime_dir() < 0) {
+	if (internal_config.no_shconf == 0 &&
+			eal_create_runtime_dir() < 0) {
 		rte_eal_init_alert("Cannot create runtime directory\n");
 		rte_errno = EACCES;
 		return -1;
lib/librte_eal/linuxapp/eal/eal.c +2 -1
index ec7cea55d..191960caa 100644
@@ -832,7 +832,8 @@ rte_eal_init(int argc, char **argv)
 	}
 
 	/* create runtime data directory */
-	if (eal_create_runtime_dir() < 0) {
+	if (internal_config.no_shconf == 0 &&
+			eal_create_runtime_dir() < 0) {
 		rte_eal_init_alert("Cannot create runtime directory\n");
 		rte_errno = EACCES;
 		return -1;
Signature · 1 line
2.17.1
#31 lore raw

PATCH v3 6/8 mem: add support for hugepage-unlink mode

In reply to Anatoly Burakov

Unlink hugepages after creating them, to honor the hugepage-unlink mode. We cannot resize non-existing files, so make single file segments explicitly unsupported.

---

Notes:
v1->v2:
- Move check for hugepage unlink into this patch, to be consistent with commit message

RFC->v1:
- Use --huge-unlink only

RFC->v1:
- Use --huge-unlink only

 lib/librte_eal/common/eal_common_options.c |  6 ++++++
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 16 +++++++++++++++-
 2 files changed, 21 insertions(+), 1 deletion(-)
lib/librte_eal/common/eal_common_options.c +6 -0
index 45ea01a8b..df5d53648 100644
@@ -1332,6 +1332,12 @@ eal_check_common_options(struct internal_config *internal_cfg)
 			" is only supported in non-legacy memory mode\n");
 		return -1;
 	}
+	if (internal_cfg->single_file_segments &&
+			internal_cfg->hugepage_unlink) {
+		RTE_LOG(ERR, EAL, "Option --"OPT_SINGLE_FILE_SEGMENTS" is "
+			"not compatible with --"OPT_HUGE_UNLINK"\n");
+		return -1;
+	}
 
 	return 0;
 }
lib/librte_eal/linuxapp/eal/eal_memalloc.c +15 -1
index 69604f823..d610923b8 100644
@@ -489,6 +489,13 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
 				__func__, strerror(errno));
 			goto resized;
 		}
+		if (internal_config.hugepage_unlink) {
+			if (unlink(path)) {
+				RTE_LOG(DEBUG, EAL, "%s(): unlink() failed: %s\n",
+					__func__, strerror(errno));
+				goto resized;
+			}
+		}
 	}
 
 	/*
@@ -587,7 +594,8 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
 		/* ignore failure, can't make it any worse */
 	} else {
 		/* only remove file if we can take out a write lock */
-		if (lock(fd, LOCK_EX) == 1)
+		if (internal_config.hugepage_unlink == 0 &&
+				lock(fd, LOCK_EX) == 1)
 			unlink(path);
 		close(fd);
 	}
@@ -612,6 +620,12 @@ free_seg(struct rte_memseg *ms, struct hugepage_info *hi,
 		return -1;
 	}
 
+	/* if we've already unlinked the page, nothing needs to be done */
+	if (internal_config.hugepage_unlink) {
+		memset(ms, 0, sizeof(*ms));
+		return 0;
+	}
+
 	/* if we are not in single file segments mode, we're going to unmap the
 	 * segment and thus drop the lock on original fd, but hugepage dir is
 	 * now locked so we can take out another one without races.
Signature · 1 line
2.17.1
#32 lore raw

PATCH v3 7/8 eal: add --in-memory option

In reply to Anatoly Burakov

This command-line option will cause DPDK to operate entirely in memory and not create any shared files at runtime, including any shared configuration or hugetlbfs files. This is useful for debug purposes, as well as for certain use cases like containers or automatic memory cleanup.

Currently, this option acts as a strict superset of --no-shconf and --huge-unlink commands.

---

Notes:
RFC->v1:
- Do not deprecate old options, instead just coopt them

 lib/librte_eal/common/eal_common_options.c | 18 ++++++++++++++----
 lib/librte_eal/common/eal_internal_cfg.h   |  4 ++++
 lib/librte_eal/common/eal_options.h        |  2 ++
 3 files changed, 20 insertions(+), 4 deletions(-)
lib/librte_eal/common/eal_common_options.c +14 -4
index df5d53648..f308b57c3 100644
@@ -66,6 +66,7 @@ eal_long_options[] = {
 	{OPT_NO_HUGE,           0, NULL, OPT_NO_HUGE_NUM          },
 	{OPT_NO_PCI,            0, NULL, OPT_NO_PCI_NUM           },
 	{OPT_NO_SHCONF,         0, NULL, OPT_NO_SHCONF_NUM        },
+	{OPT_IN_MEMORY,         0, NULL, OPT_IN_MEMORY_NUM        },
 	{OPT_PCI_BLACKLIST,     1, NULL, OPT_PCI_BLACKLIST_NUM    },
 	{OPT_PCI_WHITELIST,     1, NULL, OPT_PCI_WHITELIST_NUM    },
 	{OPT_PROC_TYPE,         1, NULL, OPT_PROC_TYPE_NUM        },
@@ -1170,6 +1171,13 @@ eal_parse_common_option(int opt, const char *optarg,
 		conf->no_shconf = 1;
 		break;
 
+	case OPT_IN_MEMORY_NUM:
+		conf->in_memory = 1;
+		/* in-memory is a superset of noshconf and huge-unlink */
+		conf->no_shconf = 1;
+		conf->hugepage_unlink = 1;
+		break;
+
 	case OPT_PROC_TYPE_NUM:
 		conf->process_type = eal_parse_proc_type(optarg);
 		break;
@@ -1321,8 +1329,8 @@ eal_check_common_options(struct internal_config *internal_cfg)
 			"be specified together with --"OPT_NO_HUGE"\n");
 		return -1;
 	}
-
-	if (internal_cfg->no_hugetlbfs && internal_cfg->hugepage_unlink) {
+	if (internal_cfg->no_hugetlbfs && internal_cfg->hugepage_unlink &&
+			!internal_cfg->in_memory) {
 		RTE_LOG(ERR, EAL, "Option --"OPT_HUGE_UNLINK" cannot "
 			"be specified together with --"OPT_NO_HUGE"\n");
 		return -1;
@@ -1330,12 +1338,12 @@ eal_check_common_options(struct internal_config *internal_cfg)
 	if (internal_config.force_socket_limits && internal_config.legacy_mem) {
 		RTE_LOG(ERR, EAL, "Option --"OPT_SOCKET_LIMIT
 			" is only supported in non-legacy memory mode\n");
-		return -1;
 	}
 	if (internal_cfg->single_file_segments &&
 			internal_cfg->hugepage_unlink) {
 		RTE_LOG(ERR, EAL, "Option --"OPT_SINGLE_FILE_SEGMENTS" is "
-			"not compatible with --"OPT_HUGE_UNLINK"\n");
+			"not compatible with neither --"OPT_IN_MEMORY" nor "
+			"--"OPT_HUGE_UNLINK"\n");
 		return -1;
 	}
 
@@ -1386,6 +1394,8 @@ eal_common_usage(void)
 	       "                      Set specific log level\n"
 	       "  -v                  Display version information on startup\n"
 	       "  -h, --help          This help\n"
+	       "  --"OPT_IN_MEMORY"   Operate entirely in memory. This will \n"
+	       "                      disable secondary process support\n"
 	       "\nEAL options for DEBUG use only:\n"
 	       "  --"OPT_HUGE_UNLINK"       Unlink hugepage files after init\n"
 	       "  --"OPT_NO_HUGE"           Use malloc instead of hugetlbfs\n"
lib/librte_eal/common/eal_internal_cfg.h +4 -0
index d66cd0313..00ee6e06e 100644
@@ -41,6 +41,10 @@ struct internal_config {
 	volatile unsigned vmware_tsc_map; /**< true to use VMware TSC mapping
 										* instead of native TSC */
 	volatile unsigned no_shconf;      /**< true if there is no shared config */
+	volatile unsigned in_memory;
+	/**< true if DPDK should operate entirely in-memory and not create any
+	 * shared files or runtime data.
+	 */
 	volatile unsigned create_uio_dev; /**< true to create /dev/uioX devices */
 	volatile enum rte_proc_type_t process_type; /**< multi-process proc type */
 	/** true to try allocating memory on specific sockets */
lib/librte_eal/common/eal_options.h +2 -0
index 6d92f64a8..96e166787 100644
@@ -45,6 +45,8 @@ enum {
 	OPT_NO_PCI_NUM,
 #define OPT_NO_SHCONF         "no-shconf"
 	OPT_NO_SHCONF_NUM,
+#define OPT_IN_MEMORY         "in-memory"
+	OPT_IN_MEMORY_NUM,
 #define OPT_SOCKET_MEM        "socket-mem"
 	OPT_SOCKET_MEM_NUM,
 #define OPT_SOCKET_LIMIT        "socket-limit"
Signature · 1 line
2.17.1
#33 lore raw

PATCH v3 8/8 mem: support in-memory mode

In reply to Anatoly Burakov

Implement the final piece of the in-memory mode puzzle - enable running DPDK entirely in memory, without creating any files.

To do it, use mmap with MAP_HUGETLB and size flags to enable DPDK to work without hugetlbfs mountpoints. In order to enable this, a few things needed to be changed.

First of all, we need to allow empty hugetlbfs mountpoints in hugepage_info, and handle them correctly (by not trying to create any files and lock any directories).

Next, we need to reorder the mapping sequence, because the page is not really allocated until the page fault, and we cannot get its IOVA address before we trigger the page fault.

Finally, decide at compile time whether we are going to be supporting anonymous hugepages or not, because we cannot check for it at runtime.

---

Notes:
RFC->v1:
- Drop memfd and instead use mmap() with MAP_HUGETLB. This will drop the kernel requirements down to 3.8, and does not impose any restrictions glibc (as far as i known).

Unfortunately, there's a bit of an issue with this approach, because mmap() is stupid and will happily ignore unsupported arguments. This means that if the binary were to be compiled on a 3.8+ kernel but run on a pre-3.8 kernel (such as currently supported minimum of 3.2), then most likely the memory would be allocated using regular pages, causing unthinkable performance degradation. No solution to this problem is currently known to me.

 .../linuxapp/eal/eal_hugepage_info.c          |  91 ++++++++----
 lib/librte_eal/linuxapp/eal/eal_memalloc.c    | 140 +++++++++++-------
 lib/librte_eal/linuxapp/eal/eal_memory.c      |   3 +-
 3 files changed, 149 insertions(+), 85 deletions(-)
lib/librte_eal/linuxapp/eal/eal_hugepage_info.c +59 -32
index 7f8e2fd9c..3a7d4b222 100644
@@ -18,6 +18,8 @@
 #include <sys/queue.h>
 #include <sys/stat.h>
 
+#include <linux/mman.h> /* for hugetlb-related flags */
+
 #include <rte_memory.h>
 #include <rte_eal.h>
 #include <rte_launch.h>
@@ -313,11 +315,49 @@ compare_hpi(const void *a, const void *b)
 	return hpi_b->hugepage_sz - hpi_a->hugepage_sz;
 }
 
+static void
+calc_num_pages(struct hugepage_info *hpi, struct dirent *dirent)
+{
+	uint64_t total_pages = 0;
+	unsigned int i;
+
+	/*
+	 * first, try to put all hugepages into relevant sockets, but
+	 * if first attempts fails, fall back to collecting all pages
+	 * in one socket and sorting them later
+	 */
+	total_pages = 0;
+	/* we also don't want to do this for legacy init */
+	if (!internal_config.legacy_mem)
+		for (i = 0; i < rte_socket_count(); i++) {
+			int socket = rte_socket_id_by_idx(i);
+			unsigned int num_pages =
+					get_num_hugepages_on_node(
+						dirent->d_name, socket);
+			hpi->num_pages[socket] = num_pages;
+			total_pages += num_pages;
+		}
+	/*
+	 * we failed to sort memory from the get go, so fall
+	 * back to old way
+	 */
+	if (total_pages == 0) {
+		hpi->num_pages[0] = get_num_hugepages(dirent->d_name);
+
+#ifndef RTE_ARCH_64
+		/* for 32-bit systems, limit number of hugepages to
+		 * 1GB per page size */
+		hpi->num_pages[0] = RTE_MIN(hpi->num_pages[0],
+				RTE_PGSIZE_1G / hpi->hugepage_sz);
+#endif
+	}
+}
+
 static int
 hugepage_info_init(void)
 {	const char dirent_start_text[] = "hugepages-";
 	const size_t dirent_start_len = sizeof(dirent_start_text) - 1;
-	unsigned int i, total_pages, num_sizes = 0;
+	unsigned int i, num_sizes = 0;
 	DIR *dir;
 	struct dirent *dirent;
 
@@ -355,6 +395,22 @@ hugepage_info_init(void)
 					"%" PRIu64 " reserved, but no mounted "
 					"hugetlbfs found for that size\n",
 					num_pages, hpi->hugepage_sz);
+			/* if we have kernel support for reserving hugepages
+			 * through mmap, and we're in in-memory mode, treat this
+			 * page size as valid. we cannot be in legacy mode at
+			 * this point because we've checked this earlier in the
+			 * init process.
+			 */
+#ifdef MAP_HUGE_SHIFT
+			if (internal_config.in_memory) {
+				RTE_LOG(DEBUG, EAL, "In-memory mode enabled, "
+					"hugepages of size %" PRIu64 " bytes "
+					"will be allocated anonymously\n",
+					hpi->hugepage_sz);
+				calc_num_pages(hpi, dirent);
+				num_sizes++;
+			}
+#endif
 			continue;
 		}
 
@@ -371,35 +427,7 @@ hugepage_info_init(void)
 		if (clear_hugedir(hpi->hugedir) == -1)
 			break;
 
-		/*
-		 * first, try to put all hugepages into relevant sockets, but
-		 * if first attempts fails, fall back to collecting all pages
-		 * in one socket and sorting them later
-		 */
-		total_pages = 0;
-		/* we also don't want to do this for legacy init */
-		if (!internal_config.legacy_mem)
-			for (i = 0; i < rte_socket_count(); i++) {
-				int socket = rte_socket_id_by_idx(i);
-				unsigned int num_pages =
-						get_num_hugepages_on_node(
-							dirent->d_name, socket);
-				hpi->num_pages[socket] = num_pages;
-				total_pages += num_pages;
-			}
-		/*
-		 * we failed to sort memory from the get go, so fall
-		 * back to old way
-		 */
-		if (total_pages == 0)
-			hpi->num_pages[0] = get_num_hugepages(dirent->d_name);
-
-#ifndef RTE_ARCH_64
-		/* for 32-bit systems, limit number of hugepages to
-		 * 1GB per page size */
-		hpi->num_pages[0] = RTE_MIN(hpi->num_pages[0],
-					    RTE_PGSIZE_1G / hpi->hugepage_sz);
-#endif
+		calc_num_pages(hpi, dirent);
 
 		num_sizes++;
 	}
@@ -423,8 +451,7 @@ hugepage_info_init(void)
 
 		for (j = 0; j < RTE_MAX_NUMA_NODES; j++)
 			num_pages += hpi->num_pages[j];
-		if (strnlen(hpi->hugedir, sizeof(hpi->hugedir)) != 0 &&
-				num_pages > 0)
+		if (num_pages > 0)
 			return 0;
 	}
 
lib/librte_eal/linuxapp/eal/eal_memalloc.c +89 -51

215 lines not on this page · raw message

lib/librte_eal/linuxapp/eal/eal_memory.c +1 -2
index ddfa8b133..dbf19499e 100644
@@ -1088,8 +1088,7 @@ get_socket_mem_size(int socket)
 
 	for (i = 0; i < internal_config.num_hugepage_sizes; i++){
 		struct hugepage_info *hpi = &internal_config.hugepage_info[i];
-		if (strnlen(hpi->hugedir, sizeof(hpi->hugedir)) != 0)
-			size += hpi->hugepage_sz * hpi->num_pages[socket];
+		size += hpi->hugepage_sz * hpi->num_pages[socket];
 	}
 
 	return size;
Signature · 1 line
2.17.1
#34 lore raw
In reply to Anatoly Burakov
Quoted 9 lines

Anatoly Burakov (8):
fbarray: support no-shconf mode
ipc: add support for no-shconf mode
eal: add support for no-shconf for hugepage info
eal: add support for no-shconf in hugepage data file
eal: do not create runtime dir in no-shconf mode
mem: add support for hugepage-unlink mode
eal: add --in-memory option
mem: support in-memory mode

Applied, thanks.