* [dpdk-dev] [PATCH 0/3] Add support for using a config file for DPDK @ 2017-05-30 8:30 Jacek Piasecki 2017-05-30 8:30 ` [dpdk-dev] [PATCH 1/3] cfgfile: add new API functions Jacek Piasecki ` (2 more replies) 0 siblings, 3 replies; 70+ messages in thread From: Jacek Piasecki @ 2017-05-30 8:30 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, michalx.k.jastrzebski From: Michal Jastrzebski <michalx.k.jastrzebski@intel.com> This patch introduce a mechanism for running dpdk application with parameters provided by configuration file. New API for cfgfile library allows to create a cfgfile at runtime, add new section and add entry in a section - opens up the possibility to have applications dynamically build up a proper DPDK configuration, rather than having to have a pre-existing one. 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. Testpmd application is used to the 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. Currently *.ini file format is supported, but we would like to demonstrate in v2 how alternative config file formats could be used. Other work planned for v2: support for subsections – allowing to pass i.e. [DPDK.vdev0] and its parameters, cleanup to EAL API and testpmd. Jacek Piasecki (1): cfgfile: add new API functions Kuba Kozak (2): eal: add functions parsing EAL arguments app/testpmd: changed example to parse options from cfg file app/test-pmd/config.ini | 16 ++ app/test-pmd/parameters.c | 135 ++++++++++- app/test-pmd/testpmd.c | 51 +++- app/test-pmd/testpmd.h | 2 +- lib/Makefile | 6 +- lib/librte_cfgfile/Makefile | 1 + lib/librte_cfgfile/rte_cfgfile.c | 293 +++++++++++++---------- lib/librte_cfgfile/rte_cfgfile.h | 52 ++++ lib/librte_cfgfile/rte_cfgfile_version.map | 9 + lib/librte_eal/bsdapp/eal/Makefile | 4 + lib/librte_eal/bsdapp/eal/eal.c | 128 +++++++++- lib/librte_eal/bsdapp/eal/rte_eal_version.map | 5 + lib/librte_eal/common/include/rte_eal.h | 6 + lib/librte_eal/linuxapp/eal/Makefile | 3 + lib/librte_eal/linuxapp/eal/eal.c | 108 ++++++++- lib/librte_eal/linuxapp/eal/rte_eal_version.map | 4 + mk/rte.app.mk | 2 +- 17 files changed, 684 insertions(+), 141 deletions(-) create mode 100644 app/test-pmd/config.ini -- 1.7.9.5 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH 1/3] cfgfile: add new API functions 2017-05-30 8:30 [dpdk-dev] [PATCH 0/3] Add support for using a config file for DPDK Jacek Piasecki @ 2017-05-30 8:30 ` Jacek Piasecki 2017-05-31 14:20 ` Bruce Richardson 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 0/7] Add support for using a config file for DPDK Jacek Piasecki 2017-05-30 8:30 ` [dpdk-dev] [PATCH 2/3] eal: add functions parsing EAL arguments Jacek Piasecki 2017-05-30 8:30 ` [dpdk-dev] [PATCH 3/3] app/testpmd: changed example to parse options from cfg file Jacek Piasecki 2 siblings, 2 replies; 70+ messages in thread From: Jacek Piasecki @ 2017-05-30 8:30 UTC (permalink / raw) To: dev Cc: bruce.richardson, deepak.k.jain, michalx.k.jastrzebski, Jacek Piasecki Extend existing cfgfile library with providing new API functions: rte_cfgfile_create() - create new cfgfile object rte_cfgfile_add_section() - add new section to existing cfgfile object rte_cfgfile_add_entry() - add new entry to existing cfgfile object in specified section This modification allows to create a cfgfile on runtime and opens up the possibility to have applications dynamically build up a proper DPDK configuration, rather than having to have a pre-existing one. Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> --- lib/librte_cfgfile/Makefile | 1 + lib/librte_cfgfile/rte_cfgfile.c | 293 ++++++++++++++++------------ lib/librte_cfgfile/rte_cfgfile.h | 50 +++++ lib/librte_cfgfile/rte_cfgfile_version.map | 9 + 4 files changed, 227 insertions(+), 126 deletions(-) diff --git a/lib/librte_cfgfile/Makefile b/lib/librte_cfgfile/Makefile index 755ef11..0bee43e 100644 --- a/lib/librte_cfgfile/Makefile +++ b/lib/librte_cfgfile/Makefile @@ -38,6 +38,7 @@ LIB = librte_cfgfile.a CFLAGS += -O3 CFLAGS += $(WERROR_FLAGS) +CFLAGS += -I$(SRCDIR)/../librte_eal/common/include EXPORT_MAP := rte_cfgfile_version.map diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c index b54a523..457f8be 100644 --- a/lib/librte_cfgfile/rte_cfgfile.c +++ b/lib/librte_cfgfile/rte_cfgfile.c @@ -35,8 +35,8 @@ #include <stdlib.h> #include <string.h> #include <ctype.h> +#include <errno.h> #include <rte_common.h> -#include <rte_string_fns.h> #include "rte_cfgfile.h" @@ -144,10 +144,6 @@ struct rte_cfgfile * rte_cfgfile_load_with_params(const char *filename, int flags, const struct rte_cfgfile_parameters *params) { - int allocated_sections = CFG_ALLOC_SECTION_BATCH; - int allocated_entries = 0; - int curr_section = -1; - int curr_entry = -1; char buffer[CFG_NAME_LEN + CFG_VALUE_LEN + 4] = {0}; int lineno = 0; struct rte_cfgfile *cfg = NULL; @@ -159,28 +155,7 @@ struct rte_cfgfile * if (f == NULL) return NULL; - cfg = malloc(sizeof(*cfg) + sizeof(cfg->sections[0]) * - allocated_sections); - if (cfg == NULL) - goto error2; - - memset(cfg->sections, 0, sizeof(cfg->sections[0]) * allocated_sections); - - if (flags & CFG_FLAG_GLOBAL_SECTION) { - curr_section = 0; - allocated_entries = CFG_ALLOC_ENTRY_BATCH; - cfg->sections[curr_section] = malloc( - sizeof(*cfg->sections[0]) + - sizeof(cfg->sections[0]->entries[0]) * - allocated_entries); - if (cfg->sections[curr_section] == NULL) { - printf("Error - no memory for global section\n"); - goto error1; - } - - snprintf(cfg->sections[curr_section]->name, - sizeof(cfg->sections[0]->name), "GLOBAL"); - } + cfg = rte_cfgfile_create(flags); while (fgets(buffer, sizeof(buffer), f) != NULL) { char *pos = NULL; @@ -191,6 +166,7 @@ struct rte_cfgfile * "Check if line too long\n", lineno); goto error1; } + /* skip parsing if comment character found */ pos = memchr(buffer, params->comment_character, len); if (pos != NULL) { *pos = '\0'; @@ -198,6 +174,7 @@ struct rte_cfgfile * } len = _strip(buffer, len); + /* if not section line go to parse entry line */ if (buffer[0] != '[' && memchr(buffer, '=', len) == NULL) continue; @@ -212,121 +189,185 @@ struct rte_cfgfile * *end = '\0'; _strip(&buffer[1], end - &buffer[1]); - /* close off old section and add start new one */ - if (curr_section >= 0) - cfg->sections[curr_section]->num_entries = - curr_entry + 1; - curr_section++; - - /* resize overall struct if we don't have room for more - sections */ - if (curr_section == allocated_sections) { - allocated_sections += CFG_ALLOC_SECTION_BATCH; - struct rte_cfgfile *n_cfg = realloc(cfg, - sizeof(*cfg) + sizeof(cfg->sections[0]) - * allocated_sections); - if (n_cfg == NULL) { - curr_section--; - printf("Error - no more memory\n"); - goto error1; - } - cfg = n_cfg; - } - - /* allocate space for new section */ - allocated_entries = CFG_ALLOC_ENTRY_BATCH; - curr_entry = -1; - cfg->sections[curr_section] = malloc( - sizeof(*cfg->sections[0]) + - sizeof(cfg->sections[0]->entries[0]) * - allocated_entries); - if (cfg->sections[curr_section] == NULL) { - printf("Error - no more memory\n"); - goto error1; - } - - snprintf(cfg->sections[curr_section]->name, - sizeof(cfg->sections[0]->name), - "%s", &buffer[1]); + rte_cfgfile_add_section(&cfg, &buffer[1]); } else { /* value line */ - if (curr_section < 0) { - printf("Error line %d - value outside of" - "section\n", lineno); - goto error1; - } - - struct rte_cfgfile_section *sect = - cfg->sections[curr_section]; - int n; char *split[2] = {NULL}; - n = rte_strsplit(buffer, sizeof(buffer), split, 2, '='); - if (flags & CFG_FLAG_EMPTY_VALUES) { - if ((n < 1) || (n > 2)) { - printf("Error at line %d - cannot split string, n=%d\n", - lineno, n); - goto error1; - } - } else { - if (n != 2) { - printf("Error at line %d - cannot split string, n=%d\n", - lineno, n); - goto error1; - } - } - curr_entry++; - if (curr_entry == allocated_entries) { - allocated_entries += CFG_ALLOC_ENTRY_BATCH; - struct rte_cfgfile_section *n_sect = realloc( - sect, sizeof(*sect) + - sizeof(sect->entries[0]) * - allocated_entries); - if (n_sect == NULL) { - curr_entry--; - printf("Error - no more memory\n"); - goto error1; - } - sect = cfg->sections[curr_section] = n_sect; - } - - sect->entries[curr_entry] = malloc( - sizeof(*sect->entries[0])); - if (sect->entries[curr_entry] == NULL) { - printf("Error - no more memory\n"); + split[0] = buffer; + split[1] = memchr(buffer, '=', len); + if ((split[1] == NULL) && + !(flags & CFG_FLAG_EMPTY_VALUES)) { + printf("Error at line %d - cannot split " + "string\n", lineno); goto error1; } - - struct rte_cfgfile_entry *entry = sect->entries[ - curr_entry]; - snprintf(entry->name, sizeof(entry->name), "%s", - split[0]); - snprintf(entry->value, sizeof(entry->value), "%s", - split[1] ? split[1] : ""); - _strip(entry->name, strnlen(entry->name, - sizeof(entry->name))); - _strip(entry->value, strnlen(entry->value, - sizeof(entry->value))); + if (split[1] != NULL) { + *split[1] = '\0'; + split[1]++; + } + if (cfg->num_sections == 0) + goto error1; + rte_cfgfile_add_entry(cfg, + cfg->sections[cfg->num_sections - 1]->name, + split[0], split[1] ? split[1] : ""); } } fclose(f); - cfg->flags = flags; - cfg->num_sections = curr_section + 1; - /* curr_section will still be -1 if we have an empty file */ - if (curr_section >= 0) - cfg->sections[curr_section]->num_entries = curr_entry + 1; return cfg; - error1: - cfg->num_sections = curr_section + 1; - if (curr_section >= 0) - cfg->sections[curr_section]->num_entries = curr_entry + 1; rte_cfgfile_close(cfg); -error2: fclose(f); return NULL; } +struct rte_cfgfile * +rte_cfgfile_create(int flags) +{ + int allocated_sections = CFG_ALLOC_SECTION_BATCH; + struct rte_cfgfile *cfg = NULL; + + cfg = malloc(sizeof(*cfg) + sizeof(cfg->sections[0]) * + allocated_sections); + if (cfg == NULL) { + printf("Error - no memory to create cfgfile\n"); + return NULL; + } + + memset(cfg->sections, 0, sizeof(cfg->sections[0]) * allocated_sections); + + cfg->flags = flags; + cfg->num_sections = 0; + + if (flags & CFG_FLAG_GLOBAL_SECTION) + rte_cfgfile_add_section(&cfg, "GLOBAL"); + return cfg; +} + +int +rte_cfgfile_add_section(struct rte_cfgfile **cfgfile, const char *sectionname) +{ + struct rte_cfgfile *cfg = *cfgfile; + int curr_section = cfg->num_sections - 1; + int allocated_sections = 0; + + /* check if given section already exist */ + if (rte_cfgfile_has_section(cfg, sectionname) != 0) { + printf("Given section '%s' already exist\n", sectionname); + return 0; + } + /* calculate allocated sections from number of sections */ + if ((cfg->num_sections) != 0) + allocated_sections = (cfg->num_sections/ + CFG_ALLOC_SECTION_BATCH + 1) * CFG_ALLOC_SECTION_BATCH; + + curr_section++; + /* resize overall struct if we don't have room for more sections */ + if (curr_section == allocated_sections) { + allocated_sections += CFG_ALLOC_SECTION_BATCH; + struct rte_cfgfile *n_cfg = realloc(cfg, + sizeof(*cfg) + sizeof(cfg->sections[0]) + * allocated_sections); + if (n_cfg == NULL) + return -ENOMEM; + *cfgfile = n_cfg; + cfg = *cfgfile; + } + /* allocate space for new section */ + cfg->sections[curr_section] = malloc( + sizeof(*cfg->sections[0]) + + sizeof(cfg->sections[0]->entries[0]) * + CFG_ALLOC_ENTRY_BATCH); + + if (cfg->sections[curr_section] == NULL) + return -ENOMEM; + + snprintf(cfg->sections[curr_section]->name, + sizeof(cfg->sections[0]->name), "%s", sectionname); + + cfg->sections[curr_section]->num_entries = 0; + cfg->num_sections = curr_section + 1; + return 0; +} + +static int +_get_section_index(struct rte_cfgfile *cfgfile, const char *sectionname) { + int i; + + for (i = 0; i < cfgfile->num_sections; i++) { + if (strncmp(cfgfile->sections[i]->name, sectionname, + sizeof(cfgfile->sections[0]->name)) == 0) + return i; + } + return -1; +} + +static signed int +_add_entry(struct rte_cfgfile *cfgfile, const signed int curr_section, + const char *entryname, const char *entryvalue) +{ + int allocated_entries = 0; + int curr_entry = cfgfile->sections[curr_section]->num_entries - 1; + + /* calculate allocated entries from number of entries */ + if ((curr_entry + 1) != 0) + allocated_entries = ((curr_entry + 1)/ + CFG_ALLOC_ENTRY_BATCH + 1) * CFG_ALLOC_ENTRY_BATCH; + + curr_entry++; + struct rte_cfgfile_section *sect = cfgfile->sections[curr_section]; + + sect->entries[curr_entry] = malloc(sizeof(*sect->entries[0])); + + if (curr_entry == allocated_entries) { + allocated_entries += CFG_ALLOC_ENTRY_BATCH; + struct rte_cfgfile_section *n_sect = realloc( + sect, sizeof(*sect) + + sizeof(sect->entries[0]) * + allocated_entries); + if (n_sect == NULL) + return -ENOMEM; + sect = cfgfile->sections[curr_section] = n_sect; + } + + if (sect->entries[curr_entry] == NULL) { + cfgfile->num_sections = curr_section + 1; + if (curr_section >= 0) { + cfgfile->sections[curr_section]->num_entries = + curr_entry + 1; + return -ENOMEM; + } + } + + struct rte_cfgfile_entry *entry = sect->entries[curr_entry]; + + snprintf(entry->name, sizeof(entry->name), "%s", entryname); + snprintf(entry->value, sizeof(entry->value), "%s", entryvalue); + _strip(entry->name, strnlen(entry->name, sizeof(entry->name))); + _strip(entry->value, strnlen(entry->value, sizeof(entry->value))); + + cfgfile->sections[curr_section]->num_entries = curr_entry + 1; + + return 0; +}; + +int rte_cfgfile_add_entry(struct rte_cfgfile *cfgfile, const char *sectionname, + const char *entryname, const char *entryvalue) +{ + int curr_section; + + /* check if given entry in specified section already exist */ + if (rte_cfgfile_has_entry(cfgfile, sectionname, entryname) != 0) + return 0; + + /* search for section index by sectionname */ + curr_section = _get_section_index(cfgfile, sectionname); + + if (curr_section < 0) + return -EINVAL; + + return _add_entry(cfgfile, curr_section, entryname, entryvalue); +} int rte_cfgfile_close(struct rte_cfgfile *cfg) { diff --git a/lib/librte_cfgfile/rte_cfgfile.h b/lib/librte_cfgfile/rte_cfgfile.h index fa10d40..902ec69 100644 --- a/lib/librte_cfgfile/rte_cfgfile.h +++ b/lib/librte_cfgfile/rte_cfgfile.h @@ -121,6 +121,56 @@ struct rte_cfgfile *rte_cfgfile_load_with_params(const char *filename, int flags, const struct rte_cfgfile_parameters *params); /** + * Create new empty cfgfile instance. + * + * @param flags + * CFG_FLAG_GLOBAL_SECTION + * Indicates that the file supports key value entries before the first + * defined section. These entries can be accessed in the "GLOBAL" + * section. + * CFG_FLAG_EMPTY_VALUES + * Indicates that file supports key value entries where the value can + * be zero length (e.g., "key="). + * @return + * Handle to empty cfgfile instance on success, NULL on error + */ +struct rte_cfgfile *rte_cfgfile_create(int flags); + +/** + * Add section in cfgfile instance. + * + * @param cfgfile + * A pointer to a pointer to the cfgfile structure, this approach enables + * cfgfile object passing to and after required change + * returning from function. + * @param sectionname + * Section name which will be add to cfgfile. + * @return + * value 0 on success, value different than 0 otherwise + */ +int +rte_cfgfile_add_section(struct rte_cfgfile **cfgfile, const char *sectionname); + +/** + * Add entry in cfgfile instance. + * + * @param cfgfile + * A pointer to a pointer to the cfgfile structure, this approach enables + * cfgfile object passing to and after required change + * returning from function. + * @param sectionname + * Given section name to add an entry. + * @param entryname + * Entry name. + * @param entryvalue + * Entry value. + * @return + * value 0 on success, value different than 0 otherwise + */ +int rte_cfgfile_add_entry(struct rte_cfgfile *cfgfile, const char *sectionname, + const char *entryname, const char *entryvalue); + +/** * Get number of sections in config file * * @param cfg diff --git a/lib/librte_cfgfile/rte_cfgfile_version.map b/lib/librte_cfgfile/rte_cfgfile_version.map index 5fe60f7..6ed7a4e 100644 --- a/lib/librte_cfgfile/rte_cfgfile_version.map +++ b/lib/librte_cfgfile/rte_cfgfile_version.map @@ -27,3 +27,12 @@ DPDK_17.05 { rte_cfgfile_load_with_params; } DPDK_16.04; + +DPDK_17.08 { + global: + + rte_cfgfile_add_entry; + rte_cfgfile_add_section; + rte_cfgfile_create; + +} DPDK_17.05; \ No newline at end of file -- 1.7.9.5 ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH 1/3] cfgfile: add new API functions 2017-05-30 8:30 ` [dpdk-dev] [PATCH 1/3] cfgfile: add new API functions Jacek Piasecki @ 2017-05-31 14:20 ` Bruce Richardson 2017-05-31 14:22 ` Bruce Richardson 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 0/7] Add support for using a config file for DPDK Jacek Piasecki 1 sibling, 1 reply; 70+ messages in thread From: Bruce Richardson @ 2017-05-31 14:20 UTC (permalink / raw) To: Jacek Piasecki; +Cc: dev, deepak.k.jain, michalx.k.jastrzebski On Tue, May 30, 2017 at 10:30:35AM +0200, Jacek Piasecki wrote: > Extend existing cfgfile library with providing new API functions: > rte_cfgfile_create() - create new cfgfile object > rte_cfgfile_add_section() - add new section to existing cfgfile object > rte_cfgfile_add_entry() - add new entry to existing cfgfile object > in specified section > This modification allows to create a cfgfile on runtime and > opens up the possibility to have applications dynamically build up > a proper DPDK configuration, rather than having to have a pre-existing one. > > Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> Hi, There seems to be some additional work in this patch apart from what is described above, which may go into a separate patchset to improve readability. For example, the dependency on librte_eal (apart from one header) is removed, so those changes could go in a separate patch. Also, you might consider moving the rework of the load API to a separate patch, i.e. have one patch add the new APIs, and then a second patch rework existing load code to be simpler using those APIs. Other comments inline below. /Bruce > --- > lib/librte_cfgfile/Makefile | 1 + > lib/librte_cfgfile/rte_cfgfile.c | 293 ++++++++++++++++------------ > lib/librte_cfgfile/rte_cfgfile.h | 50 +++++ > lib/librte_cfgfile/rte_cfgfile_version.map | 9 + > 4 files changed, 227 insertions(+), 126 deletions(-) > <snip> > > +struct rte_cfgfile * > +rte_cfgfile_create(int flags) > +{ > + int allocated_sections = CFG_ALLOC_SECTION_BATCH; > + struct rte_cfgfile *cfg = NULL; > + > + cfg = malloc(sizeof(*cfg) + sizeof(cfg->sections[0]) * > + allocated_sections); > + if (cfg == NULL) { > + printf("Error - no memory to create cfgfile\n"); > + return NULL; > + } > + > + memset(cfg->sections, 0, sizeof(cfg->sections[0]) * allocated_sections); > + > + cfg->flags = flags; > + cfg->num_sections = 0; > + > + if (flags & CFG_FLAG_GLOBAL_SECTION) > + rte_cfgfile_add_section(&cfg, "GLOBAL"); > + return cfg; > +} > + > +int > +rte_cfgfile_add_section(struct rte_cfgfile **cfgfile, const char *sectionname) > +{ > + struct rte_cfgfile *cfg = *cfgfile; > + int curr_section = cfg->num_sections - 1; Consider removing this variable, I don't know if it's neccessary. It certainly shouldn't be assigned here using "- 1" and then incremented unconditionally later on. Throughout the function cfg->num_sections can be used instead. > + int allocated_sections = 0; > + > + /* check if given section already exist */ > + if (rte_cfgfile_has_section(cfg, sectionname) != 0) { > + printf("Given section '%s' already exist\n", sectionname); > + return 0; I think this should return an error code, -EEXIST. However, I believe we have support for multiple sections with the same name - see rte_cfgfile_section_entries_by_entries - so this check will break that support. > + } > + /* calculate allocated sections from number of sections */ > + if ((cfg->num_sections) != 0) > + allocated_sections = (cfg->num_sections/ > + CFG_ALLOC_SECTION_BATCH + 1) * CFG_ALLOC_SECTION_BATCH; > + Rather than compute this value each time, just add a field to the structure indicating how many are allocated. It should be less error prone. > + curr_section++; > + /* resize overall struct if we don't have room for more sections */ > + if (curr_section == allocated_sections) { > + allocated_sections += CFG_ALLOC_SECTION_BATCH; > + struct rte_cfgfile *n_cfg = realloc(cfg, > + sizeof(*cfg) + sizeof(cfg->sections[0]) > + * allocated_sections); > + if (n_cfg == NULL) > + return -ENOMEM; > + *cfgfile = n_cfg; > + cfg = *cfgfile; We should change the definition of rte_config structure to have a pointer to the sections, rather than having them tacked on at the end. This would mean that you could just realloc the sections themselves, not the whole structure. It therefore means that the function can take a regular struct ptr param, rather than a ptr to struct ptr. > + } > + /* allocate space for new section */ > + cfg->sections[curr_section] = malloc( > + sizeof(*cfg->sections[0]) + > + sizeof(cfg->sections[0]->entries[0]) * > + CFG_ALLOC_ENTRY_BATCH); > + > + if (cfg->sections[curr_section] == NULL) > + return -ENOMEM; > + > + snprintf(cfg->sections[curr_section]->name, > + sizeof(cfg->sections[0]->name), "%s", sectionname); > + > + cfg->sections[curr_section]->num_entries = 0; > + cfg->num_sections = curr_section + 1; Don't need to use curr_section here, just do cfg->num_sections++; cfg->num_sections++; > + return 0; > +} > + > +static int > +_get_section_index(struct rte_cfgfile *cfgfile, const char *sectionname) { > + int i; > + > + for (i = 0; i < cfgfile->num_sections; i++) { > + if (strncmp(cfgfile->sections[i]->name, sectionname, > + sizeof(cfgfile->sections[0]->name)) == 0) > + return i; > + } > + return -1; > +} This shouldn't be necessary, as we can use existing _get_section() function instead. [Or else make one use the other] > + > +static signed int > +_add_entry(struct rte_cfgfile *cfgfile, const signed int curr_section, > + const char *entryname, const char *entryvalue) > +{ > + int allocated_entries = 0; > + int curr_entry = cfgfile->sections[curr_section]->num_entries - 1; > + > + /* calculate allocated entries from number of entries */ > + if ((curr_entry + 1) != 0) > + allocated_entries = ((curr_entry + 1)/ > + CFG_ALLOC_ENTRY_BATCH + 1) * CFG_ALLOC_ENTRY_BATCH; > + As with the add_section, we don't need a curr_entry variable, and also add a new struct member to track the number of allocated elements. > + curr_entry++; > + struct rte_cfgfile_section *sect = cfgfile->sections[curr_section]; > + > + sect->entries[curr_entry] = malloc(sizeof(*sect->entries[0])); > + > + if (curr_entry == allocated_entries) { > + allocated_entries += CFG_ALLOC_ENTRY_BATCH; > + struct rte_cfgfile_section *n_sect = realloc( > + sect, sizeof(*sect) + > + sizeof(sect->entries[0]) * > + allocated_entries); > + if (n_sect == NULL) > + return -ENOMEM; > + sect = cfgfile->sections[curr_section] = n_sect; > + } > + > + if (sect->entries[curr_entry] == NULL) { > + cfgfile->num_sections = curr_section + 1; > + if (curr_section >= 0) { > + cfgfile->sections[curr_section]->num_entries = > + curr_entry + 1; > + return -ENOMEM; > + } > + } > + Do we need to check for the existence of an entry with that name here? > + struct rte_cfgfile_entry *entry = sect->entries[curr_entry]; > + > + snprintf(entry->name, sizeof(entry->name), "%s", entryname); > + snprintf(entry->value, sizeof(entry->value), "%s", entryvalue); > + _strip(entry->name, strnlen(entry->name, sizeof(entry->name))); > + _strip(entry->value, strnlen(entry->value, sizeof(entry->value))); > + > + cfgfile->sections[curr_section]->num_entries = curr_entry + 1; > + > + return 0; > +}; > + > +int rte_cfgfile_add_entry(struct rte_cfgfile *cfgfile, const char *sectionname, > + const char *entryname, const char *entryvalue) > +{ > + int curr_section; > + > + /* check if given entry in specified section already exist */ > + if (rte_cfgfile_has_entry(cfgfile, sectionname, entryname) != 0) > + return 0; > + > + /* search for section index by sectionname */ > + curr_section = _get_section_index(cfgfile, sectionname); > + > + if (curr_section < 0) > + return -EINVAL; > + > + return _add_entry(cfgfile, curr_section, entryname, entryvalue); rename function to "add_section_entry", perhaps. If you use _get_section() function instead of the _get_section_index() one, you can potentially pass in the section by pointer and not pass in the cfgfile pointer at all. > +} > <snip> ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH 1/3] cfgfile: add new API functions 2017-05-31 14:20 ` Bruce Richardson @ 2017-05-31 14:22 ` Bruce Richardson 0 siblings, 0 replies; 70+ messages in thread From: Bruce Richardson @ 2017-05-31 14:22 UTC (permalink / raw) To: Jacek Piasecki; +Cc: dev, deepak.k.jain, michalx.k.jastrzebski On Wed, May 31, 2017 at 03:20:00PM +0100, Bruce Richardson wrote: > On Tue, May 30, 2017 at 10:30:35AM +0200, Jacek Piasecki wrote: > > Extend existing cfgfile library with providing new API functions: > > rte_cfgfile_create() - create new cfgfile object > > rte_cfgfile_add_section() - add new section to existing cfgfile object > > rte_cfgfile_add_entry() - add new entry to existing cfgfile object > > in specified section > > This modification allows to create a cfgfile on runtime and > > opens up the possibility to have applications dynamically build up > > a proper DPDK configuration, rather than having to have a pre-existing one. > > > > Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> > > Hi, > > There seems to be some additional work in this patch apart from what is > described above, which may go into a separate patchset to improve > readability. s/a separate patchset/separate patches/ > For example, the dependency on librte_eal (apart from one > header) is removed, so those changes could go in a separate patch. > Also, you might consider moving the rework of the load API to a separate > patch, i.e. have one patch add the new APIs, and then a second patch > rework existing load code to be simpler using those APIs. > ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v2 0/7] Add support for using a config file for DPDK 2017-05-30 8:30 ` [dpdk-dev] [PATCH 1/3] cfgfile: add new API functions Jacek Piasecki 2017-05-31 14:20 ` Bruce Richardson @ 2017-06-26 10:59 ` Jacek Piasecki 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 1/7] cfgfile: remove EAL dependency Jacek Piasecki ` (6 more replies) 1 sibling, 7 replies; 70+ messages in thread From: Jacek Piasecki @ 2017-06-26 10:59 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, Jacek Piasecki This patchset introduce a mechanism for running dpdk application with parameters provided by configuration file. New API for cfgfile library allows to create a cfgfile at runtime, add new section and add entry in a section - opens up the possibility to have applications dynamically build up a proper DPDK configuration, rather than having to have a pre-existing one. 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. Testpmd application is used to the 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. Last patch demonstrates the usage of JSON file format insted of config.ini JSON file can be called the same way as above, thru --cfgfile-path <path> --- 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 (3): cfgfile: remove EAL dependency cfgfile: add new functions to API test/cfgfile: add new unit test Kuba Kozak (4): cfgfile: rework of load function eal: add functions parsing EAL arguments app/testpmd: changed example to parse options from cfg file app/testpmd: add parse arguments from JSON config file app/test-pmd/Makefile | 6 + app/test-pmd/config.ini | 24 + app/test-pmd/config.json | 33 + app/test-pmd/parameters.c | 1193 +++++++++++++--------- app/test-pmd/testpmd.c | 159 ++- app/test-pmd/testpmd.h | 3 +- config/common_base | 6 + lib/Makefile | 6 +- lib/librte_cfgfile/Makefile | 1 + lib/librte_cfgfile/rte_cfgfile.c | 397 ++++--- lib/librte_cfgfile/rte_cfgfile.h | 76 ++ lib/librte_cfgfile/rte_cfgfile_version.map | 11 + 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 +- test/test/test_cfgfile.c | 40 + test/test/test_cfgfiles/etc/realloc_sections.ini | 128 +++ 25 files changed, 1983 insertions(+), 770 deletions(-) create mode 100644 app/test-pmd/config.ini create mode 100644 app/test-pmd/config.json create mode 100644 test/test/test_cfgfiles/etc/realloc_sections.ini -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v2 1/7] cfgfile: remove EAL dependency 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 0/7] Add support for using a config file for DPDK Jacek Piasecki @ 2017-06-26 10:59 ` Jacek Piasecki 2017-06-26 13:12 ` Dumitrescu, Cristian 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 0/4] Rework cfgfile API to enable apps config file support Jacek Piasecki 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 2/7] cfgfile: add new functions to API Jacek Piasecki ` (5 subsequent siblings) 6 siblings, 2 replies; 70+ messages in thread From: Jacek Piasecki @ 2017-06-26 10:59 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, Jacek Piasecki This patch removes the dependency to EAL in cfgfile library. Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> --- lib/librte_cfgfile/Makefile | 1 + lib/librte_cfgfile/rte_cfgfile.c | 29 +++++++++++++++++------------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/librte_cfgfile/Makefile b/lib/librte_cfgfile/Makefile index 755ef11..0bee43e 100644 --- a/lib/librte_cfgfile/Makefile +++ b/lib/librte_cfgfile/Makefile @@ -38,6 +38,7 @@ LIB = librte_cfgfile.a CFLAGS += -O3 CFLAGS += $(WERROR_FLAGS) +CFLAGS += -I$(SRCDIR)/../librte_eal/common/include EXPORT_MAP := rte_cfgfile_version.map diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c index b54a523..c6ae3e3 100644 --- a/lib/librte_cfgfile/rte_cfgfile.c +++ b/lib/librte_cfgfile/rte_cfgfile.c @@ -36,7 +36,6 @@ #include <string.h> #include <ctype.h> #include <rte_common.h> -#include <rte_string_fns.h> #include "rte_cfgfile.h" @@ -258,19 +257,25 @@ rte_cfgfile_load_with_params(const char *filename, int flags, struct rte_cfgfile_section *sect = cfg->sections[curr_section]; - int n; + char *split[2] = {NULL}; - n = rte_strsplit(buffer, sizeof(buffer), split, 2, '='); - if (flags & CFG_FLAG_EMPTY_VALUES) { - if ((n < 1) || (n > 2)) { - printf("Error at line %d - cannot split string, n=%d\n", - lineno, n); - goto error1; - } + split[0] = buffer; + split[1] = memchr(buffer, '=', len); + + /* when delimeter not found */ + if (split[1] == NULL) { + printf("Error at line %d - cannot " + "split string\n", lineno); + goto error1; } else { - if (n != 2) { - printf("Error at line %d - cannot split string, n=%d\n", - lineno, n); + /* when delimeter found */ + *split[1] = '\0'; + split[1]++; + + if (!(flags & CFG_FLAG_EMPTY_VALUES) && + (*split[1] == '\0')) { + printf("Error at line %d - cannot " + "split string\n", lineno); goto error1; } } -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v2 1/7] cfgfile: remove EAL dependency 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 1/7] cfgfile: remove EAL dependency Jacek Piasecki @ 2017-06-26 13:12 ` Dumitrescu, Cristian 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 0/4] Rework cfgfile API to enable apps config file support Jacek Piasecki 1 sibling, 0 replies; 70+ messages in thread From: Dumitrescu, Cristian @ 2017-06-26 13:12 UTC (permalink / raw) To: Piasecki, JacekX, dev; +Cc: Richardson, Bruce, Jain, Deepak K, Piasecki, JacekX > -----Original Message----- > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jacek Piasecki > Sent: Monday, June 26, 2017 11:59 AM > To: dev@dpdk.org > Cc: Richardson, Bruce <bruce.richardson@intel.com>; Jain, Deepak K > <deepak.k.jain@intel.com>; Piasecki, JacekX <jacekx.piasecki@intel.com> > Subject: [dpdk-dev] [PATCH v2 1/7] cfgfile: remove EAL dependency > > This patch removes the dependency to EAL in cfgfile library. > > Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> > --- > lib/librte_cfgfile/Makefile | 1 + > lib/librte_cfgfile/rte_cfgfile.c | 29 +++++++++++++++++------------ > 2 files changed, 18 insertions(+), 12 deletions(-) > > diff --git a/lib/librte_cfgfile/Makefile b/lib/librte_cfgfile/Makefile > index 755ef11..0bee43e 100644 > --- a/lib/librte_cfgfile/Makefile > +++ b/lib/librte_cfgfile/Makefile > @@ -38,6 +38,7 @@ LIB = librte_cfgfile.a > > CFLAGS += -O3 > CFLAGS += $(WERROR_FLAGS) > +CFLAGS += -I$(SRCDIR)/../librte_eal/common/include > > EXPORT_MAP := rte_cfgfile_version.map > > diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c > index b54a523..c6ae3e3 100644 > --- a/lib/librte_cfgfile/rte_cfgfile.c > +++ b/lib/librte_cfgfile/rte_cfgfile.c > @@ -36,7 +36,6 @@ > #include <string.h> > #include <ctype.h> > #include <rte_common.h> > -#include <rte_string_fns.h> > > #include "rte_cfgfile.h" > > @@ -258,19 +257,25 @@ rte_cfgfile_load_with_params(const char > *filename, int flags, > > struct rte_cfgfile_section *sect = > cfg->sections[curr_section]; > - int n; > + > char *split[2] = {NULL}; > - n = rte_strsplit(buffer, sizeof(buffer), split, 2, '='); > - if (flags & CFG_FLAG_EMPTY_VALUES) { > - if ((n < 1) || (n > 2)) { > - printf("Error at line %d - cannot split > string, n=%d\n", > - lineno, n); > - goto error1; > - } > + split[0] = buffer; > + split[1] = memchr(buffer, '=', len); > + > + /* when delimeter not found */ > + if (split[1] == NULL) { > + printf("Error at line %d - cannot " > + "split string\n", lineno); > + goto error1; > } else { > - if (n != 2) { > - printf("Error at line %d - cannot split > string, n=%d\n", > - lineno, n); > + /* when delimeter found */ > + *split[1] = '\0'; > + split[1]++; > + > + if (!(flags & CFG_FLAG_EMPTY_VALUES) && > + (*split[1] == '\0')) { > + printf("Error at line %d - cannot " > + "split string\n", lineno); > goto error1; > } > } > -- > 2.7.4 Please separate the cfg file functionality from the eal functionality into distinct patch sets. ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v3 0/4] Rework cfgfile API to enable apps config file support 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 1/7] cfgfile: remove EAL dependency Jacek Piasecki 2017-06-26 13:12 ` Dumitrescu, Cristian @ 2017-06-27 10:26 ` Jacek Piasecki 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 1/4] cfgfile: remove EAL dependency Jacek Piasecki ` (4 more replies) 1 sibling, 5 replies; 70+ messages in thread From: Jacek Piasecki @ 2017-06-27 10:26 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, 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. --- 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 (3): cfgfile: remove EAL dependency cfgfile: add new functions to API test/cfgfile: add new unit test Kuba Kozak (1): cfgfile: rework of load function lib/librte_cfgfile/Makefile | 1 + lib/librte_cfgfile/rte_cfgfile.c | 397 +++++++++++++++-------- lib/librte_cfgfile/rte_cfgfile.h | 76 +++++ lib/librte_cfgfile/rte_cfgfile_version.map | 11 + test/test/test_cfgfile.c | 40 +++ test/test/test_cfgfiles/etc/realloc_sections.ini | 128 ++++++++ 6 files changed, 514 insertions(+), 139 deletions(-) create mode 100644 test/test/test_cfgfiles/etc/realloc_sections.ini -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v3 1/4] cfgfile: remove EAL dependency 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 0/4] Rework cfgfile API to enable apps config file support Jacek Piasecki @ 2017-06-27 10:26 ` Jacek Piasecki 2017-06-30 9:44 ` Bruce Richardson 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 2/4] cfgfile: add new functions to API Jacek Piasecki ` (3 subsequent siblings) 4 siblings, 1 reply; 70+ messages in thread From: Jacek Piasecki @ 2017-06-27 10:26 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, Jacek Piasecki This patch removes the dependency to EAL in cfgfile library. Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> --- lib/librte_cfgfile/Makefile | 1 + lib/librte_cfgfile/rte_cfgfile.c | 29 +++++++++++++++++------------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/librte_cfgfile/Makefile b/lib/librte_cfgfile/Makefile index 755ef11..0bee43e 100644 --- a/lib/librte_cfgfile/Makefile +++ b/lib/librte_cfgfile/Makefile @@ -38,6 +38,7 @@ LIB = librte_cfgfile.a CFLAGS += -O3 CFLAGS += $(WERROR_FLAGS) +CFLAGS += -I$(SRCDIR)/../librte_eal/common/include EXPORT_MAP := rte_cfgfile_version.map diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c index b54a523..c6ae3e3 100644 --- a/lib/librte_cfgfile/rte_cfgfile.c +++ b/lib/librte_cfgfile/rte_cfgfile.c @@ -36,7 +36,6 @@ #include <string.h> #include <ctype.h> #include <rte_common.h> -#include <rte_string_fns.h> #include "rte_cfgfile.h" @@ -258,19 +257,25 @@ rte_cfgfile_load_with_params(const char *filename, int flags, struct rte_cfgfile_section *sect = cfg->sections[curr_section]; - int n; + char *split[2] = {NULL}; - n = rte_strsplit(buffer, sizeof(buffer), split, 2, '='); - if (flags & CFG_FLAG_EMPTY_VALUES) { - if ((n < 1) || (n > 2)) { - printf("Error at line %d - cannot split string, n=%d\n", - lineno, n); - goto error1; - } + split[0] = buffer; + split[1] = memchr(buffer, '=', len); + + /* when delimeter not found */ + if (split[1] == NULL) { + printf("Error at line %d - cannot " + "split string\n", lineno); + goto error1; } else { - if (n != 2) { - printf("Error at line %d - cannot split string, n=%d\n", - lineno, n); + /* when delimeter found */ + *split[1] = '\0'; + split[1]++; + + if (!(flags & CFG_FLAG_EMPTY_VALUES) && + (*split[1] == '\0')) { + printf("Error at line %d - cannot " + "split string\n", lineno); goto error1; } } -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v3 1/4] cfgfile: remove EAL dependency 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 1/4] cfgfile: remove EAL dependency Jacek Piasecki @ 2017-06-30 9:44 ` Bruce Richardson 2017-06-30 11:16 ` Bruce Richardson 0 siblings, 1 reply; 70+ messages in thread From: Bruce Richardson @ 2017-06-30 9:44 UTC (permalink / raw) To: Jacek Piasecki; +Cc: dev, deepak.k.jain On Tue, Jun 27, 2017 at 12:26:47PM +0200, Jacek Piasecki wrote: > This patch removes the dependency to EAL in cfgfile library. > > Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> > --- > lib/librte_cfgfile/Makefile | 1 + > lib/librte_cfgfile/rte_cfgfile.c | 29 +++++++++++++++++------------ > 2 files changed, 18 insertions(+), 12 deletions(-) > > diff --git a/lib/librte_cfgfile/Makefile b/lib/librte_cfgfile/Makefile > index 755ef11..0bee43e 100644 > --- a/lib/librte_cfgfile/Makefile > +++ b/lib/librte_cfgfile/Makefile > @@ -38,6 +38,7 @@ LIB = librte_cfgfile.a > > CFLAGS += -O3 > CFLAGS += $(WERROR_FLAGS) > +CFLAGS += -I$(SRCDIR)/../librte_eal/common/include > > EXPORT_MAP := rte_cfgfile_version.map > > diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c > index b54a523..c6ae3e3 100644 > --- a/lib/librte_cfgfile/rte_cfgfile.c > +++ b/lib/librte_cfgfile/rte_cfgfile.c > @@ -36,7 +36,6 @@ > #include <string.h> > #include <ctype.h> > #include <rte_common.h> > -#include <rte_string_fns.h> > > #include "rte_cfgfile.h" > > @@ -258,19 +257,25 @@ rte_cfgfile_load_with_params(const char *filename, int flags, > > struct rte_cfgfile_section *sect = > cfg->sections[curr_section]; > - int n; > + > char *split[2] = {NULL}; > - n = rte_strsplit(buffer, sizeof(buffer), split, 2, '='); > - if (flags & CFG_FLAG_EMPTY_VALUES) { > - if ((n < 1) || (n > 2)) { > - printf("Error at line %d - cannot split string, n=%d\n", > - lineno, n); > - goto error1; > - } > + split[0] = buffer; > + split[1] = memchr(buffer, '=', len); > + > + /* when delimeter not found */ > + if (split[1] == NULL) { > + printf("Error at line %d - cannot " > + "split string\n", lineno); > + goto error1; This check for NULL is not needed, as earlier in the function we find the following: if (buffer[0] != '[' && memchr(buffer, '=', len) == NULL) continue; which means that there must be an "=" in buffer by the time we get to this line. > } else { FYI, you don't need an else after a goto. Save indentation where we can! :-) /Bruce ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v3 1/4] cfgfile: remove EAL dependency 2017-06-30 9:44 ` Bruce Richardson @ 2017-06-30 11:16 ` Bruce Richardson 0 siblings, 0 replies; 70+ messages in thread From: Bruce Richardson @ 2017-06-30 11:16 UTC (permalink / raw) To: Jacek Piasecki; +Cc: dev, deepak.k.jain On Fri, Jun 30, 2017 at 10:44:34AM +0100, Bruce Richardson wrote: > On Tue, Jun 27, 2017 at 12:26:47PM +0200, Jacek Piasecki wrote: > > This patch removes the dependency to EAL in cfgfile library. > > > > Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> > > --- > > lib/librte_cfgfile/Makefile | 1 + > > lib/librte_cfgfile/rte_cfgfile.c | 29 +++++++++++++++++------------ > > 2 files changed, 18 insertions(+), 12 deletions(-) > > > > diff --git a/lib/librte_cfgfile/Makefile b/lib/librte_cfgfile/Makefile > > index 755ef11..0bee43e 100644 > > --- a/lib/librte_cfgfile/Makefile > > +++ b/lib/librte_cfgfile/Makefile > > @@ -38,6 +38,7 @@ LIB = librte_cfgfile.a > > > > CFLAGS += -O3 > > CFLAGS += $(WERROR_FLAGS) > > +CFLAGS += -I$(SRCDIR)/../librte_eal/common/include > > > > EXPORT_MAP := rte_cfgfile_version.map > > > > diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c > > index b54a523..c6ae3e3 100644 > > --- a/lib/librte_cfgfile/rte_cfgfile.c > > +++ b/lib/librte_cfgfile/rte_cfgfile.c > > @@ -36,7 +36,6 @@ > > #include <string.h> > > #include <ctype.h> > > #include <rte_common.h> > > -#include <rte_string_fns.h> > > > > #include "rte_cfgfile.h" > > > > @@ -258,19 +257,25 @@ rte_cfgfile_load_with_params(const char *filename, int flags, > > > > struct rte_cfgfile_section *sect = > > cfg->sections[curr_section]; > > - int n; > > + > > char *split[2] = {NULL}; > > - n = rte_strsplit(buffer, sizeof(buffer), split, 2, '='); > > - if (flags & CFG_FLAG_EMPTY_VALUES) { > > - if ((n < 1) || (n > 2)) { > > - printf("Error at line %d - cannot split string, n=%d\n", > > - lineno, n); > > - goto error1; > > - } > > + split[0] = buffer; > > + split[1] = memchr(buffer, '=', len); > > + > > + /* when delimeter not found */ > > + if (split[1] == NULL) { > > + printf("Error at line %d - cannot " > > + "split string\n", lineno); > > + goto error1; > > This check for NULL is not needed, as earlier in the function we find > the following: > > if (buffer[0] != '[' && memchr(buffer, '=', len) == NULL) > continue; > > which means that there must be an "=" in buffer by the time we get to this > line. > > > } else { > > FYI, you don't need an else after a goto. Save indentation where we can! > :-) > I see now that a later patch removes this unneeded "if", but it might be better to move the removal back to this patch instead. /Bruce ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v3 2/4] cfgfile: add new functions to API 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 0/4] Rework cfgfile API to enable apps config file support Jacek Piasecki 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 1/4] cfgfile: remove EAL dependency Jacek Piasecki @ 2017-06-27 10:26 ` Jacek Piasecki 2017-06-30 9:55 ` Bruce Richardson 2017-06-30 10:28 ` Bruce Richardson 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 3/4] cfgfile: rework of load function Jacek Piasecki ` (2 subsequent siblings) 4 siblings, 2 replies; 70+ messages in thread From: Jacek Piasecki @ 2017-06-27 10:26 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, Jacek Piasecki Extend existing cfgfile library with providing new API functions: rte_cfgfile_create() - create new cfgfile object rte_cfgfile_add_section() - add new section to existing cfgfile object rte_cfgfile_add_entry() - add new entry to existing cfgfile object in specified section rte_cfgfile_set_entry() - update existing entry in cfgfile object rte_cfgfile_save() - save existing cfgfile object to INI file This modification allows to create a cfgfile on runtime and opens up the possibility to have applications dynamically build up a proper DPDK configuration, rather than having to have a pre-existing one. Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> --- lib/librte_cfgfile/rte_cfgfile.c | 249 +++++++++++++++++++++++++++-- lib/librte_cfgfile/rte_cfgfile.h | 76 +++++++++ lib/librte_cfgfile/rte_cfgfile_version.map | 11 ++ 3 files changed, 323 insertions(+), 13 deletions(-) diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c index c6ae3e3..518b6ab 100644 --- a/lib/librte_cfgfile/rte_cfgfile.c +++ b/lib/librte_cfgfile/rte_cfgfile.c @@ -35,6 +35,7 @@ #include <stdlib.h> #include <string.h> #include <ctype.h> +#include <errno.h> #include <rte_common.h> #include "rte_cfgfile.h" @@ -42,13 +43,17 @@ struct rte_cfgfile_section { char name[CFG_NAME_LEN]; int num_entries; - struct rte_cfgfile_entry *entries[0]; + int free_entries; + int allocated_entries; + struct rte_cfgfile_entry **entries; }; struct rte_cfgfile { int flags; int num_sections; - struct rte_cfgfile_section *sections[0]; + int free_sections; + int allocated_sections; + struct rte_cfgfile_section **sections; }; /** when we resize a file structure, how many extra entries @@ -104,6 +109,65 @@ _strip(char *str, unsigned len) return newlen; } +static struct rte_cfgfile_section * +_get_section(struct rte_cfgfile *cfg, const char *sectionname) +{ + int i; + + for (i = 0; i < cfg->num_sections; i++) { + if (strncmp(cfg->sections[i]->name, sectionname, + sizeof(cfg->sections[0]->name)) == 0) + return cfg->sections[i]; + } + return NULL; +} + +static int +_add_entry(struct rte_cfgfile_section *section, const char *entryname, + const char *entryvalue) +{ + int i; + + /* resize entry structure if we don't have room for more entries */ + if (section->free_entries == 0) { + + struct rte_cfgfile_entry **n_entries = + realloc(section->entries, + sizeof(section->entries[0]) * + ((section->allocated_entries) + + CFG_ALLOC_ENTRY_BATCH)); + + if (n_entries == NULL) + return -ENOMEM; + + section->entries = n_entries; + + for (i = section->allocated_entries; + i < (section->allocated_entries) + + CFG_ALLOC_ENTRY_BATCH; i++) { + section->entries[i] = + malloc(sizeof(struct rte_cfgfile_entry)); + + if (section->entries[i] == NULL) + return -ENOMEM; + } + section->allocated_entries += CFG_ALLOC_ENTRY_BATCH; + section->free_entries += CFG_ALLOC_ENTRY_BATCH; + } + + /* fill up entry fields with key name and value */ + struct rte_cfgfile_entry *curr_entry = + section->entries[section->num_entries]; + + snprintf(curr_entry->name, sizeof(curr_entry->name), "%s", entryname); + snprintf(curr_entry->value, sizeof(curr_entry->value), "%s", + entryvalue); + section->num_entries++; + section->free_entries--; + + return 0; +} + static int rte_cfgfile_check_params(const struct rte_cfgfile_parameters *params) { @@ -332,6 +396,176 @@ rte_cfgfile_load_with_params(const char *filename, int flags, return NULL; } +struct rte_cfgfile * +rte_cfgfile_create(int flags) +{ + int i, j; + struct rte_cfgfile *cfg = NULL; + + cfg = malloc(sizeof(*cfg)); + if (cfg == NULL) + return NULL; + + memset(cfg, 0, sizeof((*cfg))); + + cfg->flags = flags; + + /* allocate first batch of sections and entries */ + cfg->sections = malloc(sizeof(cfg->sections[0]) * + CFG_ALLOC_SECTION_BATCH); + if (cfg->sections == NULL) + return NULL; + + for (i = 0; i < CFG_ALLOC_SECTION_BATCH; i++) { + cfg->sections[i] = malloc(sizeof(struct rte_cfgfile_section)); + if (cfg->sections[i] == NULL) + return NULL; + + memset(cfg->sections[i], 0, + sizeof(struct rte_cfgfile_section)); + + cfg->sections[i]->entries = + malloc(sizeof(cfg->sections[i]->entries[0]) + * CFG_ALLOC_ENTRY_BATCH); + if (cfg->sections[i]->entries == NULL) + return NULL; + + for (j = 0; j < CFG_ALLOC_ENTRY_BATCH; j++) { + cfg->sections[i]->entries[j] = malloc(sizeof(struct + rte_cfgfile_entry)); + if (cfg->sections[i]->entries[j] == NULL) + return NULL; + } + cfg->sections[i]->allocated_entries = CFG_ALLOC_ENTRY_BATCH; + cfg->sections[i]->free_entries = CFG_ALLOC_ENTRY_BATCH; + } + cfg->allocated_sections = CFG_ALLOC_SECTION_BATCH; + cfg->free_sections = CFG_ALLOC_SECTION_BATCH; + + if (flags & CFG_FLAG_GLOBAL_SECTION) + rte_cfgfile_add_section(cfg, "GLOBAL"); + return cfg; +} + +int +rte_cfgfile_add_section(struct rte_cfgfile *cfg, const char *sectionname) +{ + int i; + /* resize overall struct if we don't have room for more sections */ + if (cfg->free_sections == 0) { + + struct rte_cfgfile_section **n_sections = + realloc(cfg->sections, + sizeof(cfg->sections[0]) * + ((cfg->allocated_sections) + + CFG_ALLOC_SECTION_BATCH)); + + if (n_sections == NULL) + return -ENOMEM; + + cfg->sections = n_sections; + + for (i = cfg->allocated_sections; + i < (cfg->allocated_sections) + + CFG_ALLOC_SECTION_BATCH; i++) { + cfg->sections[i] = + malloc(sizeof(struct rte_cfgfile_section)); + + if (cfg->sections[i] == NULL) + return -ENOMEM; + + memset(cfg->sections[i], 0, + sizeof(struct rte_cfgfile_section)); + } + cfg->allocated_sections += CFG_ALLOC_SECTION_BATCH; + cfg->free_sections += CFG_ALLOC_SECTION_BATCH; + } + + snprintf(cfg->sections[cfg->num_sections]->name, + sizeof(cfg->sections[0]->name), "%s", sectionname); + cfg->sections[cfg->num_sections]->num_entries = 0; + + cfg->num_sections++; + cfg->free_sections--; + + return 0; +} + +int rte_cfgfile_add_entry(struct rte_cfgfile *cfg, + const char *sectionname, const char *entryname, + const char *entryvalue) +{ + int ret; + + if (cfg == NULL) + return -EINVAL; + + if (rte_cfgfile_has_entry(cfg, sectionname, entryname) != 0) + return -EEXIST; + + /* search for section pointer by sectionname */ + struct rte_cfgfile_section *curr_section = _get_section(cfg, + sectionname); + if (curr_section == NULL) + return -EINVAL; + + ret = _add_entry(curr_section, entryname, entryvalue); + + return ret; +} + +int rte_cfgfile_set_entry(struct rte_cfgfile *cfg, const char *sectionname, + const char *entryname, const char *entryvalue) +{ + int i; + + if (cfg == NULL) + return -EINVAL; + + /* search for section pointer by sectionname */ + struct rte_cfgfile_section *curr_section = _get_section(cfg, + sectionname); + if (curr_section == NULL) + return -EINVAL; + + if (entryvalue == NULL) + entryvalue = ""; + + for (i = 0; i < curr_section->num_entries; i++) + if (!strcmp(curr_section->entries[i]->name, entryname)) { + strcpy(curr_section->entries[i]->value, entryvalue); + return 0; + } + return -1; +} + +int rte_cfgfile_save(struct rte_cfgfile *cfg, const char *filename) +{ + char buffer[CFG_NAME_LEN + CFG_VALUE_LEN + 4] = {0}; + int i, j; + + if ((cfg == NULL) || (filename == NULL)) + return -EINVAL; + + FILE *f = fopen(filename, "w"); + + if (f == NULL) + return -EINVAL; + + for (i = 0; i < cfg->num_sections; i++) { + snprintf(buffer, sizeof(buffer), "[%s]\n", + cfg->sections[i]->name); + fputs(buffer, f); + + for (j = 0; j < cfg->sections[i]->num_entries; j++) { + snprintf(buffer, sizeof(buffer), "%s=%s\n", + cfg->sections[i]->entries[j]->name, + cfg->sections[i]->entries[j]->value); + fputs(buffer, f); + } + } + return fclose(f); +} int rte_cfgfile_close(struct rte_cfgfile *cfg) { @@ -385,17 +619,6 @@ rte_cfgfile_sections(struct rte_cfgfile *cfg, char *sections[], return i; } -static const struct rte_cfgfile_section * -_get_section(struct rte_cfgfile *cfg, const char *sectionname) -{ - int i; - for (i = 0; i < cfg->num_sections; i++) { - if (strncmp(cfg->sections[i]->name, sectionname, - sizeof(cfg->sections[0]->name)) == 0) - return cfg->sections[i]; - } - return NULL; -} int rte_cfgfile_has_section(struct rte_cfgfile *cfg, const char *sectionname) diff --git a/lib/librte_cfgfile/rte_cfgfile.h b/lib/librte_cfgfile/rte_cfgfile.h index fa10d40..6245c7e 100644 --- a/lib/librte_cfgfile/rte_cfgfile.h +++ b/lib/librte_cfgfile/rte_cfgfile.h @@ -121,6 +121,82 @@ struct rte_cfgfile *rte_cfgfile_load_with_params(const char *filename, int flags, const struct rte_cfgfile_parameters *params); /** + * Create new cfgfile instance with empty sections and entries + * + * @param flags + * - CFG_FLAG_GLOBAL_SECTION + * Indicates that the file supports key value entries before the first + * defined section. These entries can be accessed in the "GLOBAL" + * section. + * - CFG_FLAG_EMPTY_VALUES + * Indicates that file supports key value entries where the value can + * be zero length (e.g., "key="). + * @return + * Handle to cfgfile instance on success, NULL otherwise + */ +struct rte_cfgfile *rte_cfgfile_create(int flags); + +/** + * Add section in cfgfile instance. + * + * @param cfg + * Pointer to the cfgfile structure. + * @param sectionname + * Section name which will be add to cfgfile. + * @return + * 0 on success, -ENOMEM if can't add section + */ +int +rte_cfgfile_add_section(struct rte_cfgfile *cfg, const char *sectionname); + +/** + * Add entry to specified section in cfgfile instance. + * + * @param cfg + * Pointer to the cfgfile structure. + * @param sectionname + * Given section name to add an entry. + * @param entryname + * Entry name to add. + * @entryvalue + * Entry value to add. + * @return + * 0 on success, -EEXIST if entry already exist, -EINVAL if bad argument + */ +int rte_cfgfile_add_entry(struct rte_cfgfile *cfg, + const char *sectionname, const char *entryname, + const char *entryvalue); + +/** + * Update value of specified entry name in given section in config file + * + * @param cfg + * Config file + * @param sectionname + * Section name + * @param entryname + * Entry name to look for the value change + * @param entryvalue + * New entry value. Can be also an empty string if CFG_FLAG_EMPTY_VALUES = 1 + * @return + * 0 on success, -EINVAL if bad argument + */ +int rte_cfgfile_set_entry(struct rte_cfgfile *cfg, const char *sectionname, + const char *entryname, const char *entryvalue); + +/** + * Save object cfgfile to file on disc + * + * @param cfg + * Config file structure + * @param filename + * File name to save data + * @return + * 0 on success, errno otherwise + */ +int rte_cfgfile_save(struct rte_cfgfile *cfg, const char *filename); + +/** * Get number of sections in config file * * @param cfg diff --git a/lib/librte_cfgfile/rte_cfgfile_version.map b/lib/librte_cfgfile/rte_cfgfile_version.map index 5fe60f7..de68ff6 100644 --- a/lib/librte_cfgfile/rte_cfgfile_version.map +++ b/lib/librte_cfgfile/rte_cfgfile_version.map @@ -27,3 +27,14 @@ DPDK_17.05 { rte_cfgfile_load_with_params; } DPDK_16.04; + +DPDK_17.08 { + global: + + rte_cfgfile_add_entry; + rte_cfgfile_add_section; + rte_cfgfile_create; + rte_cfgfile_save; + rte_cfgfile_set_entry; + +} DPDK_17.05; \ No newline at end of file -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v3 2/4] cfgfile: add new functions to API 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 2/4] cfgfile: add new functions to API Jacek Piasecki @ 2017-06-30 9:55 ` Bruce Richardson 2017-06-30 10:28 ` Bruce Richardson 1 sibling, 0 replies; 70+ messages in thread From: Bruce Richardson @ 2017-06-30 9:55 UTC (permalink / raw) To: Jacek Piasecki; +Cc: dev, deepak.k.jain On Tue, Jun 27, 2017 at 12:26:48PM +0200, Jacek Piasecki wrote: > Extend existing cfgfile library with providing new API functions: > > rte_cfgfile_create() - create new cfgfile object > rte_cfgfile_add_section() - add new section to existing cfgfile > object > rte_cfgfile_add_entry() - add new entry to existing cfgfile > object in specified section > rte_cfgfile_set_entry() - update existing entry in cfgfile object > rte_cfgfile_save() - save existing cfgfile object to INI file > > This modification allows to create a cfgfile on > runtime and opens up the possibility to have applications > dynamically build up a proper DPDK configuration, rather than having > to have a pre-existing one. > > Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> > --- > lib/librte_cfgfile/rte_cfgfile.c | 249 +++++++++++++++++++++++++++-- > lib/librte_cfgfile/rte_cfgfile.h | 76 +++++++++ > lib/librte_cfgfile/rte_cfgfile_version.map | 11 ++ > 3 files changed, 323 insertions(+), 13 deletions(-) > <snip> > +/** > + * Add entry to specified section in cfgfile instance. > + * > + * @param cfg > + * Pointer to the cfgfile structure. > + * @param sectionname > + * Given section name to add an entry. > + * @param entryname > + * Entry name to add. > + * @entryvalue missing "param" here. Building the docs throws an error on this. +/home/bruce/dpdk.org/lib/librte_cfgfile/rte_cfgfile.h:161: warning: Found unknown command `\entryvalue' +/home/bruce/dpdk.org/lib/librte_cfgfile/rte_cfgfile.h:166: warning: The following parameters of rte_cfgfile_add_entry(struct rte_cfgfile *cfg, const char *sectionname, const char *entryname, const char *entryvalue) are not documented: + parameter 'entryvalue' > + * Entry value to add. > + * @return > + * 0 on success, -EEXIST if entry already exist, -EINVAL if bad argument > + */ > +int rte_cfgfile_add_entry(struct rte_cfgfile *cfg, > + const char *sectionname, const char *entryname, > + const char *entryvalue); > + ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v3 2/4] cfgfile: add new functions to API 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 2/4] cfgfile: add new functions to API Jacek Piasecki 2017-06-30 9:55 ` Bruce Richardson @ 2017-06-30 10:28 ` Bruce Richardson 1 sibling, 0 replies; 70+ messages in thread From: Bruce Richardson @ 2017-06-30 10:28 UTC (permalink / raw) To: Jacek Piasecki; +Cc: dev, deepak.k.jain On Tue, Jun 27, 2017 at 12:26:48PM +0200, Jacek Piasecki wrote: > Extend existing cfgfile library with providing new API functions: > > rte_cfgfile_create() - create new cfgfile object > rte_cfgfile_add_section() - add new section to existing cfgfile > object > rte_cfgfile_add_entry() - add new entry to existing cfgfile > object in specified section > rte_cfgfile_set_entry() - update existing entry in cfgfile object > rte_cfgfile_save() - save existing cfgfile object to INI file > > This modification allows to create a cfgfile on > runtime and opens up the possibility to have applications > dynamically build up a proper DPDK configuration, rather than having > to have a pre-existing one. > > Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> Some comments inline below on the code. I also think you might want to split this patch into 2 or 3 to make review easier. For example: * Patch to add add_section and add_entry functions * Patch to add set_entry function * Patch to add create() and save functions /Bruce > --- > lib/librte_cfgfile/rte_cfgfile.c | 249 +++++++++++++++++++++++++++-- > lib/librte_cfgfile/rte_cfgfile.h | 76 +++++++++ > lib/librte_cfgfile/rte_cfgfile_version.map | 11 ++ > 3 files changed, 323 insertions(+), 13 deletions(-) > > diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c > index c6ae3e3..518b6ab 100644 > --- a/lib/librte_cfgfile/rte_cfgfile.c > +++ b/lib/librte_cfgfile/rte_cfgfile.c > @@ -35,6 +35,7 @@ > #include <stdlib.h> > #include <string.h> > #include <ctype.h> > +#include <errno.h> > #include <rte_common.h> > > #include "rte_cfgfile.h" > @@ -42,13 +43,17 @@ > struct rte_cfgfile_section { > char name[CFG_NAME_LEN]; > int num_entries; > - struct rte_cfgfile_entry *entries[0]; > + int free_entries; > + int allocated_entries; > + struct rte_cfgfile_entry **entries; > }; I'm not sure that we need to use an array of pointers here any more. It might work easier to just store the entries for each section in a single block, i.e. have the last member just: "struct rte_cfgfile_entry *entries;" Also, allocated_entries value seems unneeded, since it is always equal to num_entries + free_entries. The place where is seems to be used, when allocating new entries, free_entries == 0, so allocated_entries == num_entries, making allocated entries doubly-unneeded there. Another, possibly better, alternative might be to remove the "free_entries" variable. [It's possibly better as you don't need to do an increment and a decrement on adding an entry, but just do an increment] > > struct rte_cfgfile { > int flags; > int num_sections; > - struct rte_cfgfile_section *sections[0]; > + int free_sections; > + int allocated_sections; > + struct rte_cfgfile_section **sections; > }; As above: for the entries in a section, we should be ok putting all sections in a single array, rather than having an array of pointers, and we don't need both an allocated_sections variable and a free_sections one. > > /** when we resize a file structure, how many extra entries > @@ -104,6 +109,65 @@ _strip(char *str, unsigned len) > return newlen; > } > > +static struct rte_cfgfile_section * > +_get_section(struct rte_cfgfile *cfg, const char *sectionname) > +{ > + int i; > + > + for (i = 0; i < cfg->num_sections; i++) { > + if (strncmp(cfg->sections[i]->name, sectionname, > + sizeof(cfg->sections[0]->name)) == 0) > + return cfg->sections[i]; > + } > + return NULL; > +} > + > +static int > +_add_entry(struct rte_cfgfile_section *section, const char *entryname, > + const char *entryvalue) > +{ > + int i; > + > + /* resize entry structure if we don't have room for more entries */ > + if (section->free_entries == 0) { > + > + struct rte_cfgfile_entry **n_entries = > + realloc(section->entries, > + sizeof(section->entries[0]) * > + ((section->allocated_entries) + > + CFG_ALLOC_ENTRY_BATCH)); > + > + if (n_entries == NULL) > + return -ENOMEM; > + > + section->entries = n_entries; > + > + for (i = section->allocated_entries; > + i < (section->allocated_entries) + > + CFG_ALLOC_ENTRY_BATCH; i++) { > + section->entries[i] = > + malloc(sizeof(struct rte_cfgfile_entry)); > + > + if (section->entries[i] == NULL) > + return -ENOMEM; > + } Even if you keep the entries array as an array of pointers, you still don't need to loop here for malloc. Instead just malloc a single block for CFG_ALLOC_ENTRY_BATCH entries in one go, and set the pointers to point to values in that block. Too many malloc calls is fragmenting memory. > + section->allocated_entries += CFG_ALLOC_ENTRY_BATCH; > + section->free_entries += CFG_ALLOC_ENTRY_BATCH; > + } > + > + /* fill up entry fields with key name and value */ > + struct rte_cfgfile_entry *curr_entry = > + section->entries[section->num_entries]; > + > + snprintf(curr_entry->name, sizeof(curr_entry->name), "%s", entryname); > + snprintf(curr_entry->value, sizeof(curr_entry->value), "%s", > + entryvalue); > + section->num_entries++; > + section->free_entries--; > + > + return 0; > +} > + > static int > rte_cfgfile_check_params(const struct rte_cfgfile_parameters *params) > { > @@ -332,6 +396,176 @@ rte_cfgfile_load_with_params(const char *filename, int flags, > return NULL; > } > > +struct rte_cfgfile * > +rte_cfgfile_create(int flags) > +{ > + int i, j; > + struct rte_cfgfile *cfg = NULL; > + > + cfg = malloc(sizeof(*cfg)); > + if (cfg == NULL) > + return NULL; > + > + memset(cfg, 0, sizeof((*cfg))); > + > + cfg->flags = flags; > + > + /* allocate first batch of sections and entries */ > + cfg->sections = malloc(sizeof(cfg->sections[0]) * > + CFG_ALLOC_SECTION_BATCH); > + if (cfg->sections == NULL) > + return NULL; > + > + for (i = 0; i < CFG_ALLOC_SECTION_BATCH; i++) { > + cfg->sections[i] = malloc(sizeof(struct rte_cfgfile_section)); > + if (cfg->sections[i] == NULL) > + return NULL; > + > + memset(cfg->sections[i], 0, > + sizeof(struct rte_cfgfile_section)); > + > + cfg->sections[i]->entries = > + malloc(sizeof(cfg->sections[i]->entries[0]) > + * CFG_ALLOC_ENTRY_BATCH); > + if (cfg->sections[i]->entries == NULL) > + return NULL; > + > + for (j = 0; j < CFG_ALLOC_ENTRY_BATCH; j++) { > + cfg->sections[i]->entries[j] = malloc(sizeof(struct > + rte_cfgfile_entry)); > + if (cfg->sections[i]->entries[j] == NULL) > + return NULL; > + } > + cfg->sections[i]->allocated_entries = CFG_ALLOC_ENTRY_BATCH; > + cfg->sections[i]->free_entries = CFG_ALLOC_ENTRY_BATCH; > + } > + cfg->allocated_sections = CFG_ALLOC_SECTION_BATCH; > + cfg->free_sections = CFG_ALLOC_SECTION_BATCH; This work to initialise things is duplicated from the other add_section and add_entries functions. I'd just remove it from here, and have the newly allocated cfgfile structure be completely empty. Then on adding the first section and first entry, the allocation happens. No need to do it here. > + > + if (flags & CFG_FLAG_GLOBAL_SECTION) > + rte_cfgfile_add_section(cfg, "GLOBAL"); > + return cfg; > +} > + > +int > +rte_cfgfile_add_section(struct rte_cfgfile *cfg, const char *sectionname) > +{ > + int i; You are missing parameter checking. > + /* resize overall struct if we don't have room for more sections */ > + if (cfg->free_sections == 0) { > + > + struct rte_cfgfile_section **n_sections = > + realloc(cfg->sections, > + sizeof(cfg->sections[0]) * > + ((cfg->allocated_sections) + > + CFG_ALLOC_SECTION_BATCH)); > + > + if (n_sections == NULL) > + return -ENOMEM; > + > + cfg->sections = n_sections; > + > + for (i = cfg->allocated_sections; > + i < (cfg->allocated_sections) + > + CFG_ALLOC_SECTION_BATCH; i++) { > + cfg->sections[i] = > + malloc(sizeof(struct rte_cfgfile_section)); > + > + if (cfg->sections[i] == NULL) > + return -ENOMEM; > + > + memset(cfg->sections[i], 0, > + sizeof(struct rte_cfgfile_section)); > + } Same comment for too many mallocs (and memsets) as with add_entry. > + cfg->allocated_sections += CFG_ALLOC_SECTION_BATCH; > + cfg->free_sections += CFG_ALLOC_SECTION_BATCH; > + } > + > + snprintf(cfg->sections[cfg->num_sections]->name, > + sizeof(cfg->sections[0]->name), "%s", sectionname); > + cfg->sections[cfg->num_sections]->num_entries = 0; > + > + cfg->num_sections++; > + cfg->free_sections--; > + > + return 0; > +} > + > +int rte_cfgfile_add_entry(struct rte_cfgfile *cfg, > + const char *sectionname, const char *entryname, > + const char *entryvalue) > +{ > + int ret; > + > + if (cfg == NULL) > + return -EINVAL; > + Check other parameters for NULL too? > + if (rte_cfgfile_has_entry(cfg, sectionname, entryname) != 0) > + return -EEXIST; > + > + /* search for section pointer by sectionname */ > + struct rte_cfgfile_section *curr_section = _get_section(cfg, > + sectionname); > + if (curr_section == NULL) > + return -EINVAL; > + > + ret = _add_entry(curr_section, entryname, entryvalue); > + > + return ret; > +} > + > +int rte_cfgfile_set_entry(struct rte_cfgfile *cfg, const char *sectionname, > + const char *entryname, const char *entryvalue) > +{ > + int i; > + > + if (cfg == NULL) > + return -EINVAL; > + parameter checking? > + /* search for section pointer by sectionname */ > + struct rte_cfgfile_section *curr_section = _get_section(cfg, > + sectionname); > + if (curr_section == NULL) > + return -EINVAL; > + > + if (entryvalue == NULL) > + entryvalue = ""; > + > + for (i = 0; i < curr_section->num_entries; i++) > + if (!strcmp(curr_section->entries[i]->name, entryname)) { > + strcpy(curr_section->entries[i]->value, entryvalue); strcpy is unsafe here. Use snprintf as in other cases above where you are setting string values. > + return 0; > + } > + return -1; > +} > + > +int rte_cfgfile_save(struct rte_cfgfile *cfg, const char *filename) > +{ > + char buffer[CFG_NAME_LEN + CFG_VALUE_LEN + 4] = {0}; > + int i, j; > + > + if ((cfg == NULL) || (filename == NULL)) > + return -EINVAL; > + > + FILE *f = fopen(filename, "w"); > + > + if (f == NULL) > + return -EINVAL; Other functions e.g. the one above return -1 on error (and should set rte_errno appropriately in that case). Please standardize on one approach for error handling in this library - either return -1 and set rte_errno (my preference), or return error code directly. Mixing both is confusing. > + > + for (i = 0; i < cfg->num_sections; i++) { > + snprintf(buffer, sizeof(buffer), "[%s]\n", > + cfg->sections[i]->name); > + fputs(buffer, f); > + > + for (j = 0; j < cfg->sections[i]->num_entries; j++) { > + snprintf(buffer, sizeof(buffer), "%s=%s\n", > + cfg->sections[i]->entries[j]->name, > + cfg->sections[i]->entries[j]->value); > + fputs(buffer, f); Is there a reason to write to the buffer first and then to the file? Why not just write directly to the file? Check the return value from the write too. > + } > + } > + return fclose(f); > +} > > int rte_cfgfile_close(struct rte_cfgfile *cfg) > { > @@ -385,17 +619,6 @@ rte_cfgfile_sections(struct rte_cfgfile *cfg, char *sections[], > return i; > } > > -static const struct rte_cfgfile_section * > -_get_section(struct rte_cfgfile *cfg, const char *sectionname) > -{ > - int i; > - for (i = 0; i < cfg->num_sections; i++) { > - if (strncmp(cfg->sections[i]->name, sectionname, > - sizeof(cfg->sections[0]->name)) == 0) > - return cfg->sections[i]; > - } > - return NULL; > -} > > int > rte_cfgfile_has_section(struct rte_cfgfile *cfg, const char *sectionname) > diff --git a/lib/librte_cfgfile/rte_cfgfile.h b/lib/librte_cfgfile/rte_cfgfile.h > index fa10d40..6245c7e 100644 > --- a/lib/librte_cfgfile/rte_cfgfile.h > +++ b/lib/librte_cfgfile/rte_cfgfile.h > @@ -121,6 +121,82 @@ struct rte_cfgfile *rte_cfgfile_load_with_params(const char *filename, > int flags, const struct rte_cfgfile_parameters *params); > > /** > + * Create new cfgfile instance with empty sections and entries > + * > + * @param flags > + * - CFG_FLAG_GLOBAL_SECTION > + * Indicates that the file supports key value entries before the first > + * defined section. These entries can be accessed in the "GLOBAL" > + * section. > + * - CFG_FLAG_EMPTY_VALUES > + * Indicates that file supports key value entries where the value can > + * be zero length (e.g., "key="). > + * @return > + * Handle to cfgfile instance on success, NULL otherwise > + */ > +struct rte_cfgfile *rte_cfgfile_create(int flags); > + > +/** > + * Add section in cfgfile instance. > + * > + * @param cfg > + * Pointer to the cfgfile structure. > + * @param sectionname > + * Section name which will be add to cfgfile. > + * @return > + * 0 on success, -ENOMEM if can't add section > + */ > +int > +rte_cfgfile_add_section(struct rte_cfgfile *cfg, const char *sectionname); > + > +/** > + * Add entry to specified section in cfgfile instance. > + * > + * @param cfg > + * Pointer to the cfgfile structure. > + * @param sectionname > + * Given section name to add an entry. > + * @param entryname > + * Entry name to add. > + * @entryvalue > + * Entry value to add. > + * @return > + * 0 on success, -EEXIST if entry already exist, -EINVAL if bad argument > + */ > +int rte_cfgfile_add_entry(struct rte_cfgfile *cfg, > + const char *sectionname, const char *entryname, > + const char *entryvalue); > + > +/** > + * Update value of specified entry name in given section in config file > + * > + * @param cfg > + * Config file > + * @param sectionname > + * Section name > + * @param entryname > + * Entry name to look for the value change > + * @param entryvalue > + * New entry value. Can be also an empty string if CFG_FLAG_EMPTY_VALUES = 1 > + * @return > + * 0 on success, -EINVAL if bad argument What about if the value doesn't exist? > + */ > +int rte_cfgfile_set_entry(struct rte_cfgfile *cfg, const char *sectionname, > + const char *entryname, const char *entryvalue); > + > +/** > + * Save object cfgfile to file on disc > + * > + * @param cfg > + * Config file structure > + * @param filename > + * File name to save data > + * @return > + * 0 on success, errno otherwise > + */ > +int rte_cfgfile_save(struct rte_cfgfile *cfg, const char *filename); > + > +/** > * Get number of sections in config file > * > * @param cfg > diff --git a/lib/librte_cfgfile/rte_cfgfile_version.map b/lib/librte_cfgfile/rte_cfgfile_version.map > index 5fe60f7..de68ff6 100644 > --- a/lib/librte_cfgfile/rte_cfgfile_version.map > +++ b/lib/librte_cfgfile/rte_cfgfile_version.map > @@ -27,3 +27,14 @@ DPDK_17.05 { > rte_cfgfile_load_with_params; > > } DPDK_16.04; > + > +DPDK_17.08 { > + global: > + > + rte_cfgfile_add_entry; > + rte_cfgfile_add_section; > + rte_cfgfile_create; > + rte_cfgfile_save; > + rte_cfgfile_set_entry; > + > +} DPDK_17.05; > \ No newline at end of file > -- > 2.7.4 > ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v3 3/4] cfgfile: rework of load function 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 0/4] Rework cfgfile API to enable apps config file support Jacek Piasecki 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 1/4] cfgfile: remove EAL dependency Jacek Piasecki 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 2/4] cfgfile: add new functions to API Jacek Piasecki @ 2017-06-27 10:26 ` Jacek Piasecki 2017-06-30 11:18 ` Bruce Richardson 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 4/4] test/cfgfile: add new unit test Jacek Piasecki 2017-06-30 11:20 ` [dpdk-dev] [PATCH v3 0/4] Rework cfgfile API to enable apps config file support Bruce Richardson 4 siblings, 1 reply; 70+ messages in thread From: Jacek Piasecki @ 2017-06-27 10:26 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, Kuba Kozak, Jacek Piasecki From: Kuba Kozak <kubax.kozak@intel.com> New functions added to cfgfile library make it possible to significantly simplify the code of rte_cfgfile_load_with_params() This patch shows the new body of this function. Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> --- lib/librte_cfgfile/rte_cfgfile.c | 143 +++++---------------------------------- 1 file changed, 17 insertions(+), 126 deletions(-) diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c index 518b6ab..5625c80 100644 --- a/lib/librte_cfgfile/rte_cfgfile.c +++ b/lib/librte_cfgfile/rte_cfgfile.c @@ -207,10 +207,6 @@ struct rte_cfgfile * rte_cfgfile_load_with_params(const char *filename, int flags, const struct rte_cfgfile_parameters *params) { - int allocated_sections = CFG_ALLOC_SECTION_BATCH; - int allocated_entries = 0; - int curr_section = -1; - int curr_entry = -1; char buffer[CFG_NAME_LEN + CFG_VALUE_LEN + 4] = {0}; int lineno = 0; struct rte_cfgfile *cfg = NULL; @@ -222,28 +218,7 @@ rte_cfgfile_load_with_params(const char *filename, int flags, if (f == NULL) return NULL; - cfg = malloc(sizeof(*cfg) + sizeof(cfg->sections[0]) * - allocated_sections); - if (cfg == NULL) - goto error2; - - memset(cfg->sections, 0, sizeof(cfg->sections[0]) * allocated_sections); - - if (flags & CFG_FLAG_GLOBAL_SECTION) { - curr_section = 0; - allocated_entries = CFG_ALLOC_ENTRY_BATCH; - cfg->sections[curr_section] = malloc( - sizeof(*cfg->sections[0]) + - sizeof(cfg->sections[0]->entries[0]) * - allocated_entries); - if (cfg->sections[curr_section] == NULL) { - printf("Error - no memory for global section\n"); - goto error1; - } - - snprintf(cfg->sections[curr_section]->name, - sizeof(cfg->sections[0]->name), "GLOBAL"); - } + cfg = rte_cfgfile_create(flags); while (fgets(buffer, sizeof(buffer), f) != NULL) { char *pos = NULL; @@ -254,6 +229,7 @@ rte_cfgfile_load_with_params(const char *filename, int flags, "Check if line too long\n", lineno); goto error1; } + /* skip parsing if comment character found */ pos = memchr(buffer, params->comment_character, len); if (pos != NULL) { *pos = '\0'; @@ -261,6 +237,7 @@ rte_cfgfile_load_with_params(const char *filename, int flags, } len = _strip(buffer, len); + /* skip lines without useful content */ if (buffer[0] != '[' && memchr(buffer, '=', len) == NULL) continue; @@ -268,130 +245,44 @@ rte_cfgfile_load_with_params(const char *filename, int flags, /* section heading line */ char *end = memchr(buffer, ']', len); if (end == NULL) { - printf("Error line %d - no terminating '['" + printf("Error line %d - no terminating ']'" "character found\n", lineno); goto error1; } *end = '\0'; _strip(&buffer[1], end - &buffer[1]); - /* close off old section and add start new one */ - if (curr_section >= 0) - cfg->sections[curr_section]->num_entries = - curr_entry + 1; - curr_section++; - - /* resize overall struct if we don't have room for more - sections */ - if (curr_section == allocated_sections) { - allocated_sections += CFG_ALLOC_SECTION_BATCH; - struct rte_cfgfile *n_cfg = realloc(cfg, - sizeof(*cfg) + sizeof(cfg->sections[0]) - * allocated_sections); - if (n_cfg == NULL) { - curr_section--; - printf("Error - no more memory\n"); - goto error1; - } - cfg = n_cfg; - } - - /* allocate space for new section */ - allocated_entries = CFG_ALLOC_ENTRY_BATCH; - curr_entry = -1; - cfg->sections[curr_section] = malloc( - sizeof(*cfg->sections[0]) + - sizeof(cfg->sections[0]->entries[0]) * - allocated_entries); - if (cfg->sections[curr_section] == NULL) { - printf("Error - no more memory\n"); - goto error1; - } - - snprintf(cfg->sections[curr_section]->name, - sizeof(cfg->sections[0]->name), - "%s", &buffer[1]); + rte_cfgfile_add_section(cfg, &buffer[1]); } else { - /* value line */ - if (curr_section < 0) { - printf("Error line %d - value outside of" - "section\n", lineno); - goto error1; - } - - struct rte_cfgfile_section *sect = - cfg->sections[curr_section]; - + /* key and value line */ char *split[2] = {NULL}; + split[0] = buffer; split[1] = memchr(buffer, '=', len); + *split[1] = '\0'; + split[1]++; + + _strip(split[0], strlen(split[0])); + _strip(split[1], strlen(split[1])); - /* when delimeter not found */ - if (split[1] == NULL) { + if (!(flags & CFG_FLAG_EMPTY_VALUES) && + (*split[1] == '\0')) { printf("Error at line %d - cannot " "split string\n", lineno); goto error1; - } else { - /* when delimeter found */ - *split[1] = '\0'; - split[1]++; - - if (!(flags & CFG_FLAG_EMPTY_VALUES) && - (*split[1] == '\0')) { - printf("Error at line %d - cannot " - "split string\n", lineno); - goto error1; - } } - curr_entry++; - if (curr_entry == allocated_entries) { - allocated_entries += CFG_ALLOC_ENTRY_BATCH; - struct rte_cfgfile_section *n_sect = realloc( - sect, sizeof(*sect) + - sizeof(sect->entries[0]) * - allocated_entries); - if (n_sect == NULL) { - curr_entry--; - printf("Error - no more memory\n"); - goto error1; - } - sect = cfg->sections[curr_section] = n_sect; - } - - sect->entries[curr_entry] = malloc( - sizeof(*sect->entries[0])); - if (sect->entries[curr_entry] == NULL) { - printf("Error - no more memory\n"); + if (cfg->num_sections == 0) goto error1; - } - struct rte_cfgfile_entry *entry = sect->entries[ - curr_entry]; - snprintf(entry->name, sizeof(entry->name), "%s", - split[0]); - snprintf(entry->value, sizeof(entry->value), "%s", - split[1] ? split[1] : ""); - _strip(entry->name, strnlen(entry->name, - sizeof(entry->name))); - _strip(entry->value, strnlen(entry->value, - sizeof(entry->value))); + _add_entry(cfg->sections[cfg->num_sections - 1], + split[0], (split[1] ? split[1] : "")); } } fclose(f); - cfg->flags = flags; - cfg->num_sections = curr_section + 1; - /* curr_section will still be -1 if we have an empty file */ - if (curr_section >= 0) - cfg->sections[curr_section]->num_entries = curr_entry + 1; return cfg; - error1: - cfg->num_sections = curr_section + 1; - if (curr_section >= 0) - cfg->sections[curr_section]->num_entries = curr_entry + 1; rte_cfgfile_close(cfg); -error2: fclose(f); return NULL; } -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v3 3/4] cfgfile: rework of load function 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 3/4] cfgfile: rework of load function Jacek Piasecki @ 2017-06-30 11:18 ` Bruce Richardson 0 siblings, 0 replies; 70+ messages in thread From: Bruce Richardson @ 2017-06-30 11:18 UTC (permalink / raw) To: Jacek Piasecki; +Cc: dev, deepak.k.jain, Kuba Kozak On Tue, Jun 27, 2017 at 12:26:49PM +0200, Jacek Piasecki wrote: > From: Kuba Kozak <kubax.kozak@intel.com> > > New functions added to cfgfile library make it possible > to significantly simplify the code of rte_cfgfile_load_with_params() > > This patch shows the new body of this function. > > Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> > --- > lib/librte_cfgfile/rte_cfgfile.c | 143 +++++---------------------------------- > 1 file changed, 17 insertions(+), 126 deletions(-) > > diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c > index 518b6ab..5625c80 100644 > --- a/lib/librte_cfgfile/rte_cfgfile.c > +++ b/lib/librte_cfgfile/rte_cfgfile.c > @@ -207,10 +207,6 @@ struct rte_cfgfile * > rte_cfgfile_load_with_params(const char *filename, int flags, > const struct rte_cfgfile_parameters *params) > { > - int allocated_sections = CFG_ALLOC_SECTION_BATCH; > - int allocated_entries = 0; > - int curr_section = -1; > - int curr_entry = -1; > char buffer[CFG_NAME_LEN + CFG_VALUE_LEN + 4] = {0}; > int lineno = 0; > struct rte_cfgfile *cfg = NULL; > @@ -222,28 +218,7 @@ rte_cfgfile_load_with_params(const char *filename, int flags, > if (f == NULL) > return NULL; > > - cfg = malloc(sizeof(*cfg) + sizeof(cfg->sections[0]) * > - allocated_sections); > - if (cfg == NULL) > - goto error2; > - > - memset(cfg->sections, 0, sizeof(cfg->sections[0]) * allocated_sections); > - > - if (flags & CFG_FLAG_GLOBAL_SECTION) { > - curr_section = 0; > - allocated_entries = CFG_ALLOC_ENTRY_BATCH; > - cfg->sections[curr_section] = malloc( > - sizeof(*cfg->sections[0]) + > - sizeof(cfg->sections[0]->entries[0]) * > - allocated_entries); > - if (cfg->sections[curr_section] == NULL) { > - printf("Error - no memory for global section\n"); > - goto error1; > - } > - > - snprintf(cfg->sections[curr_section]->name, > - sizeof(cfg->sections[0]->name), "GLOBAL"); > - } > + cfg = rte_cfgfile_create(flags); > > while (fgets(buffer, sizeof(buffer), f) != NULL) { > char *pos = NULL; > @@ -254,6 +229,7 @@ rte_cfgfile_load_with_params(const char *filename, int flags, > "Check if line too long\n", lineno); > goto error1; > } > + /* skip parsing if comment character found */ > pos = memchr(buffer, params->comment_character, len); > if (pos != NULL) { > *pos = '\0'; > @@ -261,6 +237,7 @@ rte_cfgfile_load_with_params(const char *filename, int flags, > } > > len = _strip(buffer, len); > + /* skip lines without useful content */ > if (buffer[0] != '[' && memchr(buffer, '=', len) == NULL) > continue; > > @@ -268,130 +245,44 @@ rte_cfgfile_load_with_params(const char *filename, int flags, > /* section heading line */ > char *end = memchr(buffer, ']', len); > if (end == NULL) { > - printf("Error line %d - no terminating '['" > + printf("Error line %d - no terminating ']'" > "character found\n", lineno); > goto error1; > } > *end = '\0'; > _strip(&buffer[1], end - &buffer[1]); > > - /* close off old section and add start new one */ > - if (curr_section >= 0) > - cfg->sections[curr_section]->num_entries = > - curr_entry + 1; > - curr_section++; > - > - /* resize overall struct if we don't have room for more > - sections */ > - if (curr_section == allocated_sections) { > - allocated_sections += CFG_ALLOC_SECTION_BATCH; > - struct rte_cfgfile *n_cfg = realloc(cfg, > - sizeof(*cfg) + sizeof(cfg->sections[0]) > - * allocated_sections); > - if (n_cfg == NULL) { > - curr_section--; > - printf("Error - no more memory\n"); > - goto error1; > - } > - cfg = n_cfg; > - } > - > - /* allocate space for new section */ > - allocated_entries = CFG_ALLOC_ENTRY_BATCH; > - curr_entry = -1; > - cfg->sections[curr_section] = malloc( > - sizeof(*cfg->sections[0]) + > - sizeof(cfg->sections[0]->entries[0]) * > - allocated_entries); > - if (cfg->sections[curr_section] == NULL) { > - printf("Error - no more memory\n"); > - goto error1; > - } > - > - snprintf(cfg->sections[curr_section]->name, > - sizeof(cfg->sections[0]->name), > - "%s", &buffer[1]); > + rte_cfgfile_add_section(cfg, &buffer[1]); > } else { > - /* value line */ > - if (curr_section < 0) { > - printf("Error line %d - value outside of" > - "section\n", lineno); > - goto error1; > - } > - > - struct rte_cfgfile_section *sect = > - cfg->sections[curr_section]; > - > + /* key and value line */ > char *split[2] = {NULL}; > + > split[0] = buffer; > split[1] = memchr(buffer, '=', len); > + *split[1] = '\0'; > + split[1]++; > + > + _strip(split[0], strlen(split[0])); > + _strip(split[1], strlen(split[1])); > > - /* when delimeter not found */ > - if (split[1] == NULL) { > + if (!(flags & CFG_FLAG_EMPTY_VALUES) && > + (*split[1] == '\0')) { > printf("Error at line %d - cannot " > "split string\n", lineno); This error message could do with an update. It's not that you can't split the string, it's that the value is empty - something not allowed. Also, it's bad practice to split literal strings for printing. This is the one case where you are encouraged to go over the 80-char limit rather than wrapping the line. /Bruce ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v3 4/4] test/cfgfile: add new unit test 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 0/4] Rework cfgfile API to enable apps config file support Jacek Piasecki ` (2 preceding siblings ...) 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 3/4] cfgfile: rework of load function Jacek Piasecki @ 2017-06-27 10:26 ` Jacek Piasecki 2017-06-30 11:20 ` [dpdk-dev] [PATCH v3 0/4] Rework cfgfile API to enable apps config file support Bruce Richardson 4 siblings, 0 replies; 70+ messages in thread From: Jacek Piasecki @ 2017-06-27 10:26 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, Jacek Piasecki Load huge realloc_sections.ini file to check malloc/realloc ability of cfgfile library. Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> --- test/test/test_cfgfile.c | 40 +++++++ test/test/test_cfgfiles/etc/realloc_sections.ini | 128 +++++++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 test/test/test_cfgfiles/etc/realloc_sections.ini diff --git a/test/test/test_cfgfile.c b/test/test/test_cfgfile.c index 4cc9b14..2278618 100644 --- a/test/test/test_cfgfile.c +++ b/test/test/test_cfgfile.c @@ -111,6 +111,7 @@ _test_cfgfile_sample(struct rte_cfgfile *cfgfile) return 0; } + static int test_cfgfile_sample1(void) { @@ -154,6 +155,42 @@ test_cfgfile_sample2(void) } static int +test_cfgfile_realloc_sections(void) +{ + struct rte_cfgfile *cfgfile; + int ret; + const char *value; + + cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/realloc_sections.ini", 0); + TEST_ASSERT_NOT_NULL(cfgfile, "Failed to load config file"); + + ret = rte_cfgfile_num_sections(cfgfile, NULL, 0); + TEST_ASSERT(ret == 9, "Unexpected number of sections: %d", ret); + + ret = rte_cfgfile_has_section(cfgfile, "section9"); + TEST_ASSERT(ret, "section9 missing"); + + ret = rte_cfgfile_section_num_entries(cfgfile, "section3"); + TEST_ASSERT(ret == 21, + "section3 unexpected number of entries: %d", ret); + + ret = rte_cfgfile_section_num_entries(cfgfile, "section9"); + TEST_ASSERT(ret == 8, "section9 unexpected number of entries: %d", ret); + + value = rte_cfgfile_get_entry(cfgfile, "section9", "key8"); + TEST_ASSERT(strcmp("value8_section9", value) == 0, + "key unexpected value: %s", value); + + ret = rte_cfgfile_save(cfgfile, "cfgfile_save.ini"); + TEST_ASSERT_SUCCESS(ret, "Failed to save *.ini file"); + + ret = rte_cfgfile_close(cfgfile); + TEST_ASSERT_SUCCESS(ret, "Failed to close cfgfile"); + + return 0; +} + +static int test_cfgfile_invalid_section_header(void) { struct rte_cfgfile *cfgfile; @@ -292,6 +329,9 @@ test_cfgfile(void) if (test_cfgfile_sample2()) return -1; + if (test_cfgfile_realloc_sections()) + return -1; + if (test_cfgfile_invalid_section_header()) return -1; diff --git a/test/test/test_cfgfiles/etc/realloc_sections.ini b/test/test/test_cfgfiles/etc/realloc_sections.ini new file mode 100644 index 0000000..e653e40 --- /dev/null +++ b/test/test/test_cfgfiles/etc/realloc_sections.ini @@ -0,0 +1,128 @@ +[section1] +key1=value1_section1 +key2=value2_section1 +key3=value3_section1 +key4=value4_section1 +key5=value5_section1 +key6=value6_section1 +key7=value7_section1 +key8=value8_section1 +key9=value9_section1 +key10=value10_section1 +key11=value11_section1 +key12=value12_section1 +key13=value13_section1 +key14=value14_section1 +key15=value15_section1 +key16=value16_section1 +key17=value17_section1 +key18=value18_section1 +key19=value19_section1 +key20=value20_section1 +key21=value21_section1 + +[section2] +key1=value1_section2 +key2=value2_section2 +key3=value3_section2 +key4=value4_section2 +key5=value5_section2 +key6=value6_section2 +key7=value7_section2 +key8=value8_section2 +key9=value9_section2 +key10=value10_section2 +key11=value11_section2 +key12=value12_section2 +key13=value13_section2 +key14=value14_section2 +key15=value15_section2 +key16=value16_section2 +key17=value17_section2 +key18=value18_section2 +key19=value19_section2 +key20=value20_section2 +key21=value21_section2 + +[section3] +key1=value1_section3 +key2=value2_section3 +key3=value3_section3 +key4=value4_section3 +key5=value5_section3 +key6=value6_section3 +key7=value7_section3 +key8=value8_section3 +key9=value9_section3 +key10=value10_section3 +key11=value11_section3 +key12=value12_section3 +key13=value13_section3 +key14=value14_section3 +key15=value15_section3 +key16=value16_section3 +key17=value17_section3 +key18=value18_section3 +key19=value19_section3 +key20=value20_section3 +key21=value21_section3 + +[section4] +key1=value1_section4 +key2=value2_section4 +key3=value3_section4 +key4=value4_section4 +key5=value5_section4 +key6=value6_section4 +key7=value7_section4 +key8=value8_section4 + +[section5] +key1=value1_section5 +key2=value2_section5 +key3=value3_section5 +key4=value4_section5 +key5=value5_section5 +key6=value6_section5 +key7=value7_section5 +key8=value8_section5 + +[section6] +key1=value1_section6 +key2=value2_section6 +key3=value3_section6 +key4=value4_section6 +key5=value5_section6 +key6=value6_section6 +key7=value7_section6 +key8=value8_section6 + +[section7] +key1=value1_section7 +key2=value2_section7 +key3=value3_section7 +key4=value4_section7 +key5=value5_section7 +key6=value6_section7 +key7=value7_section7 +key8=value8_section7 + +[section8] +key1=value1_section8 +key2=value2_section8 +key3=value3_section8 +key4=value4_section8 +key5=value5_section8 +key6=value6_section8 +key7=value7_section8 +key8=value8_section8 + +[section9] +key1=value1_section9 +key2=value2_section9 +key3=value3_section9 +key4=value4_section9 +key5=value5_section9 +key6=value6_section9 +key7=value7_section9 +key8=value8_section9 -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v3 0/4] Rework cfgfile API to enable apps config file support 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 0/4] Rework cfgfile API to enable apps config file support Jacek Piasecki ` (3 preceding siblings ...) 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 4/4] test/cfgfile: add new unit test Jacek Piasecki @ 2017-06-30 11:20 ` Bruce Richardson 4 siblings, 0 replies; 70+ messages in thread From: Bruce Richardson @ 2017-06-30 11:20 UTC (permalink / raw) To: Jacek Piasecki; +Cc: dev, deepak.k.jain On Tue, Jun 27, 2017 at 12:26:46PM +0200, Jacek Piasecki wrote: > 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. > > --- > 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 (3): > cfgfile: remove EAL dependency > cfgfile: add new functions to API > test/cfgfile: add new unit test > > Kuba Kozak (1): > cfgfile: rework of load function > This looks a good set to have. Some cleanup work needed on the code, but from a high-level implementation view, it's fine. Once issues flagged by me are fixed: Acked-by: Bruce Richardson <bruce.richardson@intel.com> ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v2 2/7] cfgfile: add new functions to API 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 0/7] Add support for using a config file for DPDK Jacek Piasecki 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 1/7] cfgfile: remove EAL dependency Jacek Piasecki @ 2017-06-26 10:59 ` Jacek Piasecki 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 3/7] cfgfile: rework of load function Jacek Piasecki ` (4 subsequent siblings) 6 siblings, 0 replies; 70+ messages in thread From: Jacek Piasecki @ 2017-06-26 10:59 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, Jacek Piasecki Extend existing cfgfile library with providing new API functions: rte_cfgfile_create() - create new cfgfile object rte_cfgfile_add_section() - add new section to existing cfgfile object rte_cfgfile_add_entry() - add new entry to existing cfgfile object in specified section rte_cfgfile_set_entry() - update existing entry in cfgfile object rte_cfgfile_save() - save existing cfgfile object to INI file This modification allows to create a cfgfile on runtime and opens up the possibility to have applications dynamically build up a proper DPDK configuration, rather than having to have a pre-existing one. Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> --- lib/librte_cfgfile/rte_cfgfile.c | 249 +++++++++++++++++++++++++++-- lib/librte_cfgfile/rte_cfgfile.h | 76 +++++++++ lib/librte_cfgfile/rte_cfgfile_version.map | 11 ++ 3 files changed, 323 insertions(+), 13 deletions(-) diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c index c6ae3e3..518b6ab 100644 --- a/lib/librte_cfgfile/rte_cfgfile.c +++ b/lib/librte_cfgfile/rte_cfgfile.c @@ -35,6 +35,7 @@ #include <stdlib.h> #include <string.h> #include <ctype.h> +#include <errno.h> #include <rte_common.h> #include "rte_cfgfile.h" @@ -42,13 +43,17 @@ struct rte_cfgfile_section { char name[CFG_NAME_LEN]; int num_entries; - struct rte_cfgfile_entry *entries[0]; + int free_entries; + int allocated_entries; + struct rte_cfgfile_entry **entries; }; struct rte_cfgfile { int flags; int num_sections; - struct rte_cfgfile_section *sections[0]; + int free_sections; + int allocated_sections; + struct rte_cfgfile_section **sections; }; /** when we resize a file structure, how many extra entries @@ -104,6 +109,65 @@ _strip(char *str, unsigned len) return newlen; } +static struct rte_cfgfile_section * +_get_section(struct rte_cfgfile *cfg, const char *sectionname) +{ + int i; + + for (i = 0; i < cfg->num_sections; i++) { + if (strncmp(cfg->sections[i]->name, sectionname, + sizeof(cfg->sections[0]->name)) == 0) + return cfg->sections[i]; + } + return NULL; +} + +static int +_add_entry(struct rte_cfgfile_section *section, const char *entryname, + const char *entryvalue) +{ + int i; + + /* resize entry structure if we don't have room for more entries */ + if (section->free_entries == 0) { + + struct rte_cfgfile_entry **n_entries = + realloc(section->entries, + sizeof(section->entries[0]) * + ((section->allocated_entries) + + CFG_ALLOC_ENTRY_BATCH)); + + if (n_entries == NULL) + return -ENOMEM; + + section->entries = n_entries; + + for (i = section->allocated_entries; + i < (section->allocated_entries) + + CFG_ALLOC_ENTRY_BATCH; i++) { + section->entries[i] = + malloc(sizeof(struct rte_cfgfile_entry)); + + if (section->entries[i] == NULL) + return -ENOMEM; + } + section->allocated_entries += CFG_ALLOC_ENTRY_BATCH; + section->free_entries += CFG_ALLOC_ENTRY_BATCH; + } + + /* fill up entry fields with key name and value */ + struct rte_cfgfile_entry *curr_entry = + section->entries[section->num_entries]; + + snprintf(curr_entry->name, sizeof(curr_entry->name), "%s", entryname); + snprintf(curr_entry->value, sizeof(curr_entry->value), "%s", + entryvalue); + section->num_entries++; + section->free_entries--; + + return 0; +} + static int rte_cfgfile_check_params(const struct rte_cfgfile_parameters *params) { @@ -332,6 +396,176 @@ rte_cfgfile_load_with_params(const char *filename, int flags, return NULL; } +struct rte_cfgfile * +rte_cfgfile_create(int flags) +{ + int i, j; + struct rte_cfgfile *cfg = NULL; + + cfg = malloc(sizeof(*cfg)); + if (cfg == NULL) + return NULL; + + memset(cfg, 0, sizeof((*cfg))); + + cfg->flags = flags; + + /* allocate first batch of sections and entries */ + cfg->sections = malloc(sizeof(cfg->sections[0]) * + CFG_ALLOC_SECTION_BATCH); + if (cfg->sections == NULL) + return NULL; + + for (i = 0; i < CFG_ALLOC_SECTION_BATCH; i++) { + cfg->sections[i] = malloc(sizeof(struct rte_cfgfile_section)); + if (cfg->sections[i] == NULL) + return NULL; + + memset(cfg->sections[i], 0, + sizeof(struct rte_cfgfile_section)); + + cfg->sections[i]->entries = + malloc(sizeof(cfg->sections[i]->entries[0]) + * CFG_ALLOC_ENTRY_BATCH); + if (cfg->sections[i]->entries == NULL) + return NULL; + + for (j = 0; j < CFG_ALLOC_ENTRY_BATCH; j++) { + cfg->sections[i]->entries[j] = malloc(sizeof(struct + rte_cfgfile_entry)); + if (cfg->sections[i]->entries[j] == NULL) + return NULL; + } + cfg->sections[i]->allocated_entries = CFG_ALLOC_ENTRY_BATCH; + cfg->sections[i]->free_entries = CFG_ALLOC_ENTRY_BATCH; + } + cfg->allocated_sections = CFG_ALLOC_SECTION_BATCH; + cfg->free_sections = CFG_ALLOC_SECTION_BATCH; + + if (flags & CFG_FLAG_GLOBAL_SECTION) + rte_cfgfile_add_section(cfg, "GLOBAL"); + return cfg; +} + +int +rte_cfgfile_add_section(struct rte_cfgfile *cfg, const char *sectionname) +{ + int i; + /* resize overall struct if we don't have room for more sections */ + if (cfg->free_sections == 0) { + + struct rte_cfgfile_section **n_sections = + realloc(cfg->sections, + sizeof(cfg->sections[0]) * + ((cfg->allocated_sections) + + CFG_ALLOC_SECTION_BATCH)); + + if (n_sections == NULL) + return -ENOMEM; + + cfg->sections = n_sections; + + for (i = cfg->allocated_sections; + i < (cfg->allocated_sections) + + CFG_ALLOC_SECTION_BATCH; i++) { + cfg->sections[i] = + malloc(sizeof(struct rte_cfgfile_section)); + + if (cfg->sections[i] == NULL) + return -ENOMEM; + + memset(cfg->sections[i], 0, + sizeof(struct rte_cfgfile_section)); + } + cfg->allocated_sections += CFG_ALLOC_SECTION_BATCH; + cfg->free_sections += CFG_ALLOC_SECTION_BATCH; + } + + snprintf(cfg->sections[cfg->num_sections]->name, + sizeof(cfg->sections[0]->name), "%s", sectionname); + cfg->sections[cfg->num_sections]->num_entries = 0; + + cfg->num_sections++; + cfg->free_sections--; + + return 0; +} + +int rte_cfgfile_add_entry(struct rte_cfgfile *cfg, + const char *sectionname, const char *entryname, + const char *entryvalue) +{ + int ret; + + if (cfg == NULL) + return -EINVAL; + + if (rte_cfgfile_has_entry(cfg, sectionname, entryname) != 0) + return -EEXIST; + + /* search for section pointer by sectionname */ + struct rte_cfgfile_section *curr_section = _get_section(cfg, + sectionname); + if (curr_section == NULL) + return -EINVAL; + + ret = _add_entry(curr_section, entryname, entryvalue); + + return ret; +} + +int rte_cfgfile_set_entry(struct rte_cfgfile *cfg, const char *sectionname, + const char *entryname, const char *entryvalue) +{ + int i; + + if (cfg == NULL) + return -EINVAL; + + /* search for section pointer by sectionname */ + struct rte_cfgfile_section *curr_section = _get_section(cfg, + sectionname); + if (curr_section == NULL) + return -EINVAL; + + if (entryvalue == NULL) + entryvalue = ""; + + for (i = 0; i < curr_section->num_entries; i++) + if (!strcmp(curr_section->entries[i]->name, entryname)) { + strcpy(curr_section->entries[i]->value, entryvalue); + return 0; + } + return -1; +} + +int rte_cfgfile_save(struct rte_cfgfile *cfg, const char *filename) +{ + char buffer[CFG_NAME_LEN + CFG_VALUE_LEN + 4] = {0}; + int i, j; + + if ((cfg == NULL) || (filename == NULL)) + return -EINVAL; + + FILE *f = fopen(filename, "w"); + + if (f == NULL) + return -EINVAL; + + for (i = 0; i < cfg->num_sections; i++) { + snprintf(buffer, sizeof(buffer), "[%s]\n", + cfg->sections[i]->name); + fputs(buffer, f); + + for (j = 0; j < cfg->sections[i]->num_entries; j++) { + snprintf(buffer, sizeof(buffer), "%s=%s\n", + cfg->sections[i]->entries[j]->name, + cfg->sections[i]->entries[j]->value); + fputs(buffer, f); + } + } + return fclose(f); +} int rte_cfgfile_close(struct rte_cfgfile *cfg) { @@ -385,17 +619,6 @@ rte_cfgfile_sections(struct rte_cfgfile *cfg, char *sections[], return i; } -static const struct rte_cfgfile_section * -_get_section(struct rte_cfgfile *cfg, const char *sectionname) -{ - int i; - for (i = 0; i < cfg->num_sections; i++) { - if (strncmp(cfg->sections[i]->name, sectionname, - sizeof(cfg->sections[0]->name)) == 0) - return cfg->sections[i]; - } - return NULL; -} int rte_cfgfile_has_section(struct rte_cfgfile *cfg, const char *sectionname) diff --git a/lib/librte_cfgfile/rte_cfgfile.h b/lib/librte_cfgfile/rte_cfgfile.h index fa10d40..6245c7e 100644 --- a/lib/librte_cfgfile/rte_cfgfile.h +++ b/lib/librte_cfgfile/rte_cfgfile.h @@ -121,6 +121,82 @@ struct rte_cfgfile *rte_cfgfile_load_with_params(const char *filename, int flags, const struct rte_cfgfile_parameters *params); /** + * Create new cfgfile instance with empty sections and entries + * + * @param flags + * - CFG_FLAG_GLOBAL_SECTION + * Indicates that the file supports key value entries before the first + * defined section. These entries can be accessed in the "GLOBAL" + * section. + * - CFG_FLAG_EMPTY_VALUES + * Indicates that file supports key value entries where the value can + * be zero length (e.g., "key="). + * @return + * Handle to cfgfile instance on success, NULL otherwise + */ +struct rte_cfgfile *rte_cfgfile_create(int flags); + +/** + * Add section in cfgfile instance. + * + * @param cfg + * Pointer to the cfgfile structure. + * @param sectionname + * Section name which will be add to cfgfile. + * @return + * 0 on success, -ENOMEM if can't add section + */ +int +rte_cfgfile_add_section(struct rte_cfgfile *cfg, const char *sectionname); + +/** + * Add entry to specified section in cfgfile instance. + * + * @param cfg + * Pointer to the cfgfile structure. + * @param sectionname + * Given section name to add an entry. + * @param entryname + * Entry name to add. + * @entryvalue + * Entry value to add. + * @return + * 0 on success, -EEXIST if entry already exist, -EINVAL if bad argument + */ +int rte_cfgfile_add_entry(struct rte_cfgfile *cfg, + const char *sectionname, const char *entryname, + const char *entryvalue); + +/** + * Update value of specified entry name in given section in config file + * + * @param cfg + * Config file + * @param sectionname + * Section name + * @param entryname + * Entry name to look for the value change + * @param entryvalue + * New entry value. Can be also an empty string if CFG_FLAG_EMPTY_VALUES = 1 + * @return + * 0 on success, -EINVAL if bad argument + */ +int rte_cfgfile_set_entry(struct rte_cfgfile *cfg, const char *sectionname, + const char *entryname, const char *entryvalue); + +/** + * Save object cfgfile to file on disc + * + * @param cfg + * Config file structure + * @param filename + * File name to save data + * @return + * 0 on success, errno otherwise + */ +int rte_cfgfile_save(struct rte_cfgfile *cfg, const char *filename); + +/** * Get number of sections in config file * * @param cfg diff --git a/lib/librte_cfgfile/rte_cfgfile_version.map b/lib/librte_cfgfile/rte_cfgfile_version.map index 5fe60f7..de68ff6 100644 --- a/lib/librte_cfgfile/rte_cfgfile_version.map +++ b/lib/librte_cfgfile/rte_cfgfile_version.map @@ -27,3 +27,14 @@ DPDK_17.05 { rte_cfgfile_load_with_params; } DPDK_16.04; + +DPDK_17.08 { + global: + + rte_cfgfile_add_entry; + rte_cfgfile_add_section; + rte_cfgfile_create; + rte_cfgfile_save; + rte_cfgfile_set_entry; + +} DPDK_17.05; \ No newline at end of file -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v2 3/7] cfgfile: rework of load function 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 0/7] Add support for using a config file for DPDK Jacek Piasecki 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 1/7] cfgfile: remove EAL dependency Jacek Piasecki 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 2/7] cfgfile: add new functions to API Jacek Piasecki @ 2017-06-26 10:59 ` Jacek Piasecki 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 4/7] test/cfgfile: add new unit test Jacek Piasecki ` (3 subsequent siblings) 6 siblings, 0 replies; 70+ messages in thread From: Jacek Piasecki @ 2017-06-26 10:59 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, Kuba Kozak, Jacek Piasecki From: Kuba Kozak <kubax.kozak@intel.com> New functions added to cfgfile library make it possible to significantly simplify the code of rte_cfgfile_load_with_params() This patch shows the new body of this function. Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> --- lib/librte_cfgfile/rte_cfgfile.c | 143 +++++---------------------------------- 1 file changed, 17 insertions(+), 126 deletions(-) diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c index 518b6ab..5625c80 100644 --- a/lib/librte_cfgfile/rte_cfgfile.c +++ b/lib/librte_cfgfile/rte_cfgfile.c @@ -207,10 +207,6 @@ struct rte_cfgfile * rte_cfgfile_load_with_params(const char *filename, int flags, const struct rte_cfgfile_parameters *params) { - int allocated_sections = CFG_ALLOC_SECTION_BATCH; - int allocated_entries = 0; - int curr_section = -1; - int curr_entry = -1; char buffer[CFG_NAME_LEN + CFG_VALUE_LEN + 4] = {0}; int lineno = 0; struct rte_cfgfile *cfg = NULL; @@ -222,28 +218,7 @@ rte_cfgfile_load_with_params(const char *filename, int flags, if (f == NULL) return NULL; - cfg = malloc(sizeof(*cfg) + sizeof(cfg->sections[0]) * - allocated_sections); - if (cfg == NULL) - goto error2; - - memset(cfg->sections, 0, sizeof(cfg->sections[0]) * allocated_sections); - - if (flags & CFG_FLAG_GLOBAL_SECTION) { - curr_section = 0; - allocated_entries = CFG_ALLOC_ENTRY_BATCH; - cfg->sections[curr_section] = malloc( - sizeof(*cfg->sections[0]) + - sizeof(cfg->sections[0]->entries[0]) * - allocated_entries); - if (cfg->sections[curr_section] == NULL) { - printf("Error - no memory for global section\n"); - goto error1; - } - - snprintf(cfg->sections[curr_section]->name, - sizeof(cfg->sections[0]->name), "GLOBAL"); - } + cfg = rte_cfgfile_create(flags); while (fgets(buffer, sizeof(buffer), f) != NULL) { char *pos = NULL; @@ -254,6 +229,7 @@ rte_cfgfile_load_with_params(const char *filename, int flags, "Check if line too long\n", lineno); goto error1; } + /* skip parsing if comment character found */ pos = memchr(buffer, params->comment_character, len); if (pos != NULL) { *pos = '\0'; @@ -261,6 +237,7 @@ rte_cfgfile_load_with_params(const char *filename, int flags, } len = _strip(buffer, len); + /* skip lines without useful content */ if (buffer[0] != '[' && memchr(buffer, '=', len) == NULL) continue; @@ -268,130 +245,44 @@ rte_cfgfile_load_with_params(const char *filename, int flags, /* section heading line */ char *end = memchr(buffer, ']', len); if (end == NULL) { - printf("Error line %d - no terminating '['" + printf("Error line %d - no terminating ']'" "character found\n", lineno); goto error1; } *end = '\0'; _strip(&buffer[1], end - &buffer[1]); - /* close off old section and add start new one */ - if (curr_section >= 0) - cfg->sections[curr_section]->num_entries = - curr_entry + 1; - curr_section++; - - /* resize overall struct if we don't have room for more - sections */ - if (curr_section == allocated_sections) { - allocated_sections += CFG_ALLOC_SECTION_BATCH; - struct rte_cfgfile *n_cfg = realloc(cfg, - sizeof(*cfg) + sizeof(cfg->sections[0]) - * allocated_sections); - if (n_cfg == NULL) { - curr_section--; - printf("Error - no more memory\n"); - goto error1; - } - cfg = n_cfg; - } - - /* allocate space for new section */ - allocated_entries = CFG_ALLOC_ENTRY_BATCH; - curr_entry = -1; - cfg->sections[curr_section] = malloc( - sizeof(*cfg->sections[0]) + - sizeof(cfg->sections[0]->entries[0]) * - allocated_entries); - if (cfg->sections[curr_section] == NULL) { - printf("Error - no more memory\n"); - goto error1; - } - - snprintf(cfg->sections[curr_section]->name, - sizeof(cfg->sections[0]->name), - "%s", &buffer[1]); + rte_cfgfile_add_section(cfg, &buffer[1]); } else { - /* value line */ - if (curr_section < 0) { - printf("Error line %d - value outside of" - "section\n", lineno); - goto error1; - } - - struct rte_cfgfile_section *sect = - cfg->sections[curr_section]; - + /* key and value line */ char *split[2] = {NULL}; + split[0] = buffer; split[1] = memchr(buffer, '=', len); + *split[1] = '\0'; + split[1]++; + + _strip(split[0], strlen(split[0])); + _strip(split[1], strlen(split[1])); - /* when delimeter not found */ - if (split[1] == NULL) { + if (!(flags & CFG_FLAG_EMPTY_VALUES) && + (*split[1] == '\0')) { printf("Error at line %d - cannot " "split string\n", lineno); goto error1; - } else { - /* when delimeter found */ - *split[1] = '\0'; - split[1]++; - - if (!(flags & CFG_FLAG_EMPTY_VALUES) && - (*split[1] == '\0')) { - printf("Error at line %d - cannot " - "split string\n", lineno); - goto error1; - } } - curr_entry++; - if (curr_entry == allocated_entries) { - allocated_entries += CFG_ALLOC_ENTRY_BATCH; - struct rte_cfgfile_section *n_sect = realloc( - sect, sizeof(*sect) + - sizeof(sect->entries[0]) * - allocated_entries); - if (n_sect == NULL) { - curr_entry--; - printf("Error - no more memory\n"); - goto error1; - } - sect = cfg->sections[curr_section] = n_sect; - } - - sect->entries[curr_entry] = malloc( - sizeof(*sect->entries[0])); - if (sect->entries[curr_entry] == NULL) { - printf("Error - no more memory\n"); + if (cfg->num_sections == 0) goto error1; - } - struct rte_cfgfile_entry *entry = sect->entries[ - curr_entry]; - snprintf(entry->name, sizeof(entry->name), "%s", - split[0]); - snprintf(entry->value, sizeof(entry->value), "%s", - split[1] ? split[1] : ""); - _strip(entry->name, strnlen(entry->name, - sizeof(entry->name))); - _strip(entry->value, strnlen(entry->value, - sizeof(entry->value))); + _add_entry(cfg->sections[cfg->num_sections - 1], + split[0], (split[1] ? split[1] : "")); } } fclose(f); - cfg->flags = flags; - cfg->num_sections = curr_section + 1; - /* curr_section will still be -1 if we have an empty file */ - if (curr_section >= 0) - cfg->sections[curr_section]->num_entries = curr_entry + 1; return cfg; - error1: - cfg->num_sections = curr_section + 1; - if (curr_section >= 0) - cfg->sections[curr_section]->num_entries = curr_entry + 1; rte_cfgfile_close(cfg); -error2: fclose(f); return NULL; } -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v2 4/7] test/cfgfile: add new unit test 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 0/7] Add support for using a config file for DPDK Jacek Piasecki ` (2 preceding siblings ...) 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 3/7] cfgfile: rework of load function Jacek Piasecki @ 2017-06-26 10:59 ` Jacek Piasecki 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 5/7] eal: add functions parsing EAL arguments Jacek Piasecki ` (2 subsequent siblings) 6 siblings, 0 replies; 70+ messages in thread From: Jacek Piasecki @ 2017-06-26 10:59 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, Jacek Piasecki Load huge realloc_sections.ini file to check malloc/realloc ability of cfgfile library. Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> --- test/test/test_cfgfile.c | 40 +++++++ test/test/test_cfgfiles/etc/realloc_sections.ini | 128 +++++++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 test/test/test_cfgfiles/etc/realloc_sections.ini diff --git a/test/test/test_cfgfile.c b/test/test/test_cfgfile.c index 4cc9b14..2278618 100644 --- a/test/test/test_cfgfile.c +++ b/test/test/test_cfgfile.c @@ -111,6 +111,7 @@ _test_cfgfile_sample(struct rte_cfgfile *cfgfile) return 0; } + static int test_cfgfile_sample1(void) { @@ -154,6 +155,42 @@ test_cfgfile_sample2(void) } static int +test_cfgfile_realloc_sections(void) +{ + struct rte_cfgfile *cfgfile; + int ret; + const char *value; + + cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/realloc_sections.ini", 0); + TEST_ASSERT_NOT_NULL(cfgfile, "Failed to load config file"); + + ret = rte_cfgfile_num_sections(cfgfile, NULL, 0); + TEST_ASSERT(ret == 9, "Unexpected number of sections: %d", ret); + + ret = rte_cfgfile_has_section(cfgfile, "section9"); + TEST_ASSERT(ret, "section9 missing"); + + ret = rte_cfgfile_section_num_entries(cfgfile, "section3"); + TEST_ASSERT(ret == 21, + "section3 unexpected number of entries: %d", ret); + + ret = rte_cfgfile_section_num_entries(cfgfile, "section9"); + TEST_ASSERT(ret == 8, "section9 unexpected number of entries: %d", ret); + + value = rte_cfgfile_get_entry(cfgfile, "section9", "key8"); + TEST_ASSERT(strcmp("value8_section9", value) == 0, + "key unexpected value: %s", value); + + ret = rte_cfgfile_save(cfgfile, "cfgfile_save.ini"); + TEST_ASSERT_SUCCESS(ret, "Failed to save *.ini file"); + + ret = rte_cfgfile_close(cfgfile); + TEST_ASSERT_SUCCESS(ret, "Failed to close cfgfile"); + + return 0; +} + +static int test_cfgfile_invalid_section_header(void) { struct rte_cfgfile *cfgfile; @@ -292,6 +329,9 @@ test_cfgfile(void) if (test_cfgfile_sample2()) return -1; + if (test_cfgfile_realloc_sections()) + return -1; + if (test_cfgfile_invalid_section_header()) return -1; diff --git a/test/test/test_cfgfiles/etc/realloc_sections.ini b/test/test/test_cfgfiles/etc/realloc_sections.ini new file mode 100644 index 0000000..e653e40 --- /dev/null +++ b/test/test/test_cfgfiles/etc/realloc_sections.ini @@ -0,0 +1,128 @@ +[section1] +key1=value1_section1 +key2=value2_section1 +key3=value3_section1 +key4=value4_section1 +key5=value5_section1 +key6=value6_section1 +key7=value7_section1 +key8=value8_section1 +key9=value9_section1 +key10=value10_section1 +key11=value11_section1 +key12=value12_section1 +key13=value13_section1 +key14=value14_section1 +key15=value15_section1 +key16=value16_section1 +key17=value17_section1 +key18=value18_section1 +key19=value19_section1 +key20=value20_section1 +key21=value21_section1 + +[section2] +key1=value1_section2 +key2=value2_section2 +key3=value3_section2 +key4=value4_section2 +key5=value5_section2 +key6=value6_section2 +key7=value7_section2 +key8=value8_section2 +key9=value9_section2 +key10=value10_section2 +key11=value11_section2 +key12=value12_section2 +key13=value13_section2 +key14=value14_section2 +key15=value15_section2 +key16=value16_section2 +key17=value17_section2 +key18=value18_section2 +key19=value19_section2 +key20=value20_section2 +key21=value21_section2 + +[section3] +key1=value1_section3 +key2=value2_section3 +key3=value3_section3 +key4=value4_section3 +key5=value5_section3 +key6=value6_section3 +key7=value7_section3 +key8=value8_section3 +key9=value9_section3 +key10=value10_section3 +key11=value11_section3 +key12=value12_section3 +key13=value13_section3 +key14=value14_section3 +key15=value15_section3 +key16=value16_section3 +key17=value17_section3 +key18=value18_section3 +key19=value19_section3 +key20=value20_section3 +key21=value21_section3 + +[section4] +key1=value1_section4 +key2=value2_section4 +key3=value3_section4 +key4=value4_section4 +key5=value5_section4 +key6=value6_section4 +key7=value7_section4 +key8=value8_section4 + +[section5] +key1=value1_section5 +key2=value2_section5 +key3=value3_section5 +key4=value4_section5 +key5=value5_section5 +key6=value6_section5 +key7=value7_section5 +key8=value8_section5 + +[section6] +key1=value1_section6 +key2=value2_section6 +key3=value3_section6 +key4=value4_section6 +key5=value5_section6 +key6=value6_section6 +key7=value7_section6 +key8=value8_section6 + +[section7] +key1=value1_section7 +key2=value2_section7 +key3=value3_section7 +key4=value4_section7 +key5=value5_section7 +key6=value6_section7 +key7=value7_section7 +key8=value8_section7 + +[section8] +key1=value1_section8 +key2=value2_section8 +key3=value3_section8 +key4=value4_section8 +key5=value5_section8 +key6=value6_section8 +key7=value7_section8 +key8=value8_section8 + +[section9] +key1=value1_section9 +key2=value2_section9 +key3=value3_section9 +key4=value4_section9 +key5=value5_section9 +key6=value6_section9 +key7=value7_section9 +key8=value8_section9 -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v2 5/7] eal: add functions parsing EAL arguments 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 0/7] Add support for using a config file for DPDK Jacek Piasecki ` (3 preceding siblings ...) 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 4/7] test/cfgfile: add new unit test Jacek Piasecki @ 2017-06-26 10:59 ` Jacek Piasecki 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 0/3] EAL change for using a config file for DPDK Jacek Piasecki 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 6/7] app/testpmd: changed example to parse options from cfg file Jacek Piasecki 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 7/7] app/testpmd: add parse arguments from JSON config file Jacek Piasecki 6 siblings, 1 reply; 70+ messages in thread From: Jacek Piasecki @ 2017-06-26 10:59 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, Kuba Kozak 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> --- 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 # # 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 -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v3 0/3] EAL change for using a config file for DPDK 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 5/7] eal: add functions parsing EAL arguments Jacek Piasecki @ 2017-06-27 10:52 ` Jacek Piasecki 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 1/3] eal: add functions parsing EAL arguments Jacek Piasecki ` (3 more replies) 0 siblings, 4 replies; 70+ messages in thread From: Jacek Piasecki @ 2017-06-27 10:52 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, Jacek Piasecki 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. Testpmd application is used to the 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. Last patch demonstrates the usage of JSON file format insted of config.ini JSON file can be called the same way as above, thru --cfgfile-path <path> --- 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: changed example to parse options from cfg file app/testpmd: add parse arguments from JSON config file app/test-pmd/Makefile | 6 + app/test-pmd/config.ini | 24 + app/test-pmd/config.json | 33 + app/test-pmd/parameters.c | 1193 +++++++++++++---------- app/test-pmd/testpmd.c | 159 ++- app/test-pmd/testpmd.h | 3 +- config/common_base | 6 + 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 +- 19 files changed, 1469 insertions(+), 631 deletions(-) create mode 100644 app/test-pmd/config.ini create mode 100644 app/test-pmd/config.json -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v3 1/3] eal: add functions parsing EAL arguments 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 0/3] EAL change for using a config file for DPDK Jacek Piasecki @ 2017-06-27 10:52 ` Jacek Piasecki 2017-06-30 16:04 ` Bruce Richardson ` (2 more replies) 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 2/3] app/testpmd: changed example to parse options from " Jacek Piasecki ` (2 subsequent siblings) 3 siblings, 3 replies; 70+ messages in thread From: Jacek Piasecki @ 2017-06-27 10:52 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, Kuba Kozak 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(-) 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 -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v3 1/3] eal: add functions parsing EAL arguments 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 1/3] eal: add functions parsing EAL arguments Jacek Piasecki @ 2017-06-30 16:04 ` Bruce Richardson 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 0/5] Rework cfgfile API to enable apps config file support Jacek Piasecki 2017-07-10 12:51 ` [dpdk-dev] [PATCH v4 0/3] EAL change for using a config file for DPDK Kuba Kozak 2 siblings, 0 replies; 70+ messages in thread From: Bruce Richardson @ 2017-06-30 16:04 UTC (permalink / raw) To: Jacek Piasecki; +Cc: dev, deepak.k.jain, Kuba Kozak 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 > ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v4 0/5] Rework cfgfile API to enable apps config file support 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 1/3] eal: add functions parsing EAL arguments Jacek Piasecki 2017-06-30 16:04 ` Bruce Richardson @ 2017-07-10 12:44 ` Jacek Piasecki 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 1/5] cfgfile: remove EAL dependency Jacek Piasecki ` (5 more replies) 2017-07-10 12:51 ` [dpdk-dev] [PATCH v4 0/3] EAL change for using a config file for DPDK Kuba Kozak 2 siblings, 6 replies; 70+ messages in thread From: Jacek Piasecki @ 2017-07-10 12:44 UTC (permalink / raw) To: dev Cc: bruce.richardson, deepak.k.jain, kubax.kozak, michalx.k.jastrzebski, 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 -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v4 1/5] cfgfile: remove EAL dependency 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 0/5] Rework cfgfile API to enable apps config file support Jacek Piasecki @ 2017-07-10 12:44 ` Jacek Piasecki 2017-08-30 17:58 ` Bruce Richardson 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 2/5] cfgfile: change existing API functions Jacek Piasecki ` (4 subsequent siblings) 5 siblings, 1 reply; 70+ messages in thread From: Jacek Piasecki @ 2017-07-10 12:44 UTC (permalink / raw) To: dev Cc: bruce.richardson, deepak.k.jain, kubax.kozak, michalx.k.jastrzebski, Jacek Piasecki This patch removes the dependency to EAL in cfgfile library. Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> --- lib/Makefile | 3 +-- lib/librte_cfgfile/Makefile | 1 + lib/librte_cfgfile/rte_cfgfile.c | 29 +++++++++++++++++------------ 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index 07e1fd0..cf47a2a 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -32,6 +32,7 @@ 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 DIRS-$(CONFIG_RTE_LIBRTE_RING) += librte_ring DEPDIRS-librte_ring := librte_eal @@ -41,8 +42,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_cfgfile/Makefile b/lib/librte_cfgfile/Makefile index 755ef11..0bee43e 100644 --- a/lib/librte_cfgfile/Makefile +++ b/lib/librte_cfgfile/Makefile @@ -38,6 +38,7 @@ LIB = librte_cfgfile.a CFLAGS += -O3 CFLAGS += $(WERROR_FLAGS) +CFLAGS += -I$(SRCDIR)/../librte_eal/common/include EXPORT_MAP := rte_cfgfile_version.map diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c index b54a523..c6ae3e3 100644 --- a/lib/librte_cfgfile/rte_cfgfile.c +++ b/lib/librte_cfgfile/rte_cfgfile.c @@ -36,7 +36,6 @@ #include <string.h> #include <ctype.h> #include <rte_common.h> -#include <rte_string_fns.h> #include "rte_cfgfile.h" @@ -258,19 +257,25 @@ rte_cfgfile_load_with_params(const char *filename, int flags, struct rte_cfgfile_section *sect = cfg->sections[curr_section]; - int n; + char *split[2] = {NULL}; - n = rte_strsplit(buffer, sizeof(buffer), split, 2, '='); - if (flags & CFG_FLAG_EMPTY_VALUES) { - if ((n < 1) || (n > 2)) { - printf("Error at line %d - cannot split string, n=%d\n", - lineno, n); - goto error1; - } + split[0] = buffer; + split[1] = memchr(buffer, '=', len); + + /* when delimeter not found */ + if (split[1] == NULL) { + printf("Error at line %d - cannot " + "split string\n", lineno); + goto error1; } else { - if (n != 2) { - printf("Error at line %d - cannot split string, n=%d\n", - lineno, n); + /* when delimeter found */ + *split[1] = '\0'; + split[1]++; + + if (!(flags & CFG_FLAG_EMPTY_VALUES) && + (*split[1] == '\0')) { + printf("Error at line %d - cannot " + "split string\n", lineno); goto error1; } } -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v4 1/5] cfgfile: remove EAL dependency 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 1/5] cfgfile: remove EAL dependency Jacek Piasecki @ 2017-08-30 17:58 ` Bruce Richardson 0 siblings, 0 replies; 70+ messages in thread From: Bruce Richardson @ 2017-08-30 17:58 UTC (permalink / raw) To: Jacek Piasecki; +Cc: dev, deepak.k.jain, kubax.kozak, michalx.k.jastrzebski On Mon, Jul 10, 2017 at 02:44:13PM +0200, Jacek Piasecki wrote: > This patch removes the dependency to EAL in cfgfile library. > > Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> Looks ok to me Acked-by: Bruce Richardson <bruce.richardson@intel.com> ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v4 2/5] cfgfile: change existing API functions 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 0/5] Rework cfgfile API to enable apps config file support Jacek Piasecki 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 1/5] cfgfile: remove EAL dependency Jacek Piasecki @ 2017-07-10 12:44 ` Jacek Piasecki 2017-08-30 20:07 ` Bruce Richardson 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 3/5] cfgfile: add new functions to API Jacek Piasecki ` (3 subsequent siblings) 5 siblings, 1 reply; 70+ messages in thread From: Jacek Piasecki @ 2017-07-10 12:44 UTC (permalink / raw) To: dev Cc: bruce.richardson, deepak.k.jain, kubax.kozak, michalx.k.jastrzebski, Jacek Piasecki Change to flat arrays in cfgfile struct force slightly diffrent data access for most of cfgfile functions. This patch provides necessary changes in existing API. Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> --- lib/librte_cfgfile/rte_cfgfile.c | 120 +++++++++++++++++++-------------------- lib/librte_cfgfile/rte_cfgfile.h | 6 +- 2 files changed, 62 insertions(+), 64 deletions(-) diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c index c6ae3e3..50fe37a 100644 --- a/lib/librte_cfgfile/rte_cfgfile.c +++ b/lib/librte_cfgfile/rte_cfgfile.c @@ -35,6 +35,7 @@ #include <stdlib.h> #include <string.h> #include <ctype.h> +#include <errno.h> #include <rte_common.h> #include "rte_cfgfile.h" @@ -42,13 +43,15 @@ struct rte_cfgfile_section { char name[CFG_NAME_LEN]; int num_entries; - struct rte_cfgfile_entry *entries[0]; + int allocated_entries; + struct rte_cfgfile_entry *entries; }; struct rte_cfgfile { int flags; int num_sections; - struct rte_cfgfile_section *sections[0]; + int allocated_sections; + struct rte_cfgfile_section *sections; }; /** when we resize a file structure, how many extra entries @@ -104,6 +107,19 @@ _strip(char *str, unsigned len) return newlen; } +static struct rte_cfgfile_section * +_get_section(struct rte_cfgfile *cfg, const char *sectionname) +{ + int i; + + for (i = 0; i < cfg->num_sections; i++) { + if (strncmp(cfg->sections[i].name, sectionname, + sizeof(cfg->sections[0].name)) == 0) + return &cfg->sections[i]; + } + return NULL; +} + static int rte_cfgfile_check_params(const struct rte_cfgfile_parameters *params) { @@ -168,17 +184,17 @@ rte_cfgfile_load_with_params(const char *filename, int flags, if (flags & CFG_FLAG_GLOBAL_SECTION) { curr_section = 0; allocated_entries = CFG_ALLOC_ENTRY_BATCH; - cfg->sections[curr_section] = malloc( - sizeof(*cfg->sections[0]) + - sizeof(cfg->sections[0]->entries[0]) * + cfg->sections = malloc( + sizeof(cfg->sections[0]) + + sizeof(cfg->sections[0].entries) * allocated_entries); - if (cfg->sections[curr_section] == NULL) { + if (cfg->sections == NULL) { printf("Error - no memory for global section\n"); goto error1; } - snprintf(cfg->sections[curr_section]->name, - sizeof(cfg->sections[0]->name), "GLOBAL"); + snprintf(cfg->sections[curr_section].name, + sizeof(cfg->sections[0].name), "GLOBAL"); } while (fgets(buffer, sizeof(buffer), f) != NULL) { @@ -213,7 +229,7 @@ rte_cfgfile_load_with_params(const char *filename, int flags, /* close off old section and add start new one */ if (curr_section >= 0) - cfg->sections[curr_section]->num_entries = + cfg->sections[curr_section].num_entries = curr_entry + 1; curr_section++; @@ -235,17 +251,17 @@ rte_cfgfile_load_with_params(const char *filename, int flags, /* allocate space for new section */ allocated_entries = CFG_ALLOC_ENTRY_BATCH; curr_entry = -1; - cfg->sections[curr_section] = malloc( - sizeof(*cfg->sections[0]) + - sizeof(cfg->sections[0]->entries[0]) * + cfg->sections = malloc( + sizeof(cfg->sections[0]) + + sizeof(cfg->sections[0].entries) * allocated_entries); - if (cfg->sections[curr_section] == NULL) { + if (cfg->sections == NULL) { printf("Error - no more memory\n"); goto error1; } - snprintf(cfg->sections[curr_section]->name, - sizeof(cfg->sections[0]->name), + snprintf(cfg->sections[curr_section].name, + sizeof(cfg->sections[0].name), "%s", &buffer[1]); } else { /* value line */ @@ -255,8 +271,7 @@ rte_cfgfile_load_with_params(const char *filename, int flags, goto error1; } - struct rte_cfgfile_section *sect = - cfg->sections[curr_section]; + struct rte_cfgfile_section *sect = cfg->sections; char *split[2] = {NULL}; split[0] = buffer; @@ -292,18 +307,17 @@ rte_cfgfile_load_with_params(const char *filename, int flags, printf("Error - no more memory\n"); goto error1; } - sect = cfg->sections[curr_section] = n_sect; + sect = cfg->sections = n_sect; } - sect->entries[curr_entry] = malloc( - sizeof(*sect->entries[0])); - if (sect->entries[curr_entry] == NULL) { + sect->entries = malloc( + sizeof(sect->entries[0])); + if (sect->entries == NULL) { printf("Error - no more memory\n"); goto error1; } - struct rte_cfgfile_entry *entry = sect->entries[ - curr_entry]; + struct rte_cfgfile_entry *entry = sect->entries; snprintf(entry->name, sizeof(entry->name), "%s", split[0]); snprintf(entry->value, sizeof(entry->value), "%s", @@ -319,42 +333,38 @@ rte_cfgfile_load_with_params(const char *filename, int flags, cfg->num_sections = curr_section + 1; /* curr_section will still be -1 if we have an empty file */ if (curr_section >= 0) - cfg->sections[curr_section]->num_entries = curr_entry + 1; + cfg->sections[curr_section].num_entries = curr_entry + 1; return cfg; error1: cfg->num_sections = curr_section + 1; if (curr_section >= 0) - cfg->sections[curr_section]->num_entries = curr_entry + 1; + cfg->sections[curr_section].num_entries = curr_entry + 1; rte_cfgfile_close(cfg); error2: fclose(f); return NULL; } - int rte_cfgfile_close(struct rte_cfgfile *cfg) { - int i, j; + int i; if (cfg == NULL) return -1; - for (i = 0; i < cfg->num_sections; i++) { - if (cfg->sections[i] != NULL) { - if (cfg->sections[i]->num_entries) { - for (j = 0; j < cfg->sections[i]->num_entries; - j++) { - if (cfg->sections[i]->entries[j] != - NULL) - free(cfg->sections[i]-> - entries[j]); - } + if (cfg->sections != NULL) { + for (i = 0; i < cfg->allocated_sections; i++) { + if (cfg->sections[i].entries != NULL) { + free(cfg->sections[i].entries); + cfg->sections[i].entries = NULL; } - free(cfg->sections[i]); } + free(cfg->sections); + cfg->sections = NULL; } free(cfg); + cfg = NULL; return 0; } @@ -366,7 +376,7 @@ size_t length) int i; int num_sections = 0; for (i = 0; i < cfg->num_sections; i++) { - if (strncmp(cfg->sections[i]->name, sectionname, length) == 0) + if (strncmp(cfg->sections[i].name, sectionname, length) == 0) num_sections++; } return num_sections; @@ -380,23 +390,11 @@ rte_cfgfile_sections(struct rte_cfgfile *cfg, char *sections[], for (i = 0; i < cfg->num_sections && i < max_sections; i++) snprintf(sections[i], CFG_NAME_LEN, "%s", - cfg->sections[i]->name); + cfg->sections[i].name); return i; } -static const struct rte_cfgfile_section * -_get_section(struct rte_cfgfile *cfg, const char *sectionname) -{ - int i; - for (i = 0; i < cfg->num_sections; i++) { - if (strncmp(cfg->sections[i]->name, sectionname, - sizeof(cfg->sections[0]->name)) == 0) - return cfg->sections[i]; - } - return NULL; -} - int rte_cfgfile_has_section(struct rte_cfgfile *cfg, const char *sectionname) { @@ -409,7 +407,7 @@ rte_cfgfile_section_num_entries(struct rte_cfgfile *cfg, { const struct rte_cfgfile_section *s = _get_section(cfg, sectionname); if (s == NULL) - return -1; + return -EINVAL; return s->num_entries; } @@ -421,9 +419,9 @@ rte_cfgfile_section_entries(struct rte_cfgfile *cfg, const char *sectionname, int i; const struct rte_cfgfile_section *sect = _get_section(cfg, sectionname); if (sect == NULL) - return -1; + return -EINVAL; for (i = 0; i < max_entries && i < sect->num_entries; i++) - entries[i] = *sect->entries[i]; + entries[i] = sect->entries[i]; return i; } @@ -436,12 +434,12 @@ rte_cfgfile_section_entries_by_index(struct rte_cfgfile *cfg, int index, const struct rte_cfgfile_section *sect; if (index < 0 || index >= cfg->num_sections) - return -1; + return -EINVAL; - sect = cfg->sections[index]; + sect = &cfg->sections[index]; snprintf(sectionname, CFG_NAME_LEN, "%s", sect->name); for (i = 0; i < max_entries && i < sect->num_entries; i++) - entries[i] = *sect->entries[i]; + entries[i] = sect->entries[i]; return i; } @@ -454,9 +452,9 @@ rte_cfgfile_get_entry(struct rte_cfgfile *cfg, const char *sectionname, if (sect == NULL) return NULL; for (i = 0; i < sect->num_entries; i++) - if (strncmp(sect->entries[i]->name, entryname, CFG_NAME_LEN) - == 0) - return sect->entries[i]->value; + if (strncmp(sect->entries[i].name, entryname, CFG_NAME_LEN) + == 0) + return sect->entries[i].value; return NULL; } diff --git a/lib/librte_cfgfile/rte_cfgfile.h b/lib/librte_cfgfile/rte_cfgfile.h index fa10d40..4702110 100644 --- a/lib/librte_cfgfile/rte_cfgfile.h +++ b/lib/librte_cfgfile/rte_cfgfile.h @@ -178,7 +178,7 @@ int rte_cfgfile_has_section(struct rte_cfgfile *cfg, const char *sectionname); * @param sectionname * Section name * @return -* Number of entries in section on success, -1 otherwise +* Number of entries in section on success, -EINVAL otherwise */ int rte_cfgfile_section_num_entries(struct rte_cfgfile *cfg, const char *sectionname); @@ -199,7 +199,7 @@ int rte_cfgfile_section_num_entries(struct rte_cfgfile *cfg, * @param max_entries * Maximum number of section entries to be stored in entries array * @return -* Number of entries populated on success, -1 otherwise +* Number of entries populated on success, -EINVAL otherwise */ int rte_cfgfile_section_entries(struct rte_cfgfile *cfg, const char *sectionname, @@ -226,7 +226,7 @@ int rte_cfgfile_section_entries(struct rte_cfgfile *cfg, * @param max_entries * Maximum number of section entries to be stored in entries array * @return -* Number of entries populated on success, -1 otherwise +* Number of entries populated on success, -EINVAL otherwise */ int rte_cfgfile_section_entries_by_index(struct rte_cfgfile *cfg, int index, -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v4 2/5] cfgfile: change existing API functions 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 2/5] cfgfile: change existing API functions Jacek Piasecki @ 2017-08-30 20:07 ` Bruce Richardson 0 siblings, 0 replies; 70+ messages in thread From: Bruce Richardson @ 2017-08-30 20:07 UTC (permalink / raw) To: Jacek Piasecki; +Cc: dev, deepak.k.jain, kubax.kozak, michalx.k.jastrzebski I think the commit title needs rewording. This changes the internals not the API. On Mon, Jul 10, 2017 at 02:44:14PM +0200, Jacek Piasecki wrote: > Change to flat arrays in cfgfile struct force slightly > diffrent data access for most of cfgfile functions. > This patch provides necessary changes in existing API. > > Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> > --- Some comments below. I believe the change in return value from -1 to -EINVAL, though a more correct error, actually counts as an ABI change, so I think that should be removed, i.e. keep errors at -1. Once done: Acked-by: Bruce Richardon <bruce.richardson@intel.com> > lib/librte_cfgfile/rte_cfgfile.c | 120 +++++++++++++++++++-------------------- > lib/librte_cfgfile/rte_cfgfile.h | 6 +- > 2 files changed, 62 insertions(+), 64 deletions(-) > > diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c > index c6ae3e3..50fe37a 100644 > --- a/lib/librte_cfgfile/rte_cfgfile.c > +++ b/lib/librte_cfgfile/rte_cfgfile.c > @@ -35,6 +35,7 @@ > #include <stdlib.h> > #include <string.h> > #include <ctype.h> > +#include <errno.h> > #include <rte_common.h> > > #include "rte_cfgfile.h" > @@ -42,13 +43,15 @@ > struct rte_cfgfile_section { > char name[CFG_NAME_LEN]; > int num_entries; > - struct rte_cfgfile_entry *entries[0]; > + int allocated_entries; > + struct rte_cfgfile_entry *entries; > }; > > struct rte_cfgfile { > int flags; > int num_sections; > - struct rte_cfgfile_section *sections[0]; > + int allocated_sections; > + struct rte_cfgfile_section *sections; > }; > These are good changes, allowing us to have the sections array and entries arrays separate from the basic data structures. <snip> > @@ -409,7 +407,7 @@ rte_cfgfile_section_num_entries(struct rte_cfgfile *cfg, > { > const struct rte_cfgfile_section *s = _get_section(cfg, sectionname); > if (s == NULL) > - return -1; > + return -EINVAL; > return s->num_entries; > } I think this change should be dropped for backward compatibility, or else put in NEXT_ABI #ifdefs and an ABI notice added to the RN. ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v4 3/5] cfgfile: add new functions to API 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 0/5] Rework cfgfile API to enable apps config file support Jacek Piasecki 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 1/5] cfgfile: remove EAL dependency Jacek Piasecki 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 2/5] cfgfile: change existing API functions Jacek Piasecki @ 2017-07-10 12:44 ` Jacek Piasecki 2017-08-30 20:18 ` Bruce Richardson 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 4/5] cfgfile: rework of load function Jacek Piasecki ` (2 subsequent siblings) 5 siblings, 1 reply; 70+ messages in thread From: Jacek Piasecki @ 2017-07-10 12:44 UTC (permalink / raw) To: dev Cc: bruce.richardson, deepak.k.jain, kubax.kozak, michalx.k.jastrzebski, Jacek Piasecki Extend existing cfgfile library with providing new API functions: rte_cfgfile_create() - create new cfgfile object rte_cfgfile_add_section() - add new section to existing cfgfile object rte_cfgfile_add_entry() - add new entry to existing cfgfile object in specified section rte_cfgfile_set_entry() - update existing entry in cfgfile object rte_cfgfile_save() - save existing cfgfile object to INI file This modification allows to create a cfgfile on runtime and opens up the possibility to have applications dynamically build up a proper DPDK configuration, rather than having to have a pre-existing one. Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> --- lib/librte_cfgfile/rte_cfgfile.c | 186 +++++++++++++++++++++++++++++ lib/librte_cfgfile/rte_cfgfile.h | 76 ++++++++++++ lib/librte_cfgfile/rte_cfgfile_version.map | 11 ++ 3 files changed, 273 insertions(+) diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c index 50fe37a..225e42a 100644 --- a/lib/librte_cfgfile/rte_cfgfile.c +++ b/lib/librte_cfgfile/rte_cfgfile.c @@ -121,6 +121,36 @@ _get_section(struct rte_cfgfile *cfg, const char *sectionname) } static int +_add_entry(struct rte_cfgfile_section *section, const char *entryname, + const char *entryvalue) +{ + /* resize entry structure if we don't have room for more entries */ + if (section->num_entries == section->allocated_entries) { + struct rte_cfgfile_entry *n_entries = realloc( + section->entries, + sizeof(struct rte_cfgfile_entry) * + ((section->allocated_entries) + + CFG_ALLOC_ENTRY_BATCH)); + + if (n_entries == NULL) + return -ENOMEM; + + section->entries = n_entries; + section->allocated_entries += CFG_ALLOC_ENTRY_BATCH; + } + /* fill up entry fields with key name and value */ + struct rte_cfgfile_entry *curr_entry = + §ion->entries[section->num_entries]; + + snprintf(curr_entry->name, sizeof(curr_entry->name), "%s", entryname); + snprintf(curr_entry->value, + sizeof(curr_entry->value), "%s", entryvalue); + section->num_entries++; + + return 0; +} + +static int rte_cfgfile_check_params(const struct rte_cfgfile_parameters *params) { unsigned int valid_comment; @@ -346,6 +376,162 @@ rte_cfgfile_load_with_params(const char *filename, int flags, return NULL; } +struct rte_cfgfile * +rte_cfgfile_create(int flags) +{ + int i; + struct rte_cfgfile *cfg = NULL; + + cfg = malloc(sizeof(*cfg)); + + if (cfg == NULL) + return NULL; + + cfg->flags = flags; + cfg->num_sections = 0; + + /* allocate first batch of sections and entries */ + cfg->sections = malloc(sizeof(struct rte_cfgfile_section) * + CFG_ALLOC_SECTION_BATCH); + + if (cfg->sections == NULL) + return NULL; + + cfg->allocated_sections = CFG_ALLOC_SECTION_BATCH; + + for (i = 0; i < CFG_ALLOC_SECTION_BATCH; i++) { + cfg->sections[i].entries = malloc(sizeof( + struct rte_cfgfile_entry) * CFG_ALLOC_ENTRY_BATCH); + + if (cfg->sections[i].entries == NULL) + return NULL; + + cfg->sections[i].num_entries = 0; + cfg->sections[i].allocated_entries = CFG_ALLOC_ENTRY_BATCH; + } + + if (flags & CFG_FLAG_GLOBAL_SECTION) + rte_cfgfile_add_section(cfg, "GLOBAL"); + return cfg; +} + +int +rte_cfgfile_add_section(struct rte_cfgfile *cfg, const char *sectionname) +{ + int i; + + if (cfg == NULL) + return -EINVAL; + + if (sectionname == NULL) + return -EINVAL; + + /* resize overall struct if we don't have room for more sections */ + if (cfg->num_sections == cfg->allocated_sections) { + + struct rte_cfgfile_section *n_sections = + realloc(cfg->sections, + sizeof(struct rte_cfgfile_section) * + ((cfg->allocated_sections) + + CFG_ALLOC_SECTION_BATCH)); + + if (n_sections == NULL) + return -ENOMEM; + + for (i = 0; i < CFG_ALLOC_SECTION_BATCH; i++) { + n_sections[i + cfg->allocated_sections].num_entries = 0; + n_sections[i + + cfg->allocated_sections].allocated_entries = 0; + n_sections[i + cfg->allocated_sections].entries = NULL; + } + cfg->sections = n_sections; + cfg->allocated_sections += CFG_ALLOC_SECTION_BATCH; + } + + snprintf(cfg->sections[cfg->num_sections].name, + sizeof(cfg->sections[0].name), "%s", sectionname); + cfg->sections[cfg->num_sections].num_entries = 0; + cfg->num_sections++; + + return 0; +} + +int rte_cfgfile_add_entry(struct rte_cfgfile *cfg, + const char *sectionname, const char *entryname, + const char *entryvalue) +{ + int ret; + + if ((cfg == NULL) || (sectionname == NULL) || (entryname == NULL) + || (entryvalue == NULL)) + return -EINVAL; + + if (rte_cfgfile_has_entry(cfg, sectionname, entryname) != 0) + return -EEXIST; + + /* search for section pointer by sectionname */ + struct rte_cfgfile_section *curr_section = _get_section(cfg, + sectionname); + if (curr_section == NULL) + return -EINVAL; + + ret = _add_entry(curr_section, entryname, entryvalue); + + return ret; +} + +int rte_cfgfile_set_entry(struct rte_cfgfile *cfg, const char *sectionname, + const char *entryname, const char *entryvalue) +{ + int i; + + if ((cfg == NULL) || (sectionname == NULL) || (entryname == NULL)) + return -EINVAL; + + /* search for section pointer by sectionname */ + struct rte_cfgfile_section *curr_section = _get_section(cfg, + sectionname); + if (curr_section == NULL) + return -EINVAL; + + if (entryvalue == NULL) + entryvalue = ""; + + for (i = 0; i < curr_section->num_entries; i++) + if (!strcmp(curr_section->entries[i].name, entryname)) { + snprintf(curr_section->entries[i].value, + sizeof(curr_section->entries[i].value), + "%s", entryvalue); + return 0; + } + printf("Error - entry name doesn't exist\n"); + return -EINVAL; +} + +int rte_cfgfile_save(struct rte_cfgfile *cfg, const char *filename) +{ + int i, j; + + if ((cfg == NULL) || (filename == NULL)) + return -EINVAL; + + FILE *f = fopen(filename, "w"); + + if (f == NULL) + return -EINVAL; + + for (i = 0; i < cfg->num_sections; i++) { + fprintf(f, "[%s]\n", cfg->sections[i].name); + + for (j = 0; j < cfg->sections[i].num_entries; j++) { + fprintf(f, "%s=%s\n", + cfg->sections[i].entries[j].name, + cfg->sections[i].entries[j].value); + } + } + return fclose(f); +} + int rte_cfgfile_close(struct rte_cfgfile *cfg) { int i; diff --git a/lib/librte_cfgfile/rte_cfgfile.h b/lib/librte_cfgfile/rte_cfgfile.h index 4702110..8431b86 100644 --- a/lib/librte_cfgfile/rte_cfgfile.h +++ b/lib/librte_cfgfile/rte_cfgfile.h @@ -121,6 +121,82 @@ struct rte_cfgfile *rte_cfgfile_load_with_params(const char *filename, int flags, const struct rte_cfgfile_parameters *params); /** + * Create new cfgfile instance with empty sections and entries + * + * @param flags + * - CFG_FLAG_GLOBAL_SECTION + * Indicates that the file supports key value entries before the first + * defined section. These entries can be accessed in the "GLOBAL" + * section. + * - CFG_FLAG_EMPTY_VALUES + * Indicates that file supports key value entries where the value can + * be zero length (e.g., "key="). + * @return + * Handle to cfgfile instance on success, NULL otherwise + */ +struct rte_cfgfile *rte_cfgfile_create(int flags); + +/** + * Add section in cfgfile instance. + * + * @param cfg + * Pointer to the cfgfile structure. + * @param sectionname + * Section name which will be add to cfgfile. + * @return + * 0 on success, -ENOMEM if can't add section + */ +int +rte_cfgfile_add_section(struct rte_cfgfile *cfg, const char *sectionname); + +/** + * Add entry to specified section in cfgfile instance. + * + * @param cfg + * Pointer to the cfgfile structure. + * @param sectionname + * Given section name to add an entry. + * @param entryname + * Entry name to add. + * @param entryvalue + * Entry value to add. + * @return + * 0 on success, -EEXIST if entry already exist, -EINVAL if bad argument + */ +int rte_cfgfile_add_entry(struct rte_cfgfile *cfg, + const char *sectionname, const char *entryname, + const char *entryvalue); + +/** + * Update value of specified entry name in given section in config file + * + * @param cfg + * Config file + * @param sectionname + * Section name + * @param entryname + * Entry name to look for the value change + * @param entryvalue + * New entry value. Can be also an empty string if CFG_FLAG_EMPTY_VALUES = 1 + * @return + * 0 on success, -EINVAL if bad argument + */ +int rte_cfgfile_set_entry(struct rte_cfgfile *cfg, const char *sectionname, + const char *entryname, const char *entryvalue); + +/** + * Save object cfgfile to file on disc + * + * @param cfg + * Config file structure + * @param filename + * File name to save data + * @return + * 0 on success, errno otherwise + */ +int rte_cfgfile_save(struct rte_cfgfile *cfg, const char *filename); + +/** * Get number of sections in config file * * @param cfg diff --git a/lib/librte_cfgfile/rte_cfgfile_version.map b/lib/librte_cfgfile/rte_cfgfile_version.map index 5fe60f7..de68ff6 100644 --- a/lib/librte_cfgfile/rte_cfgfile_version.map +++ b/lib/librte_cfgfile/rte_cfgfile_version.map @@ -27,3 +27,14 @@ DPDK_17.05 { rte_cfgfile_load_with_params; } DPDK_16.04; + +DPDK_17.08 { + global: + + rte_cfgfile_add_entry; + rte_cfgfile_add_section; + rte_cfgfile_create; + rte_cfgfile_save; + rte_cfgfile_set_entry; + +} DPDK_17.05; \ No newline at end of file -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v4 3/5] cfgfile: add new functions to API 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 3/5] cfgfile: add new functions to API Jacek Piasecki @ 2017-08-30 20:18 ` Bruce Richardson 0 siblings, 0 replies; 70+ messages in thread From: Bruce Richardson @ 2017-08-30 20:18 UTC (permalink / raw) To: Jacek Piasecki; +Cc: dev, deepak.k.jain, kubax.kozak, michalx.k.jastrzebski Title needs a reword to indicate the types of new API functions e.g.: cfgfile: add APIs for cfgfile modification On Mon, Jul 10, 2017 at 02:44:15PM +0200, Jacek Piasecki wrote: > Extend existing cfgfile library with providing new API functions: > > rte_cfgfile_create() - create new cfgfile object > rte_cfgfile_add_section() - add new section to existing cfgfile > object > rte_cfgfile_add_entry() - add new entry to existing cfgfile > object in specified section > rte_cfgfile_set_entry() - update existing entry in cfgfile object > rte_cfgfile_save() - save existing cfgfile object to INI file > > This modification allows to create a cfgfile on > runtime and opens up the possibility to have applications > dynamically build up a proper DPDK configuration, rather than having > to have a pre-existing one. > > Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> > --- Good additions Acked-by: Bruce Richardson <bruce.richardson@intel.com> ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v4 4/5] cfgfile: rework of load function 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 0/5] Rework cfgfile API to enable apps config file support Jacek Piasecki ` (2 preceding siblings ...) 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 3/5] cfgfile: add new functions to API Jacek Piasecki @ 2017-07-10 12:44 ` Jacek Piasecki 2017-08-30 20:24 ` Bruce Richardson 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 5/5] test/cfgfile: add new unit test Jacek Piasecki 2017-07-10 15:13 ` [dpdk-dev] [PATCH v4 0/5] Rework cfgfile API to enable apps config file support Thomas Monjalon 5 siblings, 1 reply; 70+ messages in thread From: Jacek Piasecki @ 2017-07-10 12:44 UTC (permalink / raw) To: dev Cc: bruce.richardson, deepak.k.jain, kubax.kozak, michalx.k.jastrzebski, Jacek Piasecki New functions added to cfgfile library make it possible to significantly simplify the code of rte_cfgfile_load_with_params() This patch shows the new body of this function. Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> --- lib/librte_cfgfile/rte_cfgfile.c | 156 ++++++++------------------------------- 1 file changed, 29 insertions(+), 127 deletions(-) diff --git a/lib/librte_cfgfile/rte_cfgfile.c b/lib/librte_cfgfile/rte_cfgfile.c index 225e42a..e2e7307 100644 --- a/lib/librte_cfgfile/rte_cfgfile.c +++ b/lib/librte_cfgfile/rte_cfgfile.c @@ -189,10 +189,6 @@ struct rte_cfgfile * rte_cfgfile_load_with_params(const char *filename, int flags, const struct rte_cfgfile_parameters *params) { - int allocated_sections = CFG_ALLOC_SECTION_BATCH; - int allocated_entries = 0; - int curr_section = -1; - int curr_entry = -1; char buffer[CFG_NAME_LEN + CFG_VALUE_LEN + 4] = {0}; int lineno = 0; struct rte_cfgfile *cfg = NULL; @@ -204,28 +200,7 @@ rte_cfgfile_load_with_params(const char *filename, int flags, if (f == NULL) return NULL; - cfg = malloc(sizeof(*cfg) + sizeof(cfg->sections[0]) * - allocated_sections); - if (cfg == NULL) - goto error2; - - memset(cfg->sections, 0, sizeof(cfg->sections[0]) * allocated_sections); - - if (flags & CFG_FLAG_GLOBAL_SECTION) { - curr_section = 0; - allocated_entries = CFG_ALLOC_ENTRY_BATCH; - cfg->sections = malloc( - sizeof(cfg->sections[0]) + - sizeof(cfg->sections[0].entries) * - allocated_entries); - if (cfg->sections == NULL) { - printf("Error - no memory for global section\n"); - goto error1; - } - - snprintf(cfg->sections[curr_section].name, - sizeof(cfg->sections[0].name), "GLOBAL"); - } + cfg = rte_cfgfile_create(flags); while (fgets(buffer, sizeof(buffer), f) != NULL) { char *pos = NULL; @@ -236,13 +211,15 @@ rte_cfgfile_load_with_params(const char *filename, int flags, "Check if line too long\n", lineno); goto error1; } + /* skip parsing if comment character found */ pos = memchr(buffer, params->comment_character, len); - if (pos != NULL) { + if (pos != NULL && (*(pos-1) != '\\')) { *pos = '\0'; len = pos - buffer; } len = _strip(buffer, len); + /* skip lines without useful content */ if (buffer[0] != '[' && memchr(buffer, '=', len) == NULL) continue; @@ -250,128 +227,53 @@ rte_cfgfile_load_with_params(const char *filename, int flags, /* section heading line */ char *end = memchr(buffer, ']', len); if (end == NULL) { - printf("Error line %d - no terminating '['" + printf("Error line %d - no terminating ']'" "character found\n", lineno); goto error1; } *end = '\0'; _strip(&buffer[1], end - &buffer[1]); - /* close off old section and add start new one */ - if (curr_section >= 0) - cfg->sections[curr_section].num_entries = - curr_entry + 1; - curr_section++; - - /* resize overall struct if we don't have room for more - sections */ - if (curr_section == allocated_sections) { - allocated_sections += CFG_ALLOC_SECTION_BATCH; - struct rte_cfgfile *n_cfg = realloc(cfg, - sizeof(*cfg) + sizeof(cfg->sections[0]) - * allocated_sections); - if (n_cfg == NULL) { - curr_section--; - printf("Error - no more memory\n"); - goto error1; - } - cfg = n_cfg; - } - - /* allocate space for new section */ - allocated_entries = CFG_ALLOC_ENTRY_BATCH; - curr_entry = -1; - cfg->sections = malloc( - sizeof(cfg->sections[0]) + - sizeof(cfg->sections[0].entries) * - allocated_entries); - if (cfg->sections == NULL) { - printf("Error - no more memory\n"); - goto error1; - } - - snprintf(cfg->sections[curr_section].name, - sizeof(cfg->sections[0].name), - "%s", &buffer[1]); + rte_cfgfile_add_section(cfg, &buffer[1]); } else { - /* value line */ - if (curr_section < 0) { - printf("Error line %d - value outside of" - "section\n", lineno); - goto error1; - } - - struct rte_cfgfile_section *sect = cfg->sections; - + /* key and value line */ char *split[2] = {NULL}; + split[0] = buffer; split[1] = memchr(buffer, '=', len); - - /* when delimeter not found */ - if (split[1] == NULL) { - printf("Error at line %d - cannot " - "split string\n", lineno); - goto error1; - } else { - /* when delimeter found */ - *split[1] = '\0'; - split[1]++; - - if (!(flags & CFG_FLAG_EMPTY_VALUES) && - (*split[1] == '\0')) { - printf("Error at line %d - cannot " - "split string\n", lineno); - goto error1; - } + *split[1] = '\0'; + split[1]++; + + _strip(split[0], strlen(split[0])); + _strip(split[1], strlen(split[1])); + char *end = memchr(split[1], '\\', strlen(split[1])); + while (end != NULL) { + if (*(end+1) == params->comment_character) { + *end = '\0'; + strcat(split[1], end+1); + } else + end++; + end = memchr(end, '\\', strlen(end)); } - curr_entry++; - if (curr_entry == allocated_entries) { - allocated_entries += CFG_ALLOC_ENTRY_BATCH; - struct rte_cfgfile_section *n_sect = realloc( - sect, sizeof(*sect) + - sizeof(sect->entries[0]) * - allocated_entries); - if (n_sect == NULL) { - curr_entry--; - printf("Error - no more memory\n"); - goto error1; - } - sect = cfg->sections = n_sect; + if (!(flags & CFG_FLAG_EMPTY_VALUES) && + (*split[1] == '\0')) { + printf("Error at line %d - cannot use empty " + "values\n", lineno); + goto error1; } - sect->entries = malloc( - sizeof(sect->entries[0])); - if (sect->entries == NULL) { - printf("Error - no more memory\n"); + if (cfg->num_sections == 0) goto error1; - } - struct rte_cfgfile_entry *entry = sect->entries; - snprintf(entry->name, sizeof(entry->name), "%s", - split[0]); - snprintf(entry->value, sizeof(entry->value), "%s", - split[1] ? split[1] : ""); - _strip(entry->name, strnlen(entry->name, - sizeof(entry->name))); - _strip(entry->value, strnlen(entry->value, - sizeof(entry->value))); + _add_entry(&cfg->sections[cfg->num_sections - 1], + split[0], (split[1] ? split[1] : "")); } } fclose(f); - cfg->flags = flags; - cfg->num_sections = curr_section + 1; - /* curr_section will still be -1 if we have an empty file */ - if (curr_section >= 0) - cfg->sections[curr_section].num_entries = curr_entry + 1; return cfg; - error1: - cfg->num_sections = curr_section + 1; - if (curr_section >= 0) - cfg->sections[curr_section].num_entries = curr_entry + 1; rte_cfgfile_close(cfg); -error2: fclose(f); return NULL; } -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v4 4/5] cfgfile: rework of load function 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 4/5] cfgfile: rework of load function Jacek Piasecki @ 2017-08-30 20:24 ` Bruce Richardson 0 siblings, 0 replies; 70+ messages in thread From: Bruce Richardson @ 2017-08-30 20:24 UTC (permalink / raw) To: Jacek Piasecki; +Cc: dev, deepak.k.jain, kubax.kozak, michalx.k.jastrzebski On Mon, Jul 10, 2017 at 02:44:16PM +0200, Jacek Piasecki wrote: > New functions added to cfgfile library make it possible > to significantly simplify the code of rte_cfgfile_load_with_params() > > This patch shows the new body of this function. > > Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> > --- > lib/librte_cfgfile/rte_cfgfile.c | 156 ++++++++------------------------------- > 1 file changed, 29 insertions(+), 127 deletions(-) > Acked-by: Bruce Richardson <bruce.richardson@intel.com> ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v4 5/5] test/cfgfile: add new unit test 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 0/5] Rework cfgfile API to enable apps config file support Jacek Piasecki ` (3 preceding siblings ...) 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 4/5] cfgfile: rework of load function Jacek Piasecki @ 2017-07-10 12:44 ` Jacek Piasecki 2017-08-30 20:25 ` Bruce Richardson 2017-09-04 9:30 ` Bruce Richardson 2017-07-10 15:13 ` [dpdk-dev] [PATCH v4 0/5] Rework cfgfile API to enable apps config file support Thomas Monjalon 5 siblings, 2 replies; 70+ messages in thread From: Jacek Piasecki @ 2017-07-10 12:44 UTC (permalink / raw) To: dev Cc: bruce.richardson, deepak.k.jain, kubax.kozak, michalx.k.jastrzebski, Jacek Piasecki Load huge realloc_sections.ini file to check malloc/realloc ability of cfgfile library. Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> --- test/test/test_cfgfile.c | 40 +++++++ test/test/test_cfgfiles/etc/realloc_sections.ini | 128 +++++++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 test/test/test_cfgfiles/etc/realloc_sections.ini diff --git a/test/test/test_cfgfile.c b/test/test/test_cfgfile.c index 4cc9b14..2278618 100644 --- a/test/test/test_cfgfile.c +++ b/test/test/test_cfgfile.c @@ -111,6 +111,7 @@ _test_cfgfile_sample(struct rte_cfgfile *cfgfile) return 0; } + static int test_cfgfile_sample1(void) { @@ -154,6 +155,42 @@ test_cfgfile_sample2(void) } static int +test_cfgfile_realloc_sections(void) +{ + struct rte_cfgfile *cfgfile; + int ret; + const char *value; + + cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/realloc_sections.ini", 0); + TEST_ASSERT_NOT_NULL(cfgfile, "Failed to load config file"); + + ret = rte_cfgfile_num_sections(cfgfile, NULL, 0); + TEST_ASSERT(ret == 9, "Unexpected number of sections: %d", ret); + + ret = rte_cfgfile_has_section(cfgfile, "section9"); + TEST_ASSERT(ret, "section9 missing"); + + ret = rte_cfgfile_section_num_entries(cfgfile, "section3"); + TEST_ASSERT(ret == 21, + "section3 unexpected number of entries: %d", ret); + + ret = rte_cfgfile_section_num_entries(cfgfile, "section9"); + TEST_ASSERT(ret == 8, "section9 unexpected number of entries: %d", ret); + + value = rte_cfgfile_get_entry(cfgfile, "section9", "key8"); + TEST_ASSERT(strcmp("value8_section9", value) == 0, + "key unexpected value: %s", value); + + ret = rte_cfgfile_save(cfgfile, "cfgfile_save.ini"); + TEST_ASSERT_SUCCESS(ret, "Failed to save *.ini file"); + + ret = rte_cfgfile_close(cfgfile); + TEST_ASSERT_SUCCESS(ret, "Failed to close cfgfile"); + + return 0; +} + +static int test_cfgfile_invalid_section_header(void) { struct rte_cfgfile *cfgfile; @@ -292,6 +329,9 @@ test_cfgfile(void) if (test_cfgfile_sample2()) return -1; + if (test_cfgfile_realloc_sections()) + return -1; + if (test_cfgfile_invalid_section_header()) return -1; diff --git a/test/test/test_cfgfiles/etc/realloc_sections.ini b/test/test/test_cfgfiles/etc/realloc_sections.ini new file mode 100644 index 0000000..e653e40 --- /dev/null +++ b/test/test/test_cfgfiles/etc/realloc_sections.ini @@ -0,0 +1,128 @@ +[section1] +key1=value1_section1 +key2=value2_section1 +key3=value3_section1 +key4=value4_section1 +key5=value5_section1 +key6=value6_section1 +key7=value7_section1 +key8=value8_section1 +key9=value9_section1 +key10=value10_section1 +key11=value11_section1 +key12=value12_section1 +key13=value13_section1 +key14=value14_section1 +key15=value15_section1 +key16=value16_section1 +key17=value17_section1 +key18=value18_section1 +key19=value19_section1 +key20=value20_section1 +key21=value21_section1 + +[section2] +key1=value1_section2 +key2=value2_section2 +key3=value3_section2 +key4=value4_section2 +key5=value5_section2 +key6=value6_section2 +key7=value7_section2 +key8=value8_section2 +key9=value9_section2 +key10=value10_section2 +key11=value11_section2 +key12=value12_section2 +key13=value13_section2 +key14=value14_section2 +key15=value15_section2 +key16=value16_section2 +key17=value17_section2 +key18=value18_section2 +key19=value19_section2 +key20=value20_section2 +key21=value21_section2 + +[section3] +key1=value1_section3 +key2=value2_section3 +key3=value3_section3 +key4=value4_section3 +key5=value5_section3 +key6=value6_section3 +key7=value7_section3 +key8=value8_section3 +key9=value9_section3 +key10=value10_section3 +key11=value11_section3 +key12=value12_section3 +key13=value13_section3 +key14=value14_section3 +key15=value15_section3 +key16=value16_section3 +key17=value17_section3 +key18=value18_section3 +key19=value19_section3 +key20=value20_section3 +key21=value21_section3 + +[section4] +key1=value1_section4 +key2=value2_section4 +key3=value3_section4 +key4=value4_section4 +key5=value5_section4 +key6=value6_section4 +key7=value7_section4 +key8=value8_section4 + +[section5] +key1=value1_section5 +key2=value2_section5 +key3=value3_section5 +key4=value4_section5 +key5=value5_section5 +key6=value6_section5 +key7=value7_section5 +key8=value8_section5 + +[section6] +key1=value1_section6 +key2=value2_section6 +key3=value3_section6 +key4=value4_section6 +key5=value5_section6 +key6=value6_section6 +key7=value7_section6 +key8=value8_section6 + +[section7] +key1=value1_section7 +key2=value2_section7 +key3=value3_section7 +key4=value4_section7 +key5=value5_section7 +key6=value6_section7 +key7=value7_section7 +key8=value8_section7 + +[section8] +key1=value1_section8 +key2=value2_section8 +key3=value3_section8 +key4=value4_section8 +key5=value5_section8 +key6=value6_section8 +key7=value7_section8 +key8=value8_section8 + +[section9] +key1=value1_section9 +key2=value2_section9 +key3=value3_section9 +key4=value4_section9 +key5=value5_section9 +key6=value6_section9 +key7=value7_section9 +key8=value8_section9 -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v4 5/5] test/cfgfile: add new unit test 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 5/5] test/cfgfile: add new unit test Jacek Piasecki @ 2017-08-30 20:25 ` Bruce Richardson 2017-09-04 9:21 ` Bruce Richardson 2017-09-04 9:30 ` Bruce Richardson 1 sibling, 1 reply; 70+ messages in thread From: Bruce Richardson @ 2017-08-30 20:25 UTC (permalink / raw) To: Jacek Piasecki; +Cc: dev, deepak.k.jain, kubax.kozak, michalx.k.jastrzebski On Mon, Jul 10, 2017 at 02:44:17PM +0200, Jacek Piasecki wrote: > Load huge realloc_sections.ini file to check malloc/realloc > ability of cfgfile library. > > Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> > --- This may need some work still. The cfgfile tests fail for me when I run them: RTE>>cfgfile_autotest TestCase test_cfgfile_realloc_sections() line 165 failed: Failed to load config file Test Failed RTE>> ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v4 5/5] test/cfgfile: add new unit test 2017-08-30 20:25 ` Bruce Richardson @ 2017-09-04 9:21 ` Bruce Richardson 0 siblings, 0 replies; 70+ messages in thread From: Bruce Richardson @ 2017-09-04 9:21 UTC (permalink / raw) To: Jacek Piasecki; +Cc: dev, deepak.k.jain, kubax.kozak, michalx.k.jastrzebski On Wed, Aug 30, 2017 at 09:25:51PM +0100, Bruce Richardson wrote: > On Mon, Jul 10, 2017 at 02:44:17PM +0200, Jacek Piasecki wrote: > > Load huge realloc_sections.ini file to check malloc/realloc > > ability of cfgfile library. > > > > Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> > > --- > > This may need some work still. The cfgfile tests fail for me when I run > them: > > RTE>>cfgfile_autotest > TestCase test_cfgfile_realloc_sections() line 165 failed: Failed to load config file > Test Failed > RTE>> > Deleting the build directory and recreating it allows these tests to pass. Following up with Jacek offline, it appears that the test data used here is not copied over each time on build, which is what causes the error - using old data/resources with the new tests. Therefore, it appears the tests themselves are not at fault. Acked-by: Bruce Richardson <bruce.richardson@intel.com> ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v4 5/5] test/cfgfile: add new unit test 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 5/5] test/cfgfile: add new unit test Jacek Piasecki 2017-08-30 20:25 ` Bruce Richardson @ 2017-09-04 9:30 ` Bruce Richardson 2017-09-15 13:56 ` Thomas Monjalon 1 sibling, 1 reply; 70+ messages in thread From: Bruce Richardson @ 2017-09-04 9:30 UTC (permalink / raw) To: Jacek Piasecki; +Cc: dev, deepak.k.jain, kubax.kozak, michalx.k.jastrzebski On Mon, Jul 10, 2017 at 02:44:17PM +0200, Jacek Piasecki wrote: > Load huge realloc_sections.ini file to check malloc/realloc > ability of cfgfile library. > > Signed-off-by: Jacek Piasecki <jacekx.piasecki@intel.com> > --- > test/test/test_cfgfile.c | 40 +++++++ > test/test/test_cfgfiles/etc/realloc_sections.ini | 128 +++++++++++++++++++++++ > 2 files changed, 168 insertions(+) > create mode 100644 test/test/test_cfgfiles/etc/realloc_sections.ini > > diff --git a/test/test/test_cfgfile.c b/test/test/test_cfgfile.c > index 4cc9b14..2278618 100644 > --- a/test/test/test_cfgfile.c > +++ b/test/test/test_cfgfile.c > @@ -111,6 +111,7 @@ _test_cfgfile_sample(struct rte_cfgfile *cfgfile) > return 0; > } > > + > static int > test_cfgfile_sample1(void) > { > @@ -154,6 +155,42 @@ test_cfgfile_sample2(void) > } > > static int > +test_cfgfile_realloc_sections(void) > +{ > + struct rte_cfgfile *cfgfile; > + int ret; > + const char *value; > + > + cfgfile = rte_cfgfile_load(CFG_FILES_ETC "/realloc_sections.ini", 0); > + TEST_ASSERT_NOT_NULL(cfgfile, "Failed to load config file"); > + > + ret = rte_cfgfile_num_sections(cfgfile, NULL, 0); > + TEST_ASSERT(ret == 9, "Unexpected number of sections: %d", ret); > + > + ret = rte_cfgfile_has_section(cfgfile, "section9"); > + TEST_ASSERT(ret, "section9 missing"); > + > + ret = rte_cfgfile_section_num_entries(cfgfile, "section3"); > + TEST_ASSERT(ret == 21, > + "section3 unexpected number of entries: %d", ret); > + > + ret = rte_cfgfile_section_num_entries(cfgfile, "section9"); > + TEST_ASSERT(ret == 8, "section9 unexpected number of entries: %d", ret); > + > + value = rte_cfgfile_get_entry(cfgfile, "section9", "key8"); > + TEST_ASSERT(strcmp("value8_section9", value) == 0, > + "key unexpected value: %s", value); > + > + ret = rte_cfgfile_save(cfgfile, "cfgfile_save.ini"); > + TEST_ASSERT_SUCCESS(ret, "Failed to save *.ini file"); This file is a temporary one, so: a) should be placed in /tmp b) should be removed at the end of the test. ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v4 5/5] test/cfgfile: add new unit test 2017-09-04 9:30 ` Bruce Richardson @ 2017-09-15 13:56 ` Thomas Monjalon 2017-09-18 13:49 ` Jastrzebski, MichalX K 0 siblings, 1 reply; 70+ messages in thread From: Thomas Monjalon @ 2017-09-15 13:56 UTC (permalink / raw) To: Jacek Piasecki Cc: dev, Bruce Richardson, deepak.k.jain, kubax.kozak, michalx.k.jastrzebski 04/09/2017 11:30, Bruce Richardson: > This file is a temporary one, so: > a) should be placed in /tmp > b) should be removed at the end of the test. Jacek, do you plan to update this series in 17.11 timeframe? ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v4 5/5] test/cfgfile: add new unit test 2017-09-15 13:56 ` Thomas Monjalon @ 2017-09-18 13:49 ` Jastrzebski, MichalX K 0 siblings, 0 replies; 70+ messages in thread From: Jastrzebski, MichalX K @ 2017-09-18 13:49 UTC (permalink / raw) To: Thomas Monjalon, Piasecki, JacekX Cc: dev, Richardson, Bruce, Jain, Deepak K, Kozak, KubaX > -----Original Message----- > From: Thomas Monjalon [mailto:thomas@monjalon.net] > Sent: Friday, September 15, 2017 3:56 PM > To: Piasecki, JacekX <jacekx.piasecki@intel.com> > Cc: dev@dpdk.org; Richardson, Bruce <bruce.richardson@intel.com>; Jain, > Deepak K <deepak.k.jain@intel.com>; Kozak, KubaX > <kubax.kozak@intel.com>; Jastrzebski, MichalX K > <michalx.k.jastrzebski@intel.com> > Subject: Re: [dpdk-dev] [PATCH v4 5/5] test/cfgfile: add new unit test > > 04/09/2017 11:30, Bruce Richardson: > > This file is a temporary one, so: > > a) should be placed in /tmp > > b) should be removed at the end of the test. > > Jacek, do you plan to update this series in 17.11 timeframe? Hi Thomas, yes we plan to update the series. V5 should be sent tomorrow. ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v4 0/5] Rework cfgfile API to enable apps config file support 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 0/5] Rework cfgfile API to enable apps config file support Jacek Piasecki ` (4 preceding siblings ...) 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 5/5] test/cfgfile: add new unit test Jacek Piasecki @ 2017-07-10 15:13 ` Thomas Monjalon 2017-07-20 21:48 ` Thomas Monjalon 5 siblings, 1 reply; 70+ messages in thread From: Thomas Monjalon @ 2017-07-10 15:13 UTC (permalink / raw) To: Jacek Piasecki, Cristian Dumitrescu Cc: dev, bruce.richardson, deepak.k.jain, kubax.kozak, michalx.k.jastrzebski 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 > > ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v4 0/5] Rework cfgfile API to enable apps config file support 2017-07-10 15:13 ` [dpdk-dev] [PATCH v4 0/5] Rework cfgfile API to enable apps config file support Thomas Monjalon @ 2017-07-20 21:48 ` Thomas Monjalon 0 siblings, 0 replies; 70+ messages in thread From: Thomas Monjalon @ 2017-07-20 21:48 UTC (permalink / raw) To: Jacek Piasecki Cc: dev, Cristian Dumitrescu, bruce.richardson, deepak.k.jain, kubax.kozak, michalx.k.jastrzebski 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. ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v4 0/3] EAL change for using a config file for DPDK 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 1/3] eal: add functions parsing EAL arguments Jacek Piasecki 2017-06-30 16:04 ` Bruce Richardson 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 0/5] Rework cfgfile API to enable apps config file support Jacek Piasecki @ 2017-07-10 12:51 ` Kuba Kozak 2017-07-10 12:51 ` [dpdk-dev] [PATCH v4 1/3] eal: add functions parsing EAL arguments Kuba Kozak ` (2 more replies) 2 siblings, 3 replies; 70+ messages in thread From: Kuba Kozak @ 2017-07-10 12:51 UTC (permalink / raw) To: dev Cc: deepak.k.jain, bruce.richardson, michalx.k.jastrzebski, jacekx.piasecki, Kuba Kozak 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 -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v4 1/3] eal: add functions parsing EAL arguments 2017-07-10 12:51 ` [dpdk-dev] [PATCH v4 0/3] EAL change for using a config file for DPDK Kuba Kozak @ 2017-07-10 12:51 ` Kuba Kozak 2017-07-13 9:26 ` [dpdk-dev] [PATCH v5 0/3] EAL change for using a config file for DPDK Kuba Kozak 2017-07-13 10:07 ` Kuba Kozak 2017-07-10 12:51 ` [dpdk-dev] [PATCH v4 2/3] app/testpmd: add parse options from cfg file Kuba Kozak 2017-07-10 12:51 ` [dpdk-dev] [PATCH v4 3/3] app/testpmd: add parse options from JSON " Kuba Kozak 2 siblings, 2 replies; 70+ messages in thread From: Kuba Kozak @ 2017-07-10 12:51 UTC (permalink / raw) To: dev Cc: deepak.k.jain, bruce.richardson, michalx.k.jastrzebski, jacekx.piasecki, Kuba Kozak 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> --- 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 +- 12 files changed, 452 insertions(+), 128 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index 1080a95..2c6c380 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -34,6 +34,9 @@ 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 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..4a0c221 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" @@ -99,6 +100,8 @@ static struct flock wr_lock = { .l_len = sizeof(early_mem_config.memseg), }; +static int run_once_reset_internal_config; + /* Address of global and public configuration */ static struct rte_config rte_config = { .mem_config = &early_mem_config, @@ -347,6 +350,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 +422,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) { @@ -517,7 +536,10 @@ rte_eal_init(int argc, char **argv) thread_id = pthread_self(); - eal_reset_internal_config(&internal_config); + if (!run_once_reset_internal_config) { + eal_reset_internal_config(&internal_config); + run_once_reset_internal_config = 1; + } /* set log level as early as possible */ eal_log_level_parse(argc, argv); @@ -677,3 +699,68 @@ rte_eal_process_type(void) { return rte_config.process_type; } + +#ifdef RTE_LIBRTE_CFGFILE +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; + } + + if (!run_once_reset_internal_config) { + eal_reset_internal_config(&internal_config); + run_once_reset_internal_config = 1; + } + + /* set log level as early as possible */ + eal_log_level_cfg(cfg); + + if (rte_eal_cpu_init() < 0) { + rte_eal_init_alert("Cannot detect lcores."); + rte_errno = ENOTSUP; + return -1; + } + + 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 381f895..932f990 100644 --- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map +++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map @@ -200,6 +200,7 @@ DPDK_17.08 { rte_bus_find; rte_bus_find_by_device; rte_bus_find_by_name; + rte_eal_configure; } DPDK_17.05; diff --git a/lib/librte_eal/common/eal_common_lcore.c b/lib/librte_eal/common/eal_common_lcore.c index 84fa0cb..d0f4c6f 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. diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c index 075b0ea..b568f05 100644 --- a/lib/librte_eal/common/eal_common_options.c +++ b/lib/librte_eal/common/eal_common_options.c @@ -50,6 +50,10 @@ #include <rte_version.h> #include <rte_devargs.h> #include <rte_memcpy.h> +#ifdef RTE_LIBRTE_CFGFILE +#include <rte_cfgfile.h> +#include <rte_errno.h> +#endif #include "eal_internal_cfg.h" #include "eal_options.h" @@ -1078,3 +1082,105 @@ eal_common_usage(void) " --"OPT_NO_SHCONF" No shared config (mmap'd files)\n" "\n", RTE_MAX_LCORE); } + +#ifdef RTE_LIBRTE_CFGFILE +/* Parse the arguments for --log-level only */ +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 + +#ifdef RTE_LIBRTE_CFGFILE +static void rte_eal_init_alert(const char *msg) +{ + fprintf(stderr, "EAL: FATAL: %s\n", msg); + RTE_LOG(ERR, EAL, "%s\n", msg); +} + +#define vdev_buff_size 200 +#define sectionname_size 20 +int +parse_vdev_devices(struct rte_cfgfile *cfg) +{ + char sectionname[sectionname_size] = "DPDK.vdev0"; + char buffer[vdev_buff_size]; + int vdev_nb = 0; + int n_entries; + int buf_len; + char *buf_ptr; + int i; + int ret; + + /* ----------- parsing VDEVS */ + 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; + } + + buffer[0] = '\0'; + buf_ptr = buffer; + buf_len = vdev_buff_size; + for (i = 0; i < n_entries; i++) { + ret = snprintf(buf_ptr, buf_len, "%s%s%s%s", + entries[i].name, + (entries[i].value[0] != '\0') ? + "=" : "", + entries[i].value, + (i < (n_entries - 1)) ? "," : ""); + if (ret >= buf_len) { + printf("parse_vdev_devices(): buffer[] size is " + "to small\n"); + return -1; + } + buf_len -= ret; + buf_ptr += ret; + } + + /* parsing vdev */ + if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, + buffer) < 0) { + return -1; + } + snprintf(sectionname, sectionname_size, "DPDK.vdev%d", vdev_nb); + } + /* ----------- parsing VDEVS */ + return 0; +} + +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; + } + } +} +#endif diff --git a/lib/librte_eal/common/eal_options.h b/lib/librte_eal/common/eal_options.h index a881c62..0fce11c 100644 --- a/lib/librte_eal/common/eal_options.h +++ b/lib/librte_eal/common/eal_options.h @@ -96,5 +96,8 @@ int eal_check_common_options(struct internal_config *internal_cfg); void eal_common_usage(void); enum rte_proc_type_t eal_proc_type_detect(void); int eal_plugins_init(void); +void eal_log_level_cfg(struct rte_cfgfile *cfg); +int parse_vdev_devices(struct rte_cfgfile *cfg); +void eal_getopt(const char *str, int *opt, int *option_index); #endif /* EAL_OPTIONS_H */ diff --git a/lib/librte_eal/common/include/rte_eal.h b/lib/librte_eal/common/include/rte_eal.h index 6b7c5ca..a1c78c0 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,24 @@ 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. + * @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 8651e27..7c1c559 100644 --- a/lib/librte_eal/linuxapp/eal/Makefile +++ b/lib/librte_eal/linuxapp/eal/Makefile @@ -53,6 +53,9 @@ LDLIBS += -lrt ifeq ($(CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES),y) LDLIBS += -lnuma endif +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..f09aeff 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" @@ -101,6 +104,8 @@ static struct rte_mem_config early_mem_config; * duration of the program, as we hold a write lock on it in the primary proc */ static int mem_cfg_fd = -1; +static int run_once_reset_internal_config; + static struct flock wr_lock = { .l_type = F_WRLCK, .l_whence = SEEK_SET, @@ -515,119 +520,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) { @@ -774,7 +795,10 @@ rte_eal_init(int argc, char **argv) thread_id = pthread_self(); - eal_reset_internal_config(&internal_config); + if (!run_once_reset_internal_config) { + eal_reset_internal_config(&internal_config); + run_once_reset_internal_config = 1; + } /* set log level as early as possible */ eal_log_level_parse(argc, argv); @@ -995,3 +1019,68 @@ rte_eal_check_module(const char *module_name) /* Module has been found */ return 1; } + +#ifdef RTE_LIBRTE_CFGFILE +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; + } + + if (!run_once_reset_internal_config) { + eal_reset_internal_config(&internal_config); + run_once_reset_internal_config = 1; + } + + /* set log level as early as possible */ + eal_log_level_cfg(cfg); + + if (rte_eal_cpu_init() < 0) { + rte_eal_init_alert("Cannot detect lcores."); + rte_errno = ENOTSUP; + return -1; + } + + 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 0f9e009..d206fd3 100644 --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map @@ -205,6 +205,7 @@ DPDK_17.08 { rte_bus_find; rte_bus_find_by_device; rte_bus_find_by_name; + rte_eal_configure; } DPDK_17.05; diff --git a/mk/rte.app.mk b/mk/rte.app.mk index e239581..6c1b508 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -81,7 +81,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 @@ -97,6 +96,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 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v5 0/3] EAL change for using a config file for DPDK 2017-07-10 12:51 ` [dpdk-dev] [PATCH v4 1/3] eal: add functions parsing EAL arguments Kuba Kozak @ 2017-07-13 9:26 ` Kuba Kozak 2017-07-13 10:07 ` Kuba Kozak 1 sibling, 0 replies; 70+ messages in thread From: Kuba Kozak @ 2017-07-13 9:26 UTC (permalink / raw) To: dev Cc: deepak.k.jain, bruce.richardson, michalx.k.jastrzebski, jacekx.piasecki, Kuba Kozak 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" v5: changed define "RTE_DEVTYPE_VIRTUAL" to "RTE_DEVTYPE_UNDEFINED" due to compilation errors (changes on current master). 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 -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v5 0/3] EAL change for using a config file for DPDK 2017-07-10 12:51 ` [dpdk-dev] [PATCH v4 1/3] eal: add functions parsing EAL arguments Kuba Kozak 2017-07-13 9:26 ` [dpdk-dev] [PATCH v5 0/3] EAL change for using a config file for DPDK Kuba Kozak @ 2017-07-13 10:07 ` Kuba Kozak 2017-07-13 10:07 ` [dpdk-dev] [PATCH v5 1/3] eal: add functions parsing EAL arguments Kuba Kozak ` (3 more replies) 1 sibling, 4 replies; 70+ messages in thread From: Kuba Kozak @ 2017-07-13 10:07 UTC (permalink / raw) To: dev Cc: deepak.k.jain, bruce.richardson, michalx.k.jastrzebski, jacekx.piasecki, Kuba Kozak 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" v5: changed define "RTE_DEVTYPE_VIRTUAL" to "RTE_DEVTYPE_UNDEFINED" due to compilation errors (changes on current master). 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 -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v5 1/3] eal: add functions parsing EAL arguments 2017-07-13 10:07 ` Kuba Kozak @ 2017-07-13 10:07 ` Kuba Kozak 2017-07-13 10:07 ` [dpdk-dev] [PATCH v5 2/3] app/testpmd: add parse options from cfg file Kuba Kozak ` (2 subsequent siblings) 3 siblings, 0 replies; 70+ messages in thread From: Kuba Kozak @ 2017-07-13 10:07 UTC (permalink / raw) To: dev Cc: deepak.k.jain, bruce.richardson, michalx.k.jastrzebski, jacekx.piasecki, Kuba Kozak 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> --- 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 +- 12 files changed, 452 insertions(+), 128 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index 1080a95..2c6c380 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -34,6 +34,9 @@ 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 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..4a0c221 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" @@ -99,6 +100,8 @@ static struct flock wr_lock = { .l_len = sizeof(early_mem_config.memseg), }; +static int run_once_reset_internal_config; + /* Address of global and public configuration */ static struct rte_config rte_config = { .mem_config = &early_mem_config, @@ -347,6 +350,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 +422,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) { @@ -517,7 +536,10 @@ rte_eal_init(int argc, char **argv) thread_id = pthread_self(); - eal_reset_internal_config(&internal_config); + if (!run_once_reset_internal_config) { + eal_reset_internal_config(&internal_config); + run_once_reset_internal_config = 1; + } /* set log level as early as possible */ eal_log_level_parse(argc, argv); @@ -677,3 +699,68 @@ rte_eal_process_type(void) { return rte_config.process_type; } + +#ifdef RTE_LIBRTE_CFGFILE +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; + } + + if (!run_once_reset_internal_config) { + eal_reset_internal_config(&internal_config); + run_once_reset_internal_config = 1; + } + + /* set log level as early as possible */ + eal_log_level_cfg(cfg); + + if (rte_eal_cpu_init() < 0) { + rte_eal_init_alert("Cannot detect lcores."); + rte_errno = ENOTSUP; + return -1; + } + + 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 381f895..932f990 100644 --- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map +++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map @@ -200,6 +200,7 @@ DPDK_17.08 { rte_bus_find; rte_bus_find_by_device; rte_bus_find_by_name; + rte_eal_configure; } DPDK_17.05; diff --git a/lib/librte_eal/common/eal_common_lcore.c b/lib/librte_eal/common/eal_common_lcore.c index 84fa0cb..d0f4c6f 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. diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c index 075b0ea..aaf0f2c 100644 --- a/lib/librte_eal/common/eal_common_options.c +++ b/lib/librte_eal/common/eal_common_options.c @@ -50,6 +50,10 @@ #include <rte_version.h> #include <rte_devargs.h> #include <rte_memcpy.h> +#ifdef RTE_LIBRTE_CFGFILE +#include <rte_cfgfile.h> +#include <rte_errno.h> +#endif #include "eal_internal_cfg.h" #include "eal_options.h" @@ -1078,3 +1082,105 @@ eal_common_usage(void) " --"OPT_NO_SHCONF" No shared config (mmap'd files)\n" "\n", RTE_MAX_LCORE); } + +#ifdef RTE_LIBRTE_CFGFILE +/* Parse the arguments for --log-level only */ +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 + +#ifdef RTE_LIBRTE_CFGFILE +static void rte_eal_init_alert(const char *msg) +{ + fprintf(stderr, "EAL: FATAL: %s\n", msg); + RTE_LOG(ERR, EAL, "%s\n", msg); +} + +#define vdev_buff_size 200 +#define sectionname_size 20 +int +parse_vdev_devices(struct rte_cfgfile *cfg) +{ + char sectionname[sectionname_size] = "DPDK.vdev0"; + char buffer[vdev_buff_size]; + int vdev_nb = 0; + int n_entries; + int buf_len; + char *buf_ptr; + int i; + int ret; + + /* ----------- parsing VDEVS */ + 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; + } + + buffer[0] = '\0'; + buf_ptr = buffer; + buf_len = vdev_buff_size; + for (i = 0; i < n_entries; i++) { + ret = snprintf(buf_ptr, buf_len, "%s%s%s%s", + entries[i].name, + (entries[i].value[0] != '\0') ? + "=" : "", + entries[i].value, + (i < (n_entries - 1)) ? "," : ""); + if (ret >= buf_len) { + printf("parse_vdev_devices(): buffer[] size is " + "to small\n"); + return -1; + } + buf_len -= ret; + buf_ptr += ret; + } + + /* parsing vdev */ + if (rte_eal_devargs_add(RTE_DEVTYPE_UNDEFINED, + buffer) < 0) { + return -1; + } + snprintf(sectionname, sectionname_size, "DPDK.vdev%d", vdev_nb); + } + /* ----------- parsing VDEVS */ + return 0; +} + +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; + } + } +} +#endif diff --git a/lib/librte_eal/common/eal_options.h b/lib/librte_eal/common/eal_options.h index a881c62..0fce11c 100644 --- a/lib/librte_eal/common/eal_options.h +++ b/lib/librte_eal/common/eal_options.h @@ -96,5 +96,8 @@ int eal_check_common_options(struct internal_config *internal_cfg); void eal_common_usage(void); enum rte_proc_type_t eal_proc_type_detect(void); int eal_plugins_init(void); +void eal_log_level_cfg(struct rte_cfgfile *cfg); +int parse_vdev_devices(struct rte_cfgfile *cfg); +void eal_getopt(const char *str, int *opt, int *option_index); #endif /* EAL_OPTIONS_H */ diff --git a/lib/librte_eal/common/include/rte_eal.h b/lib/librte_eal/common/include/rte_eal.h index 6b7c5ca..a1c78c0 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,24 @@ 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. + * @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 8651e27..7c1c559 100644 --- a/lib/librte_eal/linuxapp/eal/Makefile +++ b/lib/librte_eal/linuxapp/eal/Makefile @@ -53,6 +53,9 @@ LDLIBS += -lrt ifeq ($(CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES),y) LDLIBS += -lnuma endif +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..f09aeff 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" @@ -101,6 +104,8 @@ static struct rte_mem_config early_mem_config; * duration of the program, as we hold a write lock on it in the primary proc */ static int mem_cfg_fd = -1; +static int run_once_reset_internal_config; + static struct flock wr_lock = { .l_type = F_WRLCK, .l_whence = SEEK_SET, @@ -515,119 +520,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) { @@ -774,7 +795,10 @@ rte_eal_init(int argc, char **argv) thread_id = pthread_self(); - eal_reset_internal_config(&internal_config); + if (!run_once_reset_internal_config) { + eal_reset_internal_config(&internal_config); + run_once_reset_internal_config = 1; + } /* set log level as early as possible */ eal_log_level_parse(argc, argv); @@ -995,3 +1019,68 @@ rte_eal_check_module(const char *module_name) /* Module has been found */ return 1; } + +#ifdef RTE_LIBRTE_CFGFILE +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; + } + + if (!run_once_reset_internal_config) { + eal_reset_internal_config(&internal_config); + run_once_reset_internal_config = 1; + } + + /* set log level as early as possible */ + eal_log_level_cfg(cfg); + + if (rte_eal_cpu_init() < 0) { + rte_eal_init_alert("Cannot detect lcores."); + rte_errno = ENOTSUP; + return -1; + } + + 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 0f9e009..d206fd3 100644 --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map @@ -205,6 +205,7 @@ DPDK_17.08 { rte_bus_find; rte_bus_find_by_device; rte_bus_find_by_name; + rte_eal_configure; } DPDK_17.05; diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 5bb4290..b883d08 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -81,7 +81,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 @@ -97,6 +96,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 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v5 2/3] app/testpmd: add parse options from cfg file 2017-07-13 10:07 ` Kuba Kozak 2017-07-13 10:07 ` [dpdk-dev] [PATCH v5 1/3] eal: add functions parsing EAL arguments Kuba Kozak @ 2017-07-13 10:07 ` Kuba Kozak 2017-07-13 10:07 ` [dpdk-dev] [PATCH v5 3/3] app/testpmd: add parse options from JSON " Kuba Kozak 2019-01-23 19:31 ` [dpdk-dev] [PATCH v5 0/3] EAL change for using a config file for DPDK Ferruh Yigit 3 siblings, 0 replies; 70+ messages in thread From: Kuba Kozak @ 2017-07-13 10:07 UTC (permalink / raw) To: dev Cc: deepak.k.jain, bruce.richardson, michalx.k.jastrzebski, jacekx.piasecki, Kuba Kozak This patch shows how to pass arguments to application using config.ini file. If a --cfgfile-path <path> option is passed into commandline non EAL section, then the file is loaded and used by app. If a config.ini file is present in current working directory, and no --cfgfile-path option is passed in, config.ini file will be loaded and used by app as default configuration. Signed-off-by: Kuba Kozak <kubax.kozak@intel.com> Suggested-by: Bruce Richardson <bruce.richardson@intel.com> --- app/test-pmd/config.ini | 24 + app/test-pmd/parameters.c | 1181 +++++++++++++++++++++++++-------------------- app/test-pmd/testpmd.c | 67 ++- app/test-pmd/testpmd.h | 3 +- 4 files changed, 761 insertions(+), 514 deletions(-) create mode 100644 app/test-pmd/config.ini diff --git a/app/test-pmd/config.ini b/app/test-pmd/config.ini new file mode 100644 index 0000000..54c83a2 --- /dev/null +++ b/app/test-pmd/config.ini @@ -0,0 +1,24 @@ +[DPDK] +v = +l = 0-4 +n = 4 +master-lcore = 0 +proc-type = primary + +[TEST-PMD] +i = +portmask = 0xff +nb-cores = 4 +port-topology = paired + +[DPDK.vdev0] +net_ring0 = + +[DPDK.vdev1] +net_ring1 = + +[DPDK.vdev2] +net_ring2 = + +[DPDK.vdev3] +net_ring3 = \ No newline at end of file diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c index 958b3d0..d32861a 100644 --- a/app/test-pmd/parameters.c +++ b/app/test-pmd/parameters.c @@ -77,9 +77,98 @@ #include <rte_eth_bond.h> #endif #include <rte_flow.h> +#ifdef RTE_LIBRTE_CFGFILE +#include <rte_cfgfile.h> +#endif #include "testpmd.h" +enum { TX, RX }; + +static struct option lgopts[] = { + { "cfgfile-path", 1, 0, 1 }, + { "help", 0, 0, 0 }, +#ifdef RTE_LIBRTE_CMDLINE + { "interactive", 0, 0, 0 }, + { "cmdline-file", 1, 0, 0 }, + { "auto-start", 0, 0, 0 }, + { "eth-peers-configfile", 1, 0, 0 }, + { "eth-peer", 1, 0, 0 }, +#endif + { "tx-first", 0, 0, 0 }, + { "stats-period", 1, 0, 0 }, + { "ports", 1, 0, 0 }, + { "nb-cores", 1, 0, 0 }, + { "nb-ports", 1, 0, 0 }, + { "coremask", 1, 0, 0 }, + { "portmask", 1, 0, 0 }, + { "numa", 0, 0, 0 }, + { "no-numa", 0, 0, 0 }, + { "mp-anon", 0, 0, 0 }, + { "port-numa-config", 1, 0, 0 }, + { "ring-numa-config", 1, 0, 0 }, + { "socket-num", 1, 0, 0 }, + { "mbuf-size", 1, 0, 0 }, + { "total-num-mbufs", 1, 0, 0 }, + { "max-pkt-len", 1, 0, 0 }, + { "pkt-filter-mode", 1, 0, 0 }, + { "pkt-filter-report-hash", 1, 0, 0 }, + { "pkt-filter-size", 1, 0, 0 }, + { "pkt-filter-drop-queue", 1, 0, 0 }, +#ifdef RTE_LIBRTE_LATENCY_STATS + { "latencystats", 1, 0, 0 }, +#endif +#ifdef RTE_LIBRTE_BITRATE + { "bitrate-stats", 1, 0, 0 }, +#endif + { "disable-crc-strip", 0, 0, 0 }, + { "enable-lro", 0, 0, 0 }, + { "enable-rx-cksum", 0, 0, 0 }, + { "enable-scatter", 0, 0, 0 }, + { "disable-hw-vlan", 0, 0, 0 }, + { "disable-hw-vlan-filter", 0, 0, 0 }, + { "disable-hw-vlan-strip", 0, 0, 0 }, + { "disable-hw-vlan-extend", 0, 0, 0 }, + { "enable-drop-en", 0, 0, 0 }, + { "disable-rss", 0, 0, 0 }, + { "port-topology", 1, 0, 0 }, + { "forward-mode", 1, 0, 0 }, + { "rss-ip", 0, 0, 0 }, + { "rss-udp", 0, 0, 0 }, + { "rxq", 1, 0, 0 }, + { "txq", 1, 0, 0 }, + { "rxd", 1, 0, 0 }, + { "txd", 1, 0, 0 }, + { "burst", 1, 0, 0 }, + { "mbcache", 1, 0, 0 }, + { "txpt", 1, 0, 0 }, + { "txht", 1, 0, 0 }, + { "txwt", 1, 0, 0 }, + { "txfreet", 1, 0, 0 }, + { "txrst", 1, 0, 0 }, + { "txqflags", 1, 0, 0 }, + { "rxpt", 1, 0, 0 }, + { "rxht", 1, 0, 0 }, + { "rxwt", 1, 0, 0 }, + { "rxfreet", 1, 0, 0 }, + { "tx-queue-stats-mapping", 1, 0, 0 }, + { "rx-queue-stats-mapping", 1, 0, 0 }, + { "no-flush-rx", 0, 0, 0 }, + { "txpkts", 1, 0, 0 }, + { "disable-link-check", 0, 0, 0 }, + { "no-lsc-interrupt", 0, 0, 0 }, + { "no-rmv-interrupt", 0, 0, 0 }, + { "print-event", 1, 0, 0 }, + { "mask-event", 1, 0, 0 }, + { 0, 0, 0, 0 }, +}; + +#ifdef RTE_LIBRTE_CMDLINE +#define SHORTOPTS "i" +#else +#define SHORTOPTS "" +#endif + static void usage(char* progname) { @@ -554,578 +643,646 @@ parse_event_printing_config(const char *optarg, int enable) return 0; } -void -launch_args_parse(int argc, char** argv) +static int +parse_option(int opt, char *optarg, int opt_idx, char *prgname) { - int n, opt; - char **argvopt; - int opt_idx; - enum { TX, RX }; + int n; - static struct option lgopts[] = { - { "help", 0, 0, 0 }, + switch (opt) { #ifdef RTE_LIBRTE_CMDLINE - { "interactive", 0, 0, 0 }, - { "cmdline-file", 1, 0, 0 }, - { "auto-start", 0, 0, 0 }, - { "eth-peers-configfile", 1, 0, 0 }, - { "eth-peer", 1, 0, 0 }, -#endif - { "tx-first", 0, 0, 0 }, - { "stats-period", 1, 0, 0 }, - { "ports", 1, 0, 0 }, - { "nb-cores", 1, 0, 0 }, - { "nb-ports", 1, 0, 0 }, - { "coremask", 1, 0, 0 }, - { "portmask", 1, 0, 0 }, - { "numa", 0, 0, 0 }, - { "no-numa", 0, 0, 0 }, - { "mp-anon", 0, 0, 0 }, - { "port-numa-config", 1, 0, 0 }, - { "ring-numa-config", 1, 0, 0 }, - { "socket-num", 1, 0, 0 }, - { "mbuf-size", 1, 0, 0 }, - { "total-num-mbufs", 1, 0, 0 }, - { "max-pkt-len", 1, 0, 0 }, - { "pkt-filter-mode", 1, 0, 0 }, - { "pkt-filter-report-hash", 1, 0, 0 }, - { "pkt-filter-size", 1, 0, 0 }, - { "pkt-filter-drop-queue", 1, 0, 0 }, -#ifdef RTE_LIBRTE_LATENCY_STATS - { "latencystats", 1, 0, 0 }, -#endif -#ifdef RTE_LIBRTE_BITRATE - { "bitrate-stats", 1, 0, 0 }, + case 'i': + printf("Interactive-mode selected\n"); + interactive = 1; + break; #endif - { "disable-crc-strip", 0, 0, 0 }, - { "enable-lro", 0, 0, 0 }, - { "enable-rx-cksum", 0, 0, 0 }, - { "enable-scatter", 0, 0, 0 }, - { "disable-hw-vlan", 0, 0, 0 }, - { "disable-hw-vlan-filter", 0, 0, 0 }, - { "disable-hw-vlan-strip", 0, 0, 0 }, - { "disable-hw-vlan-extend", 0, 0, 0 }, - { "enable-drop-en", 0, 0, 0 }, - { "disable-rss", 0, 0, 0 }, - { "port-topology", 1, 0, 0 }, - { "forward-mode", 1, 0, 0 }, - { "rss-ip", 0, 0, 0 }, - { "rss-udp", 0, 0, 0 }, - { "rxq", 1, 0, 0 }, - { "txq", 1, 0, 0 }, - { "rxd", 1, 0, 0 }, - { "txd", 1, 0, 0 }, - { "burst", 1, 0, 0 }, - { "mbcache", 1, 0, 0 }, - { "txpt", 1, 0, 0 }, - { "txht", 1, 0, 0 }, - { "txwt", 1, 0, 0 }, - { "txfreet", 1, 0, 0 }, - { "txrst", 1, 0, 0 }, - { "txqflags", 1, 0, 0 }, - { "rxpt", 1, 0, 0 }, - { "rxht", 1, 0, 0 }, - { "rxwt", 1, 0, 0 }, - { "rxfreet", 1, 0, 0 }, - { "tx-queue-stats-mapping", 1, 0, 0 }, - { "rx-queue-stats-mapping", 1, 0, 0 }, - { "no-flush-rx", 0, 0, 0 }, - { "txpkts", 1, 0, 0 }, - { "disable-link-check", 0, 0, 0 }, - { "no-lsc-interrupt", 0, 0, 0 }, - { "no-rmv-interrupt", 0, 0, 0 }, - { "print-event", 1, 0, 0 }, - { "mask-event", 1, 0, 0 }, - { 0, 0, 0, 0 }, - }; + case 'a': + printf("Auto-start selected\n"); + auto_start = 1; + break; - argvopt = argv; - -#ifdef RTE_LIBRTE_CMDLINE -#define SHORTOPTS "i" -#else -#define SHORTOPTS "" -#endif - while ((opt = getopt_long(argc, argvopt, SHORTOPTS "ah", - lgopts, &opt_idx)) != EOF) { - switch (opt) { + case 0: /*long options */ + if (!strcmp(lgopts[opt_idx].name, "help")) { + usage(prgname); + rte_exit(EXIT_SUCCESS, "Displayed help\n"); + return 0; + } #ifdef RTE_LIBRTE_CMDLINE - case 'i': + if (!strcmp(lgopts[opt_idx].name, "interactive")) { printf("Interactive-mode selected\n"); interactive = 1; - break; -#endif - case 'a': + } + if (!strcmp(lgopts[opt_idx].name, "cmdline-file")) { + printf("CLI commands to be read from %s\n", + optarg); + snprintf(cmdline_filename, + sizeof(cmdline_filename), "%s", + optarg); + } + if (!strcmp(lgopts[opt_idx].name, "auto-start")) { printf("Auto-start selected\n"); auto_start = 1; - break; + } + if (!strcmp(lgopts[opt_idx].name, "tx-first")) { + printf("Ports to start sending a burst of " + "packets first\n"); + tx_first = 1; + } + if (!strcmp(lgopts[opt_idx].name, "stats-period")) { + char *end = NULL; + unsigned int n; - case 0: /*long options */ - if (!strcmp(lgopts[opt_idx].name, "help")) { - usage(argv[0]); - rte_exit(EXIT_SUCCESS, "Displayed help\n"); - } -#ifdef RTE_LIBRTE_CMDLINE - if (!strcmp(lgopts[opt_idx].name, "interactive")) { - printf("Interactive-mode selected\n"); - interactive = 1; - } - if (!strcmp(lgopts[opt_idx].name, "cmdline-file")) { - printf("CLI commands to be read from %s\n", - optarg); - snprintf(cmdline_filename, - sizeof(cmdline_filename), "%s", - optarg); - } - if (!strcmp(lgopts[opt_idx].name, "auto-start")) { - printf("Auto-start selected\n"); - auto_start = 1; - } - if (!strcmp(lgopts[opt_idx].name, "tx-first")) { - printf("Ports to start sending a burst of " - "packets first\n"); - tx_first = 1; - } - if (!strcmp(lgopts[opt_idx].name, "stats-period")) { - char *end = NULL; - unsigned int n; + n = strtoul(optarg, &end, 10); + if ((optarg[0] == '\0') || (end == NULL) || + (*end != '\0')) + break; - n = strtoul(optarg, &end, 10); - if ((optarg[0] == '\0') || (end == NULL) || - (*end != '\0')) - break; + stats_period = n; + break; + } + if (!strcmp(lgopts[opt_idx].name, + "eth-peers-configfile")) { + if (init_peer_eth_addrs(optarg) != 0) + rte_exit(EXIT_FAILURE, + "Cannot open logfile\n"); + } + if (!strcmp(lgopts[opt_idx].name, "eth-peer")) { + char *port_end; + uint8_t c, peer_addr[6]; - stats_period = n; - break; - } - if (!strcmp(lgopts[opt_idx].name, - "eth-peers-configfile")) { - if (init_peer_eth_addrs(optarg) != 0) - rte_exit(EXIT_FAILURE, - "Cannot open logfile\n"); + errno = 0; + n = strtoul(optarg, &port_end, 10); + if (errno != 0 || port_end == optarg || + *port_end++ != ',') + rte_exit(EXIT_FAILURE, + "Invalid eth-peer: %s", optarg); + if (n >= RTE_MAX_ETHPORTS) { + rte_exit(EXIT_FAILURE, + "eth-peer: port %d >= " + "RTE_MAX_ETHPORTS(%d)\n", + n, RTE_MAX_ETHPORTS); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "eth-peer")) { - char *port_end; - uint8_t c, peer_addr[6]; - - errno = 0; - n = strtoul(optarg, &port_end, 10); - if (errno != 0 || port_end == optarg || *port_end++ != ',') - rte_exit(EXIT_FAILURE, - "Invalid eth-peer: %s", optarg); - if (n >= RTE_MAX_ETHPORTS) - rte_exit(EXIT_FAILURE, - "eth-peer: port %d >= RTE_MAX_ETHPORTS(%d)\n", - n, RTE_MAX_ETHPORTS); - if (cmdline_parse_etheraddr(NULL, port_end, - &peer_addr, sizeof(peer_addr)) < 0) - rte_exit(EXIT_FAILURE, - "Invalid ethernet address: %s\n", - port_end); - for (c = 0; c < 6; c++) - peer_eth_addrs[n].addr_bytes[c] = - peer_addr[c]; - nb_peer_eth_addrs++; + if (cmdline_parse_etheraddr(NULL, port_end, + &peer_addr, sizeof(peer_addr)) < 0) { + rte_exit(EXIT_FAILURE, + "Invalid ethernet address: %s\n", + port_end); + return -1; } + for (c = 0; c < 6; c++) + peer_eth_addrs[n].addr_bytes[c] = + peer_addr[c]; + nb_peer_eth_addrs++; + } #endif - if (!strcmp(lgopts[opt_idx].name, "nb-ports")) { - n = atoi(optarg); - if (n > 0 && n <= nb_ports) - nb_fwd_ports = (uint8_t) n; - else - rte_exit(EXIT_FAILURE, - "Invalid port %d\n", n); + if (!strcmp(lgopts[opt_idx].name, "nb-ports")) { + n = atoi(optarg); + if (n > 0 && n <= nb_ports) + nb_fwd_ports = (uint8_t) n; + else { + rte_exit(EXIT_FAILURE, + "Invalid port %d\n", n); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "nb-cores")) { - n = atoi(optarg); - if (n > 0 && n <= nb_lcores) - nb_fwd_lcores = (uint8_t) n; - else - rte_exit(EXIT_FAILURE, - "nb-cores should be > 0 and <= %d\n", - nb_lcores); + } + if (!strcmp(lgopts[opt_idx].name, "nb-cores")) { + n = atoi(optarg); + if (n > 0 && n <= nb_lcores) + nb_fwd_lcores = (uint8_t) n; + else { + rte_exit(EXIT_FAILURE, + "nb-cores should be > 0 and <= %d\n", + nb_lcores); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "coremask")) - parse_fwd_coremask(optarg); - if (!strcmp(lgopts[opt_idx].name, "portmask")) - parse_fwd_portmask(optarg); - if (!strcmp(lgopts[opt_idx].name, "no-numa")) - numa_support = 0; - if (!strcmp(lgopts[opt_idx].name, "numa")) - numa_support = 1; - if (!strcmp(lgopts[opt_idx].name, "mp-anon")) { - mp_anon = 1; + } + if (!strcmp(lgopts[opt_idx].name, "coremask")) + parse_fwd_coremask(optarg); + if (!strcmp(lgopts[opt_idx].name, "portmask")) + parse_fwd_portmask(optarg); + if (!strcmp(lgopts[opt_idx].name, "no-numa")) + numa_support = 0; + if (!strcmp(lgopts[opt_idx].name, "numa")) + numa_support = 1; + if (!strcmp(lgopts[opt_idx].name, "mp-anon")) + mp_anon = 1; + if (!strcmp(lgopts[opt_idx].name, "port-numa-config")) { + if (parse_portnuma_config(optarg)) { + rte_exit(EXIT_FAILURE, + "invalid port-numa configuration\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "port-numa-config")) { - if (parse_portnuma_config(optarg)) - rte_exit(EXIT_FAILURE, - "invalid port-numa configuration\n"); + } + if (!strcmp(lgopts[opt_idx].name, "ring-numa-config")) + if (parse_ringnuma_config(optarg)) { + rte_exit(EXIT_FAILURE, + "invalid ring-numa configuration\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "ring-numa-config")) - if (parse_ringnuma_config(optarg)) - rte_exit(EXIT_FAILURE, - "invalid ring-numa configuration\n"); - if (!strcmp(lgopts[opt_idx].name, "socket-num")) { - n = atoi(optarg); - if (!new_socket_id((uint8_t)n)) { - socket_num = (uint8_t)n; - } else { - print_invalid_socket_id_error(); - rte_exit(EXIT_FAILURE, - "Invalid socket id"); - } + if (!strcmp(lgopts[opt_idx].name, "socket-num")) { + n = atoi(optarg); + if (!new_socket_id((uint8_t)n)) { + socket_num = (uint8_t)n; + } else { + print_invalid_socket_id_error(); + rte_exit(EXIT_FAILURE, + "Invalid socket id"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "mbuf-size")) { - n = atoi(optarg); - if (n > 0 && n <= 0xFFFF) - mbuf_data_size = (uint16_t) n; - else - rte_exit(EXIT_FAILURE, - "mbuf-size should be > 0 and < 65536\n"); + } + if (!strcmp(lgopts[opt_idx].name, "mbuf-size")) { + n = atoi(optarg); + if (n > 0 && n <= 0xFFFF) + mbuf_data_size = (uint16_t) n; + else { + rte_exit(EXIT_FAILURE, + "mbuf-size should be > 0 and < 65536\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "total-num-mbufs")) { - n = atoi(optarg); - if (n > 1024) - param_total_num_mbufs = (unsigned)n; - else - rte_exit(EXIT_FAILURE, - "total-num-mbufs should be > 1024\n"); + } + if (!strcmp(lgopts[opt_idx].name, "total-num-mbufs")) { + n = atoi(optarg); + if (n > 1024) + param_total_num_mbufs = (unsigned int)n; + else { + rte_exit(EXIT_FAILURE, + "total-num-mbufs should be > 1024\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "max-pkt-len")) { - n = atoi(optarg); - if (n >= ETHER_MIN_LEN) { - rx_mode.max_rx_pkt_len = (uint32_t) n; - if (n > ETHER_MAX_LEN) - rx_mode.jumbo_frame = 1; - } else - rte_exit(EXIT_FAILURE, - "Invalid max-pkt-len=%d - should be > %d\n", - n, ETHER_MIN_LEN); + } + if (!strcmp(lgopts[opt_idx].name, "max-pkt-len")) { + n = atoi(optarg); + if (n >= ETHER_MIN_LEN) { + rx_mode.max_rx_pkt_len = (uint32_t) n; + if (n > ETHER_MAX_LEN) + rx_mode.jumbo_frame = 1; + } else { + rte_exit(EXIT_FAILURE, + "Invalid max-pkt-len=%d - should be > %d\n", + n, ETHER_MIN_LEN); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "pkt-filter-mode")) { - if (!strcmp(optarg, "signature")) - fdir_conf.mode = - RTE_FDIR_MODE_SIGNATURE; - else if (!strcmp(optarg, "perfect")) - fdir_conf.mode = RTE_FDIR_MODE_PERFECT; - else if (!strcmp(optarg, "perfect-mac-vlan")) - fdir_conf.mode = RTE_FDIR_MODE_PERFECT_MAC_VLAN; - else if (!strcmp(optarg, "perfect-tunnel")) - fdir_conf.mode = RTE_FDIR_MODE_PERFECT_TUNNEL; - else if (!strcmp(optarg, "none")) - fdir_conf.mode = RTE_FDIR_MODE_NONE; - else - rte_exit(EXIT_FAILURE, - "pkt-mode-invalid %s invalid - must be: " - "none, signature, perfect, perfect-mac-vlan" - " or perfect-tunnel\n", - optarg); + } + if (!strcmp(lgopts[opt_idx].name, "pkt-filter-mode")) { + if (!strcmp(optarg, "signature")) + fdir_conf.mode = + RTE_FDIR_MODE_SIGNATURE; + else if (!strcmp(optarg, "perfect")) + fdir_conf.mode = RTE_FDIR_MODE_PERFECT; + else if (!strcmp(optarg, "perfect-mac-vlan")) + fdir_conf.mode = RTE_FDIR_MODE_PERFECT_MAC_VLAN; + else if (!strcmp(optarg, "perfect-tunnel")) + fdir_conf.mode = RTE_FDIR_MODE_PERFECT_TUNNEL; + else if (!strcmp(optarg, "none")) + fdir_conf.mode = RTE_FDIR_MODE_NONE; + else { + rte_exit(EXIT_FAILURE, + "pkt-mode-invalid %s invalid - must be: " + "none, signature, perfect, perfect-mac-vlan" + " or perfect-tunnel\n", + optarg); + return -1; } - if (!strcmp(lgopts[opt_idx].name, - "pkt-filter-report-hash")) { - if (!strcmp(optarg, "none")) - fdir_conf.status = - RTE_FDIR_NO_REPORT_STATUS; - else if (!strcmp(optarg, "match")) - fdir_conf.status = - RTE_FDIR_REPORT_STATUS; - else if (!strcmp(optarg, "always")) - fdir_conf.status = - RTE_FDIR_REPORT_STATUS_ALWAYS; - else - rte_exit(EXIT_FAILURE, - "pkt-filter-report-hash %s invalid " - "- must be: none or match or always\n", - optarg); + } + if (!strcmp(lgopts[opt_idx].name, + "pkt-filter-report-hash")) { + if (!strcmp(optarg, "none")) + fdir_conf.status = + RTE_FDIR_NO_REPORT_STATUS; + else if (!strcmp(optarg, "match")) + fdir_conf.status = + RTE_FDIR_REPORT_STATUS; + else if (!strcmp(optarg, "always")) + fdir_conf.status = + RTE_FDIR_REPORT_STATUS_ALWAYS; + else { + rte_exit(EXIT_FAILURE, + "pkt-filter-report-hash %s invalid " + "- must be: none or match or always\n", + optarg); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "pkt-filter-size")) { - if (!strcmp(optarg, "64K")) - fdir_conf.pballoc = - RTE_FDIR_PBALLOC_64K; - else if (!strcmp(optarg, "128K")) - fdir_conf.pballoc = - RTE_FDIR_PBALLOC_128K; - else if (!strcmp(optarg, "256K")) - fdir_conf.pballoc = - RTE_FDIR_PBALLOC_256K; - else - rte_exit(EXIT_FAILURE, "pkt-filter-size %s invalid -" - " must be: 64K or 128K or 256K\n", - optarg); + } + if (!strcmp(lgopts[opt_idx].name, "pkt-filter-size")) { + if (!strcmp(optarg, "64K")) + fdir_conf.pballoc = + RTE_FDIR_PBALLOC_64K; + else if (!strcmp(optarg, "128K")) + fdir_conf.pballoc = + RTE_FDIR_PBALLOC_128K; + else if (!strcmp(optarg, "256K")) + fdir_conf.pballoc = + RTE_FDIR_PBALLOC_256K; + else { + rte_exit(EXIT_FAILURE, "pkt-filter-size %s invalid -" + " must be: 64K or 128K or 256K\n", + optarg); + return -1; } - if (!strcmp(lgopts[opt_idx].name, - "pkt-filter-drop-queue")) { - n = atoi(optarg); - if (n >= 0) - fdir_conf.drop_queue = (uint8_t) n; - else - rte_exit(EXIT_FAILURE, - "drop queue %d invalid - must" - "be >= 0 \n", n); + } + if (!strcmp(lgopts[opt_idx].name, + "pkt-filter-drop-queue")) { + n = atoi(optarg); + if (n >= 0) + fdir_conf.drop_queue = (uint8_t) n; + else { + rte_exit(EXIT_FAILURE, + "drop queue %d invalid - must " + "be >= 0\n", n); + return -1; } + } #ifdef RTE_LIBRTE_LATENCY_STATS - if (!strcmp(lgopts[opt_idx].name, - "latencystats")) { - n = atoi(optarg); - if (n >= 0) { - latencystats_lcore_id = (lcoreid_t) n; - latencystats_enabled = 1; - } else - rte_exit(EXIT_FAILURE, - "invalid lcore id %d for latencystats" - " must be >= 0\n", n); + if (!strcmp(lgopts[opt_idx].name, + "latencystats")) { + n = atoi(optarg); + if (n >= 0) { + latencystats_lcore_id = (lcoreid_t) n; + latencystats_enabled = 1; + } else { + rte_exit(EXIT_FAILURE, + "invalid lcore id %d for latencystats" + " must be >= 0\n", n); + return -1; } + } #endif #ifdef RTE_LIBRTE_BITRATE - if (!strcmp(lgopts[opt_idx].name, "bitrate-stats")) { - n = atoi(optarg); - if (n >= 0) { - bitrate_lcore_id = (lcoreid_t) n; - bitrate_enabled = 1; - } else - rte_exit(EXIT_FAILURE, - "invalid lcore id %d for bitrate stats" - " must be >= 0\n", n); + if (!strcmp(lgopts[opt_idx].name, "bitrate-stats")) { + n = atoi(optarg); + if (n >= 0) { + bitrate_lcore_id = (lcoreid_t) n; + bitrate_enabled = 1; + } else { + rte_exit(EXIT_FAILURE, + "invalid lcore id %d for bitrate stats" + " must be >= 0\n", n); + return -1; } + } #endif - if (!strcmp(lgopts[opt_idx].name, "disable-crc-strip")) - rx_mode.hw_strip_crc = 0; - if (!strcmp(lgopts[opt_idx].name, "enable-lro")) - rx_mode.enable_lro = 1; - if (!strcmp(lgopts[opt_idx].name, "enable-scatter")) - rx_mode.enable_scatter = 1; - if (!strcmp(lgopts[opt_idx].name, "enable-rx-cksum")) - rx_mode.hw_ip_checksum = 1; - - if (!strcmp(lgopts[opt_idx].name, "disable-hw-vlan")) { - rx_mode.hw_vlan_filter = 0; - rx_mode.hw_vlan_strip = 0; - rx_mode.hw_vlan_extend = 0; - } + if (!strcmp(lgopts[opt_idx].name, "disable-crc-strip")) + rx_mode.hw_strip_crc = 0; + if (!strcmp(lgopts[opt_idx].name, "enable-lro")) + rx_mode.enable_lro = 1; + if (!strcmp(lgopts[opt_idx].name, "enable-scatter")) + rx_mode.enable_scatter = 1; + if (!strcmp(lgopts[opt_idx].name, "enable-rx-cksum")) + rx_mode.hw_ip_checksum = 1; - if (!strcmp(lgopts[opt_idx].name, - "disable-hw-vlan-filter")) - rx_mode.hw_vlan_filter = 0; - - if (!strcmp(lgopts[opt_idx].name, - "disable-hw-vlan-strip")) - rx_mode.hw_vlan_strip = 0; - - if (!strcmp(lgopts[opt_idx].name, - "disable-hw-vlan-extend")) - rx_mode.hw_vlan_extend = 0; - - if (!strcmp(lgopts[opt_idx].name, "enable-drop-en")) - rx_drop_en = 1; - - if (!strcmp(lgopts[opt_idx].name, "disable-rss")) - rss_hf = 0; - if (!strcmp(lgopts[opt_idx].name, "port-topology")) { - if (!strcmp(optarg, "paired")) - port_topology = PORT_TOPOLOGY_PAIRED; - else if (!strcmp(optarg, "chained")) - port_topology = PORT_TOPOLOGY_CHAINED; - else if (!strcmp(optarg, "loop")) - port_topology = PORT_TOPOLOGY_LOOP; - else - rte_exit(EXIT_FAILURE, "port-topology %s invalid -" - " must be: paired or chained \n", - optarg); + if (!strcmp(lgopts[opt_idx].name, "disable-hw-vlan")) { + rx_mode.hw_vlan_filter = 0; + rx_mode.hw_vlan_strip = 0; + rx_mode.hw_vlan_extend = 0; + } + + if (!strcmp(lgopts[opt_idx].name, + "disable-hw-vlan-filter")) + rx_mode.hw_vlan_filter = 0; + + if (!strcmp(lgopts[opt_idx].name, + "disable-hw-vlan-strip")) + rx_mode.hw_vlan_strip = 0; + + if (!strcmp(lgopts[opt_idx].name, + "disable-hw-vlan-extend")) + rx_mode.hw_vlan_extend = 0; + + if (!strcmp(lgopts[opt_idx].name, "enable-drop-en")) + rx_drop_en = 1; + + if (!strcmp(lgopts[opt_idx].name, "disable-rss")) + rss_hf = 0; + if (!strcmp(lgopts[opt_idx].name, "port-topology")) { + if (!strcmp(optarg, "paired")) + port_topology = PORT_TOPOLOGY_PAIRED; + else if (!strcmp(optarg, "chained")) + port_topology = PORT_TOPOLOGY_CHAINED; + else if (!strcmp(optarg, "loop")) + port_topology = PORT_TOPOLOGY_LOOP; + else { + rte_exit(EXIT_FAILURE, "port-topology %s invalid -" + " must be: paired or chained\n", + optarg); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "forward-mode")) - set_pkt_forwarding_mode(optarg); - if (!strcmp(lgopts[opt_idx].name, "rss-ip")) - rss_hf = ETH_RSS_IP; - if (!strcmp(lgopts[opt_idx].name, "rss-udp")) - rss_hf = ETH_RSS_UDP; - if (!strcmp(lgopts[opt_idx].name, "rxq")) { - n = atoi(optarg); - if (n >= 0 && n <= (int) MAX_QUEUE_ID) - nb_rxq = (queueid_t) n; - else - rte_exit(EXIT_FAILURE, "rxq %d invalid - must be" - " >= 0 && <= %d\n", n, - (int) MAX_QUEUE_ID); + } + if (!strcmp(lgopts[opt_idx].name, "forward-mode")) + set_pkt_forwarding_mode(optarg); + if (!strcmp(lgopts[opt_idx].name, "rss-ip")) + rss_hf = ETH_RSS_IP; + if (!strcmp(lgopts[opt_idx].name, "rss-udp")) + rss_hf = ETH_RSS_UDP; + if (!strcmp(lgopts[opt_idx].name, "rxq")) { + n = atoi(optarg); + if (n >= 0 && n <= (int) MAX_QUEUE_ID) + nb_rxq = (queueid_t) n; + else { + rte_exit(EXIT_FAILURE, "rxq %d invalid - must be" + " >= 0 && <= %d\n", n, + (int) MAX_QUEUE_ID); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txq")) { - n = atoi(optarg); - if (n >= 0 && n <= (int) MAX_QUEUE_ID) - nb_txq = (queueid_t) n; - else - rte_exit(EXIT_FAILURE, "txq %d invalid - must be" - " >= 0 && <= %d\n", n, - (int) MAX_QUEUE_ID); + } + if (!strcmp(lgopts[opt_idx].name, "txq")) { + n = atoi(optarg); + if (n >= 0 && n <= (int) MAX_QUEUE_ID) + nb_txq = (queueid_t) n; + else { + rte_exit(EXIT_FAILURE, "txq %d invalid - must be" + " >= 0 && <= %d\n", n, + (int) MAX_QUEUE_ID); + return -1; } - if (!nb_rxq && !nb_txq) { - rte_exit(EXIT_FAILURE, "Either rx or tx queues should " - "be non-zero\n"); + } + if (!nb_rxq && !nb_txq) { + rte_exit(EXIT_FAILURE, "Either rx or tx queues should " + "be non-zero\n"); + return -1; + } + if (!strcmp(lgopts[opt_idx].name, "burst")) { + n = atoi(optarg); + if ((n >= 1) && (n <= MAX_PKT_BURST)) + nb_pkt_per_burst = (uint16_t) n; + else { + rte_exit(EXIT_FAILURE, + "burst must >= 1 and <= %d]", + MAX_PKT_BURST); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "burst")) { - n = atoi(optarg); - if ((n >= 1) && (n <= MAX_PKT_BURST)) - nb_pkt_per_burst = (uint16_t) n; - else - rte_exit(EXIT_FAILURE, - "burst must >= 1 and <= %d]", - MAX_PKT_BURST); + } + if (!strcmp(lgopts[opt_idx].name, "mbcache")) { + n = atoi(optarg); + if ((n >= 0) && + (n <= RTE_MEMPOOL_CACHE_MAX_SIZE)) + mb_mempool_cache = (uint16_t) n; + else { + rte_exit(EXIT_FAILURE, + "mbcache must be >= 0 and <= %d\n", + RTE_MEMPOOL_CACHE_MAX_SIZE); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "mbcache")) { - n = atoi(optarg); - if ((n >= 0) && - (n <= RTE_MEMPOOL_CACHE_MAX_SIZE)) - mb_mempool_cache = (uint16_t) n; - else - rte_exit(EXIT_FAILURE, - "mbcache must be >= 0 and <= %d\n", - RTE_MEMPOOL_CACHE_MAX_SIZE); + } + if (!strcmp(lgopts[opt_idx].name, "txfreet")) { + n = atoi(optarg); + if (n >= 0) + tx_free_thresh = (int16_t)n; + else { + rte_exit(EXIT_FAILURE, "txfreet must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txfreet")) { - n = atoi(optarg); - if (n >= 0) - tx_free_thresh = (int16_t)n; - else - rte_exit(EXIT_FAILURE, "txfreet must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txrst")) { + n = atoi(optarg); + if (n >= 0) + tx_rs_thresh = (int16_t)n; + else { + rte_exit(EXIT_FAILURE, "txrst must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txrst")) { - n = atoi(optarg); - if (n >= 0) - tx_rs_thresh = (int16_t)n; - else - rte_exit(EXIT_FAILURE, "txrst must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txqflags")) { + char *end = NULL; + + n = strtoul(optarg, &end, 16); + if (n >= 0) + txq_flags = (int32_t)n; + else { + rte_exit(EXIT_FAILURE, + "txqflags must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txqflags")) { - char *end = NULL; - n = strtoul(optarg, &end, 16); - if (n >= 0) - txq_flags = (int32_t)n; - else + } + if (!strcmp(lgopts[opt_idx].name, "rxd")) { + n = atoi(optarg); + if (n > 0) { + if (rx_free_thresh >= n) rte_exit(EXIT_FAILURE, - "txqflags must be >= 0\n"); + "rxd must be > " + "rx_free_thresh(%d)\n", + (int)rx_free_thresh); + else + nb_rxd = (uint16_t) n; + } else { + rte_exit(EXIT_FAILURE, + "rxd(%d) invalid - must be > 0\n", + n); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxd")) { - n = atoi(optarg); - if (n > 0) { - if (rx_free_thresh >= n) - rte_exit(EXIT_FAILURE, - "rxd must be > " - "rx_free_thresh(%d)\n", - (int)rx_free_thresh); - else - nb_rxd = (uint16_t) n; - } else - rte_exit(EXIT_FAILURE, - "rxd(%d) invalid - must be > 0\n", - n); + } + if (!strcmp(lgopts[opt_idx].name, "txd")) { + n = atoi(optarg); + if (n > 0) + nb_txd = (uint16_t) n; + else { + rte_exit(EXIT_FAILURE, "txd must be in > 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txd")) { - n = atoi(optarg); - if (n > 0) - nb_txd = (uint16_t) n; - else - rte_exit(EXIT_FAILURE, "txd must be in > 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txpt")) { + n = atoi(optarg); + if (n >= 0) + tx_pthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "txpt must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txpt")) { - n = atoi(optarg); - if (n >= 0) - tx_pthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "txpt must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txht")) { + n = atoi(optarg); + if (n >= 0) + tx_hthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "txht must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txht")) { - n = atoi(optarg); - if (n >= 0) - tx_hthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "txht must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txwt")) { + n = atoi(optarg); + if (n >= 0) + tx_wthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "txwt must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txwt")) { - n = atoi(optarg); - if (n >= 0) - tx_wthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "txwt must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "rxpt")) { + n = atoi(optarg); + if (n >= 0) + rx_pthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "rxpt must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxpt")) { - n = atoi(optarg); - if (n >= 0) - rx_pthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "rxpt must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "rxht")) { + n = atoi(optarg); + if (n >= 0) + rx_hthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "rxht must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxht")) { - n = atoi(optarg); - if (n >= 0) - rx_hthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "rxht must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "rxwt")) { + n = atoi(optarg); + if (n >= 0) + rx_wthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "rxwt must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxwt")) { - n = atoi(optarg); - if (n >= 0) - rx_wthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "rxwt must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "rxfreet")) { + n = atoi(optarg); + if (n >= 0) + rx_free_thresh = (int16_t)n; + else { + rte_exit(EXIT_FAILURE, "rxfreet must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxfreet")) { - n = atoi(optarg); - if (n >= 0) - rx_free_thresh = (int16_t)n; - else - rte_exit(EXIT_FAILURE, "rxfreet must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "tx-queue-stats-mapping")) { + if (parse_queue_stats_mapping_config(optarg, TX)) { + rte_exit(EXIT_FAILURE, + "invalid TX queue statistics mapping config entered\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "tx-queue-stats-mapping")) { - if (parse_queue_stats_mapping_config(optarg, TX)) { - rte_exit(EXIT_FAILURE, - "invalid TX queue statistics mapping config entered\n"); - } + } + if (!strcmp(lgopts[opt_idx].name, "rx-queue-stats-mapping")) { + if (parse_queue_stats_mapping_config(optarg, RX)) { + rte_exit(EXIT_FAILURE, + "invalid RX queue statistics mapping config entered\n"); } - if (!strcmp(lgopts[opt_idx].name, "rx-queue-stats-mapping")) { - if (parse_queue_stats_mapping_config(optarg, RX)) { - rte_exit(EXIT_FAILURE, - "invalid RX queue statistics mapping config entered\n"); - } + } + if (!strcmp(lgopts[opt_idx].name, "txpkts")) { + unsigned int seg_lengths[RTE_MAX_SEGS_PER_PKT]; + unsigned int nb_segs; + + nb_segs = parse_item_list(optarg, "txpkt segments", + RTE_MAX_SEGS_PER_PKT, seg_lengths, 0); + if (nb_segs > 0) + set_tx_pkt_segments(seg_lengths, nb_segs); + else { + rte_exit(EXIT_FAILURE, "bad txpkts\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txpkts")) { - unsigned seg_lengths[RTE_MAX_SEGS_PER_PKT]; - unsigned int nb_segs; - - nb_segs = parse_item_list(optarg, "txpkt segments", - RTE_MAX_SEGS_PER_PKT, seg_lengths, 0); - if (nb_segs > 0) - set_tx_pkt_segments(seg_lengths, nb_segs); - else - rte_exit(EXIT_FAILURE, "bad txpkts\n"); + } + if (!strcmp(lgopts[opt_idx].name, "no-flush-rx")) + no_flush_rx = 1; + if (!strcmp(lgopts[opt_idx].name, "disable-link-check")) + no_link_check = 1; + if (!strcmp(lgopts[opt_idx].name, "no-lsc-interrupt")) + lsc_interrupt = 0; + if (!strcmp(lgopts[opt_idx].name, "no-rmv-interrupt")) + rmv_interrupt = 0; + if (!strcmp(lgopts[opt_idx].name, "print-event")) + if (parse_event_printing_config(optarg, 1)) { + rte_exit(EXIT_FAILURE, + "invalid print-event argument\n"); + return -1; + } + if (!strcmp(lgopts[opt_idx].name, "mask-event")) + if (parse_event_printing_config(optarg, 0)) { + rte_exit(EXIT_FAILURE, + "invalid mask-event argument\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "no-flush-rx")) - no_flush_rx = 1; - if (!strcmp(lgopts[opt_idx].name, "disable-link-check")) - no_link_check = 1; - if (!strcmp(lgopts[opt_idx].name, "no-lsc-interrupt")) - lsc_interrupt = 0; - if (!strcmp(lgopts[opt_idx].name, "no-rmv-interrupt")) - rmv_interrupt = 0; - if (!strcmp(lgopts[opt_idx].name, "print-event")) - if (parse_event_printing_config(optarg, 1)) { - rte_exit(EXIT_FAILURE, - "invalid print-event argument\n"); - } - if (!strcmp(lgopts[opt_idx].name, "mask-event")) - if (parse_event_printing_config(optarg, 0)) { - rte_exit(EXIT_FAILURE, - "invalid mask-event argument\n"); - } - break; - case 'h': - usage(argv[0]); - rte_exit(EXIT_SUCCESS, "Displayed help\n"); - break; - default: - usage(argv[0]); - rte_exit(EXIT_FAILURE, - "Command line is incomplete or incorrect\n"); + break; + case 'h': + usage(prgname); + rte_exit(EXIT_SUCCESS, "Displayed help\n"); + return -1; + case 1: + /* does nothing*/ + break; + default: + usage(prgname); + rte_exit(EXIT_FAILURE, + "Command line is incomplete or incorrect\n"); + return -1; + } + return 0; +} + +void +launch_args_parse(int argc, char **argv) +{ + int opt; + char **argvopt; + int opt_idx; + + argvopt = argv; + + while ((opt = getopt_long(argc, argvopt, SHORTOPTS "ah", + lgopts, &opt_idx)) != EOF) { + parse_option(opt, optarg, opt_idx, argv[0]); + } +} + +#ifdef RTE_LIBRTE_CFGFILE +static void +non_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; lgopts[i].name != NULL; i++) { + if (strcmp(str, lgopts[i].name) == 0) { + *opt = lgopts[i].val; + *option_index = i; break; } } } +#endif + +#ifdef RTE_LIBRTE_CFGFILE +#define APP_SECTION "TEST-PMD" +int non_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, APP_SECTION); + + if (n_entries < 1) { + printf("No %s section entries " + "in cfgfile object\n", APP_SECTION); + return -1; + } + + struct rte_cfgfile_entry entries[n_entries]; + + if (n_entries != + rte_cfgfile_section_entries(cfg, APP_SECTION, entries, + n_entries)) { + rte_exit(EXIT_FAILURE, "Unexpected fault"); + return -1; + } + + for (i = 0; i < n_entries; i++) { + non_eal_getopt(entries[i].name, &opt, &option_index); + + parse_option(opt, entries[i].value, + option_index, prgname); + } + return 0; +} +#endif diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index e09b803..7b82976 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -91,6 +91,9 @@ #include <rte_latencystats.h> #endif #include <rte_gro.h> +#ifdef RTE_LIBRTE_CFGFILE +#include <rte_cfgfile.h> +#endif #include "testpmd.h" @@ -2266,15 +2269,66 @@ signal_handler(int signum) } } +#ifdef RTE_LIBRTE_CFGFILE +/* Load config file path from command line */ +static char * +cfgfile_load_path(int argc, char **argv) +{ + int i; + + for (i = 0; i < argc; i++) { + if (!strcmp("--cfgfile-path", argv[i])) { + if (argv[i+1] && argv[i+1][0] != '-') + return strdup(argv[i+1]); + } else if (!strncmp("--cfgfile-path=", argv[i], 15)) { + char *ptr = argv[i]; + + ptr += 15; + if (strlen(ptr)) + return strdup(ptr); + } + } + return NULL; +} +#endif + +#define APP_NAME "TEST-PMD" int main(int argc, char** argv) { int diag; uint8_t port_id; +#ifdef RTE_LIBRTE_CFGFILE + struct rte_cfgfile *cfg = NULL; + char *config_file = NULL; +#endif signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); +#ifdef RTE_LIBRTE_CFGFILE + /* load --cfgfile-path argument from argv */ + config_file = cfgfile_load_path(argc, argv); + + if (config_file) { + printf("Info: found cfgfile-path \"%s\"\n", config_file); + } else { + printf("Info: not found cfgfile-path parameter " + "(searching for cfgfile " + "in default directory)\n"); + config_file = strdup("config.ini"); + } + + cfg = rte_cfgfile_load(config_file, CFG_FLAG_EMPTY_VALUES); + + if (cfg == NULL) { + printf("Info: Valid cfgfile not found\n"); + } else { + diag = rte_eal_configure(cfg, argv[0]); + if (diag < 0) + rte_panic("Cannot init EAL\n"); + } +#endif diag = rte_eal_init(argc, argv); if (diag < 0) rte_panic("Cannot init EAL\n"); @@ -2304,6 +2358,18 @@ main(int argc, char** argv) latencystats_enabled = 0; #endif +#ifdef RTE_LIBRTE_CFGFILE + if (cfg != NULL) { + non_eal_configure(cfg, argv[0]); + rte_cfgfile_close(cfg); + cfg = 0; + + if (config_file) { + free(config_file); + config_file = 0; + } + } +#endif argc -= diag; argv += diag; if (argc > 1) @@ -2400,6 +2466,5 @@ main(int argc, char** argv) if (rc < 0) return 1; } - return 0; } diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 73985c3..8ff4d88 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -512,7 +512,7 @@ port_pci_reg_write(struct rte_port *port, uint32_t reg_off, uint32_t reg_v) unsigned int parse_item_list(char* str, const char* item_name, unsigned int max_items, unsigned int *parsed_items, int check_unique_values); -void launch_args_parse(int argc, char** argv); +void launch_args_parse(int argc, char **argv); void cmdline_read_from_file(const char *filename); void prompt(void); void prompt_exit(void); @@ -656,6 +656,7 @@ enum print_warning { }; int port_id_is_invalid(portid_t port_id, enum print_warning warning); int new_socket_id(unsigned int socket_id); +int non_eal_configure(struct rte_cfgfile *cfg, char *prgname); /* * Work-around of a compilation error with ICC on invocations of the -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v5 3/3] app/testpmd: add parse options from JSON cfg file 2017-07-13 10:07 ` Kuba Kozak 2017-07-13 10:07 ` [dpdk-dev] [PATCH v5 1/3] eal: add functions parsing EAL arguments Kuba Kozak 2017-07-13 10:07 ` [dpdk-dev] [PATCH v5 2/3] app/testpmd: add parse options from cfg file Kuba Kozak @ 2017-07-13 10:07 ` Kuba Kozak 2019-01-23 19:31 ` [dpdk-dev] [PATCH v5 0/3] EAL change for using a config file for DPDK Ferruh Yigit 3 siblings, 0 replies; 70+ messages in thread From: Kuba Kozak @ 2017-07-13 10:07 UTC (permalink / raw) To: dev Cc: deepak.k.jain, bruce.richardson, michalx.k.jastrzebski, jacekx.piasecki, Kuba Kozak This patch shows usage of Jansson library to parse application arguments from JSON config file. https://github.com/akheron/jansson If a --cfgfile-path <path> option is passed into commandline non EAL section, then the disired JSON file is loaded and used by app. In case when JSON doesn't exist an INI file is loaded. The INI file can be passed also from --cfgfile-path option. 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. Signed-off-by: Kuba Kozak <kubax.kozak@intel.com> Suggested-by: Bruce Richardson <bruce.richardson@intel.com> --- app/test-pmd/Makefile | 6 ++++ app/test-pmd/config.json | 33 +++++++++++++++++ app/test-pmd/testpmd.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++- config/common_base | 5 +++ 4 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 app/test-pmd/config.json diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile index c36be19..a1c84cc 100644 --- a/app/test-pmd/Makefile +++ b/app/test-pmd/Makefile @@ -83,6 +83,12 @@ endif endif +ifeq ($(CONFIG_RTE_JSON_SUPPORT),y) +ifeq ($(CONFIG_RTE_LIBRTE_CFGFILE),y) +LDLIBS += -ljansson +endif +endif + CFLAGS_cmdline.o := -D_GNU_SOURCE include $(RTE_SDK)/mk/rte.app.mk diff --git a/app/test-pmd/config.json b/app/test-pmd/config.json new file mode 100644 index 0000000..4589dbc --- /dev/null +++ b/app/test-pmd/config.json @@ -0,0 +1,33 @@ +{ + "DPDK": + { + "v": "", + "l": "0-4", + "n": "4", + "master-lcore": "0", + "proc-type": "primary" + }, + "TEST-PMD": + { + "i": "", + "portmask": "0xff", + "nb-cores": "4", + "port-topology": "paired" + }, + "DPDK.vdev0": + { + "net_ring0": "" + }, + "DPDK.vdev1": + { + "net_ring1": "" + }, + "DPDK.vdev2": + { + "net_ring2": "" + }, + "DPDK.vdev3": + { + "net_ring3": "" + } +} diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index 7b82976..014bb46 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -46,6 +46,10 @@ #include <stdint.h> #include <unistd.h> + +#ifdef RTE_JSON_SUPPORT +#include <jansson.h> +#endif #include <inttypes.h> #include <rte_common.h> @@ -2290,6 +2294,87 @@ cfgfile_load_path(int argc, char **argv) } return NULL; } + +#ifdef RTE_JSON_SUPPORT +/* + * Decoding JSON structure to rte_cfgfile structure. + * Returns handler to cfgfile object, NULL if error. + */ +static struct +rte_cfgfile *l3fwd_json_to_cfg(json_t *json, int flags) +{ + if (!json) { + printf("Error: JSON structure is NULL, nothing to parse\n"); + return NULL; + } + /* create an empty instance of cfgfile structure */ + struct rte_cfgfile *cfgfile = rte_cfgfile_create(flags); + + if (!cfgfile) + return NULL; + + const char *section; + json_t *entry; + + /* set pointer to first section */ + void *iter_section = json_object_iter(json); + + while (iter_section) { + + section = json_object_iter_key(iter_section); + entry = json_object_iter_value(iter_section); + + /* add parsed section name of current section to cfgfile */ + rte_cfgfile_add_section(cfgfile, section); + + /* set pointer to first entry */ + void *iter_entry = json_object_iter(entry); + + while (iter_entry) { + + const char *key; + const char *value; + + key = json_object_iter_key(iter_entry); + value = json_string_value( + json_object_iter_value(iter_entry)); + + /* add parsed key and value of current entry */ + /* to cfgfile */ + rte_cfgfile_add_entry(cfgfile, section, key, value); + + /* pointer to next entry */ + iter_entry = json_object_iter_next(entry, iter_entry); + } + /* pointer to next section */ + iter_section = json_object_iter_next(json, iter_section); + } + return cfgfile; +} + +/* + * Check presence and load JSON file to rte_cfgfile structure. + * Returns handler to cfgfile object, NULL if error. + */ +static struct +rte_cfgfile *l3fwd_load_json_to_cfg(const char *path) +{ + struct rte_cfgfile *cfgfile = NULL; + /* check if config file exist */ + if (access(path, F_OK) != -1) { + /* parse JSON file */ + json_error_t error; + json_t *json = json_load_file(path, 0, &error); + + if (json) + cfgfile = l3fwd_json_to_cfg(json, 0); + else + fprintf(stderr, "JSON error on line %d: %s\n", + error.line, error.text); + } + return cfgfile; +} +#endif #endif #define APP_NAME "TEST-PMD" @@ -2318,9 +2403,16 @@ main(int argc, char** argv) "in default directory)\n"); config_file = strdup("config.ini"); } - +#ifndef RTE_JSON_SUPPORT cfg = rte_cfgfile_load(config_file, CFG_FLAG_EMPTY_VALUES); +#endif +#ifdef RTE_JSON_SUPPORT + if (strstr(config_file, ".ini")) + cfg = rte_cfgfile_load(config_file, CFG_FLAG_EMPTY_VALUES); + else if (strstr(config_file, ".json")) + cfg = l3fwd_load_json_to_cfg(config_file); +#endif if (cfg == NULL) { printf("Info: Valid cfgfile not found\n"); } else { diff --git a/config/common_base b/config/common_base index 8ae6e92..98e8fa2 100644 --- a/config/common_base +++ b/config/common_base @@ -744,3 +744,8 @@ CONFIG_RTE_APP_CRYPTO_PERF=y # Compile the eventdev application # CONFIG_RTE_APP_EVENTDEV=y + +# +# Compile JSON support +# +CONFIG_RTE_JSON_SUPPORT=n \ No newline at end of file -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v5 0/3] EAL change for using a config file for DPDK 2017-07-13 10:07 ` Kuba Kozak ` (2 preceding siblings ...) 2017-07-13 10:07 ` [dpdk-dev] [PATCH v5 3/3] app/testpmd: add parse options from JSON " Kuba Kozak @ 2019-01-23 19:31 ` Ferruh Yigit 2019-01-23 20:26 ` Thomas Monjalon 3 siblings, 1 reply; 70+ messages in thread From: Ferruh Yigit @ 2019-01-23 19:31 UTC (permalink / raw) To: Kuba Kozak Cc: deepak.k.jain, bruce.richardson, michalx.k.jastrzebski, jacekx.piasecki, dpdk-dev, Thomas Monjalon, Stephen Hemminger, Kevin Traynor, David Marchand On 7/13/2017 11:07 AM, kubax.kozak at intel.com (Kuba Kozak) wrote: > 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" > > v5: > changed define "RTE_DEVTYPE_VIRTUAL" to "RTE_DEVTYPE_UNDEFINED" > due to compilation errors (changes on current master). > > 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 This patchset is idle more than a year now. It solves problem of eal parameters, it doesn't remove them but at least moves from command line to config file. The patch seems mostly done, but what is the status of it, do we want to continue it? And if we want to continue it can this be a good candidate for GCOS? ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v5 0/3] EAL change for using a config file for DPDK 2019-01-23 19:31 ` [dpdk-dev] [PATCH v5 0/3] EAL change for using a config file for DPDK Ferruh Yigit @ 2019-01-23 20:26 ` Thomas Monjalon 2019-01-24 13:54 ` Ferruh Yigit 0 siblings, 1 reply; 70+ messages in thread From: Thomas Monjalon @ 2019-01-23 20:26 UTC (permalink / raw) To: Ferruh Yigit Cc: Kuba Kozak, deepak.k.jain, bruce.richardson, michalx.k.jastrzebski, jacekx.piasecki, dpdk-dev, Stephen Hemminger, Kevin Traynor, David Marchand 23/01/2019 20:31, Ferruh Yigit: > On 7/13/2017 11:07 AM, kubax.kozak at intel.com (Kuba Kozak) wrote: > > 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" > > > > v5: > > changed define "RTE_DEVTYPE_VIRTUAL" to "RTE_DEVTYPE_UNDEFINED" > > due to compilation errors (changes on current master). > > > > 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 > > This patchset is idle more than a year now. > It solves problem of eal parameters, it doesn't remove them but at least moves > from command line to config file. > > The patch seems mostly done, but what is the status of it, do we want to > continue it? > And if we want to continue it can this be a good candidate for GCOS? I think we must focus on reorganization of EAL first. When the options parsing will be better isolated, and accessible from API independant of rte_eal_init, then we could provide some helpers to use those APIs for a config file, a custom command line or anything else. ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v5 0/3] EAL change for using a config file for DPDK 2019-01-23 20:26 ` Thomas Monjalon @ 2019-01-24 13:54 ` Ferruh Yigit 2019-01-24 14:32 ` Thomas Monjalon 0 siblings, 1 reply; 70+ messages in thread From: Ferruh Yigit @ 2019-01-24 13:54 UTC (permalink / raw) To: Thomas Monjalon Cc: Kuba Kozak, deepak.k.jain, bruce.richardson, michalx.k.jastrzebski, jacekx.piasecki, dpdk-dev, Stephen Hemminger, Kevin Traynor, David Marchand On 1/23/2019 8:26 PM, Thomas Monjalon wrote: > 23/01/2019 20:31, Ferruh Yigit: >> On 7/13/2017 11:07 AM, kubax.kozak at intel.com (Kuba Kozak) wrote: >>> 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" >>> >>> v5: >>> changed define "RTE_DEVTYPE_VIRTUAL" to "RTE_DEVTYPE_UNDEFINED" >>> due to compilation errors (changes on current master). >>> >>> 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 >> >> This patchset is idle more than a year now. >> It solves problem of eal parameters, it doesn't remove them but at least moves >> from command line to config file. >> >> The patch seems mostly done, but what is the status of it, do we want to >> continue it? >> And if we want to continue it can this be a good candidate for GCOS? > > I think we must focus on reorganization of EAL first. > When the options parsing will be better isolated, > and accessible from API independant of rte_eal_init, > then we could provide some helpers to use those APIs > for a config file, a custom command line or anything else. Is there any actions do we need to take when patches are rejected? ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v5 0/3] EAL change for using a config file for DPDK 2019-01-24 13:54 ` Ferruh Yigit @ 2019-01-24 14:32 ` Thomas Monjalon 2019-01-24 14:46 ` Ferruh Yigit 0 siblings, 1 reply; 70+ messages in thread From: Thomas Monjalon @ 2019-01-24 14:32 UTC (permalink / raw) To: Ferruh Yigit Cc: Kuba Kozak, deepak.k.jain, bruce.richardson, michalx.k.jastrzebski, jacekx.piasecki, dpdk-dev, Stephen Hemminger, Kevin Traynor, David Marchand 24/01/2019 14:54, Ferruh Yigit: > On 1/23/2019 8:26 PM, Thomas Monjalon wrote: > > 23/01/2019 20:31, Ferruh Yigit: > >> On 7/13/2017 11:07 AM, kubax.kozak at intel.com (Kuba Kozak) wrote: > >>> 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" > >>> > >>> v5: > >>> changed define "RTE_DEVTYPE_VIRTUAL" to "RTE_DEVTYPE_UNDEFINED" > >>> due to compilation errors (changes on current master). > >>> > >>> 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 > >> > >> This patchset is idle more than a year now. > >> It solves problem of eal parameters, it doesn't remove them but at least moves > >> from command line to config file. > >> > >> The patch seems mostly done, but what is the status of it, do we want to > >> continue it? > >> And if we want to continue it can this be a good candidate for GCOS? > > > > I think we must focus on reorganization of EAL first. > > When the options parsing will be better isolated, > > and accessible from API independant of rte_eal_init, > > then we could provide some helpers to use those APIs > > for a config file, a custom command line or anything else. > > Is there any actions do we need to take when patches are rejected? Not sure I understand your question. Any opinion about such plan? ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v5 0/3] EAL change for using a config file for DPDK 2019-01-24 14:32 ` Thomas Monjalon @ 2019-01-24 14:46 ` Ferruh Yigit 2019-01-24 16:06 ` Thomas Monjalon 0 siblings, 1 reply; 70+ messages in thread From: Ferruh Yigit @ 2019-01-24 14:46 UTC (permalink / raw) To: Thomas Monjalon Cc: Kuba Kozak, deepak.k.jain, bruce.richardson, michalx.k.jastrzebski, jacekx.piasecki, dpdk-dev, Stephen Hemminger, Kevin Traynor, David Marchand On 1/24/2019 2:32 PM, Thomas Monjalon wrote: > 24/01/2019 14:54, Ferruh Yigit: >> On 1/23/2019 8:26 PM, Thomas Monjalon wrote: >>> 23/01/2019 20:31, Ferruh Yigit: >>>> On 7/13/2017 11:07 AM, kubax.kozak at intel.com (Kuba Kozak) wrote: >>>>> 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" >>>>> >>>>> v5: >>>>> changed define "RTE_DEVTYPE_VIRTUAL" to "RTE_DEVTYPE_UNDEFINED" >>>>> due to compilation errors (changes on current master). >>>>> >>>>> 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 >>>> >>>> This patchset is idle more than a year now. >>>> It solves problem of eal parameters, it doesn't remove them but at least moves >>>> from command line to config file. >>>> >>>> The patch seems mostly done, but what is the status of it, do we want to >>>> continue it? >>>> And if we want to continue it can this be a good candidate for GCOS? >>> >>> I think we must focus on reorganization of EAL first. >>> When the options parsing will be better isolated, >>> and accessible from API independant of rte_eal_init, >>> then we could provide some helpers to use those APIs >>> for a config file, a custom command line or anything else. >> >> Is there any actions do we need to take when patches are rejected? > > Not sure I understand your question. > Any opinion about such plan? When patch status updated, they will disappear from our radar, should we do something to remind us this kind of work needs to be done and already some patches are available to benefit. Keeping them in the patchwork is one option, but it is getting hard to manage as the list grows there, and not all work stays relevant/active in the backlog. Also their status is not clear in the patchwork backlog. ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v5 0/3] EAL change for using a config file for DPDK 2019-01-24 14:46 ` Ferruh Yigit @ 2019-01-24 16:06 ` Thomas Monjalon 2019-01-24 16:18 ` Ferruh Yigit 0 siblings, 1 reply; 70+ messages in thread From: Thomas Monjalon @ 2019-01-24 16:06 UTC (permalink / raw) To: Ferruh Yigit Cc: Kuba Kozak, deepak.k.jain, bruce.richardson, michalx.k.jastrzebski, jacekx.piasecki, dpdk-dev, Stephen Hemminger, Kevin Traynor, David Marchand 24/01/2019 15:46, Ferruh Yigit: > On 1/24/2019 2:32 PM, Thomas Monjalon wrote: > > 24/01/2019 14:54, Ferruh Yigit: > >> On 1/23/2019 8:26 PM, Thomas Monjalon wrote: > >>> 23/01/2019 20:31, Ferruh Yigit: > >>>> On 7/13/2017 11:07 AM, kubax.kozak at intel.com (Kuba Kozak) wrote: > >>>>> 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" > >>>>> > >>>>> v5: > >>>>> changed define "RTE_DEVTYPE_VIRTUAL" to "RTE_DEVTYPE_UNDEFINED" > >>>>> due to compilation errors (changes on current master). > >>>>> > >>>>> 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 > >>>> > >>>> This patchset is idle more than a year now. > >>>> It solves problem of eal parameters, it doesn't remove them but at least moves > >>>> from command line to config file. > >>>> > >>>> The patch seems mostly done, but what is the status of it, do we want to > >>>> continue it? > >>>> And if we want to continue it can this be a good candidate for GCOS? > >>> > >>> I think we must focus on reorganization of EAL first. > >>> When the options parsing will be better isolated, > >>> and accessible from API independant of rte_eal_init, > >>> then we could provide some helpers to use those APIs > >>> for a config file, a custom command line or anything else. > >> > >> Is there any actions do we need to take when patches are rejected? > > > > Not sure I understand your question. > > Any opinion about such plan? > > When patch status updated, they will disappear from our radar, should we do > something to remind us this kind of work needs to be done and already some > patches are available to benefit. > > Keeping them in the patchwork is one option, but it is getting hard to manage as > the list grows there, and not all work stays relevant/active in the backlog. > Also their status is not clear in the patchwork backlog. I think we should add an item in the roadmap with a link to this patch. ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v5 0/3] EAL change for using a config file for DPDK 2019-01-24 16:06 ` Thomas Monjalon @ 2019-01-24 16:18 ` Ferruh Yigit 2019-01-24 17:45 ` Thomas Monjalon 0 siblings, 1 reply; 70+ messages in thread From: Ferruh Yigit @ 2019-01-24 16:18 UTC (permalink / raw) To: Thomas Monjalon Cc: Kuba Kozak, deepak.k.jain, bruce.richardson, michalx.k.jastrzebski, jacekx.piasecki, dpdk-dev, Stephen Hemminger, Kevin Traynor, David Marchand On 1/24/2019 4:06 PM, Thomas Monjalon wrote: > 24/01/2019 15:46, Ferruh Yigit: >> On 1/24/2019 2:32 PM, Thomas Monjalon wrote: >>> 24/01/2019 14:54, Ferruh Yigit: >>>> On 1/23/2019 8:26 PM, Thomas Monjalon wrote: >>>>> 23/01/2019 20:31, Ferruh Yigit: >>>>>> On 7/13/2017 11:07 AM, kubax.kozak at intel.com (Kuba Kozak) wrote: >>>>>>> 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" >>>>>>> >>>>>>> v5: >>>>>>> changed define "RTE_DEVTYPE_VIRTUAL" to "RTE_DEVTYPE_UNDEFINED" >>>>>>> due to compilation errors (changes on current master). >>>>>>> >>>>>>> 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 >>>>>> >>>>>> This patchset is idle more than a year now. >>>>>> It solves problem of eal parameters, it doesn't remove them but at least moves >>>>>> from command line to config file. >>>>>> >>>>>> The patch seems mostly done, but what is the status of it, do we want to >>>>>> continue it? >>>>>> And if we want to continue it can this be a good candidate for GCOS? >>>>> >>>>> I think we must focus on reorganization of EAL first. >>>>> When the options parsing will be better isolated, >>>>> and accessible from API independant of rte_eal_init, >>>>> then we could provide some helpers to use those APIs >>>>> for a config file, a custom command line or anything else. >>>> >>>> Is there any actions do we need to take when patches are rejected? >>> >>> Not sure I understand your question. >>> Any opinion about such plan? >> >> When patch status updated, they will disappear from our radar, should we do >> something to remind us this kind of work needs to be done and already some >> patches are available to benefit. >> >> Keeping them in the patchwork is one option, but it is getting hard to manage as >> the list grows there, and not all work stays relevant/active in the backlog. >> Also their status is not clear in the patchwork backlog. > > I think we should add an item in the roadmap with a link to this patch. OK. Do you want me do it? ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v5 0/3] EAL change for using a config file for DPDK 2019-01-24 16:18 ` Ferruh Yigit @ 2019-01-24 17:45 ` Thomas Monjalon 2019-01-28 14:43 ` Ferruh Yigit 0 siblings, 1 reply; 70+ messages in thread From: Thomas Monjalon @ 2019-01-24 17:45 UTC (permalink / raw) To: Ferruh Yigit Cc: Kuba Kozak, deepak.k.jain, bruce.richardson, michalx.k.jastrzebski, jacekx.piasecki, dpdk-dev, Stephen Hemminger, Kevin Traynor, David Marchand 24/01/2019 17:18, Ferruh Yigit: > On 1/24/2019 4:06 PM, Thomas Monjalon wrote: > > 24/01/2019 15:46, Ferruh Yigit: > >> On 1/24/2019 2:32 PM, Thomas Monjalon wrote: > >>> 24/01/2019 14:54, Ferruh Yigit: > >>>> On 1/23/2019 8:26 PM, Thomas Monjalon wrote: > >>>>> 23/01/2019 20:31, Ferruh Yigit: > >>>>>> On 7/13/2017 11:07 AM, kubax.kozak at intel.com (Kuba Kozak) wrote: > >>>>>>> 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" > >>>>>>> > >>>>>>> v5: > >>>>>>> changed define "RTE_DEVTYPE_VIRTUAL" to "RTE_DEVTYPE_UNDEFINED" > >>>>>>> due to compilation errors (changes on current master). > >>>>>>> > >>>>>>> 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 > >>>>>> > >>>>>> This patchset is idle more than a year now. > >>>>>> It solves problem of eal parameters, it doesn't remove them but at least moves > >>>>>> from command line to config file. > >>>>>> > >>>>>> The patch seems mostly done, but what is the status of it, do we want to > >>>>>> continue it? > >>>>>> And if we want to continue it can this be a good candidate for GCOS? > >>>>> > >>>>> I think we must focus on reorganization of EAL first. > >>>>> When the options parsing will be better isolated, > >>>>> and accessible from API independant of rte_eal_init, > >>>>> then we could provide some helpers to use those APIs > >>>>> for a config file, a custom command line or anything else. > >>>> > >>>> Is there any actions do we need to take when patches are rejected? > >>> > >>> Not sure I understand your question. > >>> Any opinion about such plan? > >> > >> When patch status updated, they will disappear from our radar, should we do > >> something to remind us this kind of work needs to be done and already some > >> patches are available to benefit. > >> > >> Keeping them in the patchwork is one option, but it is getting hard to manage as > >> the list grows there, and not all work stays relevant/active in the backlog. > >> Also their status is not clear in the patchwork backlog. > > > > I think we should add an item in the roadmap with a link to this patch. > > OK. Do you want me do it? Yes please expose your view in a roadmap patch. If needed, we can discuss the plan in techboard meeting. ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v5 0/3] EAL change for using a config file for DPDK 2019-01-24 17:45 ` Thomas Monjalon @ 2019-01-28 14:43 ` Ferruh Yigit 0 siblings, 0 replies; 70+ messages in thread From: Ferruh Yigit @ 2019-01-28 14:43 UTC (permalink / raw) To: Thomas Monjalon Cc: Kuba Kozak, deepak.k.jain, bruce.richardson, michalx.k.jastrzebski, jacekx.piasecki, dpdk-dev, Stephen Hemminger, Kevin Traynor, David Marchand On 1/24/2019 5:45 PM, Thomas Monjalon wrote: > 24/01/2019 17:18, Ferruh Yigit: >> On 1/24/2019 4:06 PM, Thomas Monjalon wrote: >>> 24/01/2019 15:46, Ferruh Yigit: >>>> On 1/24/2019 2:32 PM, Thomas Monjalon wrote: >>>>> 24/01/2019 14:54, Ferruh Yigit: >>>>>> On 1/23/2019 8:26 PM, Thomas Monjalon wrote: >>>>>>> 23/01/2019 20:31, Ferruh Yigit: >>>>>>>> On 7/13/2017 11:07 AM, kubax.kozak at intel.com (Kuba Kozak) wrote: >>>>>>>>> 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" >>>>>>>>> >>>>>>>>> v5: >>>>>>>>> changed define "RTE_DEVTYPE_VIRTUAL" to "RTE_DEVTYPE_UNDEFINED" >>>>>>>>> due to compilation errors (changes on current master). >>>>>>>>> >>>>>>>>> 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 >>>>>>>> >>>>>>>> This patchset is idle more than a year now. >>>>>>>> It solves problem of eal parameters, it doesn't remove them but at least moves >>>>>>>> from command line to config file. >>>>>>>> >>>>>>>> The patch seems mostly done, but what is the status of it, do we want to >>>>>>>> continue it? >>>>>>>> And if we want to continue it can this be a good candidate for GCOS? >>>>>>> >>>>>>> I think we must focus on reorganization of EAL first. >>>>>>> When the options parsing will be better isolated, >>>>>>> and accessible from API independant of rte_eal_init, >>>>>>> then we could provide some helpers to use those APIs >>>>>>> for a config file, a custom command line or anything else. >>>>>> >>>>>> Is there any actions do we need to take when patches are rejected? >>>>> >>>>> Not sure I understand your question. >>>>> Any opinion about such plan? >>>> >>>> When patch status updated, they will disappear from our radar, should we do >>>> something to remind us this kind of work needs to be done and already some >>>> patches are available to benefit. >>>> >>>> Keeping them in the patchwork is one option, but it is getting hard to manage as >>>> the list grows there, and not all work stays relevant/active in the backlog. >>>> Also their status is not clear in the patchwork backlog. >>> >>> I think we should add an item in the roadmap with a link to this patch. >> >> OK. Do you want me do it? > > Yes please expose your view in a roadmap patch. > If needed, we can discuss the plan in techboard meeting. sent, https://mails.dpdk.org/archives/web/2019-January/001011.html ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v4 2/3] app/testpmd: add parse options from cfg file 2017-07-10 12:51 ` [dpdk-dev] [PATCH v4 0/3] EAL change for using a config file for DPDK Kuba Kozak 2017-07-10 12:51 ` [dpdk-dev] [PATCH v4 1/3] eal: add functions parsing EAL arguments Kuba Kozak @ 2017-07-10 12:51 ` Kuba Kozak 2017-07-10 12:51 ` [dpdk-dev] [PATCH v4 3/3] app/testpmd: add parse options from JSON " Kuba Kozak 2 siblings, 0 replies; 70+ messages in thread From: Kuba Kozak @ 2017-07-10 12:51 UTC (permalink / raw) To: dev Cc: deepak.k.jain, bruce.richardson, michalx.k.jastrzebski, jacekx.piasecki, Kuba Kozak This patch shows how to pass arguments to application using config.ini file. If a --cfgfile-path <path> option is passed into commandline non EAL section, then the file is loaded and used by app. If a config.ini file is present in current working directory, and no --cfgfile-path option is passed in, config.ini file will be loaded and used by app as default configuration. Signed-off-by: Kuba Kozak <kubax.kozak@intel.com> Suggested-by: Bruce Richardson <bruce.richardson@intel.com> --- app/test-pmd/config.ini | 24 + app/test-pmd/parameters.c | 1181 +++++++++++++++++++++++++-------------------- app/test-pmd/testpmd.c | 67 ++- app/test-pmd/testpmd.h | 3 +- 4 files changed, 761 insertions(+), 514 deletions(-) create mode 100644 app/test-pmd/config.ini diff --git a/app/test-pmd/config.ini b/app/test-pmd/config.ini new file mode 100644 index 0000000..54c83a2 --- /dev/null +++ b/app/test-pmd/config.ini @@ -0,0 +1,24 @@ +[DPDK] +v = +l = 0-4 +n = 4 +master-lcore = 0 +proc-type = primary + +[TEST-PMD] +i = +portmask = 0xff +nb-cores = 4 +port-topology = paired + +[DPDK.vdev0] +net_ring0 = + +[DPDK.vdev1] +net_ring1 = + +[DPDK.vdev2] +net_ring2 = + +[DPDK.vdev3] +net_ring3 = \ No newline at end of file diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c index 958b3d0..d32861a 100644 --- a/app/test-pmd/parameters.c +++ b/app/test-pmd/parameters.c @@ -77,9 +77,98 @@ #include <rte_eth_bond.h> #endif #include <rte_flow.h> +#ifdef RTE_LIBRTE_CFGFILE +#include <rte_cfgfile.h> +#endif #include "testpmd.h" +enum { TX, RX }; + +static struct option lgopts[] = { + { "cfgfile-path", 1, 0, 1 }, + { "help", 0, 0, 0 }, +#ifdef RTE_LIBRTE_CMDLINE + { "interactive", 0, 0, 0 }, + { "cmdline-file", 1, 0, 0 }, + { "auto-start", 0, 0, 0 }, + { "eth-peers-configfile", 1, 0, 0 }, + { "eth-peer", 1, 0, 0 }, +#endif + { "tx-first", 0, 0, 0 }, + { "stats-period", 1, 0, 0 }, + { "ports", 1, 0, 0 }, + { "nb-cores", 1, 0, 0 }, + { "nb-ports", 1, 0, 0 }, + { "coremask", 1, 0, 0 }, + { "portmask", 1, 0, 0 }, + { "numa", 0, 0, 0 }, + { "no-numa", 0, 0, 0 }, + { "mp-anon", 0, 0, 0 }, + { "port-numa-config", 1, 0, 0 }, + { "ring-numa-config", 1, 0, 0 }, + { "socket-num", 1, 0, 0 }, + { "mbuf-size", 1, 0, 0 }, + { "total-num-mbufs", 1, 0, 0 }, + { "max-pkt-len", 1, 0, 0 }, + { "pkt-filter-mode", 1, 0, 0 }, + { "pkt-filter-report-hash", 1, 0, 0 }, + { "pkt-filter-size", 1, 0, 0 }, + { "pkt-filter-drop-queue", 1, 0, 0 }, +#ifdef RTE_LIBRTE_LATENCY_STATS + { "latencystats", 1, 0, 0 }, +#endif +#ifdef RTE_LIBRTE_BITRATE + { "bitrate-stats", 1, 0, 0 }, +#endif + { "disable-crc-strip", 0, 0, 0 }, + { "enable-lro", 0, 0, 0 }, + { "enable-rx-cksum", 0, 0, 0 }, + { "enable-scatter", 0, 0, 0 }, + { "disable-hw-vlan", 0, 0, 0 }, + { "disable-hw-vlan-filter", 0, 0, 0 }, + { "disable-hw-vlan-strip", 0, 0, 0 }, + { "disable-hw-vlan-extend", 0, 0, 0 }, + { "enable-drop-en", 0, 0, 0 }, + { "disable-rss", 0, 0, 0 }, + { "port-topology", 1, 0, 0 }, + { "forward-mode", 1, 0, 0 }, + { "rss-ip", 0, 0, 0 }, + { "rss-udp", 0, 0, 0 }, + { "rxq", 1, 0, 0 }, + { "txq", 1, 0, 0 }, + { "rxd", 1, 0, 0 }, + { "txd", 1, 0, 0 }, + { "burst", 1, 0, 0 }, + { "mbcache", 1, 0, 0 }, + { "txpt", 1, 0, 0 }, + { "txht", 1, 0, 0 }, + { "txwt", 1, 0, 0 }, + { "txfreet", 1, 0, 0 }, + { "txrst", 1, 0, 0 }, + { "txqflags", 1, 0, 0 }, + { "rxpt", 1, 0, 0 }, + { "rxht", 1, 0, 0 }, + { "rxwt", 1, 0, 0 }, + { "rxfreet", 1, 0, 0 }, + { "tx-queue-stats-mapping", 1, 0, 0 }, + { "rx-queue-stats-mapping", 1, 0, 0 }, + { "no-flush-rx", 0, 0, 0 }, + { "txpkts", 1, 0, 0 }, + { "disable-link-check", 0, 0, 0 }, + { "no-lsc-interrupt", 0, 0, 0 }, + { "no-rmv-interrupt", 0, 0, 0 }, + { "print-event", 1, 0, 0 }, + { "mask-event", 1, 0, 0 }, + { 0, 0, 0, 0 }, +}; + +#ifdef RTE_LIBRTE_CMDLINE +#define SHORTOPTS "i" +#else +#define SHORTOPTS "" +#endif + static void usage(char* progname) { @@ -554,578 +643,646 @@ parse_event_printing_config(const char *optarg, int enable) return 0; } -void -launch_args_parse(int argc, char** argv) +static int +parse_option(int opt, char *optarg, int opt_idx, char *prgname) { - int n, opt; - char **argvopt; - int opt_idx; - enum { TX, RX }; + int n; - static struct option lgopts[] = { - { "help", 0, 0, 0 }, + switch (opt) { #ifdef RTE_LIBRTE_CMDLINE - { "interactive", 0, 0, 0 }, - { "cmdline-file", 1, 0, 0 }, - { "auto-start", 0, 0, 0 }, - { "eth-peers-configfile", 1, 0, 0 }, - { "eth-peer", 1, 0, 0 }, -#endif - { "tx-first", 0, 0, 0 }, - { "stats-period", 1, 0, 0 }, - { "ports", 1, 0, 0 }, - { "nb-cores", 1, 0, 0 }, - { "nb-ports", 1, 0, 0 }, - { "coremask", 1, 0, 0 }, - { "portmask", 1, 0, 0 }, - { "numa", 0, 0, 0 }, - { "no-numa", 0, 0, 0 }, - { "mp-anon", 0, 0, 0 }, - { "port-numa-config", 1, 0, 0 }, - { "ring-numa-config", 1, 0, 0 }, - { "socket-num", 1, 0, 0 }, - { "mbuf-size", 1, 0, 0 }, - { "total-num-mbufs", 1, 0, 0 }, - { "max-pkt-len", 1, 0, 0 }, - { "pkt-filter-mode", 1, 0, 0 }, - { "pkt-filter-report-hash", 1, 0, 0 }, - { "pkt-filter-size", 1, 0, 0 }, - { "pkt-filter-drop-queue", 1, 0, 0 }, -#ifdef RTE_LIBRTE_LATENCY_STATS - { "latencystats", 1, 0, 0 }, -#endif -#ifdef RTE_LIBRTE_BITRATE - { "bitrate-stats", 1, 0, 0 }, + case 'i': + printf("Interactive-mode selected\n"); + interactive = 1; + break; #endif - { "disable-crc-strip", 0, 0, 0 }, - { "enable-lro", 0, 0, 0 }, - { "enable-rx-cksum", 0, 0, 0 }, - { "enable-scatter", 0, 0, 0 }, - { "disable-hw-vlan", 0, 0, 0 }, - { "disable-hw-vlan-filter", 0, 0, 0 }, - { "disable-hw-vlan-strip", 0, 0, 0 }, - { "disable-hw-vlan-extend", 0, 0, 0 }, - { "enable-drop-en", 0, 0, 0 }, - { "disable-rss", 0, 0, 0 }, - { "port-topology", 1, 0, 0 }, - { "forward-mode", 1, 0, 0 }, - { "rss-ip", 0, 0, 0 }, - { "rss-udp", 0, 0, 0 }, - { "rxq", 1, 0, 0 }, - { "txq", 1, 0, 0 }, - { "rxd", 1, 0, 0 }, - { "txd", 1, 0, 0 }, - { "burst", 1, 0, 0 }, - { "mbcache", 1, 0, 0 }, - { "txpt", 1, 0, 0 }, - { "txht", 1, 0, 0 }, - { "txwt", 1, 0, 0 }, - { "txfreet", 1, 0, 0 }, - { "txrst", 1, 0, 0 }, - { "txqflags", 1, 0, 0 }, - { "rxpt", 1, 0, 0 }, - { "rxht", 1, 0, 0 }, - { "rxwt", 1, 0, 0 }, - { "rxfreet", 1, 0, 0 }, - { "tx-queue-stats-mapping", 1, 0, 0 }, - { "rx-queue-stats-mapping", 1, 0, 0 }, - { "no-flush-rx", 0, 0, 0 }, - { "txpkts", 1, 0, 0 }, - { "disable-link-check", 0, 0, 0 }, - { "no-lsc-interrupt", 0, 0, 0 }, - { "no-rmv-interrupt", 0, 0, 0 }, - { "print-event", 1, 0, 0 }, - { "mask-event", 1, 0, 0 }, - { 0, 0, 0, 0 }, - }; + case 'a': + printf("Auto-start selected\n"); + auto_start = 1; + break; - argvopt = argv; - -#ifdef RTE_LIBRTE_CMDLINE -#define SHORTOPTS "i" -#else -#define SHORTOPTS "" -#endif - while ((opt = getopt_long(argc, argvopt, SHORTOPTS "ah", - lgopts, &opt_idx)) != EOF) { - switch (opt) { + case 0: /*long options */ + if (!strcmp(lgopts[opt_idx].name, "help")) { + usage(prgname); + rte_exit(EXIT_SUCCESS, "Displayed help\n"); + return 0; + } #ifdef RTE_LIBRTE_CMDLINE - case 'i': + if (!strcmp(lgopts[opt_idx].name, "interactive")) { printf("Interactive-mode selected\n"); interactive = 1; - break; -#endif - case 'a': + } + if (!strcmp(lgopts[opt_idx].name, "cmdline-file")) { + printf("CLI commands to be read from %s\n", + optarg); + snprintf(cmdline_filename, + sizeof(cmdline_filename), "%s", + optarg); + } + if (!strcmp(lgopts[opt_idx].name, "auto-start")) { printf("Auto-start selected\n"); auto_start = 1; - break; + } + if (!strcmp(lgopts[opt_idx].name, "tx-first")) { + printf("Ports to start sending a burst of " + "packets first\n"); + tx_first = 1; + } + if (!strcmp(lgopts[opt_idx].name, "stats-period")) { + char *end = NULL; + unsigned int n; - case 0: /*long options */ - if (!strcmp(lgopts[opt_idx].name, "help")) { - usage(argv[0]); - rte_exit(EXIT_SUCCESS, "Displayed help\n"); - } -#ifdef RTE_LIBRTE_CMDLINE - if (!strcmp(lgopts[opt_idx].name, "interactive")) { - printf("Interactive-mode selected\n"); - interactive = 1; - } - if (!strcmp(lgopts[opt_idx].name, "cmdline-file")) { - printf("CLI commands to be read from %s\n", - optarg); - snprintf(cmdline_filename, - sizeof(cmdline_filename), "%s", - optarg); - } - if (!strcmp(lgopts[opt_idx].name, "auto-start")) { - printf("Auto-start selected\n"); - auto_start = 1; - } - if (!strcmp(lgopts[opt_idx].name, "tx-first")) { - printf("Ports to start sending a burst of " - "packets first\n"); - tx_first = 1; - } - if (!strcmp(lgopts[opt_idx].name, "stats-period")) { - char *end = NULL; - unsigned int n; + n = strtoul(optarg, &end, 10); + if ((optarg[0] == '\0') || (end == NULL) || + (*end != '\0')) + break; - n = strtoul(optarg, &end, 10); - if ((optarg[0] == '\0') || (end == NULL) || - (*end != '\0')) - break; + stats_period = n; + break; + } + if (!strcmp(lgopts[opt_idx].name, + "eth-peers-configfile")) { + if (init_peer_eth_addrs(optarg) != 0) + rte_exit(EXIT_FAILURE, + "Cannot open logfile\n"); + } + if (!strcmp(lgopts[opt_idx].name, "eth-peer")) { + char *port_end; + uint8_t c, peer_addr[6]; - stats_period = n; - break; - } - if (!strcmp(lgopts[opt_idx].name, - "eth-peers-configfile")) { - if (init_peer_eth_addrs(optarg) != 0) - rte_exit(EXIT_FAILURE, - "Cannot open logfile\n"); + errno = 0; + n = strtoul(optarg, &port_end, 10); + if (errno != 0 || port_end == optarg || + *port_end++ != ',') + rte_exit(EXIT_FAILURE, + "Invalid eth-peer: %s", optarg); + if (n >= RTE_MAX_ETHPORTS) { + rte_exit(EXIT_FAILURE, + "eth-peer: port %d >= " + "RTE_MAX_ETHPORTS(%d)\n", + n, RTE_MAX_ETHPORTS); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "eth-peer")) { - char *port_end; - uint8_t c, peer_addr[6]; - - errno = 0; - n = strtoul(optarg, &port_end, 10); - if (errno != 0 || port_end == optarg || *port_end++ != ',') - rte_exit(EXIT_FAILURE, - "Invalid eth-peer: %s", optarg); - if (n >= RTE_MAX_ETHPORTS) - rte_exit(EXIT_FAILURE, - "eth-peer: port %d >= RTE_MAX_ETHPORTS(%d)\n", - n, RTE_MAX_ETHPORTS); - if (cmdline_parse_etheraddr(NULL, port_end, - &peer_addr, sizeof(peer_addr)) < 0) - rte_exit(EXIT_FAILURE, - "Invalid ethernet address: %s\n", - port_end); - for (c = 0; c < 6; c++) - peer_eth_addrs[n].addr_bytes[c] = - peer_addr[c]; - nb_peer_eth_addrs++; + if (cmdline_parse_etheraddr(NULL, port_end, + &peer_addr, sizeof(peer_addr)) < 0) { + rte_exit(EXIT_FAILURE, + "Invalid ethernet address: %s\n", + port_end); + return -1; } + for (c = 0; c < 6; c++) + peer_eth_addrs[n].addr_bytes[c] = + peer_addr[c]; + nb_peer_eth_addrs++; + } #endif - if (!strcmp(lgopts[opt_idx].name, "nb-ports")) { - n = atoi(optarg); - if (n > 0 && n <= nb_ports) - nb_fwd_ports = (uint8_t) n; - else - rte_exit(EXIT_FAILURE, - "Invalid port %d\n", n); + if (!strcmp(lgopts[opt_idx].name, "nb-ports")) { + n = atoi(optarg); + if (n > 0 && n <= nb_ports) + nb_fwd_ports = (uint8_t) n; + else { + rte_exit(EXIT_FAILURE, + "Invalid port %d\n", n); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "nb-cores")) { - n = atoi(optarg); - if (n > 0 && n <= nb_lcores) - nb_fwd_lcores = (uint8_t) n; - else - rte_exit(EXIT_FAILURE, - "nb-cores should be > 0 and <= %d\n", - nb_lcores); + } + if (!strcmp(lgopts[opt_idx].name, "nb-cores")) { + n = atoi(optarg); + if (n > 0 && n <= nb_lcores) + nb_fwd_lcores = (uint8_t) n; + else { + rte_exit(EXIT_FAILURE, + "nb-cores should be > 0 and <= %d\n", + nb_lcores); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "coremask")) - parse_fwd_coremask(optarg); - if (!strcmp(lgopts[opt_idx].name, "portmask")) - parse_fwd_portmask(optarg); - if (!strcmp(lgopts[opt_idx].name, "no-numa")) - numa_support = 0; - if (!strcmp(lgopts[opt_idx].name, "numa")) - numa_support = 1; - if (!strcmp(lgopts[opt_idx].name, "mp-anon")) { - mp_anon = 1; + } + if (!strcmp(lgopts[opt_idx].name, "coremask")) + parse_fwd_coremask(optarg); + if (!strcmp(lgopts[opt_idx].name, "portmask")) + parse_fwd_portmask(optarg); + if (!strcmp(lgopts[opt_idx].name, "no-numa")) + numa_support = 0; + if (!strcmp(lgopts[opt_idx].name, "numa")) + numa_support = 1; + if (!strcmp(lgopts[opt_idx].name, "mp-anon")) + mp_anon = 1; + if (!strcmp(lgopts[opt_idx].name, "port-numa-config")) { + if (parse_portnuma_config(optarg)) { + rte_exit(EXIT_FAILURE, + "invalid port-numa configuration\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "port-numa-config")) { - if (parse_portnuma_config(optarg)) - rte_exit(EXIT_FAILURE, - "invalid port-numa configuration\n"); + } + if (!strcmp(lgopts[opt_idx].name, "ring-numa-config")) + if (parse_ringnuma_config(optarg)) { + rte_exit(EXIT_FAILURE, + "invalid ring-numa configuration\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "ring-numa-config")) - if (parse_ringnuma_config(optarg)) - rte_exit(EXIT_FAILURE, - "invalid ring-numa configuration\n"); - if (!strcmp(lgopts[opt_idx].name, "socket-num")) { - n = atoi(optarg); - if (!new_socket_id((uint8_t)n)) { - socket_num = (uint8_t)n; - } else { - print_invalid_socket_id_error(); - rte_exit(EXIT_FAILURE, - "Invalid socket id"); - } + if (!strcmp(lgopts[opt_idx].name, "socket-num")) { + n = atoi(optarg); + if (!new_socket_id((uint8_t)n)) { + socket_num = (uint8_t)n; + } else { + print_invalid_socket_id_error(); + rte_exit(EXIT_FAILURE, + "Invalid socket id"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "mbuf-size")) { - n = atoi(optarg); - if (n > 0 && n <= 0xFFFF) - mbuf_data_size = (uint16_t) n; - else - rte_exit(EXIT_FAILURE, - "mbuf-size should be > 0 and < 65536\n"); + } + if (!strcmp(lgopts[opt_idx].name, "mbuf-size")) { + n = atoi(optarg); + if (n > 0 && n <= 0xFFFF) + mbuf_data_size = (uint16_t) n; + else { + rte_exit(EXIT_FAILURE, + "mbuf-size should be > 0 and < 65536\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "total-num-mbufs")) { - n = atoi(optarg); - if (n > 1024) - param_total_num_mbufs = (unsigned)n; - else - rte_exit(EXIT_FAILURE, - "total-num-mbufs should be > 1024\n"); + } + if (!strcmp(lgopts[opt_idx].name, "total-num-mbufs")) { + n = atoi(optarg); + if (n > 1024) + param_total_num_mbufs = (unsigned int)n; + else { + rte_exit(EXIT_FAILURE, + "total-num-mbufs should be > 1024\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "max-pkt-len")) { - n = atoi(optarg); - if (n >= ETHER_MIN_LEN) { - rx_mode.max_rx_pkt_len = (uint32_t) n; - if (n > ETHER_MAX_LEN) - rx_mode.jumbo_frame = 1; - } else - rte_exit(EXIT_FAILURE, - "Invalid max-pkt-len=%d - should be > %d\n", - n, ETHER_MIN_LEN); + } + if (!strcmp(lgopts[opt_idx].name, "max-pkt-len")) { + n = atoi(optarg); + if (n >= ETHER_MIN_LEN) { + rx_mode.max_rx_pkt_len = (uint32_t) n; + if (n > ETHER_MAX_LEN) + rx_mode.jumbo_frame = 1; + } else { + rte_exit(EXIT_FAILURE, + "Invalid max-pkt-len=%d - should be > %d\n", + n, ETHER_MIN_LEN); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "pkt-filter-mode")) { - if (!strcmp(optarg, "signature")) - fdir_conf.mode = - RTE_FDIR_MODE_SIGNATURE; - else if (!strcmp(optarg, "perfect")) - fdir_conf.mode = RTE_FDIR_MODE_PERFECT; - else if (!strcmp(optarg, "perfect-mac-vlan")) - fdir_conf.mode = RTE_FDIR_MODE_PERFECT_MAC_VLAN; - else if (!strcmp(optarg, "perfect-tunnel")) - fdir_conf.mode = RTE_FDIR_MODE_PERFECT_TUNNEL; - else if (!strcmp(optarg, "none")) - fdir_conf.mode = RTE_FDIR_MODE_NONE; - else - rte_exit(EXIT_FAILURE, - "pkt-mode-invalid %s invalid - must be: " - "none, signature, perfect, perfect-mac-vlan" - " or perfect-tunnel\n", - optarg); + } + if (!strcmp(lgopts[opt_idx].name, "pkt-filter-mode")) { + if (!strcmp(optarg, "signature")) + fdir_conf.mode = + RTE_FDIR_MODE_SIGNATURE; + else if (!strcmp(optarg, "perfect")) + fdir_conf.mode = RTE_FDIR_MODE_PERFECT; + else if (!strcmp(optarg, "perfect-mac-vlan")) + fdir_conf.mode = RTE_FDIR_MODE_PERFECT_MAC_VLAN; + else if (!strcmp(optarg, "perfect-tunnel")) + fdir_conf.mode = RTE_FDIR_MODE_PERFECT_TUNNEL; + else if (!strcmp(optarg, "none")) + fdir_conf.mode = RTE_FDIR_MODE_NONE; + else { + rte_exit(EXIT_FAILURE, + "pkt-mode-invalid %s invalid - must be: " + "none, signature, perfect, perfect-mac-vlan" + " or perfect-tunnel\n", + optarg); + return -1; } - if (!strcmp(lgopts[opt_idx].name, - "pkt-filter-report-hash")) { - if (!strcmp(optarg, "none")) - fdir_conf.status = - RTE_FDIR_NO_REPORT_STATUS; - else if (!strcmp(optarg, "match")) - fdir_conf.status = - RTE_FDIR_REPORT_STATUS; - else if (!strcmp(optarg, "always")) - fdir_conf.status = - RTE_FDIR_REPORT_STATUS_ALWAYS; - else - rte_exit(EXIT_FAILURE, - "pkt-filter-report-hash %s invalid " - "- must be: none or match or always\n", - optarg); + } + if (!strcmp(lgopts[opt_idx].name, + "pkt-filter-report-hash")) { + if (!strcmp(optarg, "none")) + fdir_conf.status = + RTE_FDIR_NO_REPORT_STATUS; + else if (!strcmp(optarg, "match")) + fdir_conf.status = + RTE_FDIR_REPORT_STATUS; + else if (!strcmp(optarg, "always")) + fdir_conf.status = + RTE_FDIR_REPORT_STATUS_ALWAYS; + else { + rte_exit(EXIT_FAILURE, + "pkt-filter-report-hash %s invalid " + "- must be: none or match or always\n", + optarg); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "pkt-filter-size")) { - if (!strcmp(optarg, "64K")) - fdir_conf.pballoc = - RTE_FDIR_PBALLOC_64K; - else if (!strcmp(optarg, "128K")) - fdir_conf.pballoc = - RTE_FDIR_PBALLOC_128K; - else if (!strcmp(optarg, "256K")) - fdir_conf.pballoc = - RTE_FDIR_PBALLOC_256K; - else - rte_exit(EXIT_FAILURE, "pkt-filter-size %s invalid -" - " must be: 64K or 128K or 256K\n", - optarg); + } + if (!strcmp(lgopts[opt_idx].name, "pkt-filter-size")) { + if (!strcmp(optarg, "64K")) + fdir_conf.pballoc = + RTE_FDIR_PBALLOC_64K; + else if (!strcmp(optarg, "128K")) + fdir_conf.pballoc = + RTE_FDIR_PBALLOC_128K; + else if (!strcmp(optarg, "256K")) + fdir_conf.pballoc = + RTE_FDIR_PBALLOC_256K; + else { + rte_exit(EXIT_FAILURE, "pkt-filter-size %s invalid -" + " must be: 64K or 128K or 256K\n", + optarg); + return -1; } - if (!strcmp(lgopts[opt_idx].name, - "pkt-filter-drop-queue")) { - n = atoi(optarg); - if (n >= 0) - fdir_conf.drop_queue = (uint8_t) n; - else - rte_exit(EXIT_FAILURE, - "drop queue %d invalid - must" - "be >= 0 \n", n); + } + if (!strcmp(lgopts[opt_idx].name, + "pkt-filter-drop-queue")) { + n = atoi(optarg); + if (n >= 0) + fdir_conf.drop_queue = (uint8_t) n; + else { + rte_exit(EXIT_FAILURE, + "drop queue %d invalid - must " + "be >= 0\n", n); + return -1; } + } #ifdef RTE_LIBRTE_LATENCY_STATS - if (!strcmp(lgopts[opt_idx].name, - "latencystats")) { - n = atoi(optarg); - if (n >= 0) { - latencystats_lcore_id = (lcoreid_t) n; - latencystats_enabled = 1; - } else - rte_exit(EXIT_FAILURE, - "invalid lcore id %d for latencystats" - " must be >= 0\n", n); + if (!strcmp(lgopts[opt_idx].name, + "latencystats")) { + n = atoi(optarg); + if (n >= 0) { + latencystats_lcore_id = (lcoreid_t) n; + latencystats_enabled = 1; + } else { + rte_exit(EXIT_FAILURE, + "invalid lcore id %d for latencystats" + " must be >= 0\n", n); + return -1; } + } #endif #ifdef RTE_LIBRTE_BITRATE - if (!strcmp(lgopts[opt_idx].name, "bitrate-stats")) { - n = atoi(optarg); - if (n >= 0) { - bitrate_lcore_id = (lcoreid_t) n; - bitrate_enabled = 1; - } else - rte_exit(EXIT_FAILURE, - "invalid lcore id %d for bitrate stats" - " must be >= 0\n", n); + if (!strcmp(lgopts[opt_idx].name, "bitrate-stats")) { + n = atoi(optarg); + if (n >= 0) { + bitrate_lcore_id = (lcoreid_t) n; + bitrate_enabled = 1; + } else { + rte_exit(EXIT_FAILURE, + "invalid lcore id %d for bitrate stats" + " must be >= 0\n", n); + return -1; } + } #endif - if (!strcmp(lgopts[opt_idx].name, "disable-crc-strip")) - rx_mode.hw_strip_crc = 0; - if (!strcmp(lgopts[opt_idx].name, "enable-lro")) - rx_mode.enable_lro = 1; - if (!strcmp(lgopts[opt_idx].name, "enable-scatter")) - rx_mode.enable_scatter = 1; - if (!strcmp(lgopts[opt_idx].name, "enable-rx-cksum")) - rx_mode.hw_ip_checksum = 1; - - if (!strcmp(lgopts[opt_idx].name, "disable-hw-vlan")) { - rx_mode.hw_vlan_filter = 0; - rx_mode.hw_vlan_strip = 0; - rx_mode.hw_vlan_extend = 0; - } + if (!strcmp(lgopts[opt_idx].name, "disable-crc-strip")) + rx_mode.hw_strip_crc = 0; + if (!strcmp(lgopts[opt_idx].name, "enable-lro")) + rx_mode.enable_lro = 1; + if (!strcmp(lgopts[opt_idx].name, "enable-scatter")) + rx_mode.enable_scatter = 1; + if (!strcmp(lgopts[opt_idx].name, "enable-rx-cksum")) + rx_mode.hw_ip_checksum = 1; - if (!strcmp(lgopts[opt_idx].name, - "disable-hw-vlan-filter")) - rx_mode.hw_vlan_filter = 0; - - if (!strcmp(lgopts[opt_idx].name, - "disable-hw-vlan-strip")) - rx_mode.hw_vlan_strip = 0; - - if (!strcmp(lgopts[opt_idx].name, - "disable-hw-vlan-extend")) - rx_mode.hw_vlan_extend = 0; - - if (!strcmp(lgopts[opt_idx].name, "enable-drop-en")) - rx_drop_en = 1; - - if (!strcmp(lgopts[opt_idx].name, "disable-rss")) - rss_hf = 0; - if (!strcmp(lgopts[opt_idx].name, "port-topology")) { - if (!strcmp(optarg, "paired")) - port_topology = PORT_TOPOLOGY_PAIRED; - else if (!strcmp(optarg, "chained")) - port_topology = PORT_TOPOLOGY_CHAINED; - else if (!strcmp(optarg, "loop")) - port_topology = PORT_TOPOLOGY_LOOP; - else - rte_exit(EXIT_FAILURE, "port-topology %s invalid -" - " must be: paired or chained \n", - optarg); + if (!strcmp(lgopts[opt_idx].name, "disable-hw-vlan")) { + rx_mode.hw_vlan_filter = 0; + rx_mode.hw_vlan_strip = 0; + rx_mode.hw_vlan_extend = 0; + } + + if (!strcmp(lgopts[opt_idx].name, + "disable-hw-vlan-filter")) + rx_mode.hw_vlan_filter = 0; + + if (!strcmp(lgopts[opt_idx].name, + "disable-hw-vlan-strip")) + rx_mode.hw_vlan_strip = 0; + + if (!strcmp(lgopts[opt_idx].name, + "disable-hw-vlan-extend")) + rx_mode.hw_vlan_extend = 0; + + if (!strcmp(lgopts[opt_idx].name, "enable-drop-en")) + rx_drop_en = 1; + + if (!strcmp(lgopts[opt_idx].name, "disable-rss")) + rss_hf = 0; + if (!strcmp(lgopts[opt_idx].name, "port-topology")) { + if (!strcmp(optarg, "paired")) + port_topology = PORT_TOPOLOGY_PAIRED; + else if (!strcmp(optarg, "chained")) + port_topology = PORT_TOPOLOGY_CHAINED; + else if (!strcmp(optarg, "loop")) + port_topology = PORT_TOPOLOGY_LOOP; + else { + rte_exit(EXIT_FAILURE, "port-topology %s invalid -" + " must be: paired or chained\n", + optarg); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "forward-mode")) - set_pkt_forwarding_mode(optarg); - if (!strcmp(lgopts[opt_idx].name, "rss-ip")) - rss_hf = ETH_RSS_IP; - if (!strcmp(lgopts[opt_idx].name, "rss-udp")) - rss_hf = ETH_RSS_UDP; - if (!strcmp(lgopts[opt_idx].name, "rxq")) { - n = atoi(optarg); - if (n >= 0 && n <= (int) MAX_QUEUE_ID) - nb_rxq = (queueid_t) n; - else - rte_exit(EXIT_FAILURE, "rxq %d invalid - must be" - " >= 0 && <= %d\n", n, - (int) MAX_QUEUE_ID); + } + if (!strcmp(lgopts[opt_idx].name, "forward-mode")) + set_pkt_forwarding_mode(optarg); + if (!strcmp(lgopts[opt_idx].name, "rss-ip")) + rss_hf = ETH_RSS_IP; + if (!strcmp(lgopts[opt_idx].name, "rss-udp")) + rss_hf = ETH_RSS_UDP; + if (!strcmp(lgopts[opt_idx].name, "rxq")) { + n = atoi(optarg); + if (n >= 0 && n <= (int) MAX_QUEUE_ID) + nb_rxq = (queueid_t) n; + else { + rte_exit(EXIT_FAILURE, "rxq %d invalid - must be" + " >= 0 && <= %d\n", n, + (int) MAX_QUEUE_ID); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txq")) { - n = atoi(optarg); - if (n >= 0 && n <= (int) MAX_QUEUE_ID) - nb_txq = (queueid_t) n; - else - rte_exit(EXIT_FAILURE, "txq %d invalid - must be" - " >= 0 && <= %d\n", n, - (int) MAX_QUEUE_ID); + } + if (!strcmp(lgopts[opt_idx].name, "txq")) { + n = atoi(optarg); + if (n >= 0 && n <= (int) MAX_QUEUE_ID) + nb_txq = (queueid_t) n; + else { + rte_exit(EXIT_FAILURE, "txq %d invalid - must be" + " >= 0 && <= %d\n", n, + (int) MAX_QUEUE_ID); + return -1; } - if (!nb_rxq && !nb_txq) { - rte_exit(EXIT_FAILURE, "Either rx or tx queues should " - "be non-zero\n"); + } + if (!nb_rxq && !nb_txq) { + rte_exit(EXIT_FAILURE, "Either rx or tx queues should " + "be non-zero\n"); + return -1; + } + if (!strcmp(lgopts[opt_idx].name, "burst")) { + n = atoi(optarg); + if ((n >= 1) && (n <= MAX_PKT_BURST)) + nb_pkt_per_burst = (uint16_t) n; + else { + rte_exit(EXIT_FAILURE, + "burst must >= 1 and <= %d]", + MAX_PKT_BURST); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "burst")) { - n = atoi(optarg); - if ((n >= 1) && (n <= MAX_PKT_BURST)) - nb_pkt_per_burst = (uint16_t) n; - else - rte_exit(EXIT_FAILURE, - "burst must >= 1 and <= %d]", - MAX_PKT_BURST); + } + if (!strcmp(lgopts[opt_idx].name, "mbcache")) { + n = atoi(optarg); + if ((n >= 0) && + (n <= RTE_MEMPOOL_CACHE_MAX_SIZE)) + mb_mempool_cache = (uint16_t) n; + else { + rte_exit(EXIT_FAILURE, + "mbcache must be >= 0 and <= %d\n", + RTE_MEMPOOL_CACHE_MAX_SIZE); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "mbcache")) { - n = atoi(optarg); - if ((n >= 0) && - (n <= RTE_MEMPOOL_CACHE_MAX_SIZE)) - mb_mempool_cache = (uint16_t) n; - else - rte_exit(EXIT_FAILURE, - "mbcache must be >= 0 and <= %d\n", - RTE_MEMPOOL_CACHE_MAX_SIZE); + } + if (!strcmp(lgopts[opt_idx].name, "txfreet")) { + n = atoi(optarg); + if (n >= 0) + tx_free_thresh = (int16_t)n; + else { + rte_exit(EXIT_FAILURE, "txfreet must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txfreet")) { - n = atoi(optarg); - if (n >= 0) - tx_free_thresh = (int16_t)n; - else - rte_exit(EXIT_FAILURE, "txfreet must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txrst")) { + n = atoi(optarg); + if (n >= 0) + tx_rs_thresh = (int16_t)n; + else { + rte_exit(EXIT_FAILURE, "txrst must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txrst")) { - n = atoi(optarg); - if (n >= 0) - tx_rs_thresh = (int16_t)n; - else - rte_exit(EXIT_FAILURE, "txrst must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txqflags")) { + char *end = NULL; + + n = strtoul(optarg, &end, 16); + if (n >= 0) + txq_flags = (int32_t)n; + else { + rte_exit(EXIT_FAILURE, + "txqflags must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txqflags")) { - char *end = NULL; - n = strtoul(optarg, &end, 16); - if (n >= 0) - txq_flags = (int32_t)n; - else + } + if (!strcmp(lgopts[opt_idx].name, "rxd")) { + n = atoi(optarg); + if (n > 0) { + if (rx_free_thresh >= n) rte_exit(EXIT_FAILURE, - "txqflags must be >= 0\n"); + "rxd must be > " + "rx_free_thresh(%d)\n", + (int)rx_free_thresh); + else + nb_rxd = (uint16_t) n; + } else { + rte_exit(EXIT_FAILURE, + "rxd(%d) invalid - must be > 0\n", + n); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxd")) { - n = atoi(optarg); - if (n > 0) { - if (rx_free_thresh >= n) - rte_exit(EXIT_FAILURE, - "rxd must be > " - "rx_free_thresh(%d)\n", - (int)rx_free_thresh); - else - nb_rxd = (uint16_t) n; - } else - rte_exit(EXIT_FAILURE, - "rxd(%d) invalid - must be > 0\n", - n); + } + if (!strcmp(lgopts[opt_idx].name, "txd")) { + n = atoi(optarg); + if (n > 0) + nb_txd = (uint16_t) n; + else { + rte_exit(EXIT_FAILURE, "txd must be in > 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txd")) { - n = atoi(optarg); - if (n > 0) - nb_txd = (uint16_t) n; - else - rte_exit(EXIT_FAILURE, "txd must be in > 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txpt")) { + n = atoi(optarg); + if (n >= 0) + tx_pthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "txpt must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txpt")) { - n = atoi(optarg); - if (n >= 0) - tx_pthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "txpt must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txht")) { + n = atoi(optarg); + if (n >= 0) + tx_hthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "txht must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txht")) { - n = atoi(optarg); - if (n >= 0) - tx_hthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "txht must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txwt")) { + n = atoi(optarg); + if (n >= 0) + tx_wthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "txwt must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txwt")) { - n = atoi(optarg); - if (n >= 0) - tx_wthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "txwt must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "rxpt")) { + n = atoi(optarg); + if (n >= 0) + rx_pthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "rxpt must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxpt")) { - n = atoi(optarg); - if (n >= 0) - rx_pthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "rxpt must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "rxht")) { + n = atoi(optarg); + if (n >= 0) + rx_hthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "rxht must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxht")) { - n = atoi(optarg); - if (n >= 0) - rx_hthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "rxht must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "rxwt")) { + n = atoi(optarg); + if (n >= 0) + rx_wthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "rxwt must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxwt")) { - n = atoi(optarg); - if (n >= 0) - rx_wthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "rxwt must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "rxfreet")) { + n = atoi(optarg); + if (n >= 0) + rx_free_thresh = (int16_t)n; + else { + rte_exit(EXIT_FAILURE, "rxfreet must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxfreet")) { - n = atoi(optarg); - if (n >= 0) - rx_free_thresh = (int16_t)n; - else - rte_exit(EXIT_FAILURE, "rxfreet must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "tx-queue-stats-mapping")) { + if (parse_queue_stats_mapping_config(optarg, TX)) { + rte_exit(EXIT_FAILURE, + "invalid TX queue statistics mapping config entered\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "tx-queue-stats-mapping")) { - if (parse_queue_stats_mapping_config(optarg, TX)) { - rte_exit(EXIT_FAILURE, - "invalid TX queue statistics mapping config entered\n"); - } + } + if (!strcmp(lgopts[opt_idx].name, "rx-queue-stats-mapping")) { + if (parse_queue_stats_mapping_config(optarg, RX)) { + rte_exit(EXIT_FAILURE, + "invalid RX queue statistics mapping config entered\n"); } - if (!strcmp(lgopts[opt_idx].name, "rx-queue-stats-mapping")) { - if (parse_queue_stats_mapping_config(optarg, RX)) { - rte_exit(EXIT_FAILURE, - "invalid RX queue statistics mapping config entered\n"); - } + } + if (!strcmp(lgopts[opt_idx].name, "txpkts")) { + unsigned int seg_lengths[RTE_MAX_SEGS_PER_PKT]; + unsigned int nb_segs; + + nb_segs = parse_item_list(optarg, "txpkt segments", + RTE_MAX_SEGS_PER_PKT, seg_lengths, 0); + if (nb_segs > 0) + set_tx_pkt_segments(seg_lengths, nb_segs); + else { + rte_exit(EXIT_FAILURE, "bad txpkts\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txpkts")) { - unsigned seg_lengths[RTE_MAX_SEGS_PER_PKT]; - unsigned int nb_segs; - - nb_segs = parse_item_list(optarg, "txpkt segments", - RTE_MAX_SEGS_PER_PKT, seg_lengths, 0); - if (nb_segs > 0) - set_tx_pkt_segments(seg_lengths, nb_segs); - else - rte_exit(EXIT_FAILURE, "bad txpkts\n"); + } + if (!strcmp(lgopts[opt_idx].name, "no-flush-rx")) + no_flush_rx = 1; + if (!strcmp(lgopts[opt_idx].name, "disable-link-check")) + no_link_check = 1; + if (!strcmp(lgopts[opt_idx].name, "no-lsc-interrupt")) + lsc_interrupt = 0; + if (!strcmp(lgopts[opt_idx].name, "no-rmv-interrupt")) + rmv_interrupt = 0; + if (!strcmp(lgopts[opt_idx].name, "print-event")) + if (parse_event_printing_config(optarg, 1)) { + rte_exit(EXIT_FAILURE, + "invalid print-event argument\n"); + return -1; + } + if (!strcmp(lgopts[opt_idx].name, "mask-event")) + if (parse_event_printing_config(optarg, 0)) { + rte_exit(EXIT_FAILURE, + "invalid mask-event argument\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "no-flush-rx")) - no_flush_rx = 1; - if (!strcmp(lgopts[opt_idx].name, "disable-link-check")) - no_link_check = 1; - if (!strcmp(lgopts[opt_idx].name, "no-lsc-interrupt")) - lsc_interrupt = 0; - if (!strcmp(lgopts[opt_idx].name, "no-rmv-interrupt")) - rmv_interrupt = 0; - if (!strcmp(lgopts[opt_idx].name, "print-event")) - if (parse_event_printing_config(optarg, 1)) { - rte_exit(EXIT_FAILURE, - "invalid print-event argument\n"); - } - if (!strcmp(lgopts[opt_idx].name, "mask-event")) - if (parse_event_printing_config(optarg, 0)) { - rte_exit(EXIT_FAILURE, - "invalid mask-event argument\n"); - } - break; - case 'h': - usage(argv[0]); - rte_exit(EXIT_SUCCESS, "Displayed help\n"); - break; - default: - usage(argv[0]); - rte_exit(EXIT_FAILURE, - "Command line is incomplete or incorrect\n"); + break; + case 'h': + usage(prgname); + rte_exit(EXIT_SUCCESS, "Displayed help\n"); + return -1; + case 1: + /* does nothing*/ + break; + default: + usage(prgname); + rte_exit(EXIT_FAILURE, + "Command line is incomplete or incorrect\n"); + return -1; + } + return 0; +} + +void +launch_args_parse(int argc, char **argv) +{ + int opt; + char **argvopt; + int opt_idx; + + argvopt = argv; + + while ((opt = getopt_long(argc, argvopt, SHORTOPTS "ah", + lgopts, &opt_idx)) != EOF) { + parse_option(opt, optarg, opt_idx, argv[0]); + } +} + +#ifdef RTE_LIBRTE_CFGFILE +static void +non_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; lgopts[i].name != NULL; i++) { + if (strcmp(str, lgopts[i].name) == 0) { + *opt = lgopts[i].val; + *option_index = i; break; } } } +#endif + +#ifdef RTE_LIBRTE_CFGFILE +#define APP_SECTION "TEST-PMD" +int non_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, APP_SECTION); + + if (n_entries < 1) { + printf("No %s section entries " + "in cfgfile object\n", APP_SECTION); + return -1; + } + + struct rte_cfgfile_entry entries[n_entries]; + + if (n_entries != + rte_cfgfile_section_entries(cfg, APP_SECTION, entries, + n_entries)) { + rte_exit(EXIT_FAILURE, "Unexpected fault"); + return -1; + } + + for (i = 0; i < n_entries; i++) { + non_eal_getopt(entries[i].name, &opt, &option_index); + + parse_option(opt, entries[i].value, + option_index, prgname); + } + return 0; +} +#endif diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index e09b803..7b82976 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -91,6 +91,9 @@ #include <rte_latencystats.h> #endif #include <rte_gro.h> +#ifdef RTE_LIBRTE_CFGFILE +#include <rte_cfgfile.h> +#endif #include "testpmd.h" @@ -2266,15 +2269,66 @@ signal_handler(int signum) } } +#ifdef RTE_LIBRTE_CFGFILE +/* Load config file path from command line */ +static char * +cfgfile_load_path(int argc, char **argv) +{ + int i; + + for (i = 0; i < argc; i++) { + if (!strcmp("--cfgfile-path", argv[i])) { + if (argv[i+1] && argv[i+1][0] != '-') + return strdup(argv[i+1]); + } else if (!strncmp("--cfgfile-path=", argv[i], 15)) { + char *ptr = argv[i]; + + ptr += 15; + if (strlen(ptr)) + return strdup(ptr); + } + } + return NULL; +} +#endif + +#define APP_NAME "TEST-PMD" int main(int argc, char** argv) { int diag; uint8_t port_id; +#ifdef RTE_LIBRTE_CFGFILE + struct rte_cfgfile *cfg = NULL; + char *config_file = NULL; +#endif signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); +#ifdef RTE_LIBRTE_CFGFILE + /* load --cfgfile-path argument from argv */ + config_file = cfgfile_load_path(argc, argv); + + if (config_file) { + printf("Info: found cfgfile-path \"%s\"\n", config_file); + } else { + printf("Info: not found cfgfile-path parameter " + "(searching for cfgfile " + "in default directory)\n"); + config_file = strdup("config.ini"); + } + + cfg = rte_cfgfile_load(config_file, CFG_FLAG_EMPTY_VALUES); + + if (cfg == NULL) { + printf("Info: Valid cfgfile not found\n"); + } else { + diag = rte_eal_configure(cfg, argv[0]); + if (diag < 0) + rte_panic("Cannot init EAL\n"); + } +#endif diag = rte_eal_init(argc, argv); if (diag < 0) rte_panic("Cannot init EAL\n"); @@ -2304,6 +2358,18 @@ main(int argc, char** argv) latencystats_enabled = 0; #endif +#ifdef RTE_LIBRTE_CFGFILE + if (cfg != NULL) { + non_eal_configure(cfg, argv[0]); + rte_cfgfile_close(cfg); + cfg = 0; + + if (config_file) { + free(config_file); + config_file = 0; + } + } +#endif argc -= diag; argv += diag; if (argc > 1) @@ -2400,6 +2466,5 @@ main(int argc, char** argv) if (rc < 0) return 1; } - return 0; } diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 73985c3..8ff4d88 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -512,7 +512,7 @@ port_pci_reg_write(struct rte_port *port, uint32_t reg_off, uint32_t reg_v) unsigned int parse_item_list(char* str, const char* item_name, unsigned int max_items, unsigned int *parsed_items, int check_unique_values); -void launch_args_parse(int argc, char** argv); +void launch_args_parse(int argc, char **argv); void cmdline_read_from_file(const char *filename); void prompt(void); void prompt_exit(void); @@ -656,6 +656,7 @@ enum print_warning { }; int port_id_is_invalid(portid_t port_id, enum print_warning warning); int new_socket_id(unsigned int socket_id); +int non_eal_configure(struct rte_cfgfile *cfg, char *prgname); /* * Work-around of a compilation error with ICC on invocations of the -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v4 3/3] app/testpmd: add parse options from JSON cfg file 2017-07-10 12:51 ` [dpdk-dev] [PATCH v4 0/3] EAL change for using a config file for DPDK Kuba Kozak 2017-07-10 12:51 ` [dpdk-dev] [PATCH v4 1/3] eal: add functions parsing EAL arguments Kuba Kozak 2017-07-10 12:51 ` [dpdk-dev] [PATCH v4 2/3] app/testpmd: add parse options from cfg file Kuba Kozak @ 2017-07-10 12:51 ` Kuba Kozak 2 siblings, 0 replies; 70+ messages in thread From: Kuba Kozak @ 2017-07-10 12:51 UTC (permalink / raw) To: dev Cc: deepak.k.jain, bruce.richardson, michalx.k.jastrzebski, jacekx.piasecki, Kuba Kozak This patch shows usage of Jansson library to parse application arguments from JSON config file. https://github.com/akheron/jansson If a --cfgfile-path <path> option is passed into commandline non EAL section, then the disired JSON file is loaded and used by app. In case when JSON doesn't exist an INI file is loaded. The INI file can be passed also from --cfgfile-path option. 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. Signed-off-by: Kuba Kozak <kubax.kozak@intel.com> Suggested-by: Bruce Richardson <bruce.richardson@intel.com> --- app/test-pmd/Makefile | 6 ++++ app/test-pmd/config.json | 33 +++++++++++++++++ app/test-pmd/testpmd.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++- config/common_base | 5 +++ 4 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 app/test-pmd/config.json diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile index c36be19..a1c84cc 100644 --- a/app/test-pmd/Makefile +++ b/app/test-pmd/Makefile @@ -83,6 +83,12 @@ endif endif +ifeq ($(CONFIG_RTE_JSON_SUPPORT),y) +ifeq ($(CONFIG_RTE_LIBRTE_CFGFILE),y) +LDLIBS += -ljansson +endif +endif + CFLAGS_cmdline.o := -D_GNU_SOURCE include $(RTE_SDK)/mk/rte.app.mk diff --git a/app/test-pmd/config.json b/app/test-pmd/config.json new file mode 100644 index 0000000..4589dbc --- /dev/null +++ b/app/test-pmd/config.json @@ -0,0 +1,33 @@ +{ + "DPDK": + { + "v": "", + "l": "0-4", + "n": "4", + "master-lcore": "0", + "proc-type": "primary" + }, + "TEST-PMD": + { + "i": "", + "portmask": "0xff", + "nb-cores": "4", + "port-topology": "paired" + }, + "DPDK.vdev0": + { + "net_ring0": "" + }, + "DPDK.vdev1": + { + "net_ring1": "" + }, + "DPDK.vdev2": + { + "net_ring2": "" + }, + "DPDK.vdev3": + { + "net_ring3": "" + } +} diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index 7b82976..014bb46 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -46,6 +46,10 @@ #include <stdint.h> #include <unistd.h> + +#ifdef RTE_JSON_SUPPORT +#include <jansson.h> +#endif #include <inttypes.h> #include <rte_common.h> @@ -2290,6 +2294,87 @@ cfgfile_load_path(int argc, char **argv) } return NULL; } + +#ifdef RTE_JSON_SUPPORT +/* + * Decoding JSON structure to rte_cfgfile structure. + * Returns handler to cfgfile object, NULL if error. + */ +static struct +rte_cfgfile *l3fwd_json_to_cfg(json_t *json, int flags) +{ + if (!json) { + printf("Error: JSON structure is NULL, nothing to parse\n"); + return NULL; + } + /* create an empty instance of cfgfile structure */ + struct rte_cfgfile *cfgfile = rte_cfgfile_create(flags); + + if (!cfgfile) + return NULL; + + const char *section; + json_t *entry; + + /* set pointer to first section */ + void *iter_section = json_object_iter(json); + + while (iter_section) { + + section = json_object_iter_key(iter_section); + entry = json_object_iter_value(iter_section); + + /* add parsed section name of current section to cfgfile */ + rte_cfgfile_add_section(cfgfile, section); + + /* set pointer to first entry */ + void *iter_entry = json_object_iter(entry); + + while (iter_entry) { + + const char *key; + const char *value; + + key = json_object_iter_key(iter_entry); + value = json_string_value( + json_object_iter_value(iter_entry)); + + /* add parsed key and value of current entry */ + /* to cfgfile */ + rte_cfgfile_add_entry(cfgfile, section, key, value); + + /* pointer to next entry */ + iter_entry = json_object_iter_next(entry, iter_entry); + } + /* pointer to next section */ + iter_section = json_object_iter_next(json, iter_section); + } + return cfgfile; +} + +/* + * Check presence and load JSON file to rte_cfgfile structure. + * Returns handler to cfgfile object, NULL if error. + */ +static struct +rte_cfgfile *l3fwd_load_json_to_cfg(const char *path) +{ + struct rte_cfgfile *cfgfile = NULL; + /* check if config file exist */ + if (access(path, F_OK) != -1) { + /* parse JSON file */ + json_error_t error; + json_t *json = json_load_file(path, 0, &error); + + if (json) + cfgfile = l3fwd_json_to_cfg(json, 0); + else + fprintf(stderr, "JSON error on line %d: %s\n", + error.line, error.text); + } + return cfgfile; +} +#endif #endif #define APP_NAME "TEST-PMD" @@ -2318,9 +2403,16 @@ main(int argc, char** argv) "in default directory)\n"); config_file = strdup("config.ini"); } - +#ifndef RTE_JSON_SUPPORT cfg = rte_cfgfile_load(config_file, CFG_FLAG_EMPTY_VALUES); +#endif +#ifdef RTE_JSON_SUPPORT + if (strstr(config_file, ".ini")) + cfg = rte_cfgfile_load(config_file, CFG_FLAG_EMPTY_VALUES); + else if (strstr(config_file, ".json")) + cfg = l3fwd_load_json_to_cfg(config_file); +#endif if (cfg == NULL) { printf("Info: Valid cfgfile not found\n"); } else { diff --git a/config/common_base b/config/common_base index 8ae6e92..98e8fa2 100644 --- a/config/common_base +++ b/config/common_base @@ -744,3 +744,8 @@ CONFIG_RTE_APP_CRYPTO_PERF=y # Compile the eventdev application # CONFIG_RTE_APP_EVENTDEV=y + +# +# Compile JSON support +# +CONFIG_RTE_JSON_SUPPORT=n \ No newline at end of file -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v3 2/3] app/testpmd: changed example to parse options from cfg file 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 0/3] EAL change for using a config file for DPDK Jacek Piasecki 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 1/3] eal: add functions parsing EAL arguments Jacek Piasecki @ 2017-06-27 10:52 ` Jacek Piasecki 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 3/3] app/testpmd: add parse arguments from JSON config file Jacek Piasecki 2017-07-05 0:00 ` [dpdk-dev] [PATCH v3 0/3] EAL change for using a config file for DPDK Thomas Monjalon 3 siblings, 0 replies; 70+ messages in thread From: Jacek Piasecki @ 2017-06-27 10:52 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, Kuba Kozak From: Kuba Kozak <kubax.kozak@intel.com> This patch shows how to pass arguments to application using config.ini file. If a --cfgfile-path <path> option is passed into commandline non EAL section, then the file is loaded and used by app. If a config.ini file is present in current working directory, and no --cfgfile-path option is passed in, config.ini file will be loaded and used by app as default configuration. Signed-off-by: Kuba Kozak <kubax.kozak@intel.com> Suggested-by: Bruce Richardson <bruce.richardson@intel.com> --- app/test-pmd/config.ini | 24 + app/test-pmd/parameters.c | 1193 ++++++++++++++++++++++++++------------------- app/test-pmd/testpmd.c | 67 ++- app/test-pmd/testpmd.h | 3 +- 4 files changed, 790 insertions(+), 497 deletions(-) create mode 100644 app/test-pmd/config.ini diff --git a/app/test-pmd/config.ini b/app/test-pmd/config.ini new file mode 100644 index 0000000..54c83a2 --- /dev/null +++ b/app/test-pmd/config.ini @@ -0,0 +1,24 @@ +[DPDK] +v = +l = 0-4 +n = 4 +master-lcore = 0 +proc-type = primary + +[TEST-PMD] +i = +portmask = 0xff +nb-cores = 4 +port-topology = paired + +[DPDK.vdev0] +net_ring0 = + +[DPDK.vdev1] +net_ring1 = + +[DPDK.vdev2] +net_ring2 = + +[DPDK.vdev3] +net_ring3 = \ No newline at end of file diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c index fbe6284..4202691 100644 --- a/app/test-pmd/parameters.c +++ b/app/test-pmd/parameters.c @@ -77,9 +77,96 @@ #include <rte_eth_bond.h> #endif #include <rte_flow.h> +#ifdef RTE_LIBRTE_CFGFILE +#include <rte_cfgfile.h> +#endif #include "testpmd.h" +enum { TX, RX }; + +static struct option lgopts[] = { + { "cfgfile-path", 1, 0, 1 }, + { "help", 0, 0, 0 }, +#ifdef RTE_LIBRTE_CMDLINE + { "interactive", 0, 0, 0 }, + { "cmdline-file", 1, 0, 0 }, + { "auto-start", 0, 0, 0 }, + { "eth-peers-configfile", 1, 0, 0 }, + { "eth-peer", 1, 0, 0 }, +#endif + { "ports", 1, 0, 0 }, + { "nb-cores", 1, 0, 0 }, + { "nb-ports", 1, 0, 0 }, + { "coremask", 1, 0, 0 }, + { "portmask", 1, 0, 0 }, + { "numa", 0, 0, 0 }, + { "no-numa", 0, 0, 0 }, + { "mp-anon", 0, 0, 0 }, + { "port-numa-config", 1, 0, 0 }, + { "ring-numa-config", 1, 0, 0 }, + { "socket-num", 1, 0, 0 }, + { "mbuf-size", 1, 0, 0 }, + { "total-num-mbufs", 1, 0, 0 }, + { "max-pkt-len", 1, 0, 0 }, + { "pkt-filter-mode", 1, 0, 0 }, + { "pkt-filter-report-hash", 1, 0, 0 }, + { "pkt-filter-size", 1, 0, 0 }, + { "pkt-filter-drop-queue", 1, 0, 0 }, +#ifdef RTE_LIBRTE_LATENCY_STATS + { "latencystats", 1, 0, 0 }, +#endif +#ifdef RTE_LIBRTE_BITRATE + { "bitrate-stats", 1, 0, 0 }, +#endif + { "disable-crc-strip", 0, 0, 0 }, + { "enable-lro", 0, 0, 0 }, + { "enable-rx-cksum", 0, 0, 0 }, + { "enable-scatter", 0, 0, 0 }, + { "disable-hw-vlan", 0, 0, 0 }, + { "disable-hw-vlan-filter", 0, 0, 0 }, + { "disable-hw-vlan-strip", 0, 0, 0 }, + { "disable-hw-vlan-extend", 0, 0, 0 }, + { "enable-drop-en", 0, 0, 0 }, + { "disable-rss", 0, 0, 0 }, + { "port-topology", 1, 0, 0 }, + { "forward-mode", 1, 0, 0 }, + { "rss-ip", 0, 0, 0 }, + { "rss-udp", 0, 0, 0 }, + { "rxq", 1, 0, 0 }, + { "txq", 1, 0, 0 }, + { "rxd", 1, 0, 0 }, + { "txd", 1, 0, 0 }, + { "burst", 1, 0, 0 }, + { "mbcache", 1, 0, 0 }, + { "txpt", 1, 0, 0 }, + { "txht", 1, 0, 0 }, + { "txwt", 1, 0, 0 }, + { "txfreet", 1, 0, 0 }, + { "txrst", 1, 0, 0 }, + { "txqflags", 1, 0, 0 }, + { "rxpt", 1, 0, 0 }, + { "rxht", 1, 0, 0 }, + { "rxwt", 1, 0, 0 }, + { "rxfreet", 1, 0, 0 }, + { "tx-queue-stats-mapping", 1, 0, 0 }, + { "rx-queue-stats-mapping", 1, 0, 0 }, + { "no-flush-rx", 0, 0, 0 }, + { "txpkts", 1, 0, 0 }, + { "disable-link-check", 0, 0, 0 }, + { "no-lsc-interrupt", 0, 0, 0 }, + { "no-rmv-interrupt", 0, 0, 0 }, + { "print-event", 1, 0, 0 }, + { "mask-event", 1, 0, 0 }, + { 0, 0, 0, 0 }, +}; + +#ifdef RTE_LIBRTE_CMDLINE +#define SHORTOPTS "i" +#else +#define SHORTOPTS "" +#endif + static void usage(char* progname) { @@ -549,559 +636,675 @@ parse_event_printing_config(const char *optarg, int enable) return 0; } -void -launch_args_parse(int argc, char** argv) +static int +parse_option(int opt, char *optarg, int opt_idx, char *prgname) { - int n, opt; - char **argvopt; - int opt_idx; - enum { TX, RX }; + int n; - static struct option lgopts[] = { - { "help", 0, 0, 0 }, + switch (opt) { #ifdef RTE_LIBRTE_CMDLINE - { "interactive", 0, 0, 0 }, - { "cmdline-file", 1, 0, 0 }, - { "auto-start", 0, 0, 0 }, - { "eth-peers-configfile", 1, 0, 0 }, - { "eth-peer", 1, 0, 0 }, -#endif - { "ports", 1, 0, 0 }, - { "nb-cores", 1, 0, 0 }, - { "nb-ports", 1, 0, 0 }, - { "coremask", 1, 0, 0 }, - { "portmask", 1, 0, 0 }, - { "numa", 0, 0, 0 }, - { "no-numa", 0, 0, 0 }, - { "mp-anon", 0, 0, 0 }, - { "port-numa-config", 1, 0, 0 }, - { "ring-numa-config", 1, 0, 0 }, - { "socket-num", 1, 0, 0 }, - { "mbuf-size", 1, 0, 0 }, - { "total-num-mbufs", 1, 0, 0 }, - { "max-pkt-len", 1, 0, 0 }, - { "pkt-filter-mode", 1, 0, 0 }, - { "pkt-filter-report-hash", 1, 0, 0 }, - { "pkt-filter-size", 1, 0, 0 }, - { "pkt-filter-drop-queue", 1, 0, 0 }, -#ifdef RTE_LIBRTE_LATENCY_STATS - { "latencystats", 1, 0, 0 }, -#endif -#ifdef RTE_LIBRTE_BITRATE - { "bitrate-stats", 1, 0, 0 }, + case 'i': + printf("Interactive-mode selected\n"); + interactive = 1; + break; #endif - { "disable-crc-strip", 0, 0, 0 }, - { "enable-lro", 0, 0, 0 }, - { "enable-rx-cksum", 0, 0, 0 }, - { "enable-scatter", 0, 0, 0 }, - { "disable-hw-vlan", 0, 0, 0 }, - { "disable-hw-vlan-filter", 0, 0, 0 }, - { "disable-hw-vlan-strip", 0, 0, 0 }, - { "disable-hw-vlan-extend", 0, 0, 0 }, - { "enable-drop-en", 0, 0, 0 }, - { "disable-rss", 0, 0, 0 }, - { "port-topology", 1, 0, 0 }, - { "forward-mode", 1, 0, 0 }, - { "rss-ip", 0, 0, 0 }, - { "rss-udp", 0, 0, 0 }, - { "rxq", 1, 0, 0 }, - { "txq", 1, 0, 0 }, - { "rxd", 1, 0, 0 }, - { "txd", 1, 0, 0 }, - { "burst", 1, 0, 0 }, - { "mbcache", 1, 0, 0 }, - { "txpt", 1, 0, 0 }, - { "txht", 1, 0, 0 }, - { "txwt", 1, 0, 0 }, - { "txfreet", 1, 0, 0 }, - { "txrst", 1, 0, 0 }, - { "txqflags", 1, 0, 0 }, - { "rxpt", 1, 0, 0 }, - { "rxht", 1, 0, 0 }, - { "rxwt", 1, 0, 0 }, - { "rxfreet", 1, 0, 0 }, - { "tx-queue-stats-mapping", 1, 0, 0 }, - { "rx-queue-stats-mapping", 1, 0, 0 }, - { "no-flush-rx", 0, 0, 0 }, - { "txpkts", 1, 0, 0 }, - { "disable-link-check", 0, 0, 0 }, - { "no-lsc-interrupt", 0, 0, 0 }, - { "no-rmv-interrupt", 0, 0, 0 }, - { "print-event", 1, 0, 0 }, - { "mask-event", 1, 0, 0 }, - { 0, 0, 0, 0 }, - }; + case 'a': + printf("Auto-start selected\n"); + auto_start = 1; + break; - argvopt = argv; - -#ifdef RTE_LIBRTE_CMDLINE -#define SHORTOPTS "i" -#else -#define SHORTOPTS "" -#endif - while ((opt = getopt_long(argc, argvopt, SHORTOPTS "ah", - lgopts, &opt_idx)) != EOF) { - switch (opt) { + case 0: /*long options */ + if (!strcmp(lgopts[opt_idx].name, "help")) { + usage(prgname); + rte_exit(EXIT_SUCCESS, "Displayed help\n"); + return 0; + } #ifdef RTE_LIBRTE_CMDLINE - case 'i': + if (!strcmp(lgopts[opt_idx].name, "interactive")) { printf("Interactive-mode selected\n"); interactive = 1; - break; -#endif - case 'a': + } + if (!strcmp(lgopts[opt_idx].name, "cmdline-file")) { + printf("CLI commands to be read from %s\n", + optarg); + snprintf(cmdline_filename, + sizeof(cmdline_filename), "%s", + optarg); + } + if (!strcmp(lgopts[opt_idx].name, "auto-start")) { printf("Auto-start selected\n"); auto_start = 1; - break; + } + if (!strcmp(lgopts[opt_idx].name, + "eth-peers-configfile")) { + if (init_peer_eth_addrs(optarg) != 0) + rte_exit(EXIT_FAILURE, + "Cannot open logfile\n"); + } + if (!strcmp(lgopts[opt_idx].name, "eth-peer")) { + char *port_end; + uint8_t c, peer_addr[6]; - case 0: /*long options */ - if (!strcmp(lgopts[opt_idx].name, "help")) { - usage(argv[0]); - rte_exit(EXIT_SUCCESS, "Displayed help\n"); - } -#ifdef RTE_LIBRTE_CMDLINE - if (!strcmp(lgopts[opt_idx].name, "interactive")) { - printf("Interactive-mode selected\n"); - interactive = 1; - } - if (!strcmp(lgopts[opt_idx].name, "cmdline-file")) { - printf("CLI commands to be read from %s\n", - optarg); - snprintf(cmdline_filename, - sizeof(cmdline_filename), "%s", - optarg); - } - if (!strcmp(lgopts[opt_idx].name, "auto-start")) { - printf("Auto-start selected\n"); - auto_start = 1; - } - if (!strcmp(lgopts[opt_idx].name, - "eth-peers-configfile")) { - if (init_peer_eth_addrs(optarg) != 0) - rte_exit(EXIT_FAILURE, - "Cannot open logfile\n"); + errno = 0; + n = strtoul(optarg, &port_end, 10); + if (errno != 0 || port_end == optarg || + *port_end++ != ',') + rte_exit(EXIT_FAILURE, + "Invalid eth-peer: %s", optarg); + if (n >= RTE_MAX_ETHPORTS) { + rte_exit(EXIT_FAILURE, + "eth-peer: port %d >= " + "RTE_MAX_ETHPORTS(%d)\n", + n, RTE_MAX_ETHPORTS); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "eth-peer")) { - char *port_end; - uint8_t c, peer_addr[6]; - - errno = 0; - n = strtoul(optarg, &port_end, 10); - if (errno != 0 || port_end == optarg || *port_end++ != ',') - rte_exit(EXIT_FAILURE, - "Invalid eth-peer: %s", optarg); - if (n >= RTE_MAX_ETHPORTS) - rte_exit(EXIT_FAILURE, - "eth-peer: port %d >= RTE_MAX_ETHPORTS(%d)\n", - n, RTE_MAX_ETHPORTS); - if (cmdline_parse_etheraddr(NULL, port_end, - &peer_addr, sizeof(peer_addr)) < 0) - rte_exit(EXIT_FAILURE, - "Invalid ethernet address: %s\n", - port_end); - for (c = 0; c < 6; c++) - peer_eth_addrs[n].addr_bytes[c] = - peer_addr[c]; - nb_peer_eth_addrs++; + if (cmdline_parse_etheraddr(NULL, port_end, + &peer_addr, sizeof(peer_addr)) < 0) { + rte_exit(EXIT_FAILURE, + "Invalid ethernet address: %s\n", + port_end); + return -1; } + for (c = 0; c < 6; c++) + peer_eth_addrs[n].addr_bytes[c] = + peer_addr[c]; + nb_peer_eth_addrs++; + } #endif - if (!strcmp(lgopts[opt_idx].name, "nb-ports")) { - n = atoi(optarg); - if (n > 0 && n <= nb_ports) - nb_fwd_ports = (uint8_t) n; - else - rte_exit(EXIT_FAILURE, - "Invalid port %d\n", n); + if (!strcmp(lgopts[opt_idx].name, "nb-ports")) { + n = atoi(optarg); + if (n > 0 && n <= nb_ports) + nb_fwd_ports = (uint8_t) n; + else { + rte_exit(EXIT_FAILURE, + "Invalid port %d\n", n); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "nb-cores")) { - n = atoi(optarg); - if (n > 0 && n <= nb_lcores) - nb_fwd_lcores = (uint8_t) n; - else - rte_exit(EXIT_FAILURE, - "nb-cores should be > 0 and <= %d\n", - nb_lcores); + } + if (!strcmp(lgopts[opt_idx].name, "nb-cores")) { + n = atoi(optarg); + if (n > 0 && n <= nb_lcores) + nb_fwd_lcores = (uint8_t) n; + else { + rte_exit(EXIT_FAILURE, + "nb-cores should be > 0 and <= %d\n", + nb_lcores); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "coremask")) - parse_fwd_coremask(optarg); - if (!strcmp(lgopts[opt_idx].name, "portmask")) - parse_fwd_portmask(optarg); - if (!strcmp(lgopts[opt_idx].name, "no-numa")) - numa_support = 0; - if (!strcmp(lgopts[opt_idx].name, "numa")) - numa_support = 1; - if (!strcmp(lgopts[opt_idx].name, "mp-anon")) { - mp_anon = 1; + } + if (!strcmp(lgopts[opt_idx].name, "coremask")) + parse_fwd_coremask(optarg); + if (!strcmp(lgopts[opt_idx].name, "portmask")) + parse_fwd_portmask(optarg); + if (!strcmp(lgopts[opt_idx].name, "no-numa")) + numa_support = 0; + if (!strcmp(lgopts[opt_idx].name, "numa")) + numa_support = 1; + if (!strcmp(lgopts[opt_idx].name, "mp-anon")) + mp_anon = 1; + if (!strcmp(lgopts[opt_idx].name, "port-numa-config")) { + if (parse_portnuma_config(optarg)) { + rte_exit(EXIT_FAILURE, + "invalid port-numa configuration\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "port-numa-config")) { - if (parse_portnuma_config(optarg)) - rte_exit(EXIT_FAILURE, - "invalid port-numa configuration\n"); + } + if (!strcmp(lgopts[opt_idx].name, "ring-numa-config")) + if (parse_ringnuma_config(optarg)) { + rte_exit(EXIT_FAILURE, + "invalid ring-numa configuration\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "ring-numa-config")) - if (parse_ringnuma_config(optarg)) - rte_exit(EXIT_FAILURE, - "invalid ring-numa configuration\n"); - if (!strcmp(lgopts[opt_idx].name, "socket-num")) { - n = atoi(optarg); - if (!new_socket_id((uint8_t)n)) { - socket_num = (uint8_t)n; - } else { - print_invalid_socket_id_error(); - rte_exit(EXIT_FAILURE, - "Invalid socket id"); - } + if (!strcmp(lgopts[opt_idx].name, "socket-num")) { + n = atoi(optarg); + if (!new_socket_id((uint8_t)n)) { + socket_num = (uint8_t)n; + } else { + print_invalid_socket_id_error(); + rte_exit(EXIT_FAILURE, + "Invalid socket id"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "mbuf-size")) { - n = atoi(optarg); - if (n > 0 && n <= 0xFFFF) - mbuf_data_size = (uint16_t) n; - else - rte_exit(EXIT_FAILURE, - "mbuf-size should be > 0 and < 65536\n"); + } + if (!strcmp(lgopts[opt_idx].name, "mbuf-size")) { + n = atoi(optarg); + if (n > 0 && n <= 0xFFFF) + mbuf_data_size = (uint16_t) n; + else { + rte_exit(EXIT_FAILURE, + "mbuf-size should be > 0 and < 65536\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "total-num-mbufs")) { - n = atoi(optarg); - if (n > 1024) - param_total_num_mbufs = (unsigned)n; - else - rte_exit(EXIT_FAILURE, - "total-num-mbufs should be > 1024\n"); + } + if (!strcmp(lgopts[opt_idx].name, "total-num-mbufs")) { + n = atoi(optarg); + if (n > 1024) + param_total_num_mbufs = (unsigned int)n; + else { + rte_exit(EXIT_FAILURE, + "total-num-mbufs should be > 1024\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "max-pkt-len")) { - n = atoi(optarg); - if (n >= ETHER_MIN_LEN) { - rx_mode.max_rx_pkt_len = (uint32_t) n; - if (n > ETHER_MAX_LEN) - rx_mode.jumbo_frame = 1; - } else - rte_exit(EXIT_FAILURE, - "Invalid max-pkt-len=%d - should be > %d\n", - n, ETHER_MIN_LEN); + } + if (!strcmp(lgopts[opt_idx].name, "max-pkt-len")) { + n = atoi(optarg); + if (n >= ETHER_MIN_LEN) { + rx_mode.max_rx_pkt_len = (uint32_t) n; + if (n > ETHER_MAX_LEN) + rx_mode.jumbo_frame = 1; + } else { + rte_exit(EXIT_FAILURE, + "Invalid max-pkt-len=%d - should be > %d\n", + n, ETHER_MIN_LEN); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "pkt-filter-mode")) { - if (!strcmp(optarg, "signature")) - fdir_conf.mode = - RTE_FDIR_MODE_SIGNATURE; - else if (!strcmp(optarg, "perfect")) - fdir_conf.mode = RTE_FDIR_MODE_PERFECT; - else if (!strcmp(optarg, "perfect-mac-vlan")) - fdir_conf.mode = RTE_FDIR_MODE_PERFECT_MAC_VLAN; - else if (!strcmp(optarg, "perfect-tunnel")) - fdir_conf.mode = RTE_FDIR_MODE_PERFECT_TUNNEL; - else if (!strcmp(optarg, "none")) - fdir_conf.mode = RTE_FDIR_MODE_NONE; - else - rte_exit(EXIT_FAILURE, - "pkt-mode-invalid %s invalid - must be: " - "none, signature, perfect, perfect-mac-vlan" - " or perfect-tunnel\n", - optarg); + } + if (!strcmp(lgopts[opt_idx].name, "pkt-filter-mode")) { + if (!strcmp(optarg, "signature")) + fdir_conf.mode = + RTE_FDIR_MODE_SIGNATURE; + else if (!strcmp(optarg, "perfect")) + fdir_conf.mode = RTE_FDIR_MODE_PERFECT; + else if (!strcmp(optarg, "perfect-mac-vlan")) + fdir_conf.mode = RTE_FDIR_MODE_PERFECT_MAC_VLAN; + else if (!strcmp(optarg, "perfect-tunnel")) + fdir_conf.mode = RTE_FDIR_MODE_PERFECT_TUNNEL; + else if (!strcmp(optarg, "none")) + fdir_conf.mode = RTE_FDIR_MODE_NONE; + else { + rte_exit(EXIT_FAILURE, + "pkt-mode-invalid %s invalid - must be: " + "none, signature, perfect, perfect-mac-vlan" + " or perfect-tunnel\n", + optarg); + return -1; } - if (!strcmp(lgopts[opt_idx].name, - "pkt-filter-report-hash")) { - if (!strcmp(optarg, "none")) - fdir_conf.status = - RTE_FDIR_NO_REPORT_STATUS; - else if (!strcmp(optarg, "match")) - fdir_conf.status = - RTE_FDIR_REPORT_STATUS; - else if (!strcmp(optarg, "always")) - fdir_conf.status = - RTE_FDIR_REPORT_STATUS_ALWAYS; - else - rte_exit(EXIT_FAILURE, - "pkt-filter-report-hash %s invalid " - "- must be: none or match or always\n", - optarg); + } + if (!strcmp(lgopts[opt_idx].name, + "pkt-filter-report-hash")) { + if (!strcmp(optarg, "none")) + fdir_conf.status = + RTE_FDIR_NO_REPORT_STATUS; + else if (!strcmp(optarg, "match")) + fdir_conf.status = + RTE_FDIR_REPORT_STATUS; + else if (!strcmp(optarg, "always")) + fdir_conf.status = + RTE_FDIR_REPORT_STATUS_ALWAYS; + else { + rte_exit(EXIT_FAILURE, + "pkt-filter-report-hash %s invalid " + "- must be: none or match or always\n", + optarg); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "pkt-filter-size")) { - if (!strcmp(optarg, "64K")) - fdir_conf.pballoc = - RTE_FDIR_PBALLOC_64K; - else if (!strcmp(optarg, "128K")) - fdir_conf.pballoc = - RTE_FDIR_PBALLOC_128K; - else if (!strcmp(optarg, "256K")) - fdir_conf.pballoc = - RTE_FDIR_PBALLOC_256K; - else - rte_exit(EXIT_FAILURE, "pkt-filter-size %s invalid -" - " must be: 64K or 128K or 256K\n", - optarg); + } + if (!strcmp(lgopts[opt_idx].name, "pkt-filter-size")) { + if (!strcmp(optarg, "64K")) + fdir_conf.pballoc = + RTE_FDIR_PBALLOC_64K; + else if (!strcmp(optarg, "128K")) + fdir_conf.pballoc = + RTE_FDIR_PBALLOC_128K; + else if (!strcmp(optarg, "256K")) + fdir_conf.pballoc = + RTE_FDIR_PBALLOC_256K; + else { + rte_exit(EXIT_FAILURE, "pkt-filter-size %s invalid -" + " must be: 64K or 128K or 256K\n", + optarg); + return -1; } - if (!strcmp(lgopts[opt_idx].name, - "pkt-filter-drop-queue")) { - n = atoi(optarg); - if (n >= 0) - fdir_conf.drop_queue = (uint8_t) n; - else - rte_exit(EXIT_FAILURE, - "drop queue %d invalid - must" - "be >= 0 \n", n); + } + if (!strcmp(lgopts[opt_idx].name, + "pkt-filter-drop-queue")) { + n = atoi(optarg); + if (n >= 0) + fdir_conf.drop_queue = (uint8_t) n; + else { + rte_exit(EXIT_FAILURE, + "drop queue %d invalid - must " + "be >= 0\n", n); + return -1; } + } #ifdef RTE_LIBRTE_LATENCY_STATS - if (!strcmp(lgopts[opt_idx].name, - "latencystats")) { - n = atoi(optarg); - if (n >= 0) { - latencystats_lcore_id = (lcoreid_t) n; - latencystats_enabled = 1; - } else - rte_exit(EXIT_FAILURE, - "invalid lcore id %d for latencystats" - " must be >= 0\n", n); + if (!strcmp(lgopts[opt_idx].name, + "latencystats")) { + n = atoi(optarg); + if (n >= 0) { + latencystats_lcore_id = (lcoreid_t) n; + latencystats_enabled = 1; + } else { + rte_exit(EXIT_FAILURE, + "invalid lcore id %d for latencystats" + " must be >= 0\n", n); + return -1; } + } #endif #ifdef RTE_LIBRTE_BITRATE - if (!strcmp(lgopts[opt_idx].name, "bitrate-stats")) { - n = atoi(optarg); - if (n >= 0) { - bitrate_lcore_id = (lcoreid_t) n; - bitrate_enabled = 1; - } else - rte_exit(EXIT_FAILURE, - "invalid lcore id %d for bitrate stats" - " must be >= 0\n", n); + if (!strcmp(lgopts[opt_idx].name, "bitrate-stats")) { + n = atoi(optarg); + if (n >= 0) { + bitrate_lcore_id = (lcoreid_t) n; + bitrate_enabled = 1; + } else { + rte_exit(EXIT_FAILURE, + "invalid lcore id %d for bitrate stats" + " must be >= 0\n", n); + return -1; } + } #endif - if (!strcmp(lgopts[opt_idx].name, "disable-crc-strip")) - rx_mode.hw_strip_crc = 0; - if (!strcmp(lgopts[opt_idx].name, "enable-lro")) - rx_mode.enable_lro = 1; - if (!strcmp(lgopts[opt_idx].name, "enable-scatter")) - rx_mode.enable_scatter = 1; - if (!strcmp(lgopts[opt_idx].name, "enable-rx-cksum")) - rx_mode.hw_ip_checksum = 1; - - if (!strcmp(lgopts[opt_idx].name, "disable-hw-vlan")) { - rx_mode.hw_vlan_filter = 0; - rx_mode.hw_vlan_strip = 0; - rx_mode.hw_vlan_extend = 0; - } + if (!strcmp(lgopts[opt_idx].name, "disable-crc-strip")) + rx_mode.hw_strip_crc = 0; + if (!strcmp(lgopts[opt_idx].name, "enable-lro")) + rx_mode.enable_lro = 1; + if (!strcmp(lgopts[opt_idx].name, "enable-scatter")) + rx_mode.enable_scatter = 1; + if (!strcmp(lgopts[opt_idx].name, "enable-rx-cksum")) + rx_mode.hw_ip_checksum = 1; - if (!strcmp(lgopts[opt_idx].name, - "disable-hw-vlan-filter")) - rx_mode.hw_vlan_filter = 0; - - if (!strcmp(lgopts[opt_idx].name, - "disable-hw-vlan-strip")) - rx_mode.hw_vlan_strip = 0; - - if (!strcmp(lgopts[opt_idx].name, - "disable-hw-vlan-extend")) - rx_mode.hw_vlan_extend = 0; - - if (!strcmp(lgopts[opt_idx].name, "enable-drop-en")) - rx_drop_en = 1; - - if (!strcmp(lgopts[opt_idx].name, "disable-rss")) - rss_hf = 0; - if (!strcmp(lgopts[opt_idx].name, "port-topology")) { - if (!strcmp(optarg, "paired")) - port_topology = PORT_TOPOLOGY_PAIRED; - else if (!strcmp(optarg, "chained")) - port_topology = PORT_TOPOLOGY_CHAINED; - else if (!strcmp(optarg, "loop")) - port_topology = PORT_TOPOLOGY_LOOP; - else - rte_exit(EXIT_FAILURE, "port-topology %s invalid -" - " must be: paired or chained \n", - optarg); + if (!strcmp(lgopts[opt_idx].name, "disable-hw-vlan")) { + rx_mode.hw_vlan_filter = 0; + rx_mode.hw_vlan_strip = 0; + rx_mode.hw_vlan_extend = 0; + } + + if (!strcmp(lgopts[opt_idx].name, + "disable-hw-vlan-filter")) + rx_mode.hw_vlan_filter = 0; + + if (!strcmp(lgopts[opt_idx].name, + "disable-hw-vlan-strip")) + rx_mode.hw_vlan_strip = 0; + + if (!strcmp(lgopts[opt_idx].name, + "disable-hw-vlan-extend")) + rx_mode.hw_vlan_extend = 0; + + if (!strcmp(lgopts[opt_idx].name, "enable-drop-en")) + rx_drop_en = 1; + + if (!strcmp(lgopts[opt_idx].name, "disable-rss")) + rss_hf = 0; + if (!strcmp(lgopts[opt_idx].name, "port-topology")) { + if (!strcmp(optarg, "paired")) + port_topology = PORT_TOPOLOGY_PAIRED; + else if (!strcmp(optarg, "chained")) + port_topology = PORT_TOPOLOGY_CHAINED; + else if (!strcmp(optarg, "loop")) + port_topology = PORT_TOPOLOGY_LOOP; + else { + rte_exit(EXIT_FAILURE, "port-topology %s invalid -" + " must be: paired or chained\n", + optarg); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "forward-mode")) - set_pkt_forwarding_mode(optarg); - if (!strcmp(lgopts[opt_idx].name, "rss-ip")) - rss_hf = ETH_RSS_IP; - if (!strcmp(lgopts[opt_idx].name, "rss-udp")) - rss_hf = ETH_RSS_UDP; - if (!strcmp(lgopts[opt_idx].name, "rxq")) { - n = atoi(optarg); - if (n >= 0 && n <= (int) MAX_QUEUE_ID) - nb_rxq = (queueid_t) n; - else - rte_exit(EXIT_FAILURE, "rxq %d invalid - must be" - " >= 0 && <= %d\n", n, - (int) MAX_QUEUE_ID); + } + if (!strcmp(lgopts[opt_idx].name, "forward-mode")) + set_pkt_forwarding_mode(optarg); + if (!strcmp(lgopts[opt_idx].name, "rss-ip")) + rss_hf = ETH_RSS_IP; + if (!strcmp(lgopts[opt_idx].name, "rss-udp")) + rss_hf = ETH_RSS_UDP; + if (!strcmp(lgopts[opt_idx].name, "rxq")) { + n = atoi(optarg); + if (n >= 0 && n <= (int) MAX_QUEUE_ID) + nb_rxq = (queueid_t) n; + else { + rte_exit(EXIT_FAILURE, "rxq %d invalid - must be" + " >= 0 && <= %d\n", n, + (int) MAX_QUEUE_ID); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txq")) { - n = atoi(optarg); - if (n >= 0 && n <= (int) MAX_QUEUE_ID) - nb_txq = (queueid_t) n; - else - rte_exit(EXIT_FAILURE, "txq %d invalid - must be" - " >= 0 && <= %d\n", n, - (int) MAX_QUEUE_ID); + } + if (!strcmp(lgopts[opt_idx].name, "txq")) { + n = atoi(optarg); + if (n >= 0 && n <= (int) MAX_QUEUE_ID) + nb_txq = (queueid_t) n; + else { + rte_exit(EXIT_FAILURE, "txq %d invalid - must be" + " >= 0 && <= %d\n", n, + (int) MAX_QUEUE_ID); + return -1; } - if (!nb_rxq && !nb_txq) { - rte_exit(EXIT_FAILURE, "Either rx or tx queues should " - "be non-zero\n"); + } + if (!nb_rxq && !nb_txq) { + rte_exit(EXIT_FAILURE, "Either rx or tx queues should " + "be non-zero\n"); + return -1; + } + if (!strcmp(lgopts[opt_idx].name, "burst")) { + n = atoi(optarg); + if ((n >= 1) && (n <= MAX_PKT_BURST)) + nb_pkt_per_burst = (uint16_t) n; + else { + rte_exit(EXIT_FAILURE, + "burst must >= 1 and <= %d]", + MAX_PKT_BURST); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "burst")) { - n = atoi(optarg); - if ((n >= 1) && (n <= MAX_PKT_BURST)) - nb_pkt_per_burst = (uint16_t) n; - else - rte_exit(EXIT_FAILURE, - "burst must >= 1 and <= %d]", - MAX_PKT_BURST); + } + if (!strcmp(lgopts[opt_idx].name, "mbcache")) { + n = atoi(optarg); + if ((n >= 0) && + (n <= RTE_MEMPOOL_CACHE_MAX_SIZE)) + mb_mempool_cache = (uint16_t) n; + else { + rte_exit(EXIT_FAILURE, + "mbcache must be >= 0 and <= %d\n", + RTE_MEMPOOL_CACHE_MAX_SIZE); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "mbcache")) { - n = atoi(optarg); - if ((n >= 0) && - (n <= RTE_MEMPOOL_CACHE_MAX_SIZE)) - mb_mempool_cache = (uint16_t) n; - else - rte_exit(EXIT_FAILURE, - "mbcache must be >= 0 and <= %d\n", - RTE_MEMPOOL_CACHE_MAX_SIZE); + } + if (!strcmp(lgopts[opt_idx].name, "txfreet")) { + n = atoi(optarg); + if (n >= 0) + tx_free_thresh = (int16_t)n; + else { + rte_exit(EXIT_FAILURE, "txfreet must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txfreet")) { - n = atoi(optarg); - if (n >= 0) - tx_free_thresh = (int16_t)n; - else - rte_exit(EXIT_FAILURE, "txfreet must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txrst")) { + n = atoi(optarg); + if (n >= 0) + tx_rs_thresh = (int16_t)n; + else { + rte_exit(EXIT_FAILURE, "txrst must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txrst")) { - n = atoi(optarg); - if (n >= 0) - tx_rs_thresh = (int16_t)n; - else - rte_exit(EXIT_FAILURE, "txrst must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txqflags")) { + char *end = NULL; + + n = strtoul(optarg, &end, 16); + if (n >= 0) + txq_flags = (int32_t)n; + else { + rte_exit(EXIT_FAILURE, + "txqflags must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txqflags")) { - char *end = NULL; - n = strtoul(optarg, &end, 16); - if (n >= 0) - txq_flags = (int32_t)n; - else + } + if (!strcmp(lgopts[opt_idx].name, "rxd")) { + n = atoi(optarg); + if (n > 0) { + if (rx_free_thresh >= n) rte_exit(EXIT_FAILURE, - "txqflags must be >= 0\n"); + "rxd must be > " + "rx_free_thresh(%d)\n", + (int)rx_free_thresh); + else + nb_rxd = (uint16_t) n; + } else { + rte_exit(EXIT_FAILURE, + "rxd(%d) invalid - must be > 0\n", + n); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxd")) { - n = atoi(optarg); - if (n > 0) { - if (rx_free_thresh >= n) - rte_exit(EXIT_FAILURE, - "rxd must be > " - "rx_free_thresh(%d)\n", - (int)rx_free_thresh); - else - nb_rxd = (uint16_t) n; - } else - rte_exit(EXIT_FAILURE, - "rxd(%d) invalid - must be > 0\n", - n); + } + if (!strcmp(lgopts[opt_idx].name, "txd")) { + n = atoi(optarg); + if (n > 0) + nb_txd = (uint16_t) n; + else { + rte_exit(EXIT_FAILURE, "txd must be in > 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txd")) { - n = atoi(optarg); - if (n > 0) - nb_txd = (uint16_t) n; - else - rte_exit(EXIT_FAILURE, "txd must be in > 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txpt")) { + n = atoi(optarg); + if (n >= 0) + tx_pthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "txpt must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txpt")) { - n = atoi(optarg); - if (n >= 0) - tx_pthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "txpt must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txht")) { + n = atoi(optarg); + if (n >= 0) + tx_hthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "txht must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txht")) { - n = atoi(optarg); - if (n >= 0) - tx_hthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "txht must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txwt")) { + n = atoi(optarg); + if (n >= 0) + tx_wthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "txwt must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txwt")) { - n = atoi(optarg); - if (n >= 0) - tx_wthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "txwt must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "rxpt")) { + n = atoi(optarg); + if (n >= 0) + rx_pthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "rxpt must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxpt")) { - n = atoi(optarg); - if (n >= 0) - rx_pthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "rxpt must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "rxht")) { + n = atoi(optarg); + if (n >= 0) + rx_hthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "rxht must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxht")) { - n = atoi(optarg); - if (n >= 0) - rx_hthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "rxht must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "rxwt")) { + n = atoi(optarg); + if (n >= 0) + rx_wthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "rxwt must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxwt")) { - n = atoi(optarg); - if (n >= 0) - rx_wthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "rxwt must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "rxfreet")) { + n = atoi(optarg); + if (n >= 0) + rx_free_thresh = (int16_t)n; + else { + rte_exit(EXIT_FAILURE, "rxfreet must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxfreet")) { - n = atoi(optarg); - if (n >= 0) - rx_free_thresh = (int16_t)n; - else - rte_exit(EXIT_FAILURE, "rxfreet must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "tx-queue-stats-mapping")) { + if (parse_queue_stats_mapping_config(optarg, TX)) { + rte_exit(EXIT_FAILURE, + "invalid TX queue statistics mapping config entered\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "tx-queue-stats-mapping")) { - if (parse_queue_stats_mapping_config(optarg, TX)) { - rte_exit(EXIT_FAILURE, - "invalid TX queue statistics mapping config entered\n"); - } + } + if (!strcmp(lgopts[opt_idx].name, "rx-queue-stats-mapping")) { + if (parse_queue_stats_mapping_config(optarg, RX)) { + rte_exit(EXIT_FAILURE, + "invalid RX queue statistics mapping config entered\n"); } - if (!strcmp(lgopts[opt_idx].name, "rx-queue-stats-mapping")) { - if (parse_queue_stats_mapping_config(optarg, RX)) { - rte_exit(EXIT_FAILURE, - "invalid RX queue statistics mapping config entered\n"); - } + } + if (!strcmp(lgopts[opt_idx].name, "txpkts")) { + unsigned int seg_lengths[RTE_MAX_SEGS_PER_PKT]; + unsigned int nb_segs; + + nb_segs = parse_item_list(optarg, "txpkt segments", + RTE_MAX_SEGS_PER_PKT, seg_lengths, 0); + if (nb_segs > 0) + set_tx_pkt_segments(seg_lengths, nb_segs); + else { + rte_exit(EXIT_FAILURE, "bad txpkts\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txpkts")) { - unsigned seg_lengths[RTE_MAX_SEGS_PER_PKT]; - unsigned int nb_segs; - - nb_segs = parse_item_list(optarg, "txpkt segments", - RTE_MAX_SEGS_PER_PKT, seg_lengths, 0); - if (nb_segs > 0) - set_tx_pkt_segments(seg_lengths, nb_segs); - else - rte_exit(EXIT_FAILURE, "bad txpkts\n"); + } + if (!strcmp(lgopts[opt_idx].name, "no-flush-rx")) + no_flush_rx = 1; + if (!strcmp(lgopts[opt_idx].name, "disable-link-check")) + no_link_check = 1; + if (!strcmp(lgopts[opt_idx].name, "no-lsc-interrupt")) + lsc_interrupt = 0; + if (!strcmp(lgopts[opt_idx].name, "no-rmv-interrupt")) + rmv_interrupt = 0; + if (!strcmp(lgopts[opt_idx].name, "print-event")) + if (parse_event_printing_config(optarg, 1)) { + rte_exit(EXIT_FAILURE, + "invalid print-event argument\n"); + return -1; + } + if (!strcmp(lgopts[opt_idx].name, "mask-event")) + if (parse_event_printing_config(optarg, 0)) { + rte_exit(EXIT_FAILURE, + "invalid mask-event argument\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "no-flush-rx")) - no_flush_rx = 1; - if (!strcmp(lgopts[opt_idx].name, "disable-link-check")) - no_link_check = 1; - if (!strcmp(lgopts[opt_idx].name, "no-lsc-interrupt")) - lsc_interrupt = 0; - if (!strcmp(lgopts[opt_idx].name, "no-rmv-interrupt")) - rmv_interrupt = 0; - if (!strcmp(lgopts[opt_idx].name, "print-event")) - if (parse_event_printing_config(optarg, 1)) { - rte_exit(EXIT_FAILURE, - "invalid print-event argument\n"); - } - if (!strcmp(lgopts[opt_idx].name, "mask-event")) - if (parse_event_printing_config(optarg, 0)) { - rte_exit(EXIT_FAILURE, - "invalid mask-event argument\n"); - } - break; - case 'h': - usage(argv[0]); - rte_exit(EXIT_SUCCESS, "Displayed help\n"); - break; - default: - usage(argv[0]); - rte_exit(EXIT_FAILURE, - "Command line is incomplete or incorrect\n"); + break; + case 'h': + usage(prgname); + rte_exit(EXIT_SUCCESS, "Displayed help\n"); + return -1; + case 1: + /* does nothing*/ + break; + default: + usage(prgname); + rte_exit(EXIT_FAILURE, + "Command line is incomplete or incorrect\n"); + return -1; + } + return 0; +} + +void +launch_args_parse(int argc, char **argv) +{ + int opt; + char **argvopt; + int opt_idx; + + argvopt = argv; + + while ((opt = getopt_long(argc, argvopt, SHORTOPTS "ah", + lgopts, &opt_idx)) != EOF) { + parse_option(opt, optarg, opt_idx, argv[0]); + } +} + +#ifdef RTE_LIBRTE_CFGFILE_DEBUG +#define max_nb_sections 100 +static void print_cfg(struct rte_cfgfile *cfg) +{ + int i, num_sections, num_entries, j; + + printf("-------------------------\n"); + printf("SECTIONS:\n\n"); + + char *sections[max_nb_sections+1]; + + for (i = 0; i < max_nb_sections; i++) + sections[i] = malloc(sizeof(sections[0]) * 64); + sections[i] = 0; + + num_sections = rte_cfgfile_sections(cfg, sections, max_nb_sections); + + for (i = 0; i < num_sections; i++) { + printf("************************\n"); + printf("%s:\n", sections[i]); + num_entries = rte_cfgfile_section_num_entries(cfg, sections[i]); + + struct rte_cfgfile_entry entries[num_entries]; + + rte_cfgfile_section_entries(cfg, sections[i], + entries, num_entries); + for (j = 0; j < num_entries; j++) + printf("%s -> %s\n", entries[j].name, + entries[j].value); + } + printf("************************\n\n"); + printf("-------------------------\n\n"); + + i = 0; + while (sections[i]) { + free(sections[i]); + sections[i] = 0; + i++; + } +} +#endif + +#ifdef RTE_LIBRTE_CFGFILE +static void +non_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; lgopts[i].name != NULL; i++) { + if (strcmp(str, lgopts[i].name) == 0) { + *opt = lgopts[i].val; + *option_index = i; break; } } } +#endif + +#ifdef RTE_LIBRTE_CFGFILE +#define APP_SECTION "TEST-PMD" +int non_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; + } + +#ifdef RTE_LIBRTE_CFGFILE_DEBUG + print_cfg(cfg); +#endif + + n_entries = rte_cfgfile_section_num_entries(cfg, APP_SECTION); + + if (n_entries < 1) { + printf("No %s section entries " + "in cfgfile object\n", APP_SECTION); + return -1; + } + + struct rte_cfgfile_entry entries[n_entries]; + + if (n_entries != + rte_cfgfile_section_entries(cfg, APP_SECTION, entries, + n_entries)) { + rte_exit(EXIT_FAILURE, "Unexpected fault"); + return -1; + } + + for (i = 0; i < n_entries; i++) { + non_eal_getopt(entries[i].name, &opt, &option_index); + + parse_option(opt, entries[i].value, + option_index, prgname); + } + return 0; +} +#endif diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index b29328a..cd69a6b 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -90,6 +90,9 @@ #ifdef RTE_LIBRTE_LATENCY_STATS #include <rte_latencystats.h> #endif +#ifdef RTE_LIBRTE_CFGFILE +#include <rte_cfgfile.h> +#endif #include "testpmd.h" @@ -2251,15 +2254,66 @@ signal_handler(int signum) } } +#ifdef RTE_LIBRTE_CFGFILE +/* Load config file path from command line */ +static char * +cfgfile_load_path(int argc, char **argv) +{ + int i; + + for (i = 0; i < argc; i++) { + if (!strcmp("--cfgfile-path", argv[i])) { + if (argv[i+1] && argv[i+1][0] != '-') + return strdup(argv[i+1]); + } else if (!strncmp("--cfgfile-path=", argv[i], 15)) { + char *ptr = argv[i]; + + ptr += 15; + if (strlen(ptr)) + return strdup(ptr); + } + } + return NULL; +} +#endif + +#define APP_NAME "TEST-PMD" int main(int argc, char** argv) { int diag; uint8_t port_id; +#ifdef RTE_LIBRTE_CFGFILE + struct rte_cfgfile *cfg = NULL; + char *config_file = NULL; +#endif signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); +#ifdef RTE_LIBRTE_CFGFILE + /* load --cfgfile-path argument from argv */ + config_file = cfgfile_load_path(argc, argv); + + if (config_file) { + printf("Info: found cfgfile-path \"%s\"\n", config_file); + } else { + printf("Info: not found cfgfile-path parameter " + "(searching for cfgfile " + "in default directory)\n"); + config_file = strdup("config.ini"); + } + + cfg = rte_cfgfile_load(config_file, CFG_FLAG_EMPTY_VALUES); + + if (cfg == NULL) { + printf("Info: Valid cfgfile not found\n"); + cfg = rte_cfgfile_create(CFG_FLAG_EMPTY_VALUES); + } + diag = rte_eal_configure(cfg, argv[0]); + if (diag < 0) + rte_panic("Cannot init EAL\n"); +#endif diag = rte_eal_init(argc, argv); if (diag < 0) rte_panic("Cannot init EAL\n"); @@ -2289,6 +2343,18 @@ main(int argc, char** argv) latencystats_enabled = 0; #endif +#ifdef RTE_LIBRTE_CFGFILE + if (argc > 1) { + non_eal_configure(cfg, argv[0]); + rte_cfgfile_close(cfg); + cfg = 0; + + if (config_file) { + free(config_file); + config_file = 0; + } + } +#endif argc -= diag; argv += diag; if (argc > 1) @@ -2360,6 +2426,5 @@ main(int argc, char** argv) if (rc < 0) return 1; } - return 0; } diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 364502d..93eebbf 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -499,7 +499,7 @@ port_pci_reg_write(struct rte_port *port, uint32_t reg_off, uint32_t reg_v) unsigned int parse_item_list(char* str, const char* item_name, unsigned int max_items, unsigned int *parsed_items, int check_unique_values); -void launch_args_parse(int argc, char** argv); +void launch_args_parse(int argc, char **argv); void cmdline_read_from_file(const char *filename); void prompt(void); void prompt_exit(void); @@ -641,6 +641,7 @@ enum print_warning { }; int port_id_is_invalid(portid_t port_id, enum print_warning warning); int new_socket_id(unsigned int socket_id); +int non_eal_configure(struct rte_cfgfile *cfg, char *prgname); /* * Work-around of a compilation error with ICC on invocations of the -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v3 3/3] app/testpmd: add parse arguments from JSON config file 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 0/3] EAL change for using a config file for DPDK Jacek Piasecki 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 1/3] eal: add functions parsing EAL arguments Jacek Piasecki 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 2/3] app/testpmd: changed example to parse options from " Jacek Piasecki @ 2017-06-27 10:52 ` Jacek Piasecki 2017-07-05 0:00 ` [dpdk-dev] [PATCH v3 0/3] EAL change for using a config file for DPDK Thomas Monjalon 3 siblings, 0 replies; 70+ messages in thread From: Jacek Piasecki @ 2017-06-27 10:52 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, Kuba Kozak From: Kuba Kozak <kubax.kozak@intel.com> This patch shows usage of Jansson library to parse application arguments from JSON config file. https://github.com/akheron/jansson If a --cfgfile-path <path> option is passed into commandline non EAL section, then the disired JSON file is loaded and used by app. In case when JSON doesn't exist an INI file is loaded. The INI file can be passed also from --cfgfile-path option. 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. Signed-off-by: Kuba Kozak <kubax.kozak@intel.com> Suggested-by: Bruce Richardson <bruce.richardson@intel.com> --- app/test-pmd/Makefile | 6 ++++ app/test-pmd/config.json | 33 +++++++++++++++++ app/test-pmd/testpmd.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++- config/common_base | 5 +++ 4 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 app/test-pmd/config.json diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile index c36be19..a1c84cc 100644 --- a/app/test-pmd/Makefile +++ b/app/test-pmd/Makefile @@ -83,6 +83,12 @@ endif endif +ifeq ($(CONFIG_RTE_JSON_SUPPORT),y) +ifeq ($(CONFIG_RTE_LIBRTE_CFGFILE),y) +LDLIBS += -ljansson +endif +endif + CFLAGS_cmdline.o := -D_GNU_SOURCE include $(RTE_SDK)/mk/rte.app.mk diff --git a/app/test-pmd/config.json b/app/test-pmd/config.json new file mode 100644 index 0000000..4589dbc --- /dev/null +++ b/app/test-pmd/config.json @@ -0,0 +1,33 @@ +{ + "DPDK": + { + "v": "", + "l": "0-4", + "n": "4", + "master-lcore": "0", + "proc-type": "primary" + }, + "TEST-PMD": + { + "i": "", + "portmask": "0xff", + "nb-cores": "4", + "port-topology": "paired" + }, + "DPDK.vdev0": + { + "net_ring0": "" + }, + "DPDK.vdev1": + { + "net_ring1": "" + }, + "DPDK.vdev2": + { + "net_ring2": "" + }, + "DPDK.vdev3": + { + "net_ring3": "" + } +} diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index cd69a6b..9ce1bbe 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -46,6 +46,10 @@ #include <stdint.h> #include <unistd.h> + +#ifdef RTE_JSON_SUPPORT +#include <jansson.h> +#endif #include <inttypes.h> #include <rte_common.h> @@ -2275,6 +2279,87 @@ cfgfile_load_path(int argc, char **argv) } return NULL; } + +#ifdef RTE_JSON_SUPPORT +/* + * Decoding JSON structure to rte_cfgfile structure. + * Returns handler to cfgfile object, NULL if error. + */ +static struct +rte_cfgfile *l3fwd_json_to_cfg(json_t *json, int flags) +{ + if (!json) { + printf("Error: JSON structure is NULL, nothing to parse\n"); + return NULL; + } + /* create an empty instance of cfgfile structure */ + struct rte_cfgfile *cfgfile = rte_cfgfile_create(flags); + + if (!cfgfile) + return NULL; + + const char *section; + json_t *entry; + + /* set pointer to first section */ + void *iter_section = json_object_iter(json); + + while (iter_section) { + + section = json_object_iter_key(iter_section); + entry = json_object_iter_value(iter_section); + + /* add parsed section name of current section to cfgfile */ + rte_cfgfile_add_section(cfgfile, section); + + /* set pointer to first entry */ + void *iter_entry = json_object_iter(entry); + + while (iter_entry) { + + const char *key; + const char *value; + + key = json_object_iter_key(iter_entry); + value = json_string_value( + json_object_iter_value(iter_entry)); + + /* add parsed key and value of current entry */ + /* to cfgfile */ + rte_cfgfile_add_entry(cfgfile, section, key, value); + + /* pointer to next entry */ + iter_entry = json_object_iter_next(entry, iter_entry); + } + /* pointer to next section */ + iter_section = json_object_iter_next(json, iter_section); + } + return cfgfile; +} + +/* + * Check presence and load JSON file to rte_cfgfile structure. + * Returns handler to cfgfile object, NULL if error. + */ +static struct +rte_cfgfile *l3fwd_load_json_to_cfg(const char *path) +{ + struct rte_cfgfile *cfgfile = NULL; + /* check if config file exist */ + if (access(path, F_OK) != -1) { + /* parse JSON file */ + json_error_t error; + json_t *json = json_load_file(path, 0, &error); + + if (json) + cfgfile = l3fwd_json_to_cfg(json, 0); + else + fprintf(stderr, "JSON error on line %d: %s\n", + error.line, error.text); + } + return cfgfile; +} +#endif #endif #define APP_NAME "TEST-PMD" @@ -2303,9 +2388,16 @@ main(int argc, char** argv) "in default directory)\n"); config_file = strdup("config.ini"); } - +#ifndef RTE_JSON_SUPPORT cfg = rte_cfgfile_load(config_file, CFG_FLAG_EMPTY_VALUES); +#endif +#ifdef RTE_JSON_SUPPORT + if (strstr(config_file, ".ini")) + cfg = rte_cfgfile_load(config_file, CFG_FLAG_EMPTY_VALUES); + else if (strstr(config_file, ".json")) + cfg = l3fwd_load_json_to_cfg(config_file); +#endif if (cfg == NULL) { printf("Info: Valid cfgfile not found\n"); cfg = rte_cfgfile_create(CFG_FLAG_EMPTY_VALUES); diff --git a/config/common_base b/config/common_base index c1d0e69..0eed278 100644 --- a/config/common_base +++ b/config/common_base @@ -734,3 +734,8 @@ CONFIG_RTE_TEST_PMD_RECORD_BURST_STATS=n # Compile the crypto performance application # CONFIG_RTE_APP_CRYPTO_PERF=y + +# +# Compile JSON support +# +CONFIG_RTE_JSON_SUPPORT=n -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH v3 0/3] EAL change for using a config file for DPDK 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 0/3] EAL change for using a config file for DPDK Jacek Piasecki ` (2 preceding siblings ...) 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 3/3] app/testpmd: add parse arguments from JSON config file Jacek Piasecki @ 2017-07-05 0:00 ` Thomas Monjalon 3 siblings, 0 replies; 70+ messages in thread From: Thomas Monjalon @ 2017-07-05 0:00 UTC (permalink / raw) To: Jacek Piasecki, bruce.richardson; +Cc: dev, deepak.k.jain 27/06/2017 12:52, Jacek Piasecki: > 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. I think we should focus on better API for apps instead of forging the default EAL config into the stone of a config file. Anyway, we do not have enough time in 17.08 release cycle to properly discuss this important topic. I hope it opens the discussion in order to have a clear view of what we could change and integrate in 17.11. ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v2 6/7] app/testpmd: changed example to parse options from cfg file 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 0/7] Add support for using a config file for DPDK Jacek Piasecki ` (4 preceding siblings ...) 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 5/7] eal: add functions parsing EAL arguments Jacek Piasecki @ 2017-06-26 10:59 ` Jacek Piasecki 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 7/7] app/testpmd: add parse arguments from JSON config file Jacek Piasecki 6 siblings, 0 replies; 70+ messages in thread From: Jacek Piasecki @ 2017-06-26 10:59 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, Kuba Kozak From: Kuba Kozak <kubax.kozak@intel.com> This patch shows how to pass arguments to application using config.ini file. If a --cfgfile-path <path> option is passed into commandline non EAL section, then the file is loaded and used by app. If a config.ini file is present in current working directory, and no --cfgfile-path option is passed in, config.ini file will be loaded and used by app as default configuration. Signed-off-by: Kuba Kozak <kubax.kozak@intel.com> Suggested-by: Bruce Richardson <bruce.richardson@intel.com> --- app/test-pmd/config.ini | 24 + app/test-pmd/parameters.c | 1193 ++++++++++++++++++++++++++------------------- app/test-pmd/testpmd.c | 67 ++- app/test-pmd/testpmd.h | 3 +- 4 files changed, 790 insertions(+), 497 deletions(-) create mode 100644 app/test-pmd/config.ini diff --git a/app/test-pmd/config.ini b/app/test-pmd/config.ini new file mode 100644 index 0000000..54c83a2 --- /dev/null +++ b/app/test-pmd/config.ini @@ -0,0 +1,24 @@ +[DPDK] +v = +l = 0-4 +n = 4 +master-lcore = 0 +proc-type = primary + +[TEST-PMD] +i = +portmask = 0xff +nb-cores = 4 +port-topology = paired + +[DPDK.vdev0] +net_ring0 = + +[DPDK.vdev1] +net_ring1 = + +[DPDK.vdev2] +net_ring2 = + +[DPDK.vdev3] +net_ring3 = \ No newline at end of file diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c index fbe6284..4202691 100644 --- a/app/test-pmd/parameters.c +++ b/app/test-pmd/parameters.c @@ -77,9 +77,96 @@ #include <rte_eth_bond.h> #endif #include <rte_flow.h> +#ifdef RTE_LIBRTE_CFGFILE +#include <rte_cfgfile.h> +#endif #include "testpmd.h" +enum { TX, RX }; + +static struct option lgopts[] = { + { "cfgfile-path", 1, 0, 1 }, + { "help", 0, 0, 0 }, +#ifdef RTE_LIBRTE_CMDLINE + { "interactive", 0, 0, 0 }, + { "cmdline-file", 1, 0, 0 }, + { "auto-start", 0, 0, 0 }, + { "eth-peers-configfile", 1, 0, 0 }, + { "eth-peer", 1, 0, 0 }, +#endif + { "ports", 1, 0, 0 }, + { "nb-cores", 1, 0, 0 }, + { "nb-ports", 1, 0, 0 }, + { "coremask", 1, 0, 0 }, + { "portmask", 1, 0, 0 }, + { "numa", 0, 0, 0 }, + { "no-numa", 0, 0, 0 }, + { "mp-anon", 0, 0, 0 }, + { "port-numa-config", 1, 0, 0 }, + { "ring-numa-config", 1, 0, 0 }, + { "socket-num", 1, 0, 0 }, + { "mbuf-size", 1, 0, 0 }, + { "total-num-mbufs", 1, 0, 0 }, + { "max-pkt-len", 1, 0, 0 }, + { "pkt-filter-mode", 1, 0, 0 }, + { "pkt-filter-report-hash", 1, 0, 0 }, + { "pkt-filter-size", 1, 0, 0 }, + { "pkt-filter-drop-queue", 1, 0, 0 }, +#ifdef RTE_LIBRTE_LATENCY_STATS + { "latencystats", 1, 0, 0 }, +#endif +#ifdef RTE_LIBRTE_BITRATE + { "bitrate-stats", 1, 0, 0 }, +#endif + { "disable-crc-strip", 0, 0, 0 }, + { "enable-lro", 0, 0, 0 }, + { "enable-rx-cksum", 0, 0, 0 }, + { "enable-scatter", 0, 0, 0 }, + { "disable-hw-vlan", 0, 0, 0 }, + { "disable-hw-vlan-filter", 0, 0, 0 }, + { "disable-hw-vlan-strip", 0, 0, 0 }, + { "disable-hw-vlan-extend", 0, 0, 0 }, + { "enable-drop-en", 0, 0, 0 }, + { "disable-rss", 0, 0, 0 }, + { "port-topology", 1, 0, 0 }, + { "forward-mode", 1, 0, 0 }, + { "rss-ip", 0, 0, 0 }, + { "rss-udp", 0, 0, 0 }, + { "rxq", 1, 0, 0 }, + { "txq", 1, 0, 0 }, + { "rxd", 1, 0, 0 }, + { "txd", 1, 0, 0 }, + { "burst", 1, 0, 0 }, + { "mbcache", 1, 0, 0 }, + { "txpt", 1, 0, 0 }, + { "txht", 1, 0, 0 }, + { "txwt", 1, 0, 0 }, + { "txfreet", 1, 0, 0 }, + { "txrst", 1, 0, 0 }, + { "txqflags", 1, 0, 0 }, + { "rxpt", 1, 0, 0 }, + { "rxht", 1, 0, 0 }, + { "rxwt", 1, 0, 0 }, + { "rxfreet", 1, 0, 0 }, + { "tx-queue-stats-mapping", 1, 0, 0 }, + { "rx-queue-stats-mapping", 1, 0, 0 }, + { "no-flush-rx", 0, 0, 0 }, + { "txpkts", 1, 0, 0 }, + { "disable-link-check", 0, 0, 0 }, + { "no-lsc-interrupt", 0, 0, 0 }, + { "no-rmv-interrupt", 0, 0, 0 }, + { "print-event", 1, 0, 0 }, + { "mask-event", 1, 0, 0 }, + { 0, 0, 0, 0 }, +}; + +#ifdef RTE_LIBRTE_CMDLINE +#define SHORTOPTS "i" +#else +#define SHORTOPTS "" +#endif + static void usage(char* progname) { @@ -549,559 +636,675 @@ parse_event_printing_config(const char *optarg, int enable) return 0; } -void -launch_args_parse(int argc, char** argv) +static int +parse_option(int opt, char *optarg, int opt_idx, char *prgname) { - int n, opt; - char **argvopt; - int opt_idx; - enum { TX, RX }; + int n; - static struct option lgopts[] = { - { "help", 0, 0, 0 }, + switch (opt) { #ifdef RTE_LIBRTE_CMDLINE - { "interactive", 0, 0, 0 }, - { "cmdline-file", 1, 0, 0 }, - { "auto-start", 0, 0, 0 }, - { "eth-peers-configfile", 1, 0, 0 }, - { "eth-peer", 1, 0, 0 }, -#endif - { "ports", 1, 0, 0 }, - { "nb-cores", 1, 0, 0 }, - { "nb-ports", 1, 0, 0 }, - { "coremask", 1, 0, 0 }, - { "portmask", 1, 0, 0 }, - { "numa", 0, 0, 0 }, - { "no-numa", 0, 0, 0 }, - { "mp-anon", 0, 0, 0 }, - { "port-numa-config", 1, 0, 0 }, - { "ring-numa-config", 1, 0, 0 }, - { "socket-num", 1, 0, 0 }, - { "mbuf-size", 1, 0, 0 }, - { "total-num-mbufs", 1, 0, 0 }, - { "max-pkt-len", 1, 0, 0 }, - { "pkt-filter-mode", 1, 0, 0 }, - { "pkt-filter-report-hash", 1, 0, 0 }, - { "pkt-filter-size", 1, 0, 0 }, - { "pkt-filter-drop-queue", 1, 0, 0 }, -#ifdef RTE_LIBRTE_LATENCY_STATS - { "latencystats", 1, 0, 0 }, -#endif -#ifdef RTE_LIBRTE_BITRATE - { "bitrate-stats", 1, 0, 0 }, + case 'i': + printf("Interactive-mode selected\n"); + interactive = 1; + break; #endif - { "disable-crc-strip", 0, 0, 0 }, - { "enable-lro", 0, 0, 0 }, - { "enable-rx-cksum", 0, 0, 0 }, - { "enable-scatter", 0, 0, 0 }, - { "disable-hw-vlan", 0, 0, 0 }, - { "disable-hw-vlan-filter", 0, 0, 0 }, - { "disable-hw-vlan-strip", 0, 0, 0 }, - { "disable-hw-vlan-extend", 0, 0, 0 }, - { "enable-drop-en", 0, 0, 0 }, - { "disable-rss", 0, 0, 0 }, - { "port-topology", 1, 0, 0 }, - { "forward-mode", 1, 0, 0 }, - { "rss-ip", 0, 0, 0 }, - { "rss-udp", 0, 0, 0 }, - { "rxq", 1, 0, 0 }, - { "txq", 1, 0, 0 }, - { "rxd", 1, 0, 0 }, - { "txd", 1, 0, 0 }, - { "burst", 1, 0, 0 }, - { "mbcache", 1, 0, 0 }, - { "txpt", 1, 0, 0 }, - { "txht", 1, 0, 0 }, - { "txwt", 1, 0, 0 }, - { "txfreet", 1, 0, 0 }, - { "txrst", 1, 0, 0 }, - { "txqflags", 1, 0, 0 }, - { "rxpt", 1, 0, 0 }, - { "rxht", 1, 0, 0 }, - { "rxwt", 1, 0, 0 }, - { "rxfreet", 1, 0, 0 }, - { "tx-queue-stats-mapping", 1, 0, 0 }, - { "rx-queue-stats-mapping", 1, 0, 0 }, - { "no-flush-rx", 0, 0, 0 }, - { "txpkts", 1, 0, 0 }, - { "disable-link-check", 0, 0, 0 }, - { "no-lsc-interrupt", 0, 0, 0 }, - { "no-rmv-interrupt", 0, 0, 0 }, - { "print-event", 1, 0, 0 }, - { "mask-event", 1, 0, 0 }, - { 0, 0, 0, 0 }, - }; + case 'a': + printf("Auto-start selected\n"); + auto_start = 1; + break; - argvopt = argv; - -#ifdef RTE_LIBRTE_CMDLINE -#define SHORTOPTS "i" -#else -#define SHORTOPTS "" -#endif - while ((opt = getopt_long(argc, argvopt, SHORTOPTS "ah", - lgopts, &opt_idx)) != EOF) { - switch (opt) { + case 0: /*long options */ + if (!strcmp(lgopts[opt_idx].name, "help")) { + usage(prgname); + rte_exit(EXIT_SUCCESS, "Displayed help\n"); + return 0; + } #ifdef RTE_LIBRTE_CMDLINE - case 'i': + if (!strcmp(lgopts[opt_idx].name, "interactive")) { printf("Interactive-mode selected\n"); interactive = 1; - break; -#endif - case 'a': + } + if (!strcmp(lgopts[opt_idx].name, "cmdline-file")) { + printf("CLI commands to be read from %s\n", + optarg); + snprintf(cmdline_filename, + sizeof(cmdline_filename), "%s", + optarg); + } + if (!strcmp(lgopts[opt_idx].name, "auto-start")) { printf("Auto-start selected\n"); auto_start = 1; - break; + } + if (!strcmp(lgopts[opt_idx].name, + "eth-peers-configfile")) { + if (init_peer_eth_addrs(optarg) != 0) + rte_exit(EXIT_FAILURE, + "Cannot open logfile\n"); + } + if (!strcmp(lgopts[opt_idx].name, "eth-peer")) { + char *port_end; + uint8_t c, peer_addr[6]; - case 0: /*long options */ - if (!strcmp(lgopts[opt_idx].name, "help")) { - usage(argv[0]); - rte_exit(EXIT_SUCCESS, "Displayed help\n"); - } -#ifdef RTE_LIBRTE_CMDLINE - if (!strcmp(lgopts[opt_idx].name, "interactive")) { - printf("Interactive-mode selected\n"); - interactive = 1; - } - if (!strcmp(lgopts[opt_idx].name, "cmdline-file")) { - printf("CLI commands to be read from %s\n", - optarg); - snprintf(cmdline_filename, - sizeof(cmdline_filename), "%s", - optarg); - } - if (!strcmp(lgopts[opt_idx].name, "auto-start")) { - printf("Auto-start selected\n"); - auto_start = 1; - } - if (!strcmp(lgopts[opt_idx].name, - "eth-peers-configfile")) { - if (init_peer_eth_addrs(optarg) != 0) - rte_exit(EXIT_FAILURE, - "Cannot open logfile\n"); + errno = 0; + n = strtoul(optarg, &port_end, 10); + if (errno != 0 || port_end == optarg || + *port_end++ != ',') + rte_exit(EXIT_FAILURE, + "Invalid eth-peer: %s", optarg); + if (n >= RTE_MAX_ETHPORTS) { + rte_exit(EXIT_FAILURE, + "eth-peer: port %d >= " + "RTE_MAX_ETHPORTS(%d)\n", + n, RTE_MAX_ETHPORTS); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "eth-peer")) { - char *port_end; - uint8_t c, peer_addr[6]; - - errno = 0; - n = strtoul(optarg, &port_end, 10); - if (errno != 0 || port_end == optarg || *port_end++ != ',') - rte_exit(EXIT_FAILURE, - "Invalid eth-peer: %s", optarg); - if (n >= RTE_MAX_ETHPORTS) - rte_exit(EXIT_FAILURE, - "eth-peer: port %d >= RTE_MAX_ETHPORTS(%d)\n", - n, RTE_MAX_ETHPORTS); - if (cmdline_parse_etheraddr(NULL, port_end, - &peer_addr, sizeof(peer_addr)) < 0) - rte_exit(EXIT_FAILURE, - "Invalid ethernet address: %s\n", - port_end); - for (c = 0; c < 6; c++) - peer_eth_addrs[n].addr_bytes[c] = - peer_addr[c]; - nb_peer_eth_addrs++; + if (cmdline_parse_etheraddr(NULL, port_end, + &peer_addr, sizeof(peer_addr)) < 0) { + rte_exit(EXIT_FAILURE, + "Invalid ethernet address: %s\n", + port_end); + return -1; } + for (c = 0; c < 6; c++) + peer_eth_addrs[n].addr_bytes[c] = + peer_addr[c]; + nb_peer_eth_addrs++; + } #endif - if (!strcmp(lgopts[opt_idx].name, "nb-ports")) { - n = atoi(optarg); - if (n > 0 && n <= nb_ports) - nb_fwd_ports = (uint8_t) n; - else - rte_exit(EXIT_FAILURE, - "Invalid port %d\n", n); + if (!strcmp(lgopts[opt_idx].name, "nb-ports")) { + n = atoi(optarg); + if (n > 0 && n <= nb_ports) + nb_fwd_ports = (uint8_t) n; + else { + rte_exit(EXIT_FAILURE, + "Invalid port %d\n", n); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "nb-cores")) { - n = atoi(optarg); - if (n > 0 && n <= nb_lcores) - nb_fwd_lcores = (uint8_t) n; - else - rte_exit(EXIT_FAILURE, - "nb-cores should be > 0 and <= %d\n", - nb_lcores); + } + if (!strcmp(lgopts[opt_idx].name, "nb-cores")) { + n = atoi(optarg); + if (n > 0 && n <= nb_lcores) + nb_fwd_lcores = (uint8_t) n; + else { + rte_exit(EXIT_FAILURE, + "nb-cores should be > 0 and <= %d\n", + nb_lcores); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "coremask")) - parse_fwd_coremask(optarg); - if (!strcmp(lgopts[opt_idx].name, "portmask")) - parse_fwd_portmask(optarg); - if (!strcmp(lgopts[opt_idx].name, "no-numa")) - numa_support = 0; - if (!strcmp(lgopts[opt_idx].name, "numa")) - numa_support = 1; - if (!strcmp(lgopts[opt_idx].name, "mp-anon")) { - mp_anon = 1; + } + if (!strcmp(lgopts[opt_idx].name, "coremask")) + parse_fwd_coremask(optarg); + if (!strcmp(lgopts[opt_idx].name, "portmask")) + parse_fwd_portmask(optarg); + if (!strcmp(lgopts[opt_idx].name, "no-numa")) + numa_support = 0; + if (!strcmp(lgopts[opt_idx].name, "numa")) + numa_support = 1; + if (!strcmp(lgopts[opt_idx].name, "mp-anon")) + mp_anon = 1; + if (!strcmp(lgopts[opt_idx].name, "port-numa-config")) { + if (parse_portnuma_config(optarg)) { + rte_exit(EXIT_FAILURE, + "invalid port-numa configuration\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "port-numa-config")) { - if (parse_portnuma_config(optarg)) - rte_exit(EXIT_FAILURE, - "invalid port-numa configuration\n"); + } + if (!strcmp(lgopts[opt_idx].name, "ring-numa-config")) + if (parse_ringnuma_config(optarg)) { + rte_exit(EXIT_FAILURE, + "invalid ring-numa configuration\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "ring-numa-config")) - if (parse_ringnuma_config(optarg)) - rte_exit(EXIT_FAILURE, - "invalid ring-numa configuration\n"); - if (!strcmp(lgopts[opt_idx].name, "socket-num")) { - n = atoi(optarg); - if (!new_socket_id((uint8_t)n)) { - socket_num = (uint8_t)n; - } else { - print_invalid_socket_id_error(); - rte_exit(EXIT_FAILURE, - "Invalid socket id"); - } + if (!strcmp(lgopts[opt_idx].name, "socket-num")) { + n = atoi(optarg); + if (!new_socket_id((uint8_t)n)) { + socket_num = (uint8_t)n; + } else { + print_invalid_socket_id_error(); + rte_exit(EXIT_FAILURE, + "Invalid socket id"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "mbuf-size")) { - n = atoi(optarg); - if (n > 0 && n <= 0xFFFF) - mbuf_data_size = (uint16_t) n; - else - rte_exit(EXIT_FAILURE, - "mbuf-size should be > 0 and < 65536\n"); + } + if (!strcmp(lgopts[opt_idx].name, "mbuf-size")) { + n = atoi(optarg); + if (n > 0 && n <= 0xFFFF) + mbuf_data_size = (uint16_t) n; + else { + rte_exit(EXIT_FAILURE, + "mbuf-size should be > 0 and < 65536\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "total-num-mbufs")) { - n = atoi(optarg); - if (n > 1024) - param_total_num_mbufs = (unsigned)n; - else - rte_exit(EXIT_FAILURE, - "total-num-mbufs should be > 1024\n"); + } + if (!strcmp(lgopts[opt_idx].name, "total-num-mbufs")) { + n = atoi(optarg); + if (n > 1024) + param_total_num_mbufs = (unsigned int)n; + else { + rte_exit(EXIT_FAILURE, + "total-num-mbufs should be > 1024\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "max-pkt-len")) { - n = atoi(optarg); - if (n >= ETHER_MIN_LEN) { - rx_mode.max_rx_pkt_len = (uint32_t) n; - if (n > ETHER_MAX_LEN) - rx_mode.jumbo_frame = 1; - } else - rte_exit(EXIT_FAILURE, - "Invalid max-pkt-len=%d - should be > %d\n", - n, ETHER_MIN_LEN); + } + if (!strcmp(lgopts[opt_idx].name, "max-pkt-len")) { + n = atoi(optarg); + if (n >= ETHER_MIN_LEN) { + rx_mode.max_rx_pkt_len = (uint32_t) n; + if (n > ETHER_MAX_LEN) + rx_mode.jumbo_frame = 1; + } else { + rte_exit(EXIT_FAILURE, + "Invalid max-pkt-len=%d - should be > %d\n", + n, ETHER_MIN_LEN); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "pkt-filter-mode")) { - if (!strcmp(optarg, "signature")) - fdir_conf.mode = - RTE_FDIR_MODE_SIGNATURE; - else if (!strcmp(optarg, "perfect")) - fdir_conf.mode = RTE_FDIR_MODE_PERFECT; - else if (!strcmp(optarg, "perfect-mac-vlan")) - fdir_conf.mode = RTE_FDIR_MODE_PERFECT_MAC_VLAN; - else if (!strcmp(optarg, "perfect-tunnel")) - fdir_conf.mode = RTE_FDIR_MODE_PERFECT_TUNNEL; - else if (!strcmp(optarg, "none")) - fdir_conf.mode = RTE_FDIR_MODE_NONE; - else - rte_exit(EXIT_FAILURE, - "pkt-mode-invalid %s invalid - must be: " - "none, signature, perfect, perfect-mac-vlan" - " or perfect-tunnel\n", - optarg); + } + if (!strcmp(lgopts[opt_idx].name, "pkt-filter-mode")) { + if (!strcmp(optarg, "signature")) + fdir_conf.mode = + RTE_FDIR_MODE_SIGNATURE; + else if (!strcmp(optarg, "perfect")) + fdir_conf.mode = RTE_FDIR_MODE_PERFECT; + else if (!strcmp(optarg, "perfect-mac-vlan")) + fdir_conf.mode = RTE_FDIR_MODE_PERFECT_MAC_VLAN; + else if (!strcmp(optarg, "perfect-tunnel")) + fdir_conf.mode = RTE_FDIR_MODE_PERFECT_TUNNEL; + else if (!strcmp(optarg, "none")) + fdir_conf.mode = RTE_FDIR_MODE_NONE; + else { + rte_exit(EXIT_FAILURE, + "pkt-mode-invalid %s invalid - must be: " + "none, signature, perfect, perfect-mac-vlan" + " or perfect-tunnel\n", + optarg); + return -1; } - if (!strcmp(lgopts[opt_idx].name, - "pkt-filter-report-hash")) { - if (!strcmp(optarg, "none")) - fdir_conf.status = - RTE_FDIR_NO_REPORT_STATUS; - else if (!strcmp(optarg, "match")) - fdir_conf.status = - RTE_FDIR_REPORT_STATUS; - else if (!strcmp(optarg, "always")) - fdir_conf.status = - RTE_FDIR_REPORT_STATUS_ALWAYS; - else - rte_exit(EXIT_FAILURE, - "pkt-filter-report-hash %s invalid " - "- must be: none or match or always\n", - optarg); + } + if (!strcmp(lgopts[opt_idx].name, + "pkt-filter-report-hash")) { + if (!strcmp(optarg, "none")) + fdir_conf.status = + RTE_FDIR_NO_REPORT_STATUS; + else if (!strcmp(optarg, "match")) + fdir_conf.status = + RTE_FDIR_REPORT_STATUS; + else if (!strcmp(optarg, "always")) + fdir_conf.status = + RTE_FDIR_REPORT_STATUS_ALWAYS; + else { + rte_exit(EXIT_FAILURE, + "pkt-filter-report-hash %s invalid " + "- must be: none or match or always\n", + optarg); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "pkt-filter-size")) { - if (!strcmp(optarg, "64K")) - fdir_conf.pballoc = - RTE_FDIR_PBALLOC_64K; - else if (!strcmp(optarg, "128K")) - fdir_conf.pballoc = - RTE_FDIR_PBALLOC_128K; - else if (!strcmp(optarg, "256K")) - fdir_conf.pballoc = - RTE_FDIR_PBALLOC_256K; - else - rte_exit(EXIT_FAILURE, "pkt-filter-size %s invalid -" - " must be: 64K or 128K or 256K\n", - optarg); + } + if (!strcmp(lgopts[opt_idx].name, "pkt-filter-size")) { + if (!strcmp(optarg, "64K")) + fdir_conf.pballoc = + RTE_FDIR_PBALLOC_64K; + else if (!strcmp(optarg, "128K")) + fdir_conf.pballoc = + RTE_FDIR_PBALLOC_128K; + else if (!strcmp(optarg, "256K")) + fdir_conf.pballoc = + RTE_FDIR_PBALLOC_256K; + else { + rte_exit(EXIT_FAILURE, "pkt-filter-size %s invalid -" + " must be: 64K or 128K or 256K\n", + optarg); + return -1; } - if (!strcmp(lgopts[opt_idx].name, - "pkt-filter-drop-queue")) { - n = atoi(optarg); - if (n >= 0) - fdir_conf.drop_queue = (uint8_t) n; - else - rte_exit(EXIT_FAILURE, - "drop queue %d invalid - must" - "be >= 0 \n", n); + } + if (!strcmp(lgopts[opt_idx].name, + "pkt-filter-drop-queue")) { + n = atoi(optarg); + if (n >= 0) + fdir_conf.drop_queue = (uint8_t) n; + else { + rte_exit(EXIT_FAILURE, + "drop queue %d invalid - must " + "be >= 0\n", n); + return -1; } + } #ifdef RTE_LIBRTE_LATENCY_STATS - if (!strcmp(lgopts[opt_idx].name, - "latencystats")) { - n = atoi(optarg); - if (n >= 0) { - latencystats_lcore_id = (lcoreid_t) n; - latencystats_enabled = 1; - } else - rte_exit(EXIT_FAILURE, - "invalid lcore id %d for latencystats" - " must be >= 0\n", n); + if (!strcmp(lgopts[opt_idx].name, + "latencystats")) { + n = atoi(optarg); + if (n >= 0) { + latencystats_lcore_id = (lcoreid_t) n; + latencystats_enabled = 1; + } else { + rte_exit(EXIT_FAILURE, + "invalid lcore id %d for latencystats" + " must be >= 0\n", n); + return -1; } + } #endif #ifdef RTE_LIBRTE_BITRATE - if (!strcmp(lgopts[opt_idx].name, "bitrate-stats")) { - n = atoi(optarg); - if (n >= 0) { - bitrate_lcore_id = (lcoreid_t) n; - bitrate_enabled = 1; - } else - rte_exit(EXIT_FAILURE, - "invalid lcore id %d for bitrate stats" - " must be >= 0\n", n); + if (!strcmp(lgopts[opt_idx].name, "bitrate-stats")) { + n = atoi(optarg); + if (n >= 0) { + bitrate_lcore_id = (lcoreid_t) n; + bitrate_enabled = 1; + } else { + rte_exit(EXIT_FAILURE, + "invalid lcore id %d for bitrate stats" + " must be >= 0\n", n); + return -1; } + } #endif - if (!strcmp(lgopts[opt_idx].name, "disable-crc-strip")) - rx_mode.hw_strip_crc = 0; - if (!strcmp(lgopts[opt_idx].name, "enable-lro")) - rx_mode.enable_lro = 1; - if (!strcmp(lgopts[opt_idx].name, "enable-scatter")) - rx_mode.enable_scatter = 1; - if (!strcmp(lgopts[opt_idx].name, "enable-rx-cksum")) - rx_mode.hw_ip_checksum = 1; - - if (!strcmp(lgopts[opt_idx].name, "disable-hw-vlan")) { - rx_mode.hw_vlan_filter = 0; - rx_mode.hw_vlan_strip = 0; - rx_mode.hw_vlan_extend = 0; - } + if (!strcmp(lgopts[opt_idx].name, "disable-crc-strip")) + rx_mode.hw_strip_crc = 0; + if (!strcmp(lgopts[opt_idx].name, "enable-lro")) + rx_mode.enable_lro = 1; + if (!strcmp(lgopts[opt_idx].name, "enable-scatter")) + rx_mode.enable_scatter = 1; + if (!strcmp(lgopts[opt_idx].name, "enable-rx-cksum")) + rx_mode.hw_ip_checksum = 1; - if (!strcmp(lgopts[opt_idx].name, - "disable-hw-vlan-filter")) - rx_mode.hw_vlan_filter = 0; - - if (!strcmp(lgopts[opt_idx].name, - "disable-hw-vlan-strip")) - rx_mode.hw_vlan_strip = 0; - - if (!strcmp(lgopts[opt_idx].name, - "disable-hw-vlan-extend")) - rx_mode.hw_vlan_extend = 0; - - if (!strcmp(lgopts[opt_idx].name, "enable-drop-en")) - rx_drop_en = 1; - - if (!strcmp(lgopts[opt_idx].name, "disable-rss")) - rss_hf = 0; - if (!strcmp(lgopts[opt_idx].name, "port-topology")) { - if (!strcmp(optarg, "paired")) - port_topology = PORT_TOPOLOGY_PAIRED; - else if (!strcmp(optarg, "chained")) - port_topology = PORT_TOPOLOGY_CHAINED; - else if (!strcmp(optarg, "loop")) - port_topology = PORT_TOPOLOGY_LOOP; - else - rte_exit(EXIT_FAILURE, "port-topology %s invalid -" - " must be: paired or chained \n", - optarg); + if (!strcmp(lgopts[opt_idx].name, "disable-hw-vlan")) { + rx_mode.hw_vlan_filter = 0; + rx_mode.hw_vlan_strip = 0; + rx_mode.hw_vlan_extend = 0; + } + + if (!strcmp(lgopts[opt_idx].name, + "disable-hw-vlan-filter")) + rx_mode.hw_vlan_filter = 0; + + if (!strcmp(lgopts[opt_idx].name, + "disable-hw-vlan-strip")) + rx_mode.hw_vlan_strip = 0; + + if (!strcmp(lgopts[opt_idx].name, + "disable-hw-vlan-extend")) + rx_mode.hw_vlan_extend = 0; + + if (!strcmp(lgopts[opt_idx].name, "enable-drop-en")) + rx_drop_en = 1; + + if (!strcmp(lgopts[opt_idx].name, "disable-rss")) + rss_hf = 0; + if (!strcmp(lgopts[opt_idx].name, "port-topology")) { + if (!strcmp(optarg, "paired")) + port_topology = PORT_TOPOLOGY_PAIRED; + else if (!strcmp(optarg, "chained")) + port_topology = PORT_TOPOLOGY_CHAINED; + else if (!strcmp(optarg, "loop")) + port_topology = PORT_TOPOLOGY_LOOP; + else { + rte_exit(EXIT_FAILURE, "port-topology %s invalid -" + " must be: paired or chained\n", + optarg); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "forward-mode")) - set_pkt_forwarding_mode(optarg); - if (!strcmp(lgopts[opt_idx].name, "rss-ip")) - rss_hf = ETH_RSS_IP; - if (!strcmp(lgopts[opt_idx].name, "rss-udp")) - rss_hf = ETH_RSS_UDP; - if (!strcmp(lgopts[opt_idx].name, "rxq")) { - n = atoi(optarg); - if (n >= 0 && n <= (int) MAX_QUEUE_ID) - nb_rxq = (queueid_t) n; - else - rte_exit(EXIT_FAILURE, "rxq %d invalid - must be" - " >= 0 && <= %d\n", n, - (int) MAX_QUEUE_ID); + } + if (!strcmp(lgopts[opt_idx].name, "forward-mode")) + set_pkt_forwarding_mode(optarg); + if (!strcmp(lgopts[opt_idx].name, "rss-ip")) + rss_hf = ETH_RSS_IP; + if (!strcmp(lgopts[opt_idx].name, "rss-udp")) + rss_hf = ETH_RSS_UDP; + if (!strcmp(lgopts[opt_idx].name, "rxq")) { + n = atoi(optarg); + if (n >= 0 && n <= (int) MAX_QUEUE_ID) + nb_rxq = (queueid_t) n; + else { + rte_exit(EXIT_FAILURE, "rxq %d invalid - must be" + " >= 0 && <= %d\n", n, + (int) MAX_QUEUE_ID); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txq")) { - n = atoi(optarg); - if (n >= 0 && n <= (int) MAX_QUEUE_ID) - nb_txq = (queueid_t) n; - else - rte_exit(EXIT_FAILURE, "txq %d invalid - must be" - " >= 0 && <= %d\n", n, - (int) MAX_QUEUE_ID); + } + if (!strcmp(lgopts[opt_idx].name, "txq")) { + n = atoi(optarg); + if (n >= 0 && n <= (int) MAX_QUEUE_ID) + nb_txq = (queueid_t) n; + else { + rte_exit(EXIT_FAILURE, "txq %d invalid - must be" + " >= 0 && <= %d\n", n, + (int) MAX_QUEUE_ID); + return -1; } - if (!nb_rxq && !nb_txq) { - rte_exit(EXIT_FAILURE, "Either rx or tx queues should " - "be non-zero\n"); + } + if (!nb_rxq && !nb_txq) { + rte_exit(EXIT_FAILURE, "Either rx or tx queues should " + "be non-zero\n"); + return -1; + } + if (!strcmp(lgopts[opt_idx].name, "burst")) { + n = atoi(optarg); + if ((n >= 1) && (n <= MAX_PKT_BURST)) + nb_pkt_per_burst = (uint16_t) n; + else { + rte_exit(EXIT_FAILURE, + "burst must >= 1 and <= %d]", + MAX_PKT_BURST); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "burst")) { - n = atoi(optarg); - if ((n >= 1) && (n <= MAX_PKT_BURST)) - nb_pkt_per_burst = (uint16_t) n; - else - rte_exit(EXIT_FAILURE, - "burst must >= 1 and <= %d]", - MAX_PKT_BURST); + } + if (!strcmp(lgopts[opt_idx].name, "mbcache")) { + n = atoi(optarg); + if ((n >= 0) && + (n <= RTE_MEMPOOL_CACHE_MAX_SIZE)) + mb_mempool_cache = (uint16_t) n; + else { + rte_exit(EXIT_FAILURE, + "mbcache must be >= 0 and <= %d\n", + RTE_MEMPOOL_CACHE_MAX_SIZE); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "mbcache")) { - n = atoi(optarg); - if ((n >= 0) && - (n <= RTE_MEMPOOL_CACHE_MAX_SIZE)) - mb_mempool_cache = (uint16_t) n; - else - rte_exit(EXIT_FAILURE, - "mbcache must be >= 0 and <= %d\n", - RTE_MEMPOOL_CACHE_MAX_SIZE); + } + if (!strcmp(lgopts[opt_idx].name, "txfreet")) { + n = atoi(optarg); + if (n >= 0) + tx_free_thresh = (int16_t)n; + else { + rte_exit(EXIT_FAILURE, "txfreet must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txfreet")) { - n = atoi(optarg); - if (n >= 0) - tx_free_thresh = (int16_t)n; - else - rte_exit(EXIT_FAILURE, "txfreet must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txrst")) { + n = atoi(optarg); + if (n >= 0) + tx_rs_thresh = (int16_t)n; + else { + rte_exit(EXIT_FAILURE, "txrst must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txrst")) { - n = atoi(optarg); - if (n >= 0) - tx_rs_thresh = (int16_t)n; - else - rte_exit(EXIT_FAILURE, "txrst must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txqflags")) { + char *end = NULL; + + n = strtoul(optarg, &end, 16); + if (n >= 0) + txq_flags = (int32_t)n; + else { + rte_exit(EXIT_FAILURE, + "txqflags must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txqflags")) { - char *end = NULL; - n = strtoul(optarg, &end, 16); - if (n >= 0) - txq_flags = (int32_t)n; - else + } + if (!strcmp(lgopts[opt_idx].name, "rxd")) { + n = atoi(optarg); + if (n > 0) { + if (rx_free_thresh >= n) rte_exit(EXIT_FAILURE, - "txqflags must be >= 0\n"); + "rxd must be > " + "rx_free_thresh(%d)\n", + (int)rx_free_thresh); + else + nb_rxd = (uint16_t) n; + } else { + rte_exit(EXIT_FAILURE, + "rxd(%d) invalid - must be > 0\n", + n); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxd")) { - n = atoi(optarg); - if (n > 0) { - if (rx_free_thresh >= n) - rte_exit(EXIT_FAILURE, - "rxd must be > " - "rx_free_thresh(%d)\n", - (int)rx_free_thresh); - else - nb_rxd = (uint16_t) n; - } else - rte_exit(EXIT_FAILURE, - "rxd(%d) invalid - must be > 0\n", - n); + } + if (!strcmp(lgopts[opt_idx].name, "txd")) { + n = atoi(optarg); + if (n > 0) + nb_txd = (uint16_t) n; + else { + rte_exit(EXIT_FAILURE, "txd must be in > 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txd")) { - n = atoi(optarg); - if (n > 0) - nb_txd = (uint16_t) n; - else - rte_exit(EXIT_FAILURE, "txd must be in > 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txpt")) { + n = atoi(optarg); + if (n >= 0) + tx_pthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "txpt must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txpt")) { - n = atoi(optarg); - if (n >= 0) - tx_pthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "txpt must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txht")) { + n = atoi(optarg); + if (n >= 0) + tx_hthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "txht must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txht")) { - n = atoi(optarg); - if (n >= 0) - tx_hthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "txht must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "txwt")) { + n = atoi(optarg); + if (n >= 0) + tx_wthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "txwt must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txwt")) { - n = atoi(optarg); - if (n >= 0) - tx_wthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "txwt must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "rxpt")) { + n = atoi(optarg); + if (n >= 0) + rx_pthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "rxpt must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxpt")) { - n = atoi(optarg); - if (n >= 0) - rx_pthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "rxpt must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "rxht")) { + n = atoi(optarg); + if (n >= 0) + rx_hthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "rxht must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxht")) { - n = atoi(optarg); - if (n >= 0) - rx_hthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "rxht must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "rxwt")) { + n = atoi(optarg); + if (n >= 0) + rx_wthresh = (int8_t)n; + else { + rte_exit(EXIT_FAILURE, "rxwt must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxwt")) { - n = atoi(optarg); - if (n >= 0) - rx_wthresh = (int8_t)n; - else - rte_exit(EXIT_FAILURE, "rxwt must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "rxfreet")) { + n = atoi(optarg); + if (n >= 0) + rx_free_thresh = (int16_t)n; + else { + rte_exit(EXIT_FAILURE, "rxfreet must be >= 0\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "rxfreet")) { - n = atoi(optarg); - if (n >= 0) - rx_free_thresh = (int16_t)n; - else - rte_exit(EXIT_FAILURE, "rxfreet must be >= 0\n"); + } + if (!strcmp(lgopts[opt_idx].name, "tx-queue-stats-mapping")) { + if (parse_queue_stats_mapping_config(optarg, TX)) { + rte_exit(EXIT_FAILURE, + "invalid TX queue statistics mapping config entered\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "tx-queue-stats-mapping")) { - if (parse_queue_stats_mapping_config(optarg, TX)) { - rte_exit(EXIT_FAILURE, - "invalid TX queue statistics mapping config entered\n"); - } + } + if (!strcmp(lgopts[opt_idx].name, "rx-queue-stats-mapping")) { + if (parse_queue_stats_mapping_config(optarg, RX)) { + rte_exit(EXIT_FAILURE, + "invalid RX queue statistics mapping config entered\n"); } - if (!strcmp(lgopts[opt_idx].name, "rx-queue-stats-mapping")) { - if (parse_queue_stats_mapping_config(optarg, RX)) { - rte_exit(EXIT_FAILURE, - "invalid RX queue statistics mapping config entered\n"); - } + } + if (!strcmp(lgopts[opt_idx].name, "txpkts")) { + unsigned int seg_lengths[RTE_MAX_SEGS_PER_PKT]; + unsigned int nb_segs; + + nb_segs = parse_item_list(optarg, "txpkt segments", + RTE_MAX_SEGS_PER_PKT, seg_lengths, 0); + if (nb_segs > 0) + set_tx_pkt_segments(seg_lengths, nb_segs); + else { + rte_exit(EXIT_FAILURE, "bad txpkts\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "txpkts")) { - unsigned seg_lengths[RTE_MAX_SEGS_PER_PKT]; - unsigned int nb_segs; - - nb_segs = parse_item_list(optarg, "txpkt segments", - RTE_MAX_SEGS_PER_PKT, seg_lengths, 0); - if (nb_segs > 0) - set_tx_pkt_segments(seg_lengths, nb_segs); - else - rte_exit(EXIT_FAILURE, "bad txpkts\n"); + } + if (!strcmp(lgopts[opt_idx].name, "no-flush-rx")) + no_flush_rx = 1; + if (!strcmp(lgopts[opt_idx].name, "disable-link-check")) + no_link_check = 1; + if (!strcmp(lgopts[opt_idx].name, "no-lsc-interrupt")) + lsc_interrupt = 0; + if (!strcmp(lgopts[opt_idx].name, "no-rmv-interrupt")) + rmv_interrupt = 0; + if (!strcmp(lgopts[opt_idx].name, "print-event")) + if (parse_event_printing_config(optarg, 1)) { + rte_exit(EXIT_FAILURE, + "invalid print-event argument\n"); + return -1; + } + if (!strcmp(lgopts[opt_idx].name, "mask-event")) + if (parse_event_printing_config(optarg, 0)) { + rte_exit(EXIT_FAILURE, + "invalid mask-event argument\n"); + return -1; } - if (!strcmp(lgopts[opt_idx].name, "no-flush-rx")) - no_flush_rx = 1; - if (!strcmp(lgopts[opt_idx].name, "disable-link-check")) - no_link_check = 1; - if (!strcmp(lgopts[opt_idx].name, "no-lsc-interrupt")) - lsc_interrupt = 0; - if (!strcmp(lgopts[opt_idx].name, "no-rmv-interrupt")) - rmv_interrupt = 0; - if (!strcmp(lgopts[opt_idx].name, "print-event")) - if (parse_event_printing_config(optarg, 1)) { - rte_exit(EXIT_FAILURE, - "invalid print-event argument\n"); - } - if (!strcmp(lgopts[opt_idx].name, "mask-event")) - if (parse_event_printing_config(optarg, 0)) { - rte_exit(EXIT_FAILURE, - "invalid mask-event argument\n"); - } - break; - case 'h': - usage(argv[0]); - rte_exit(EXIT_SUCCESS, "Displayed help\n"); - break; - default: - usage(argv[0]); - rte_exit(EXIT_FAILURE, - "Command line is incomplete or incorrect\n"); + break; + case 'h': + usage(prgname); + rte_exit(EXIT_SUCCESS, "Displayed help\n"); + return -1; + case 1: + /* does nothing*/ + break; + default: + usage(prgname); + rte_exit(EXIT_FAILURE, + "Command line is incomplete or incorrect\n"); + return -1; + } + return 0; +} + +void +launch_args_parse(int argc, char **argv) +{ + int opt; + char **argvopt; + int opt_idx; + + argvopt = argv; + + while ((opt = getopt_long(argc, argvopt, SHORTOPTS "ah", + lgopts, &opt_idx)) != EOF) { + parse_option(opt, optarg, opt_idx, argv[0]); + } +} + +#ifdef RTE_LIBRTE_CFGFILE_DEBUG +#define max_nb_sections 100 +static void print_cfg(struct rte_cfgfile *cfg) +{ + int i, num_sections, num_entries, j; + + printf("-------------------------\n"); + printf("SECTIONS:\n\n"); + + char *sections[max_nb_sections+1]; + + for (i = 0; i < max_nb_sections; i++) + sections[i] = malloc(sizeof(sections[0]) * 64); + sections[i] = 0; + + num_sections = rte_cfgfile_sections(cfg, sections, max_nb_sections); + + for (i = 0; i < num_sections; i++) { + printf("************************\n"); + printf("%s:\n", sections[i]); + num_entries = rte_cfgfile_section_num_entries(cfg, sections[i]); + + struct rte_cfgfile_entry entries[num_entries]; + + rte_cfgfile_section_entries(cfg, sections[i], + entries, num_entries); + for (j = 0; j < num_entries; j++) + printf("%s -> %s\n", entries[j].name, + entries[j].value); + } + printf("************************\n\n"); + printf("-------------------------\n\n"); + + i = 0; + while (sections[i]) { + free(sections[i]); + sections[i] = 0; + i++; + } +} +#endif + +#ifdef RTE_LIBRTE_CFGFILE +static void +non_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; lgopts[i].name != NULL; i++) { + if (strcmp(str, lgopts[i].name) == 0) { + *opt = lgopts[i].val; + *option_index = i; break; } } } +#endif + +#ifdef RTE_LIBRTE_CFGFILE +#define APP_SECTION "TEST-PMD" +int non_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; + } + +#ifdef RTE_LIBRTE_CFGFILE_DEBUG + print_cfg(cfg); +#endif + + n_entries = rte_cfgfile_section_num_entries(cfg, APP_SECTION); + + if (n_entries < 1) { + printf("No %s section entries " + "in cfgfile object\n", APP_SECTION); + return -1; + } + + struct rte_cfgfile_entry entries[n_entries]; + + if (n_entries != + rte_cfgfile_section_entries(cfg, APP_SECTION, entries, + n_entries)) { + rte_exit(EXIT_FAILURE, "Unexpected fault"); + return -1; + } + + for (i = 0; i < n_entries; i++) { + non_eal_getopt(entries[i].name, &opt, &option_index); + + parse_option(opt, entries[i].value, + option_index, prgname); + } + return 0; +} +#endif diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index b29328a..cd69a6b 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -90,6 +90,9 @@ #ifdef RTE_LIBRTE_LATENCY_STATS #include <rte_latencystats.h> #endif +#ifdef RTE_LIBRTE_CFGFILE +#include <rte_cfgfile.h> +#endif #include "testpmd.h" @@ -2251,15 +2254,66 @@ signal_handler(int signum) } } +#ifdef RTE_LIBRTE_CFGFILE +/* Load config file path from command line */ +static char * +cfgfile_load_path(int argc, char **argv) +{ + int i; + + for (i = 0; i < argc; i++) { + if (!strcmp("--cfgfile-path", argv[i])) { + if (argv[i+1] && argv[i+1][0] != '-') + return strdup(argv[i+1]); + } else if (!strncmp("--cfgfile-path=", argv[i], 15)) { + char *ptr = argv[i]; + + ptr += 15; + if (strlen(ptr)) + return strdup(ptr); + } + } + return NULL; +} +#endif + +#define APP_NAME "TEST-PMD" int main(int argc, char** argv) { int diag; uint8_t port_id; +#ifdef RTE_LIBRTE_CFGFILE + struct rte_cfgfile *cfg = NULL; + char *config_file = NULL; +#endif signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); +#ifdef RTE_LIBRTE_CFGFILE + /* load --cfgfile-path argument from argv */ + config_file = cfgfile_load_path(argc, argv); + + if (config_file) { + printf("Info: found cfgfile-path \"%s\"\n", config_file); + } else { + printf("Info: not found cfgfile-path parameter " + "(searching for cfgfile " + "in default directory)\n"); + config_file = strdup("config.ini"); + } + + cfg = rte_cfgfile_load(config_file, CFG_FLAG_EMPTY_VALUES); + + if (cfg == NULL) { + printf("Info: Valid cfgfile not found\n"); + cfg = rte_cfgfile_create(CFG_FLAG_EMPTY_VALUES); + } + diag = rte_eal_configure(cfg, argv[0]); + if (diag < 0) + rte_panic("Cannot init EAL\n"); +#endif diag = rte_eal_init(argc, argv); if (diag < 0) rte_panic("Cannot init EAL\n"); @@ -2289,6 +2343,18 @@ main(int argc, char** argv) latencystats_enabled = 0; #endif +#ifdef RTE_LIBRTE_CFGFILE + if (argc > 1) { + non_eal_configure(cfg, argv[0]); + rte_cfgfile_close(cfg); + cfg = 0; + + if (config_file) { + free(config_file); + config_file = 0; + } + } +#endif argc -= diag; argv += diag; if (argc > 1) @@ -2360,6 +2426,5 @@ main(int argc, char** argv) if (rc < 0) return 1; } - return 0; } diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index 364502d..93eebbf 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -499,7 +499,7 @@ port_pci_reg_write(struct rte_port *port, uint32_t reg_off, uint32_t reg_v) unsigned int parse_item_list(char* str, const char* item_name, unsigned int max_items, unsigned int *parsed_items, int check_unique_values); -void launch_args_parse(int argc, char** argv); +void launch_args_parse(int argc, char **argv); void cmdline_read_from_file(const char *filename); void prompt(void); void prompt_exit(void); @@ -641,6 +641,7 @@ enum print_warning { }; int port_id_is_invalid(portid_t port_id, enum print_warning warning); int new_socket_id(unsigned int socket_id); +int non_eal_configure(struct rte_cfgfile *cfg, char *prgname); /* * Work-around of a compilation error with ICC on invocations of the -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH v2 7/7] app/testpmd: add parse arguments from JSON config file 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 0/7] Add support for using a config file for DPDK Jacek Piasecki ` (5 preceding siblings ...) 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 6/7] app/testpmd: changed example to parse options from cfg file Jacek Piasecki @ 2017-06-26 10:59 ` Jacek Piasecki 6 siblings, 0 replies; 70+ messages in thread From: Jacek Piasecki @ 2017-06-26 10:59 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, Kuba Kozak From: Kuba Kozak <kubax.kozak@intel.com> This patch shows usage of Jansson library to parse application arguments from JSON config file. https://github.com/akheron/jansson If a --cfgfile-path <path> option is passed into commandline non EAL section, then the disired JSON file is loaded and used by app. In case when JSON doesn't exist an INI file is loaded. The INI file can be passed also from --cfgfile-path option. 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. Signed-off-by: Kuba Kozak <kubax.kozak@intel.com> Suggested-by: Bruce Richardson <bruce.richardson@intel.com> --- app/test-pmd/Makefile | 6 ++++ app/test-pmd/config.json | 33 +++++++++++++++++ app/test-pmd/testpmd.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++- config/common_base | 5 +++ 4 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 app/test-pmd/config.json diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile index c36be19..a1c84cc 100644 --- a/app/test-pmd/Makefile +++ b/app/test-pmd/Makefile @@ -83,6 +83,12 @@ endif endif +ifeq ($(CONFIG_RTE_JSON_SUPPORT),y) +ifeq ($(CONFIG_RTE_LIBRTE_CFGFILE),y) +LDLIBS += -ljansson +endif +endif + CFLAGS_cmdline.o := -D_GNU_SOURCE include $(RTE_SDK)/mk/rte.app.mk diff --git a/app/test-pmd/config.json b/app/test-pmd/config.json new file mode 100644 index 0000000..4589dbc --- /dev/null +++ b/app/test-pmd/config.json @@ -0,0 +1,33 @@ +{ + "DPDK": + { + "v": "", + "l": "0-4", + "n": "4", + "master-lcore": "0", + "proc-type": "primary" + }, + "TEST-PMD": + { + "i": "", + "portmask": "0xff", + "nb-cores": "4", + "port-topology": "paired" + }, + "DPDK.vdev0": + { + "net_ring0": "" + }, + "DPDK.vdev1": + { + "net_ring1": "" + }, + "DPDK.vdev2": + { + "net_ring2": "" + }, + "DPDK.vdev3": + { + "net_ring3": "" + } +} diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index cd69a6b..9ce1bbe 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -46,6 +46,10 @@ #include <stdint.h> #include <unistd.h> + +#ifdef RTE_JSON_SUPPORT +#include <jansson.h> +#endif #include <inttypes.h> #include <rte_common.h> @@ -2275,6 +2279,87 @@ cfgfile_load_path(int argc, char **argv) } return NULL; } + +#ifdef RTE_JSON_SUPPORT +/* + * Decoding JSON structure to rte_cfgfile structure. + * Returns handler to cfgfile object, NULL if error. + */ +static struct +rte_cfgfile *l3fwd_json_to_cfg(json_t *json, int flags) +{ + if (!json) { + printf("Error: JSON structure is NULL, nothing to parse\n"); + return NULL; + } + /* create an empty instance of cfgfile structure */ + struct rte_cfgfile *cfgfile = rte_cfgfile_create(flags); + + if (!cfgfile) + return NULL; + + const char *section; + json_t *entry; + + /* set pointer to first section */ + void *iter_section = json_object_iter(json); + + while (iter_section) { + + section = json_object_iter_key(iter_section); + entry = json_object_iter_value(iter_section); + + /* add parsed section name of current section to cfgfile */ + rte_cfgfile_add_section(cfgfile, section); + + /* set pointer to first entry */ + void *iter_entry = json_object_iter(entry); + + while (iter_entry) { + + const char *key; + const char *value; + + key = json_object_iter_key(iter_entry); + value = json_string_value( + json_object_iter_value(iter_entry)); + + /* add parsed key and value of current entry */ + /* to cfgfile */ + rte_cfgfile_add_entry(cfgfile, section, key, value); + + /* pointer to next entry */ + iter_entry = json_object_iter_next(entry, iter_entry); + } + /* pointer to next section */ + iter_section = json_object_iter_next(json, iter_section); + } + return cfgfile; +} + +/* + * Check presence and load JSON file to rte_cfgfile structure. + * Returns handler to cfgfile object, NULL if error. + */ +static struct +rte_cfgfile *l3fwd_load_json_to_cfg(const char *path) +{ + struct rte_cfgfile *cfgfile = NULL; + /* check if config file exist */ + if (access(path, F_OK) != -1) { + /* parse JSON file */ + json_error_t error; + json_t *json = json_load_file(path, 0, &error); + + if (json) + cfgfile = l3fwd_json_to_cfg(json, 0); + else + fprintf(stderr, "JSON error on line %d: %s\n", + error.line, error.text); + } + return cfgfile; +} +#endif #endif #define APP_NAME "TEST-PMD" @@ -2303,9 +2388,16 @@ main(int argc, char** argv) "in default directory)\n"); config_file = strdup("config.ini"); } - +#ifndef RTE_JSON_SUPPORT cfg = rte_cfgfile_load(config_file, CFG_FLAG_EMPTY_VALUES); +#endif +#ifdef RTE_JSON_SUPPORT + if (strstr(config_file, ".ini")) + cfg = rte_cfgfile_load(config_file, CFG_FLAG_EMPTY_VALUES); + else if (strstr(config_file, ".json")) + cfg = l3fwd_load_json_to_cfg(config_file); +#endif if (cfg == NULL) { printf("Info: Valid cfgfile not found\n"); cfg = rte_cfgfile_create(CFG_FLAG_EMPTY_VALUES); diff --git a/config/common_base b/config/common_base index c1d0e69..0eed278 100644 --- a/config/common_base +++ b/config/common_base @@ -734,3 +734,8 @@ CONFIG_RTE_TEST_PMD_RECORD_BURST_STATS=n # Compile the crypto performance application # CONFIG_RTE_APP_CRYPTO_PERF=y + +# +# Compile JSON support +# +CONFIG_RTE_JSON_SUPPORT=n -- 2.7.4 ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH 2/3] eal: add functions parsing EAL arguments 2017-05-30 8:30 [dpdk-dev] [PATCH 0/3] Add support for using a config file for DPDK Jacek Piasecki 2017-05-30 8:30 ` [dpdk-dev] [PATCH 1/3] cfgfile: add new API functions Jacek Piasecki @ 2017-05-30 8:30 ` Jacek Piasecki 2017-05-31 15:46 ` Bruce Richardson 2017-05-30 8:30 ` [dpdk-dev] [PATCH 3/3] app/testpmd: changed example to parse options from cfg file Jacek Piasecki 2 siblings, 1 reply; 70+ messages in thread From: Jacek Piasecki @ 2017-05-30 8:30 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, michalx.k.jastrzebski, Kuba Kozak From: Kuba Kozak <kubax.kozak@intel.com> added function rte_eal_configure which translate options from config file into argc, **argv form. changed function rte_eal_init to meld argc, argv** options from config file with these from command line and then parse as before Signed-off-by: Kuba Kozak <kubax.kozak@intel.com> Suggested-by: Bruce Richardson <bruce.richardson@intel.com> --- lib/Makefile | 6 +- lib/librte_cfgfile/rte_cfgfile.h | 2 + lib/librte_eal/bsdapp/eal/Makefile | 4 + lib/librte_eal/bsdapp/eal/eal.c | 128 ++++++++++++++++++++++- lib/librte_eal/bsdapp/eal/rte_eal_version.map | 5 + lib/librte_eal/common/include/rte_eal.h | 6 ++ lib/librte_eal/linuxapp/eal/Makefile | 3 + lib/librte_eal/linuxapp/eal/eal.c | 108 ++++++++++++++++++- lib/librte_eal/linuxapp/eal/rte_eal_version.map | 4 + mk/rte.app.mk | 2 +- 10 files changed, 261 insertions(+), 7 deletions(-) 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_cfgfile/rte_cfgfile.h b/lib/librte_cfgfile/rte_cfgfile.h index 902ec69..8808aa7 100644 --- a/lib/librte_cfgfile/rte_cfgfile.h +++ b/lib/librte_cfgfile/rte_cfgfile.h @@ -49,6 +49,8 @@ * ***/ +struct rte_cfgfile; /* forward declaration of struct */ + #ifndef CFG_NAME_LEN #define CFG_NAME_LEN 64 #endif 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..e5e11c8 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" @@ -92,6 +93,12 @@ * duration of the program, as we hold a write lock on it in the primary proc */ static int mem_cfg_fd = -1; +static int cfg_argc; +#ifdef RTE_LIBRTE_CFGFILE +static char **cfg_argv; +#endif + + static struct flock wr_lock = { .l_type = F_WRLCK, .l_whence = SEEK_SET, @@ -492,10 +499,28 @@ static void rte_eal_init_alert(const char *msg) RTE_LOG(ERR, EAL, "%s\n", msg); } +#ifdef RTE_LIBRTE_CFGFILE +static void +free_pointer_array(char **pkt) +{ + int i = 0; + + if (pkt) { + while (pkt[i]) { + free(pkt[i]); + pkt[i++] = 0; + } + free(pkt); + pkt = 0; + } +} +#endif + /* Launch threads, called at application init(). */ int rte_eal_init(int argc, char **argv) { + int combined_argc; /* combine cfg and param versions */ int i, fctret, ret; pthread_t thread_id; static rte_atomic32_t run_once = RTE_ATOMIC32_INIT(0); @@ -519,8 +544,25 @@ static void rte_eal_init_alert(const char *msg) eal_reset_internal_config(&internal_config); +#ifdef RTE_LIBRTE_CFGFILE + combined_argc = argc + cfg_argc; + char *combined_argv[combined_argc + 1]; + + combined_argv[0] = argv[0]; + for (i = 0; i < cfg_argc; i++) + combined_argv[i + 1] = cfg_argv[i]; + for (i = 1; i < argc; i++) + combined_argv[i + cfg_argc] = argv[i]; + combined_argv[combined_argc] = NULL; +#else + combined_argc = argc; + char **combined_argv; + + combined_argv = argv; +#endif + /* set log level as early as possible */ - eal_log_level_parse(argc, argv); + eal_log_level_parse(combined_argc, combined_argv); if (rte_eal_cpu_init() < 0) { rte_eal_init_alert("Cannot detect lcores."); @@ -528,13 +570,21 @@ static void rte_eal_init_alert(const char *msg) return -1; } - fctret = eal_parse_args(argc, argv); + fctret = eal_parse_args(combined_argc, combined_argv); if (fctret < 0) { rte_eal_init_alert("Invalid 'command line' arguments."); rte_errno = EINVAL; rte_atomic32_clear(&run_once); return -1; } + fctret -= cfg_argc; + +#ifdef RTE_LIBRTE_CFGFILE + free_pointer_array(cfg_argv); +#endif + + if (fctret) + argv[fctret] = argv[0]; if (internal_config.no_hugetlbfs == 0 && internal_config.process_type != RTE_PROC_SECONDARY && @@ -677,3 +727,77 @@ enum rte_proc_type_t { return rte_config.process_type; } + +#ifdef RTE_LIBRTE_CFGFILE + +static char *strdup_with_prefix(const char *p) +{ + char *np; + + if (strlen(p) > 1) { + np = (char *)malloc(strlen(p)+3); + if (np) + strcpy(np, "--"); + } else { + np = (char *)malloc(strlen(p)+2); + if (np) + strcpy(np, "-"); + } + return np ? strcat(np, p) : np; +} + +int +rte_eal_configure(struct rte_cfgfile *cfg) +{ + int i, num_entries; + + if (cfg == NULL) { + rte_errno = -EINVAL; + return -1; + } + + if (!rte_cfgfile_has_section(cfg, "DPDK")) + return 0; + + num_entries = rte_cfgfile_section_num_entries(cfg, "DPDK"); + if (num_entries <= 0) + return 0; + + cfg_argv = malloc((num_entries * 2 + 1) * sizeof(cfg_argv[0])); + if (cfg_argv == NULL) { + rte_errno = -ENOMEM; + return -1; + } + + struct rte_cfgfile_entry cfg_entries[num_entries]; + + rte_cfgfile_section_entries(cfg, "DPDK", cfg_entries, num_entries); + + cfg_argc = 0; + for (i = 0; i < num_entries; i++) { + cfg_argv[cfg_argc] = strdup_with_prefix(cfg_entries[i].name); + if (!(cfg_argv[cfg_argc])) + goto allocation_error; + cfg_argc++; + if (strlen(cfg_entries[i].value)) { + cfg_argv[cfg_argc] = strdup(cfg_entries[i].value); + if (!(cfg_argv[cfg_argc])) + goto allocation_error; + cfg_argc++; + } + } + /* set last pointer to 0 */ + cfg_argv[cfg_argc] = 0; + + return cfg_argc; + +allocation_error: + rte_eal_init_alert("Cannot allocate memory in rte_eal_configure()\n"); + rte_errno = ENOMEM; + for (i = 1; i < cfg_argc; i++) { + free(cfg_argv[i]); + cfg_argv[i] = 0; + } + return -1; +} +#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..a9b637b 100644 --- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map +++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map @@ -193,3 +193,8 @@ 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/include/rte_eal.h b/lib/librte_eal/common/include/rte_eal.h index abf020b..6a0b18b 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,10 @@ struct rte_config { */ int rte_eal_init(int argc, char **argv); +#ifdef RTE_LIBRTE_CFGFILE +int rte_eal_configure(struct rte_cfgfile *cfg); +#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..b4078b5 100644 --- a/lib/librte_eal/linuxapp/eal/eal.c +++ b/lib/librte_eal/linuxapp/eal/eal.c @@ -78,6 +78,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" @@ -122,6 +123,12 @@ /* used by rte_rdtsc() */ int rte_cycles_vmware_tsc_map; + +static int cfg_argc; +#ifdef RTE_LIBRTE_CFGFILE +static char **cfg_argv; +#endif + /* Return a pointer to the configuration structure */ struct rte_config * rte_eal_get_configuration(void) @@ -745,10 +752,12 @@ static void rte_eal_init_alert(const char *msg) RTE_LOG(ERR, EAL, "%s\n", msg); } + /* Launch threads, called at application init(). */ int rte_eal_init(int argc, char **argv) { + int combined_argc; /* combine cfg and param versions */ int i, fctret, ret; pthread_t thread_id; static rte_atomic32_t run_once = RTE_ATOMIC32_INIT(0); @@ -776,8 +785,25 @@ static void rte_eal_init_alert(const char *msg) eal_reset_internal_config(&internal_config); +#ifdef RTE_LIBRTE_CFGFILE + combined_argc = argc + cfg_argc; + char *combined_argv[combined_argc + 1]; + + combined_argv[0] = argv[0]; + for (i = 0; i < cfg_argc; i++) + combined_argv[i + 1] = cfg_argv[i]; + for (i = 1; i < argc; i++) + combined_argv[i + cfg_argc] = argv[i]; + combined_argv[combined_argc] = NULL; +#else + combined_argc = argc; + char **combined_argv; + + combined_argv = argv; +#endif + /* set log level as early as possible */ - eal_log_level_parse(argc, argv); + eal_log_level_parse(combined_argc, combined_argv); if (rte_eal_cpu_init() < 0) { rte_eal_init_alert("Cannot detect lcores."); @@ -785,13 +811,17 @@ static void rte_eal_init_alert(const char *msg) return -1; } - fctret = eal_parse_args(argc, argv); + fctret = eal_parse_args(combined_argc, combined_argv); if (fctret < 0) { rte_eal_init_alert("Invalid 'command line' arguments."); rte_errno = EINVAL; rte_atomic32_clear(&run_once); return -1; } + fctret -= cfg_argc; + + if (fctret) + argv[fctret] = argv[0]; if (internal_config.no_hugetlbfs == 0 && internal_config.process_type != RTE_PROC_SECONDARY && @@ -995,3 +1025,77 @@ int rte_eal_has_hugepages(void) /* Module has been found */ return 1; } + +#ifdef RTE_LIBRTE_CFGFILE + +static char *strdup_with_prefix(const char *p) +{ + char *np; + + if (strlen(p) > 1) { + np = (char *)malloc(strlen(p)+3); + if (np) + strcpy(np, "--"); + } else { + np = (char *)malloc(strlen(p)+2); + if (np) + strcpy(np, "-"); + } + return np ? strcat(np, p) : np; +} + +int +rte_eal_configure(struct rte_cfgfile *cfg) +{ + int i, num_entries; + + if (cfg == NULL) { + rte_errno = -EINVAL; + return -1; + } + + if (!rte_cfgfile_has_section(cfg, "DPDK")) + return 0; + + num_entries = rte_cfgfile_section_num_entries(cfg, "DPDK"); + if (num_entries <= 0) + return 0; + + cfg_argv = malloc((num_entries * 2 + 1) * sizeof(cfg_argv[0])); + if (cfg_argv == NULL) { + rte_errno = -ENOMEM; + return -1; + } + + struct rte_cfgfile_entry cfg_entries[num_entries]; + + rte_cfgfile_section_entries(cfg, "DPDK", cfg_entries, num_entries); + + cfg_argc = 0; + for (i = 0; i < num_entries; i++) { + cfg_argv[cfg_argc] = strdup_with_prefix(cfg_entries[i].name); + if (!(cfg_argv[cfg_argc])) + goto allocation_error; + cfg_argc++; + if (strlen(cfg_entries[i].value)) { + cfg_argv[cfg_argc] = strdup(cfg_entries[i].value); + if (!(cfg_argv[cfg_argc])) + goto allocation_error; + cfg_argc++; + } + } + /* set last pointer to 0 */ + cfg_argv[cfg_argc] = 0; + + return cfg_argc; + +allocation_error: + rte_eal_init_alert("Cannot allocate memory in rte_eal_configure()\n"); + rte_errno = ENOMEM; + for (i = 1; i < cfg_argc; i++) { + free(cfg_argv[i]); + cfg_argv[i] = 0; + } + return -1; +} +#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 -- 1.7.9.5 ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH 2/3] eal: add functions parsing EAL arguments 2017-05-30 8:30 ` [dpdk-dev] [PATCH 2/3] eal: add functions parsing EAL arguments Jacek Piasecki @ 2017-05-31 15:46 ` Bruce Richardson 0 siblings, 0 replies; 70+ messages in thread From: Bruce Richardson @ 2017-05-31 15:46 UTC (permalink / raw) To: Jacek Piasecki; +Cc: dev, deepak.k.jain, michalx.k.jastrzebski, Kuba Kozak On Tue, May 30, 2017 at 10:30:36AM +0200, Jacek Piasecki wrote: > From: Kuba Kozak <kubax.kozak@intel.com> > > added function rte_eal_configure which translate > options from config file into argc, **argv form. > > changed function rte_eal_init to meld > argc, argv** options from config file with > these from command line and then parse as > before > Hi, while this approach to merging the values from two sources (config struct and cmdline) works, I'm not sure it's the best way to implement this. I would have thought it more logical to separate out cmdline args into name-value pairs to add to the cfgfile struct internally instead. However, this has the disadvantage of forcing a dependency on cfgfile, or adding a third name-value pair struct to DPDK [after kvargs, which supports flat pairs, and cfgfile, which supports sections and pairs]. Using the cfgfile struct also saves us from "flattening out" hierarchical information we may wish to add in the config file. For example, consider the following cfgfile structure: [DPDK] lcores = 20-25 socket-mem = 2048, 1024 vdevs = 2 [DPDK.vdev0] name = eth_pcap0 rx_pcap = /path/to/file tx_pcap = /path/to/other_file [DPDK.vdev1] name = eth_tap0 iface = iface_arg Longer term, it would be good to keep those vdev entries separated as passed as such to the driver, rather than merging them back into a single string to be separated out again by kvargs lib. /Bruce ^ permalink raw reply [flat|nested] 70+ messages in thread
* [dpdk-dev] [PATCH 3/3] app/testpmd: changed example to parse options from cfg file 2017-05-30 8:30 [dpdk-dev] [PATCH 0/3] Add support for using a config file for DPDK Jacek Piasecki 2017-05-30 8:30 ` [dpdk-dev] [PATCH 1/3] cfgfile: add new API functions Jacek Piasecki 2017-05-30 8:30 ` [dpdk-dev] [PATCH 2/3] eal: add functions parsing EAL arguments Jacek Piasecki @ 2017-05-30 8:30 ` Jacek Piasecki 2017-06-20 2:13 ` Wu, Jingjing 2 siblings, 1 reply; 70+ messages in thread From: Jacek Piasecki @ 2017-05-30 8:30 UTC (permalink / raw) To: dev; +Cc: bruce.richardson, deepak.k.jain, michalx.k.jastrzebski, Kuba Kozak From: Kuba Kozak <kubax.kozak@intel.com> This patch shows how to pass arguments to application using config.ini file. If a --cfgfile-path <path> option is passed into commandline 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. Signed-off-by: Kuba Kozak <kubax.kozak@intel.com> Suggested-by: Bruce Richardson <bruce.richardson@intel.com> --- app/test-pmd/config.ini | 16 ++++++ app/test-pmd/parameters.c | 135 +++++++++++++++++++++++++++++++++++++++++++-- app/test-pmd/testpmd.c | 51 ++++++++++++++++- app/test-pmd/testpmd.h | 2 +- 4 files changed, 196 insertions(+), 8 deletions(-) create mode 100644 app/test-pmd/config.ini diff --git a/app/test-pmd/config.ini b/app/test-pmd/config.ini new file mode 100644 index 0000000..dfafc55 --- /dev/null +++ b/app/test-pmd/config.ini @@ -0,0 +1,16 @@ +[DPDK] +v = +l = 0-4 +n = 4 +master-lcore = 0 +proc-type = primary +vdev = net_ring0 +vdev = net_ring1 +vdev = net_ring2 +vdev = net_ring3 + +[TEST-PMD] +i = +portmask = 0xf +nb-cores = 4 +port-topology = paired diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c index fbe6284..974c548 100644 --- a/app/test-pmd/parameters.c +++ b/app/test-pmd/parameters.c @@ -77,9 +77,15 @@ #include <rte_eth_bond.h> #endif #include <rte_flow.h> +#include <rte_cfgfile.h> #include "testpmd.h" +#ifdef RTE_LIBRTE_CFGFILE +static int cfg_argc; +static char **cfg_argv; +#endif + static void usage(char* progname) { @@ -549,15 +555,107 @@ return 0; } +#ifdef RTE_LIBRTE_CFGFILE + +static void +free_pointer_array(char **pkt) +{ + int i = 0; + + if (pkt) { + while (pkt[i]) { + free(pkt[i]); + pkt[i++] = 0; + } + free(pkt); + pkt = 0; + } +} + +static char *strdup_with_prefix(const char *p) +{ + char *np; + + if (strlen(p) > 1) { + np = (char *)malloc(strlen(p)+3); + if (np) + strcpy(np, "--"); + } else { + np = (char *)malloc(strlen(p)+2); + if (np) + strcpy(np, "-"); + } + return np ? strcat(np, p) : np; +} + +#define APP_SECTION "TEST-PMD" +static int non_eal_configure(struct rte_cfgfile *cfg) +{ + int i, num_entries; + + if (cfg == NULL) { + rte_errno = -EINVAL; + return -1; + } + + if (!rte_cfgfile_has_section(cfg, APP_SECTION)) + return 0; + + num_entries = rte_cfgfile_section_num_entries(cfg, APP_SECTION); + if (num_entries <= 0) + return 0; + + cfg_argv = malloc((num_entries * 2 + 1) * sizeof(cfg_argv[0])); + if (cfg_argv == NULL) { + rte_errno = -ENOMEM; + return -1; + } + + struct rte_cfgfile_entry cfg_entries[num_entries]; + + rte_cfgfile_section_entries(cfg, APP_SECTION, cfg_entries, num_entries); + + cfg_argc = 0; + for (i = 0; i < num_entries; i++) { + cfg_argv[cfg_argc] = strdup_with_prefix(cfg_entries[i].name); + if (!(cfg_argv[cfg_argc])) + goto allocation_error; + cfg_argc++; + if (strlen(cfg_entries[i].value)) { + cfg_argv[cfg_argc] = strdup(cfg_entries[i].value); + if (!(cfg_argv[cfg_argc])) + goto allocation_error; + cfg_argc++; + } + } + /* set last pointer to 0 */ + cfg_argv[cfg_argc] = 0; + + return cfg_argc; + +allocation_error: + printf("Warning: Cannot allocate memory in rte_eal_configure()\n"); + rte_errno = ENOMEM; + for (i = 1; i < cfg_argc; i++) { + free(cfg_argv[i]); + cfg_argv[i] = 0; + } + return -1; +} +#endif + void -launch_args_parse(int argc, char** argv) +launch_args_parse(int argc, char **argv, struct rte_cfgfile *cfg) { + int combined_argc; /* combine cfg and param versions */ + char **combined_argv; int n, opt; char **argvopt; int opt_idx; enum { TX, RX }; static struct option lgopts[] = { + { "cfgfile-path", 1, 0, 1 }, { "help", 0, 0, 0 }, #ifdef RTE_LIBRTE_CMDLINE { "interactive", 0, 0, 0 }, @@ -632,14 +730,32 @@ { 0, 0, 0, 0 }, }; - argvopt = argv; +#ifdef RTE_LIBRTE_CFGFILE + int i; + + non_eal_configure(cfg); + + combined_argc = argc + cfg_argc; + combined_argv = malloc((combined_argc + 1) * sizeof(char *)); + combined_argv[0] = argv[0]; + for (i = 0; i < cfg_argc; i++) + combined_argv[i + 1] = cfg_argv[i]; + for (i = 1; i < argc; i++) + combined_argv[i + cfg_argc] = argv[i]; + combined_argv[combined_argc] = NULL; +#else + combined_argc = argc; + combined_argv = argv; +#endif + + argvopt = combined_argv; #ifdef RTE_LIBRTE_CMDLINE #define SHORTOPTS "i" #else #define SHORTOPTS "" #endif - while ((opt = getopt_long(argc, argvopt, SHORTOPTS "ah", + while ((opt = getopt_long(combined_argc, argvopt, SHORTOPTS "ah", lgopts, &opt_idx)) != EOF) { switch (opt) { #ifdef RTE_LIBRTE_CMDLINE @@ -655,7 +771,7 @@ case 0: /*long options */ if (!strcmp(lgopts[opt_idx].name, "help")) { - usage(argv[0]); + usage(combined_argv[0]); rte_exit(EXIT_SUCCESS, "Displayed help\n"); } #ifdef RTE_LIBRTE_CMDLINE @@ -1094,14 +1210,21 @@ break; case 'h': - usage(argv[0]); + usage(combined_argv[0]); rte_exit(EXIT_SUCCESS, "Displayed help\n"); break; + case 1: + /* does nothing*/ + break; default: - usage(argv[0]); + usage(combined_argv[0]); rte_exit(EXIT_FAILURE, "Command line is incomplete or incorrect\n"); break; } } + +#ifdef RTE_LIBRTE_CFGFILE + free_pointer_array(cfg_argv); +#endif } diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index d1041af..0d9d363 100644 --- a/app/test-pmd/testpmd.c +++ b/app/test-pmd/testpmd.c @@ -87,6 +87,7 @@ #ifdef RTE_LIBRTE_LATENCY_STATS #include <rte_latencystats.h> #endif +#include <rte_cfgfile.h> #include "testpmd.h" @@ -2248,15 +2249,54 @@ uint8_t port_is_bonding_slave(portid_t slave_pid) } } + + +#ifdef RTE_LIBRTE_CFGFILE +/* Load config file path from command line */ +static char * +cfgfile_load_path(int argc, char **argv) +{ + int i; + + for (i = 0; i < argc; i++) { + if (!strcmp("--cfgfile-path", argv[i])) { + if (i < argc) + return strdup(argv[i+1]); + } + } + return 0; +} +#endif + int main(int argc, char** argv) { int diag; uint8_t port_id; + struct rte_cfgfile *cfg = NULL; + char *config_file = NULL; signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); +#ifdef RTE_LIBRTE_CFGFILE + /* load --cfgfile-path argument from argv */ + config_file = cfgfile_load_path(argc, argv); + + if (config_file) { + printf("Info: found cfgfile-path \"%s\"\n", config_file); + } else { + printf("Info: not found cfgfile-path parameter " + "(searching for cfgfile " + "in default directory)\n"); + config_file = strdup("config.ini"); + } + cfg = rte_cfgfile_load(config_file, CFG_FLAG_EMPTY_VALUES); + if (cfg == NULL) + printf("Info: Valid cfgfile not found\n"); + rte_eal_configure(cfg); +#endif + diag = rte_eal_init(argc, argv); if (diag < 0) rte_panic("Cannot init EAL\n"); @@ -2289,7 +2329,16 @@ uint8_t port_is_bonding_slave(portid_t slave_pid) argc -= diag; argv += diag; if (argc > 1) - launch_args_parse(argc, argv); + launch_args_parse(argc, argv, cfg); + + + rte_cfgfile_close(cfg); + cfg = 0; + + if (config_file) { + free(config_file); + config_file = 0; + } if (!nb_rxq && !nb_txq) printf("Warning: Either rx or tx queues should be non-zero\n"); diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index e6c43ba..5c1d477 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -499,7 +499,7 @@ enum tx_pkt_split { unsigned int parse_item_list(char* str, const char* item_name, unsigned int max_items, unsigned int *parsed_items, int check_unique_values); -void launch_args_parse(int argc, char** argv); +void launch_args_parse(int argc, char **argv, struct rte_cfgfile *cfg); void cmdline_read_from_file(const char *filename); void prompt(void); void prompt_exit(void); -- 1.7.9.5 ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH 3/3] app/testpmd: changed example to parse options from cfg file 2017-05-30 8:30 ` [dpdk-dev] [PATCH 3/3] app/testpmd: changed example to parse options from cfg file Jacek Piasecki @ 2017-06-20 2:13 ` Wu, Jingjing 2017-06-20 10:10 ` Kozak, KubaX 0 siblings, 1 reply; 70+ messages in thread From: Wu, Jingjing @ 2017-06-20 2:13 UTC (permalink / raw) To: Piasecki, JacekX, dev Cc: Richardson, Bruce, Jain, Deepak K, Jastrzebski, MichalX K, Kozak, KubaX > + > +#ifdef RTE_LIBRTE_CFGFILE > +/* Load config file path from command line */ static char * > +cfgfile_load_path(int argc, char **argv) { > + int i; > + > + for (i = 0; i < argc; i++) { > + if (!strcmp("--cfgfile-path", argv[i])) { > + if (i < argc) > + return strdup(argv[i+1]); > + } > + } > + return 0; > +} > +#endif > + It is a little confused. Is the cfgfile-path is application's argument or EAL's? Where is it supposed to be located? > int > main(int argc, char** argv) > { > int diag; > uint8_t port_id; > + struct rte_cfgfile *cfg = NULL; > + char *config_file = NULL; > > signal(SIGINT, signal_handler); > signal(SIGTERM, signal_handler); > > +#ifdef RTE_LIBRTE_CFGFILE > + /* load --cfgfile-path argument from argv */ > + config_file = cfgfile_load_path(argc, argv); > + > + if (config_file) { > + printf("Info: found cfgfile-path \"%s\"\n", config_file); > + } else { > + printf("Info: not found cfgfile-path parameter " > + "(searching for cfgfile " > + "in default directory)\n"); > + config_file = strdup("config.ini"); > + } > + cfg = rte_cfgfile_load(config_file, CFG_FLAG_EMPTY_VALUES); > + if (cfg == NULL) > + printf("Info: Valid cfgfile not found\n"); > + rte_eal_configure(cfg); > +#endif > + Does it mean if RTE_LIBRTE_CFGFILE is defined, then the arguments are passed by Cfgfile, if no cfgfile will use config.ini by default? How about the legacy command lines? I think even cfgfile is good, we still need to keep the command line way. > diag = rte_eal_init(argc, argv); > if (diag < 0) > rte_panic("Cannot init EAL\n"); > @@ -2289,7 +2329,16 @@ uint8_t port_is_bonding_slave(portid_t slave_pid) > argc -= diag; > argv += diag; > if (argc > 1) > - launch_args_parse(argc, argv); > + launch_args_parse(argc, argv, cfg); > + The argc and argv have been overwritten by cfgfile, right? Does it make sense to Pass cfg to launch_args_parse? And you also need to update the testpmd doc to describe this new use. Thanks Jingjing ^ permalink raw reply [flat|nested] 70+ messages in thread
* Re: [dpdk-dev] [PATCH 3/3] app/testpmd: changed example to parse options from cfg file 2017-06-20 2:13 ` Wu, Jingjing @ 2017-06-20 10:10 ` Kozak, KubaX 0 siblings, 0 replies; 70+ messages in thread From: Kozak, KubaX @ 2017-06-20 10:10 UTC (permalink / raw) To: Wu, Jingjing, dev Cc: Richardson, Bruce, Jain, Deepak K, Jastrzebski, MichalX K, Piasecki, JacekX Comments inline. Best regards, Kuba Kozak > -----Original Message----- > From: Wu, Jingjing > Sent: Tuesday, June 20, 2017 04:14 > To: Piasecki, JacekX <jacekx.piasecki@intel.com>; dev@dpdk.org > Cc: Richardson, Bruce <bruce.richardson@intel.com>; Jain, Deepak K <deepak.k.jain@intel.com>; > Jastrzebski, MichalX K <michalx.k.jastrzebski@intel.com>; Kozak, KubaX <kubax.kozak@intel.com> > Subject: RE: [dpdk-dev] [PATCH 3/3] app/testpmd: changed example to parse options from cfg file > > > + > > +#ifdef RTE_LIBRTE_CFGFILE > > +/* Load config file path from command line */ static char * > > +cfgfile_load_path(int argc, char **argv) { > > + int i; > > + > > + for (i = 0; i < argc; i++) { > > + if (!strcmp("--cfgfile-path", argv[i])) { > > + if (i < argc) > > + return strdup(argv[i+1]); > > + } > > + } > > + return 0; > > +} > > +#endif > > + > It is a little confused. Is the cfgfile-path is application's argument or EAL's? > Where is it supposed to be located? It is an application argument. > > > int > > main(int argc, char** argv) > > { > > int diag; > > uint8_t port_id; > > + struct rte_cfgfile *cfg = NULL; > > + char *config_file = NULL; > > > > signal(SIGINT, signal_handler); > > signal(SIGTERM, signal_handler); > > > > +#ifdef RTE_LIBRTE_CFGFILE > > + /* load --cfgfile-path argument from argv */ > > + config_file = cfgfile_load_path(argc, argv); > > + > > + if (config_file) { > > + printf("Info: found cfgfile-path \"%s\"\n", config_file); > > + } else { > > + printf("Info: not found cfgfile-path parameter " > > + "(searching for cfgfile " > > + "in default directory)\n"); > > + config_file = strdup("config.ini"); > > + } > > + cfg = rte_cfgfile_load(config_file, CFG_FLAG_EMPTY_VALUES); > > + if (cfg == NULL) > > + printf("Info: Valid cfgfile not found\n"); > > + rte_eal_configure(cfg); > > +#endif > > + > Does it mean if RTE_LIBRTE_CFGFILE is defined, then the arguments are passed by Cfgfile, if no cfgfile > will use config.ini by default? How about the legacy command lines? > I think even cfgfile is good, we still need to keep the command line way. If RTE_LIBRTE_CFGFILE is defined then arguments are passed both by cfgfile and command line. Command line arguments have priority over cfgfile arguments and they override their values. > > > diag = rte_eal_init(argc, argv); > > if (diag < 0) > > rte_panic("Cannot init EAL\n"); > > @@ -2289,7 +2329,16 @@ uint8_t port_is_bonding_slave(portid_t slave_pid) > > argc -= diag; > > argv += diag; > > if (argc > 1) > > - launch_args_parse(argc, argv); > > + launch_args_parse(argc, argv, cfg); > > + > > The argc and argv have been overwritten by cfgfile, right? Does it make sense to Pass cfg to > launch_args_parse? This function translate argv arguments into configuration file form and append/override current cfgfile. Finally it parse application arguments from cfgfile. Intention was to parse arguments from single source (configuration file form). > > > And you also need to update the testpmd doc to describe this new use. > > Thanks > Jingjing ^ permalink raw reply [flat|nested] 70+ messages in thread
end of thread, other threads:[~2019-01-28 14:43 UTC | newest] Thread overview: 70+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2017-05-30 8:30 [dpdk-dev] [PATCH 0/3] Add support for using a config file for DPDK Jacek Piasecki 2017-05-30 8:30 ` [dpdk-dev] [PATCH 1/3] cfgfile: add new API functions Jacek Piasecki 2017-05-31 14:20 ` Bruce Richardson 2017-05-31 14:22 ` Bruce Richardson 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 0/7] Add support for using a config file for DPDK Jacek Piasecki 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 1/7] cfgfile: remove EAL dependency Jacek Piasecki 2017-06-26 13:12 ` Dumitrescu, Cristian 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 0/4] Rework cfgfile API to enable apps config file support Jacek Piasecki 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 1/4] cfgfile: remove EAL dependency Jacek Piasecki 2017-06-30 9:44 ` Bruce Richardson 2017-06-30 11:16 ` Bruce Richardson 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 2/4] cfgfile: add new functions to API Jacek Piasecki 2017-06-30 9:55 ` Bruce Richardson 2017-06-30 10:28 ` Bruce Richardson 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 3/4] cfgfile: rework of load function Jacek Piasecki 2017-06-30 11:18 ` Bruce Richardson 2017-06-27 10:26 ` [dpdk-dev] [PATCH v3 4/4] test/cfgfile: add new unit test Jacek Piasecki 2017-06-30 11:20 ` [dpdk-dev] [PATCH v3 0/4] Rework cfgfile API to enable apps config file support Bruce Richardson 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 2/7] cfgfile: add new functions to API Jacek Piasecki 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 3/7] cfgfile: rework of load function Jacek Piasecki 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 4/7] test/cfgfile: add new unit test Jacek Piasecki 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 5/7] eal: add functions parsing EAL arguments Jacek Piasecki 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 0/3] EAL change for using a config file for DPDK Jacek Piasecki 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 1/3] eal: add functions parsing EAL arguments Jacek Piasecki 2017-06-30 16:04 ` Bruce Richardson 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 0/5] Rework cfgfile API to enable apps config file support Jacek Piasecki 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 1/5] cfgfile: remove EAL dependency Jacek Piasecki 2017-08-30 17:58 ` Bruce Richardson 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 2/5] cfgfile: change existing API functions Jacek Piasecki 2017-08-30 20:07 ` Bruce Richardson 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 3/5] cfgfile: add new functions to API Jacek Piasecki 2017-08-30 20:18 ` Bruce Richardson 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 4/5] cfgfile: rework of load function Jacek Piasecki 2017-08-30 20:24 ` Bruce Richardson 2017-07-10 12:44 ` [dpdk-dev] [PATCH v4 5/5] test/cfgfile: add new unit test Jacek Piasecki 2017-08-30 20:25 ` Bruce Richardson 2017-09-04 9:21 ` Bruce Richardson 2017-09-04 9:30 ` Bruce Richardson 2017-09-15 13:56 ` Thomas Monjalon 2017-09-18 13:49 ` Jastrzebski, MichalX K 2017-07-10 15:13 ` [dpdk-dev] [PATCH v4 0/5] Rework cfgfile API to enable apps config file support Thomas Monjalon 2017-07-20 21:48 ` Thomas Monjalon 2017-07-10 12:51 ` [dpdk-dev] [PATCH v4 0/3] EAL change for using a config file for DPDK Kuba Kozak 2017-07-10 12:51 ` [dpdk-dev] [PATCH v4 1/3] eal: add functions parsing EAL arguments Kuba Kozak 2017-07-13 9:26 ` [dpdk-dev] [PATCH v5 0/3] EAL change for using a config file for DPDK Kuba Kozak 2017-07-13 10:07 ` Kuba Kozak 2017-07-13 10:07 ` [dpdk-dev] [PATCH v5 1/3] eal: add functions parsing EAL arguments Kuba Kozak 2017-07-13 10:07 ` [dpdk-dev] [PATCH v5 2/3] app/testpmd: add parse options from cfg file Kuba Kozak 2017-07-13 10:07 ` [dpdk-dev] [PATCH v5 3/3] app/testpmd: add parse options from JSON " Kuba Kozak 2019-01-23 19:31 ` [dpdk-dev] [PATCH v5 0/3] EAL change for using a config file for DPDK Ferruh Yigit 2019-01-23 20:26 ` Thomas Monjalon 2019-01-24 13:54 ` Ferruh Yigit 2019-01-24 14:32 ` Thomas Monjalon 2019-01-24 14:46 ` Ferruh Yigit 2019-01-24 16:06 ` Thomas Monjalon 2019-01-24 16:18 ` Ferruh Yigit 2019-01-24 17:45 ` Thomas Monjalon 2019-01-28 14:43 ` Ferruh Yigit 2017-07-10 12:51 ` [dpdk-dev] [PATCH v4 2/3] app/testpmd: add parse options from cfg file Kuba Kozak 2017-07-10 12:51 ` [dpdk-dev] [PATCH v4 3/3] app/testpmd: add parse options from JSON " Kuba Kozak 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 2/3] app/testpmd: changed example to parse options from " Jacek Piasecki 2017-06-27 10:52 ` [dpdk-dev] [PATCH v3 3/3] app/testpmd: add parse arguments from JSON config file Jacek Piasecki 2017-07-05 0:00 ` [dpdk-dev] [PATCH v3 0/3] EAL change for using a config file for DPDK Thomas Monjalon 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 6/7] app/testpmd: changed example to parse options from cfg file Jacek Piasecki 2017-06-26 10:59 ` [dpdk-dev] [PATCH v2 7/7] app/testpmd: add parse arguments from JSON config file Jacek Piasecki 2017-05-30 8:30 ` [dpdk-dev] [PATCH 2/3] eal: add functions parsing EAL arguments Jacek Piasecki 2017-05-31 15:46 ` Bruce Richardson 2017-05-30 8:30 ` [dpdk-dev] [PATCH 3/3] app/testpmd: changed example to parse options from cfg file Jacek Piasecki 2017-06-20 2:13 ` Wu, Jingjing 2017-06-20 10:10 ` Kozak, KubaX
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).