From e1a00536c8ed65bee4e86976a0805fdc65faa741 Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Tue, 28 Jan 2014 17:06:34 +0100 Subject: [PATCH] kvargs: add a new library to parse key/value arguments Copy the code from rte_eth_pcap_arg_parser.[ch], without any functional modifications, only: - rename functions and structure - restyle (indentation) - add comments (doxygen style) - add "const" or "static" attributes, remove unneeded "inline" Signed-off-by: Olivier Matz Acked-by: Bruce Richardson --- config/defconfig_i686-default-linuxapp-gcc | 5 + config/defconfig_i686-default-linuxapp-icc | 5 + config/defconfig_x86_64-default-bsdapp-gcc | 5 + config/defconfig_x86_64-default-linuxapp-gcc | 5 + config/defconfig_x86_64-default-linuxapp-icc | 5 + lib/Makefile | 1 + lib/librte_kvargs/Makefile | 52 ++++ lib/librte_kvargs/rte_kvargs.c | 248 +++++++++++++++++++ lib/librte_kvargs/rte_kvargs.h | 159 ++++++++++++ mk/rte.app.mk | 4 + 10 files changed, 489 insertions(+) create mode 100644 lib/librte_kvargs/Makefile create mode 100644 lib/librte_kvargs/rte_kvargs.c create mode 100644 lib/librte_kvargs/rte_kvargs.h diff --git a/config/defconfig_i686-default-linuxapp-gcc b/config/defconfig_i686-default-linuxapp-gcc index 847c071202..14bd3d191d 100644 --- a/config/defconfig_i686-default-linuxapp-gcc +++ b/config/defconfig_i686-default-linuxapp-gcc @@ -139,6 +139,11 @@ CONFIG_RTE_LIBRTE_EAL_BAREMETAL=n # CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=y +# +# Compile the argument parser library +# +CONFIG_RTE_LIBRTE_KVARGS=y + # # Compile generic ethernet library # diff --git a/config/defconfig_i686-default-linuxapp-icc b/config/defconfig_i686-default-linuxapp-icc index d84c0a65a6..ec3386ea3f 100644 --- a/config/defconfig_i686-default-linuxapp-icc +++ b/config/defconfig_i686-default-linuxapp-icc @@ -139,6 +139,11 @@ CONFIG_RTE_LIBRTE_EAL_BAREMETAL=n # CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=y +# +# Compile the argument parser library +# +CONFIG_RTE_LIBRTE_KVARGS=y + # # Compile generic ethernet library # diff --git a/config/defconfig_x86_64-default-bsdapp-gcc b/config/defconfig_x86_64-default-bsdapp-gcc index e415825133..d960e1d0e9 100644 --- a/config/defconfig_x86_64-default-bsdapp-gcc +++ b/config/defconfig_x86_64-default-bsdapp-gcc @@ -125,6 +125,11 @@ CONFIG_RTE_LIBRTE_EAL_BAREMETAL=n # CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=y +# +# Compile the argument parser library +# +CONFIG_RTE_LIBRTE_KVARGS=y + # # Compile generic ethernet library # diff --git a/config/defconfig_x86_64-default-linuxapp-gcc b/config/defconfig_x86_64-default-linuxapp-gcc index ced4ae9696..f11ffbf9ba 100644 --- a/config/defconfig_x86_64-default-linuxapp-gcc +++ b/config/defconfig_x86_64-default-linuxapp-gcc @@ -139,6 +139,11 @@ CONFIG_RTE_LIBRTE_EAL_BAREMETAL=n # CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=y +# +# Compile the argument parser library +# +CONFIG_RTE_LIBRTE_KVARGS=y + # # Compile generic ethernet library # diff --git a/config/defconfig_x86_64-default-linuxapp-icc b/config/defconfig_x86_64-default-linuxapp-icc index dfe76378e0..4eaca4cca4 100644 --- a/config/defconfig_x86_64-default-linuxapp-icc +++ b/config/defconfig_x86_64-default-linuxapp-icc @@ -139,6 +139,11 @@ CONFIG_RTE_LIBRTE_EAL_BAREMETAL=n # CONFIG_RTE_LIBRTE_EAL_VMWARE_TSC_MAP_SUPPORT=y +# +# Compile the argument parser library +# +CONFIG_RTE_LIBRTE_KVARGS=y + # # Compile generic ethernet library # diff --git a/lib/Makefile b/lib/Makefile index 157dbdb0e4..b92b3921e6 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -54,6 +54,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_POWER) += librte_power DIRS-$(CONFIG_RTE_LIBRTE_METER) += librte_meter DIRS-$(CONFIG_RTE_LIBRTE_SCHED) += librte_sched DIRS-$(CONFIG_RTE_LIBRTE_ACL) += librte_acl +DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y) DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni diff --git a/lib/librte_kvargs/Makefile b/lib/librte_kvargs/Makefile new file mode 100644 index 0000000000..16f610795e --- /dev/null +++ b/lib/librte_kvargs/Makefile @@ -0,0 +1,52 @@ +# BSD LICENSE +# +# Copyright 2014 6WIND S.A. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# - Neither the name of 6WIND S.A. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +# OF THE POSSIBILITY OF SUCH DAMAGE. + +include $(RTE_SDK)/mk/rte.vars.mk + +# library name +LIB = librte_kvargs.a + +CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3 + +# all source are stored in SRCS-y +SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) := rte_kvargs.c + +# install includes +INCS := rte_kvargs.h +SYMLINK-$(CONFIG_RTE_LIBRTE_KVARGS)-include := $(INCS) + +# this lib needs eal and malloc +DEPDIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += lib/librte_eal +DEPDIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += lib/librte_malloc + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c new file mode 100644 index 0000000000..3acb895ca0 --- /dev/null +++ b/lib/librte_kvargs/rte_kvargs.c @@ -0,0 +1,248 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. + * Copyright(c) 2014 6WIND S.A. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include + +#include +#include +#include + +#include "rte_kvargs.h" + +/* + * Initialize a rte_kvargs structure to an empty key/value list. + */ +int +rte_kvargs_init(struct rte_kvargs *kvlist) +{ + kvlist->count = 0; + kvlist->size = RTE_KVARGS_MAX; + memset(kvlist->pairs, 0, kvlist->size); + return 0; +} + +/* + * Add a key-value pair at the end of a given key/value list. + * Return an error if the list is full or if the key is duplicated. + */ +static int +rte_kvargs_add_pair(struct rte_kvargs *kvlist, char *key, char *val) +{ + unsigned i; + struct rte_kvargs_pair* entry; + + /* is the list full? */ + if (kvlist->count >= kvlist->size) { + RTE_LOG(ERR, PMD, "Couldn't add %s, key/value list is full\n", key); + return -1; + } + + /* Check if the key is duplicated */ + for (i = 0; i < kvlist->count; i++) { + entry = &kvlist->pairs[i]; + if (strcmp(entry->key, key) == 0) { + RTE_LOG(ERR, PMD, "Couldn't add %s, duplicated key\n", key); + return -1; + } + } + + entry = &kvlist->pairs[kvlist->count]; + entry->key = key; + entry->value = val; + kvlist->count++; + return 0; +} + +/* + * Receive a string with a list of arguments following the pattern + * key=value;key=value;... and insert them into the list. + * strtok() is used so the params string will be copied to be modified. + */ +static int +rte_kvargs_tokenize(struct rte_kvargs *kvlist, const char *name, + const char *params) +{ + unsigned i, count; + char *args; + char *pairs[RTE_KVARGS_MAX]; + char *pair[2]; + + /* If params are empty, nothing to do */ + if (params == NULL || params[0] == 0) { + RTE_LOG(ERR, PMD, "Couldn't parse %s device, empty arguments\n", name); + return -1; + } + + /* Copy the const char *params to a modifiable string + * to pass to rte_strsplit + */ + args = strdup(params); + if(args == NULL){ + RTE_LOG(ERR, PMD, "Couldn't parse %s device \n", name); + return -1; + } + + count = rte_strsplit(args, strnlen(args, MAX_ARG_STRLEN), pairs, + RTE_KVARGS_MAX, RTE_KVARGS_PAIRS_DELIM); + + for (i = 0; i < count; i++) { + pair[0] = NULL; + pair[1] = NULL; + + rte_strsplit(pairs[i], strnlen(pairs[i], MAX_ARG_STRLEN), pair, 2, + RTE_KVARGS_KV_DELIM); + + if (pair[0] == NULL || pair[1] == NULL || pair[0][0] == 0 + || pair[1][0] == 0) { + RTE_LOG(ERR, PMD, + "Couldn't parse %s device, wrong key or value \n", name); + goto error; + } + + if (rte_kvargs_add_pair(kvlist, pair[0], pair[1]) < 0) + goto error; + } + return 0; + +error: + rte_free(args); + return -1; +} + +/* + * Determine whether a key is valid or not by looking + * into a list of valid keys. + */ +static int +is_valid_key(const char *valid[], const char *key_match) +{ + const char **valid_ptr; + + for (valid_ptr = valid; *valid_ptr != NULL; valid_ptr++) + if (strstr(key_match, *valid_ptr) != NULL) + return 1; + return 0; +} + +/* + * Determine whether all keys are valid or not by looking + * into a list of valid keys. + */ +static int +check_for_valid_keys(struct rte_kvargs *kvlist, + const char *valid[]) +{ + unsigned i, ret; + struct rte_kvargs_pair *pair; + + for (i = 0; i < kvlist->count; i++) { + pair = &kvlist->pairs[i]; + ret = is_valid_key(valid, pair->key); + if (!ret) { + RTE_LOG(ERR, PMD, + "Error parsing device, invalid key <%s>\n", + pair->key); + return -1; + } + } + return 0; +} + +/* + * Return the number of times a given arg_name exists in the key/value list. + * E.g. given a list = { rx = 0, rx = 1, tx = 2 } the number of args for + * arg "rx" will be 2. + */ +unsigned +rte_kvargs_count(const struct rte_kvargs *kvlist, const char *key_match) +{ + const struct rte_kvargs_pair *pair; + unsigned i, ret; + + ret = 0; + for (i = 0; i < kvlist->count; i++) { + pair = &kvlist->pairs[i]; + if (strcmp(pair->key, key_match) == 0) + ret++; + } + + return ret; +} + +/* + * For each matching key, call the given handler function. + */ +int +rte_kvargs_process(const struct rte_kvargs *kvlist, + const char *key_match, + arg_handler_t handler, + void *opaque_arg) +{ + const struct rte_kvargs_pair *pair; + unsigned i; + + for (i = 0; i < kvlist->count; i++) { + pair = &kvlist->pairs[i]; + if (strstr(pair->key, key_match) != NULL) { + if ((*handler)(pair->value, opaque_arg) < 0) + return -1; + } + } + return 0; +} + +/* + * Parse the arguments "key=value;key=value;..." string and return + * an allocated structure that contains a key/value list. Also + * check if only valid keys were used. + */ +int +rte_kvargs_parse(struct rte_kvargs *kvlist, + const char *name, + const char *args, + const char *valid_keys[]) +{ + + int ret; + + ret = rte_kvargs_tokenize(kvlist, name, args); + if (ret < 0) + return ret; + + if (valid_keys == NULL) + return 0; + + return check_for_valid_keys(kvlist, valid_keys); +} diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_kvargs/rte_kvargs.h new file mode 100644 index 0000000000..bf32ce21a8 --- /dev/null +++ b/lib/librte_kvargs/rte_kvargs.h @@ -0,0 +1,159 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. + * Copyright(c) 2014 6WIND S.A. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RTE_KVARGS_H_ +#define _RTE_KVARGS_H_ + +/** + * @file + * RTE Argument parsing + * + * This module can be used to parse arguments whose format is + * key1=value1;key2=value2;key3=value3;... + * + * This file provides some helpers that are especially used by virtual + * ethernet devices at initialization for arguments parsing. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** Maximum number of key/value associations */ +#define RTE_KVARGS_MAX 32 + +/** separator character used between each pair */ +#define RTE_KVARGS_PAIRS_DELIM ';' + +/** separator character used between key and value */ +#define RTE_KVARGS_KV_DELIM '=' + +/** Type of callback function used by rte_kvargs_process() */ +typedef int (*arg_handler_t)(char *value, void *opaque); + +/** A key/value association */ +struct rte_kvargs_pair { + char *key; /**< the name (key) of the association */ + char *value; /**< the value associated to that key */ +}; + +/** Store a list of key/value associations */ +struct rte_kvargs { + unsigned count; /**< number of entries in the list */ + size_t size; /**< maximum number of entries */ + struct rte_kvargs_pair pairs[RTE_KVARGS_MAX]; /**< list of key/values */ +}; + +/** + * Initialize an empty rte_kvargs structure + * + * Set the content of the rte_kvargs structure given as a parameter + * to an empty list of key/value. + * + * @param kvlist + * The rte_kvargs structure + * + * @return + * - 0 on success + * - Negative on error + */ +int rte_kvargs_init(struct rte_kvargs *kvlist); + +/** + * Append key/value associations in a rte_kvargs structure from a string + * + * The function fills a rte_kvargs structure from a string whose format + * is key1=value1;key2=value2;... + * The key/value associations are appended to those which are already + * present in the rte_kvargs structure. + * + * @param kvlist + * The rte_kvargs structure + * @param name + * The name of the driver + * @param args + * The input string containing the key/value associations + * @param valid_keys + * A list of valid keys (table of const char *, the last must be NULL). + * This argument is ignored if NULL + * + * @return + * - 0 on success + * - Negative on error + */ +int rte_kvargs_parse(struct rte_kvargs *kvlist, const char *name, + const char *args, const char *valid_keys[]); + +/** + * Call a handler function for each key/value matching the key + * + * For each key/value association that matches the given key, calls the + * handler function with the for a given arg_name passing the value on the + * dictionary for that key and a given extra argument. + * + * @param kvlist + * The rte_kvargs structure + * @param key_match + * The key on which the handler should be called + * @param handler + * The function to call for each matching key + * @param opaque_arg + * A pointer passed unchanged to the handler + * + * @return + * - 0 on success + * - Negative on error + */ +int rte_kvargs_process(const struct rte_kvargs *kvlist, + const char *key_match, arg_handler_t handler, void *opaque_arg); + +/** + * Count the number of associations matching the given key + * + * @param kvlist + * The rte_kvargs structure + * @param key_match + * The key that should match + + * @return + * The number of entries + */ +unsigned rte_kvargs_count(const struct rte_kvargs *kvlist, + const char *key_match); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mk/rte.app.mk b/mk/rte.app.mk index aab10d18e5..ec8e24eebb 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -118,6 +118,10 @@ endif LDLIBS += --start-group +ifeq ($(CONFIG_RTE_LIBRTE_KVARGS),y) +LDLIBS += -lrte_kvargs +endif + ifeq ($(CONFIG_RTE_LIBRTE_MBUF),y) LDLIBS += -lrte_mbuf endif -- 2.20.1