diff --git a/MAINTAINERS b/MAINTAINERS
index 0c3e6d28e9..1edea42fad 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -538,6 +538,7 @@ F: doc/guides/prog_guide/rawdev.rst
 ML device API - EXPERIMENTAL
 M: Srikanth Yalavarthi <syalavarthi@marvell.com>
 F: lib/mldev/
+F: app/test-mldev/
 F: doc/guides/prog_guide/mldev.rst
 
 
diff --git a/app/meson.build b/app/meson.build
index e32ea4bd5c..74d2420f67 100644
--- a/app/meson.build
+++ b/app/meson.build
@@ -23,6 +23,7 @@ apps = [
         'test-fib',
         'test-flow-perf',
         'test-gpudev',
+        'test-mldev',
         'test-pipeline',
         'test-pmd',
         'test-regex',
diff --git a/app/test-mldev/meson.build b/app/test-mldev/meson.build
new file mode 100644
index 0000000000..8ca2e1a1c1
--- /dev/null
+++ b/app/test-mldev/meson.build
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright (c) 2022 Marvell.
+
+if is_windows
+    build = false
+    reason = 'not supported on Windows'
+    subdir_done()
+endif
+
+sources = files(
+        'ml_main.c',
+        'ml_options.c',
+        'ml_test.c',
+        'parser.c',
+)
+
+deps += ['mldev']
diff --git a/app/test-mldev/ml_common.h b/app/test-mldev/ml_common.h
new file mode 100644
index 0000000000..065180b619
--- /dev/null
+++ b/app/test-mldev/ml_common.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2022 Marvell.
+ */
+
+#ifndef _ML_COMMON_
+#define _ML_COMMON_
+
+#include <stdio.h>
+
+#define CLNRM "\x1b[0m"
+#define CLRED "\x1b[31m"
+#define CLGRN "\x1b[32m"
+#define CLYEL "\x1b[33m"
+
+#define ML_STR_FMT 20
+
+#define ml_err(fmt, args...) fprintf(stderr, CLRED "error: %s() " fmt CLNRM "\n", __func__, ##args)
+
+#define ml_info(fmt, args...) fprintf(stdout, CLYEL "" fmt CLNRM "\n", ##args)
+
+#define ml_dump(str, fmt, val...) printf("\t%-*s : " fmt "\n", ML_STR_FMT, str, ##val)
+
+#define ml_dump_begin(str) printf("\t%-*s :\n\t{\n", ML_STR_FMT, str)
+
+#define ml_dump_list(str, id, val) printf("\t%*s[%2u] : %s\n", ML_STR_FMT - 4, str, id, val)
+
+#define ml_dump_end printf("\b\t}\n\n")
+
+#endif /* _ML_COMMON_*/
diff --git a/app/test-mldev/ml_main.c b/app/test-mldev/ml_main.c
new file mode 100644
index 0000000000..d6652cd7b7
--- /dev/null
+++ b/app/test-mldev/ml_main.c
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2022 Marvell.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <rte_debug.h>
+#include <rte_eal.h>
+#include <rte_mldev.h>
+
+#include "ml_common.h"
+#include "ml_options.h"
+#include "ml_test.h"
+
+struct ml_options opt;
+struct ml_test *test;
+
+int
+main(int argc, char **argv)
+{
+	uint16_t mldevs;
+	int ret;
+
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_panic("invalid EAL arguments\n");
+	argc -= ret;
+	argv += ret;
+
+	mldevs = rte_ml_dev_count();
+	if (!mldevs)
+		rte_panic("no mldev devices found\n");
+
+	/* set default values for options */
+	ml_options_default(&opt);
+
+	/* parse the command line arguments */
+	ret = ml_options_parse(&opt, argc, argv);
+	if (ret) {
+		ml_err("parsing one or more user options failed");
+		goto error;
+	}
+
+	/* get test struct from name */
+	test = ml_test_get(opt.test_name);
+	if (test == NULL) {
+		ml_err("failed to find requested test: %s", opt.test_name);
+		goto error;
+	}
+
+	if (test->ops.test_result == NULL) {
+		ml_err("%s: ops.test_result not found", opt.test_name);
+		goto error;
+	}
+
+	/* check test options */
+	if (test->ops.opt_check) {
+		if (test->ops.opt_check(&opt)) {
+			ml_err("invalid command line argument");
+			goto error;
+		}
+	}
+
+	/* check the device capability */
+	if (test->ops.cap_check) {
+		if (test->ops.cap_check(&opt) == false) {
+			ml_info("unsupported test: %s", opt.test_name);
+			ret = ML_TEST_UNSUPPORTED;
+			goto no_cap;
+		}
+	}
+
+	/* dump options */
+	if (opt.debug) {
+		if (test->ops.opt_dump)
+			test->ops.opt_dump(&opt);
+	}
+
+	/* test specific setup */
+	if (test->ops.test_setup) {
+		if (test->ops.test_setup(test, &opt)) {
+			ml_err("failed to setup test: %s", opt.test_name);
+			goto error;
+		}
+	}
+
+	/* test driver */
+	if (test->ops.test_driver)
+		test->ops.test_driver(test, &opt);
+
+	/* get result */
+	if (test->ops.test_result)
+		ret = test->ops.test_result(test, &opt);
+
+	if (test->ops.test_destroy)
+		test->ops.test_destroy(test, &opt);
+
+no_cap:
+	if (ret == ML_TEST_SUCCESS) {
+		printf("Result: " CLGRN "%s" CLNRM "\n", "Success");
+	} else if (ret == ML_TEST_FAILED) {
+		printf("Result: " CLRED "%s" CLNRM "\n", "Failed");
+		return EXIT_FAILURE;
+	} else if (ret == ML_TEST_UNSUPPORTED) {
+		printf("Result: " CLYEL "%s" CLNRM "\n", "Unsupported");
+	}
+
+	rte_eal_cleanup();
+
+	return 0;
+
+error:
+	rte_eal_cleanup();
+
+	return EXIT_FAILURE;
+}
diff --git a/app/test-mldev/ml_options.c b/app/test-mldev/ml_options.c
new file mode 100644
index 0000000000..8fd7760e36
--- /dev/null
+++ b/app/test-mldev/ml_options.c
@@ -0,0 +1,160 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2022 Marvell.
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_memory.h>
+#include <rte_mldev.h>
+#include <rte_string_fns.h>
+
+#include "ml_common.h"
+#include "ml_options.h"
+#include "ml_test.h"
+#include "parser.h"
+
+typedef int (*option_parser_t)(struct ml_options *opt, const char *arg);
+
+void
+ml_options_default(struct ml_options *opt)
+{
+	memset(opt, 0, sizeof(*opt));
+	strlcpy(opt->test_name, "ml_test", ML_TEST_NAME_MAX_LEN);
+	opt->dev_id = 0;
+	opt->socket_id = SOCKET_ID_ANY;
+	opt->debug = false;
+}
+
+struct long_opt_parser {
+	const char *lgopt_name;
+	option_parser_t parser_fn;
+};
+
+static int
+ml_parse_test_name(struct ml_options *opt, const char *arg)
+{
+	strlcpy(opt->test_name, arg, ML_TEST_NAME_MAX_LEN);
+	return 0;
+}
+
+static int
+ml_parse_dev_id(struct ml_options *opt, const char *arg)
+{
+	int ret;
+
+	ret = parser_read_int16(&opt->dev_id, arg);
+
+	if (ret < 0)
+		return -EINVAL;
+
+	return ret;
+}
+
+static int
+ml_parse_socket_id(struct ml_options *opt, const char *arg)
+{
+	opt->socket_id = atoi(arg);
+
+	return 0;
+}
+
+static void
+ml_dump_test_options(const char *testname)
+{
+	RTE_SET_USED(testname);
+}
+
+static void
+print_usage(char *program)
+{
+	printf("\nusage : %s [EAL options] -- [application options]\n", program);
+	printf("application options:\n");
+	printf("\t--test             : name of the test application to run\n"
+	       "\t--dev_id           : device id of the ML device\n"
+	       "\t--socket_id        : socket_id of application resources\n"
+	       "\t--debug            : enable debug mode\n"
+	       "\t--help             : print help\n");
+	printf("\n");
+	printf("available tests and test specific application options:\n");
+	ml_test_dump_names(ml_dump_test_options);
+}
+
+static struct option lgopts[] = {{ML_TEST, 1, 0, 0},	  {ML_DEVICE_ID, 1, 0, 0},
+				 {ML_SOCKET_ID, 1, 0, 0}, {ML_DEBUG, 0, 0, 0},
+				 {ML_HELP, 0, 0, 0},	  {NULL, 0, 0, 0}};
+
+static int
+ml_opts_parse_long(int opt_idx, struct ml_options *opt)
+{
+	unsigned int i;
+
+	struct long_opt_parser parsermap[] = {
+		{ML_TEST, ml_parse_test_name},
+		{ML_DEVICE_ID, ml_parse_dev_id},
+		{ML_SOCKET_ID, ml_parse_socket_id},
+	};
+
+	for (i = 0; i < RTE_DIM(parsermap); i++) {
+		if (strncmp(lgopts[opt_idx].name, parsermap[i].lgopt_name,
+			    strlen(lgopts[opt_idx].name)) == 0)
+			return parsermap[i].parser_fn(opt, optarg);
+	}
+
+	return -EINVAL;
+}
+
+int
+ml_options_parse(struct ml_options *opt, int argc, char **argv)
+{
+	int opt_idx;
+	int retval;
+	int opts;
+
+	while ((opts = getopt_long(argc, argv, "", lgopts, &opt_idx)) != EOF) {
+		switch (opts) {
+		case 0: /* parse long options */
+			if (!strcmp(lgopts[opt_idx].name, "debug")) {
+				opt->debug = true;
+				break;
+			}
+
+			if (!strcmp(lgopts[opt_idx].name, "help")) {
+				print_usage(argv[0]);
+				exit(EXIT_SUCCESS);
+			}
+
+			retval = ml_opts_parse_long(opt_idx, opt);
+			if (retval != 0)
+				return retval;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+void
+ml_options_dump(struct ml_options *opt)
+{
+	struct rte_ml_dev_info dev_info;
+
+	rte_ml_dev_info_get(opt->dev_id, &dev_info);
+
+	ml_dump("driver", "%s", dev_info.driver_name);
+	ml_dump("test", "%s", opt->test_name);
+	ml_dump("dev_id", "%d", opt->dev_id);
+
+	if (opt->socket_id == SOCKET_ID_ANY)
+		ml_dump("socket_id", "%d (SOCKET_ID_ANY)", opt->socket_id);
+	else
+		ml_dump("socket_id", "%d", opt->socket_id);
+
+	ml_dump("debug", "%s", (opt->debug ? "true" : "false"));
+}
diff --git a/app/test-mldev/ml_options.h b/app/test-mldev/ml_options.h
new file mode 100644
index 0000000000..05311a9a47
--- /dev/null
+++ b/app/test-mldev/ml_options.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2022 Marvell.
+ */
+
+#ifndef _ML_OPTIONS_
+#define _ML_OPTIONS_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define ML_TEST_NAME_MAX_LEN 32
+
+/* Options names */
+#define ML_TEST	     ("test")
+#define ML_DEVICE_ID ("dev_id")
+#define ML_SOCKET_ID ("socket_id")
+#define ML_DEBUG     ("debug")
+#define ML_HELP	     ("help")
+
+struct ml_options {
+	char test_name[ML_TEST_NAME_MAX_LEN];
+	int16_t dev_id;
+	int socket_id;
+	bool debug;
+};
+
+void ml_options_default(struct ml_options *opt);
+int ml_options_parse(struct ml_options *opt, int argc, char **argv);
+void ml_options_dump(struct ml_options *opt);
+
+#endif /* _ML_OPTIONS_ */
diff --git a/app/test-mldev/ml_test.c b/app/test-mldev/ml_test.c
new file mode 100644
index 0000000000..2304712764
--- /dev/null
+++ b/app/test-mldev/ml_test.c
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2022 Marvell.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#include "ml_test.h"
+
+static STAILQ_HEAD(, ml_test_entry) head = STAILQ_HEAD_INITIALIZER(head);
+
+void
+ml_test_register(struct ml_test_entry *entry)
+{
+	STAILQ_INSERT_TAIL(&head, entry, next);
+}
+
+struct ml_test *
+ml_test_get(const char *name)
+{
+	struct ml_test_entry *entry;
+
+	if (!name)
+		return NULL;
+
+	STAILQ_FOREACH(entry, &head, next)
+	if (!strncmp(entry->test.name, name, strlen(name)))
+		return &entry->test;
+
+	return NULL;
+}
+
+void
+ml_test_dump_names(void (*f)(const char *name))
+{
+	struct ml_test_entry *entry;
+
+	STAILQ_FOREACH(entry, &head, next)
+	{
+		if (entry->test.name)
+			printf("\t %s\n", entry->test.name);
+		f(entry->test.name);
+	}
+}
diff --git a/app/test-mldev/ml_test.h b/app/test-mldev/ml_test.h
new file mode 100644
index 0000000000..4a1430ec1b
--- /dev/null
+++ b/app/test-mldev/ml_test.h
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2022 Marvell.
+ */
+
+#ifndef _ML_TEST_
+#define _ML_TEST_
+
+#include <stdbool.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#include <rte_common.h>
+
+#include "ml_options.h"
+
+#define ML_TEST_MAX_POOL_SIZE 256
+
+enum ml_test_result {
+	ML_TEST_SUCCESS,
+	ML_TEST_FAILED,
+	ML_TEST_UNSUPPORTED,
+};
+
+struct ml_test;
+
+typedef bool (*ml_test_capability_check_t)(struct ml_options *opt);
+typedef int (*ml_test_options_check_t)(struct ml_options *opt);
+typedef void (*ml_test_options_dump_t)(struct ml_options *opt);
+typedef int (*ml_test_setup_t)(struct ml_test *test, struct ml_options *opt);
+typedef void (*ml_test_destroy_t)(struct ml_test *test, struct ml_options *opt);
+typedef int (*ml_test_driver_t)(struct ml_test *test, struct ml_options *opt);
+typedef int (*ml_test_result_t)(struct ml_test *test, struct ml_options *opt);
+
+struct ml_test_ops {
+	ml_test_capability_check_t cap_check;
+	ml_test_options_check_t opt_check;
+	ml_test_options_dump_t opt_dump;
+	ml_test_setup_t test_setup;
+	ml_test_destroy_t test_destroy;
+	ml_test_driver_t test_driver;
+	ml_test_result_t test_result;
+};
+
+struct ml_test {
+	const char *name;
+	void *test_priv;
+	struct ml_test_ops ops;
+};
+
+struct ml_test_entry {
+	struct ml_test test;
+
+	STAILQ_ENTRY(ml_test_entry) next;
+};
+
+static inline void *
+ml_test_priv(struct ml_test *test)
+{
+	return test->test_priv;
+}
+
+struct ml_test *ml_test_get(const char *name);
+void ml_test_register(struct ml_test_entry *test);
+void ml_test_dump_names(void (*f)(const char *));
+
+#define ML_TEST_REGISTER(nm)                                                                       \
+	static struct ml_test_entry _ml_test_entry_##nm;                                           \
+	RTE_INIT(ml_test_##nm)                                                                     \
+	{                                                                                          \
+		_ml_test_entry_##nm.test.name = RTE_STR(nm);                                       \
+		memcpy(&_ml_test_entry_##nm.test.ops, &nm, sizeof(struct ml_test_ops));            \
+		ml_test_register(&_ml_test_entry_##nm);                                            \
+	}
+
+#endif /* _ML_TEST_ */
diff --git a/app/test-mldev/parser.c b/app/test-mldev/parser.c
new file mode 100644
index 0000000000..0b7fb63fe5
--- /dev/null
+++ b/app/test-mldev/parser.c
@@ -0,0 +1,380 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2016 Intel Corporation.
+ * Copyright (c) 2017 Cavium, Inc.
+ * Copyright (c) 2022 Marvell.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rte_common.h>
+
+#include "parser.h"
+
+static uint32_t
+get_hex_val(char c)
+{
+	switch (c) {
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+		return c - '0';
+	case 'A':
+	case 'B':
+	case 'C':
+	case 'D':
+	case 'E':
+	case 'F':
+		return c - 'A' + 10;
+	case 'a':
+	case 'b':
+	case 'c':
+	case 'd':
+	case 'e':
+	case 'f':
+		return c - 'a' + 10;
+	default:
+		return 0;
+	}
+}
+
+int
+parser_read_arg_bool(const char *p)
+{
+	p = skip_white_spaces(p);
+	int result = -EINVAL;
+
+	if (((p[0] == 'y') && (p[1] == 'e') && (p[2] == 's')) ||
+	    ((p[0] == 'Y') && (p[1] == 'E') && (p[2] == 'S'))) {
+		p += 3;
+		result = 1;
+	}
+
+	if (((p[0] == 'o') && (p[1] == 'n')) || ((p[0] == 'O') && (p[1] == 'N'))) {
+		p += 2;
+		result = 1;
+	}
+
+	if (((p[0] == 'n') && (p[1] == 'o')) || ((p[0] == 'N') && (p[1] == 'O'))) {
+		p += 2;
+		result = 0;
+	}
+
+	if (((p[0] == 'o') && (p[1] == 'f') && (p[2] == 'f')) ||
+	    ((p[0] == 'O') && (p[1] == 'F') && (p[2] == 'F'))) {
+		p += 3;
+		result = 0;
+	}
+
+	p = skip_white_spaces(p);
+
+	if (p[0] != '\0')
+		return -EINVAL;
+
+	return result;
+}
+
+int
+parser_read_uint64(uint64_t *value, const char *p)
+{
+	char *next;
+	uint64_t val;
+
+	p = skip_white_spaces(p);
+	if (!isdigit(*p))
+		return -EINVAL;
+
+	val = strtoul(p, &next, 10);
+	if (p == next)
+		return -EINVAL;
+
+	p = next;
+	switch (*p) {
+	case 'T':
+		val *= 1024ULL;
+		/* fall through */
+	case 'G':
+		val *= 1024ULL;
+		/* fall through */
+	case 'M':
+		val *= 1024ULL;
+		/* fall through */
+	case 'k':
+	case 'K':
+		val *= 1024ULL;
+		p++;
+		break;
+	}
+
+	p = skip_white_spaces(p);
+	if (*p != '\0')
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_int32(int32_t *value, const char *p)
+{
+	char *next;
+	int32_t val;
+
+	p = skip_white_spaces(p);
+	if (!isdigit(*p))
+		return -EINVAL;
+
+	val = strtol(p, &next, 10);
+	if (p == next)
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_int16(int16_t *value, const char *p)
+{
+	char *next;
+	int16_t val;
+
+	p = skip_white_spaces(p);
+	if (!isdigit(*p))
+		return -EINVAL;
+
+	val = strtol(p, &next, 10);
+	if (p == next)
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint64_hex(uint64_t *value, const char *p)
+{
+	char *next;
+	uint64_t val;
+
+	p = skip_white_spaces(p);
+
+	val = strtoul(p, &next, 16);
+	if (p == next)
+		return -EINVAL;
+
+	p = skip_white_spaces(next);
+	if (*p != '\0')
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint32(uint32_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT32_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint32_hex(uint32_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64_hex(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT32_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint16(uint16_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT16_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint16_hex(uint16_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64_hex(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT16_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint8(uint8_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT8_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint8_hex(uint8_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64_hex(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT8_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+int
+parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens)
+{
+	uint32_t i;
+
+	if ((string == NULL) || (tokens == NULL) || (*n_tokens < 1))
+		return -EINVAL;
+
+	for (i = 0; i < *n_tokens; i++) {
+		tokens[i] = strtok_r(string, PARSE_DELIMITER, &string);
+		if (tokens[i] == NULL)
+			break;
+	}
+
+	if ((i == *n_tokens) && (strtok_r(string, PARSE_DELIMITER, &string) != NULL))
+		return -E2BIG;
+
+	*n_tokens = i;
+	return 0;
+}
+
+int
+parse_hex_string(char *src, uint8_t *dst, uint32_t *size)
+{
+	char *c;
+	uint32_t len, i;
+
+	/* Check input parameters */
+	if ((src == NULL) || (dst == NULL) || (size == NULL) || (*size == 0))
+		return -1;
+
+	len = strlen(src);
+	if (((len & 3) != 0) || (len > (*size) * 2))
+		return -1;
+	*size = len / 2;
+
+	for (c = src; *c != 0; c++) {
+		if ((((*c) >= '0') && ((*c) <= '9')) || (((*c) >= 'A') && ((*c) <= 'F')) ||
+		    (((*c) >= 'a') && ((*c) <= 'f')))
+			continue;
+
+		return -1;
+	}
+
+	/* Convert chars to bytes */
+	for (i = 0; i < *size; i++)
+		dst[i] = get_hex_val(src[2 * i]) * 16 + get_hex_val(src[2 * i + 1]);
+
+	return 0;
+}
+
+int
+parse_lcores_list(bool lcores[], int lcores_num, const char *corelist)
+{
+	int i, idx = 0;
+	int min, max;
+	char *end = NULL;
+
+	if (corelist == NULL)
+		return -1;
+	while (isblank(*corelist))
+		corelist++;
+	i = strlen(corelist);
+	while ((i > 0) && isblank(corelist[i - 1]))
+		i--;
+
+	/* Get list of lcores */
+	min = RTE_MAX_LCORE;
+	do {
+		while (isblank(*corelist))
+			corelist++;
+		if (*corelist == '\0')
+			return -1;
+		idx = strtoul(corelist, &end, 10);
+		if (idx < 0 || idx > lcores_num)
+			return -1;
+
+		if (end == NULL)
+			return -1;
+		while (isblank(*end))
+			end++;
+		if (*end == '-') {
+			min = idx;
+		} else if ((*end == ',') || (*end == '\0')) {
+			max = idx;
+			if (min == RTE_MAX_LCORE)
+				min = idx;
+			for (idx = min; idx <= max; idx++) {
+				if (lcores[idx] == 1)
+					return -E2BIG;
+				lcores[idx] = 1;
+			}
+
+			min = RTE_MAX_LCORE;
+		} else
+			return -1;
+		corelist = end + 1;
+	} while (*end != '\0');
+
+	return 0;
+}
diff --git a/app/test-mldev/parser.h b/app/test-mldev/parser.h
new file mode 100644
index 0000000000..f0d5e79e4b
--- /dev/null
+++ b/app/test-mldev/parser.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2010-2016 Intel Corporation.
+ * Copyright (c) 2022 Marvell.
+ */
+
+#ifndef __INCLUDE_PARSER_H__
+#define __INCLUDE_PARSER_H__
+
+#include <ctype.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#define PARSE_DELIMITER " \f\n\r\t\v"
+
+#define skip_white_spaces(pos)                                                                     \
+	({                                                                                         \
+		__typeof__(pos) _p = (pos);                                                        \
+		for (; isspace(*_p); _p++)                                                         \
+			;                                                                          \
+		_p;                                                                                \
+	})
+
+static inline size_t
+skip_digits(const char *src)
+{
+	size_t i;
+
+	for (i = 0; isdigit(src[i]); i++)
+		;
+
+	return i;
+}
+
+int parser_read_arg_bool(const char *p);
+
+int parser_read_uint64(uint64_t *value, const char *p);
+int parser_read_uint32(uint32_t *value, const char *p);
+int parser_read_uint16(uint16_t *value, const char *p);
+int parser_read_uint8(uint8_t *value, const char *p);
+
+int parser_read_uint64_hex(uint64_t *value, const char *p);
+int parser_read_uint32_hex(uint32_t *value, const char *p);
+int parser_read_uint16_hex(uint16_t *value, const char *p);
+int parser_read_uint8_hex(uint8_t *value, const char *p);
+
+int parser_read_int32(int32_t *value, const char *p);
+int parser_read_int16(int16_t *value, const char *p);
+
+int parse_hex_string(char *src, uint8_t *dst, uint32_t *size);
+
+int parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens);
+
+int parse_lcores_list(bool lcores[], int lcores_num, const char *corelist);
+
+#endif /* __INCLUDE_PARSER_H__ */
