+enum hugepage_action {
+ HUGEPAGE_CHECK_EXISTS = 0,
+ HUGEPAGE_CHECK_LOCKED,
+ HUGEPAGE_DELETE,
+ HUGEPAGE_INVALID
+};
+
+/* if string contains a hugepage path */
+static int
+get_hugepage_path(char * src, int src_len, char * dst, int dst_len)
+{
+#define NUM_TOKENS 4
+ char *tokens[NUM_TOKENS];
+
+ /* if we couldn't properly split the string */
+ if (rte_strsplit(src, src_len, tokens, NUM_TOKENS, ' ') < NUM_TOKENS)
+ return 0;
+
+ if (strncmp(tokens[2], "hugetlbfs", sizeof("hugetlbfs")) == 0) {
+ snprintf(dst, dst_len, "%s", tokens[1]);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Cycles through hugepage directories and looks for hugepage
+ * files associated with a given prefix. Depending on value of
+ * action, the hugepages are checked if they exist, checked if
+ * they can be locked, or are simply deleted.
+ *
+ * Returns 1 if it finds at least one hugepage matching the action
+ * Returns 0 if no matching hugepages were found
+ * Returns -1 if it encounters an error
+ */
+static int
+process_hugefiles(const char * prefix, enum hugepage_action action)
+{
+ FILE * hugedir_handle = NULL;
+ DIR * hugepage_dir = NULL;
+ struct dirent *dirent = NULL;
+
+ char hugefile_prefix[PATH_MAX] = {0};
+ char hugedir[PATH_MAX] = {0};
+ char line[PATH_MAX] = {0};
+
+ int fd, lck_result, result = 0;
+
+ const int prefix_len = snprintf(hugefile_prefix,
+ sizeof(hugefile_prefix), "%smap_", prefix);
+ if (prefix_len <= 0 || prefix_len >= (int)sizeof(hugefile_prefix)
+ || prefix_len >= (int)sizeof(dirent->d_name)) {
+ printf("Error creating hugefile filename prefix\n");
+ return -1;
+ }
+
+ /* get hugetlbfs mountpoints from /proc/mounts */
+ hugedir_handle = fopen("/proc/mounts", "r");
+
+ if (hugedir_handle == NULL) {
+ printf("Error parsing /proc/mounts!\n");
+ return -1;
+ }
+
+ /* read and parse script output */
+ while (fgets(line, sizeof(line), hugedir_handle) != NULL) {
+
+ /* check if we have a hugepage filesystem path */
+ if (!get_hugepage_path(line, sizeof(line), hugedir, sizeof(hugedir)))
+ continue;
+
+ /* check if directory exists */
+ if ((hugepage_dir = opendir(hugedir)) == NULL) {
+ fclose(hugedir_handle);
+ printf("Error reading %s: %s\n", hugedir, strerror(errno));
+ return -1;
+ }
+
+ while ((dirent = readdir(hugepage_dir)) != NULL) {
+ if (memcmp(dirent->d_name, hugefile_prefix, prefix_len) != 0)
+ continue;
+
+ switch (action) {
+ case HUGEPAGE_CHECK_EXISTS:
+ {
+ /* file exists, return */
+ result = 1;
+ goto end;
+ }
+ break;
+ case HUGEPAGE_DELETE:
+ {
+ char file_path[PATH_MAX] = {0};
+
+ snprintf(file_path, sizeof(file_path),
+ "%s/%s", hugedir, dirent->d_name);
+
+ /* remove file */
+ if (remove(file_path) < 0) {
+ printf("Error deleting %s - %s!\n",
+ dirent->d_name, strerror(errno));
+ closedir(hugepage_dir);
+ result = -1;
+ goto end;
+ }
+ result = 1;
+ }
+ break;
+ case HUGEPAGE_CHECK_LOCKED:
+ {
+ /* try and lock the file */
+ fd = openat(dirfd(hugepage_dir), dirent->d_name, O_RDONLY);
+
+ /* this shouldn't happen */
+ if (fd == -1) {
+ printf("Error opening %s - %s!\n",
+ dirent->d_name, strerror(errno));
+ closedir(hugepage_dir);
+ result = -1;
+ goto end;
+ }
+
+ /* non-blocking lock */
+ lck_result = flock(fd, LOCK_EX | LOCK_NB);
+
+ /* if lock succeeds, there's something wrong */
+ if (lck_result != -1) {
+ result = 0;
+
+ /* unlock the resulting lock */
+ flock(fd, LOCK_UN);
+ close(fd);
+ closedir(hugepage_dir);
+ goto end;
+ }
+ result = 1;
+ close(fd);
+ }
+ break;
+ /* shouldn't happen */
+ default:
+ goto end;
+ } /* switch */
+
+ } /* read hugepage directory */
+ closedir(hugepage_dir);
+ } /* read /proc/mounts */
+end:
+ fclose(hugedir_handle);
+ return result;
+}
+
+#ifdef RTE_EXEC_ENV_LINUXAPP
+/*
+ * count the number of "node*" files in /sys/devices/system/node/
+ */
+static int
+get_number_of_sockets(void)
+{
+ struct dirent *dirent = NULL;
+ const char * nodedir = "/sys/devices/system/node/";
+ DIR * dir = NULL;
+ int result = 0;
+
+ /* check if directory exists */
+ if ((dir = opendir(nodedir)) == NULL) {
+ /* if errno==ENOENT this means we don't have NUMA support */
+ if (errno == ENOENT) {
+ printf("No NUMA nodes detected: assuming 1 available socket\n");
+ return 1;
+ }
+ printf("Error opening %s: %s\n", nodedir, strerror(errno));
+ return -1;
+ }
+
+ while ((dirent = readdir(dir)) != NULL)
+ if (strncmp(dirent->d_name, "node", sizeof("node") - 1) == 0)
+ result++;
+
+ closedir(dir);
+ return result;
+}
+#endif
+
+static char*
+get_current_prefix(char * prefix, int size)
+{
+ char path[PATH_MAX] = {0};
+ char buf[PATH_MAX] = {0};
+
+ /* get file for config (fd is always 3) */
+ snprintf(path, sizeof(path), "/proc/self/fd/%d", 3);
+
+ /* return NULL on error */
+ if (readlink(path, buf, sizeof(buf)) == -1)
+ return NULL;
+
+ /* get the basename */
+ snprintf(buf, sizeof(buf), "%s", basename(buf));
+
+ /* copy string all the way from second char up to start of _config */
+ snprintf(prefix, size, "%.*s",
+ (int)(strnlen(buf, sizeof(buf)) - sizeof("_config")),
+ &buf[1]);
+
+ return prefix;
+}
+
+/*
+ * Test that the app doesn't run with invalid whitelist option.
+ * Final tests ensures it does run with valid options as sanity check (one
+ * test for with Domain+BDF, second for just with BDF)
+ */
+static int
+test_whitelist_flag(void)
+{
+ unsigned i;
+#ifdef RTE_EXEC_ENV_BSDAPP
+ /* BSD target doesn't support prefixes at this point */
+ const char * prefix = "";
+#else
+ char prefix[PATH_MAX], tmp[PATH_MAX];
+ if (get_current_prefix(tmp, sizeof(tmp)) == NULL) {
+ printf("Error - unable to get current prefix!\n");
+ return -1;
+ }
+ snprintf(prefix, sizeof(prefix), "--file-prefix=%s", tmp);
+#endif
+
+ const char *wlinval[][11] = {
+ {prgname, prefix, mp_flag, "-n", "1", "-c", "1",
+ pci_whitelist, "error", "", ""},
+ {prgname, prefix, mp_flag, "-n", "1", "-c", "1",
+ pci_whitelist, "0:0:0", "", ""},
+ {prgname, prefix, mp_flag, "-n", "1", "-c", "1",
+ pci_whitelist, "0:error:0.1", "", ""},
+ {prgname, prefix, mp_flag, "-n", "1", "-c", "1",
+ pci_whitelist, "0:0:0.1error", "", ""},
+ {prgname, prefix, mp_flag, "-n", "1", "-c", "1",
+ pci_whitelist, "error0:0:0.1", "", ""},
+ {prgname, prefix, mp_flag, "-n", "1", "-c", "1",
+ pci_whitelist, "0:0:0.1.2", "", ""},
+ };
+ /* Test with valid whitelist option */
+ const char *wlval1[] = {prgname, prefix, mp_flag, "-n", "1", "-c", "1",
+ pci_whitelist, "00FF:09:0B.3"};
+ const char *wlval2[] = {prgname, prefix, mp_flag, "-n", "1", "-c", "1",
+ pci_whitelist, "09:0B.3", pci_whitelist, "0a:0b.1"};
+ const char *wlval3[] = {prgname, prefix, mp_flag, "-n", "1", "-c", "1",
+ pci_whitelist, "09:0B.3,type=test",
+ pci_whitelist, "08:00.1,type=normal",
+ };
+
+ for (i = 0; i < sizeof(wlinval) / sizeof(wlinval[0]); i++) {
+ if (launch_proc(wlinval[i]) == 0) {
+ printf("Error - process did run ok with invalid "
+ "whitelist parameter\n");
+ return -1;
+ }
+ }
+ if (launch_proc(wlval1) != 0 ) {
+ printf("Error - process did not run ok with valid whitelist\n");
+ return -1;
+ }
+ if (launch_proc(wlval2) != 0 ) {
+ printf("Error - process did not run ok with valid whitelist value set\n");
+ return -1;
+ }
+ if (launch_proc(wlval3) != 0 ) {
+ printf("Error - process did not run ok with valid whitelist + args\n");
+ return -1;
+ }
+
+ return 0;
+}
+