From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by dpdk.org (Postfix) with ESMTP id 81AD61396 for ; Fri, 29 May 2015 17:45:09 +0200 (CEST) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga103.jf.intel.com with ESMTP; 29 May 2015 08:45:08 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.13,517,1427785200"; d="scan'208";a="737426275" Received: from unknown (HELO stargo) ([10.217.248.233]) by orsmga002.jf.intel.com with SMTP; 29 May 2015 08:45:05 -0700 Received: by stargo (sSMTP sendmail emulation); Fri, 29 May 2015 17:43:32 +0200 From: Maciej Gajdzica To: dev@dpdk.org Date: Fri, 29 May 2015 17:43:08 +0200 Message-Id: <1432914198-11812-2-git-send-email-maciejx.t.gajdzica@intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1432914198-11812-1-git-send-email-maciejx.t.gajdzica@intel.com> References: <1432914198-11812-1-git-send-email-maciejx.t.gajdzica@intel.com> Subject: [dpdk-dev] [PATCH 01/11] ip_pipeline: add parsing for config files with new syntax 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, 29 May 2015 15:45:12 -0000 New syntax of config files is needed for ip_pipeline example enhancements. Some old files are temporarily disabled in the Makefile. It is part of a bigger change. Signed-off-by: Pawel Wodkowski --- examples/ip_pipeline/Makefile | 27 +- examples/ip_pipeline/app.h | 586 ++++++++++ examples/ip_pipeline/config.c | 419 ------- examples/ip_pipeline/config_parse.c | 2071 +++++++++++++++++++++++++++++++++++ examples/ip_pipeline/cpu_core_map.c | 465 ++++++++ examples/ip_pipeline/cpu_core_map.h | 69 ++ examples/ip_pipeline/main.c | 130 +-- examples/ip_pipeline/main.h | 298 ----- examples/ip_pipeline/pipeline.h | 79 ++ examples/ip_pipeline/pipeline_ops.h | 247 +++++ 10 files changed, 3539 insertions(+), 852 deletions(-) create mode 100644 examples/ip_pipeline/app.h delete mode 100644 examples/ip_pipeline/config.c create mode 100644 examples/ip_pipeline/config_parse.c create mode 100644 examples/ip_pipeline/cpu_core_map.c create mode 100644 examples/ip_pipeline/cpu_core_map.h delete mode 100644 examples/ip_pipeline/main.h create mode 100644 examples/ip_pipeline/pipeline.h create mode 100644 examples/ip_pipeline/pipeline_ops.h diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile index e70fdc7..2f224cc 100644 --- a/examples/ip_pipeline/Makefile +++ b/examples/ip_pipeline/Makefile @@ -43,20 +43,21 @@ APP = ip_pipeline # all source are stored in SRCS-y SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) := main.c -SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config.c -SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += init.c -SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += cmdline.c -SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_rx.c -SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_tx.c -SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_flow_classification.c -SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_routing.c -SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_passthrough.c -SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_ipv4_frag.c -SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_ipv4_ras.c +SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += config_parse.c +#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += init.c +SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += cpu_core_map.c +#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += cmdline.c +#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_rx.c +#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_tx.c +#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_flow_classification.c +#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_routing.c +#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_passthrough.c +#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_ipv4_frag.c +#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_ipv4_ras.c -ifeq ($(CONFIG_RTE_LIBRTE_ACL),y) -SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_firewall.c -endif +#ifeq ($(CONFIG_RTE_LIBRTE_ACL),y) +#SRCS-$(CONFIG_RTE_LIBRTE_PIPELINE) += pipeline_firewall.c +#endif CFLAGS += -O3 CFLAGS += $(WERROR_FLAGS) diff --git a/examples/ip_pipeline/app.h b/examples/ip_pipeline/app.h new file mode 100644 index 0000000..9ff7454 --- /dev/null +++ b/examples/ip_pipeline/app.h @@ -0,0 +1,586 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2015 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. + */ + +#ifndef __INCLUDE_APP_H__ +#define __INCLUDE_APP_H__ + +#include +#include + +#include +#include +#include +#include + +#include + +#include "cpu_core_map.h" +#include "pipeline.h" + +#define APP_CHECK(exp, fmt, ...) do { \ + if (!(exp)) { \ + fprintf( stderr, fmt "\n", ## __VA_ARGS__); \ + abort(); \ + } \ +} while (0) + +#ifndef APP_APPNAME_SIZE +#define APP_APPNAME_SIZE 256 +#endif + +#ifndef APP_FILE_NAME_SIZE +#define APP_FILE_NAME_SIZE 256 +#endif + +#define APP_MAX_PIPELINE_ARGS PIPELINE_MAX_ARGS + +#define APP_PARAM_NAME_SIZE PIPELINE_NAME_SIZE + +#ifndef APP_MAX_SCHED_SUBPORTS +#define APP_MAX_SCHED_SUBPORTS 8 +#endif + +#ifndef APP_MAX_SCHED_PIPES +#define APP_MAX_SCHED_PIPES 4096 +#endif + +#ifndef APP_EAL_ARG_BUFFER_SIZE +#define APP_EAL_ARG_BUFFER_SIZE 1024 +#endif + +#ifndef APP_EAL_ARGC +#define APP_EAL_ARGC 16 +#endif + +#ifndef APP_MAX_MEMPOOLS +#define APP_MAX_MEMPOOLS 8 +#endif + +#ifndef APP_MAX_LINKS +#define APP_MAX_LINKS 16 +#endif + +#ifndef APP_LINK_MAX_HWQ_IN +#define APP_LINK_MAX_HWQ_IN 64 +#endif + +#ifndef APP_LINK_MAX_HWQ_OUT +#define APP_LINK_MAX_HWQ_OUT 64 +#endif + +#define APP_MAX_HWQ_IN APP_MAX_LINKS * APP_LINK_MAX_HWQ_IN + +#define APP_MAX_HWQ_OUT APP_MAX_LINKS * APP_LINK_MAX_HWQ_OUT + +#ifndef APP_MAX_PKTQ_SWQ +#define APP_MAX_PKTQ_SWQ 256 +#endif + +#define APP_MAX_PKTQ_TM APP_MAX_LINKS + +#ifndef APP_MAX_PKTQ_SOURCE +#define APP_MAX_PKTQ_SOURCE 16 +#endif + +#ifndef APP_MAX_PKTQ_SINK +#define APP_MAX_PKTQ_SINK 16 +#endif + +#ifndef APP_MAX_MSGQ +#define APP_MAX_MSGQ 64 +#endif + +#ifndef APP_MAX_PIPELINES +#define APP_MAX_PIPELINES 64 +#endif + +#ifndef APP_MAX_THREAD_PIPELINES +#define APP_MAX_THREAD_PIPELINES 16 +#endif + +#ifndef APP_PIPELINE_TYPE_SIZE +#define APP_PIPELINE_TYPE_SIZE 64 +#endif + +#define APP_MAX_PIPELINE_PKTQ_IN PIPELINE_MAX_PORT_IN +#define APP_MAX_PIPELINE_PKTQ_OUT PIPELINE_MAX_PORT_OUT +#define APP_MAX_PIPELINE_MSGQ_IN PIPELINE_MAX_MSGQ_IN +#define APP_MAX_PIPELINE_MSGQ_OUT PIPELINE_MAX_MSGQ_OUT + +#ifndef APP_MAX_PIPELINE_TYPES +#define APP_MAX_PIPELINE_TYPES 64 +#endif + +#ifndef APP_MAX_THREADS +#define APP_MAX_THREADS RTE_MAX_LCORE +#endif + +#ifndef APP_MAX_CMDS +#define APP_MAX_CMDS 64 +#endif + +#define APP_PARAM_VALID(obj) ((obj)->name[0] != '\0') + +#define APP_PARAM_COUNT(obj_array, n_objs) \ +{ \ + size_t i; \ + \ + n_objs = 0; \ + for (i = 0; i < RTE_DIM(obj_array); i++) \ + if (APP_PARAM_VALID(&((obj_array)[i]))) \ + n_objs ++; \ +} + +/** + * Find object of name *name* in *obj_array* which is constant size array of + * elements that have field *name*. + * + * @param obj_array + * Constant size array + * @param name + * name of object to find. + * @return + * Pointer to object in *obj_array* or NULL if not found. + */ +#define APP_PARAM_FIND(obj_array, key) \ +({ \ + ssize_t obj_idx; \ + const ssize_t obj_count = RTE_DIM(obj_array); \ + \ + for (obj_idx = 0; obj_idx < obj_count; obj_idx++) { \ + if (!APP_PARAM_VALID(&((obj_array)[obj_idx]))) \ + continue; \ + \ + if (strcmp(key, (obj_array)[obj_idx].name) == 0) \ + break; \ + } \ + obj_idx < obj_count ? obj_idx : -ENOENT; \ +}) + +#define APP_PARAM_FIND_BY_ID(obj_array, prefix, id, obj) \ +do { \ + char name[APP_PARAM_NAME_SIZE]; \ + ssize_t pos; \ + \ + sprintf(name, prefix "%u", id); \ + pos = APP_PARAM_FIND(obj_array, name); \ + obj = (pos < 0)? NULL : &((obj_array)[pos]); \ +} while (0) + +#define APP_PARAM_GET_ID(obj, prefix, id) \ +do \ + sscanf(obj->name, prefix "%u", &id); \ +while (0) \ + +/** + * Set name of first free slot in *obj_array* to *obj_name*, which makes it + * valid. If object already exist return index to existing object. + * + * @param obj_array + * Constant size array of objects. + * @param obj_name + * Name of ne object. + * @return + * ssize_t - Index to object or negative error code: + * -EINVAL *name* is too long + * -ENOMEM no free slot found. + */ +#define APP_PARAM_ADD(obj_array, obj_name) \ +({ \ + ssize_t obj_idx; \ + ssize_t ret; \ + const ssize_t obj_count = RTE_DIM(obj_array); \ + \ + obj_idx = APP_PARAM_FIND(obj_array, obj_name); \ + if (obj_idx < 0) { \ + for (obj_idx = 0; obj_idx < obj_count; obj_idx++) { \ + if (!APP_PARAM_VALID(&((obj_array)[obj_idx]))) \ + break; \ + } \ + \ + if (obj_idx < obj_count) { \ + ret = snprintf((obj_array)[obj_idx].name, \ + RTE_DIM((obj_array)[obj_idx].name), \ + "%s", obj_name); \ + if (ret > (ssize_t)RTE_DIM((obj_array)[obj_idx].name)) \ + obj_idx = -EINVAL; \ + } else \ + obj_idx = -ENOMEM; \ + } \ + obj_idx; \ +}) + + +#define APP_HWQ_IN_IDX(link, q) ((link) * APP_LINK_MAX_HWQ_IN + (q)) +#define APP_HWQ_OUT_IDX(link, q) ((link) * APP_LINK_MAX_HWQ_OUT + (q)) + +#define APP_HWQ_IN_LINK_ID(id) (id / APP_LINK_MAX_HWQ_IN) +#define APP_HWQ_IN_QUEUE_ID(id) (id % APP_LINK_MAX_HWQ_IN) + +#define APP_HWQ_OUT_LINK_ID(id) (id / APP_LINK_MAX_HWQ_OUT) +#define APP_HWQ_OUT_QUEUE_ID(id) (id % APP_LINK_MAX_HWQ_OUT) + + +struct app_mempool_params { + char name[APP_PARAM_NAME_SIZE]; + uint32_t parsed; /* Used to check if object was parsed or only referenced */ + uint32_t buffer_size; + uint32_t pool_size; + uint32_t cache_size; + uint32_t cpu_socket_id; +}; + +struct app_link_params { + char name[APP_PARAM_NAME_SIZE]; + uint32_t parsed; /* Used to check if object was parsed or only referenced */ + uint32_t pmd_id; /* Generated based on port mask */ + uint32_t arp_q; /* 0 = Disabled (packets go to default queue 0) */ + uint32_t tcp_syn_local_q; /* 0 = Disabled (packets go to default queue 0) */ + uint32_t ip_local_q; /* 0 = Disabled (packets go to default queue 0) */ + uint32_t tcp_local_q; /* 0 = Disabled (packets go to default queue 0) */ + uint32_t udp_local_q; /* 0 = Disabled (packets go to default queue 0) */ + uint32_t sctp_local_q; /* 0 = Disabled (packets go to default queue 0) */ + uint32_t state; /* DOWN = 0, UP = 1 */ + uint32_t ip; /* 0 = Invalid */ + uint32_t depth; /* Valid only when IP is valid */ + uint64_t mac_addr; /* Read from HW */ + + struct rte_eth_conf conf; + uint8_t promisc; +}; + +struct app_pktq_hwq_in_params { + char name[APP_PARAM_NAME_SIZE]; + uint32_t parsed; /* Used to check if object was parsed or only referenced */ + uint32_t mempool_id; /* Position in the app->mempool_params */ + uint32_t size; + uint32_t burst; + + struct rte_eth_rxconf conf; +}; + +struct app_pktq_hwq_out_params { + char name[APP_PARAM_NAME_SIZE]; + uint32_t parsed; /* Used to check if object was parsed or only referenced */ + uint32_t size; + uint32_t burst; + uint32_t dropless; + uint64_t n_retries; + struct rte_eth_txconf conf; +}; + +struct app_pktq_swq_params { + char name[APP_PARAM_NAME_SIZE]; + uint32_t parsed; /* Used to check if object was parsed or only referenced */ + uint32_t size; + uint32_t burst_read; + uint32_t burst_write; + uint32_t dropless; + uint64_t n_retries; + uint32_t cpu_socket_id; +}; + +struct app_pktq_tm_params { + char name[APP_PARAM_NAME_SIZE]; + uint32_t parsed; /* Used to check if object was parsed or only referenced */ + char file_name[APP_FILE_NAME_SIZE]; + struct rte_sched_port_params sched_port_params; + struct rte_sched_subport_params + sched_subport_params[APP_MAX_SCHED_SUBPORTS]; + struct rte_sched_pipe_params + sched_pipe_profiles[RTE_SCHED_PIPE_PROFILES_PER_PORT]; + int sched_pipe_to_profile[APP_MAX_SCHED_SUBPORTS * APP_MAX_SCHED_PIPES]; + uint32_t burst_read; + uint32_t burst_write; +}; + +struct app_pktq_source_params { + char name[APP_PARAM_NAME_SIZE]; + uint32_t parsed; /* Used to check if object was parsed or only referenced */ + uint32_t mempool_id; /* Position in the app->mempool_params array */ + uint32_t burst; +}; + +struct app_pktq_sink_params { + char name[APP_PARAM_NAME_SIZE]; + uint8_t parsed; /* Used to check if object was parsed or only referenced */ +}; + +struct app_msgq_params { + char name[APP_PARAM_NAME_SIZE]; + uint32_t parsed; /* Used to check if object was parsed or only referenced */ + uint32_t size; + uint32_t cpu_socket_id; +}; + +enum app_pktq_in_type { + APP_PKTQ_IN_HWQ, + APP_PKTQ_IN_SWQ, + APP_PKTQ_IN_TM, + APP_PKTQ_IN_SOURCE, +}; + +struct app_pktq_in_params { + enum app_pktq_in_type type; + uint32_t id; /* Position in the appropriate app array */ +}; + +enum app_pktq_out_type { + APP_PKTQ_OUT_HWQ, + APP_PKTQ_OUT_SWQ, + APP_PKTQ_OUT_TM, + APP_PKTQ_OUT_SINK, +}; + +struct app_pktq_out_params { + enum app_pktq_out_type type; + uint32_t id; /* Position in the appropriate app array */ +}; + +struct app_pipeline_params { + char name[APP_PARAM_NAME_SIZE]; + uint8_t parsed; + + char type[APP_PIPELINE_TYPE_SIZE]; + + uint32_t socket_id; + uint32_t core_id; + uint32_t hyper_th_id; + + struct app_pktq_in_params pktq_in[APP_MAX_PIPELINE_PKTQ_IN]; + struct app_pktq_out_params pktq_out[APP_MAX_PIPELINE_PKTQ_OUT]; + uint32_t msgq_in[APP_MAX_PIPELINE_MSGQ_IN]; + uint32_t msgq_out[APP_MAX_PIPELINE_MSGQ_OUT]; + + uint32_t n_pktq_in; + uint32_t n_pktq_out; + uint32_t n_msgq_in; + uint32_t n_msgq_out; + + uint32_t timer_period; + + char *args_name[APP_MAX_PIPELINE_ARGS]; + char *args_value[APP_MAX_PIPELINE_ARGS]; + uint32_t n_args; +}; + +struct app_pipeline_data { + void *be; + void *fe; + uint64_t timer_period; +}; + +struct app_thread_pipeline_data { + void *be; + pipeline_op_run f_run; + pipeline_op_timer f_timer; + uint64_t timer_period; + uint64_t deadline; +}; + +struct app_thread_data { + struct app_thread_pipeline_data regular[APP_MAX_THREAD_PIPELINES]; + struct app_thread_pipeline_data custom[APP_MAX_THREAD_PIPELINES]; + + uint32_t n_regular; + uint32_t n_custom; + + uint64_t deadline; +}; + +struct app_params { + /* Config */ + char app_name[APP_APPNAME_SIZE]; + char config_file[APP_FILE_NAME_SIZE]; + char script_file[APP_FILE_NAME_SIZE]; + + char *eal_argv[1 + APP_EAL_ARGC]; + int eal_argc; + + uint64_t port_mask; + + struct app_mempool_params mempool_params[APP_MAX_MEMPOOLS]; + struct app_link_params link_params[APP_MAX_LINKS]; + struct app_pktq_hwq_in_params hwq_in_params[APP_MAX_HWQ_IN]; + struct app_pktq_hwq_out_params hwq_out_params[APP_MAX_HWQ_OUT]; + struct app_pktq_swq_params swq_params[APP_MAX_PKTQ_SWQ]; + struct app_pktq_tm_params tm_params[APP_MAX_PKTQ_TM]; + struct app_pktq_source_params source_params[APP_MAX_PKTQ_SOURCE]; + struct app_pktq_sink_params sink_params[APP_MAX_PKTQ_SINK]; + struct app_msgq_params msgq_params[APP_MAX_MSGQ]; + struct app_pipeline_params pipeline_params[APP_MAX_PIPELINES]; + + uint32_t n_mempools; + uint32_t n_links; + uint32_t n_pktq_hwq_in; + uint32_t n_pktq_hwq_out; + uint32_t n_pktq_swq; + uint32_t n_pktq_tm; + uint32_t n_pktq_source; + uint32_t n_pktq_sink; + uint32_t n_msgq; + uint32_t n_pipelines; + + /* Init */ + struct cpu_core_map *core_map; + uint64_t core_mask; + struct rte_mempool *mempool[APP_MAX_MEMPOOLS]; + struct rte_ring *swq[APP_MAX_PKTQ_SWQ]; + struct rte_sched_port *tm[APP_MAX_PKTQ_TM]; + struct rte_ring *msgq[APP_MAX_MSGQ]; + struct pipeline_type pipeline_type[APP_MAX_PIPELINE_TYPES]; + struct app_pipeline_data pipeline_data[APP_MAX_PIPELINES]; + struct app_thread_data thread_data[APP_MAX_THREADS]; + cmdline_parse_ctx_t cmds[APP_MAX_CMDS + 1]; + + uint32_t n_pipeline_types; + uint32_t n_cmds; +}; + +static inline uint32_t +app_n_hwq_in_get(struct app_params *app, uint32_t link_id) +{ + uint32_t max_hwq_in = 0; + uint32_t i; + + for (i = 0; i < APP_LINK_MAX_HWQ_IN; i++) { + struct app_pktq_hwq_in_params *p = &app->hwq_in_params[i]; + uint32_t rxq_link_id, rxq_queue_id; + + if (!APP_PARAM_VALID(p)) + continue; + + sscanf(p->name, "RXQ%u.%u", &rxq_link_id, &rxq_queue_id); + if (rxq_link_id != link_id) + continue; + + max_hwq_in++; + } + + return max_hwq_in; +} + +static inline uint32_t +app_n_hwq_out_get(struct app_params *app, uint32_t link_id) +{ + uint32_t max_hwq_out = 0; + uint32_t i; + + for (i = 0; i < APP_LINK_MAX_HWQ_OUT; i++) { + struct app_pktq_hwq_out_params *p = &app->hwq_out_params[i]; + uint32_t txq_link_id, txq_queue_id; + + if (!APP_PARAM_VALID(p)) + continue; + + sscanf(p->name, "TXQ%u.%u", &txq_link_id, &txq_queue_id); + if (txq_link_id != link_id) + continue; + + max_hwq_out++; + } + + return max_hwq_out; +} + +static inline struct app_link_params * +app_get_link_for_rxq(struct app_params *app, struct app_pktq_hwq_in_params *p) +{ + char link_name[APP_PARAM_NAME_SIZE]; + ssize_t link_param_idx; + uint32_t rxq_link_id, rxq_queue_id; + + sscanf(p->name, "RXQ%u.%u", &rxq_link_id, &rxq_queue_id); + sprintf(link_name, "LINK%u", rxq_link_id); + link_param_idx = APP_PARAM_FIND(app->link_params, link_name); + APP_CHECK((link_param_idx >= 0), + "Cannot find %s for %s", link_name, p->name); + + return &app->link_params[link_param_idx]; +} + +static inline struct app_link_params * +app_get_link_for_txq(struct app_params *app, struct app_pktq_hwq_out_params *p) +{ + char link_name[APP_PARAM_NAME_SIZE]; + ssize_t link_param_idx; + uint32_t txq_link_id, txq_queue_id; + + sscanf(p->name, "TXQ%u.%u", &txq_link_id, &txq_queue_id); + sprintf(link_name, "LINK%u", txq_link_id); + link_param_idx = APP_PARAM_FIND(app->link_params, link_name); + APP_CHECK((link_param_idx >= 0), + "Cannot find %s for %s", link_name, p->name); + + return &app->link_params[link_param_idx]; +} + +static inline struct app_link_params * +app_get_link_for_tm(struct app_params *app, struct app_pktq_tm_params *p_tm) +{ + char link_name[APP_PARAM_NAME_SIZE]; + uint32_t link_id; + ssize_t link_param_idx; + + sscanf(p_tm->name, "TM%u", &link_id); + sprintf(link_name, "LINK%u", link_id); + link_param_idx = APP_PARAM_FIND(app->link_params, link_name); + APP_CHECK((link_param_idx >=0), + "Cannot find %s for %s", link_name, p_tm->name); + + return &app->link_params[link_param_idx]; +} + +int app_config_init(struct app_params *app); + +int app_config_args(struct app_params *app, int argc, char **argv); + +int app_config_parse(struct app_params *app, const char *file_name); + +void app_config_save(struct app_params *app, const char *file_name); + +int app_config_check(struct app_params *app); + +int app_init(struct app_params *app); + +int app_thread(void *arg); + +int app_pipeline_type_register(struct app_params *app, struct pipeline_type *ptype); + +struct pipeline_type *app_pipeline_type_find(struct app_params *app, char *name); + +void app_link_up_internal(struct app_params *app, struct app_link_params *cp); + +void app_link_down_internal(struct app_params *app, struct app_link_params *cp); + +#endif diff --git a/examples/ip_pipeline/config.c b/examples/ip_pipeline/config.c deleted file mode 100644 index 9414a7b..0000000 --- a/examples/ip_pipeline/config.c +++ /dev/null @@ -1,419 +0,0 @@ -/*- - * BSD LICENSE - * - * Copyright(c) 2010-2014 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 -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "main.h" - -struct app_params app; - -static const char usage[] = - "Usage: %s EAL_OPTIONS-- -p PORT_MASK [-f CONFIG_FILE]\n"; - -void -app_print_usage(char *prgname) -{ - printf(usage, prgname); -} - -const char * -app_core_type_id_to_string(enum app_core_type id) -{ - switch (id) { - case APP_CORE_NONE: return "NONE"; - case APP_CORE_MASTER: return "MASTER"; - case APP_CORE_RX: return "RX"; - case APP_CORE_TX: return "TX"; - case APP_CORE_PT: return "PT"; - case APP_CORE_FC: return "FC"; - case APP_CORE_FW: return "FW"; - case APP_CORE_RT: return "RT"; - case APP_CORE_TM: return "TM"; - case APP_CORE_IPV4_FRAG: return "IPV4_FRAG"; - case APP_CORE_IPV4_RAS: return "IPV4_RAS"; - default: return NULL; - } -} - -int -app_core_type_string_to_id(const char *string, enum app_core_type *id) -{ - if (strcmp(string, "NONE") == 0) { - *id = APP_CORE_NONE; - return 0; - } - if (strcmp(string, "MASTER") == 0) { - *id = APP_CORE_MASTER; - return 0; - } - if (strcmp(string, "RX") == 0) { - *id = APP_CORE_RX; - return 0; - } - if (strcmp(string, "TX") == 0) { - *id = APP_CORE_TX; - return 0; - } - if (strcmp(string, "PT") == 0) { - *id = APP_CORE_PT; - return 0; - } - if (strcmp(string, "FC") == 0) { - *id = APP_CORE_FC; - return 0; - } - if (strcmp(string, "FW") == 0) { - *id = APP_CORE_FW; - return 0; - } - if (strcmp(string, "RT") == 0) { - *id = APP_CORE_RT; - return 0; - } - if (strcmp(string, "TM") == 0) { - *id = APP_CORE_TM; - return 0; - } - if (strcmp(string, "IPV4_FRAG") == 0) { - *id = APP_CORE_IPV4_FRAG; - return 0; - } - if (strcmp(string, "IPV4_RAS") == 0) { - *id = APP_CORE_IPV4_RAS; - return 0; - } - - return -1; -} - -static uint64_t -app_get_core_mask(void) -{ - uint64_t core_mask = 0; - uint32_t i; - - for (i = 0; i < RTE_MAX_LCORE; i++) { - if (rte_lcore_is_enabled(i) == 0) - continue; - - core_mask |= 1LLU << i; - } - - return core_mask; -} - -static int -app_install_coremask(uint64_t core_mask) -{ - uint32_t n_cores, i; - - for (n_cores = 0, i = 0; i < RTE_MAX_LCORE; i++) - if (app.cores[i].core_type != APP_CORE_NONE) - n_cores++; - - if (n_cores != app.n_cores) { - rte_panic("Number of cores in COREMASK should be %u instead " - "of %u\n", n_cores, app.n_cores); - return -1; - } - - for (i = 0; i < RTE_MAX_LCORE; i++) { - uint32_t core_id; - - if (app.cores[i].core_type == APP_CORE_NONE) - continue; - - core_id = __builtin_ctzll(core_mask); - core_mask &= ~(1LLU << core_id); - - app.cores[i].core_id = core_id; - } - - return 0; -} -static int -app_install_cfgfile(const char *file_name) -{ - struct rte_cfgfile *file; - uint32_t n_cores, i; - - memset(app.cores, 0, sizeof(app.cores)); - - if (file_name[0] == '\0') - return -1; - - file = rte_cfgfile_load(file_name, 0); - if (file == NULL) { - rte_panic("Config file %s not found\n", file_name); - return -1; - } - - n_cores = (uint32_t) rte_cfgfile_num_sections(file, "core", - strnlen("core", 5)); - if (n_cores < app.n_cores) { - rte_panic("Config file parse error: not enough cores specified " - "(%u cores missing)\n", app.n_cores - n_cores); - return -1; - } - if (n_cores > app.n_cores) { - rte_panic("Config file parse error: too many cores specified " - "(%u cores too many)\n", n_cores - app.n_cores); - return -1; - } - - for (i = 0; i < n_cores; i++) { - struct app_core_params *p = &app.cores[i]; - char section_name[16]; - const char *entry; - uint32_t j; - - /* [core X] */ - snprintf(section_name, sizeof(section_name), "core %u", i); - if (!rte_cfgfile_has_section(file, section_name)) { - rte_panic("Config file parse error: core IDs are not " - "sequential (core %u missing)\n", i); - return -1; - } - - /* type */ - entry = rte_cfgfile_get_entry(file, section_name, "type"); - if (!entry) { - rte_panic("Config file parse error: core %u type not " - "defined\n", i); - return -1; - } - if ((app_core_type_string_to_id(entry, &p->core_type) != 0) || - (p->core_type == APP_CORE_NONE)) { - rte_panic("Config file parse error: core %u type " - "error\n", i); - return -1; - } - - /* queues in */ - entry = rte_cfgfile_get_entry(file, section_name, "queues in"); - if (!entry) { - rte_panic("Config file parse error: core %u queues in " - "not defined\n", i); - return -1; - } - - for (j = 0; (j < APP_MAX_SWQ_PER_CORE) && (entry != NULL); - j++) { - char *next; - - p->swq_in[j] = (uint32_t) strtol(entry, &next, 10); - if (next == entry) - break; - entry = next; - } - - if ((j != APP_MAX_SWQ_PER_CORE) || (*entry != '\0')) { - rte_panic("Config file parse error: core %u queues in " - "error\n", i); - return -1; - } - - /* queues out */ - entry = rte_cfgfile_get_entry(file, section_name, "queues out"); - if (!entry) { - rte_panic("Config file parse error: core %u queues out " - "not defined\n", i); - return -1; - } - - for (j = 0; (j < APP_MAX_SWQ_PER_CORE) && (entry != NULL); - j++) { - char *next; - - p->swq_out[j] = (uint32_t) strtol(entry, &next, 10); - if (next == entry) - break; - entry = next; - } - if ((j != APP_MAX_SWQ_PER_CORE) || (*entry != '\0')) { - rte_panic("Config file parse error: core %u queues out " - "error\n", i); - return -1; - } - } - - rte_cfgfile_close(file); - - return 0; -} - -void app_cores_config_print(void) -{ - uint32_t i; - - for (i = 0; i < RTE_MAX_LCORE; i++) { - struct app_core_params *p = &app.cores[i]; - uint32_t j; - - if (app.cores[i].core_type == APP_CORE_NONE) - continue; - - printf("---> core %u: id = %u type = %6s [", i, p->core_id, - app_core_type_id_to_string(p->core_type)); - for (j = 0; j < APP_MAX_SWQ_PER_CORE; j++) - printf("%2d ", (int) p->swq_in[j]); - - printf("] ["); - for (j = 0; j < APP_MAX_SWQ_PER_CORE; j++) - printf("%2d ", (int) p->swq_out[j]); - - printf("]\n"); - } -} - -static int -app_install_port_mask(const char *arg) -{ - char *end = NULL; - uint64_t port_mask; - uint32_t i; - - if (arg[0] == '\0') - return -1; - - port_mask = strtoul(arg, &end, 16); - if ((end == NULL) || (*end != '\0')) - return -2; - - if (port_mask == 0) - return -3; - - app.n_ports = 0; - for (i = 0; i < 64; i++) { - if ((port_mask & (1LLU << i)) == 0) - continue; - - if (app.n_ports >= APP_MAX_PORTS) - return -4; - - app.ports[app.n_ports] = i; - app.n_ports++; - } - - if (!rte_is_power_of_2(app.n_ports)) - return -5; - - return 0; -} - -int -app_parse_args(int argc, char **argv) -{ - int opt, ret; - char **argvopt; - int option_index; - char *prgname = argv[0]; - static struct option lgopts[] = { - {NULL, 0, 0, 0} - }; - uint64_t core_mask = app_get_core_mask(); - - app.n_cores = __builtin_popcountll(core_mask); - - argvopt = argv; - while ((opt = getopt_long(argc, argvopt, "p:f:", lgopts, - &option_index)) != EOF) { - switch (opt) { - case 'p': - if (app_install_port_mask(optarg) != 0) - rte_panic("PORT_MASK should specify a number " - "of ports that is power of 2 less or " - "equal to %u\n", APP_MAX_PORTS); - break; - - case 'f': - app_install_cfgfile(optarg); - break; - - default: - return -1; - } - } - - app_install_coremask(core_mask); - - app_cores_config_print(); - - if (optind >= 0) - argv[optind - 1] = prgname; - - ret = optind - 1; - optind = 0; /* reset getopt lib */ - - return ret; -} diff --git a/examples/ip_pipeline/config_parse.c b/examples/ip_pipeline/config_parse.c new file mode 100644 index 0000000..d6242da --- /dev/null +++ b/examples/ip_pipeline/config_parse.c @@ -0,0 +1,2071 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2015 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 + +#include +#include +#include + +#include "app.h" + +/** + * Default config values + **/ + +#define DEFAULT_CONFIG_FILE "./config/ip_pipeline.cfg" + +static const struct app_mempool_params mempool_params_default = { + .parsed = 0, + .buffer_size = 2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM, + .pool_size = 32 * 1024, + .cache_size = 256, + .cpu_socket_id = 0, +}; + +static const struct app_link_params link_params_default = { + .parsed = 0, + .pmd_id = 0, + .arp_q = 0, + .tcp_syn_local_q = 0, + .ip_local_q = 0, + .tcp_local_q = 0, + .udp_local_q = 0, + .sctp_local_q = 0, + .state = 0, + .ip = 0, + .depth = 0, + .mac_addr = 0, + + .conf = { + .link_speed = 0, + .link_duplex = 0, + .rxmode = { + .mq_mode = ETH_MQ_RX_NONE, + + .header_split = 0, /* Header split */ + .hw_ip_checksum = 0, /* IP checksum offload */ + .hw_vlan_filter = 0, /* VLAN filtering */ + .hw_vlan_strip = 0, /* VLAN strip */ + .hw_vlan_extend = 0, /* Extended VLAN */ + .jumbo_frame = 0, /* Jumbo frame support */ + .hw_strip_crc = 0, /* CRC strip by HW */ + .enable_scatter = 0, /* Scattered packets RX handler */ + + .max_rx_pkt_len = 9000, /* Jumbo frame max packet length */ + .split_hdr_size = 0, /* Header split buffer size */ + }, + .txmode = { + .mq_mode = ETH_MQ_TX_NONE, + }, + .lpbk_mode = 0, + }, + + .promisc = 1, +}; + +static const struct app_pktq_hwq_in_params default_hwq_in_params = { + .parsed = 0, + .mempool_id = 0, + .size = 128, + .burst = 32, + + .conf = { + .rx_thresh = { + .pthresh = 8, + .hthresh = 8, + .wthresh = 4, + }, + .rx_free_thresh = 64, + .rx_drop_en = 0, + .rx_deferred_start = 0, + } +}; + +static const struct app_pktq_hwq_out_params default_hwq_out_params = { + .parsed = 0, + .size = 512, + .burst = 32, + .dropless = 0, + .n_retries = 0, + + .conf = { + .tx_thresh = { + .pthresh = 36, + .hthresh = 0, + .wthresh = 0, + }, + .tx_rs_thresh = 0, + .tx_free_thresh = 0, + .txq_flags = ETH_TXQ_FLAGS_NOMULTSEGS | ETH_TXQ_FLAGS_NOOFFLOADS, + .tx_deferred_start = 0, + } +}; + +static const struct app_pktq_swq_params default_swq_params = { + .parsed = 0, + .size = 256, + .burst_read = 32, + .burst_write = 32, + .dropless = 0, + .n_retries = 0, + .cpu_socket_id = 0, +}; + +struct app_pktq_tm_params default_tm_params = { + .parsed = 0, + .burst_read = 64, + .burst_write = 32, +}; + +struct app_pktq_source_params default_source_params = { + .parsed = 0, + .mempool_id = 0, + .burst = 32, +}; + +struct app_pktq_sink_params default_sink_params = { + .parsed = 0, +}; + +struct app_msgq_params default_msgq_params = { + .parsed = 0, + .size = 64, + .cpu_socket_id = 0, +}; + +struct app_pipeline_params default_pipeline_params = { + .parsed = 0, + .socket_id = 0, + .core_id = 0, + .hyper_th_id = 0, + .n_pktq_in = 0, + .n_pktq_out = 0, + .n_msgq_in = 0, + .n_msgq_out = 0, + .timer_period = 1, + .n_args = 0, +}; + +static const char app_usage[] = + "Usage: %s [-f CONFIG_FILE] [-s SCRIPT_FILE] -p PORT_MASK \n" + "\n" + "Arguments:\n" + "\t-f CONFIG_FILE: Default config file is " DEFAULT_CONFIG_FILE "\n" + "\t-p PORT_MASK: Mask of NIC port IDs in hexadecimal format\n" + "\t-s SCRIPT_FILE: No CLI script file is run when not specified\n" + "\n"; + +static void +app_print_usage(char *prgname) +{ + rte_exit(0, app_usage, prgname); +} + +#define skip_white_spaces(pos) \ +({ \ + __typeof__(pos) _p = (pos); \ + for ( ; isspace(*_p); _p++) \ + ; \ + _p; \ +}) + +#define PARSER_IMPLICIT_PARAM_ADD_CHECK(result, section_name) \ +do { \ + APP_CHECK(result != -EINVAL, \ + "CFG: [%s] name too long", section_name); \ + APP_CHECK(result != -ENOMEM, \ + "CFG: [%s] too much sections", section_name); \ + APP_CHECK(result >= 0, \ + "CFG: [%s] Unknown error while adding '%s'", section_name, \ + section_name); \ +} while (0) + +#define PARSER_PARAM_ADD_CHECK(result, params_array, section_name) \ +do { \ + APP_CHECK((result != -EINVAL), \ + "CFG: [%s] name too long", section_name); \ + APP_CHECK((result != -ENOMEM), \ + "CFG: [%s] too much sections", section_name); \ + APP_CHECK(((result >= 0) && (params_array)[result].parsed == 0), \ + "CFG: [%s] duplicate section", section_name); \ + APP_CHECK((result >= 0), \ + "CFG: [%s] Unknown error while adding '%s'", section_name, \ + section_name); \ +} while (0) + +static int +parser_read_arg_bool(const char *p) +{ + int val; + p = skip_white_spaces(p); + if (strstr(p, "yes") == p) { + val = 1; + p += 3; + } else if (strstr(p, "no") == p) { + val = 0; + p += 2; + } else + return -EINVAL; + + p = skip_white_spaces(p); + if (*p != '\0') + return -EINVAL; + + return val; +} + +static const struct rte_cfgfile_entry2 ** +parser_get_section_entries(struct rte_cfgfile *cfg, const char *sect_name) +{ + const struct rte_cfgfile_entry2 **entries; + int ent_cnt, ret; + + ent_cnt = rte_cfgfile_section_num_entries(cfg, sect_name); + APP_CHECK(ent_cnt > 0, "CFG: [%s] not entires (res=%d)", sect_name, -ent_cnt); + + entries = malloc((ent_cnt + 1) * sizeof(struct rte_cfgfile_entry2 *)); + APP_CHECK(entries != NULL, "CFG: [%s] Out of memory", sect_name); + + ret = rte_cfgfile_section_entries_v21(cfg, sect_name, entries, ent_cnt); + APP_CHECK(ret == ent_cnt, "CFG: [%s] failed to get entries", sect_name); + + entries[ent_cnt] = NULL; + return entries; +} + +static int +parser_read_uint64(uint64_t *value, const char *p) +{ + char *next; + uint64_t val; + + p = skip_white_spaces(p); + if (!isdigit(*p)) + return -EINVAL; + + val = strtoul(p, &next, 10); + if (p == next) + return -EINVAL; + + p = next; + switch (*p) { + case 'T': + val *= 1024ULL; + /* fall trought */ + case 'G': + val *= 1024ULL; + /* fall trought */ + case 'M': + val *= 1024ULL; + /* fall trought */ + case 'k': + case 'K': + val *= 1024ULL; + p++; + break; + } + + p = skip_white_spaces(p); + if (*p != '\0') + return -EINVAL; + + *value = val; + return 0; +} + +static int +parser_read_uint32(uint32_t *value, const char *p) +{ + uint64_t val = 0; + int ret = parser_read_uint64(&val, p); + + if (ret < 0) + return ret; + else if (val > UINT32_MAX) + return -ERANGE; + + *value = val; + return 0; +} + +static int +parse_pipeline_core(uint32_t *socket, uint32_t *core, uint32_t *ht, + const char *entry) +{ + size_t num_len; + char num[8]; + + uint32_t s = 0, c = 0, h = 0, val; + uint8_t s_parsed = 0, c_parsed = 0, h_parsed = 0; + const char *next = skip_white_spaces(entry); + char type; + + /* Expect or [sX][cY][h]. At least one parameter is required. */ + while (*next != '\0') { + /* If everything parsed nothing should left */ + if (s_parsed && c_parsed && h_parsed) + return -EINVAL; + + type = *next; + switch(type) { + case 's': + case 'S': + if (s_parsed) + return -EINVAL; + s_parsed = 1; + next++; + break; + case 'c': + case 'C': + if (c_parsed) + return -EINVAL; + c_parsed = 1; + next++; + break; + case 'h': + case 'H': + if (h_parsed) + return -EINVAL; + h_parsed = 1; + next++; + break; + default: + /* If it start from digit it must be only core id. */ + if (!isdigit(*next) || s_parsed || c_parsed || h_parsed) + return -EINVAL; + + type = 'C'; + } + + for (num_len = 0; *next != '\0'; next++, num_len++) { + if (num_len == RTE_DIM(num)) + return -EINVAL; + + if (!isdigit(*next)) + break; + + num[num_len] = *next; + } + + if (num_len == 0 && type != 'h') + return -EINVAL; + + num[num_len] = '\0'; + val = strtol(num, NULL, 10); + + h = 0; + switch(type) { + case 's': + case 'S': + s = val; + break; + case 'c': + case 'C': + c = val; + if (type == 'C' && *next != '\0') + return -EINVAL; + + break; + case 'h': + case 'H': + h = 1; + break; + } + } + + *socket = s; + *core = c; + *ht = h; + return 0; +} + +static size_t +skip_digits(const char *src) +{ + size_t i; + + for (i = 0; isdigit(src[i]); i++) + ; + + return i; +} + +static int +validate_name(const char *name, const char *prefix, int num) +{ + size_t i, j; + + for( i = 0; name[i] != '\0' && prefix[i] != '\0'; i++) { + if (name[i] != prefix[i]) + return -1; + } + + if (prefix[i] != '\0') + return -1; + + if (!num) { + if (name[i] != '\0') + return -1; + else + return 0; + } + + if (num == 2) { + j = skip_digits(&name[i]); + i += j; + if (j == 0 || name[i] != '.') + return -1; + i ++; + } + + if (num == 1) { + j = skip_digits(&name[i]); + i += j; + if (j == 0 || name[i] != '\0') + return -1; + } + + return 0; +} + +static int +parse_pipeline_pktq_in(struct app_params *app, + struct app_pipeline_params *p, const char *value) +{ + const char *next = value; + char *end; + char name[APP_PARAM_NAME_SIZE]; + size_t name_len; + + while (*next != '\0') { + enum app_pktq_in_type type; + int id; + + end = strchr(next, ' '); + if (!end) + name_len = strlen(next); + else + name_len = end - next; + + if (name_len == 0 || name_len == sizeof(name)) + return -EINVAL; + + strncpy(name, next, name_len); + name[name_len] = '\0'; + next += name_len; + if (*next != '\0') + next++; + + if (validate_name(name, "RXQ", 2) == 0) { + type = APP_PKTQ_IN_HWQ; + id = APP_PARAM_ADD(app->hwq_in_params, name); + } else if (validate_name(name, "SWQ", 1) == 0) { + type = APP_PKTQ_IN_SWQ; + id = APP_PARAM_ADD(app->swq_params, name); + } else if (validate_name(name, "TM", 1) == 0) { + type = APP_PKTQ_IN_TM; + id = APP_PARAM_ADD(app->tm_params, name); + } else if (validate_name(name, "SOURCE", 1) == 0) { + type = APP_PKTQ_IN_SOURCE; + id = APP_PARAM_ADD(app->source_params, name); + } else + return -EINVAL; + + if (id < 0) + return id; + + p->pktq_in[p->n_pktq_in].type = type; + p->pktq_in[p->n_pktq_in].id = (uint32_t) id; + p->n_pktq_in++; + } + + return 0; +} + +static int +parse_pipeline_pktq_out(struct app_params *app, + struct app_pipeline_params *p, const char *value) +{ + const char *next = value; + char *end; + char name[APP_PARAM_NAME_SIZE]; + size_t name_len; + + while (*next != '\0') { + enum app_pktq_out_type type; + int id; + + end = strchr(next, ' '); + if (!end) + name_len = strlen(next); + else + name_len = end - next; + + if (name_len == 0 || name_len == sizeof(name)) + return -EINVAL; + + strncpy(name, next, name_len); + name[name_len] = '\0'; + next += name_len; + if (*next != '\0') + next++; + + if (validate_name(name, "TXQ", 2) == 0) { + type = APP_PKTQ_OUT_HWQ; + id = APP_PARAM_ADD(app->hwq_out_params, name); + } else if (validate_name(name, "SWQ", 1) == 0) { + type = APP_PKTQ_OUT_SWQ; + id = APP_PARAM_ADD(app->swq_params, name); + } else if (validate_name(name, "TM", 1) == 0) { + type = APP_PKTQ_OUT_TM; + id = APP_PARAM_ADD(app->tm_params, name); + } else if (validate_name(name, "SINK", 1) == 0) { + type = APP_PKTQ_OUT_SINK; + id = APP_PARAM_ADD(app->sink_params, name); + } else + return -EINVAL; + + if (id < 0) + return id; + + p->pktq_out[p->n_pktq_out].type = type; + p->pktq_out[p->n_pktq_out].id = id; + p->n_pktq_out++; + } + + return 0; +} + +static int +parse_pipeline_msgq_in(struct app_params *app, + struct app_pipeline_params *p, const char *value) +{ + const char *next = value; + char *end; + char name[APP_PARAM_NAME_SIZE]; + size_t name_len; + ssize_t idx; + + while (*next != '\0') { + end = strchr(next, ' '); + if (!end) + name_len = strlen(next); + else + name_len = end - next; + + if (name_len == 0 || name_len == sizeof(name)) + return -EINVAL; + + strncpy(name, next, name_len); + name[name_len] = '\0'; + next += name_len; + if (*next != '\0') + next++; + + if (validate_name(name, "MSGQ", 1) == 0) { + idx = APP_PARAM_ADD(app->msgq_params, name); + } else + return -EINVAL; + + if (idx < 0) + return idx; + + p->msgq_in[p->n_msgq_in] = idx; + p->n_msgq_in++; + } + + return 0; +} + +static int +parse_pipeline_msgq_out(struct app_params *app, + struct app_pipeline_params *p, const char *value) +{ + const char *next = value; + char *end; + char name[APP_PARAM_NAME_SIZE]; + size_t name_len; + ssize_t idx; + + while (*next != '\0') { + end = strchr(next, ' '); + if (!end) + name_len = strlen(next); + else + name_len = end - next; + + if (name_len == 0 || name_len == sizeof(name)) + return -EINVAL; + + strncpy(name, next, name_len); + name[name_len] = '\0'; + next += name_len; + if (*next != '\0') + next++; + + if (validate_name(name, "MSGQ", 1) == 0) { + idx = APP_PARAM_ADD(app->msgq_params, name); + } else + return -EINVAL; + + if (idx < 0) + return idx; + + p->msgq_out[p->n_msgq_out] = idx; + p->n_msgq_out++; + } + + return 0; +} + + +static void +parse_pipeline(struct app_params *app, const char *sect_name, + struct rte_cfgfile *cfg) +{ + int ret, i; + char name[CFG_NAME_LEN]; + ssize_t param_idx; + + const struct rte_cfgfile_entry2 **entries, *ent; + struct app_pipeline_params *param; + + entries = parser_get_section_entries(cfg, sect_name); + + param_idx = APP_PARAM_ADD(app->pipeline_params, sect_name); + PARSER_PARAM_ADD_CHECK(param_idx, app->pipeline_params, sect_name); + + param = &app->pipeline_params[param_idx]; + param->parsed = 1; + + for (i = 0; entries[i] != NULL; i++) { + ent = entries[i]; + + if (strcmp(ent->name, "type") == 0) { + ret = snprintf(param->type, RTE_DIM(param->type), "%s", ent->value); + if (ret > 0 && ret < (int)RTE_DIM(param->type)) + ret = 0; + else + ret = -EINVAL; + } + else if(strcmp(ent->name, "core") == 0) + ret = parse_pipeline_core(¶m->socket_id, ¶m->core_id, + ¶m->hyper_th_id, ent->value); + else if(strcmp(ent->name, "pktq_in") == 0) + ret = parse_pipeline_pktq_in(app, param, ent->value); + else if(strcmp(ent->name, "pktq_out") == 0) + ret = parse_pipeline_pktq_out(app, param, ent->value); + else if(strcmp(ent->name, "msgq_in") == 0) + ret = parse_pipeline_msgq_in(app, param, ent->value); + else if(strcmp(ent->name, "msgq_out") == 0) + ret = parse_pipeline_msgq_out(app, param, ent->value); + else if(strcmp(ent->name, "timer_period") == 0) + ret = parser_read_uint32(¶m->timer_period, ent->value); + else { + param->args_name[param->n_args] = strdup(ent->name); + param->args_value[param->n_args] = strdup(ent->value); + + APP_CHECK((param->args_name[param->n_args] != NULL) && + (param->args_value[param->n_args] != NULL), + "CFG: [%s] out of memory", sect_name); + + param->n_args++; + ret = 0; + } + + APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n", + sect_name, ent->name, ent->value); + } + + snprintf(name, sizeof(name), "MSGQ-REQ-%s", sect_name); + param_idx = APP_PARAM_ADD(app->msgq_params, name); + PARSER_IMPLICIT_PARAM_ADD_CHECK(param_idx, name); + app->msgq_params[param_idx].cpu_socket_id = param->socket_id; + param->msgq_in[param->n_msgq_in++] = param_idx; + + snprintf(name, sizeof(name), "MSGQ-RSP-%s", sect_name); + param_idx = APP_PARAM_ADD(app->msgq_params, name); + PARSER_IMPLICIT_PARAM_ADD_CHECK(param_idx, name); + app->msgq_params[param_idx].cpu_socket_id = param->socket_id; + param->msgq_out[param->n_msgq_out++] = param_idx; + + snprintf(name, sizeof(name), "MSGQ-REQ-CORE-s%" PRIu32 "c%" PRIu32 "%s", + param->socket_id, + param->core_id, + (param->hyper_th_id) ? "h" : ""); + param_idx = APP_PARAM_ADD(app->msgq_params, name); + PARSER_IMPLICIT_PARAM_ADD_CHECK(param_idx, name); + app->msgq_params[param_idx].cpu_socket_id = param->socket_id; + + snprintf(name, sizeof(name), "MSGQ-RSP-CORE-s%" PRIu32 "c%" PRIu32 "%s", + param->socket_id, + param->core_id, + (param->hyper_th_id) ? "h" : ""); + param_idx = APP_PARAM_ADD(app->msgq_params, name); + PARSER_IMPLICIT_PARAM_ADD_CHECK(param_idx, name); + app->msgq_params[param_idx].cpu_socket_id = param->socket_id; + + free(entries); +} + +static void +parse_mempool(struct app_params *app, const char *sect_name, + struct rte_cfgfile *cfg) +{ + int ret, i; + ssize_t param_idx; + + const struct rte_cfgfile_entry2 **entries, *ent; + struct app_mempool_params *param; + + entries = parser_get_section_entries(cfg, sect_name); + + param_idx = APP_PARAM_ADD(app->mempool_params, sect_name); + PARSER_PARAM_ADD_CHECK(param_idx, app->mempool_params, sect_name); + + param = &app->mempool_params[param_idx]; + param->parsed = 1; + + for (i = 0; entries[i] != NULL; i++) { + ent = entries[i]; + + ret = -ESRCH; + if (strcmp(ent->name, "buffer_size") == 0) + ret = parser_read_uint32(¶m->buffer_size, ent->value); + else if(strcmp(ent->name, "pool_size") == 0) + ret = parser_read_uint32(¶m->pool_size, ent->value); + else if(strcmp(ent->name, "cache_size") == 0) + ret = parser_read_uint32(¶m->cache_size, ent->value); + else if(strcmp(ent->name, "cpu") == 0) + ret = parser_read_uint32(¶m->cpu_socket_id, ent->value); + + APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n", + sect_name, ent->name); + APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n", + sect_name, ent->name, ent->value); + } + + free(entries); +} + +static void +parse_link(struct app_params *app, const char *sect_name, + struct rte_cfgfile *cfg) +{ + int ret, i; + ssize_t param_idx; + + const struct rte_cfgfile_entry2 **entries, *ent; + struct app_link_params *param; + + entries = parser_get_section_entries(cfg, sect_name); + + param_idx = APP_PARAM_ADD(app->link_params, sect_name); + PARSER_PARAM_ADD_CHECK(param_idx, app->link_params, sect_name); + + param = &app->link_params[param_idx]; + param->parsed = 1; + + for (i = 0; entries[i] != NULL; i++) { + ent = entries[i]; + + ret = -ESRCH; + if (strcmp(ent->name, "arp_q") == 0) + ret = parser_read_uint32(¶m->arp_q, ent->value); + else if(strcmp(ent->name, "ip_local_q") == 0) + ret = parser_read_uint32(¶m->ip_local_q, ent->value); + else if(strcmp(ent->name, "tcp_local_q") == 0) + ret = parser_read_uint32(¶m->tcp_local_q, ent->value); + else if(strcmp(ent->name, "udp_local_q") == 0) + ret = parser_read_uint32(¶m->udp_local_q, ent->value); + else if(strcmp(ent->name, "sctp_local_q") == 0) + ret = parser_read_uint32(¶m->sctp_local_q, ent->value); + + APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n", + sect_name, ent->name); + APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n", + sect_name, ent->name, ent->value); + } + + free(entries); +} + +static void +parse_rxq(struct app_params *app, const char *sect_name, + struct rte_cfgfile *cfg) +{ + int ret, i; + ssize_t param_idx; + + const struct rte_cfgfile_entry2 **entries, *ent; + struct app_pktq_hwq_in_params *param; + + entries = parser_get_section_entries(cfg, sect_name); + + param_idx = APP_PARAM_ADD(app->hwq_in_params, sect_name); + PARSER_PARAM_ADD_CHECK(param_idx, app->hwq_in_params, sect_name); + + param = &app->hwq_in_params[param_idx]; + param->parsed = 1; + + for (i = 0; entries[i] != NULL; i++) { + ent = entries[i]; + + ret = -ESRCH; + if (strcmp(ent->name, "mempool") == 0) { + ssize_t idx; + + APP_CHECK((validate_name(ent->value, "MEMPOOL", 1) == 0), + "CFG: [%s] entry '%s': invalid mempool\n", sect_name, ent->name); + + idx = APP_PARAM_ADD(app->mempool_params, ent->value); + PARSER_IMPLICIT_PARAM_ADD_CHECK(idx, sect_name); + param->mempool_id = idx; + ret = 0; + } else if(strcmp(ent->name, "size") == 0) + ret = parser_read_uint32(¶m->size, ent->value); + else if(strcmp(ent->name, "burst") == 0) + ret = parser_read_uint32(¶m->burst, ent->value); + + APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n", + sect_name, ent->name); + APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n", + sect_name, ent->name, ent->value); + } + + free(entries); +} + +static void +parse_txq(struct app_params *app, const char *sect_name, + struct rte_cfgfile *cfg) +{ + int ret, i; + ssize_t param_idx; + + const struct rte_cfgfile_entry2 **entries, *ent; + struct app_pktq_hwq_out_params *param; + + entries = parser_get_section_entries(cfg, sect_name); + + param_idx = APP_PARAM_ADD(app->hwq_out_params, sect_name); + PARSER_PARAM_ADD_CHECK(param_idx, app->hwq_out_params, sect_name); + + param = &app->hwq_out_params[param_idx]; + param->parsed = 1; + + for (i = 0; entries[i] != NULL; i++) { + ent = entries[i]; + + ret = -ESRCH; + if(strcmp(ent->name, "size") == 0) + ret = parser_read_uint32(¶m->size, ent->value); + else if (strcmp(ent->name, "burst") == 0) + ret = parser_read_uint32(¶m->burst, ent->value); + else if(strcmp(ent->name, "dropless") == 0) { + ret = parser_read_arg_bool(ent->value); + if (ret >= 0) { + param->dropless = ret; + ret = 0; + } + } + + APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n", + sect_name, ent->name); + APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n", + sect_name, ent->name, ent->value); + } + + free(entries); +} + +static void +parse_swq(struct app_params *app, const char *sect_name, + struct rte_cfgfile *cfg) +{ + int ret, i; + ssize_t param_idx; + + const struct rte_cfgfile_entry2 **entries, *ent; + struct app_pktq_swq_params *param; + + entries = parser_get_section_entries(cfg, sect_name); + + param_idx = APP_PARAM_ADD(app->swq_params, sect_name); + PARSER_PARAM_ADD_CHECK(param_idx, app->swq_params, sect_name); + + param = &app->swq_params[param_idx]; + param->parsed = 1; + + for (i = 0; entries[i] != NULL; i++) { + ent = entries[i]; + + ret = -ESRCH; + if(strcmp(ent->name, "size") == 0) + ret = parser_read_uint32(¶m->size, ent->value); + else if (strcmp(ent->name, "burst_read") == 0) + ret = parser_read_uint32(¶m->burst_read, ent->value); + else if (strcmp(ent->name, "burst_write") == 0) + ret = parser_read_uint32(¶m->burst_write, ent->value); + else if(strcmp(ent->name, "dropless") == 0) { + ret = parser_read_arg_bool(ent->value); + if (ret >= 0) { + param->dropless = ret; + ret = 0; + } + } else if(strcmp(ent->name, "n_retries") == 0) + ret = parser_read_uint64(¶m->n_retries, ent->value); + else if(strcmp(ent->name, "cpu") == 0) + ret = parser_read_uint32(¶m->cpu_socket_id, ent->value); + + APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n", + sect_name, ent->name); + APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n", + sect_name, ent->name, ent->value); + } + + free(entries); +} + +static int +tm_cfgfile_load_sched_port( + struct rte_cfgfile *file, + struct rte_sched_port_params *port_params) +{ + const char *entry; + int j; + + entry = rte_cfgfile_get_entry(file, "port", "frame overhead"); + if (entry) + port_params->frame_overhead = (uint32_t)atoi(entry); + + entry = rte_cfgfile_get_entry(file, "port", "number of subports per port"); + if (entry) + port_params->n_subports_per_port = (uint32_t)atoi(entry); + + entry = rte_cfgfile_get_entry(file, "port", "number of pipes per subport"); + if (entry) + port_params->n_pipes_per_subport = (uint32_t)atoi(entry); + + entry = rte_cfgfile_get_entry(file, "port", "queue sizes"); + if (entry) { + char *next; + + for(j = 0; j < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; j++) { + port_params->qsize[j] = (uint16_t)strtol(entry, &next, 10); + if (next == NULL) + break; + entry = next; + } + } + +#ifdef RTE_SCHED_RED + for (j = 0; j < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; j++) { + char str[32]; + + /* Parse WRED min thresholds */ + snprintf(str, sizeof(str), "tc %d wred min", j); + entry = rte_cfgfile_get_entry(file, "red", str); + if (entry) { + char *next; + int k; + /* for each packet colour (green, yellow, red) */ + for (k = 0; k < e_RTE_METER_COLORS; k++) { + port_params->red_params[j][k].min_th + = (uint16_t)strtol(entry, &next, 10); + if (next == NULL) + break; + entry = next; + } + } + + /* Parse WRED max thresholds */ + snprintf(str, sizeof(str), "tc %d wred max", j); + entry = rte_cfgfile_get_entry(file, "red", str); + if (entry) { + char *next; + int k; + /* for each packet colour (green, yellow, red) */ + for (k = 0; k < e_RTE_METER_COLORS; k++) { + port_params->red_params[j][k].max_th + = (uint16_t)strtol(entry, &next, 10); + if (next == NULL) + break; + entry = next; + } + } + + /* Parse WRED inverse mark probabilities */ + snprintf(str, sizeof(str), "tc %d wred inv prob", j); + entry = rte_cfgfile_get_entry(file, "red", str); + if (entry) { + char *next; + int k; + /* for each packet colour (green, yellow, red) */ + for (k = 0; k < e_RTE_METER_COLORS; k++) { + port_params->red_params[j][k].maxp_inv + = (uint8_t)strtol(entry, &next, 10); + + if (next == NULL) + break; + entry = next; + } + } + + /* Parse WRED EWMA filter weights */ + snprintf(str, sizeof(str), "tc %d wred weight", j); + entry = rte_cfgfile_get_entry(file, "red", str); + if (entry) { + char *next; + int k; + /* for each packet colour (green, yellow, red) */ + for (k = 0; k < e_RTE_METER_COLORS; k++) { + port_params->red_params[j][k].wq_log2 + = (uint8_t)strtol(entry, &next, 10); + if (next == NULL) + break; + entry = next; + } + } + } +#endif /* RTE_SCHED_RED */ + + return 0; +} + +static int +tm_cfgfile_load_sched_pipe( + struct rte_cfgfile *file, + struct rte_sched_port_params *port_params, + struct rte_sched_pipe_params *pipe_params) +{ + int i, j; + char *next; + const char *entry; + int profiles; + + profiles = rte_cfgfile_num_sections(file, + "pipe profile", sizeof("pipe profile") - 1); + port_params->n_pipe_profiles = profiles; + + for (j = 0; j < profiles; j++) { + char pipe_name[32]; + snprintf(pipe_name, sizeof(pipe_name), "pipe profile %d", j); + + entry = rte_cfgfile_get_entry(file, pipe_name, "tb rate"); + if (entry) + pipe_params[j].tb_rate = (uint32_t)atoi(entry); + + entry = rte_cfgfile_get_entry(file, pipe_name, "tb size"); + if (entry) + pipe_params[j].tb_size = (uint32_t)atoi(entry); + + entry = rte_cfgfile_get_entry(file, pipe_name, "tc period"); + if (entry) + pipe_params[j].tc_period = (uint32_t)atoi(entry); + + entry = rte_cfgfile_get_entry(file, pipe_name, "tc 0 rate"); + if (entry) + pipe_params[j].tc_rate[0] = (uint32_t)atoi(entry); + + entry = rte_cfgfile_get_entry(file, pipe_name, "tc 1 rate"); + if (entry) + pipe_params[j].tc_rate[1] = (uint32_t)atoi(entry); + + entry = rte_cfgfile_get_entry(file, pipe_name, "tc 2 rate"); + if (entry) + pipe_params[j].tc_rate[2] = (uint32_t)atoi(entry); + + entry = rte_cfgfile_get_entry(file, pipe_name, "tc 3 rate"); + if (entry) + pipe_params[j].tc_rate[3] = (uint32_t)atoi(entry); + +#ifdef RTE_SCHED_SUBPORT_TC_OV + entry = rte_cfgfile_get_entry(file, pipe_name, + "tc 3 oversubscription weight"); + if (entry) + pipe_params[j].tc_ov_weight = (uint8_t)atoi(entry); +#endif + + entry = rte_cfgfile_get_entry(file, pipe_name, "tc 0 wrr weights"); + if (entry) { + for(i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) { + pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*0 + i] = + (uint8_t)strtol(entry, &next, 10); + if (next == NULL) + break; + entry = next; + } + } + entry = rte_cfgfile_get_entry(file, pipe_name, "tc 1 wrr weights"); + if (entry) { + for(i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) { + pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*1 + i] = + (uint8_t)strtol(entry, &next, 10); + if (next == NULL) + break; + entry = next; + } + } + entry = rte_cfgfile_get_entry(file, pipe_name, "tc 2 wrr weights"); + if (entry) { + for(i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) { + pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*2 + i] = + (uint8_t)strtol(entry, &next, 10); + if (next == NULL) + break; + entry = next; + } + } + entry = rte_cfgfile_get_entry(file, pipe_name, "tc 3 wrr weights"); + if (entry) { + for(i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) { + pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*3 + i] = + (uint8_t)strtol(entry, &next, 10); + if (next == NULL) + break; + entry = next; + } + } + } + return 0; +} + +static int +tm_cfgfile_load_sched_subport( + struct rte_cfgfile *file, + struct rte_sched_subport_params *subport_params, + int *pipe_to_profile) +{ + const char *entry; + int i, j, k; + + for (i = 0; i < APP_MAX_SCHED_SUBPORTS; i++) { + char sec_name[CFG_NAME_LEN]; + snprintf(sec_name, sizeof(sec_name), "subport %d", i); + + if (rte_cfgfile_has_section(file, sec_name)) { + entry = rte_cfgfile_get_entry(file, sec_name, "tb rate"); + if (entry) + subport_params[i].tb_rate = (uint32_t)atoi(entry); + + entry = rte_cfgfile_get_entry(file, sec_name, "tb size"); + if (entry) + subport_params[i].tb_size = (uint32_t)atoi(entry); + + entry = rte_cfgfile_get_entry(file, sec_name, "tc period"); + if (entry) + subport_params[i].tc_period = (uint32_t)atoi(entry); + + entry = rte_cfgfile_get_entry(file, sec_name, "tc 0 rate"); + if (entry) + subport_params[i].tc_rate[0] = (uint32_t)atoi(entry); + + entry = rte_cfgfile_get_entry(file, sec_name, "tc 1 rate"); + if (entry) + subport_params[i].tc_rate[1] = (uint32_t)atoi(entry); + + entry = rte_cfgfile_get_entry(file, sec_name, "tc 2 rate"); + if (entry) + subport_params[i].tc_rate[2] = (uint32_t)atoi(entry); + + entry = rte_cfgfile_get_entry(file, sec_name, "tc 3 rate"); + if (entry) + subport_params[i].tc_rate[3] = (uint32_t)atoi(entry); + + int n_entries = rte_cfgfile_section_num_entries(file, sec_name); + const struct rte_cfgfile_entry2 *entries[n_entries]; + + rte_cfgfile_section_entries_v21(file, sec_name, entries, n_entries); + + for (j = 0; j < n_entries; j++) { + if (strncmp("pipe", entries[j]->name, sizeof("pipe") - 1) == 0) { + int profile; + char *tokens[2] = {NULL, NULL}; + int n_tokens; + int begin, end; + char name[CFG_NAME_LEN]; + + profile = atoi(entries[j]->value); + strncpy(name, entries[j]->name, sizeof(name)); + n_tokens = rte_strsplit(&name[sizeof("pipe")], + strnlen(name, CFG_NAME_LEN), tokens, 2, '-'); + + begin = atoi(tokens[0]); + if (n_tokens == 2) + end = atoi(tokens[1]); + else + end = begin; + + if (end >= APP_MAX_SCHED_PIPES || begin > end) + return -1; + + for (k = begin; k <= end; k++) { + char profile_name[CFG_NAME_LEN]; + + snprintf(profile_name, sizeof(profile_name), + "pipe profile %d", profile); + if (rte_cfgfile_has_section(file, profile_name)) + pipe_to_profile[i * APP_MAX_SCHED_PIPES + k] = profile; + else + rte_exit(EXIT_FAILURE, "Wrong pipe profile %s\n", + entries[j]->value); + } + } + } + } + } + + return 0; +} + +static int +tm_cfgfile_load(struct app_pktq_tm_params *tm) +{ + struct rte_cfgfile *file; + uint32_t mtu, i; + + mtu = tm->sched_port_params.mtu; + memset(tm->sched_subport_params, 0, sizeof(tm->sched_subport_params)); + memset(tm->sched_pipe_profiles, 0, sizeof(tm->sched_pipe_profiles)); + memset(&tm->sched_port_params, 0, sizeof(tm->sched_pipe_profiles)); + for (i = 0; i < APP_MAX_SCHED_SUBPORTS * APP_MAX_SCHED_PIPES; i++) + tm->sched_pipe_to_profile[i] = -1; + + tm->sched_port_params.pipe_profiles = &tm->sched_pipe_profiles[0]; + tm->sched_port_params.mtu = mtu; + + if (tm->file_name[0] == '\0') + return -1; + + file = rte_cfgfile_load(tm->file_name, 0); + if (file == NULL) + return -1; + + tm_cfgfile_load_sched_port(file, &tm->sched_port_params); + tm_cfgfile_load_sched_subport(file, tm->sched_subport_params, tm->sched_pipe_to_profile); + tm_cfgfile_load_sched_pipe(file, &tm->sched_port_params, tm->sched_pipe_profiles); + + rte_cfgfile_close(file); + return 0; +} + +static void +parse_tm(struct app_params *app, const char *sect_name, + struct rte_cfgfile *cfg) +{ + int ret, i; + ssize_t param_idx; + + const struct rte_cfgfile_entry2 **entries, *ent; + struct app_pktq_tm_params *param; + + entries = parser_get_section_entries(cfg, sect_name); + + param_idx = APP_PARAM_ADD(app->tm_params, sect_name); + PARSER_PARAM_ADD_CHECK(param_idx, app->tm_params, sect_name); + + param = &app->tm_params[param_idx]; + param->parsed = 1; + + for (i = 0; entries[i] != NULL; i++) { + ent = entries[i]; + + ret = -ESRCH; + if(strcmp(ent->name, "cfg") == 0) { + int status; + + ret = 0; + status = snprintf(param->file_name, + sizeof(param->file_name), "%s", ent->value); + if (status >= (int) sizeof(param->file_name)) + ret = -EINVAL; + else { + status = tm_cfgfile_load(param); + if (status) + ret = -EBADF; + } + } else if (strcmp(ent->name, "burst_read") == 0) + ret = parser_read_uint32(¶m->burst_read, ent->value); + else if (strcmp(ent->name, "burst_write") == 0) + ret = parser_read_uint32(¶m->burst_write, ent->value); + + APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n", + sect_name, ent->name); + APP_CHECK(ret != -EBADF, "CFG: [%s] entry '%s': TM cfg parse error '%s'\n", + sect_name, ent->name, ent->value); + APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n", + sect_name, ent->name, ent->value); + } + + free(entries); +} + +static void +parse_source(struct app_params *app, const char *sect_name, + struct rte_cfgfile *cfg) +{ + int ret, i; + ssize_t param_idx; + + const struct rte_cfgfile_entry2 **entries, *ent; + struct app_pktq_source_params *param; + + entries = parser_get_section_entries(cfg, sect_name); + + param_idx = APP_PARAM_ADD(app->source_params, sect_name); + PARSER_PARAM_ADD_CHECK(param_idx, app->source_params, sect_name); + + param = &app->source_params[param_idx]; + param->parsed = 1; + + for (i = 0; entries[i] != NULL; i++) { + ent = entries[i]; + + ret = -ESRCH; + if (strcmp(ent->name, "mempool") == 0) { + ssize_t idx; + + APP_CHECK((validate_name(ent->value, "MEMPOOL", 1) == 0), + "CFG: [%s] entry '%s': invalid mempool\n", sect_name, ent->name); + + idx = APP_PARAM_ADD(app->mempool_params, ent->value); + PARSER_IMPLICIT_PARAM_ADD_CHECK(idx, sect_name); + param->mempool_id = idx; + ret = 0; + } else if (strcmp(ent->name, "burst") == 0) + ret = parser_read_uint32(¶m->burst, ent->value); + + APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n", + sect_name, ent->name); + APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n", + sect_name, ent->name, ent->value); + } + + free(entries); +} + +static void +parse_msgq_req_pipeline(struct app_params *app, const char *sect_name, + struct rte_cfgfile *cfg) +{ + int ret, i; + ssize_t param_idx; + + const struct rte_cfgfile_entry2 **entries, *ent; + struct app_msgq_params *param; + + entries = parser_get_section_entries(cfg, sect_name); + + param_idx = APP_PARAM_ADD(app->msgq_params, sect_name); + PARSER_PARAM_ADD_CHECK(param_idx, app->msgq_params, sect_name); + + param = &app->msgq_params[param_idx]; + param->parsed = 1; + + for (i = 0; entries[i] != NULL; i++) { + ent = entries[i]; + + ret = -ESRCH; + if(strcmp(ent->name, "size") == 0) + ret = parser_read_uint32(¶m->size, ent->value); + + APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n", + sect_name, ent->name); + APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n", + sect_name, ent->name, ent->value); + } + + free(entries); +} + +static void +parse_msgq_rsp_pipeline(struct app_params *app, const char *sect_name, + struct rte_cfgfile *cfg) +{ + int ret, i; + ssize_t param_idx; + + const struct rte_cfgfile_entry2 **entries, *ent; + struct app_msgq_params *param; + + entries = parser_get_section_entries(cfg, sect_name); + + param_idx = APP_PARAM_ADD(app->msgq_params, sect_name); + PARSER_PARAM_ADD_CHECK(param_idx, app->msgq_params, sect_name); + + param = &app->msgq_params[param_idx]; + param->parsed = 1; + + for (i = 0; entries[i] != NULL; i++) { + ent = entries[i]; + + ret = -ESRCH; + if(strcmp(ent->name, "size") == 0) + ret = parser_read_uint32(¶m->size, ent->value); + + APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n", + sect_name, ent->name); + APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n", + sect_name, ent->name, ent->value); + } + + free(entries); +} + +static void +parse_msgq(struct app_params *app, const char *sect_name, + struct rte_cfgfile *cfg) +{ + int ret, i; + ssize_t param_idx; + + const struct rte_cfgfile_entry2 **entries, *ent; + struct app_msgq_params *param; + + entries = parser_get_section_entries(cfg, sect_name); + + param_idx = APP_PARAM_ADD(app->msgq_params, sect_name); + PARSER_PARAM_ADD_CHECK(param_idx, app->msgq_params, sect_name); + + param = &app->msgq_params[param_idx]; + param->parsed = 1; + + for (i = 0; entries[i] != NULL; i++) { + ent = entries[i]; + + ret = -ESRCH; + if(strcmp(ent->name, "size") == 0) + ret = parser_read_uint32(¶m->size, ent->value); + else if(strcmp(ent->name, "cpu") == 0) + ret = parser_read_uint32(¶m->cpu_socket_id, ent->value); + + APP_CHECK(ret != -ESRCH, "CFG: [%s] entry '%s': unknown entry\n", + sect_name, ent->name); + APP_CHECK(ret == 0, "CFG: [%s] entry '%s': Invalid value '%s'\n", + sect_name, ent->name, ent->value); + } + + free(entries); +} + +struct config_section { + const char prefix[CFG_NAME_LEN]; + int numbers; + void (*load)(struct app_params *p, const char *sect_name, + struct rte_cfgfile *cfg); +}; + +static const struct config_section cfg_file_scheme[] = { + { "PIPELINE", 1, parse_pipeline }, + { "MEMPOOL", 1, parse_mempool }, + { "LINK", 1, parse_link }, + { "RXQ", 2, parse_rxq }, + { "TXQ", 2, parse_txq }, + { "SWQ", 1, parse_swq }, + { "TM", 1, parse_tm }, + { "SOURCE", 1, parse_source }, + { "MSGQ-REQ-PIPELINE", 1, parse_msgq_req_pipeline }, + { "MSGQ-RSP-PIPELINE", 1, parse_msgq_rsp_pipeline }, + { "MSGQ", 1, parse_msgq }, + +}; + +static void +create_implicit_mempools(struct app_params *app) +{ + ssize_t idx; + + idx = APP_PARAM_ADD(app->mempool_params, "MEMPOOL0"); + PARSER_IMPLICIT_PARAM_ADD_CHECK(idx, "start-up"); +} + +static void +parse_port_mask(struct app_params *app, uint64_t port_mask) +{ + uint32_t pmd_id, link_id; + + link_id = 0; + for (pmd_id = 0; pmd_id < RTE_MAX_ETHPORTS; pmd_id++) { + char name[APP_PARAM_NAME_SIZE]; + ssize_t idx; + + if ((port_mask & (1LLU << pmd_id)) == 0) + continue; + + snprintf(name, sizeof(name), "LINK%u", link_id); + idx = APP_PARAM_ADD(app->link_params, name); + PARSER_IMPLICIT_PARAM_ADD_CHECK(idx, name); + + app->link_params[idx].pmd_id = pmd_id; + link_id ++; + } +} + +int +app_config_parse(struct app_params *app, const char *file_name) +{ + char config_file_out[APP_FILE_NAME_SIZE]; + + char **sect_names; + struct rte_cfgfile *cfg; + + const struct config_section *sch_s; + int i, j, sect_count; + + create_implicit_mempools(app); + + parse_port_mask(app, app->port_mask); + + cfg = rte_cfgfile_load(file_name, 0); + APP_CHECK(cfg != NULL, "Unable to load config file %s", file_name); + + sect_count = rte_cfgfile_num_sections(cfg, NULL, 0); + sect_names = malloc(sect_count * sizeof(char *)); + for (i = 0; i < sect_count; i++) + sect_names[i] = malloc(CFG_NAME_LEN); + + rte_cfgfile_sections(cfg, sect_names, sect_count); + + for (i = 0; i < sect_count; i++) { + int len, cfg_name_len; + + cfg_name_len = strlen(sect_names[i]); + + /* Find section type */ + for (j = 0; j < (int)RTE_DIM(cfg_file_scheme); j++) { + sch_s = &cfg_file_scheme[j]; + len = strlen(sch_s->prefix); + + if (cfg_name_len < len) + continue; + + /* After section name we expect only '\0' or digit or digit dot + * digit so protect against false matching ex: + * if shc_s if sch_s->name is "ABC" + * cfg_sect_name "ABC0.0" match but + * cfg_sect_name is "ABCDEF" does not match + */ + if (sect_names[i][len] != '\0' && !isdigit(sect_names[i][len])) + continue; + + if (strncmp(sch_s->prefix, sect_names[i], len) == 0) + break; + } + + APP_CHECK(j < (int)RTE_DIM(cfg_file_scheme), "Unknown section %s", + sect_names[i]); + + APP_CHECK(validate_name(sect_names[i], sch_s->prefix, sch_s->numbers) == 0, + "Invalid section name '%s'", sect_names[i]); + + sch_s->load(app, sect_names[i], cfg); + } + + for (i = 0; i < sect_count; i++) + free(sect_names[i]); + + free(sect_names); + + rte_cfgfile_close(cfg); + + snprintf(config_file_out, APP_FILE_NAME_SIZE, "%s.out", app->config_file); + app_config_save(app, config_file_out); + + APP_PARAM_COUNT(app->mempool_params, app->n_mempools); + APP_PARAM_COUNT(app->link_params, app->n_links); + APP_PARAM_COUNT(app->hwq_in_params, app->n_pktq_hwq_in); + APP_PARAM_COUNT(app->hwq_out_params, app->n_pktq_hwq_out); + APP_PARAM_COUNT(app->swq_params, app->n_pktq_swq); + APP_PARAM_COUNT(app->tm_params, app->n_pktq_tm); + APP_PARAM_COUNT(app->source_params, app->n_pktq_source); + APP_PARAM_COUNT(app->sink_params, app->n_pktq_sink); + APP_PARAM_COUNT(app->msgq_params, app->n_msgq); + APP_PARAM_COUNT(app->pipeline_params, app->n_pipelines); + + return 0; +} + +static void +save_mempool_params(struct app_params *app, FILE *f) +{ + struct app_mempool_params *p; + size_t i, count; + + count = RTE_DIM(app->mempool_params); + for (i = 0; i < count; i++) { + p = &app->mempool_params[i]; + if (!APP_PARAM_VALID(p)) + continue; + + fprintf(f, "[%s]\n", p->name); + fprintf(f, "%s = %" PRIu32 "\n", "buffer_size", p->buffer_size); + fprintf(f, "%s = %" PRIu32 "\n", "pool_size", p->pool_size); + fprintf(f, "%s = %" PRIu32 "\n", "cache_size", p->cache_size); + fprintf(f, "%s = %" PRIu32 "\n", "cpu", p->cpu_socket_id); + + fputc('\n', f); + } +} + +static void +save_links_params(struct app_params *app, FILE *f) +{ + struct app_link_params *p; + size_t i, count; + + count = RTE_DIM(app->link_params); + for (i = 0; i < count; i++) { + p = &app->link_params[i]; + if (!APP_PARAM_VALID(p)) + continue; + + fprintf(f, "[%s]\n", p->name); + fprintf(f, "; %s = %" PRIu32 "\n", "pmd_id", p->pmd_id); + fprintf(f, "%s = %" PRIu32 "\n", "arp_q", p->arp_q); + fprintf(f, "%s = %" PRIu32 "\n", "tcp_syn_local_q", p->arp_q); + fprintf(f, "%s = %" PRIu32 "\n", "ip_local_q", p->ip_local_q); + fprintf(f, "%s = %" PRIu32 "\n", "tcp_local_q", p->tcp_local_q); + fprintf(f, "%s = %" PRIu32 "\n", "udp_local_q", p->udp_local_q); + fprintf(f, "%s = %" PRIu32 "\n", "sctp_local_q", p->sctp_local_q); + + fputc('\n', f); + } +} + +static void +save_rxq_params(struct app_params *app, FILE *f) +{ + struct app_pktq_hwq_in_params *p; + size_t i, count; + + count = RTE_DIM(app->hwq_in_params); + for (i = 0; i < count; i++) { + p = &app->hwq_in_params[i]; + if (!APP_PARAM_VALID(p)) + continue; + + fprintf(f, "[%s]\n", p->name); + fprintf(f, "%s = %s\n", "mempool", app->mempool_params[p->mempool_id].name); + fprintf(f, "%s = %" PRIu32 "\n", "size", p->size); + fprintf(f, "%s = %" PRIu32 "\n", "burst", p->burst); + + fputc('\n', f); + } +} + +static void +save_txq_params(struct app_params *app, FILE *f) +{ + struct app_pktq_hwq_out_params *p; + size_t i, count; + + count = RTE_DIM(app->hwq_out_params); + for (i = 0; i < count; i++) { + p = &app->hwq_out_params[i]; + if (!APP_PARAM_VALID(p)) + continue; + + fprintf(f, "[%s]\n", p->name); + fprintf(f, "%s = %" PRIu32 "\n", "size", p->size); + fprintf(f, "%s = %" PRIu32 "\n", "burst", p->burst); + fprintf(f, "%s = %s\n", "dropless", p->dropless ? "yes" : "no"); + + fputc('\n', f); + } +} + +static void +save_swq_params(struct app_params *app, FILE *f) +{ + struct app_pktq_swq_params *p; + size_t i, count; + + count = RTE_DIM(app->swq_params); + for (i = 0; i < count; i++) { + p = &app->swq_params[i]; + if (!APP_PARAM_VALID(p)) + continue; + + fprintf(f, "[%s]\n", p->name); + fprintf(f, "%s = %" PRIu32 "\n", "size", p->size); + fprintf(f, "%s = %" PRIu32 "\n", "burst_read", p->burst_read); + fprintf(f, "%s = %" PRIu32 "\n", "burst_write", p->burst_write); + fprintf(f, "%s = %s\n", "dropless", p->dropless ? "yes" : "no"); + fprintf(f, "%s = %" PRIu64 "\n", "n_retries", p->n_retries); + fprintf(f, "%s = %" PRIu32 "\n", "cpu", p->cpu_socket_id); + + fputc('\n', f); + } +} + +static void +save_tm_params(struct app_params *app, FILE *f) +{ + struct app_pktq_tm_params *p; + size_t i, count; + + count = RTE_DIM(app->tm_params); + for (i = 0; i < count; i++) { + p = &app->tm_params[i]; + if (!APP_PARAM_VALID(p)) + continue; + + fprintf(f, "[%s]\n", p->name); + fprintf(f, "%s = %s\n", "cfg", p->file_name); + fprintf(f, "%s = %u\n", "burst_read", p->burst_read); + fprintf(f, "%s = %u\n", "burst_write", p->burst_write); + + fputc('\n', f); + } +} + +static void +save_source_params(struct app_params *app, FILE *f) +{ + struct app_pktq_source_params *p; + size_t i, count; + + count = RTE_DIM(app->source_params); + for (i = 0; i < count; i++) { + p = &app->source_params[i]; + if (!APP_PARAM_VALID(p)) + continue; + + fprintf(f, "[%s]\n", p->name); + fprintf(f, "%s = %s\n", "mempool", app->mempool_params[p->mempool_id].name); + fprintf(f, "%s = %u\n", "burst", p->burst); + fputc('\n', f); + } +} + +static void +save_msgq_params(struct app_params *app, FILE *f) +{ + struct app_msgq_params *p; + size_t i, count; + + count = RTE_DIM(app->msgq_params); + for (i = 0; i < count; i++) { + p = &app->msgq_params[i]; + if (!APP_PARAM_VALID(p)) + continue; + + fprintf(f, "[%s]\n", p->name); + fprintf(f, "%s = %" PRIu32 "\n", "size", p->size); + fprintf(f, "%s = %" PRIu32 "\n", "cpu", p->cpu_socket_id); + + fputc('\n', f); + } +} + +static void +save_pipeline_params(struct app_params *app, FILE *f) +{ + size_t i, count; + + count = RTE_DIM(app->pipeline_params); + for (i = 0; i < count; i++) { + struct app_pipeline_params *p = &app->pipeline_params[i]; + + if (!APP_PARAM_VALID(p)) + continue; + + /* section name */ + fprintf(f, "[%s]\n", p->name); + + /* type */ + fprintf(f, "type = %s\n", p->type); + + /* core */ + fprintf(f, "core = s%uc%u%s\n", + p->socket_id, + p->core_id, + (p->hyper_th_id)? "h" : ""); + + /* pktq_in */ + if (p->n_pktq_in) { + uint32_t j; + + fprintf(f, "pktq_in ="); + for (j = 0; j < p->n_pktq_in; j++) { + struct app_pktq_in_params *pp = &p->pktq_in[j]; + char *name; + + switch (pp->type) { + case APP_PKTQ_IN_HWQ: + name = app->hwq_in_params[pp->id].name; + break; + case APP_PKTQ_IN_SWQ: + name = app->swq_params[pp->id].name; + break; + case APP_PKTQ_IN_TM: + name = app->tm_params[pp->id].name; + break; + case APP_PKTQ_IN_SOURCE: + name = app->source_params[pp->id].name; + break; + default: + APP_CHECK(0, "Error\n"); + } + + fprintf(f, " %s", name); + } + fprintf(f, "\n"); + } + + /* pktq_in */ + if (p->n_pktq_out) { + uint32_t j; + + fprintf(f, "pktq_out ="); + for (j = 0; j < p->n_pktq_out; j++) { + struct app_pktq_out_params *pp = &p->pktq_out[j]; + char *name; + + switch (pp->type) { + case APP_PKTQ_OUT_HWQ: + name = app->hwq_out_params[pp->id].name; + break; + case APP_PKTQ_OUT_SWQ: + name = app->swq_params[pp->id].name; + break; + case APP_PKTQ_OUT_TM: + name = app->tm_params[pp->id].name; + break; + case APP_PKTQ_OUT_SINK: + name = app->sink_params[pp->id].name; + break; + default: + APP_CHECK(0, "Error\n"); + } + + fprintf(f, " %s", name); + } + fprintf(f, "\n"); + } + + /* msgq_in */ + if (p->n_msgq_in) { + uint32_t j; + + fprintf(f, "msgq_in ="); + for (j = 0; j < p->n_msgq_in; j++) { + uint32_t id = p->msgq_in[j]; + char *name = app->msgq_params[id].name; + + fprintf(f, " %s", name); + } + fprintf(f, "\n"); + } + + /* msgq_out */ + if (p->n_msgq_in) { + uint32_t j; + + fprintf(f, "msgq_out ="); + for (j = 0; j < p->n_msgq_out; j++) { + uint32_t id = p->msgq_out[j]; + char *name = app->msgq_params[id].name; + + fprintf(f, " %s", name); + } + fprintf(f, "\n"); + } + + /* timer_period */ + fprintf(f, "timer_period = %u\n", p->timer_period); + + /* args */ + if (p->n_args) { + uint32_t j; + + for (j = 0; j < p->n_args; j++) + fprintf(f, "%s = %s\n", p->args_name[j], p->args_value[j]); + } + + fprintf(f, "\n"); + } +} + +void +app_config_save(struct app_params *app, const char *file_name) +{ + FILE *file = fopen(file_name, "w"); + + APP_CHECK(file != NULL, "Failed to save config to file '%s'", file_name); + + save_pipeline_params(app, file); + save_mempool_params(app, file); + save_links_params(app, file); + save_rxq_params(app, file); + save_txq_params(app, file); + save_swq_params(app, file); + save_tm_params(app, file); + save_source_params(app, file); + save_msgq_params(app, file); + + fclose(file); +} + +int +app_config_init(struct app_params *app) +{ + size_t i; + + memset(app, 0, sizeof(struct app_params)); + + strcpy(app->config_file, DEFAULT_CONFIG_FILE); + + for (i = 0; i < RTE_DIM(app->mempool_params); i++) + memcpy(&app->mempool_params[i], &mempool_params_default, + sizeof(struct app_mempool_params)); + + for (i = 0; i < RTE_DIM(app->link_params); i++) + memcpy(&app->link_params[i], &link_params_default, + sizeof(struct app_link_params)); + + for (i = 0; i < RTE_DIM(app->hwq_in_params); i++) + memcpy(&app->hwq_in_params[i], &default_hwq_in_params, + sizeof(default_hwq_in_params)); + + for (i = 0; i < RTE_DIM(app->hwq_out_params); i++) + memcpy(&app->hwq_out_params[i], &default_hwq_out_params, + sizeof(default_hwq_out_params)); + + for (i = 0; i < RTE_DIM(app->swq_params); i++) + memcpy(&app->swq_params[i], &default_swq_params, + sizeof(default_swq_params)); + + for (i = 0; i < RTE_DIM(app->tm_params); i++) + memcpy(&app->tm_params[i], &default_tm_params, + sizeof(default_tm_params)); + + for (i = 0; i < RTE_DIM(app->source_params); i++) + memcpy(&app->source_params[i], &default_source_params, + sizeof(default_source_params)); + + for (i = 0; i < RTE_DIM(app->sink_params); i++) + memcpy(&app->sink_params[i], &default_sink_params, + sizeof(default_sink_params)); + + for (i = 0; i < RTE_DIM(app->msgq_params); i++) + memcpy(&app->msgq_params[i], &default_msgq_params, + sizeof(default_msgq_params)); + + for (i = 0; i < RTE_DIM(app->pipeline_params); i++) + memcpy(&app->pipeline_params[i], &default_pipeline_params, + sizeof(default_pipeline_params)); + + return 0; +} + +int +app_config_args(struct app_params *app, int argc, char **argv) +{ + int opt; + int option_index, p_present, f_present, s_present; + int scaned = 0; + + static struct option lgopts[] = { + {NULL, 0, 0, 0} + }; + + /* Copy application name */ + strncpy(app->app_name, argv[0], APP_APPNAME_SIZE - 1); + + p_present = 0; + f_present = 0; + s_present = 0; + + while ((opt = getopt_long(argc, argv, "f:s:p:", lgopts, + &option_index)) != EOF) { + switch (opt) { + case 'p': + if (sscanf(optarg, "%" SCNx64 "%n", &app->port_mask, &scaned) != 1 || + (size_t) scaned != strlen(optarg)) + rte_panic("Error: PORT_MASK is not a hexadecimal integer\n"); + + if (app->port_mask == 0) + rte_panic("Error: PORT_MASK is null\n"); + + if (p_present) + rte_panic("Error: PORT_MASK is provided more than once\n"); + + p_present = 1; + break; + + case 'f': + snprintf(app->config_file, sizeof(app->config_file), "%s", optarg); + + if (!strlen(app->config_file)) + rte_panic("Error: Config file name is null\n"); + + if (f_present) + rte_panic("Error: Config file is provided more than once\n"); + + f_present = 1; + break; + + case 's': + snprintf(app->script_file, sizeof(app->script_file), "%s", optarg); + + if (!strlen(app->script_file)) + rte_panic("Error: Script file name is null\n"); + + if (s_present) + rte_panic("Error: Script file is provided more than once\n"); + + s_present = 1; + break; + + default: + app_print_usage(argv[0]); + } + } + + optind = 0; /* reset getopt lib */ + + /* Check that mandatory args have been provided */ + if (!p_present) + rte_panic("Error: PORT_MASK is not provided\n"); + + return 0; +} diff --git a/examples/ip_pipeline/cpu_core_map.c b/examples/ip_pipeline/cpu_core_map.c new file mode 100644 index 0000000..0d83879 --- /dev/null +++ b/examples/ip_pipeline/cpu_core_map.c @@ -0,0 +1,465 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2015 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 "cpu_core_map.h" + +struct cpu_core_map { + uint32_t n_max_sockets; + uint32_t n_max_cores_per_socket; + uint32_t n_max_ht_per_core; + uint32_t n_sockets; + uint32_t n_cores_per_socket; + uint32_t n_ht_per_core; + int map[0]; +}; + +static inline uint32_t +cpu_core_map_pos(struct cpu_core_map *map, + uint32_t socket_id, + uint32_t core_id, + uint32_t ht_id) +{ + return (socket_id * map->n_max_cores_per_socket + core_id) * map->n_max_ht_per_core + ht_id; +} + +static int +cpu_core_map_compute_eal(struct cpu_core_map *map); + +static int +cpu_core_map_compute_linux(struct cpu_core_map *map); + +static int +cpu_core_map_compute_and_check(struct cpu_core_map *map); + +struct cpu_core_map * +cpu_core_map_init(uint32_t n_max_sockets, + uint32_t n_max_cores_per_socket, + uint32_t n_max_ht_per_core, + uint32_t eal_initialized) +{ + uint32_t map_size, map_mem_size, i; + struct cpu_core_map *map; + int status; + + /* Check input arguments */ + if ((n_max_sockets == 0) || + (n_max_cores_per_socket == 0) || + (n_max_ht_per_core == 0)) + return NULL; + + /* Memory allocation */ + map_size = n_max_sockets * n_max_cores_per_socket * n_max_ht_per_core; + map_mem_size = sizeof(struct cpu_core_map) + map_size * sizeof(int); + map = (struct cpu_core_map *) malloc(map_mem_size); + if (map == NULL) + return NULL; + + /* Initialization */ + map->n_max_sockets = n_max_sockets; + map->n_max_cores_per_socket = n_max_cores_per_socket; + map->n_max_ht_per_core = n_max_ht_per_core; + map->n_sockets = 0; + map->n_cores_per_socket = 0; + map->n_ht_per_core = 0; + + for (i = 0; i < map_size; i++) + map->map[i] = -1; + + status = (eal_initialized)? + cpu_core_map_compute_eal(map) : + cpu_core_map_compute_linux(map); + + if (status) { + free(map); + return NULL; + } + + status = cpu_core_map_compute_and_check(map); + if (status) { + free(map); + return NULL; + } + + return map; +} + +int +cpu_core_map_compute_eal(struct cpu_core_map *map) +{ + uint32_t socket_id, core_id, ht_id; + + /* Compute map */ + for (socket_id = 0; socket_id < map->n_max_sockets; socket_id++) { + uint32_t n_detected, core_id_contig; + int lcore_id; + + n_detected = 0; + for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { + struct lcore_config *p = &lcore_config[lcore_id]; + + if ((p->detected) && (p->socket_id == socket_id)) + n_detected ++; + } + + core_id_contig = 0; + + for (core_id = 0; n_detected ; core_id++) { + ht_id = 0; + + for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { + struct lcore_config *p = &lcore_config[lcore_id]; + + if ((p->detected) && + (p->socket_id == socket_id) && + (p->core_id == core_id)) { + uint32_t pos = cpu_core_map_pos(map, socket_id, core_id_contig, ht_id); + + map->map[pos] = lcore_id; + ht_id ++; + n_detected --; + } + } + + if (ht_id) { + core_id_contig ++; + if (core_id_contig == map->n_max_cores_per_socket) + return -1; + } + } + } + + return 0; +} + +int +cpu_core_map_compute_and_check(struct cpu_core_map *map) +{ + uint32_t socket_id, core_id, ht_id; + + /* Compute n_ht_per_core, n_cores_per_socket, n_sockets */ + for (ht_id = 0; ht_id < map->n_max_ht_per_core; ht_id++) { + if (map->map[ht_id] == -1) + break; + + map->n_ht_per_core ++; + } + + if (map->n_ht_per_core == 0) + return -1; + + for (core_id = 0; core_id < map->n_max_cores_per_socket; core_id++) { + uint32_t pos = core_id * map->n_max_ht_per_core; + + if (map->map[pos] == -1) + break; + + map->n_cores_per_socket ++; + } + + if (map->n_cores_per_socket == 0) + return -1; + + for (socket_id = 0; socket_id < map->n_max_sockets; socket_id++) { + uint32_t pos = socket_id * map->n_max_cores_per_socket * map->n_max_ht_per_core; + + if (map->map[pos] == -1) + break; + + map->n_sockets ++; + } + + if (map->n_sockets == 0) + return -1; + + /* Check that each socket has exactly the same number of cores + and that each core has exactly the same number of hyper-threads */ + for (socket_id = 0; socket_id < map->n_sockets; socket_id++) { + for (core_id = 0; core_id < map->n_cores_per_socket; core_id++) + for (ht_id = 0; ht_id < map->n_max_ht_per_core; ht_id++) { + uint32_t pos = (socket_id * map->n_max_cores_per_socket + core_id) * map->n_max_ht_per_core + ht_id; + + if (((ht_id < map->n_ht_per_core) && (map->map[pos] == -1)) || + ((ht_id >= map->n_ht_per_core) && (map->map[pos] != -1))) + return -1; + } + + for ( ; core_id < map->n_max_cores_per_socket; core_id++) + for (ht_id = 0; ht_id < map->n_max_ht_per_core; ht_id++) { + uint32_t pos = cpu_core_map_pos(map, socket_id, core_id, ht_id); + + if (map->map[pos] != -1) + return -1; + } + } + + return 0; +} + +#define FILE_LINUX_CPU_N_LCORES \ + "/sys/devices/system/cpu/present" + +static int +cpu_core_map_get_n_lcores_linux(void) +{ + char buffer[64], *string; + FILE* fd; + + fd = fopen(FILE_LINUX_CPU_N_LCORES, "r"); + if (fd == NULL) + return -1; + + if (fgets(buffer, sizeof(buffer), fd) == NULL) { + fclose(fd); + return -1; + } + + fclose(fd); + + string = index(buffer, '-'); + if (string == NULL) + return -1; + + return (atoi(++string) + 1); +} + +#define FILE_LINUX_CPU_CORE_ID \ + "/sys/devices/system/cpu/cpu%u/topology/core_id" + +static int +cpu_core_map_get_core_id_linux(int lcore_id) +{ + char buffer[64]; + FILE* fd; + int core_id; + + snprintf(buffer, sizeof(buffer), FILE_LINUX_CPU_CORE_ID, lcore_id); + fd = fopen(buffer, "r"); + if (fd == NULL) + return -1; + + if (fgets(buffer, sizeof(buffer), fd) == NULL) { + fclose(fd); + return -1; + } + + fclose(fd); + + core_id = atoi(buffer); + return core_id; +} + +#define FILE_LINUX_CPU_SOCKET_ID \ + "/sys/devices/system/cpu/cpu%u/topology/physical_package_id" + +static int +cpu_core_map_get_socket_id_linux(int lcore_id) +{ + char buffer[64]; + FILE* fd; + int socket_id; + + snprintf(buffer, sizeof(buffer), FILE_LINUX_CPU_SOCKET_ID, lcore_id); + fd = fopen(buffer, "r"); + if (fd == NULL) + return -1; + + if (fgets(buffer, sizeof(buffer), fd) == NULL) { + fclose(fd); + return -1; + } + + fclose(fd); + + socket_id = atoi(buffer); + return socket_id; +} + +int +cpu_core_map_compute_linux(struct cpu_core_map *map) +{ + uint32_t socket_id, core_id, ht_id; + int n_lcores; + + n_lcores = cpu_core_map_get_n_lcores_linux(); + if (n_lcores <= 0) + return -1; + + /* Compute map */ + for (socket_id = 0; socket_id < map->n_max_sockets; socket_id++) { + uint32_t n_detected, core_id_contig; + int lcore_id; + + n_detected = 0; + for (lcore_id = 0; lcore_id < n_lcores; lcore_id++) { + int lcore_socket_id = cpu_core_map_get_socket_id_linux(lcore_id); + if (lcore_socket_id < 0) + return -1; + + if (((uint32_t) lcore_socket_id) == socket_id) + n_detected ++; + } + + core_id_contig = 0; + + for (core_id = 0; n_detected ; core_id++) { + ht_id = 0; + + for (lcore_id = 0; lcore_id < n_lcores; lcore_id++) { + int lcore_socket_id = cpu_core_map_get_socket_id_linux(lcore_id); + if (lcore_socket_id < 0) + return -1; + + int lcore_core_id = cpu_core_map_get_core_id_linux(lcore_id); + if (lcore_core_id < 0) + return -1; + + if ((((uint32_t) lcore_socket_id) == socket_id) && + (((uint32_t) lcore_core_id) == core_id)) { + uint32_t pos = cpu_core_map_pos(map, socket_id, core_id_contig, ht_id); + + map->map[pos] = lcore_id; + ht_id ++; + n_detected --; + } + } + + if (ht_id) { + core_id_contig ++; + if (core_id_contig == map->n_max_cores_per_socket) + return -1; + } + } + } + + return 0; +} + +void +cpu_core_map_print(struct cpu_core_map *map) +{ +#if 1 + uint32_t socket_id, core_id, ht_id; + + if (map == NULL) + return; + + for (socket_id = 0; socket_id < map->n_sockets; socket_id++) { + printf("Socket %u:\n", socket_id); + + for (core_id = 0; core_id < map->n_cores_per_socket; core_id++) { + printf("[%2u] = [", core_id); + + for (ht_id = 0; ht_id < map->n_ht_per_core; ht_id++) { + int lcore_id = cpu_core_map_get_lcore_id(map, socket_id, core_id, ht_id); + //uint32_t core_id_noncontig = lcore_config[lcore_id].core_id; + uint32_t core_id_noncontig = cpu_core_map_get_core_id_linux(lcore_id); + + printf(" %2d (%2u) ", lcore_id, core_id_noncontig); + } + + printf("]\n"); + } + } +#else + uint32_t size, i; + + if (map == NULL) + return; + + size = map->n_max_sockets * map->n_max_cores_per_socket * map->n_max_ht_per_core; + printf("(n_sockets = %u, n_cores_per_socket = %u, n_ht_per_core = %u) [", + map->n_sockets, map->n_cores_per_socket, map->n_ht_per_core); + for (i = 0; i < size; i++) + printf("%d ", map->map[i]); + printf("]\n"); +#endif +} + +uint32_t +cpu_core_map_get_n_sockets(struct cpu_core_map *map) +{ + if (map == NULL) + return 0; + + return map->n_sockets; +} + +uint32_t +cpu_core_map_get_n_cores_per_socket(struct cpu_core_map *map) +{ + if (map == NULL) + return 0; + + return map->n_cores_per_socket; +} + +uint32_t +cpu_core_map_get_n_ht_per_core(struct cpu_core_map *map) +{ + if (map == NULL) + return 0; + + return map->n_ht_per_core; +} + +int +cpu_core_map_get_lcore_id(struct cpu_core_map *map, + uint32_t socket_id, + uint32_t core_id, + uint32_t ht_id) +{ + uint32_t pos; + + if ((map == NULL) || + (socket_id >= map->n_sockets) || + (core_id >= map->n_cores_per_socket) || + (ht_id >= map->n_ht_per_core)) + return -1; + + pos = cpu_core_map_pos(map, socket_id, core_id, ht_id); + + return map->map[pos]; +} + +void +cpu_core_map_free(struct cpu_core_map *map) +{ + if (map) + free(map); +} diff --git a/examples/ip_pipeline/cpu_core_map.h b/examples/ip_pipeline/cpu_core_map.h new file mode 100644 index 0000000..5c2ec72 --- /dev/null +++ b/examples/ip_pipeline/cpu_core_map.h @@ -0,0 +1,69 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2015 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. + */ + +#ifndef __INCLUDE_CPU_CORE_MAP_H__ +#define __INCLUDE_CPU_CORE_MAP_H__ + +#include + +#include + +struct cpu_core_map; + +struct cpu_core_map * +cpu_core_map_init(uint32_t n_max_sockets, + uint32_t n_max_cores_per_socket, + uint32_t n_max_ht_per_core, + uint32_t eal_initialized); + +uint32_t +cpu_core_map_get_n_sockets(struct cpu_core_map *map); + +uint32_t +cpu_core_map_get_n_cores_per_socket(struct cpu_core_map *map); + +uint32_t +cpu_core_map_get_n_ht_per_core(struct cpu_core_map *map); + +int +cpu_core_map_get_lcore_id(struct cpu_core_map *map, + uint32_t socket_id, + uint32_t core_id, + uint32_t ht_id); + +void cpu_core_map_print(struct cpu_core_map *map); + +void +cpu_core_map_free(struct cpu_core_map *map); + +#endif diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c index eb750b6..a2d7ef0 100644 --- a/examples/ip_pipeline/main.c +++ b/examples/ip_pipeline/main.c @@ -1,7 +1,7 @@ /*- * BSD LICENSE * - * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. + * Copyright(c) 2010-2015 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,135 +31,21 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "app.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "main.h" +static struct app_params app; int main(int argc, char **argv) { - int ret; - - /* Init EAL */ - ret = rte_eal_init(argc, argv); - if (ret < 0) - return -1; - argc -= ret; - argv += ret; + rte_openlog_stream(stderr); - /* Parse application arguments (after the EAL ones) */ - ret = app_parse_args(argc, argv); - if (ret < 0) { - app_print_usage(argv[0]); - return -1; - } + /* Config */ + app_config_init(&app); - /* Init */ - app_init(); + app_config_args(&app, argc, argv); - /* Launch per-lcore init on every lcore */ - rte_eal_mp_remote_launch(app_lcore_main_loop, NULL, CALL_MASTER); + app_config_parse(&app, app.config_file); return 0; } - -int -app_lcore_main_loop(__attribute__((unused)) void *arg) -{ - uint32_t core_id, i; - - core_id = rte_lcore_id(); - - for (i = 0; i < app.n_cores; i++) { - struct app_core_params *p = &app.cores[i]; - - if (p->core_id != core_id) - continue; - - switch (p->core_type) { - case APP_CORE_MASTER: - app_ping(); - app_main_loop_cmdline(); - return 0; - case APP_CORE_RX: - app_main_loop_pipeline_rx(); - /* app_main_loop_rx(); */ - return 0; - case APP_CORE_TX: - app_main_loop_pipeline_tx(); - /* app_main_loop_tx(); */ - return 0; - case APP_CORE_PT: - /* app_main_loop_pipeline_passthrough(); */ - app_main_loop_passthrough(); - return 0; - case APP_CORE_FC: - app_main_loop_pipeline_flow_classification(); - return 0; - case APP_CORE_FW: - case APP_CORE_RT: - app_main_loop_pipeline_routing(); - return 0; - -#ifdef RTE_LIBRTE_ACL - app_main_loop_pipeline_firewall(); - return 0; -#else - rte_exit(EXIT_FAILURE, "ACL not present in build\n"); -#endif - - case APP_CORE_IPV4_FRAG: - app_main_loop_pipeline_ipv4_frag(); - return 0; - case APP_CORE_IPV4_RAS: - app_main_loop_pipeline_ipv4_ras(); - return 0; - - default: - rte_panic("%s: Invalid core type for core %u\n", - __func__, i); - } - } - - rte_panic("%s: Algorithmic error\n", __func__); - return -1; -} diff --git a/examples/ip_pipeline/main.h b/examples/ip_pipeline/main.h deleted file mode 100644 index 6085aaa..0000000 --- a/examples/ip_pipeline/main.h +++ /dev/null @@ -1,298 +0,0 @@ -/*- - * BSD LICENSE - * - * Copyright(c) 2010-2014 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. - */ - -#ifndef _MAIN_H_ -#define _MAIN_H_ - -#include - -#include -#include -#include -#include - -#ifdef RTE_LIBRTE_ACL -#include -#endif - -struct app_flow_key { - union { - struct { - uint8_t ttl; /* needs to be set to 0 */ - uint8_t proto; - uint16_t header_checksum; /* needs to be set to 0 */ - uint32_t ip_src; - }; - uint64_t slab0; - }; - - union { - struct { - uint32_t ip_dst; - uint16_t port_src; - uint16_t port_dst; - }; - uint64_t slab1; - }; -} __attribute__((__packed__)); - -struct app_arp_key { - uint32_t nh_ip; - uint32_t nh_iface; -} __attribute__((__packed__)); - -struct app_pkt_metadata { - uint32_t signature; - uint8_t reserved1[28]; - - struct app_flow_key flow_key; - - struct app_arp_key arp_key; - struct ether_addr nh_arp; - - uint8_t reserved3[2]; -} __attribute__((__packed__)); - -#ifndef APP_MBUF_ARRAY_SIZE -#define APP_MBUF_ARRAY_SIZE 256 -#endif - -struct app_mbuf_array { - struct rte_mbuf *array[APP_MBUF_ARRAY_SIZE]; - uint32_t n_mbufs; -}; - -#ifndef APP_MAX_PORTS -#define APP_MAX_PORTS 4 -#endif - -#ifndef APP_MAX_SWQ_PER_CORE -#define APP_MAX_SWQ_PER_CORE 8 -#endif - -#define APP_SWQ_INVALID ((uint32_t)(-1)) - -#define APP_SWQ_IN_REQ (APP_MAX_SWQ_PER_CORE - 1) - -#define APP_SWQ_OUT_RESP (APP_MAX_SWQ_PER_CORE - 1) - -enum app_core_type { - APP_CORE_NONE = 0, /* Unused */ - APP_CORE_MASTER, /* Management */ - APP_CORE_RX, /* Reception */ - APP_CORE_TX, /* Transmission */ - APP_CORE_PT, /* Pass-through */ - APP_CORE_FC, /* Flow Classification */ - APP_CORE_FW, /* Firewall */ - APP_CORE_RT, /* Routing */ - APP_CORE_TM, /* Traffic Management */ - APP_CORE_IPV4_FRAG,/* IPv4 Fragmentation */ - APP_CORE_IPV4_RAS, /* IPv4 Reassembly */ -}; - -struct app_core_params { - uint32_t core_id; - enum app_core_type core_type; - - /* SWQ map */ - uint32_t swq_in[APP_MAX_SWQ_PER_CORE]; - uint32_t swq_out[APP_MAX_SWQ_PER_CORE]; -} __rte_cache_aligned; - -struct app_params { - /* CPU cores */ - struct app_core_params cores[RTE_MAX_LCORE]; - uint32_t n_cores; - - /* Ports*/ - uint32_t ports[APP_MAX_PORTS]; - uint32_t n_ports; - uint32_t rsz_hwq_rx; - uint32_t rsz_hwq_tx; - uint32_t bsz_hwq_rd; - uint32_t bsz_hwq_wr; - struct rte_eth_conf port_conf; - struct rte_eth_rxconf rx_conf; - struct rte_eth_txconf tx_conf; - - /* SW Queues (SWQs) */ - struct rte_ring **rings; - uint32_t rsz_swq; - uint32_t bsz_swq_rd; - uint32_t bsz_swq_wr; - - /* Buffer pool */ - struct rte_mempool *pool; - struct rte_mempool *indirect_pool; - uint32_t pool_buffer_size; - uint32_t pool_size; - uint32_t pool_cache_size; - - /* Message buffer pool */ - struct rte_mempool *msg_pool; - uint32_t msg_pool_buffer_size; - uint32_t msg_pool_size; - uint32_t msg_pool_cache_size; - - /* Rule tables */ - uint32_t max_arp_rules; - uint32_t max_routing_rules; - uint32_t max_firewall_rules; - uint32_t max_flow_rules; - - /* Processing */ - uint32_t ether_hdr_pop_push; -} __rte_cache_aligned; - -extern struct app_params app; - -const char *app_core_type_id_to_string(enum app_core_type id); -int app_core_type_string_to_id(const char *string, enum app_core_type *id); -void app_cores_config_print(void); - -void app_check_core_params(void); -struct app_core_params *app_get_core_params(uint32_t core_id); -uint32_t app_get_first_core_id(enum app_core_type core_type); -struct rte_ring *app_get_ring_req(uint32_t core_id); -struct rte_ring *app_get_ring_resp(uint32_t core_id); - -int app_parse_args(int argc, char **argv); -void app_print_usage(char *prgname); -void app_init(void); -void app_ping(void); -int app_lcore_main_loop(void *arg); - -/* Hash functions */ -uint64_t test_hash(void *key, uint32_t key_size, uint64_t seed); -uint32_t rte_jhash2_16(uint32_t *k, uint32_t initval); -#if defined(__x86_64__) -uint32_t rte_aeshash_16(uint64_t *k, uint64_t seed); -uint32_t rte_crchash_16(uint64_t *k, uint64_t seed); -#endif - -/* I/O with no pipeline */ -void app_main_loop_rx(void); -void app_main_loop_tx(void); -void app_main_loop_passthrough(void); - -/* Pipeline */ -void app_main_loop_pipeline_rx(void); -void app_main_loop_pipeline_rx_frag(void); -void app_main_loop_pipeline_tx(void); -void app_main_loop_pipeline_tx_ras(void); -void app_main_loop_pipeline_flow_classification(void); -void app_main_loop_pipeline_firewall(void); -void app_main_loop_pipeline_routing(void); -void app_main_loop_pipeline_passthrough(void); -void app_main_loop_pipeline_ipv4_frag(void); -void app_main_loop_pipeline_ipv4_ras(void); - -/* Command Line Interface (CLI) */ -void app_main_loop_cmdline(void); - -/* Messages */ -enum app_msg_req_type { - APP_MSG_REQ_PING, - APP_MSG_REQ_FC_ADD, - APP_MSG_REQ_FC_DEL, - APP_MSG_REQ_FC_ADD_ALL, - APP_MSG_REQ_FW_ADD, - APP_MSG_REQ_FW_DEL, - APP_MSG_REQ_RT_ADD, - APP_MSG_REQ_RT_DEL, - APP_MSG_REQ_ARP_ADD, - APP_MSG_REQ_ARP_DEL, - APP_MSG_REQ_RX_PORT_ENABLE, - APP_MSG_REQ_RX_PORT_DISABLE, -}; - -struct app_msg_req { - enum app_msg_req_type type; - union { - struct { - uint32_t ip; - uint8_t depth; - uint8_t port; - uint32_t nh_ip; - } routing_add; - struct { - uint32_t ip; - uint8_t depth; - } routing_del; - struct { - uint8_t out_iface; - uint32_t nh_ip; - struct ether_addr nh_arp; - } arp_add; - struct { - uint8_t out_iface; - uint32_t nh_ip; - } arp_del; - struct { - union { - uint8_t key_raw[16]; - struct app_flow_key key; - }; - uint8_t port; - } flow_classif_add; - struct { - union { - uint8_t key_raw[16]; - struct app_flow_key key; - }; - } flow_classif_del; -#ifdef RTE_LIBRTE_ACL - struct { - struct rte_table_acl_rule_add_params add_params; - uint8_t port; - } firewall_add; - struct { - struct rte_table_acl_rule_delete_params delete_params; - } firewall_del; -#endif - struct { - uint8_t port; - } rx_up; - struct { - uint8_t port; - } rx_down; - }; -}; - -struct app_msg_resp { - int result; -}; - -#define APP_FLUSH 0xFF - -#endif /* _MAIN_H_ */ diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h new file mode 100644 index 0000000..de85f82 --- /dev/null +++ b/examples/ip_pipeline/pipeline.h @@ -0,0 +1,79 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2015 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. + */ + +#ifndef __INCLUDE_PIPELINE_H__ +#define __INCLUDE_PIPELINE_H__ + +#include + +#include "pipeline_ops.h" + +typedef void* (*pipeline_fe_op_init)(struct pipeline_params *params, void *arg); + +typedef int (*pipeline_fe_op_free)(void *pipeline); + +struct pipeline_fe_ops { + pipeline_fe_op_init f_init; + pipeline_fe_op_free f_free; + cmdline_parse_ctx_t *cmds; +}; + +struct pipeline_type { + const char *name; + + /* pipeline back-end */ + struct pipeline_ops *ops; + + /* pipeline front-end */ + struct pipeline_fe_ops *fe_ops; +}; + +static inline uint32_t +pipeline_type_cmds_count(struct pipeline_type *ptype) +{ + cmdline_parse_ctx_t *cmds; + uint32_t n_cmds; + + if (ptype->fe_ops == NULL) + return 0; + + cmds = ptype->fe_ops->cmds; + if (cmds == NULL) + return 0; + + for (n_cmds = 0; cmds[n_cmds]; n_cmds++); + + return n_cmds; +} + +#endif diff --git a/examples/ip_pipeline/pipeline_ops.h b/examples/ip_pipeline/pipeline_ops.h new file mode 100644 index 0000000..ae98dc7 --- /dev/null +++ b/examples/ip_pipeline/pipeline_ops.h @@ -0,0 +1,247 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2015 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. + */ + +#ifndef __INCLUDE_PIPELINE_OPS_H__ +#define __INCLUDE_PIPELINE_OPS_H__ + +#include +#include +#include +#include +#include +#include +#include + +enum pipeline_port_in_type { + PIPELINE_PORT_IN_ETHDEV_READER, + PIPELINE_PORT_IN_RING_READER, + PIPELINE_PORT_IN_RING_READER_IPV4_FRAG, + PIPELINE_PORT_IN_RING_READER_IPV6_FRAG, + PIPELINE_PORT_IN_SCHED_READER, + PIPELINE_PORT_IN_SOURCE, +}; + +struct pipeline_port_in_params { + enum pipeline_port_in_type type; + union { + struct rte_port_ethdev_reader_params ethdev; + struct rte_port_ring_reader_params ring; + struct rte_port_ring_reader_ipv4_frag_params ring_ipv4_frag; + struct rte_port_ring_reader_ipv6_frag_params ring_ipv6_frag; + struct rte_port_sched_reader_params sched; + struct rte_port_source_params source; + } params; + uint32_t burst_size; +}; + +static inline void * +pipeline_port_in_params_convert(struct pipeline_port_in_params *p) +{ + switch (p->type) { + case PIPELINE_PORT_IN_ETHDEV_READER: + return (void *) &p->params.ethdev; + case PIPELINE_PORT_IN_RING_READER: + return (void *) &p->params.ring; + case PIPELINE_PORT_IN_RING_READER_IPV4_FRAG: + return (void *) &p->params.ring_ipv4_frag; + case PIPELINE_PORT_IN_RING_READER_IPV6_FRAG: + return (void *) &p->params.ring_ipv6_frag; + case PIPELINE_PORT_IN_SCHED_READER: + return (void *) &p->params.sched; + case PIPELINE_PORT_IN_SOURCE: + return (void *) &p->params.source; + default: + return NULL; + } +} + +static inline struct rte_port_in_ops * +pipeline_port_in_params_get_ops(struct pipeline_port_in_params *p) +{ + switch (p->type) { + case PIPELINE_PORT_IN_ETHDEV_READER: + return &rte_port_ethdev_reader_ops; + case PIPELINE_PORT_IN_RING_READER: + return &rte_port_ring_reader_ops; + case PIPELINE_PORT_IN_RING_READER_IPV4_FRAG: + return &rte_port_ring_reader_ipv4_frag_ops; + case PIPELINE_PORT_IN_RING_READER_IPV6_FRAG: + return &rte_port_ring_reader_ipv6_frag_ops; + case PIPELINE_PORT_IN_SCHED_READER: + return &rte_port_sched_reader_ops; + case PIPELINE_PORT_IN_SOURCE: + return &rte_port_source_ops; + default: + return NULL; + } +} + +enum pipeline_port_out_type { + PIPELINE_PORT_OUT_ETHDEV_WRITER, + PIPELINE_PORT_OUT_ETHDEV_WRITER_NODROP, + PIPELINE_PORT_OUT_RING_WRITER, + PIPELINE_PORT_OUT_RING_WRITER_NODROP, + PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS, + PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS, + PIPELINE_PORT_OUT_SCHED_WRITER, + PIPELINE_PORT_OUT_SINK, +}; + +struct pipeline_port_out_params { + enum pipeline_port_out_type type; + union { + struct rte_port_ethdev_writer_params ethdev; + struct rte_port_ethdev_writer_nodrop_params ethdev_nodrop; + struct rte_port_ring_writer_params ring; + struct rte_port_ring_writer_nodrop_params ring_nodrop; + struct rte_port_ring_writer_ipv4_ras_params ring_ipv4_ras; + struct rte_port_ring_writer_ipv6_ras_params ring_ipv6_ras; + struct rte_port_sched_writer_params sched; + } params; +}; + +static inline void * +pipeline_port_out_params_convert(struct pipeline_port_out_params *p) +{ + switch (p->type) { + case PIPELINE_PORT_OUT_ETHDEV_WRITER: + return (void *) &p->params.ethdev; + case PIPELINE_PORT_OUT_ETHDEV_WRITER_NODROP: + return (void *) &p->params.ethdev_nodrop; + case PIPELINE_PORT_OUT_RING_WRITER: + return (void *) &p->params.ring; + case PIPELINE_PORT_OUT_RING_WRITER_NODROP: + return (void *) &p->params.ring_nodrop; + case PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS: + return (void *) &p->params.ring_ipv4_ras; + case PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS: + return (void *) &p->params.ring_ipv6_ras; + case PIPELINE_PORT_OUT_SCHED_WRITER: + return (void *) &p->params.sched; + case PIPELINE_PORT_OUT_SINK: + default: + return NULL; + } +} + +static inline void * +pipeline_port_out_params_get_ops(struct pipeline_port_out_params *p) +{ + switch (p->type) { + case PIPELINE_PORT_OUT_ETHDEV_WRITER: + return &rte_port_ethdev_writer_ops; + case PIPELINE_PORT_OUT_ETHDEV_WRITER_NODROP: + return &rte_port_ethdev_writer_nodrop_ops; + case PIPELINE_PORT_OUT_RING_WRITER: + return &rte_port_ring_writer_ops; + case PIPELINE_PORT_OUT_RING_WRITER_NODROP: + return &rte_port_ring_writer_nodrop_ops; + case PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS: + return &rte_port_ring_writer_ipv4_ras_ops; + case PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS: + return &rte_port_ring_writer_ipv6_ras_ops; + case PIPELINE_PORT_OUT_SCHED_WRITER: + return &rte_port_sched_writer_ops; + case PIPELINE_PORT_OUT_SINK: + return &rte_port_sink_ops; + default: + return NULL; + } +} + +#ifndef PIPELINE_NAME_SIZE +#define PIPELINE_NAME_SIZE 32 +#endif + +#ifndef PIPELINE_MAX_PORT_IN +#define PIPELINE_MAX_PORT_IN 16 +#endif + +#ifndef PIPELINE_MAX_PORT_OUT +#define PIPELINE_MAX_PORT_OUT 16 +#endif + +#ifndef PIPELINE_MAX_TABLES +#define PIPELINE_MAX_TABLES 16 +#endif + +#ifndef PIPELINE_MAX_MSGQ_IN +#define PIPELINE_MAX_MSGQ_IN 16 +#endif + +#ifndef PIPELINE_MAX_MSGQ_OUT +#define PIPELINE_MAX_MSGQ_OUT 16 +#endif + +#ifndef PIPELINE_MAX_ARGS +#define PIPELINE_MAX_ARGS 32 +#endif + +struct pipeline_params { + char name[PIPELINE_NAME_SIZE]; + + struct pipeline_port_in_params port_in[PIPELINE_MAX_PORT_IN]; + struct pipeline_port_out_params port_out[PIPELINE_MAX_PORT_OUT]; + struct rte_ring *msgq_in[PIPELINE_MAX_MSGQ_IN]; + struct rte_ring *msgq_out[PIPELINE_MAX_MSGQ_OUT]; + + uint32_t n_ports_in; + uint32_t n_ports_out; + uint32_t n_msgq; + + int socket_id; + + char *args_name[PIPELINE_MAX_ARGS]; + char *args_value[PIPELINE_MAX_ARGS]; + uint32_t n_args; +}; + +typedef void* (*pipeline_op_init)(struct pipeline_params *params, void *arg); + +typedef int (*pipeline_op_free)(void *pipeline); + +typedef int (*pipeline_op_run)(void *pipeline); + +typedef int (*pipeline_op_timer)(void *pipeline); + +typedef int (*pipeline_op_track)(void *pipeline, uint32_t port_in, uint32_t *port_out); + +struct pipeline_ops { + pipeline_op_init f_init; + pipeline_op_free f_free; + pipeline_op_run f_run; + pipeline_op_timer f_timer; + pipeline_op_track f_track; +}; + +#endif -- 1.7.9.5