From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by dpdk.org (Postfix) with ESMTP id BCFEA231C for ; Fri, 4 Nov 2016 04:36:26 +0100 (CET) Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga103.fm.intel.com with ESMTP; 03 Nov 2016 20:36:22 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.31,442,1473145200"; d="scan'208";a="897563583" Received: from rhorton-mobl.ger.corp.intel.com (HELO VM.sh.intel.com) ([172.16.225.75]) by orsmga003.jf.intel.com with ESMTP; 03 Nov 2016 20:36:21 -0700 From: Remy Horton To: dev@dpdk.org Date: Fri, 4 Nov 2016 11:36:17 +0800 Message-Id: <1478230579-4689-2-git-send-email-remy.horton@intel.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1478230579-4689-1-git-send-email-remy.horton@intel.com> References: <1478230579-4689-1-git-send-email-remy.horton@intel.com> Subject: [dpdk-dev] [PATCH v3 1/3] lib: add information metrics library X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 04 Nov 2016 03:36:27 -0000 This patch adds a new information metric library that allows other modules to register named metrics and update their values. It is intended to be independent of ethdev, rather than mixing ethdev and non-ethdev information in xstats. Signed-off-by: Remy Horton --- config/common_base | 5 + doc/api/doxy-api-index.md | 1 + doc/api/doxy-api.conf | 1 + doc/guides/rel_notes/release_16_11.rst | 6 + lib/Makefile | 1 + lib/librte_metrics/Makefile | 51 +++++ lib/librte_metrics/rte_metrics.c | 300 +++++++++++++++++++++++++++++ lib/librte_metrics/rte_metrics.h | 204 ++++++++++++++++++++ lib/librte_metrics/rte_metrics_version.map | 13 ++ mk/rte.app.mk | 2 + 10 files changed, 584 insertions(+) create mode 100644 lib/librte_metrics/Makefile create mode 100644 lib/librte_metrics/rte_metrics.c create mode 100644 lib/librte_metrics/rte_metrics.h create mode 100644 lib/librte_metrics/rte_metrics_version.map diff --git a/config/common_base b/config/common_base index 21d18f8..2277727 100644 --- a/config/common_base +++ b/config/common_base @@ -589,3 +589,8 @@ CONFIG_RTE_APP_TEST_RESOURCE_TAR=n CONFIG_RTE_TEST_PMD=y CONFIG_RTE_TEST_PMD_RECORD_CORE_CYCLES=n CONFIG_RTE_TEST_PMD_RECORD_BURST_STATS=n + +# +# Compile the device metrics library +# +CONFIG_RTE_LIBRTE_METRICS=y diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md index 6675f96..ca50fa6 100644 --- a/doc/api/doxy-api-index.md +++ b/doc/api/doxy-api-index.md @@ -147,4 +147,5 @@ There are many libraries, so their headers may be grouped by topics: [common] (@ref rte_common.h), [ABI compat] (@ref rte_compat.h), [keepalive] (@ref rte_keepalive.h), + [Device Metrics] (@ref rte_metrics.h), [version] (@ref rte_version.h) diff --git a/doc/api/doxy-api.conf b/doc/api/doxy-api.conf index 9dc7ae5..fe830eb 100644 --- a/doc/api/doxy-api.conf +++ b/doc/api/doxy-api.conf @@ -57,6 +57,7 @@ INPUT = doc/api/doxy-api-index.md \ lib/librte_reorder \ lib/librte_ring \ lib/librte_sched \ + lib/librte_metrics \ lib/librte_table \ lib/librte_timer \ lib/librte_vhost diff --git a/doc/guides/rel_notes/release_16_11.rst b/doc/guides/rel_notes/release_16_11.rst index aa0c09a..507f715 100644 --- a/doc/guides/rel_notes/release_16_11.rst +++ b/doc/guides/rel_notes/release_16_11.rst @@ -131,6 +131,12 @@ New Features The GCC 4.9 ``-march`` option supports the Intel processor code names. The config option ``RTE_MACHINE`` can be used to pass code names to the compiler as ``-march`` flag. +* **Added information metric library.** + + A library that allows information metrics to be added and update. It is + intended to provide a reporting mechanism that is independent of the + ethdev library. + Resolved Issues --------------- diff --git a/lib/Makefile b/lib/Makefile index 990f23a..5d85dcf 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -58,6 +58,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += librte_pdump +DIRS-$(CONFIG_RTE_LIBRTE_METRICS) += librte_metrics ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y) DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni diff --git a/lib/librte_metrics/Makefile b/lib/librte_metrics/Makefile new file mode 100644 index 0000000..8d6e23a --- /dev/null +++ b/lib/librte_metrics/Makefile @@ -0,0 +1,51 @@ +# BSD LICENSE +# +# Copyright(c) 2016 Intel Corporation. All rights reserved. +# 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 $(RTE_SDK)/mk/rte.vars.mk + +# library name +LIB = librte_metrics.a + +CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) + +EXPORT_MAP := rte_metrics_version.map + +LIBABIVER := 1 + +# all source are stored in SRCS-y +SRCS-$(CONFIG_RTE_LIBRTE_METRICS) := rte_metrics.c + +# Install header file +SYMLINK-$(CONFIG_RTE_LIBRTE_METRICS)-include += rte_metrics.h + +DEPDIRS-$(CONFIG_RTE_LIBRTE_METRICS) += lib/librte_eal + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/lib/librte_metrics/rte_metrics.c b/lib/librte_metrics/rte_metrics.c new file mode 100644 index 0000000..220c2ac --- /dev/null +++ b/lib/librte_metrics/rte_metrics.c @@ -0,0 +1,300 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * 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 +#include + +#define RTE_METRICS_MAX_METRICS 256 +#define RTE_METRICS_MEMZONE_NAME "RTE_METRICS" + +/** + * Internal stats metadata and value entry. + * + * @internal + * @param name + * Name of metric + * @param value + * Current value for metric + * @param idx_next_set + * Index of next root element (zero for none) + * @param idx_next_metric + * Index of next metric in set (zero for none) + * + * Only the root of each set needs idx_next_set but since it has to be + * assumed that number of sets could equal total number of metrics, + * having a separate set metadata table doesn't save any memory. + */ +struct rte_metrics_meta_s { + char name[RTE_METRICS_MAX_NAME_LEN]; + uint64_t value[RTE_MAX_ETHPORTS]; + uint64_t nonport_value; + uint16_t idx_next_set; + uint16_t idx_next_stat; +}; + +/** + * Internal stats info structure. + * + * @internal + * @param idx_last_set + * Index of last metadata entry with valid data. This value is + * not valid if cnt_stats is zero. + * @param cnt_stats + * Number of metrics. + * @param metadata + * Stat data memory block. + * + * Offsets into metadata are used instead of pointers because ASLR + * means that having the same physical addresses in different + * processes is not guaranteed. + */ +struct rte_metrics_data_s { + uint16_t idx_last_set; + uint16_t cnt_stats; + struct rte_metrics_meta_s metadata[RTE_METRICS_MAX_METRICS]; + rte_spinlock_t lock; +}; + + +void +rte_metrics_init(void) +{ + struct rte_metrics_data_s *stats; + const struct rte_memzone *memzone; + + if (rte_eal_process_type() != RTE_PROC_PRIMARY) + return; + + memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME); + if (memzone != NULL) + return; + memzone = rte_memzone_reserve(RTE_METRICS_MEMZONE_NAME, + sizeof(struct rte_metrics_data_s), rte_socket_id(), 0); + if (memzone == NULL) + rte_exit(EXIT_FAILURE, "Unable to allocate stats memzone\n"); + stats = memzone->addr; + memset(stats, 0, sizeof(struct rte_metrics_data_s)); + rte_spinlock_init(&stats->lock); +} + + +int +rte_metrics_reg_metric(const char *name) +{ + const char *list_names[] = {name}; + + return rte_metrics_reg_metrics(list_names, 1); +} + + +int +rte_metrics_reg_metrics(const char **names, uint16_t cnt_names) +{ + struct rte_metrics_meta_s *entry; + struct rte_metrics_data_s *stats; + const struct rte_memzone *memzone; + uint16_t idx_name; + uint16_t idx_base; + + /* Some sanity checks */ + if (cnt_names < 1 || names == NULL) + return -EINVAL; + + rte_metrics_init(); + memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME); + if (memzone == NULL) + return -EIO; + stats = memzone->addr; + + if (stats->cnt_stats + cnt_names >= RTE_METRICS_MAX_METRICS) + return -ENOMEM; + + rte_spinlock_lock(&stats->lock); + + /* Overwritten later if this is actually first set.. */ + stats->metadata[stats->idx_last_set].idx_next_set = stats->cnt_stats; + + stats->idx_last_set = idx_base = stats->cnt_stats; + + for (idx_name = 0; idx_name < cnt_names; idx_name++) { + entry = &stats->metadata[idx_name + stats->cnt_stats]; + strncpy(entry->name, names[idx_name], + RTE_METRICS_MAX_NAME_LEN); + memset(entry->value, 0, sizeof(entry->value)); + entry->idx_next_stat = idx_name + stats->cnt_stats + 1; + } + entry->idx_next_stat = 0; + entry->idx_next_set = 0; + stats->cnt_stats += cnt_names; + + rte_spinlock_unlock(&stats->lock); + + return idx_base; +} + + +int +rte_metrics_update_metric(int port_id, uint16_t key, const uint64_t value) +{ + return rte_metrics_update_metrics(port_id, key, &value, 1); +} + + +int +rte_metrics_update_metrics(int port_id, + uint16_t key, + const uint64_t *values, + uint32_t count) +{ + struct rte_metrics_meta_s *entry; + struct rte_metrics_data_s *stats; + const struct rte_memzone *memzone; + uint16_t idx_metric; + uint16_t idx_value; + uint16_t cnt_setsize; + + if (port_id != RTE_METRICS_NONPORT && + (port_id < 0 || port_id > RTE_MAX_ETHPORTS)) + return -EINVAL; + + rte_metrics_init(); + memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME); + if (memzone == NULL) + return -EIO; + stats = memzone->addr; + + rte_spinlock_lock(&stats->lock); + idx_metric = key; + cnt_setsize = 1; + while (idx_metric < stats->cnt_stats) { + entry = &stats->metadata[idx_metric]; + if (entry->idx_next_stat == 0) + break; + cnt_setsize++; + idx_metric++; + } + /* Check update does not cross set border */ + if (count > cnt_setsize) { + rte_spinlock_unlock(&stats->lock); + return -ERANGE; + } + + if (port_id == RTE_METRICS_NONPORT) + for (idx_value = 0; idx_value < count; idx_value++) { + idx_metric = key + idx_value; + stats->metadata[idx_metric].nonport_value = + values[idx_value]; + } + else + for (idx_value = 0; idx_value < count; idx_value++) { + idx_metric = key + idx_value; + stats->metadata[idx_metric].value[port_id] = + values[idx_value]; + } + rte_spinlock_unlock(&stats->lock); + return 0; +} + + +int +rte_metrics_get_names(struct rte_metric_name *names, + uint16_t capacity) +{ + struct rte_metrics_data_s *stats; + const struct rte_memzone *memzone; + uint16_t idx_name; + int return_value; + + memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME); + /* If not allocated, fail silently */ + if (memzone == NULL) + return 0; + + stats = memzone->addr; + rte_spinlock_lock(&stats->lock); + if (names != NULL) { + if (capacity < stats->cnt_stats) { + rte_spinlock_unlock(&stats->lock); + return -ERANGE; + } + for (idx_name = 0; idx_name < stats->cnt_stats; idx_name++) + strncpy(names[idx_name].name, + stats->metadata[idx_name].name, + RTE_METRICS_MAX_NAME_LEN); + } + return_value = stats->cnt_stats; + rte_spinlock_unlock(&stats->lock); + return return_value; +} + + +int +rte_metrics_get_values(int port_id, + struct rte_stat_value *values, + uint16_t capacity) +{ + struct rte_metrics_meta_s *entry; + struct rte_metrics_data_s *stats; + const struct rte_memzone *memzone; + uint16_t idx_name; + int return_value; + + memzone = rte_memzone_lookup(RTE_METRICS_MEMZONE_NAME); + /* If not allocated, fail silently */ + if (memzone == NULL) + return 0; + stats = memzone->addr; + rte_spinlock_lock(&stats->lock); + + if (values != NULL) { + if (capacity < stats->cnt_stats) { + rte_spinlock_unlock(&stats->lock); + return -ERANGE; + } + for (idx_name = 0; idx_name < stats->cnt_stats; idx_name++) { + entry = &stats->metadata[idx_name]; + values[idx_name].key = idx_name; + values[idx_name].value = entry->value[port_id]; + } + } + return_value = stats->cnt_stats; + rte_spinlock_unlock(&stats->lock); + return return_value; +} diff --git a/lib/librte_metrics/rte_metrics.h b/lib/librte_metrics/rte_metrics.h new file mode 100644 index 0000000..6b75404 --- /dev/null +++ b/lib/librte_metrics/rte_metrics.h @@ -0,0 +1,204 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2016 Intel Corporation. All rights reserved. + * 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. + */ + +/** + * @file + * + * RTE Statistics module + * + * Statistic information is populated using callbacks, each of which + * is associated with one or more metric names. When queried, the + * callback is used to update all metric in the set at once. Currently + * only bulk querying of all metric is supported. + * + */ + +#ifndef _RTE_METRICS_H_ +#define _RTE_METRICS_H_ + +/** Maximum length of statistic name (including null-terminator) */ +#define RTE_METRICS_MAX_NAME_LEN 64 + +/** Used to indicate port-independent information */ +#define RTE_METRICS_NONPORT -1 + + +/** + * Statistic name + */ +struct rte_metric_name { + /** String describing statistic */ + char name[RTE_METRICS_MAX_NAME_LEN]; +}; + + +/** + * Statistic name. + */ +struct rte_stat_value { + /** Numeric identifier of statistic */ + uint16_t key; + /** Value for statistic */ + uint64_t value; +}; + + +/** + * Initialises statistic module. This only has to be explicitly called if you + * intend to use rte_metrics_reg_metric() or rte_metrics_reg_metrics() from a + * secondary process. + */ +void rte_metrics_init(void); + + +/** + * Register a statistic and its associated callback. + * + * @param name + * Statistic name + * + * @param callback + * Callback to use when fetching statistic + * + * @param data + * Data pointer to pass to callback + * + * @return + * - Zero or positive: Success + * - Negative: Failure + */ +int rte_metrics_reg_metric(const char *name); + +/** + * Register a set of statistic and their associated callback. + * + * @param names + * List of statistic names + * + * @param cnt_names + * Number of statistics in set + * + * @param callback + * Callback to use when fetching statsitics + * + * @param data + * Data pointer to pass to callback + * + * @return + * - Zero or positive: Success + * - Negative: Failure + */ +int rte_metrics_reg_metrics(const char **names, uint16_t cnt_names); + +/** + * Get statistic name-key lookup table. + * + * @param names + * Array of names to receive key names + * + * @param capacity + * Space available in names + * + * @return + * - Non-negative: Success (number of names) + * - Negative: Failure + */ +int rte_metrics_get_names( + struct rte_metric_name *names, + uint16_t capacity); + +/** + * Fetch statistics. + * + * @param port_id + * Port id to query + * + * @param values + * Array to receive values and their keys + * + * @param capacity + * Space available in values + * + * @return + * - Non-negative: Success (number of names) + * - Negative: Failure + */ +int rte_metrics_get_values( + int port_id, + struct rte_stat_value *values, + uint16_t capacity); + +/** + * Updates a statistic metric + * + * @param port_id + * Port to update statistics for + * @param key + * Id of statistic metric to update + * @param value + * New value + * + * @return + * - -EIO if unable to access shared statistics memory + * - Zero on success + */ +int rte_metrics_update_metric( + int port_id, + uint16_t key, + const uint64_t value); + +/** + * Updates a statistic metric set. Note that it is an error to try to + * update across a set boundary. + * + * @param port_id + * Port to update statistics for + * @param key + * Base id of statistics set to update + * @param values + * Set of new values + * @param count + * Number of new values + * + * @return + * - -ERANGE if count exceeds statistic set size + * - -EIO if upable to access shared statistics memory + * - Zero on success + */ +int rte_metrics_update_metrics( + int port_id, + uint16_t key, + const uint64_t *values, + uint32_t count); + +#endif diff --git a/lib/librte_metrics/rte_metrics_version.map b/lib/librte_metrics/rte_metrics_version.map new file mode 100644 index 0000000..a31a80a --- /dev/null +++ b/lib/librte_metrics/rte_metrics_version.map @@ -0,0 +1,13 @@ +DPDK_16.11 { + global: + + rte_metrics_get_names; + rte_metrics_get_values; + rte_metrics_init; + rte_metrics_reg_metric; + rte_metrics_reg_metrics; + rte_metrics_update_metric; + rte_metrics_update_metrics; + + local: *; +}; diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 51bc3b0..2db5427 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -98,6 +98,8 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_RING) += -lrte_ring _LDLIBS-$(CONFIG_RTE_LIBRTE_EAL) += -lrte_eal _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE) += -lrte_cmdline _LDLIBS-$(CONFIG_RTE_LIBRTE_CFGFILE) += -lrte_cfgfile +_LDLIBS-$(CONFIG_RTE_LIBRTE_METRICS) += -lrte_metrics + _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_BOND) += -lrte_pmd_bond _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += -lrte_pmd_xenvirt -lxenstore -- 2.5.5