[dpdk-dev,v3,1/3] eal: add functions parsing EAL arguments

Message ID 1498560760-104196-2-git-send-email-jacekx.piasecki@intel.com (mailing list archive)
State Superseded, archived
Headers

Checks

Context Check Description
ci/Intel-compilation fail Compilation issues
ci/checkpatch success coding style OK

Commit Message

Jacek Piasecki June 27, 2017, 10:52 a.m. UTC
  From: Kuba Kozak <kubax.kozak@intel.com>

added function rte_eal_configure which configure
Environment Abstraction Layer (EAL) using
configuration structure.

Signed-off-by: Kuba Kozak <kubax.kozak@intel.com>
Suggested-by: Bruce Richardson <bruce.richardson@intel.com>
---
This patch depends on cfgfile patchset with:
"cfgfile: remove EAL dependency"
"cfgfile: add new functions to API"
"cfgfile: rework of load function"
"test/cfgfile: add new unit test"
---
 config/common_base                              |   1 +
 lib/Makefile                                    |   6 +-
 lib/librte_eal/bsdapp/eal/Makefile              |   4 +
 lib/librte_eal/bsdapp/eal/eal.c                 | 249 ++++++++++++++---
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   4 +
 lib/librte_eal/common/eal_common_cpuflags.c     |  14 +-
 lib/librte_eal/common/eal_common_lcore.c        |  11 +-
 lib/librte_eal/common/eal_common_options.c      |   5 +
 lib/librte_eal/common/include/rte_eal.h         |  21 ++
 lib/librte_eal/linuxapp/eal/Makefile            |   3 +
 lib/librte_eal/linuxapp/eal/eal.c               | 353 ++++++++++++++++++------
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |   4 +
 mk/rte.app.mk                                   |   2 +-
 13 files changed, 543 insertions(+), 134 deletions(-)
  

Comments

Bruce Richardson June 30, 2017, 4:04 p.m. UTC | #1
On Tue, Jun 27, 2017 at 12:52:38PM +0200, Jacek Piasecki wrote:
> From: Kuba Kozak <kubax.kozak@intel.com>
> 
> added function rte_eal_configure which configure
> Environment Abstraction Layer (EAL) using
> configuration structure.
> 
> Signed-off-by: Kuba Kozak <kubax.kozak@intel.com>
> Suggested-by: Bruce Richardson <bruce.richardson@intel.com>
> ---

Thanks for looking to implement this idea, to see how it would work.
Comments on the implementation inline below.

Regards,
/Bruce

> This patch depends on cfgfile patchset with:
> "cfgfile: remove EAL dependency"
> "cfgfile: add new functions to API"
> "cfgfile: rework of load function"
> "test/cfgfile: add new unit test"
> ---
>  config/common_base                              |   1 +
>  lib/Makefile                                    |   6 +-
>  lib/librte_eal/bsdapp/eal/Makefile              |   4 +
>  lib/librte_eal/bsdapp/eal/eal.c                 | 249 ++++++++++++++---
>  lib/librte_eal/bsdapp/eal/rte_eal_version.map   |   4 +
>  lib/librte_eal/common/eal_common_cpuflags.c     |  14 +-
>  lib/librte_eal/common/eal_common_lcore.c        |  11 +-
>  lib/librte_eal/common/eal_common_options.c      |   5 +
>  lib/librte_eal/common/include/rte_eal.h         |  21 ++
>  lib/librte_eal/linuxapp/eal/Makefile            |   3 +
>  lib/librte_eal/linuxapp/eal/eal.c               | 353 ++++++++++++++++++------
>  lib/librte_eal/linuxapp/eal/rte_eal_version.map |   4 +
>  mk/rte.app.mk                                   |   2 +-
>  13 files changed, 543 insertions(+), 134 deletions(-)
> 
> diff --git a/config/common_base b/config/common_base
> index f6aafd1..c1d0e69 100644
> --- a/config/common_base
> +++ b/config/common_base
> @@ -569,6 +569,7 @@ CONFIG_RTE_LIBRTE_TIMER_DEBUG=n
>  # Compile librte_cfgfile
>  #
>  CONFIG_RTE_LIBRTE_CFGFILE=y
> +CONFIG_RTE_LIBRTE_CFGFILE_DEBUG=n

This change does not belong in this patchset. In fact, I don't think it
belongs anywhere as there are no debug statements in the cfgfile
library.

>  
>  #
>  # Compile librte_cmdline
> diff --git a/lib/Makefile b/lib/Makefile
> index 07e1fd0..fc5df3a 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -32,7 +32,11 @@
>  include $(RTE_SDK)/mk/rte.vars.mk
>  
>  DIRS-y += librte_compat
> +DIRS-$(CONFIG_RTE_LIBRTE_CFGFILE) += librte_cfgfile
>  DIRS-$(CONFIG_RTE_LIBRTE_EAL) += librte_eal
> +ifeq ($(CONFIG_RTE_LIBRTE_CFGFILE),y)
> +DEPDIRS-librte_eal := librte_cfgfile
> +endif
>  DIRS-$(CONFIG_RTE_LIBRTE_RING) += librte_ring
>  DEPDIRS-librte_ring := librte_eal
>  DIRS-$(CONFIG_RTE_LIBRTE_MEMPOOL) += librte_mempool
> @@ -41,8 +45,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_MBUF) += librte_mbuf
>  DEPDIRS-librte_mbuf := librte_eal librte_mempool
>  DIRS-$(CONFIG_RTE_LIBRTE_TIMER) += librte_timer
>  DEPDIRS-librte_timer := librte_eal
> -DIRS-$(CONFIG_RTE_LIBRTE_CFGFILE) += librte_cfgfile
> -DEPDIRS-librte_cfgfile := librte_eal
>  DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
>  DEPDIRS-librte_cmdline := librte_eal
>  DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether

I think the parts of this change - the deleteion of the line saying
cfgfile depends on EAL, and the moving of the declaration of the cfgfile
library up in the file, should go in patch 1 of the earlier cfgfile set.

> diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
> index a0f9950..d70eefb 100644
> --- a/lib/librte_eal/bsdapp/eal/Makefile
> +++ b/lib/librte_eal/bsdapp/eal/Makefile
> @@ -50,6 +50,10 @@ EXPORT_MAP := rte_eal_version.map
>  
>  LIBABIVER := 4
>  
> +ifeq ($(CONFIG_RTE_LIBRTE_CFGFILE),y)
> +LDLIBS += -lrte_cfgfile
> +endif
> +

This should not be needed here. Other DPDK libs which depend on yet
other libs don't go modifying the LDLIBS like this.

>  # specific to bsdapp exec-env
>  SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) := eal.c
>  SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_memory.c
> diff --git a/lib/librte_eal/bsdapp/eal/eal.c b/lib/librte_eal/bsdapp/eal/eal.c
> index 05f0c1f..7baf848 100644
> --- a/lib/librte_eal/bsdapp/eal/eal.c
> +++ b/lib/librte_eal/bsdapp/eal/eal.c
> @@ -73,6 +73,7 @@
>  #include <rte_version.h>
>  #include <rte_atomic.h>
>  #include <malloc_heap.h>
> +#include <rte_cfgfile.h>
>  
>  #include "eal_private.h"
>  #include "eal_thread.h"
> @@ -309,6 +310,18 @@ eal_get_hugepage_mem_size(void)
>  
>  /* Parse the arguments for --log-level only */
>  static void
> +eal_log_level_cfg(struct rte_cfgfile *cfg)
> +{
> +	const char *entry;
> +
> +	entry = rte_cfgfile_get_entry(cfg, "DPDK", OPT_LOG_LEVEL);
> +	if (entry)
> +		eal_parse_common_option(OPT_LOG_LEVEL_NUM, entry,
> +				&internal_config);
> +}
> +
> +/* Parse the arguments for --log-level only */
> +static void
>  eal_log_level_parse(int argc, char **argv)
>  {
>  	int opt;
> @@ -347,6 +360,58 @@ eal_log_level_parse(int argc, char **argv)
>  	optarg = old_optarg;
>  }
>  
> +/* Parse single argument */
> +static int
> +eal_parse_option(int opt, char *optarg, int option_index, char *prgname)
> +{
> +	int ret;
> +
> +	/* getopt is not happy, stop right now */
> +	if (opt == '?') {
> +		eal_usage(prgname);
> +		ret = -1;
> +		goto out;
> +	}
> +
> +	ret = eal_parse_common_option(opt, optarg, &internal_config);
> +	/* common parser is not happy */
> +	if (ret < 0) {
> +		eal_usage(prgname);
> +		ret = -1;
> +		goto out;
> +	}
> +	/* common parser handled this option */
> +	if (ret == 0)
> +		return 0;
> +
> +	switch (opt) {
> +	case 'h':
> +		eal_usage(prgname);
> +		exit(EXIT_SUCCESS);
> +		break;
> +
> +	default:
> +		if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
> +			RTE_LOG(ERR, EAL, "Option %c is not supported "
> +				"on FreeBSD\n", opt);
> +		} else if (opt >= OPT_LONG_MIN_NUM &&
> +			   opt < OPT_LONG_MAX_NUM) {
> +			RTE_LOG(ERR, EAL, "Option %s is not supported "
> +				"on FreeBSD\n",
> +				eal_long_options[option_index].name);
> +		} else {
> +			RTE_LOG(ERR, EAL, "Option %d is not supported "
> +				"on FreeBSD\n", opt);
> +		}
> +		eal_usage(prgname);
> +		ret = -1;
> +		goto out;
> +	}
> +	return 0;
> +out:
> +	return ret;
> +}
> +
>  /* Parse the argument given in the command line of the application */
>  static int
>  eal_parse_args(int argc, char **argv)
> @@ -367,45 +432,9 @@ eal_parse_args(int argc, char **argv)
>  	while ((opt = getopt_long(argc, argvopt, eal_short_options,
>  				  eal_long_options, &option_index)) != EOF) {
>  
> -		/* getopt is not happy, stop right now */
> -		if (opt == '?') {
> -			eal_usage(prgname);
> -			ret = -1;
> -			goto out;
> -		}
> -
> -		ret = eal_parse_common_option(opt, optarg, &internal_config);
> -		/* common parser is not happy */
> -		if (ret < 0) {
> -			eal_usage(prgname);
> -			ret = -1;
> -			goto out;
> -		}
> -		/* common parser handled this option */
> -		if (ret == 0)
> -			continue;
> -
> -		switch (opt) {
> -		case 'h':
> -			eal_usage(prgname);
> -			exit(EXIT_SUCCESS);
> -		default:
> -			if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
> -				RTE_LOG(ERR, EAL, "Option %c is not supported "
> -					"on FreeBSD\n", opt);
> -			} else if (opt >= OPT_LONG_MIN_NUM &&
> -				   opt < OPT_LONG_MAX_NUM) {
> -				RTE_LOG(ERR, EAL, "Option %s is not supported "
> -					"on FreeBSD\n",
> -					eal_long_options[option_index].name);
> -			} else {
> -				RTE_LOG(ERR, EAL, "Option %d is not supported "
> -					"on FreeBSD\n", opt);
> -			}
> -			eal_usage(prgname);
> -			ret = -1;
> +		ret = eal_parse_option(opt, optarg, option_index, prgname);
> +		if (ret < 0)
>  			goto out;
> -		}
>  	}
>  
>  	if (eal_adjust_config(&internal_config) != 0) {
> @@ -677,3 +706,147 @@ rte_eal_process_type(void)
>  {
>  	return rte_config.process_type;
>  }
> +
> +#ifdef RTE_LIBRTE_CFGFILE
> +#define vdev_buff_size		200
> +#define sectionname_size	20
> +static int
> +parse_vdev_devices(struct rte_cfgfile *cfg)
> +{
> +	char sectionname[sectionname_size];
> +	char buffer1[vdev_buff_size];
> +	int vdev_nb = 0;
> +	int n_entries;
> +	int i;
> +
> +	/* ----------- parsing VDEVS */
> +	snprintf(sectionname, sectionname_size, "DPDK.vdev%d", vdev_nb);

move this inside the loop to be the first thing done, rather than having
it outside and then the last thing on each iteration.

> +
> +	for (vdev_nb = 1; rte_cfgfile_has_section(cfg, sectionname);
> +			vdev_nb++) {
> +		n_entries = rte_cfgfile_section_num_entries(cfg, sectionname);
> +
> +		struct rte_cfgfile_entry entries[n_entries];
> +
> +		if (n_entries != rte_cfgfile_section_entries(cfg, sectionname,
> +				entries, n_entries)) {
> +			rte_eal_init_alert("Unexpected fault.");
> +			rte_errno = EFAULT;
> +			return -1;
> +		}
> +
> +		buffer1[0] = 0;
> +		for (i = 0; i < n_entries; i++) {
> +			if (strlen(entries[i].value)) {
> +
> +				if ((strlen(buffer1) +
> +						strlen(entries[i].name) +
> +						strlen(entries[i].value) + 3)
> +						>= vdev_buff_size)
> +					goto buff_size_err;
> +				strcat(buffer1, entries[i].name);
> +				strcat(buffer1, "=");
> +				strcat(buffer1, entries[i].value);
> +			} else {
> +				if ((strlen(buffer1) +
> +						strlen(entries[i].name) + 2)
> +						>= vdev_buff_size)
> +					goto buff_size_err;
> +				strcat(buffer1, entries[i].name);
> +			}
> +

Doing these strlen calls and calculations that way is horribly
inefficient IMHO, even if this is not in a perf-critical path. Instead,
I would look to start with a buf_len variable which tracks the available
buffer size, and a buf_ptr variable which points to the first available
character. Then do the following each time you want to add something:

	ret = snprintf(buf_ptr, buf_len, "%s%s%s", entries[i].name,
		entries[i].value[0] != '\0' ? "=" : "",
		entries[i].value);
	if (ret >= buf_len)
		goto buff_size_err;
	buf_ptr += ret;
	buf_len -= ret;

Shorter and simpler, as well as being more efficient as it does not need
any string length computation calls, using snprintf safely instead.

> +			if (i < (n_entries - 1))
> +				strcat(buffer1, ",");

You can add this bit into the above snprintf too, in a similar way to
how I optionally added the "=".

> +		}
> +
> +		/* parsing vdev */
> +		if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL,
> +				buffer1) < 0) {
> +			return -1;
> +		}
> +		snprintf(sectionname, sectionname_size, "DPDK.vdev%d", vdev_nb);
> +	}
> +	/* ----------- parsing VDEVS */
> +	return 0;
> +
> +buff_size_err:
> +	printf("parse_vdev_devices(): buffer size is to small\n");
> +	return -1;

If the code is reworked so that there is only one place where this error
occurs, remove the label and goto, and just put the error handling
inline in the code.

> +}
> +
> +static void
> +eal_getopt(const char *str, int *opt, int *option_index)
> +{
> +	int i;
> +
> +	*opt = '?';
> +	*option_index = 0;
> +
> +	if (strlen(str) == 1) {
> +		*opt = *str;
> +		return;
> +	}
> +
> +	for (i = 0; eal_long_options[i].name != NULL; i++) {
> +		if (strcmp(str, eal_long_options[i].name) == 0) {
> +			*opt = eal_long_options[i].val;
> +			*option_index = i;
> +			break;
> +		}
> +	}
> +}
> +
> +int
> +rte_eal_configure(struct rte_cfgfile *cfg, char *prgname)
> +{
> +	int n_entries;
> +	int i;
> +	int opt;
> +	int option_index;
> +
> +	if (cfg == NULL) {
> +		rte_errno = -EINVAL;
> +		return -1;
> +	}
> +
> +	n_entries = rte_cfgfile_section_num_entries(cfg, "DPDK");
> +
> +	if (n_entries < 1) {
> +		printf("No DPDK section entries in cfgfile object\n");
> +		return 0;
> +	}
> +
> +	struct rte_cfgfile_entry entries[n_entries];
> +
> +	if (n_entries !=
> +			rte_cfgfile_section_entries(cfg, "DPDK", entries,
> +					n_entries)) {
> +		rte_eal_init_alert("Unexpected fault.");
> +		rte_errno = EFAULT;
> +		return -1;
> +	}
> +
> +	eal_reset_internal_config(&internal_config);
> +
> +	/* set log level as early as possible */
> +	eal_log_level_cfg(cfg);
> +
> +	for (i = 0; i < n_entries; i++) {
> +		eal_getopt(entries[i].name, &opt, &option_index);
> +
> +		if (eal_parse_option(opt, entries[i].value,
> +				option_index, prgname) != 0) {
> +			rte_eal_init_alert("Invalid config file arguments.");
> +			rte_errno = EINVAL;
> +			return -1;
> +		}
> +	}
> +
> +	if (parse_vdev_devices(cfg) < 0) {
> +		rte_eal_init_alert("Couldn't parse vdevs");
> +		rte_errno = ENOMEM;
> +		return -1;
> +	}
> +	return 0;
> +}
> +#endif
> diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
> index 2e48a73..a939b03 100644
> --- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
> +++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
> @@ -193,3 +193,7 @@ DPDK_17.05 {
>  	vfio_get_group_no;
>  
>  } DPDK_17.02;
> +
> +DPDK_17.08 {
> +	rte_eal_configure;
> +} DPDK_17.05;
> diff --git a/lib/librte_eal/common/eal_common_cpuflags.c b/lib/librte_eal/common/eal_common_cpuflags.c
> index 9a2d080..6a365f3 100644
> --- a/lib/librte_eal/common/eal_common_cpuflags.c
> +++ b/lib/librte_eal/common/eal_common_cpuflags.c
> @@ -50,12 +50,18 @@ rte_cpu_check_supported(void)
>  int
>  rte_cpu_is_supported(void)
>  {
> +	static int run_once;
> +	static int ret;
>  	/* This is generated at compile-time by the build system */
>  	static const enum rte_cpu_flag_t compile_time_flags[] = {
>  			RTE_COMPILE_TIME_CPUFLAGS
>  	};
>  	unsigned count = RTE_DIM(compile_time_flags), i;
> -	int ret;
> +
> +	/* No need to calculate this function again if we know the result */
> +	if (run_once)
> +		return ret;
> +	run_once = 1;
>  
>  	for (i = 0; i < count; i++) {
>  		ret = rte_cpu_get_flag_enabled(compile_time_flags[i]);
> @@ -64,16 +70,16 @@ rte_cpu_is_supported(void)
>  			fprintf(stderr,
>  				"ERROR: CPU feature flag lookup failed with error %d\n",
>  				ret);
> -			return 0;
> +			return ret = 0;
>  		}
>  		if (!ret) {
>  			fprintf(stderr,
>  			        "ERROR: This system does not support \"%s\".\n"
>  			        "Please check that RTE_MACHINE is set correctly.\n",
>  			        rte_cpu_get_flag_name(compile_time_flags[i]));
> -			return 0;
> +			return ret = 0;
>  		}
>  	}
>  
> -	return 1;
> +	return ret = 1;
>  }

This is not a bad change in and of itself. However, I'm not sure it
belongs in this patchset. With the new configure call, we should still
only be calling these initialization functions once - in eal_init().


> diff --git a/lib/librte_eal/common/eal_common_lcore.c b/lib/librte_eal/common/eal_common_lcore.c
> index 84fa0cb..ce3ef34 100644
> --- a/lib/librte_eal/common/eal_common_lcore.c
> +++ b/lib/librte_eal/common/eal_common_lcore.c
> @@ -53,11 +53,18 @@
>  int
>  rte_eal_cpu_init(void)
>  {
> +	static int run_once;
> +	static int ret;
>  	/* pointer to global configuration */
>  	struct rte_config *config = rte_eal_get_configuration();
>  	unsigned lcore_id;
>  	unsigned count = 0;
>  
> +	/* No need to calculate this function again if we know the result */
> +	if (run_once)
> +		return ret;
> +	run_once = 1;
> +
>  	/*
>  	 * Parse the maximum set of logical cores, detect the subset of running
>  	 * ones and enable them by default.
> @@ -91,7 +98,7 @@ rte_eal_cpu_init(void)
>  				"RTE_MAX_NUMA_NODES (%d)\n",
>  				lcore_config[lcore_id].socket_id,
>  				RTE_MAX_NUMA_NODES);
> -			return -1;
> +			return ret = -1;
>  #endif
>  		}
>  		RTE_LOG(DEBUG, EAL, "Detected lcore %u as "
> @@ -107,5 +114,5 @@ rte_eal_cpu_init(void)
>  		RTE_MAX_LCORE);
>  	RTE_LOG(INFO, EAL, "Detected %u lcore(s)\n", config->lcore_count);
>  
> -	return 0;
> +	return ret = 0;
>  }

As above, should not be needed.

> diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c
> index f470195..138a27f 100644
> --- a/lib/librte_eal/common/eal_common_options.c
> +++ b/lib/librte_eal/common/eal_common_options.c
> @@ -131,8 +131,13 @@ static int core_parsed;
>  void
>  eal_reset_internal_config(struct internal_config *internal_cfg)
>  {
> +	static int run_once;
>  	int i;
>  
> +	if (run_once)
> +		return;
> +	run_once = 1;
> +
>  	internal_cfg->memory = 0;
>  	internal_cfg->force_nrank = 0;
>  	internal_cfg->force_nchannel = 0;

I don't think for this function this is the way to do things, given that
the function does one job - resetting the internal config - and the new
flag just disables it. It's different from e.g. the cpu check which is
able to cache a return value.

Instead, this should be tracked at the higher eal level, and not call
the function at all if it is unneeded. This mean that eal_init should
check itself if configure has already called the function and then skip
calling it itself.

> diff --git a/lib/librte_eal/common/include/rte_eal.h b/lib/librte_eal/common/include/rte_eal.h
> index abf020b..e0705de 100644
> --- a/lib/librte_eal/common/include/rte_eal.h
> +++ b/lib/librte_eal/common/include/rte_eal.h
> @@ -46,6 +46,8 @@
>  #include <rte_per_lcore.h>
>  #include <rte_config.h>
>  
> +struct rte_cfgfile; /* forward declaration of struct */
> +
>  #ifdef __cplusplus
>  extern "C" {
>  #endif
> @@ -188,6 +190,25 @@ int rte_eal_iopl_init(void);
>   */
>  int rte_eal_init(int argc, char **argv);
>  
> +#ifdef RTE_LIBRTE_CFGFILE
> +/**
> + * Initialize the Environment Abstraction Layer (EAL) using
> + * configuration structure
> + *
> + * @param cfg
> + *   pointer to config file structure.
> + *   If 0 - function free allocated for **cfg_argv memory

Don't understand this comment.

> + * @param prgname
> + *   pointer to string with execution path
> + *
> + * @return
> + *  - On success, return 0
> + *  - On failure, returns -1.
> + */
> +int
> +rte_eal_configure(struct rte_cfgfile *cfg, char *prgname);
> +#endif
> +
>  /**
>   * Check if a primary process is currently alive
>   *
> diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
> index 640afd0..656033e 100644
> --- a/lib/librte_eal/linuxapp/eal/Makefile
> +++ b/lib/librte_eal/linuxapp/eal/Makefile
> @@ -50,6 +50,9 @@ LDLIBS += -ldl
>  LDLIBS += -lpthread
>  LDLIBS += -lgcc_s
>  LDLIBS += -lrt
> +ifeq ($(CONFIG_RTE_LIBRTE_CFGFILE),y)
> +LDLIBS += -lrte_cfgfile
> +endif
>  
>  # specific to linuxapp exec-env
>  SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) := eal.c
> diff --git a/lib/librte_eal/linuxapp/eal/eal.c b/lib/librte_eal/linuxapp/eal/eal.c
> index 7c78f2d..f5973f4 100644
> --- a/lib/librte_eal/linuxapp/eal/eal.c
> +++ b/lib/librte_eal/linuxapp/eal/eal.c
> @@ -78,6 +78,9 @@
>  #include <rte_version.h>
>  #include <rte_atomic.h>
>  #include <malloc_heap.h>
> +#ifdef RTE_LIBRTE_CFGFILE
> +#include <rte_cfgfile.h>
> +#endif
>  
>  #include "eal_private.h"
>  #include "eal_thread.h"
> @@ -478,6 +481,20 @@ eal_parse_vfio_intr(const char *mode)
>  	return -1;
>  }
>  
> +#ifdef RTE_LIBRTE_CFGFILE
> +/* Parse the arguments for --log-level only */
> +static void
> +eal_log_level_cfg(struct rte_cfgfile *cfg)
> +{
> +	const char *entry;
> +
> +	entry = rte_cfgfile_get_entry(cfg, "DPDK", OPT_LOG_LEVEL);
> +	if (entry)
> +		eal_parse_common_option(OPT_LOG_LEVEL_NUM, entry,
> +				&internal_config);
> +}
> +#endif
> +

This looks the same as the BSD version. Can it go in a common file?

>  /* Parse the arguments for --log-level only */
>  static void
>  eal_log_level_parse(int argc, char **argv)
> @@ -515,119 +532,135 @@ eal_log_level_parse(int argc, char **argv)
>  	optarg = old_optarg;
>  }
>  
> -/* Parse the argument given in the command line of the application */
> +/* Parse single argument */
>  static int
> -eal_parse_args(int argc, char **argv)
> +eal_parse_option(int opt, char *optarg, int option_index, char *prgname)
>  {
> -	int opt, ret;
> -	char **argvopt;
> -	int option_index;
> -	char *prgname = argv[0];
> -	const int old_optind = optind;
> -	const int old_optopt = optopt;
> -	char * const old_optarg = optarg;
> +	int ret;
>  
> -	argvopt = argv;
> -	optind = 1;
> +	/* getopt is not happy, stop right now */
> +	if (opt == '?') {
> +		eal_usage(prgname);
> +		ret = -1;
> +		goto out;
> +	}
>  
> -	while ((opt = getopt_long(argc, argvopt, eal_short_options,
> -				  eal_long_options, &option_index)) != EOF) {
> +	ret = eal_parse_common_option(opt, optarg, &internal_config);
> +	/* common parser is not happy */
> +	if (ret < 0) {
> +		eal_usage(prgname);
> +		ret = -1;
> +		goto out;
> +	}
> +	/* common parser handled this option */
> +	if (ret == 0)
> +		return 0;
>  
> -		/* getopt is not happy, stop right now */
> -		if (opt == '?') {
> +	switch (opt) {
> +	case 'h':
> +		eal_usage(prgname);
> +		exit(EXIT_SUCCESS);
> +		break;
> +
> +	/* long options */
> +	case OPT_XEN_DOM0_NUM:
> +#ifdef RTE_LIBRTE_XEN_DOM0
> +		internal_config.xen_dom0_support = 1;
> +		break;
> +#else
> +		RTE_LOG(ERR, EAL, "Can't support DPDK app "
> +			"running on Dom0, please configure"
> +			" RTE_LIBRTE_XEN_DOM0=y\n");
> +		ret = -1;
> +		goto out;
> +#endif
> +
> +	case OPT_HUGE_DIR_NUM:
> +		internal_config.hugepage_dir = optarg;
> +		break;
> +
> +	case OPT_FILE_PREFIX_NUM:
> +		internal_config.hugefile_prefix = optarg;
> +		break;
> +
> +	case OPT_SOCKET_MEM_NUM:
> +		if (eal_parse_socket_mem(optarg) < 0) {
> +			RTE_LOG(ERR, EAL, "invalid parameters for --"
> +					OPT_SOCKET_MEM "\n");
>  			eal_usage(prgname);
>  			ret = -1;
>  			goto out;
>  		}
> +		break;
>  
> -		ret = eal_parse_common_option(opt, optarg, &internal_config);
> -		/* common parser is not happy */
> -		if (ret < 0) {
> +	case OPT_BASE_VIRTADDR_NUM:
> +		if (eal_parse_base_virtaddr(optarg) < 0) {
> +			RTE_LOG(ERR, EAL, "invalid parameter for --"
> +					OPT_BASE_VIRTADDR "\n");
>  			eal_usage(prgname);
>  			ret = -1;
>  			goto out;
>  		}
> -		/* common parser handled this option */
> -		if (ret == 0)
> -			continue;
> +		break;
>  
> -		switch (opt) {
> -		case 'h':
> +	case OPT_VFIO_INTR_NUM:
> +		if (eal_parse_vfio_intr(optarg) < 0) {
> +			RTE_LOG(ERR, EAL, "invalid parameters for --"
> +					OPT_VFIO_INTR "\n");
>  			eal_usage(prgname);
> -			exit(EXIT_SUCCESS);
> -
> -		/* long options */
> -		case OPT_XEN_DOM0_NUM:
> -#ifdef RTE_LIBRTE_XEN_DOM0
> -			internal_config.xen_dom0_support = 1;
> -#else
> -			RTE_LOG(ERR, EAL, "Can't support DPDK app "
> -				"running on Dom0, please configure"
> -				" RTE_LIBRTE_XEN_DOM0=y\n");
>  			ret = -1;
>  			goto out;
> -#endif
> -			break;
> +		}
> +		break;
>  
> -		case OPT_HUGE_DIR_NUM:
> -			internal_config.hugepage_dir = optarg;
> -			break;
> +	case OPT_CREATE_UIO_DEV_NUM:
> +		internal_config.create_uio_dev = 1;
> +		break;
>  
> -		case OPT_FILE_PREFIX_NUM:
> -			internal_config.hugefile_prefix = optarg;
> -			break;
> +	default:
> +		if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
> +			RTE_LOG(ERR, EAL, "Option %c is not supported "
> +				"on Linux\n", opt);
> +		} else if (opt >= OPT_LONG_MIN_NUM &&
> +			   opt < OPT_LONG_MAX_NUM) {
> +			RTE_LOG(ERR, EAL, "Option %s is not supported "
> +				"on Linux\n",
> +				eal_long_options[option_index].name);
> +		} else {
> +			RTE_LOG(ERR, EAL, "Option %d is not supported "
> +				"on Linux\n", opt);
> +		}
> +		eal_usage(prgname);
> +		ret = -1;
> +		goto out;
> +	}
>  
> -		case OPT_SOCKET_MEM_NUM:
> -			if (eal_parse_socket_mem(optarg) < 0) {
> -				RTE_LOG(ERR, EAL, "invalid parameters for --"
> -						OPT_SOCKET_MEM "\n");
> -				eal_usage(prgname);
> -				ret = -1;
> -				goto out;
> -			}
> -			break;
> +	return 0;
> +out:
> +	return ret;
> +}
>  
> -		case OPT_BASE_VIRTADDR_NUM:
> -			if (eal_parse_base_virtaddr(optarg) < 0) {
> -				RTE_LOG(ERR, EAL, "invalid parameter for --"
> -						OPT_BASE_VIRTADDR "\n");
> -				eal_usage(prgname);
> -				ret = -1;
> -				goto out;
> -			}
> -			break;
> +/* Parse the argument given in the command line of the application */
> +static int
> +eal_parse_args(int argc, char **argv)
> +{
> +	int opt, ret;
> +	char **argvopt;
> +	int option_index;
> +	char *prgname = argv[0];
> +	const int old_optind = optind;
> +	const int old_optopt = optopt;
> +	char * const old_optarg = optarg;
>  
> -		case OPT_VFIO_INTR_NUM:
> -			if (eal_parse_vfio_intr(optarg) < 0) {
> -				RTE_LOG(ERR, EAL, "invalid parameters for --"
> -						OPT_VFIO_INTR "\n");
> -				eal_usage(prgname);
> -				ret = -1;
> -				goto out;
> -			}
> -			break;
> +	argvopt = argv;
> +	optind = 1;
>  
> -		case OPT_CREATE_UIO_DEV_NUM:
> -			internal_config.create_uio_dev = 1;
> -			break;
> +	while ((opt = getopt_long(argc, argvopt, eal_short_options,
> +				  eal_long_options, &option_index)) != EOF) {
>  
> -		default:
> -			if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
> -				RTE_LOG(ERR, EAL, "Option %c is not supported "
> -					"on Linux\n", opt);
> -			} else if (opt >= OPT_LONG_MIN_NUM &&
> -				   opt < OPT_LONG_MAX_NUM) {
> -				RTE_LOG(ERR, EAL, "Option %s is not supported "
> -					"on Linux\n",
> -					eal_long_options[option_index].name);
> -			} else {
> -				RTE_LOG(ERR, EAL, "Option %d is not supported "
> -					"on Linux\n", opt);
> -			}
> -			eal_usage(prgname);
> -			ret = -1;
> +		ret = eal_parse_option(opt, optarg, option_index, prgname);
> +		if (ret < 0)
>  			goto out;
> -		}
>  	}
>  
>  	if (eal_adjust_config(&internal_config) != 0) {
> @@ -995,3 +1028,149 @@ rte_eal_check_module(const char *module_name)
>  	/* Module has been found */
>  	return 1;
>  }
> +
> +#ifdef RTE_LIBRTE_CFGFILE
> +#define vdev_buff_size		200
> +#define sectionname_size	20
> +static int
> +parse_vdev_devices(struct rte_cfgfile *cfg)
> +{
> +	char sectionname[sectionname_size];
> +	char buffer1[vdev_buff_size];
> +	int vdev_nb = 0;
> +	int n_entries;
> +
> +	int i;
> +
> +	/* ----------- parsing VDEVS */
> +	snprintf(sectionname, sectionname_size, "DPDK.vdev%d", vdev_nb);
> +
> +	for (vdev_nb = 1; rte_cfgfile_has_section(cfg, sectionname);
> +			vdev_nb++) {
> +		n_entries = rte_cfgfile_section_num_entries(cfg, sectionname);
> +
> +		struct rte_cfgfile_entry entries[n_entries];
> +
> +
> +		if (n_entries != rte_cfgfile_section_entries(cfg, sectionname,
> +				entries, n_entries)) {
> +			rte_eal_init_alert("Unexpected fault.");
> +			rte_errno = EFAULT;
> +			return -1;
> +		}
> +
> +		buffer1[0] = 0;
> +		for (i = 0; i < n_entries; i++) {
> +			if (strlen(entries[i].value)) {
> +
> +				if ((strlen(buffer1) +
> +						strlen(entries[i].name) +
> +						strlen(entries[i].value) + 3)
> +						>= vdev_buff_size)
> +					goto buff_size_err;
> +				strcat(buffer1, entries[i].name);
> +				strcat(buffer1, "=");
> +				strcat(buffer1, entries[i].value);
> +			} else {
> +				if ((strlen(buffer1) +
> +						strlen(entries[i].name) + 2)
> +						>= vdev_buff_size)
> +					goto buff_size_err;
> +				strcat(buffer1, entries[i].name);
> +			}
> +
> +			if (i < (n_entries - 1))
> +				strcat(buffer1, ",");
> +		}
> +
> +		/* parsing vdev */
> +		if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL,
> +				buffer1) < 0) {
> +			return -1;
> +		}
> +		snprintf(sectionname, sectionname_size, "DPDK.vdev%d", vdev_nb);
> +	}
> +	/* ----------- parsing VDEVS */
> +	return 0;
> +
> +buff_size_err:
> +	printf("parse_vdev_devices(): buffer size is to small\n");
> +	return -1;
> +}
> +
> +static void
> +eal_getopt(const char *str, int *opt, int *option_index)
> +{
> +	int i;
> +
> +	*opt = '?';
> +	*option_index = 0;
> +
> +	if (strlen(str) == 1) {
> +		*opt = *str;
> +		return;
> +	}
> +
> +	for (i = 0; eal_long_options[i].name != NULL; i++) {
> +		if (strcmp(str, eal_long_options[i].name) == 0) {
> +			*opt = eal_long_options[i].val;
> +			*option_index = i;
> +			break;
> +		}
> +	}
> +}
> +
> +int
> +rte_eal_configure(struct rte_cfgfile *cfg, char *prgname)
> +{
> +	int n_entries;
> +	int i;
> +	int opt;
> +	int option_index;
> +
> +	if (cfg == NULL) {
> +		rte_errno = -EINVAL;
> +		return -1;
> +	}
> +
> +	n_entries = rte_cfgfile_section_num_entries(cfg, "DPDK");
> +
> +	if (n_entries < 1) {
> +		printf("No DPDK section entries in cfgfile object\n");
> +		return 0;
> +	}
> +
> +	struct rte_cfgfile_entry entries[n_entries];
> +
> +	if (n_entries !=
> +			rte_cfgfile_section_entries(cfg, "DPDK", entries,
> +					n_entries)) {
> +		rte_eal_init_alert("Unexpected fault.");
> +		rte_errno = EFAULT;
> +		return -1;
> +	}
> +
> +	eal_reset_internal_config(&internal_config);
> +
> +	/* set log level as early as possible */
> +	eal_log_level_cfg(cfg);
> +
> +	for (i = 0; i < n_entries; i++) {
> +		eal_getopt(entries[i].name, &opt, &option_index);
> +
> +		if (eal_parse_option(opt, entries[i].value,
> +				option_index, prgname) != 0) {
> +			rte_eal_init_alert("Invalid config file arguments.");
> +			rte_errno = EINVAL;
> +			return -1;
> +		}
> +	}
> +
> +	if (parse_vdev_devices(cfg) < 0) {
> +		rte_eal_init_alert("Couldn't parse vdevs");
> +		rte_errno = ENOMEM;
> +		return -1;
> +	}
> +	return 0;
> +}
> +#endif

Can this code in the #ifdef #endif block above go in a common file, as
again it looks very alike the BSD version? 

> diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
> index 670bab3..c93e6d9 100644
> --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
> +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
> @@ -198,3 +198,7 @@ DPDK_17.05 {
>  	vfio_get_group_no;
>  
>  } DPDK_17.02;
> +
> +DPDK_17.08 {
> +	rte_eal_configure;
> +} DPDK_17.05;
> diff --git a/mk/rte.app.mk b/mk/rte.app.mk
> index bcaf1b3..642af92 100644
> --- a/mk/rte.app.mk
> +++ b/mk/rte.app.mk
> @@ -80,7 +80,6 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)          += -lrte_power
>  
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)            += -lrte_efd
> -_LDLIBS-$(CONFIG_RTE_LIBRTE_CFGFILE)        += -lrte_cfgfile
>  
>  _LDLIBS-y += --whole-archive
>  
> @@ -96,6 +95,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
>  _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING)   += -lrte_mempool_ring
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_EAL)            += -lrte_eal
> +_LDLIBS-$(CONFIG_RTE_LIBRTE_CFGFILE)        += -lrte_cfgfile
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE)        += -lrte_cmdline
>  _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER)        += -lrte_reorder
>  
> -- 
> 2.7.4
>
  
Jacek Piasecki July 10, 2017, 12:44 p.m. UTC | #2
New API for cfgfile library allows to create a cfgfile at runtime, add new
section, add entry in a section, update existing entry and save cfgfile
structure to INI file - opens up the possibility to have applications
dynamically build up a proper DPDK configuration, rather than
having to have a pre-existing one. Due the new API functions, simplification
of load() function was made. One new unit test to TEST app was added. It
contains an example of a large INI file whose parsing requires multiple
reallocation of memory.

---
v4:	
	Change members of structure cfgfile:
	- struct *sections[] to *sections
	- struct *entries[] to *entries
	- remove free_sections and free_entries
	Rework of existing cfgfile API functions to work with modified
	rte_cfgfile struct.
	Rework of malloc/realloc implementation due rte_cfgfile struct change,
	reducing mulitiple mallocs.
	Change return error codes for all library functions (errno.h)
	Checkpatch fixes
v3: 
	split one patchset into two distinct patchsets:
	1. cfgfile library and TEST app changes
	2. EAL changes and examples (this patchset depends on cfgfile)
v2:
  lib eal:
  	Rework of rte_eal_configure(struct rte_cfgfile *cfg, char *prgname).
	Now this function load data from cfg structure and did initial
	initialization of EAL arguments. Vdev argument are stored in different
	subsections eg. DPDK.vdev0, DPDK.vdev1 etc. After execution of this
	function it is necessary to call rte_eal_init to complete EAL
	initialization. There is no more merging arguments from different
	sources (cfg file and command line).
  	Added non_eal_configure to testpmd application.
	Function maintain the same functionality as rte_eal_configure but
	for non-eal arguments. 
  	Added config JSON feature to testpmd last patch from patchset contain
	example showing use of .json configuration files.

  lib cfgfile:
  	Rework of add_section(), add_entry() new implementation
  	New members allocated_entries/sections, free_entries/sections
	in rte_cfgfile structure, change in array of pointers
	**sections, **entries instead of *sections[], *entries[]
  	Add  set_entry() to update/overwrite already existing entry in cfgfile
	struct
  	Add save() function to save on disc cfgfile structure in INI format
  	Rework of existing load() function  simplifying the code
  	Add unit test realloc_sections() in TEST app for testing realloc/malloc
	of new API functions, add test for save() function

Jacek Piasecki (5):
  cfgfile: remove EAL dependency
  cfgfile: change existing API functions
  cfgfile: add new functions to API
  cfgfile: rework of load function
  test/cfgfile: add new unit test

 lib/Makefile                                     |   3 +-
 lib/librte_cfgfile/Makefile                      |   1 +
 lib/librte_cfgfile/rte_cfgfile.c                 | 417 ++++++++++++++---------
 lib/librte_cfgfile/rte_cfgfile.h                 |  82 ++++-
 lib/librte_cfgfile/rte_cfgfile_version.map       |  11 +
 test/test/test_cfgfile.c                         |  40 +++
 test/test/test_cfgfiles/etc/realloc_sections.ini | 128 +++++++
 7 files changed, 514 insertions(+), 168 deletions(-)
 create mode 100644 test/test/test_cfgfiles/etc/realloc_sections.ini
  
Kuba Kozak July 10, 2017, 12:51 p.m. UTC | #3
This patchset introduce a mechanism for running dpdk application with 
parameters provided by configuration file.

A new API for EAL takes a config file data type - either loaded from
file, or built up programmatically in the application - and extracts
DPDK parameters from it to be used when eal init is called. 
This allows apps to have an alternative method to configure EAL,
other than via command-line parameters.

Reworked applications are used to demonstrate the new eal API.
If a --cfgfile-path <path> option is passed into command line non
EAL section, then the file is loaded and used by app. If a file
called config.ini is present in current working directory, and
no --cfgfile-path option is passed in, config.ini file will be
loaded and used by app.

Patch "app/testpmd: add parse options from JSON cfg file" 
demonstrates the usage of JSON instead of INI file format. 
JSON file can be called the same way as above, 
through --cfgfile-path <path> argument.
---
this patch depends on:
"Rework cfgfile API to enable apps config file support"

v4:
 Code optimalisation in parse_vdev_devices() function.
 Moved some functions from librte_eal/bsdapp and librte_eal/linuxapp
 to the librte_eal/common.
 Bug fixes.

v3: 
 split one patchset into two distinct patchsets:
 1. cfgfile library and TEST app changes
 2. EAL changes and examples (this patchset depends on cfgfile)

v2:
  lib eal:
	Rework of rte_eal_configure(struct rte_cfgfile *cfg, char *prgname).
	Now this function load data from cfg structure and did initial
	initialization of EAL arguments. Vdev argument are stored in different
	subsections eg. DPDK.vdev0, DPDK.vdev1 etc. After execution of this
	function it is necessary to call rte_eal_init to complete EAL
	initialization. There is no more merging arguments from different
	sources (cfg file and command line).
  	Added non_eal_configure to testpmd application.
	Function maintain the same functionality as rte_eal_configure but
	for non-eal arguments. 
  	Added config JSON feature to testpmd last patch from patchset contain
	example showing use of .json configuration files.

  lib cfgfile:
  	Rework of add_section(), add_entry() new implementation
  	New members allocated_entries/sections, free_entries/sections
	in rte_cfgfile structure, change in array of pointers
	**sections, **entries instead of *sections[], *entries[]
  	Add  set_entry() to update/overwrite already existing entry in cfgfile
	struct
  	Add save() function to save on disc cfgfile structure in INI format
  	Rework of existing load() function  simplifying the code
  	Add unit test realloc_sections() in TEST app for testing realloc/malloc
	of new API functions, add test for save() function

Kuba Kozak (3):
  eal: add functions parsing EAL arguments
  app/testpmd: add parse options from cfg file
  app/testpmd: add parse options from JSON cfg file

 app/test-pmd/Makefile                           |    6 +
 app/test-pmd/config.ini                         |   24 +
 app/test-pmd/config.json                        |   33 +
 app/test-pmd/parameters.c                       | 1181 +++++++++++++----------
 app/test-pmd/testpmd.c                          |  159 ++-
 app/test-pmd/testpmd.h                          |    3 +-
 config/common_base                              |    5 +
 lib/Makefile                                    |    3 +
 lib/librte_eal/bsdapp/eal/Makefile              |    4 +
 lib/librte_eal/bsdapp/eal/eal.c                 |  165 +++-
 lib/librte_eal/bsdapp/eal/rte_eal_version.map   |    1 +
 lib/librte_eal/common/eal_common_lcore.c        |    7 +
 lib/librte_eal/common/eal_common_options.c      |  106 ++
 lib/librte_eal/common/eal_options.h             |    3 +
 lib/librte_eal/common/include/rte_eal.h         |   20 +
 lib/librte_eal/linuxapp/eal/Makefile            |    3 +
 lib/librte_eal/linuxapp/eal/eal.c               |  265 +++--
 lib/librte_eal/linuxapp/eal/rte_eal_version.map |    1 +
 mk/rte.app.mk                                   |    2 +-
 19 files changed, 1349 insertions(+), 642 deletions(-)
 create mode 100644 app/test-pmd/config.ini
 create mode 100644 app/test-pmd/config.json
  
Thomas Monjalon July 10, 2017, 3:13 p.m. UTC | #4
The maintainer of librte_cfgfile is Cristian (+Cc),
please set him as recipient for next time.

10/07/2017 14:44, Jacek Piasecki:
> New API for cfgfile library allows to create a cfgfile at runtime, add new
> section, add entry in a section, update existing entry and save cfgfile
> structure to INI file - opens up the possibility to have applications
> dynamically build up a proper DPDK configuration, rather than
> having to have a pre-existing one. Due the new API functions, simplification
> of load() function was made. One new unit test to TEST app was added. It
> contains an example of a large INI file whose parsing requires multiple
> reallocation of memory.
> 
> ---
> v4:	
> 	Change members of structure cfgfile:
> 	- struct *sections[] to *sections
> 	- struct *entries[] to *entries
> 	- remove free_sections and free_entries
> 	Rework of existing cfgfile API functions to work with modified
> 	rte_cfgfile struct.
> 	Rework of malloc/realloc implementation due rte_cfgfile struct change,
> 	reducing mulitiple mallocs.
> 	Change return error codes for all library functions (errno.h)
> 	Checkpatch fixes
> v3: 
> 	split one patchset into two distinct patchsets:
> 	1. cfgfile library and TEST app changes
> 	2. EAL changes and examples (this patchset depends on cfgfile)
> v2:
>   lib eal:
>   	Rework of rte_eal_configure(struct rte_cfgfile *cfg, char *prgname).
> 	Now this function load data from cfg structure and did initial
> 	initialization of EAL arguments. Vdev argument are stored in different
> 	subsections eg. DPDK.vdev0, DPDK.vdev1 etc. After execution of this
> 	function it is necessary to call rte_eal_init to complete EAL
> 	initialization. There is no more merging arguments from different
> 	sources (cfg file and command line).
>   	Added non_eal_configure to testpmd application.
> 	Function maintain the same functionality as rte_eal_configure but
> 	for non-eal arguments. 
>   	Added config JSON feature to testpmd last patch from patchset contain
> 	example showing use of .json configuration files.
> 
>   lib cfgfile:
>   	Rework of add_section(), add_entry() new implementation
>   	New members allocated_entries/sections, free_entries/sections
> 	in rte_cfgfile structure, change in array of pointers
> 	**sections, **entries instead of *sections[], *entries[]
>   	Add  set_entry() to update/overwrite already existing entry in cfgfile
> 	struct
>   	Add save() function to save on disc cfgfile structure in INI format
>   	Rework of existing load() function  simplifying the code
>   	Add unit test realloc_sections() in TEST app for testing realloc/malloc
> 	of new API functions, add test for save() function
> 
> Jacek Piasecki (5):
>   cfgfile: remove EAL dependency
>   cfgfile: change existing API functions
>   cfgfile: add new functions to API
>   cfgfile: rework of load function
>   test/cfgfile: add new unit test
> 
>  lib/Makefile                                     |   3 +-
>  lib/librte_cfgfile/Makefile                      |   1 +
>  lib/librte_cfgfile/rte_cfgfile.c                 | 417 ++++++++++++++---------
>  lib/librte_cfgfile/rte_cfgfile.h                 |  82 ++++-
>  lib/librte_cfgfile/rte_cfgfile_version.map       |  11 +
>  test/test/test_cfgfile.c                         |  40 +++
>  test/test/test_cfgfiles/etc/realloc_sections.ini | 128 +++++++
>  7 files changed, 514 insertions(+), 168 deletions(-)
>  create mode 100644 test/test/test_cfgfiles/etc/realloc_sections.ini
> 
>
  
Thomas Monjalon July 20, 2017, 9:48 p.m. UTC | #5
10/07/2017 18:13, Thomas Monjalon:
> The maintainer of librte_cfgfile is Cristian (+Cc),
> please set him as recipient for next time.
> 
> 10/07/2017 14:44, Jacek Piasecki:
> > New API for cfgfile library allows to create a cfgfile at runtime, add new
> > section, add entry in a section, update existing entry and save cfgfile
> > structure to INI file - opens up the possibility to have applications
> > dynamically build up a proper DPDK configuration, rather than
> > having to have a pre-existing one. Due the new API functions, simplification
> > of load() function was made. One new unit test to TEST app was added. It
> > contains an example of a large INI file whose parsing requires multiple
> > reallocation of memory.

Still no review.
It is postponed to 17.11.
  

Patch

diff --git a/config/common_base b/config/common_base
index f6aafd1..c1d0e69 100644
--- a/config/common_base
+++ b/config/common_base
@@ -569,6 +569,7 @@  CONFIG_RTE_LIBRTE_TIMER_DEBUG=n
 # Compile librte_cfgfile
 #
 CONFIG_RTE_LIBRTE_CFGFILE=y
+CONFIG_RTE_LIBRTE_CFGFILE_DEBUG=n
 
 #
 # Compile librte_cmdline
diff --git a/lib/Makefile b/lib/Makefile
index 07e1fd0..fc5df3a 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -32,7 +32,11 @@ 
 include $(RTE_SDK)/mk/rte.vars.mk
 
 DIRS-y += librte_compat
+DIRS-$(CONFIG_RTE_LIBRTE_CFGFILE) += librte_cfgfile
 DIRS-$(CONFIG_RTE_LIBRTE_EAL) += librte_eal
+ifeq ($(CONFIG_RTE_LIBRTE_CFGFILE),y)
+DEPDIRS-librte_eal := librte_cfgfile
+endif
 DIRS-$(CONFIG_RTE_LIBRTE_RING) += librte_ring
 DEPDIRS-librte_ring := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_MEMPOOL) += librte_mempool
@@ -41,8 +45,6 @@  DIRS-$(CONFIG_RTE_LIBRTE_MBUF) += librte_mbuf
 DEPDIRS-librte_mbuf := librte_eal librte_mempool
 DIRS-$(CONFIG_RTE_LIBRTE_TIMER) += librte_timer
 DEPDIRS-librte_timer := librte_eal
-DIRS-$(CONFIG_RTE_LIBRTE_CFGFILE) += librte_cfgfile
-DEPDIRS-librte_cfgfile := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
 DEPDIRS-librte_cmdline := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index a0f9950..d70eefb 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -50,6 +50,10 @@  EXPORT_MAP := rte_eal_version.map
 
 LIBABIVER := 4
 
+ifeq ($(CONFIG_RTE_LIBRTE_CFGFILE),y)
+LDLIBS += -lrte_cfgfile
+endif
+
 # specific to bsdapp exec-env
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) := eal.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_memory.c
diff --git a/lib/librte_eal/bsdapp/eal/eal.c b/lib/librte_eal/bsdapp/eal/eal.c
index 05f0c1f..7baf848 100644
--- a/lib/librte_eal/bsdapp/eal/eal.c
+++ b/lib/librte_eal/bsdapp/eal/eal.c
@@ -73,6 +73,7 @@ 
 #include <rte_version.h>
 #include <rte_atomic.h>
 #include <malloc_heap.h>
+#include <rte_cfgfile.h>
 
 #include "eal_private.h"
 #include "eal_thread.h"
@@ -309,6 +310,18 @@  eal_get_hugepage_mem_size(void)
 
 /* Parse the arguments for --log-level only */
 static void
+eal_log_level_cfg(struct rte_cfgfile *cfg)
+{
+	const char *entry;
+
+	entry = rte_cfgfile_get_entry(cfg, "DPDK", OPT_LOG_LEVEL);
+	if (entry)
+		eal_parse_common_option(OPT_LOG_LEVEL_NUM, entry,
+				&internal_config);
+}
+
+/* Parse the arguments for --log-level only */
+static void
 eal_log_level_parse(int argc, char **argv)
 {
 	int opt;
@@ -347,6 +360,58 @@  eal_log_level_parse(int argc, char **argv)
 	optarg = old_optarg;
 }
 
+/* Parse single argument */
+static int
+eal_parse_option(int opt, char *optarg, int option_index, char *prgname)
+{
+	int ret;
+
+	/* getopt is not happy, stop right now */
+	if (opt == '?') {
+		eal_usage(prgname);
+		ret = -1;
+		goto out;
+	}
+
+	ret = eal_parse_common_option(opt, optarg, &internal_config);
+	/* common parser is not happy */
+	if (ret < 0) {
+		eal_usage(prgname);
+		ret = -1;
+		goto out;
+	}
+	/* common parser handled this option */
+	if (ret == 0)
+		return 0;
+
+	switch (opt) {
+	case 'h':
+		eal_usage(prgname);
+		exit(EXIT_SUCCESS);
+		break;
+
+	default:
+		if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
+			RTE_LOG(ERR, EAL, "Option %c is not supported "
+				"on FreeBSD\n", opt);
+		} else if (opt >= OPT_LONG_MIN_NUM &&
+			   opt < OPT_LONG_MAX_NUM) {
+			RTE_LOG(ERR, EAL, "Option %s is not supported "
+				"on FreeBSD\n",
+				eal_long_options[option_index].name);
+		} else {
+			RTE_LOG(ERR, EAL, "Option %d is not supported "
+				"on FreeBSD\n", opt);
+		}
+		eal_usage(prgname);
+		ret = -1;
+		goto out;
+	}
+	return 0;
+out:
+	return ret;
+}
+
 /* Parse the argument given in the command line of the application */
 static int
 eal_parse_args(int argc, char **argv)
@@ -367,45 +432,9 @@  eal_parse_args(int argc, char **argv)
 	while ((opt = getopt_long(argc, argvopt, eal_short_options,
 				  eal_long_options, &option_index)) != EOF) {
 
-		/* getopt is not happy, stop right now */
-		if (opt == '?') {
-			eal_usage(prgname);
-			ret = -1;
-			goto out;
-		}
-
-		ret = eal_parse_common_option(opt, optarg, &internal_config);
-		/* common parser is not happy */
-		if (ret < 0) {
-			eal_usage(prgname);
-			ret = -1;
-			goto out;
-		}
-		/* common parser handled this option */
-		if (ret == 0)
-			continue;
-
-		switch (opt) {
-		case 'h':
-			eal_usage(prgname);
-			exit(EXIT_SUCCESS);
-		default:
-			if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
-				RTE_LOG(ERR, EAL, "Option %c is not supported "
-					"on FreeBSD\n", opt);
-			} else if (opt >= OPT_LONG_MIN_NUM &&
-				   opt < OPT_LONG_MAX_NUM) {
-				RTE_LOG(ERR, EAL, "Option %s is not supported "
-					"on FreeBSD\n",
-					eal_long_options[option_index].name);
-			} else {
-				RTE_LOG(ERR, EAL, "Option %d is not supported "
-					"on FreeBSD\n", opt);
-			}
-			eal_usage(prgname);
-			ret = -1;
+		ret = eal_parse_option(opt, optarg, option_index, prgname);
+		if (ret < 0)
 			goto out;
-		}
 	}
 
 	if (eal_adjust_config(&internal_config) != 0) {
@@ -677,3 +706,147 @@  rte_eal_process_type(void)
 {
 	return rte_config.process_type;
 }
+
+#ifdef RTE_LIBRTE_CFGFILE
+#define vdev_buff_size		200
+#define sectionname_size	20
+static int
+parse_vdev_devices(struct rte_cfgfile *cfg)
+{
+	char sectionname[sectionname_size];
+	char buffer1[vdev_buff_size];
+	int vdev_nb = 0;
+	int n_entries;
+	int i;
+
+	/* ----------- parsing VDEVS */
+	snprintf(sectionname, sectionname_size, "DPDK.vdev%d", vdev_nb);
+
+	for (vdev_nb = 1; rte_cfgfile_has_section(cfg, sectionname);
+			vdev_nb++) {
+		n_entries = rte_cfgfile_section_num_entries(cfg, sectionname);
+
+		struct rte_cfgfile_entry entries[n_entries];
+
+		if (n_entries != rte_cfgfile_section_entries(cfg, sectionname,
+				entries, n_entries)) {
+			rte_eal_init_alert("Unexpected fault.");
+			rte_errno = EFAULT;
+			return -1;
+		}
+
+		buffer1[0] = 0;
+		for (i = 0; i < n_entries; i++) {
+			if (strlen(entries[i].value)) {
+
+				if ((strlen(buffer1) +
+						strlen(entries[i].name) +
+						strlen(entries[i].value) + 3)
+						>= vdev_buff_size)
+					goto buff_size_err;
+				strcat(buffer1, entries[i].name);
+				strcat(buffer1, "=");
+				strcat(buffer1, entries[i].value);
+			} else {
+				if ((strlen(buffer1) +
+						strlen(entries[i].name) + 2)
+						>= vdev_buff_size)
+					goto buff_size_err;
+				strcat(buffer1, entries[i].name);
+			}
+
+			if (i < (n_entries - 1))
+				strcat(buffer1, ",");
+		}
+
+		/* parsing vdev */
+		if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL,
+				buffer1) < 0) {
+			return -1;
+		}
+		snprintf(sectionname, sectionname_size, "DPDK.vdev%d", vdev_nb);
+	}
+	/* ----------- parsing VDEVS */
+	return 0;
+
+buff_size_err:
+	printf("parse_vdev_devices(): buffer size is to small\n");
+	return -1;
+}
+
+static void
+eal_getopt(const char *str, int *opt, int *option_index)
+{
+	int i;
+
+	*opt = '?';
+	*option_index = 0;
+
+	if (strlen(str) == 1) {
+		*opt = *str;
+		return;
+	}
+
+	for (i = 0; eal_long_options[i].name != NULL; i++) {
+		if (strcmp(str, eal_long_options[i].name) == 0) {
+			*opt = eal_long_options[i].val;
+			*option_index = i;
+			break;
+		}
+	}
+}
+
+int
+rte_eal_configure(struct rte_cfgfile *cfg, char *prgname)
+{
+	int n_entries;
+	int i;
+	int opt;
+	int option_index;
+
+	if (cfg == NULL) {
+		rte_errno = -EINVAL;
+		return -1;
+	}
+
+	n_entries = rte_cfgfile_section_num_entries(cfg, "DPDK");
+
+	if (n_entries < 1) {
+		printf("No DPDK section entries in cfgfile object\n");
+		return 0;
+	}
+
+	struct rte_cfgfile_entry entries[n_entries];
+
+	if (n_entries !=
+			rte_cfgfile_section_entries(cfg, "DPDK", entries,
+					n_entries)) {
+		rte_eal_init_alert("Unexpected fault.");
+		rte_errno = EFAULT;
+		return -1;
+	}
+
+	eal_reset_internal_config(&internal_config);
+
+	/* set log level as early as possible */
+	eal_log_level_cfg(cfg);
+
+	for (i = 0; i < n_entries; i++) {
+		eal_getopt(entries[i].name, &opt, &option_index);
+
+		if (eal_parse_option(opt, entries[i].value,
+				option_index, prgname) != 0) {
+			rte_eal_init_alert("Invalid config file arguments.");
+			rte_errno = EINVAL;
+			return -1;
+		}
+	}
+
+	if (parse_vdev_devices(cfg) < 0) {
+		rte_eal_init_alert("Couldn't parse vdevs");
+		rte_errno = ENOMEM;
+		return -1;
+	}
+	return 0;
+}
+#endif
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index 2e48a73..a939b03 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -193,3 +193,7 @@  DPDK_17.05 {
 	vfio_get_group_no;
 
 } DPDK_17.02;
+
+DPDK_17.08 {
+	rte_eal_configure;
+} DPDK_17.05;
diff --git a/lib/librte_eal/common/eal_common_cpuflags.c b/lib/librte_eal/common/eal_common_cpuflags.c
index 9a2d080..6a365f3 100644
--- a/lib/librte_eal/common/eal_common_cpuflags.c
+++ b/lib/librte_eal/common/eal_common_cpuflags.c
@@ -50,12 +50,18 @@  rte_cpu_check_supported(void)
 int
 rte_cpu_is_supported(void)
 {
+	static int run_once;
+	static int ret;
 	/* This is generated at compile-time by the build system */
 	static const enum rte_cpu_flag_t compile_time_flags[] = {
 			RTE_COMPILE_TIME_CPUFLAGS
 	};
 	unsigned count = RTE_DIM(compile_time_flags), i;
-	int ret;
+
+	/* No need to calculate this function again if we know the result */
+	if (run_once)
+		return ret;
+	run_once = 1;
 
 	for (i = 0; i < count; i++) {
 		ret = rte_cpu_get_flag_enabled(compile_time_flags[i]);
@@ -64,16 +70,16 @@  rte_cpu_is_supported(void)
 			fprintf(stderr,
 				"ERROR: CPU feature flag lookup failed with error %d\n",
 				ret);
-			return 0;
+			return ret = 0;
 		}
 		if (!ret) {
 			fprintf(stderr,
 			        "ERROR: This system does not support \"%s\".\n"
 			        "Please check that RTE_MACHINE is set correctly.\n",
 			        rte_cpu_get_flag_name(compile_time_flags[i]));
-			return 0;
+			return ret = 0;
 		}
 	}
 
-	return 1;
+	return ret = 1;
 }
diff --git a/lib/librte_eal/common/eal_common_lcore.c b/lib/librte_eal/common/eal_common_lcore.c
index 84fa0cb..ce3ef34 100644
--- a/lib/librte_eal/common/eal_common_lcore.c
+++ b/lib/librte_eal/common/eal_common_lcore.c
@@ -53,11 +53,18 @@ 
 int
 rte_eal_cpu_init(void)
 {
+	static int run_once;
+	static int ret;
 	/* pointer to global configuration */
 	struct rte_config *config = rte_eal_get_configuration();
 	unsigned lcore_id;
 	unsigned count = 0;
 
+	/* No need to calculate this function again if we know the result */
+	if (run_once)
+		return ret;
+	run_once = 1;
+
 	/*
 	 * Parse the maximum set of logical cores, detect the subset of running
 	 * ones and enable them by default.
@@ -91,7 +98,7 @@  rte_eal_cpu_init(void)
 				"RTE_MAX_NUMA_NODES (%d)\n",
 				lcore_config[lcore_id].socket_id,
 				RTE_MAX_NUMA_NODES);
-			return -1;
+			return ret = -1;
 #endif
 		}
 		RTE_LOG(DEBUG, EAL, "Detected lcore %u as "
@@ -107,5 +114,5 @@  rte_eal_cpu_init(void)
 		RTE_MAX_LCORE);
 	RTE_LOG(INFO, EAL, "Detected %u lcore(s)\n", config->lcore_count);
 
-	return 0;
+	return ret = 0;
 }
diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c
index f470195..138a27f 100644
--- a/lib/librte_eal/common/eal_common_options.c
+++ b/lib/librte_eal/common/eal_common_options.c
@@ -131,8 +131,13 @@  static int core_parsed;
 void
 eal_reset_internal_config(struct internal_config *internal_cfg)
 {
+	static int run_once;
 	int i;
 
+	if (run_once)
+		return;
+	run_once = 1;
+
 	internal_cfg->memory = 0;
 	internal_cfg->force_nrank = 0;
 	internal_cfg->force_nchannel = 0;
diff --git a/lib/librte_eal/common/include/rte_eal.h b/lib/librte_eal/common/include/rte_eal.h
index abf020b..e0705de 100644
--- a/lib/librte_eal/common/include/rte_eal.h
+++ b/lib/librte_eal/common/include/rte_eal.h
@@ -46,6 +46,8 @@ 
 #include <rte_per_lcore.h>
 #include <rte_config.h>
 
+struct rte_cfgfile; /* forward declaration of struct */
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -188,6 +190,25 @@  int rte_eal_iopl_init(void);
  */
 int rte_eal_init(int argc, char **argv);
 
+#ifdef RTE_LIBRTE_CFGFILE
+/**
+ * Initialize the Environment Abstraction Layer (EAL) using
+ * configuration structure
+ *
+ * @param cfg
+ *   pointer to config file structure.
+ *   If 0 - function free allocated for **cfg_argv memory
+ * @param prgname
+ *   pointer to string with execution path
+ *
+ * @return
+ *  - On success, return 0
+ *  - On failure, returns -1.
+ */
+int
+rte_eal_configure(struct rte_cfgfile *cfg, char *prgname);
+#endif
+
 /**
  * Check if a primary process is currently alive
  *
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 640afd0..656033e 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -50,6 +50,9 @@  LDLIBS += -ldl
 LDLIBS += -lpthread
 LDLIBS += -lgcc_s
 LDLIBS += -lrt
+ifeq ($(CONFIG_RTE_LIBRTE_CFGFILE),y)
+LDLIBS += -lrte_cfgfile
+endif
 
 # specific to linuxapp exec-env
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) := eal.c
diff --git a/lib/librte_eal/linuxapp/eal/eal.c b/lib/librte_eal/linuxapp/eal/eal.c
index 7c78f2d..f5973f4 100644
--- a/lib/librte_eal/linuxapp/eal/eal.c
+++ b/lib/librte_eal/linuxapp/eal/eal.c
@@ -78,6 +78,9 @@ 
 #include <rte_version.h>
 #include <rte_atomic.h>
 #include <malloc_heap.h>
+#ifdef RTE_LIBRTE_CFGFILE
+#include <rte_cfgfile.h>
+#endif
 
 #include "eal_private.h"
 #include "eal_thread.h"
@@ -478,6 +481,20 @@  eal_parse_vfio_intr(const char *mode)
 	return -1;
 }
 
+#ifdef RTE_LIBRTE_CFGFILE
+/* Parse the arguments for --log-level only */
+static void
+eal_log_level_cfg(struct rte_cfgfile *cfg)
+{
+	const char *entry;
+
+	entry = rte_cfgfile_get_entry(cfg, "DPDK", OPT_LOG_LEVEL);
+	if (entry)
+		eal_parse_common_option(OPT_LOG_LEVEL_NUM, entry,
+				&internal_config);
+}
+#endif
+
 /* Parse the arguments for --log-level only */
 static void
 eal_log_level_parse(int argc, char **argv)
@@ -515,119 +532,135 @@  eal_log_level_parse(int argc, char **argv)
 	optarg = old_optarg;
 }
 
-/* Parse the argument given in the command line of the application */
+/* Parse single argument */
 static int
-eal_parse_args(int argc, char **argv)
+eal_parse_option(int opt, char *optarg, int option_index, char *prgname)
 {
-	int opt, ret;
-	char **argvopt;
-	int option_index;
-	char *prgname = argv[0];
-	const int old_optind = optind;
-	const int old_optopt = optopt;
-	char * const old_optarg = optarg;
+	int ret;
 
-	argvopt = argv;
-	optind = 1;
+	/* getopt is not happy, stop right now */
+	if (opt == '?') {
+		eal_usage(prgname);
+		ret = -1;
+		goto out;
+	}
 
-	while ((opt = getopt_long(argc, argvopt, eal_short_options,
-				  eal_long_options, &option_index)) != EOF) {
+	ret = eal_parse_common_option(opt, optarg, &internal_config);
+	/* common parser is not happy */
+	if (ret < 0) {
+		eal_usage(prgname);
+		ret = -1;
+		goto out;
+	}
+	/* common parser handled this option */
+	if (ret == 0)
+		return 0;
 
-		/* getopt is not happy, stop right now */
-		if (opt == '?') {
+	switch (opt) {
+	case 'h':
+		eal_usage(prgname);
+		exit(EXIT_SUCCESS);
+		break;
+
+	/* long options */
+	case OPT_XEN_DOM0_NUM:
+#ifdef RTE_LIBRTE_XEN_DOM0
+		internal_config.xen_dom0_support = 1;
+		break;
+#else
+		RTE_LOG(ERR, EAL, "Can't support DPDK app "
+			"running on Dom0, please configure"
+			" RTE_LIBRTE_XEN_DOM0=y\n");
+		ret = -1;
+		goto out;
+#endif
+
+	case OPT_HUGE_DIR_NUM:
+		internal_config.hugepage_dir = optarg;
+		break;
+
+	case OPT_FILE_PREFIX_NUM:
+		internal_config.hugefile_prefix = optarg;
+		break;
+
+	case OPT_SOCKET_MEM_NUM:
+		if (eal_parse_socket_mem(optarg) < 0) {
+			RTE_LOG(ERR, EAL, "invalid parameters for --"
+					OPT_SOCKET_MEM "\n");
 			eal_usage(prgname);
 			ret = -1;
 			goto out;
 		}
+		break;
 
-		ret = eal_parse_common_option(opt, optarg, &internal_config);
-		/* common parser is not happy */
-		if (ret < 0) {
+	case OPT_BASE_VIRTADDR_NUM:
+		if (eal_parse_base_virtaddr(optarg) < 0) {
+			RTE_LOG(ERR, EAL, "invalid parameter for --"
+					OPT_BASE_VIRTADDR "\n");
 			eal_usage(prgname);
 			ret = -1;
 			goto out;
 		}
-		/* common parser handled this option */
-		if (ret == 0)
-			continue;
+		break;
 
-		switch (opt) {
-		case 'h':
+	case OPT_VFIO_INTR_NUM:
+		if (eal_parse_vfio_intr(optarg) < 0) {
+			RTE_LOG(ERR, EAL, "invalid parameters for --"
+					OPT_VFIO_INTR "\n");
 			eal_usage(prgname);
-			exit(EXIT_SUCCESS);
-
-		/* long options */
-		case OPT_XEN_DOM0_NUM:
-#ifdef RTE_LIBRTE_XEN_DOM0
-			internal_config.xen_dom0_support = 1;
-#else
-			RTE_LOG(ERR, EAL, "Can't support DPDK app "
-				"running on Dom0, please configure"
-				" RTE_LIBRTE_XEN_DOM0=y\n");
 			ret = -1;
 			goto out;
-#endif
-			break;
+		}
+		break;
 
-		case OPT_HUGE_DIR_NUM:
-			internal_config.hugepage_dir = optarg;
-			break;
+	case OPT_CREATE_UIO_DEV_NUM:
+		internal_config.create_uio_dev = 1;
+		break;
 
-		case OPT_FILE_PREFIX_NUM:
-			internal_config.hugefile_prefix = optarg;
-			break;
+	default:
+		if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
+			RTE_LOG(ERR, EAL, "Option %c is not supported "
+				"on Linux\n", opt);
+		} else if (opt >= OPT_LONG_MIN_NUM &&
+			   opt < OPT_LONG_MAX_NUM) {
+			RTE_LOG(ERR, EAL, "Option %s is not supported "
+				"on Linux\n",
+				eal_long_options[option_index].name);
+		} else {
+			RTE_LOG(ERR, EAL, "Option %d is not supported "
+				"on Linux\n", opt);
+		}
+		eal_usage(prgname);
+		ret = -1;
+		goto out;
+	}
 
-		case OPT_SOCKET_MEM_NUM:
-			if (eal_parse_socket_mem(optarg) < 0) {
-				RTE_LOG(ERR, EAL, "invalid parameters for --"
-						OPT_SOCKET_MEM "\n");
-				eal_usage(prgname);
-				ret = -1;
-				goto out;
-			}
-			break;
+	return 0;
+out:
+	return ret;
+}
 
-		case OPT_BASE_VIRTADDR_NUM:
-			if (eal_parse_base_virtaddr(optarg) < 0) {
-				RTE_LOG(ERR, EAL, "invalid parameter for --"
-						OPT_BASE_VIRTADDR "\n");
-				eal_usage(prgname);
-				ret = -1;
-				goto out;
-			}
-			break;
+/* Parse the argument given in the command line of the application */
+static int
+eal_parse_args(int argc, char **argv)
+{
+	int opt, ret;
+	char **argvopt;
+	int option_index;
+	char *prgname = argv[0];
+	const int old_optind = optind;
+	const int old_optopt = optopt;
+	char * const old_optarg = optarg;
 
-		case OPT_VFIO_INTR_NUM:
-			if (eal_parse_vfio_intr(optarg) < 0) {
-				RTE_LOG(ERR, EAL, "invalid parameters for --"
-						OPT_VFIO_INTR "\n");
-				eal_usage(prgname);
-				ret = -1;
-				goto out;
-			}
-			break;
+	argvopt = argv;
+	optind = 1;
 
-		case OPT_CREATE_UIO_DEV_NUM:
-			internal_config.create_uio_dev = 1;
-			break;
+	while ((opt = getopt_long(argc, argvopt, eal_short_options,
+				  eal_long_options, &option_index)) != EOF) {
 
-		default:
-			if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
-				RTE_LOG(ERR, EAL, "Option %c is not supported "
-					"on Linux\n", opt);
-			} else if (opt >= OPT_LONG_MIN_NUM &&
-				   opt < OPT_LONG_MAX_NUM) {
-				RTE_LOG(ERR, EAL, "Option %s is not supported "
-					"on Linux\n",
-					eal_long_options[option_index].name);
-			} else {
-				RTE_LOG(ERR, EAL, "Option %d is not supported "
-					"on Linux\n", opt);
-			}
-			eal_usage(prgname);
-			ret = -1;
+		ret = eal_parse_option(opt, optarg, option_index, prgname);
+		if (ret < 0)
 			goto out;
-		}
 	}
 
 	if (eal_adjust_config(&internal_config) != 0) {
@@ -995,3 +1028,149 @@  rte_eal_check_module(const char *module_name)
 	/* Module has been found */
 	return 1;
 }
+
+#ifdef RTE_LIBRTE_CFGFILE
+#define vdev_buff_size		200
+#define sectionname_size	20
+static int
+parse_vdev_devices(struct rte_cfgfile *cfg)
+{
+	char sectionname[sectionname_size];
+	char buffer1[vdev_buff_size];
+	int vdev_nb = 0;
+	int n_entries;
+
+	int i;
+
+	/* ----------- parsing VDEVS */
+	snprintf(sectionname, sectionname_size, "DPDK.vdev%d", vdev_nb);
+
+	for (vdev_nb = 1; rte_cfgfile_has_section(cfg, sectionname);
+			vdev_nb++) {
+		n_entries = rte_cfgfile_section_num_entries(cfg, sectionname);
+
+		struct rte_cfgfile_entry entries[n_entries];
+
+
+		if (n_entries != rte_cfgfile_section_entries(cfg, sectionname,
+				entries, n_entries)) {
+			rte_eal_init_alert("Unexpected fault.");
+			rte_errno = EFAULT;
+			return -1;
+		}
+
+		buffer1[0] = 0;
+		for (i = 0; i < n_entries; i++) {
+			if (strlen(entries[i].value)) {
+
+				if ((strlen(buffer1) +
+						strlen(entries[i].name) +
+						strlen(entries[i].value) + 3)
+						>= vdev_buff_size)
+					goto buff_size_err;
+				strcat(buffer1, entries[i].name);
+				strcat(buffer1, "=");
+				strcat(buffer1, entries[i].value);
+			} else {
+				if ((strlen(buffer1) +
+						strlen(entries[i].name) + 2)
+						>= vdev_buff_size)
+					goto buff_size_err;
+				strcat(buffer1, entries[i].name);
+			}
+
+			if (i < (n_entries - 1))
+				strcat(buffer1, ",");
+		}
+
+		/* parsing vdev */
+		if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL,
+				buffer1) < 0) {
+			return -1;
+		}
+		snprintf(sectionname, sectionname_size, "DPDK.vdev%d", vdev_nb);
+	}
+	/* ----------- parsing VDEVS */
+	return 0;
+
+buff_size_err:
+	printf("parse_vdev_devices(): buffer size is to small\n");
+	return -1;
+}
+
+static void
+eal_getopt(const char *str, int *opt, int *option_index)
+{
+	int i;
+
+	*opt = '?';
+	*option_index = 0;
+
+	if (strlen(str) == 1) {
+		*opt = *str;
+		return;
+	}
+
+	for (i = 0; eal_long_options[i].name != NULL; i++) {
+		if (strcmp(str, eal_long_options[i].name) == 0) {
+			*opt = eal_long_options[i].val;
+			*option_index = i;
+			break;
+		}
+	}
+}
+
+int
+rte_eal_configure(struct rte_cfgfile *cfg, char *prgname)
+{
+	int n_entries;
+	int i;
+	int opt;
+	int option_index;
+
+	if (cfg == NULL) {
+		rte_errno = -EINVAL;
+		return -1;
+	}
+
+	n_entries = rte_cfgfile_section_num_entries(cfg, "DPDK");
+
+	if (n_entries < 1) {
+		printf("No DPDK section entries in cfgfile object\n");
+		return 0;
+	}
+
+	struct rte_cfgfile_entry entries[n_entries];
+
+	if (n_entries !=
+			rte_cfgfile_section_entries(cfg, "DPDK", entries,
+					n_entries)) {
+		rte_eal_init_alert("Unexpected fault.");
+		rte_errno = EFAULT;
+		return -1;
+	}
+
+	eal_reset_internal_config(&internal_config);
+
+	/* set log level as early as possible */
+	eal_log_level_cfg(cfg);
+
+	for (i = 0; i < n_entries; i++) {
+		eal_getopt(entries[i].name, &opt, &option_index);
+
+		if (eal_parse_option(opt, entries[i].value,
+				option_index, prgname) != 0) {
+			rte_eal_init_alert("Invalid config file arguments.");
+			rte_errno = EINVAL;
+			return -1;
+		}
+	}
+
+	if (parse_vdev_devices(cfg) < 0) {
+		rte_eal_init_alert("Couldn't parse vdevs");
+		rte_errno = ENOMEM;
+		return -1;
+	}
+	return 0;
+}
+#endif
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index 670bab3..c93e6d9 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -198,3 +198,7 @@  DPDK_17.05 {
 	vfio_get_group_no;
 
 } DPDK_17.02;
+
+DPDK_17.08 {
+	rte_eal_configure;
+} DPDK_17.05;
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index bcaf1b3..642af92 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -80,7 +80,6 @@  _LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)          += -lrte_power
 
 _LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)          += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)            += -lrte_efd
-_LDLIBS-$(CONFIG_RTE_LIBRTE_CFGFILE)        += -lrte_cfgfile
 
 _LDLIBS-y += --whole-archive
 
@@ -96,6 +95,7 @@  _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
 _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING)   += -lrte_mempool_ring
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EAL)            += -lrte_eal
+_LDLIBS-$(CONFIG_RTE_LIBRTE_CFGFILE)        += -lrte_cfgfile
 _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE)        += -lrte_cmdline
 _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER)        += -lrte_reorder