From: Matias Elo <matias....@nokia.com> Enables changing ODP runtime configuration options by using an optional configuration file (libconfig). Path to the conf file is passed using environment variable ODP_CONF_FILE. If ODP_CONF_FILE or a particular option is not set, hardcoded default values are used intead. An example configuration file is provided in config/odp-linux.conf.
Runtime configuration is initially used by DPDK pktio to set NIC options. Adds new dependency to libconfig library. Signed-off-by: Matias Elo <matias....@nokia.com> --- /** Email created from pull request 499 (matiaselo:dev/dpdk_dev_config) ** https://github.com/Linaro/odp/pull/499 ** Patch: https://github.com/Linaro/odp/pull/499.patch ** Base sha: 5a58bbf2bb331fd7dde2ebbc0430634ace6900fb ** Merge commit sha: ab13bcecea3972b5af189e9e5d6d4873790fb554 **/ .travis.yml | 3 +- DEPENDENCIES | 2 +- config/README | 8 +++ config/odp-linux.conf | 20 +++++++ m4/odp_libconfig.m4 | 60 +++++++++++++++++++++ platform/linux-generic/Makefile.am | 4 ++ platform/linux-generic/include/odp_internal.h | 4 ++ .../linux-generic/include/odp_libconfig_internal.h | 29 ++++++++++ platform/linux-generic/include/odp_packet_dpdk.h | 8 +++ platform/linux-generic/libodp-linux.pc.in | 4 +- platform/linux-generic/m4/configure.m4 | 1 + platform/linux-generic/odp_init.c | 14 +++++ platform/linux-generic/odp_libconfig.c | 57 ++++++++++++++++++++ platform/linux-generic/pktio/dpdk.c | 63 ++++++++++++++++++++-- platform/linux-generic/test/ring/Makefile.am | 1 + 15 files changed, 271 insertions(+), 7 deletions(-) create mode 100644 config/odp-linux.conf create mode 100644 m4/odp_libconfig.m4 create mode 100644 platform/linux-generic/include/odp_libconfig_internal.h create mode 100644 platform/linux-generic/odp_libconfig.c diff --git a/.travis.yml b/.travis.yml index d9423adcc..4095516c9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,7 @@ addons: - gcc - clang-3.8 - automake autoconf libtool libssl-dev graphviz mscgen + - libconfig-dev - codespell - libpcap-dev - libnuma-dev @@ -254,7 +255,7 @@ script: - make -j $(nproc) - mkdir /dev/shm/odp - if [ -z "$CROSS_ARCH" ] ; then - sudo LD_LIBRARY_PATH="$HOME/cunit-install/$CROSS_ARCH/lib:$LD_LIBRARY_PATH" ODP_SHM_DIR=/dev/shm/odp make check ; + sudo ODP_CONFIG_FILE="`pwd`/config/odp-linux.conf" LD_LIBRARY_PATH="$HOME/cunit-install/$CROSS_ARCH/lib:$LD_LIBRARY_PATH" ODP_SHM_DIR=/dev/shm/odp make check ; fi - make install diff --git a/DEPENDENCIES b/DEPENDENCIES index 6f374ca92..b6765fecd 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -19,7 +19,7 @@ Prerequisites for building the OpenDataPlane (ODP) API 3. Required libraries - Libraries currently required to link: openssl, libatomic + Libraries currently required to link: openssl, libatomic, libconfig 3.1 OpenSSL native compile diff --git a/config/README b/config/README index 3f4336103..415334255 100644 --- a/config/README +++ b/config/README @@ -1,2 +1,10 @@ ODP configuration options ------------------------- + +Runtime configuration options can be passed to an ODP instance by +setting ODP_CONFIG_FILE environment variable to point to a libconfig +format configuration file. An example configuration file with default +values is provided in config/odp-linux.conf. If ODP_CONFIG_FILE is not +found, hardcoded default values are used instead of any configuration +file. A configuration file doesn't have to include all available +options. The missing options are replaced with hardcoded default values. diff --git a/config/odp-linux.conf b/config/odp-linux.conf new file mode 100644 index 000000000..eb40f5212 --- /dev/null +++ b/config/odp-linux.conf @@ -0,0 +1,20 @@ +# ODP runtime configuration options +# +# A configuration file doesn't have to include all available +# options. The missing options are replaced with hardcoded default +# values. +# +# See libconfig syntax: https://hyperrealm.github.io/libconfig/libconfig_manual.html#Configuration-Files + +# DPDK pktio options +pktio_dpdk: { + # Default options + num_rx_desc = 128 + num_tx_desc = 512 + rx_drop_en = 0 + + # Driver specific options (use PMD names from DPDK) + net_ixgbe: { + rx_drop_en = 1 + } +} diff --git a/m4/odp_libconfig.m4 b/m4/odp_libconfig.m4 new file mode 100644 index 000000000..e5b1d8acd --- /dev/null +++ b/m4/odp_libconfig.m4 @@ -0,0 +1,60 @@ +# ODP_LIBCONFIG([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# ----------------------------------------------------- +AC_DEFUN([ODP_LIBCONFIG], +[dnl +AC_ARG_VAR([LIBCONFIG_CPPFLAGS], [C preprocessor flags for libconfig]) +AC_ARG_VAR([LIBCONFIG_LIBS], [linker flags for libconfig library]) +AC_ARG_VAR([LIBCONFIG_STATIC_LIBS], [static linker flags for libconfig library]) + +########################################################################## +# Set optional libconfig path +########################################################################## +AC_ARG_WITH([libconfig-path], +[AS_HELP_STRING([--with-libconfig-path=DIR], + [path to libconfig libs and headers (use system path if not provided)])], +[LIBCONFIG_CPPFLAGS="-I$withval/include" +LIBCONFIG_LIBS="-L$withval/lib -lconfig"], +[if test "x$ac_cv_env_LIBCONFIG_LIBS_set" != "xset" ; then + LIBCONFIG_LIBS="-lconfig" +fi]) +if test "x$ac_cv_env_LIBCONFIG_STATIC_LIBS_set" != "xset" ; then + LIBCONFIG_STATIC_LIBS="$LIBCONFIG_LIBS -ldl" +fi + +########################################################################## +# Save and set temporary compilation flags +########################################################################## +OLD_CPPFLAGS=$CPPFLAGS +OLD_LIBS=$LIBS +CPPFLAGS="$LIBCONFIG_CPPFLAGS $CPPFLAGS" +LIBS="$LIBCONFIG_LIBS $LIBS" + +########################################################################## +# Check for libconfig availability +########################################################################## +odp_libconfig_ok=yes +AC_CHECK_HEADERS([libconfig.h], [], + [odp_libconfig_ok=no]) +AC_CACHE_CHECK([for config_init in -lconfig], [odp_cv_libconfig], +[AC_LINK_IFELSE([AC_LANG_CALL([], [config_init])], + [odp_cv_libconfig=yes], + [odp_cv_libconfig=no])]) +if test "x$odp_cv_libconfig" != "xyes" ; then + odp_libconfig_ok=no +fi + +if test "x$odp_libconfig_ok" = "xyes" ; then + m4_default([$1], [:]) +else + LIBCONFIG_CPPFLAGS="" + LIBCONFIG_LIBS="" + LIBCONFIG_STATIC_LIBS="" + m4_default([$2], [AC_MSG_FAILURE([libconfig not found])]) +fi + +########################################################################## +# Restore old saved variables +########################################################################## +LIBS=$OLD_LIBS +CPPFLAGS=$OLD_CPPFLAGS +]) # ODP_LIBCONFIG diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index 7f212fe5e..b80719081 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -10,6 +10,7 @@ AM_CPPFLAGS += -I$(top_srcdir)/platform/$(with_platform)/arch/@ARCH_DIR@ AM_CPPFLAGS += -I$(top_srcdir)/platform/$(with_platform)/arch/default AM_CPPFLAGS += $(OPENSSL_CPPFLAGS) +AM_CPPFLAGS += $(LIBCONFIG_CPPFLAGS) AM_CPPFLAGS += $(DPDK_CPPFLAGS) AM_CPPFLAGS += $(NETMAP_CPPFLAGS) @@ -94,6 +95,7 @@ noinst_HEADERS = \ include/odp_forward_typedefs_internal.h \ include/odp_internal.h \ include/odp_ipsec_internal.h \ + include/odp_libconfig_internal.h \ include/odp_llqueue.h \ include/odp_macros_internal.h \ include/odp_name_table_internal.h \ @@ -152,6 +154,7 @@ __LIB__libodp_linux_la_SOURCES = \ odp_ipsec.c \ odp_ipsec_events.c \ odp_ipsec_sad.c \ + odp_libconfig.c \ odp_name_table.c \ odp_packet.c \ odp_packet_flags.c \ @@ -284,6 +287,7 @@ endif __LIB__libodp_linux_la_LIBADD = $(ATOMIC_LIBS) __LIB__libodp_linux_la_LIBADD += $(OPENSSL_LIBS) +__LIB__libodp_linux_la_LIBADD += $(LIBCONFIG_LIBS) __LIB__libodp_linux_la_LIBADD += $(DPDK_LIBS_LIBODP) __LIB__libodp_linux_la_LIBADD += $(PTHREAD_LIBS) __LIB__libodp_linux_la_LIBADD += $(TIMER_LIBS) diff --git a/platform/linux-generic/include/odp_internal.h b/platform/linux-generic/include/odp_internal.h index f85a2f538..06ae54388 100644 --- a/platform/linux-generic/include/odp_internal.h +++ b/platform/linux-generic/include/odp_internal.h @@ -23,6 +23,7 @@ extern "C" { #include <odp_errno_define.h> #include <stdio.h> #include <sys/types.h> +#include <libconfig.h> #define MAX_CPU_NUMBER 128 #define UID_MAXLEN 30 @@ -55,10 +56,13 @@ struct odp_global_data_s { odp_cpumask_t control_cpus; odp_cpumask_t worker_cpus; int num_cpus_installed; + config_t libconfig; /*< Runtime config using libconfig */ + uint8_t libconfig_enabled; /*< Runtime config enabled */ }; enum init_stage { NO_INIT = 0, /* No init stages completed */ + LIBCONFIG_INIT, CPUMASK_INIT, TIME_INIT, SYSINFO_INIT, diff --git a/platform/linux-generic/include/odp_libconfig_internal.h b/platform/linux-generic/include/odp_libconfig_internal.h new file mode 100644 index 000000000..b75736d77 --- /dev/null +++ b/platform/linux-generic/include/odp_libconfig_internal.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2018, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * + * Common libconfig functions + */ + +#ifndef ODP_LIBCONFIG_INTERNAL_H_ +#define ODP_LIBCONFIG_INTERNAL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +int _odp_libconfig_init_global(void); +int _odp_libconfig_term_global(void); + +config_setting_t *_odp_libconfig_lookup(const char *path); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/platform/linux-generic/include/odp_packet_dpdk.h b/platform/linux-generic/include/odp_packet_dpdk.h index ec60b872f..5db7025e6 100644 --- a/platform/linux-generic/include/odp_packet_dpdk.h +++ b/platform/linux-generic/include/odp_packet_dpdk.h @@ -33,6 +33,13 @@ ODP_STATIC_ASSERT((DPDK_NB_MBUF % DPDK_MEMPOOL_CACHE_SIZE == 0) && /* Minimum RX burst size */ #define DPDK_MIN_RX_BURST 4 +/** DPDK runtime configuration options */ +typedef struct { + int num_rx_desc; + int num_tx_desc; + int rx_drop_en; +} dpdk_opt_t; + /** Cache for storing packets */ struct pkt_cache_t { /** array for storing extra RX packets */ @@ -64,6 +71,7 @@ typedef struct ODP_ALIGNED_CACHE { odp_ticketlock_t tx_lock[PKTIO_MAX_QUEUES]; /**< TX queue locks */ /** cache for storing extra RX packets */ pkt_cache_t rx_cache[PKTIO_MAX_QUEUES]; + dpdk_opt_t opt; } pkt_dpdk_t; #endif diff --git a/platform/linux-generic/libodp-linux.pc.in b/platform/linux-generic/libodp-linux.pc.in index 5125f83ad..0ab0e72c2 100644 --- a/platform/linux-generic/libodp-linux.pc.in +++ b/platform/linux-generic/libodp-linux.pc.in @@ -7,5 +7,5 @@ Name: libodp-linux Description: The ODP packet processing engine Version: @PKGCONFIG_VERSION@ Libs: -L${libdir} -lodp-linux -Libs.private: @OPENSSL_STATIC_LIBS@ @DPDK_LIBS@ @PCAP_LIBS@ @PTHREAD_LIBS@ @TIMER_LIBS@ -lpthread @ATOMIC_LIBS@ -Cflags: -I${includedir} +Libs.private: @OPENSSL_STATIC_LIBS@ @LIBCONFIG_STATIC_LIBS@ @DPDK_LIBS@ @PCAP_LIBS@ @PTHREAD_LIBS@ @TIMER_LIBS@ -lpthread @ATOMIC_LIBS@ +Cflags: -I${includedir} @LIBCONFIG_CPPFLAGS@ diff --git a/platform/linux-generic/m4/configure.m4 b/platform/linux-generic/m4/configure.m4 index 935894b8c..a2fd1134f 100644 --- a/platform/linux-generic/m4/configure.m4 +++ b/platform/linux-generic/m4/configure.m4 @@ -6,6 +6,7 @@ ODP_ATOMIC ODP_PTHREAD ODP_TIMER ODP_OPENSSL +ODP_LIBCONFIG m4_include([platform/linux-generic/m4/odp_pcap.m4]) m4_include([platform/linux-generic/m4/odp_netmap.m4]) m4_include([platform/linux-generic/m4/odp_dpdk.m4]) diff --git a/platform/linux-generic/odp_init.c b/platform/linux-generic/odp_init.c index 0c5adf335..fbfeb096b 100644 --- a/platform/linux-generic/odp_init.c +++ b/platform/linux-generic/odp_init.c @@ -12,6 +12,7 @@ #include <unistd.h> #include <odp_internal.h> #include <odp_schedule_if.h> +#include <odp_libconfig_internal.h> #include <string.h> #include <stdio.h> #include <linux/limits.h> @@ -48,6 +49,12 @@ int odp_init_global(odp_instance_t *instance, odp_global_data.abort_fn = params->abort_fn; } + if (_odp_libconfig_init_global()) { + ODP_ERR("ODP runtime config init failed.\n"); + goto init_failed; + } + stage = LIBCONFIG_INIT; + if (odp_cpumask_init_global(params)) { ODP_ERR("ODP cpumask init failed.\n"); goto init_failed; @@ -293,6 +300,13 @@ int _odp_term_global(enum init_stage stage) } /* Fall through */ + case LIBCONFIG_INIT: + if (_odp_libconfig_term_global()) { + ODP_ERR("ODP runtime config term failed.\n"); + rc = -1; + } + /* Fall through */ + case NO_INIT: ; } diff --git a/platform/linux-generic/odp_libconfig.c b/platform/linux-generic/odp_libconfig.c new file mode 100644 index 000000000..f52ca260e --- /dev/null +++ b/platform/linux-generic/odp_libconfig.c @@ -0,0 +1,57 @@ +/* Copyright (c) 2018, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "config.h" + +#include <stdlib.h> +#include <libconfig.h> + +#include <odp_internal.h> +#include <odp_debug_internal.h> +#include <odp_libconfig_internal.h> + +extern struct odp_global_data_s odp_global_data; + +int _odp_libconfig_init_global(void) +{ + char *filename; + config_t *config = &odp_global_data.libconfig; + + filename = getenv("ODP_CONFIG_FILE"); + if (filename == NULL) + return 0; + + config_init(config); + + if (!config_read_file(config, filename)) { + ODP_ERR("Failed to read config file: %s(%d): %s\n", + config_error_file(config), config_error_line(config), + config_error_text(config)); + config_destroy(config); + return -1; + } + + odp_global_data.libconfig_enabled = 1; + + return 0; +} + +int _odp_libconfig_term_global(void) +{ + if (odp_global_data.libconfig_enabled) + config_destroy(&odp_global_data.libconfig); + return 0; +} + +config_setting_t *_odp_libconfig_lookup(const char *path) +{ + config_t *config = &odp_global_data.libconfig; + + if (!odp_global_data.libconfig_enabled) + return NULL; + + return config_lookup(config, path); +} diff --git a/platform/linux-generic/pktio/dpdk.c b/platform/linux-generic/pktio/dpdk.c index 6dc602389..e1d173ee6 100644 --- a/platform/linux-generic/pktio/dpdk.c +++ b/platform/linux-generic/pktio/dpdk.c @@ -14,6 +14,7 @@ #include <ctype.h> #include <unistd.h> #include <math.h> +#include <libconfig.h> #include <odp/api/cpumask.h> @@ -24,6 +25,7 @@ #include <odp_classification_internal.h> #include <odp_packet_dpdk.h> #include <odp_debug_internal.h> +#include <odp_libconfig_internal.h> #include <protocols/eth.h> @@ -93,6 +95,56 @@ void refer_constructors(void) } #endif +static void lookup_opt(config_setting_t *default_opt, config_setting_t *drv_opt, + const char *opt, int *val) +{ + /* Default option */ + config_setting_lookup_int(default_opt, opt, val); + + /* Driver option overwrites default option */ + if (drv_opt) + config_setting_lookup_int(drv_opt, opt, val); +} + +static void init_options(pktio_entry_t *pktio_entry, + const struct rte_eth_dev_info *dev_info) +{ + dpdk_opt_t *opt = &pktio_entry->s.pkt_dpdk.opt; + config_setting_t *default_opt; + config_setting_t *drv_opt; + + /* Default values. Update 'config/odp-linux.conf' if modified. */ + opt->num_rx_desc = DPDK_NM_RX_DESC; + opt->num_tx_desc = DPDK_NM_TX_DESC; + opt->rx_drop_en = 0; + + default_opt = _odp_libconfig_lookup("pktio_dpdk"); + if (!default_opt) { + ODP_DBG("No DPDK pktio options found\n"); + goto done; + } + + /* config_lookup_from() was renamed to config_setting_lookup() in + * libconfig 1.5.0 */ +#if (LIBCONFIG_VER_MAJOR <= 1 && LIBCONFIG_VER_MINOR < 5) + drv_opt = config_lookup_from(default_opt, dev_info->driver_name); +#else + drv_opt = config_setting_lookup(default_opt, dev_info->driver_name); +#endif + + /* Read options from config file */ + lookup_opt(default_opt, drv_opt, "num_rx_desc", &opt->num_rx_desc); + lookup_opt(default_opt, drv_opt, "num_tx_desc", &opt->num_tx_desc); + lookup_opt(default_opt, drv_opt, "rx_drop_en", &opt->rx_drop_en); + +done: + printf("DPDK interface (%s): %" PRIu16 "\n", dev_info->driver_name, + pktio_entry->s.pkt_dpdk.port_id); + printf(" num_rx_desc: %d\n", opt->num_rx_desc); + printf(" num_tx_desc: %d\n", opt->num_tx_desc); + printf(" rx_drop_en: %d\n", opt->rx_drop_en); +} + /** * Calculate valid cache size for DPDK packet pool */ @@ -1337,6 +1389,9 @@ static int dpdk_open(odp_pktio_t id ODP_UNUSED, dpdk_init_capability(pktio_entry, &dev_info); + /* Initialize runtime options */ + init_options(pktio_entry, &dev_info); + mtu = dpdk_mtu_get(pktio_entry); if (mtu == 0) { ODP_ERR("Failed to read interface MTU\n"); @@ -1464,7 +1519,8 @@ static int dpdk_start(pktio_entry_t *pktio_entry) pktio_entry->s.chksum_insert_ena = 1; } - ret = rte_eth_tx_queue_setup(port_id, i, DPDK_NM_TX_DESC, + ret = rte_eth_tx_queue_setup(port_id, i, + pkt_dpdk->opt.num_tx_desc, rte_eth_dev_socket_id(port_id), txconf); if (ret < 0) { @@ -1476,9 +1532,10 @@ static int dpdk_start(pktio_entry_t *pktio_entry) /* Init RX queues */ rte_eth_dev_info_get(port_id, &dev_info); rxconf = &dev_info.default_rxconf; - rxconf->rx_drop_en = 1; + rxconf->rx_drop_en = pkt_dpdk->opt.rx_drop_en; for (i = 0; i < pktio_entry->s.num_in_queue; i++) { - ret = rte_eth_rx_queue_setup(port_id, i, DPDK_NM_RX_DESC, + ret = rte_eth_rx_queue_setup(port_id, i, + pkt_dpdk->opt.num_rx_desc, rte_eth_dev_socket_id(port_id), rxconf, pkt_dpdk->pkt_pool); if (ret < 0) { diff --git a/platform/linux-generic/test/ring/Makefile.am b/platform/linux-generic/test/ring/Makefile.am index 3f774342e..61c97e62e 100644 --- a/platform/linux-generic/test/ring/Makefile.am +++ b/platform/linux-generic/test/ring/Makefile.am @@ -15,6 +15,7 @@ TESTS = ring_main$(EXEEXT) PRELDADD += $(LIBCUNIT_COMMON) AM_CPPFLAGS += -I$(top_srcdir)/platform/linux-generic/include +AM_CPPFLAGS += $(LIBCONFIG_CPPFLAGS) TESTNAME = linux-generic-ring