From patchwork Wed Mar 18 21:35:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66895 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 426AEA057E; Wed, 18 Mar 2020 22:35:33 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 108F52C28; Wed, 18 Mar 2020 22:35:28 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by dpdk.org (Postfix) with ESMTP id 2E1562C23 for ; Wed, 18 Mar 2020 22:35:27 +0100 (CET) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILUsBv003334; Wed, 18 Mar 2020 14:35:24 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=kbHt9+KMf7KDnYhNTVf9iJafqJp31TEUyhdok6XGhOY=; b=oLxWlo8OK7P02bCCR3teJhwnB2WYyiRg2fLpoJdcSPDhtu39ziCVJC9DgTF0wb7mgleA jk3wdXddp1Za0QJ/qeHrFN8MM4NsxIwpQ0g1i4eBjd5GyzE+9rnKms/15JLtsGjSg2f4 1URDgsKf0Uy8bdtmVwc1QUcZDUNkwX/v4XPmkF7gfvl+RS5NXBxnJuXrUXtLJimwpoyu ctEU0g752zKN0unmhKB7r/JGAYyTiX5m3rQvVUp7GAqN+DYxKRKDgeTEuHNdZbl54TQZ ekMXuy75X5dhmr7sKfI1LqJILJL1BE9RdzX/whUz9yNJQ0aTAIZ1VODET5oiKBl18KcF rg== Received: from sc-exch01.marvell.com ([199.233.58.181]) by mx0a-0016f401.pphosted.com with ESMTP id 2yu8pqmr7m-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:35:24 -0700 Received: from SC-EXCH03.marvell.com (10.93.176.83) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:35:22 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:35:22 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id 09EBF3F703F; Wed, 18 Mar 2020 14:35:18 -0700 (PDT) From: To: Thomas Monjalon , Bruce Richardson , John McNamara , "Marko Kovacevic" , Jerin Jacob , Kiran Kumar K CC: , , , , , Date: Thu, 19 Mar 2020 03:05:26 +0530 Message-ID: <20200318213551.3489504-2-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 01/26] graph: define the public API for graph support X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Jerin Jacob Graph architecture abstracts the data processing functions as "node" and "link" them together to create a complex "graph" to enable reusable/modular data processing functions. These APIs enables graph framework operations such as create, lookup, dump and destroy on graph and node operations such as clone, edge update, and edge shrink, etc. The API also allows creating the stats cluster to monitor per graph and per node stats. This patch defines the public API for graph support. This patch also adds support for the build infrastructure and update the MAINTAINERS file for the graph subsystem. Signed-off-by: Jerin Jacob Signed-off-by: Kiran Kumar K Signed-off-by: Pavan Nikhilesh Signed-off-by: Nithin Dabilpuram --- MAINTAINERS | 5 + config/common_base | 7 + config/rte_config.h | 4 + doc/api/doxy-api-index.md | 1 + doc/api/doxy-api.conf.in | 1 + lib/Makefile | 3 + lib/librte_graph/Makefile | 22 + lib/librte_graph/graph.c | 5 + lib/librte_graph/meson.build | 11 + lib/librte_graph/rte_graph.h | 786 +++++++++++++++++++++++++ lib/librte_graph/rte_graph_version.map | 3 + lib/meson.build | 2 +- mk/rte.app.mk | 1 + 13 files changed, 850 insertions(+), 1 deletion(-) create mode 100644 lib/librte_graph/Makefile create mode 100644 lib/librte_graph/graph.c create mode 100644 lib/librte_graph/meson.build create mode 100644 lib/librte_graph/rte_graph.h create mode 100644 lib/librte_graph/rte_graph_version.map diff --git a/MAINTAINERS b/MAINTAINERS index c3785554f..32d0ea032 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1468,6 +1468,11 @@ F: examples/bpf/ F: app/test/test_bpf.c F: doc/guides/prog_guide/bpf_lib.rst +Graph - EXPERIMENTAL +M: Jerin Jacob +M: Kiran Kumar K +F: lib/librte_graph/ + Test Applications ----------------- diff --git a/config/common_base b/config/common_base index 7ca2f28b1..04a96aef5 100644 --- a/config/common_base +++ b/config/common_base @@ -1075,6 +1075,13 @@ CONFIG_RTE_LIBRTE_BPF_ELF=n # CONFIG_RTE_LIBRTE_IPSEC=y +# +# Compile librte_graph +# +CONFIG_RTE_LIBRTE_GRAPH=y +CONFIG_RTE_GRAPH_BURST_SIZE=256 +CONFIG_RTE_LIBRTE_GRAPH_STATS=y + # # Compile the test application # diff --git a/config/rte_config.h b/config/rte_config.h index d30786bc0..e9201fd46 100644 --- a/config/rte_config.h +++ b/config/rte_config.h @@ -98,6 +98,10 @@ /* KNI defines */ #define RTE_KNI_PREEMPT_DEFAULT 1 +/* rte_graph defines */ +#define RTE_GRAPH_BURST_SIZE 256 +#define RTE_LIBRTE_GRAPH_STATS 1 + /****** driver defines ********/ /* QuickAssist device */ diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md index dff496be0..5cc50f750 100644 --- a/doc/api/doxy-api-index.md +++ b/doc/api/doxy-api-index.md @@ -159,6 +159,7 @@ The public API headers are grouped by topics: * [pipeline] (@ref rte_pipeline.h) [port_in_action] (@ref rte_port_in_action.h) [table_action] (@ref rte_table_action.h) + * [graph] (@ref rte_graph.h): - **basic**: [approx fraction] (@ref rte_approx.h), diff --git a/doc/api/doxy-api.conf.in b/doc/api/doxy-api.conf.in index 1c4392eec..759a7213e 100644 --- a/doc/api/doxy-api.conf.in +++ b/doc/api/doxy-api.conf.in @@ -33,6 +33,7 @@ INPUT = @TOPDIR@/doc/api/doxy-api-index.md \ @TOPDIR@/lib/librte_eventdev \ @TOPDIR@/lib/librte_fib \ @TOPDIR@/lib/librte_flow_classify \ + @TOPDIR@/lib/librte_graph \ @TOPDIR@/lib/librte_gro \ @TOPDIR@/lib/librte_gso \ @TOPDIR@/lib/librte_hash \ diff --git a/lib/Makefile b/lib/Makefile index 46b91ae1a..1f572b659 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -119,6 +119,9 @@ DEPDIRS-librte_telemetry := librte_eal librte_metrics librte_ethdev DIRS-$(CONFIG_RTE_LIBRTE_RCU) += librte_rcu DEPDIRS-librte_rcu := librte_eal +DIRS-$(CONFIG_RTE_LIBRTE_GRAPH) += librte_graph +DEPDIRS-librte_graph := librte_eal + ifeq ($(CONFIG_RTE_EXEC_ENV_LINUX),y) DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni endif diff --git a/lib/librte_graph/Makefile b/lib/librte_graph/Makefile new file mode 100644 index 000000000..26fe514f3 --- /dev/null +++ b/lib/librte_graph/Makefile @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(C) 2020 Marvell International Ltd. +# + +include $(RTE_SDK)/mk/rte.vars.mk + +# library name +LIB = librte_graph.a + +CFLAGS += -O3 -DALLOW_EXPERIMENTAL_API +CFLAGS += $(WERROR_FLAGS) +LDLIBS += -lrte_eal + +EXPORT_MAP := rte_graph_version.map + +# all source are stored in SRCS-y +SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += graph.c + +# install header files +SYMLINK-$(CONFIG_RTE_LIBRTE_GRAPH)-include += rte_graph.h + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/lib/librte_graph/graph.c b/lib/librte_graph/graph.c new file mode 100644 index 000000000..a55bf443a --- /dev/null +++ b/lib/librte_graph/graph.c @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#include "rte_graph.h" diff --git a/lib/librte_graph/meson.build b/lib/librte_graph/meson.build new file mode 100644 index 000000000..455cf2ba5 --- /dev/null +++ b/lib/librte_graph/meson.build @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(C) 2020 Marvell International Ltd. +# + +name = 'graph' + +sources = files('graph.c') +headers = files('rte_graph.h') +allow_experimental_apis = true + +deps += ['eal'] diff --git a/lib/librte_graph/rte_graph.h b/lib/librte_graph/rte_graph.h new file mode 100644 index 000000000..4bcf0a6e5 --- /dev/null +++ b/lib/librte_graph/rte_graph.h @@ -0,0 +1,786 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#ifndef _RTE_GRAPH_H_ +#define _RTE_GRAPH_H_ + +/** + * @file rte_graph.h + * + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Graph architecture abstracts the data processing functions as + * "node" and "link" them together to create a complex "graph" to enable + * reusable/modular data processing functions. + * + * This API enables graph framework operations such as create, lookup, + * dump and destroy on graph and node operations such as clone, + * edge update, and edge shrink, etc. The API also allows to create the stats + * cluster to monitor per graph and per node stats. + * + */ + +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define RTE_GRAPH_NAMESIZE 64 /**< Max length of graph name. */ +#define RTE_NODE_NAMESIZE 64 /**< Max length of node name. */ +#define RTE_GRAPH_OFF_INVALID UINT32_MAX /**< Invalid graph offset. */ +#define RTE_NODE_ID_INVALID UINT32_MAX /**< Invalid node id. */ +#define RTE_EDGE_ID_INVALID UINT16_MAX /**< Invalid edge id. */ +#define RTE_GRAPH_ID_INVALID UINT16_MAX /**< Invalid graph id. */ +#define RTE_GRAPH_FENCE 0xdeadbeef12345678ULL /**< Graph fence data. */ + +typedef uint32_t rte_graph_off_t; /**< Graph offset type. */ +typedef uint32_t rte_node_t; /**< Node id type. */ +typedef uint16_t rte_edge_t; /**< Edge id type. */ +typedef uint16_t rte_graph_t; /**< Graph id type. */ + +/** Burst size in terms of log2 */ +#if RTE_GRAPH_BURST_SIZE == 1 +#define RTE_GRAPH_BURST_SIZE_LOG2 0 /**< Object burst size of 1. */ +#elif RTE_GRAPH_BURST_SIZE == 2 +#define RTE_GRAPH_BURST_SIZE_LOG2 1 /**< Object burst size of 2. */ +#elif RTE_GRAPH_BURST_SIZE == 4 +#define RTE_GRAPH_BURST_SIZE_LOG2 2 /**< Object burst size of 4. */ +#elif RTE_GRAPH_BURST_SIZE == 8 +#define RTE_GRAPH_BURST_SIZE_LOG2 3 /**< Object burst size of 8. */ +#elif RTE_GRAPH_BURST_SIZE == 16 +#define RTE_GRAPH_BURST_SIZE_LOG2 4 /**< Object burst size of 16. */ +#elif RTE_GRAPH_BURST_SIZE == 32 +#define RTE_GRAPH_BURST_SIZE_LOG2 5 /**< Object burst size of 32. */ +#elif RTE_GRAPH_BURST_SIZE == 64 +#define RTE_GRAPH_BURST_SIZE_LOG2 6 /**< Object burst size of 64. */ +#elif RTE_GRAPH_BURST_SIZE == 128 +#define RTE_GRAPH_BURST_SIZE_LOG2 7 /**< Object burst size of 128. */ +#elif RTE_GRAPH_BURST_SIZE == 256 +#define RTE_GRAPH_BURST_SIZE_LOG2 8 /**< Object burst size of 256. */ +#else +#error "Unsupported burst size" +#endif + +/* Forward declaration */ +struct rte_node; /**< Node data */ +struct rte_graph; /**< Graph data */ +struct rte_graph_cluster_stats; /**< Stats for Cluster of graphs */ +struct rte_graph_cluster_node_stats; /**< Node stats within cluster of graphs */ + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Node process function. + * + * The function invoked when the worker thread walks on nodes using + * rte_graph_walk(). + * + * @param graph + * Pointer to the graph object. + * @param node + * Pointer to the node object. + * @param objs + * Pointer to an array of objects to be processed. + * @param nb_objs + * Number of objects in the array. + * + * @return + * Number of objects processed. + * + * @see rte_graph_walk() + * + */ +typedef uint16_t (*rte_node_process_t)(struct rte_graph *graph, + struct rte_node *node, void **objs, + uint16_t nb_objs); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Node initialization function. + * + * The function invoked when the user creates the graph using rte_graph_create() + * + * @param graph + * Pointer to the graph object. + * @param node + * Pointer to the node object. + * + * @return + * - 0: Success. + * -<0: Failure. + * + * @see rte_graph_create() + */ +typedef int (*rte_node_init_t)(const struct rte_graph *graph, + struct rte_node *node); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Node finalization function. + * + * The function invoked when the user destroys the graph using + * rte_graph_destroy(). + * + * @param graph + * Pointer to the graph object. + * @param node + * Pointer to the node object. + * + * @see rte_graph_destroy() + */ +typedef void (*rte_node_fini_t)(const struct rte_graph *graph, + struct rte_node *node); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Graph cluster stats callback. + * + * @param is_first + * Flag to denote that stats are of the first node. + * @param is_last + * Flag to denote that stats are of the last node. + * @param cookie + * Cookie supplied during stats creation. + * @param stats + * Node cluster stats data. + * + * @return + * - 0: Success. + * -<0: Failure. + */ +typedef int (*rte_graph_cluster_stats_cb_t)(bool is_first, bool is_last, + void *cookie, const struct rte_graph_cluster_node_stats *stats); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Structure to hold configuration parameters for creating the graph. + * + * @see rte_graph_create() + */ +struct rte_graph_param { + int socket_id; /**< Socket id where memory is allocated. */ + uint16_t nb_node_patterns; /**< Number of node patterns. */ + const char **node_patterns; + /**< Array of node patterns based on shell pattern. */ +}; + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Structure to hold configuration parameters for graph cluster stats create. + * + * @see rte_graph_cluster_stats_create() + */ +struct rte_graph_cluster_stats_param { + int socket_id; + /**< Socket id where memory is allocated */ + rte_graph_cluster_stats_cb_t fn; + /**< Stats print callback function. NULL value allowed, in that case, + * default print stat function used. + */ + RTE_STD_C11 + union { + void *cookie; + FILE *f; /**< File pointer to dump the stats when fn == NULL. */ + }; + uint16_t nb_graph_patterns; /**< Number of graph patterns. */ + const char **graph_patterns; + /**< Array of graph patterns based on shell pattern. */ +}; + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Node cluster stats data structure. + * + * @see struct rte_graph_cluster_stats_param::fn + */ +struct rte_graph_cluster_node_stats { + uint64_t ts; /**< Current timestamp. */ + uint64_t calls; /**< Current number of calls made. */ + uint64_t objs; /**< Current number of objs processed. */ + uint64_t cycles; /**< Current number of cycles. */ + + uint64_t prev_ts; /**< Previous call timestamp. */ + uint64_t prev_calls; /**< Previous number of calls. */ + uint64_t prev_objs; /**< Previous number of processed objs. */ + uint64_t prev_cycles; /**< Previous number of cycles. */ + + uint64_t realloc_count; /**< Realloc count. */ + + rte_node_t id; /**< Node identifier of stats. */ + uint64_t hz; /**< Cycles per seconds. */ + char name[RTE_NODE_NAMESIZE]; /**< Name of the node. */ +} __rte_cache_aligned; + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Structure defines the node registration parameters. + * + * @see __rte_node_register(), RTE_NODE_REGISTER() + */ +struct rte_node_register { + char name[RTE_NODE_NAMESIZE]; /**< Name of the node. */ + uint64_t flags; /**< Node configuration flag. */ +#define RTE_NODE_SOURCE_F (1ULL << 0) /**< Node type is source. */ + rte_node_process_t process; /**< Node process function. */ + rte_node_init_t init; /**< Node init function. */ + rte_node_fini_t fini; /**< Node fini function. */ + rte_node_t id; /**< Node Identifier. */ + rte_node_t parent_id; /**< Identifier of parent node. */ + rte_edge_t nb_edges; /**< Number of edges from this node. */ + const char *next_nodes[]; /**< Names of next nodes. */ +}; + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Create Graph. + * + * Create memory reel, detect loops and find isolated nodes. + * + * @param name + * Unique name for this graph. + * @param prm + * Graph parameter, includes node names and count to be included + * in this graph. + * + * @return + * Unique graph id on success, RTE_GRAPH_ID_INVALID otherwise. + */ +__rte_experimental +rte_graph_t rte_graph_create(const char *name, struct rte_graph_param *prm); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Destroy Graph. + * + * Free Graph memory reel. + * + * @param name + * Name of the graph to destroy. + * + * @return + * 0 on success, error otherwise. + */ +__rte_experimental +rte_graph_t rte_graph_destroy(const char *name); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Get graph id from graph name. + * + * @param name + * Name of the graph to get id. + * + * @return + * Graph id on success, RTE_GRAPH_ID_INVALID otherwise. + */ +__rte_experimental +rte_graph_t rte_graph_from_name(const char *name); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Get graph name from graph id. + * + * @param id + * id of the graph to get name. + * + * @return + * Graph name on success, NULL otherwise. + */ +__rte_experimental +char *rte_graph_id_to_name(rte_graph_t id); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Export the graph as graph viz dot file + * + * @param name + * Name of the graph to export. + * @param f + * File pointer to export the graph. + * + * @return + * 0 on success, error otherwise. + */ +__rte_experimental +rte_graph_t rte_graph_export(const char *name, FILE *f); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Get graph object from its name. + * + * Typical usage of this API to get graph objects in the worker thread and + * followed calling rte_graph_walk() in a loop. + * + * @param name + * Name of the graph. + * + * @return + * Graph pointer on success, NULL otherwise. + * + * @see rte_graph_walk() + */ +__rte_experimental +struct rte_graph *rte_graph_lookup(const char *name); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Get maximum number of graph available. + * + * @return + * Maximum graph count on success, RTE_GRAPH_ID_INVALID otherwise. + */ +__rte_experimental +rte_graph_t rte_graph_max_count(void); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Dump the graph information to file. + * + * @param f + * File pointer to dump graph info. + * @param id + * Graph id to get graph info. + */ +__rte_experimental +void rte_graph_dump(FILE *f, rte_graph_t id); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Dump all graphs information to file + * + * @param f + * File pointer to dump graph info. + */ +__rte_experimental +void rte_graph_list_dump(FILE *f); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Dump graph information along with node info to file + * + * @param f + * File pointer to dump graph info. + * @param graph + * Graph pointer to get graph info. + * @param all + * true to dump nodes in the graph. + */ +__rte_experimental +void rte_graph_obj_dump(FILE *f, struct rte_graph *graph, bool all); + +/** Macro to browse rte_node object after the graph creation */ +#define rte_graph_foreach_node(count, off, graph, node) \ + for (count = 0, off = graph->nodes_start, \ + node = RTE_PTR_ADD(graph, off); \ + count < graph->nb_nodes; \ + off = node->next, node = RTE_PTR_ADD(graph, off), count++) + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Get node object with in graph from id. + * + * @param graph_id + * Graph id to get node pointer from. + * @param node_id + * Node id to get node pointer. + * + * @return + * Node pointer on success, NULL otherwise. + */ +__rte_experimental +struct rte_node *rte_graph_node_get(rte_graph_t graph_id, uint32_t node_id); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Get node pointer with in graph from name. + * + * @param graph + * Graph name to get node pointer from. + * @param name + * Node name to get the node pointer. + * + * @return + * Node pointer on success, NULL otherwise. + */ +__rte_experimental +struct rte_node *rte_graph_node_get_by_name(const char *graph, + const char *name); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Create graph stats cluster to aggregate runtime node stats. + * + * @param prm + * Parameters including file pointer to dump stats, + * Graph pattern to create cluster and callback function. + * + * @return + * Valid pointer on success, NULL otherwise. + */ +__rte_experimental +struct rte_graph_cluster_stats *rte_graph_cluster_stats_create( + const struct rte_graph_cluster_stats_param *prm); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Destroy cluster stats. + * + * @param stat + * Valid cluster pointer to destroy. + * + */ +__rte_experimental +void rte_graph_cluster_stats_destroy(struct rte_graph_cluster_stats *stat); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Get stats to application. + * + * @param[out] stat + * Cluster status. + * @param skip_cb + * true to skip callback function invocation. + */ +__rte_experimental +void rte_graph_cluster_stats_get(struct rte_graph_cluster_stats *stat, + bool skip_cb); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Reset cluster stats to zero. + * + * @param stat + * Valid cluster stats pointer. + */ +__rte_experimental +void rte_graph_cluster_stats_reset(struct rte_graph_cluster_stats *stat); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Register new packet processing node. Nodes can be registered + * dynamically via this call or statically via the RTE_NODE_REGISTER + * macro. + * + * @param node + * Valid node pointer with name, process function and next_nodes. + * + * @return + * Valid node id on success, RTE_NODE_ID_INVALID otherwise. + * + * @see RTE_NODE_REGISTER() + */ +__rte_experimental +rte_node_t __rte_node_register(const struct rte_node_register *node); + +/** + * Register a static node. + * + * The static node is registered through the constructor scheme, thereby, it can + * be used in a multi-process scenario. + * + * @param node + * Valid node pointer with name, process function, and next_nodes. + */ +#define RTE_NODE_REGISTER(node) \ + RTE_INIT(rte_node_register_##node) \ + { \ + node.parent_id = RTE_NODE_ID_INVALID; \ + node.id = __rte_node_register(&node); \ + } + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Clone a node from static node(node created from RTE_NODE_REGISTER). + * + * @param id + * Static node id to clone from. + * @param name + * Name of the new node. The library prepends the parent node name to the + * user-specified the name. The final node name will be, + * "parent node name" + "-" + name. + * + * @return + * Valid node id on success, RTE_NODE_ID_INVALID otherwise. + */ +__rte_experimental +rte_node_t rte_node_clone(rte_node_t id, const char *name); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Get node id from node name. + * + * @param name + * Valid node name. In the case of the cloned node, the name will be + * "parent node name" + "-" + name. + * + * @return + * Valid node id on success, RTE_NODE_ID_INVALID otherwise. + */ +__rte_experimental +rte_node_t rte_node_from_name(const char *name); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Get node name from node id. + * + * @param id + * Valid node id. + * + * @return + * Valid node name on success, NULL otherwise. + */ +__rte_experimental +char *rte_node_id_to_name(rte_node_t id); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Get the number of edges for a node from node id. + * + * @param id + * Valid node id. + * + * @return + * Valid edge count on success, RTE_EDGE_ID_INVALID otherwise. + */ +__rte_experimental +rte_edge_t rte_node_edge_count(rte_node_t id); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Update the edges for a node from node id. + * + * @param id + * Valid node id. + * @param from + * Index to update the edges from. RTE_EDGE_ID_INVALID is valid, + * in that case, it will be added to the end of the list. + * @param next_nodes + * Name of the edges to update. + * @param nb_edges + * Number of edges to update. + * + * @return + * Valid edge count on success, 0 otherwise. + */ +__rte_experimental +rte_edge_t rte_node_edge_update(rte_node_t id, rte_edge_t from, + const char **next_nodes, uint16_t nb_edges); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Shrink the edges to a given size. + * + * @param id + * Valid node id. + * @param size + * New size to shrink the edges. + * + * @return + * New size on success, RTE_EDGE_ID_INVALID otherwise. + */ +__rte_experimental +rte_edge_t rte_node_edge_shrink(rte_node_t id, rte_edge_t size); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Get the edge names from a given node. + * + * @param id + * Valid node id. + * @param[out] next_nodes + * Buffer to copy the edge names. The NULL value is allowed in that case, + * the function returns the size of the array that needs to be allocated. + * + * @return + * When next_nodes == NULL, it returns the size of the array else + * number of item copied. + */ +__rte_experimental +rte_node_t rte_node_edge_get(rte_node_t id, char *next_nodes[]); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Get maximum nodes created so far. + * + * @return + * Maximum nodes count on success, 0 otherwise. + */ +__rte_experimental +rte_node_t rte_node_max_count(void); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Dump node info to file. + * + * @param f + * File pointer to dump the node info. + * @param id + * Node id to get the info. + */ +__rte_experimental +void rte_node_dump(FILE *f, rte_node_t id); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Dump all node info to file. + * + * @param f + * File pointer to dump the node info. + */ +__rte_experimental +void rte_node_list_dump(FILE *f); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Test the validity of node id. + * + * @param id + * Node id to check. + * + * @return + * 1 if valid id, 0 otherwise. + */ +static __rte_always_inline int +rte_node_is_invalid(rte_node_t id) +{ + return (id == RTE_NODE_ID_INVALID); +} + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Test the validity of edge id. + * + * @param id + * Edge node id to check. + * + * @return + * 1 if valid id, 0 otherwise. + */ +static __rte_always_inline int +rte_edge_is_invalid(rte_edge_t id) +{ + return (id == RTE_EDGE_ID_INVALID); +} + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Test the validity of graph id. + * + * @param id + * Graph id to check. + * + * @return + * 1 if valid id, 0 otherwise. + */ +static __rte_always_inline int +rte_graph_is_invalid(rte_graph_t id) +{ + return (id == RTE_GRAPH_ID_INVALID); +} + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Test stats feature support. + * + * @return + * 1 if stats enabled, 0 otherwise. + */ +static __rte_always_inline int +rte_graph_has_stats_feature(void) +{ +#ifdef RTE_LIBRTE_GRAPH_STATS + return RTE_LIBRTE_GRAPH_STATS; +#else + return 0; +#endif +} + +#ifdef __cplusplus +} +#endif + +#endif /* _RTE_GRAPH_H_ */ diff --git a/lib/librte_graph/rte_graph_version.map b/lib/librte_graph/rte_graph_version.map new file mode 100644 index 000000000..55ef35df5 --- /dev/null +++ b/lib/librte_graph/rte_graph_version.map @@ -0,0 +1,3 @@ +EXPERIMENTAL { + +}; diff --git a/lib/meson.build b/lib/meson.build index 9c3cc55d5..c43d86bb9 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -30,7 +30,7 @@ libraries = [ # add pkt framework libs which use other libs from above 'port', 'table', 'pipeline', # flow_classify lib depends on pkt framework table lib - 'flow_classify', 'bpf', 'telemetry'] + 'flow_classify', 'bpf', 'graph', 'telemetry'] if is_windows libraries = ['kvargs','eal'] # only supported libraries for windows diff --git a/mk/rte.app.mk b/mk/rte.app.mk index d295ca0a5..b1195f09a 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -98,6 +98,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE) += -lrte_cmdline _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder _LDLIBS-$(CONFIG_RTE_LIBRTE_SCHED) += -lrte_sched _LDLIBS-$(CONFIG_RTE_LIBRTE_RCU) += -lrte_rcu +_LDLIBS-$(CONFIG_RTE_LIBRTE_GRAPH) += -lrte_graph ifeq ($(CONFIG_RTE_EXEC_ENV_LINUX),y) _LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni From patchwork Wed Mar 18 21:35:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66896 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 87357A057D; Wed, 18 Mar 2020 22:35:46 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id D02BE1C02A; Wed, 18 Mar 2020 22:35:31 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by dpdk.org (Postfix) with ESMTP id 2E5F81BF7E for ; Wed, 18 Mar 2020 22:35:30 +0100 (CET) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILV0Z1003373; Wed, 18 Mar 2020 14:35:28 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=TA1Hf0BjzaqVDjku7hWLCQKuhIifD06bx1D8CC77fbs=; b=OqM+7JB1omqYbNQua2PuhtfKoJOSbbQLimt/zoD/Q4B6tMz0tqB2MElOciC+dRlOtbIC xo89XVDJt9mncjiZhEl4+jGDud+9T0Xtl2WpSMwjkdFgbbeVstz2poyJ9IFtil0Un/Dy SLNLyFpFTwE5T/JiKsGVy6VXVoc5eO+9GrWLFGLMt4QoYgdjkTR7vet4mNH1kfrExNFO cKHWOeuzkkWB8dIXy9f3zUqZAUlfORluZnbqHpp9zxzRXTbOEbYev24yMSEKkb/IFtVd oQe3Dy8RFVJwrmNMCo7c/9g/Gs1e+9OwO6fc/Kmza9SdzXMsau1VGDny1QDt4NeeBUmo nw== Received: from sc-exch04.marvell.com ([199.233.58.184]) by mx0a-0016f401.pphosted.com with ESMTP id 2yu8pqmr87-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:35:28 -0700 Received: from SC-EXCH03.marvell.com (10.93.176.83) by SC-EXCH04.marvell.com (10.93.176.84) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:35:26 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:35:26 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id 1853C3F703F; Wed, 18 Mar 2020 14:35:23 -0700 (PDT) From: To: Jerin Jacob , Kiran Kumar K CC: , , , , , , Date: Thu, 19 Mar 2020 03:05:27 +0530 Message-ID: <20200318213551.3489504-3-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 02/26] graph: implement node registration X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Jerin Jacob Adding rte_node_register() API implementation includes allocating memory for node object, check for duplicate node name and add the allocated node to STAILQ node_list for future use. Signed-off-by: Jerin Jacob Signed-off-by: Kiran Kumar K Signed-off-by: Pavan Nikhilesh --- lib/librte_graph/Makefile | 1 + lib/librte_graph/graph.c | 18 +++- lib/librte_graph/graph_private.h | 74 ++++++++++++++++ lib/librte_graph/meson.build | 2 +- lib/librte_graph/node.c | 115 +++++++++++++++++++++++++ lib/librte_graph/rte_graph_version.map | 4 + 6 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 lib/librte_graph/graph_private.h create mode 100644 lib/librte_graph/node.c diff --git a/lib/librte_graph/Makefile b/lib/librte_graph/Makefile index 26fe514f3..933d0ee49 100644 --- a/lib/librte_graph/Makefile +++ b/lib/librte_graph/Makefile @@ -14,6 +14,7 @@ LDLIBS += -lrte_eal EXPORT_MAP := rte_graph_version.map # all source are stored in SRCS-y +SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += node.c SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += graph.c # install header files diff --git a/lib/librte_graph/graph.c b/lib/librte_graph/graph.c index a55bf443a..a9c124896 100644 --- a/lib/librte_graph/graph.c +++ b/lib/librte_graph/graph.c @@ -2,4 +2,20 @@ * Copyright(C) 2020 Marvell International Ltd. */ -#include "rte_graph.h" +#include + +#include "graph_private.h" + +static rte_spinlock_t graph_lock = RTE_SPINLOCK_INITIALIZER; + +void +graph_spinlock_lock(void) +{ + rte_spinlock_lock(&graph_lock); +} + +void +graph_spinlock_unlock(void) +{ + rte_spinlock_unlock(&graph_lock); +} diff --git a/lib/librte_graph/graph_private.h b/lib/librte_graph/graph_private.h new file mode 100644 index 000000000..ba56927fa --- /dev/null +++ b/lib/librte_graph/graph_private.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#ifndef _RTE_GRAPH_PRIVATE_H_ +#define _RTE_GRAPH_PRIVATE_H_ + +#include +#include + +#include +#include +#include + +/** + * @internal + * + * Structure that holds node internal data. + */ +struct node { + STAILQ_ENTRY(node) next; /**< Next node in the list. */ + char name[RTE_NODE_NAMESIZE]; /**< Name of the node. */ + uint64_t flags; /**< Node configuration flag. */ + rte_node_process_t process; /**< Node process function. */ + rte_node_init_t init; /**< Node init function. */ + rte_node_fini_t fini; /**< Node fini function. */ + rte_node_t id; /**< Allocated identifier for the node. */ + rte_node_t parent_id; /**< Parent node identifier. */ + rte_edge_t nb_edges; /**< Number of edges from this node. */ + char next_nodes[][RTE_NODE_NAMESIZE]; /**< Names of next nodes. */ +}; + +/* Node functions */ +STAILQ_HEAD(node_head, node); + +/** + * @internal + * + * Get the head of the node list. + * + * @return + * Pointer to the node head. + */ +struct node_head *node_list_head_get(void); + +/** + * @internal + * + * Get node pointer from node name. + * + * @param name + * Pointer to character string containing the node name. + * + * @return + * Pointer to the node. + */ +struct node *node_from_name(const char *name); + +/* Lock functions */ +/** + * @internal + * + * Take a lock on the graph internal spin lock. + */ +void graph_spinlock_lock(void); + +/** + * @internal + * + * Release a lock on the graph internal spin lock. + */ +void graph_spinlock_unlock(void); + +#endif /* _RTE_GRAPH_PRIVATE_H_ */ diff --git a/lib/librte_graph/meson.build b/lib/librte_graph/meson.build index 455cf2ba5..5754ac23b 100644 --- a/lib/librte_graph/meson.build +++ b/lib/librte_graph/meson.build @@ -4,7 +4,7 @@ name = 'graph' -sources = files('graph.c') +sources = files('node.c', 'graph.c') headers = files('rte_graph.h') allow_experimental_apis = true diff --git a/lib/librte_graph/node.c b/lib/librte_graph/node.c new file mode 100644 index 000000000..7999ca6ed --- /dev/null +++ b/lib/librte_graph/node.c @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "graph_private.h" + +static struct node_head node_list = STAILQ_HEAD_INITIALIZER(node_list); +static rte_node_t node_id; + +#define NODE_ID_CHECK(id) ID_CHECK(id, node_id) + +/* Private functions */ +struct node_head * +node_list_head_get(void) +{ + return &node_list; +} + +struct node * +node_from_name(const char *name) +{ + struct node *node; + + STAILQ_FOREACH(node, &node_list, next) + if (strncmp(node->name, name, RTE_NODE_NAMESIZE) == 0) + return node; + + return NULL; +} + +static bool +node_has_duplicate_entry(const char *name) +{ + struct node *node; + + /* Is duplicate name registered */ + STAILQ_FOREACH(node, &node_list, next) { + if (strncmp(node->name, name, RTE_NODE_NAMESIZE) == 0) { + rte_errno = EEXIST; + return 1; + } + } + return 0; +} + +/* Public functions */ +rte_node_t +__rte_node_register(const struct rte_node_register *reg) +{ + struct node *node; + rte_edge_t i; + size_t sz; + + graph_spinlock_lock(); + + /* Check sanity */ + if (reg == NULL || reg->process == NULL) { + rte_errno = EINVAL; + goto fail; + } + + /* Check for duplicate name */ + if (node_has_duplicate_entry(reg->name)) + goto fail; + + sz = sizeof(struct node) + (reg->nb_edges * RTE_NODE_NAMESIZE); + node = calloc(1, sz); + if (node == NULL) { + rte_errno = ENOMEM; + goto fail; + } + + /* Initialize the node */ + if (rte_strscpy(node->name, reg->name, RTE_NODE_NAMESIZE) < 0) { + rte_errno = E2BIG; + goto free; + } + node->flags = reg->flags; + node->process = reg->process; + node->init = reg->init; + node->fini = reg->fini; + node->nb_edges = reg->nb_edges; + node->parent_id = reg->parent_id; + for (i = 0; i < reg->nb_edges; i++) { + if (rte_strscpy(node->next_nodes[i], reg->next_nodes[i], + RTE_NODE_NAMESIZE) < 0) { + rte_errno = E2BIG; + goto free; + } + } + + node->id = node_id++; + + /* Add the node at tail */ + STAILQ_INSERT_TAIL(&node_list, node, next); + graph_spinlock_unlock(); + + return node->id; +free: + free(node); +fail: + graph_spinlock_unlock(); + return RTE_NODE_ID_INVALID; +} + diff --git a/lib/librte_graph/rte_graph_version.map b/lib/librte_graph/rte_graph_version.map index 55ef35df5..0884c09f1 100644 --- a/lib/librte_graph/rte_graph_version.map +++ b/lib/librte_graph/rte_graph_version.map @@ -1,3 +1,7 @@ EXPERIMENTAL { + global: + __rte_node_register; + + local: *; }; From patchwork Wed Mar 18 21:35:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66897 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 0E57BA057D; Wed, 18 Mar 2020 22:35:57 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 1BE221BF7E; Wed, 18 Mar 2020 22:35:36 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by dpdk.org (Postfix) with ESMTP id 186891BF7E for ; Wed, 18 Mar 2020 22:35:33 +0100 (CET) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILV0Z2003373; Wed, 18 Mar 2020 14:35:32 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=J9utzqq2KUlVcQ48F+PoxWm2CYbAsHtCYoq3aEt1va0=; b=pXZwrkk9Af7zSyN4on18SXl0V9vel+z7cLwT7d2Qr7bMx7fVrgZAREpK9i84mClIz4b0 AGD1hjlj1nGS/D9pZqa+Zb6Hh0eHyQD1lEAa4GMq56nb3OI7qYZATbE/M3bEmOa+QnWv cgQfzeUnlW9tAsfjUxZ35woBqDa7YJLhxS2D8D538mG1xM8e6e2m6prpNwJBx0dBgUP/ eZls/4tt8AasGEfsyGHHBF/4KyPbCQ8mg49AwTWB6G38x7pHGiuaomM4p30JirIla2c8 1gx9L+riuTGqKrjNZB0RGOe/84QEYQZR7c8SKTL0PzEhLH9GXu83DHT8f4FuyCDu250w sQ== Received: from sc-exch01.marvell.com ([199.233.58.181]) by mx0a-0016f401.pphosted.com with ESMTP id 2yu8pqmr8k-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:35:32 -0700 Received: from SC-EXCH01.marvell.com (10.93.176.81) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:35:30 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:35:30 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id 0D63E3F703F; Wed, 18 Mar 2020 14:35:27 -0700 (PDT) From: To: Jerin Jacob , Kiran Kumar K CC: , , , , , , Date: Thu, 19 Mar 2020 03:05:28 +0530 Message-ID: <20200318213551.3489504-4-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 03/26] graph: implement node operations X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Jerin Jacob Adding node-specific API implementation like cloning node, updating edges for the node, shrinking edges of a node, retrieving edges of a node. Signed-off-by: Jerin Jacob Signed-off-by: Kiran Kumar K Signed-off-by: Pavan Nikhilesh --- lib/librte_graph/graph_private.h | 10 + lib/librte_graph/node.c | 269 +++++++++++++++++++++++++ lib/librte_graph/rte_graph_version.map | 10 + 3 files changed, 289 insertions(+) diff --git a/lib/librte_graph/graph_private.h b/lib/librte_graph/graph_private.h index ba56927fa..28405ddb7 100644 --- a/lib/librte_graph/graph_private.h +++ b/lib/librte_graph/graph_private.h @@ -12,6 +12,16 @@ #include #include + +#define ID_CHECK(id, id_max) \ + do { \ + if ((id) >= (id_max)) { \ + rte_errno = EINVAL; \ + goto fail; \ + } \ + } while (0) + + /** * @internal * diff --git a/lib/librte_graph/node.c b/lib/librte_graph/node.c index 7999ca6ed..8de857889 100644 --- a/lib/librte_graph/node.c +++ b/lib/librte_graph/node.c @@ -113,3 +113,272 @@ __rte_node_register(const struct rte_node_register *reg) return RTE_NODE_ID_INVALID; } +static int +clone_name(struct rte_node_register *reg, struct node *node, const char *name) +{ + ssize_t sz, rc; + +#define SZ RTE_NODE_NAMESIZE + rc = rte_strscpy(reg->name, node->name, SZ); + if (rc < 0) + goto fail; + sz = rc; + rc = rte_strscpy(reg->name + sz, "-", RTE_MAX((int16_t)(SZ - sz), 0)); + if (rc < 0) + goto fail; + sz += rc; + sz = rte_strscpy(reg->name + sz, name, RTE_MAX((int16_t)(SZ - sz), 0)); + if (sz < 0) + goto fail; + + return 0; +fail: + rte_errno = E2BIG; + return -rte_errno; +} + +static rte_node_t +node_clone(struct node *node, const char *name) +{ + rte_node_t rc = RTE_NODE_ID_INVALID; + struct rte_node_register *reg; + rte_edge_t i; + + /* Don't allow to clone a node from a cloned node */ + if (node->parent_id != RTE_NODE_ID_INVALID) { + rte_errno = EEXIST; + goto fail; + } + + /* Check for duplicate name */ + if (node_has_duplicate_entry(name)) + goto fail; + + reg = calloc(1, sizeof(*reg) + (sizeof(char *) * node->nb_edges)); + if (reg == NULL) { + rte_errno = ENOMEM; + goto fail; + } + + /* Clone the source node */ + reg->flags = node->flags; + reg->process = node->process; + reg->init = node->init; + reg->fini = node->fini; + reg->nb_edges = node->nb_edges; + reg->parent_id = node->id; + + for (i = 0; i < node->nb_edges; i++) + reg->next_nodes[i] = node->next_nodes[i]; + + /* Naming ceremony of the new node. name is node->name + "-" + name */ + if (clone_name(reg, node, name)) + goto free; + + rc = __rte_node_register(reg); +free: + free(reg); +fail: + return rc; +} + +rte_node_t +rte_node_clone(rte_node_t id, const char *name) +{ + struct node *node; + + NODE_ID_CHECK(id); + STAILQ_FOREACH(node, &node_list, next) + if (node->id == id) + return node_clone(node, name); + +fail: + return RTE_NODE_ID_INVALID; +} + +rte_node_t +rte_node_from_name(const char *name) +{ + struct node *node; + + STAILQ_FOREACH(node, &node_list, next) + if (strncmp(node->name, name, RTE_NODE_NAMESIZE) == 0) + return node->id; + + return RTE_NODE_ID_INVALID; +} + +char * +rte_node_id_to_name(rte_node_t id) +{ + struct node *node; + + NODE_ID_CHECK(id); + STAILQ_FOREACH(node, &node_list, next) + if (node->id == id) + return node->name; + +fail: + return NULL; +} + +rte_edge_t +rte_node_edge_count(rte_node_t id) +{ + struct node *node; + + NODE_ID_CHECK(id); + STAILQ_FOREACH(node, &node_list, next) + if (node->id == id) + return node->nb_edges; +fail: + return RTE_EDGE_ID_INVALID; +} + +static rte_edge_t +edge_update(struct node *node, struct node *prev, rte_edge_t from, + const char **next_nodes, rte_edge_t nb_edges) +{ + rte_edge_t i, max_edges, count = 0; + struct node *new_node; + bool need_realloc; + size_t sz; + + if (from == RTE_EDGE_ID_INVALID) + from = node->nb_edges; + + /* Don't create hole in next_nodes[] list */ + if (from > node->nb_edges) { + rte_errno = ENOMEM; + goto fail; + } + + /* Remove me from list */ + STAILQ_REMOVE(&node_list, node, node, next); + + /* Allocate the storage space for new node if required */ + max_edges = from + nb_edges; + need_realloc = max_edges > node->nb_edges; + if (need_realloc) { + sz = sizeof(struct node) + (max_edges * RTE_NODE_NAMESIZE); + new_node = realloc(node, sz); + if (new_node == NULL) { + rte_errno = ENOMEM; + goto restore; + } else { + node = new_node; + } + } + + /* Update the new nodes name */ + for (i = from; i < max_edges; i++, count++) { + if (rte_strscpy(node->next_nodes[i], next_nodes[count], + RTE_NODE_NAMESIZE) < 0) { + rte_errno = E2BIG; + goto restore; + } + } +restore: + /* Update the linked list to point new node address in prev node */ + if (prev) + STAILQ_INSERT_AFTER(&node_list, prev, node, next); + else + STAILQ_INSERT_HEAD(&node_list, node, next); + + if (need_realloc) + node->nb_edges += count; + +fail: + return count; +} + +rte_edge_t +rte_node_edge_shrink(rte_node_t id, rte_edge_t size) +{ + rte_edge_t rc = RTE_EDGE_ID_INVALID; + struct node *node; + + NODE_ID_CHECK(id); + graph_spinlock_lock(); + + STAILQ_FOREACH(node, &node_list, next) { + if (node->id == id) { + if (node->nb_edges < size) { + rte_errno = E2BIG; + goto fail; + } + node->nb_edges = size; + rc = size; + break; + } + } + +fail: + graph_spinlock_unlock(); + return rc; +} + +rte_edge_t +rte_node_edge_update(rte_node_t id, rte_edge_t from, const char **next_nodes, + uint16_t nb_edges) +{ + rte_edge_t rc = RTE_EDGE_ID_INVALID; + struct node *n, *prev; + + NODE_ID_CHECK(id); + graph_spinlock_lock(); + + prev = NULL; + STAILQ_FOREACH(n, &node_list, next) { + if (n->id == id) { + rc = edge_update(n, prev, from, next_nodes, nb_edges); + break; + } + prev = n; + } + + graph_spinlock_unlock(); +fail: + return rc; +} + +static rte_node_t +node_copy_edges(struct node *node, char *next_nodes[]) +{ + rte_edge_t i; + + for (i = 0; i < node->nb_edges; i++) + next_nodes[i] = node->next_nodes[i]; + + return i; +} + +rte_node_t +rte_node_edge_get(rte_node_t id, char *next_nodes[]) +{ + rte_node_t rc = RTE_NODE_ID_INVALID; + struct node *node; + + NODE_ID_CHECK(id); + graph_spinlock_lock(); + + STAILQ_FOREACH(node, &node_list, next) { + if (node->id == id) { + if (next_nodes == NULL) + rc = sizeof(char *) * node->nb_edges; + else + rc = node_copy_edges(node, next_nodes); + break; + } + } + + graph_spinlock_unlock(); +fail: + return rc; +} + +rte_node_t +rte_node_max_count(void) +{ + return node_id; +} diff --git a/lib/librte_graph/rte_graph_version.map b/lib/librte_graph/rte_graph_version.map index 0884c09f1..412386356 100644 --- a/lib/librte_graph/rte_graph_version.map +++ b/lib/librte_graph/rte_graph_version.map @@ -3,5 +3,15 @@ EXPERIMENTAL { __rte_node_register; + rte_node_clone; + rte_node_edge_count; + rte_node_edge_get; + rte_node_edge_shrink; + rte_node_edge_update; + rte_node_from_name; + rte_node_id_to_name; + rte_node_list_dump; + rte_node_max_count; + local: *; }; From patchwork Wed Mar 18 21:35:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66898 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id C2E0AA057D; Wed, 18 Mar 2020 22:36:06 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 65C851C066; Wed, 18 Mar 2020 22:35:39 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) by dpdk.org (Postfix) with ESMTP id 43B4C1C045 for ; Wed, 18 Mar 2020 22:35:38 +0100 (CET) Received: from pps.filterd (m0045851.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILVpsB021913; Wed, 18 Mar 2020 14:35:36 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=ilZ2GdeF1+RhoXCKSVL2eGZEolkcW8NhXa9EpxHcfbY=; b=oSHRiOF4XlDCoyFpbNsEQgdCPI6bgrx9Xf7hTGwu/6X7fyjGN0mT8WebQaHlqBydh+xT GVV4R2eW9cBuPUkbCIBx0bn6PeUI4HmSivhiS6ZoFG9XtB/RDdQGtsFWrhT0B+y0Omjt rUY+Mviim6UQNEyYlXMeCPeEfskzOP7aNd9uBvOTrpS3uTlwB/jN/Ugco2t+yjKfvWhf Dz88suGV0XxzqAXJoAI09mqRF4h0oCqpU6smRiFHFCdUF4CU5B0AN1HoYRe3lN5Iiraw 88ElWpTZbKHwGHs4t6QUV95qFMjLPfWe1wCd/Wf9ZrfBA8mHYASFNcC52SVEIZIYAUMA iw== Received: from sc-exch02.marvell.com ([199.233.58.182]) by mx0b-0016f401.pphosted.com with ESMTP id 2yu9rpcc1v-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:35:36 -0700 Received: from SC-EXCH03.marvell.com (10.93.176.83) by SC-EXCH02.marvell.com (10.93.176.82) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:35:34 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:35:34 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id E00603F703F; Wed, 18 Mar 2020 14:35:31 -0700 (PDT) From: To: Jerin Jacob , Kiran Kumar K CC: , , , , , , Date: Thu, 19 Mar 2020 03:05:29 +0530 Message-ID: <20200318213551.3489504-5-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 04/26] graph: implement node debug routines X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Jerin Jacob Adding node debug API implementation support to dump single or all the node objects to the given file. Signed-off-by: Jerin Jacob Signed-off-by: Kiran Kumar K Signed-off-by: Pavan Nikhilesh --- lib/librte_graph/Makefile | 1 + lib/librte_graph/graph_debug.c | 25 ++++++++++++++++++++ lib/librte_graph/graph_private.h | 12 ++++++++++ lib/librte_graph/meson.build | 2 +- lib/librte_graph/node.c | 32 ++++++++++++++++++++++++++ lib/librte_graph/rte_graph_version.map | 1 + 6 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 lib/librte_graph/graph_debug.c diff --git a/lib/librte_graph/Makefile b/lib/librte_graph/Makefile index 933d0ee49..2a6d86933 100644 --- a/lib/librte_graph/Makefile +++ b/lib/librte_graph/Makefile @@ -16,6 +16,7 @@ EXPORT_MAP := rte_graph_version.map # all source are stored in SRCS-y SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += node.c SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += graph.c +SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += graph_debug.c # install header files SYMLINK-$(CONFIG_RTE_LIBRTE_GRAPH)-include += rte_graph.h diff --git a/lib/librte_graph/graph_debug.c b/lib/librte_graph/graph_debug.c new file mode 100644 index 000000000..75238e7ca --- /dev/null +++ b/lib/librte_graph/graph_debug.c @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#include +#include + +#include "graph_private.h" + +void +node_dump(FILE *f, struct node *n) +{ + rte_edge_t i; + + fprintf(f, "node <%s>\n", n->name); + fprintf(f, " id=%" PRIu32 "\n", n->id); + fprintf(f, " flags=0x%" PRIx64 "\n", n->flags); + fprintf(f, " addr=%p\n", n); + fprintf(f, " process=%p\n", n->process); + fprintf(f, " nb_edges=%d\n", n->nb_edges); + + for (i = 0; i < n->nb_edges; i++) + fprintf(f, " edge[%d] <%s>\n", i, n->next_nodes[i]); +} + diff --git a/lib/librte_graph/graph_private.h b/lib/librte_graph/graph_private.h index 28405ddb7..a8efee7c8 100644 --- a/lib/librte_graph/graph_private.h +++ b/lib/librte_graph/graph_private.h @@ -81,4 +81,16 @@ void graph_spinlock_lock(void); */ void graph_spinlock_unlock(void); +/** + * @internal + * + * Dump internal node object data. + * + * @param f + * FILE pointer to dump the info. + * @param g + * Pointer to the internal node object. + */ +void node_dump(FILE *f, struct node *n); + #endif /* _RTE_GRAPH_PRIVATE_H_ */ diff --git a/lib/librte_graph/meson.build b/lib/librte_graph/meson.build index 5754ac23b..01512182f 100644 --- a/lib/librte_graph/meson.build +++ b/lib/librte_graph/meson.build @@ -4,7 +4,7 @@ name = 'graph' -sources = files('node.c', 'graph.c') +sources = files('node.c', 'graph.c', 'graph_debug.c') headers = files('rte_graph.h') allow_experimental_apis = true diff --git a/lib/librte_graph/node.c b/lib/librte_graph/node.c index 8de857889..2f9c2ea4c 100644 --- a/lib/librte_graph/node.c +++ b/lib/librte_graph/node.c @@ -377,6 +377,38 @@ rte_node_edge_get(rte_node_t id, char *next_nodes[]) return rc; } +static void +node_scan_dump(FILE *f, rte_node_t id, bool all) +{ + struct node *node; + + RTE_ASSERT(f != NULL); + NODE_ID_CHECK(id); + + STAILQ_FOREACH(node, &node_list, next) { + if (all == true) { + node_dump(f, node); + } else if (node->id == id) { + node_dump(f, node); + return; + } + } +fail: + return; +} + +void +rte_node_dump(FILE *f, rte_node_t id) +{ + node_scan_dump(f, id, false); +} + +void +rte_node_list_dump(FILE *f) +{ + node_scan_dump(f, 0, true); +} + rte_node_t rte_node_max_count(void) { diff --git a/lib/librte_graph/rte_graph_version.map b/lib/librte_graph/rte_graph_version.map index 412386356..f2c2139c5 100644 --- a/lib/librte_graph/rte_graph_version.map +++ b/lib/librte_graph/rte_graph_version.map @@ -4,6 +4,7 @@ EXPERIMENTAL { __rte_node_register; rte_node_clone; + rte_node_dump; rte_node_edge_count; rte_node_edge_get; rte_node_edge_shrink; From patchwork Wed Mar 18 21:35:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66899 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 98CBFA057D; Wed, 18 Mar 2020 22:36:16 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id B1E951C06C; Wed, 18 Mar 2020 22:35:44 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by dpdk.org (Postfix) with ESMTP id E11401C06C for ; Wed, 18 Mar 2020 22:35:42 +0100 (CET) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILUsK3003325; Wed, 18 Mar 2020 14:35:40 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=zjaMRxZJuRTRG5V2SkqdCi3qAPaRB1NteCPrMdWa/zE=; b=eOeP7evBqL1LbXUGUw+dWrnuneUfom5qmaQSEVgqQQcLk354W1MB9nRjtRd5k7p1De0T 8OcEfsvOKdsbe+bQo+4ahGaLJBiQHZegzOL4M/tczqgZP6g1cNcuGibSaeSm0V1r5Idj imaCbaU5uSe+P+74DaZgsGmg6lwnveh2sY6gvwEFHfrBW6GGNxbUY50JlZ1kz9cIKNFZ dDh5lPWwvZB0DNF+7/ZpmQqNWbyFNQUgl5ZjzOLCkYkyNDuYdfbsqUp05CYdoNyVG8OP bmopToWIv4faqgIPKYMWJ95MBHy67f/iwPDy7LJDNIN4NHHR5+OkV/wQc8W8i+lJKNYk yg== Received: from sc-exch02.marvell.com ([199.233.58.182]) by mx0a-0016f401.pphosted.com with ESMTP id 2yu8pqmr9d-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:35:40 -0700 Received: from DC5-EXCH02.marvell.com (10.69.176.39) by SC-EXCH02.marvell.com (10.93.176.82) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:35:39 -0700 Received: from SC-EXCH03.marvell.com (10.93.176.83) by DC5-EXCH02.marvell.com (10.69.176.39) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:35:38 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:35:38 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id DB2C23F703F; Wed, 18 Mar 2020 14:35:35 -0700 (PDT) From: To: Jerin Jacob , Kiran Kumar K CC: , , , , , , Date: Thu, 19 Mar 2020 03:05:30 +0530 Message-ID: <20200318213551.3489504-6-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 05/26] graph: implement internal graph operation helpers X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Jerin Jacob Adding internal graph API helpers support to check whether a graph has isolated nodes and any node have a loop to itself and BFS algorithm implementation etc. Signed-off-by: Jerin Jacob --- lib/librte_graph/Makefile | 1 + lib/librte_graph/graph.c | 2 +- lib/librte_graph/graph_ops.c | 169 ++++++++++++++++++++++++++++++ lib/librte_graph/graph_private.h | 173 +++++++++++++++++++++++++++++++ lib/librte_graph/meson.build | 2 +- 5 files changed, 345 insertions(+), 2 deletions(-) create mode 100644 lib/librte_graph/graph_ops.c diff --git a/lib/librte_graph/Makefile b/lib/librte_graph/Makefile index 2a6d86933..39ecb2652 100644 --- a/lib/librte_graph/Makefile +++ b/lib/librte_graph/Makefile @@ -16,6 +16,7 @@ EXPORT_MAP := rte_graph_version.map # all source are stored in SRCS-y SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += node.c SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += graph.c +SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += graph_ops.c SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += graph_debug.c # install header files diff --git a/lib/librte_graph/graph.c b/lib/librte_graph/graph.c index a9c124896..4c3f2fe7b 100644 --- a/lib/librte_graph/graph.c +++ b/lib/librte_graph/graph.c @@ -7,7 +7,7 @@ #include "graph_private.h" static rte_spinlock_t graph_lock = RTE_SPINLOCK_INITIALIZER; - +int rte_graph_logtype; void graph_spinlock_lock(void) { diff --git a/lib/librte_graph/graph_ops.c b/lib/librte_graph/graph_ops.c new file mode 100644 index 000000000..335595311 --- /dev/null +++ b/lib/librte_graph/graph_ops.c @@ -0,0 +1,169 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#include +#include + +#include +#include + +#include "graph_private.h" + +/* Check whether a node has next_node to itself */ +static inline int +node_has_loop_edge(struct node *node) +{ + rte_edge_t i; + char *name; + int rc = 0; + + for (i = 0; i < node->nb_edges; i++) { + if (strncmp(node->name, node->next_nodes[i], + RTE_NODE_NAMESIZE) == 0) { + name = node->name; + rc = 1; + SET_ERR_JMP(EINVAL, fail, "Node %s has loop to self", + name); + } + } +fail: + return rc; +} + +int +graph_node_has_loop_edge(struct graph *graph) +{ + struct graph_node *graph_node; + + STAILQ_FOREACH(graph_node, &graph->node_list, next) + if (node_has_loop_edge(graph_node->node)) + return 1; + + return 0; +} + +rte_node_t +graph_src_nodes_count(struct graph *graph) +{ + struct graph_node *graph_node; + rte_node_t rc = 0; + + STAILQ_FOREACH(graph_node, &graph->node_list, next) + if (graph_node->node->flags & RTE_NODE_SOURCE_F) + rc++; + + if (rc == 0) + SET_ERR_JMP(EINVAL, fail, "Graph needs at least a source node"); +fail: + return rc; +} + +/* Check whether a node has next_node to a source node */ +int +graph_node_has_edge_to_src_node(struct graph *graph) +{ + struct graph_node *graph_node; + struct node *node; + rte_edge_t i; + + STAILQ_FOREACH(graph_node, &graph->node_list, next) { + for (i = 0; i < graph_node->node->nb_edges; i++) { + node = graph_node->adjacency_list[i]->node; + if (node->flags & RTE_NODE_SOURCE_F) + SET_ERR_JMP( + EEXIST, fail, + "Node %s points to the source node %s", + graph_node->node->name, node->name); + } + } + + return 0; +fail: + return 1; +} + +rte_node_t +graph_nodes_count(struct graph *graph) +{ + struct graph_node *graph_node; + rte_node_t count = 0; + + STAILQ_FOREACH(graph_node, &graph->node_list, next) + count++; + + return count; +} + +void +graph_mark_nodes_as_not_visited(struct graph *graph) +{ + struct graph_node *graph_node; + + STAILQ_FOREACH(graph_node, &graph->node_list, next) + graph_node->visited = false; +} + +int +graph_bfs(struct graph *graph, struct graph_node *start) +{ + struct graph_node **queue, *v, *tmp; + uint16_t head = 0, tail = 0; + rte_edge_t i; + size_t sz; + + sz = sizeof(struct graph_node *) * graph_nodes_count(graph); + queue = malloc(sz); + if (queue == NULL) + SET_ERR_JMP(ENOMEM, fail, "Failed to alloc BFS queue of %zu", + sz); + + /* BFS algorithm */ + queue[tail++] = start; + start->visited = true; + while (head != tail) { + v = queue[head++]; + for (i = 0; i < v->node->nb_edges; i++) { + tmp = v->adjacency_list[i]; + if (tmp->visited == false) { + queue[tail++] = tmp; + tmp->visited = true; + } + } + } + + free(queue); + return 0; + +fail: + return -rte_errno; +} + +/* Check whether a node has connected path or parent node */ +int +graph_has_isolated_node(struct graph *graph) +{ + struct graph_node *graph_node; + + graph_mark_nodes_as_not_visited(graph); + + STAILQ_FOREACH(graph_node, &graph->node_list, next) { + if (graph_node->node->flags & RTE_NODE_SOURCE_F) { + if (graph_node->node->nb_edges == 0) + SET_ERR_JMP(EINVAL, fail, + "%s node needs minimum one edge", + graph_node->node->name); + if (graph_bfs(graph, graph_node)) + goto fail; + } + } + + STAILQ_FOREACH(graph_node, &graph->node_list, next) + if (graph_node->visited == false) + SET_ERR_JMP(EINVAL, fail, "Found isolated node %s", + graph_node->node->name); + + return 0; +fail: + return 1; +} diff --git a/lib/librte_graph/graph_private.h b/lib/librte_graph/graph_private.h index a8efee7c8..7bf491d3d 100644 --- a/lib/librte_graph/graph_private.h +++ b/lib/librte_graph/graph_private.h @@ -12,6 +12,16 @@ #include #include +extern int rte_graph_logtype; + +#define GRAPH_LOG(level, ...) \ + rte_log(RTE_LOG_##level, rte_graph_logtype, \ + RTE_FMT("GRAPH: %s():%u " RTE_FMT_HEAD(__VA_ARGS__, ) "\n", \ + __func__, __LINE__, RTE_FMT_TAIL(__VA_ARGS__, ))) + +#define graph_err(...) GRAPH_LOG(ERR, __VA_ARGS__) +#define graph_info(...) GRAPH_LOG(INFO, __VA_ARGS__) +#define graph_dbg(...) GRAPH_LOG(DEBUG, __VA_ARGS__) #define ID_CHECK(id, id_max) \ do { \ @@ -21,6 +31,12 @@ } \ } while (0) +#define SET_ERR_JMP(err, where, fmt, ...) \ + do { \ + graph_err(fmt, ##__VA_ARGS__); \ + rte_errno = err; \ + goto where; \ + } while (0) /** * @internal @@ -40,6 +56,52 @@ struct node { char next_nodes[][RTE_NODE_NAMESIZE]; /**< Names of next nodes. */ }; +/** + * @internal + * + * Structure that holds the graph node data. + */ +struct graph_node { + STAILQ_ENTRY(graph_node) next; /**< Next graph node in the list. */ + struct node *node; /**< Pointer to internal node. */ + bool visited; /**< Flag used in BFS to mark node visited. */ + struct graph_node *adjacency_list[]; /**< Adjacency list of the node. */ +}; + +/** + * @internal + * + * Structure that holds graph internal data. + */ +struct graph { + STAILQ_ENTRY(graph) next; + /**< List of graphs. */ + char name[RTE_GRAPH_NAMESIZE]; + /**< Name of the graph. */ + const struct rte_memzone *mz; + /**< Memzone to store graph data. */ + rte_graph_off_t nodes_start; + /**< Node memory start offset in graph reel. */ + rte_node_t src_node_count; + /**< Number of source nodes in a graph. */ + struct rte_graph *graph; + /**< Pointer to graph data. */ + rte_node_t node_count; + /**< Total number of nodes. */ + uint32_t cir_start; + /**< Circular buffer start offset in graph reel. */ + uint32_t cir_mask; + /**< Circular buffer mask for wrap around. */ + rte_graph_t id; + /**< Graph identifier. */ + size_t mem_sz; + /**< Memory size of the graph. */ + int socket; + /**< Socket identifier where memory is allocated. */ + STAILQ_HEAD(gnode_list, graph_node) node_list; + /**< Nodes in a graph. */ +}; + /* Node functions */ STAILQ_HEAD(node_head, node); @@ -66,6 +128,19 @@ struct node_head *node_list_head_get(void); */ struct node *node_from_name(const char *name); +/* Graph list functions */ +STAILQ_HEAD(graph_head, graph); + +/** + * @internal + * + * Get the head of the graph list. + * + * @return + * Pointer to the graph head. + */ +struct graph_head *graph_list_head_get(void); + /* Lock functions */ /** * @internal @@ -81,6 +156,104 @@ void graph_spinlock_lock(void); */ void graph_spinlock_unlock(void); +/* Graph operations */ +/** + * @internal + * + * Run a BFS(Breadth First Search) on the graph marking all + * the graph nodes as visited. + * + * @param graph + * Pointer to the internal graph object. + * @param start + * Pointer to the starting graph node. + * + * @return + * - 0: Success. + * - -ENOMEM: Not enough memory for BFS. + */ +int graph_bfs(struct graph *graph, struct graph_node *start); + +/** + * @internal + * + * Check if there is an isolated node in the given graph. + * + * @param graph + * Pointer to the internal graph object. + * + * @return + * - 0: No isolated node found. + * - 1: Isolated node found. + */ +int graph_has_isolated_node(struct graph *graph); + +/** + * @internal + * + * Check whether a node in the graph has next_node to a source node. + * + * @param graph + * Pointer to the internal graph object. + * + * @return + * - 0: Node has an edge to source node. + * - 1: Node doesn't have an edge to source node. + */ +int graph_node_has_edge_to_src_node(struct graph *graph); + +/** + * @internal + * + * Checks whether node in the graph has a edge to itself i.e. forms a + * loop. + * + * @param graph + * Pointer to the internal graph object. + * + * @return + * - 0: Node has an edge to itself. + * - 1: Node doesn't have an edge to itself. + */ +int graph_node_has_loop_edge(struct graph *graph); + +/** + * @internal + * + * Get the count of source nodes in the graph. + * + * @param graph + * Pointer to the internal graph object. + * + * @return + * Number of source nodes. + */ +rte_node_t graph_src_nodes_count(struct graph *graph); + +/** + * @internal + * + * Get the count of total number of nodes in the graph. + * + * @param graph + * Pointer to the internal graph object. + * + * @return + * Number of nodes. + */ +rte_node_t graph_nodes_count(struct graph *graph); + +/** + * @internal + * + * Clear the visited flag of all the nodes in the graph. + * + * @param graph + * Pointer to the internal graph object. + */ +void graph_mark_nodes_as_not_visited(struct graph *graph); + + /** * @internal * diff --git a/lib/librte_graph/meson.build b/lib/librte_graph/meson.build index 01512182f..16e0625c1 100644 --- a/lib/librte_graph/meson.build +++ b/lib/librte_graph/meson.build @@ -4,7 +4,7 @@ name = 'graph' -sources = files('node.c', 'graph.c', 'graph_debug.c') +sources = files('node.c', 'graph.c', 'graph_ops.c', 'graph_debug.c') headers = files('rte_graph.h') allow_experimental_apis = true From patchwork Wed Mar 18 21:35:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66900 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id C06FDA057D; Wed, 18 Mar 2020 22:36:30 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 733FF1C0AF; Wed, 18 Mar 2020 22:35:47 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by dpdk.org (Postfix) with ESMTP id 3885B1C0AF for ; Wed, 18 Mar 2020 22:35:46 +0100 (CET) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILUs4r003328; Wed, 18 Mar 2020 14:35:44 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=ndqWDRY8pA+1FnPj+5AohlJmglnBlZzwLtohtaIYq8o=; b=RpgQ8VStg8dFWNXjBcJPOLGF82QNN0y+AAVqTrIhI4jNI0X46nxSRdDBlTAia5EXSvUY Eo0kTdqsiM9NOjFnKaCiI6u7w19PKj+mEkhboKzy+wTMRQG2njMOJBBuf+93nCzc7Y6l +tO2rd+56rd7IeAf9C4zDaUwoam/3jMH05dwaQv0jSktzwidwwGHrClEcS2JWJAupoKg yMzW2IXWSoIf/jSvYUQfr+zzt5gg1kSwvqm/P8GnHXyR6dqwSBSmJxm+dRXctCszvVss VdFZ6UI01Ad3KIa+rBljadKZeNa7vF9Yw1ak0tLaN7DpDi9hRhy8ggBQoWjRRlhsWUaT Ow== Received: from sc-exch03.marvell.com ([199.233.58.183]) by mx0a-0016f401.pphosted.com with ESMTP id 2yu8pqmr9e-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:35:43 -0700 Received: from SC-EXCH01.marvell.com (10.93.176.81) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:35:42 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:35:42 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id CAC813F703F; Wed, 18 Mar 2020 14:35:39 -0700 (PDT) From: To: Jerin Jacob , Kiran Kumar K CC: , , , , , , Date: Thu, 19 Mar 2020 03:05:31 +0530 Message-ID: <20200318213551.3489504-7-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 06/26] graph: populate fastpath memory for graph reel X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Jerin Jacob Adding support to create and populate the memory for graph reel. This includes reserving the memory in the memzone, populating the nodes, Allocating memory for node-specific streams to hold objects. Once it is populated the reel memory contains the following sections. +---------------------+ | Graph Header | +---------------------+ | Fence | +---------------------+ | Circular buffer | +---------------------+ | Fence | +---------------------+ | Node Object 0 | +------------------- -+ | Node Object 1 | +------------------- -+ | Node Object 2 | +------------------- -+ | Node Object n | +------------------- -+ Signed-off-by: Jerin Jacob Signed-off-by: Kiran Kumar K Signed-off-by: Pavan Nikhilesh --- lib/librte_graph/Makefile | 2 + lib/librte_graph/graph.c | 16 ++ lib/librte_graph/graph_populate.c | 234 +++++++++++++++++++++++++ lib/librte_graph/graph_private.h | 64 +++++++ lib/librte_graph/meson.build | 4 +- lib/librte_graph/node.c | 5 + lib/librte_graph/rte_graph_version.map | 1 + lib/librte_graph/rte_graph_worker.h | 107 +++++++++++ 8 files changed, 431 insertions(+), 2 deletions(-) create mode 100644 lib/librte_graph/graph_populate.c create mode 100644 lib/librte_graph/rte_graph_worker.h diff --git a/lib/librte_graph/Makefile b/lib/librte_graph/Makefile index 39ecb2652..7bfd7d51f 100644 --- a/lib/librte_graph/Makefile +++ b/lib/librte_graph/Makefile @@ -18,8 +18,10 @@ SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += node.c SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += graph.c SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += graph_ops.c SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += graph_debug.c +SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += graph_populate.c # install header files SYMLINK-$(CONFIG_RTE_LIBRTE_GRAPH)-include += rte_graph.h +SYMLINK-$(CONFIG_RTE_LIBRTE_GRAPH)-include += rte_graph_worker.h include $(RTE_SDK)/mk/rte.lib.mk diff --git a/lib/librte_graph/graph.c b/lib/librte_graph/graph.c index 4c3f2fe7b..e1930b7d2 100644 --- a/lib/librte_graph/graph.c +++ b/lib/librte_graph/graph.c @@ -2,6 +2,7 @@ * Copyright(C) 2020 Marvell International Ltd. */ +#include #include #include "graph_private.h" @@ -19,3 +20,18 @@ graph_spinlock_unlock(void) { rte_spinlock_unlock(&graph_lock); } + +void __rte_noinline +__rte_node_stream_alloc(struct rte_graph *graph, struct rte_node *node) +{ + uint16_t size = node->size; + + RTE_VERIFY(size != UINT16_MAX); + /* Allocate double amount of size to avoid immediate realloc */ + size = RTE_MIN(UINT16_MAX, RTE_MAX(RTE_GRAPH_BURST_SIZE, size * 2)); + node->objs = rte_realloc_socket(node->objs, size * sizeof(void *), + RTE_CACHE_LINE_SIZE, graph->socket); + RTE_VERIFY(node->objs); + node->size = size; + node->realloc_count++; +} diff --git a/lib/librte_graph/graph_populate.c b/lib/librte_graph/graph_populate.c new file mode 100644 index 000000000..093512efa --- /dev/null +++ b/lib/librte_graph/graph_populate.c @@ -0,0 +1,234 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#include +#include + +#include +#include +#include +#include + +#include "graph_private.h" + +static size_t +graph_fp_mem_calc_size(struct graph *graph) +{ + struct graph_node *graph_node; + rte_node_t val; + size_t sz; + + /* Graph header */ + sz = sizeof(struct rte_graph); + /* Source nodes list */ + sz += sizeof(rte_graph_off_t) * graph->src_node_count; + /* Circular buffer for pending streams of size number of nodes */ + val = rte_align32pow2(graph->node_count * sizeof(rte_graph_off_t)); + sz = RTE_ALIGN(sz, val); + graph->cir_start = sz; + graph->cir_mask = rte_align32pow2(graph->node_count) - 1; + sz += val; + /* Fence */ + sz += sizeof(RTE_GRAPH_FENCE); + sz = RTE_ALIGN(sz, RTE_CACHE_LINE_SIZE); + graph->nodes_start = sz; + /* For 0..N node objects with fence */ + STAILQ_FOREACH(graph_node, &graph->node_list, next) { + sz = RTE_ALIGN(sz, RTE_CACHE_LINE_SIZE); + sz += sizeof(struct rte_node); + /* Pointer to next nodes(edges) */ + sz += sizeof(struct rte_node *) * graph_node->node->nb_edges; + } + + graph->mem_sz = sz; + return sz; +} + +static void +graph_header_popluate(struct graph *_graph) +{ + struct rte_graph *graph = _graph->graph; + + graph->tail = 0; + graph->head = (int32_t)-_graph->src_node_count; + graph->cir_mask = _graph->cir_mask; + graph->nb_nodes = _graph->node_count; + graph->cir_start = RTE_PTR_ADD(graph, _graph->cir_start); + graph->nodes_start = _graph->nodes_start; + graph->socket = _graph->socket; + graph->id = _graph->id; + memcpy(graph->name, _graph->name, RTE_GRAPH_NAMESIZE); + graph->fence = RTE_GRAPH_FENCE; +} + +static void +graph_nodes_populate(struct graph *_graph) +{ + rte_graph_off_t off = _graph->nodes_start; + struct rte_graph *graph = _graph->graph; + struct graph_node *graph_node; + rte_edge_t count, nb_edges; + const char *parent; + rte_node_t pid; + + STAILQ_FOREACH(graph_node, &_graph->node_list, next) { + struct rte_node *node = RTE_PTR_ADD(graph, off); + memset(node, 0, sizeof(*node)); + node->fence = RTE_GRAPH_FENCE; + node->off = off; + node->process = graph_node->node->process; + memcpy(node->name, graph_node->node->name, RTE_GRAPH_NAMESIZE); + pid = graph_node->node->parent_id; + if (pid != RTE_NODE_ID_INVALID) { /* Cloned node */ + parent = rte_node_id_to_name(pid); + memcpy(node->parent, parent, RTE_GRAPH_NAMESIZE); + } + node->id = graph_node->node->id; + node->parent_id = pid; + nb_edges = graph_node->node->nb_edges; + node->nb_edges = nb_edges; + off += sizeof(struct rte_node); + /* Copy the name in first pass to replace with rte_node* later*/ + for (count = 0; count < nb_edges; count++) + node->nodes[count] = (struct rte_node *)&graph_node + ->adjacency_list[count] + ->node->name[0]; + + off += sizeof(struct rte_node *) * nb_edges; + off = RTE_ALIGN(off, RTE_CACHE_LINE_SIZE); + node->next = off; + __rte_node_stream_alloc(graph, node); + } +} + +struct rte_node * +graph_node_id_to_ptr(const struct rte_graph *graph, rte_node_t id) +{ + rte_node_t count; + rte_graph_off_t off; + struct rte_node *node; + + rte_graph_foreach_node(count, off, graph, node) + if (unlikely(node->id == id)) + return node; + + return NULL; +} + +struct rte_node * +graph_node_name_to_ptr(const struct rte_graph *graph, const char *name) +{ + rte_node_t count; + rte_graph_off_t off; + struct rte_node *node; + + rte_graph_foreach_node(count, off, graph, node) + if (strncmp(name, node->name, RTE_NODE_NAMESIZE) == 0) + return node; + + return NULL; +} + +static int +graph_node_nexts_populate(struct graph *_graph) +{ + rte_node_t count, val; + rte_graph_off_t off; + struct rte_node *node; + const struct rte_graph *graph = _graph->graph; + const char *name; + + rte_graph_foreach_node(count, off, graph, node) { + for (val = 0; val < node->nb_edges; val++) { + name = (const char *)node->nodes[val]; + node->nodes[val] = graph_node_name_to_ptr(graph, name); + if (node->nodes[val] == NULL) + SET_ERR_JMP(EINVAL, fail, "%s not found", name); + } + } + + return 0; +fail: + return -rte_errno; +} + +static int +graph_src_nodes_populate(struct graph *_graph) +{ + struct rte_graph *graph = _graph->graph; + struct graph_node *graph_node; + struct rte_node *node; + int32_t head = -1; + const char *name; + + STAILQ_FOREACH(graph_node, &_graph->node_list, next) { + if (graph_node->node->flags & RTE_NODE_SOURCE_F) { + name = graph_node->node->name; + node = graph_node_name_to_ptr(graph, name); + if (node == NULL) + SET_ERR_JMP(EINVAL, fail, "%s not found", name); + + __rte_node_stream_alloc(graph, node); + graph->cir_start[head--] = node->off; + } + } + + return 0; +fail: + return -rte_errno; +} + +static int +graph_fp_mem_populate(struct graph *graph) +{ + int rc; + + graph_header_popluate(graph); + graph_nodes_populate(graph); + rc = graph_node_nexts_populate(graph); + rc |= graph_src_nodes_populate(graph); + + return rc; +} + +int +graph_fp_mem_create(struct graph *graph) +{ + const struct rte_memzone *mz; + size_t sz; + + sz = graph_fp_mem_calc_size(graph); + mz = rte_memzone_reserve(graph->name, sz, graph->socket, 0); + if (mz == NULL) + SET_ERR_JMP(ENOMEM, fail, "Memzone %s reserve failed", + graph->name); + + graph->graph = mz->addr; + graph->mz = mz; + + return graph_fp_mem_populate(graph); +fail: + return -rte_errno; +} + +static void +graph_nodes_mem_destroy(struct rte_graph *graph) +{ + rte_node_t count; + rte_graph_off_t off; + struct rte_node *node; + + if (graph == NULL) + return; + + rte_graph_foreach_node(count, off, graph, node) + rte_free(node->objs); +} + +int +graph_fp_mem_destroy(struct graph *graph) +{ + graph_nodes_mem_destroy(graph->graph); + return rte_memzone_free(graph->mz); +} diff --git a/lib/librte_graph/graph_private.h b/lib/librte_graph/graph_private.h index 7bf491d3d..051fad53a 100644 --- a/lib/librte_graph/graph_private.h +++ b/lib/librte_graph/graph_private.h @@ -11,6 +11,7 @@ #include #include #include +#include extern int rte_graph_logtype; @@ -253,6 +254,69 @@ rte_node_t graph_nodes_count(struct graph *graph); */ void graph_mark_nodes_as_not_visited(struct graph *graph); +/* Fast path graph memory populate unctions */ + +/** + * @internal + * + * Create fast-path memory for the graph and nodes. + * + * @param graph + * Pointer to the internal graph object. + * + * @return + * - 0: Success. + * - -ENOMEM: Not enough for graph and nodes. + * - -EINVAL: Graph nodes not found. + */ +int graph_fp_mem_create(struct graph *graph); + +/** + * @internal + * + * Free fast-path memory used by graph and nodes. + * + * @param graph + * Pointer to the internal graph object. + * + * @return + * - 0: Success. + * - <0: Graph memzone related error. + */ +int graph_fp_mem_destroy(struct graph *graph); + +/* Lookup functions */ +/** + * @internal + * + * Get graph node object from node id. + * + * @param graph + * Pointer to rte_graph object. + * @param id + * Node Identifier. + * + * @return + * Pointer to rte_node if identifier is valid else NULL. + */ +struct rte_node *graph_node_id_to_ptr(const struct rte_graph *graph, + rte_node_t id); + +/** + * @internal + * + * Get graph node object from node name. + * + * @param graph + * Pointer to rte_graph object. + * @param node_name + * Pointer to character string holding the node name. + * + * @return + * Pointer to rte_node if identifier is valid else NULL. + */ +struct rte_node *graph_node_name_to_ptr(const struct rte_graph *graph, + const char *node_name); /** * @internal diff --git a/lib/librte_graph/meson.build b/lib/librte_graph/meson.build index 16e0625c1..fb203a5e2 100644 --- a/lib/librte_graph/meson.build +++ b/lib/librte_graph/meson.build @@ -4,8 +4,8 @@ name = 'graph' -sources = files('node.c', 'graph.c', 'graph_ops.c', 'graph_debug.c') -headers = files('rte_graph.h') +sources = files('node.c', 'graph.c', 'graph_ops.c', 'graph_debug.c', 'graph_populate.c') +headers = files('rte_graph.h', 'rte_graph_worker.h') allow_experimental_apis = true deps += ['eal'] diff --git a/lib/librte_graph/node.c b/lib/librte_graph/node.c index 2f9c2ea4c..639269870 100644 --- a/lib/librte_graph/node.c +++ b/lib/librte_graph/node.c @@ -61,6 +61,11 @@ __rte_node_register(const struct rte_node_register *reg) rte_edge_t i; size_t sz; + /* Limit Node specific metadata to one cacheline on 64B CL machine */ + RTE_BUILD_BUG_ON((offsetof(struct rte_node, nodes) - + offsetof(struct rte_node, ctx)) != + RTE_CACHE_LINE_MIN_SIZE); + graph_spinlock_lock(); /* Check sanity */ diff --git a/lib/librte_graph/rte_graph_version.map b/lib/librte_graph/rte_graph_version.map index f2c2139c5..a9fe1b610 100644 --- a/lib/librte_graph/rte_graph_version.map +++ b/lib/librte_graph/rte_graph_version.map @@ -2,6 +2,7 @@ EXPERIMENTAL { global: __rte_node_register; + __rte_node_stream_alloc; rte_node_clone; rte_node_dump; diff --git a/lib/librte_graph/rte_graph_worker.h b/lib/librte_graph/rte_graph_worker.h new file mode 100644 index 000000000..a7c780d4d --- /dev/null +++ b/lib/librte_graph/rte_graph_worker.h @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#ifndef _RTE_GRAPH_WORKER_H_ +#define _RTE_GRAPH_WORKER_H_ + +/** + * @file rte_graph_worker.h + * + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * This API allows a worker thread to walk over a graph and nodes to create, + * process, enqueue and move streams of objects to the next nodes. + */ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @internal + * + * Data structure to hold graph data. + */ +struct rte_graph { + uint32_t tail; /**< Tail of circular buffer. */ + uint32_t head; /**< Head of circular buffer. */ + uint32_t cir_mask; /**< Circular buffer wrap around mask. */ + rte_node_t nb_nodes; /**< Number of nodes in the graph. */ + rte_graph_off_t *cir_start; /**< Pointer to circular buffer. */ + rte_graph_off_t nodes_start; /**< Offset at which node memory starts. */ + rte_graph_t id; /**< Graph identifier. */ + int socket; /**< Socket ID where memory is allocated. */ + char name[RTE_GRAPH_NAMESIZE]; /**< Name of the graph. */ + uint64_t fence; /**< Fence. */ +} __rte_cache_aligned; + +/** + * @internal + * + * Data structure to hold node data. + */ +struct rte_node { + /* Slow path area */ + uint64_t fence; /**< Fence. */ + rte_graph_off_t next; /**< Index to next node. */ + rte_node_t id; /**< Node identifier. */ + rte_node_t parent_id; /**< Parent Node identifier. */ + rte_edge_t nb_edges; /**< Number of edges from this node. */ + uint32_t realloc_count; /**< Number of times realloced. */ + + char parent[RTE_NODE_NAMESIZE]; /**< Parent node name. */ + char name[RTE_NODE_NAMESIZE]; /**< Name of the node. */ + + /* Fast path area */ +#define RTE_NODE_CTX_SZ 16 + uint8_t ctx[RTE_NODE_CTX_SZ] __rte_cache_aligned; /**< Node Context. */ + uint16_t size; /**< Total number of objects available. */ + uint16_t idx; /**< Number of objects used. */ + rte_graph_off_t off; /**< Offset of node in the graph reel. */ + uint64_t total_cycles; /**< Cycles spent in this node. */ + uint64_t total_calls; /**< Calls done to this node. */ + uint64_t total_objs; /**< Objects processed by this node. */ + RTE_STD_C11 + union { + void **objs; /**< Array of object pointers. */ + uint64_t objs_u64; + }; + RTE_STD_C11 + union { + rte_node_process_t process; /**< Process function. */ + uint64_t process_u64; + }; + struct rte_node *nodes[] __rte_cache_min_aligned; /**< Next nodes. */ +} __rte_cache_aligned; + +/** + * @internal + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Allocate a stream of objects. + * + * If stream already exists then re-allocate it to a larger size. + * + * @param graph + * Pointer to the graph object. + * @param node + * Pointer to the node object. + */ +__rte_experimental +void __rte_node_stream_alloc(struct rte_graph *graph, struct rte_node *node); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTE_GRAPH_WORKER_H_ */ From patchwork Wed Mar 18 21:35:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66901 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 2EE93A057D; Wed, 18 Mar 2020 22:36:40 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 2CEC61C0AB; Wed, 18 Mar 2020 22:35:52 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) by dpdk.org (Postfix) with ESMTP id 56FA21C0B3 for ; Wed, 18 Mar 2020 22:35:50 +0100 (CET) Received: from pps.filterd (m0045851.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILVpsD021913; Wed, 18 Mar 2020 14:35:48 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=VNRruvko60xlMWEtyfH4EvHVIKnEtIZJBX8ZKUm+xRY=; b=QD3A6fP07qqHVQTGgFMSd87ZgtPBTxLO1yzCeyfRoaNkBMKF7DKVCCg5zznGdZux2o3q 8T06O8V2TVyYp/ZPj55jT3XMEV+TcLRYG8eAkeOhAYJPjwsiGjr8LIRaKEVVDE9ZFl3B 3O27LoZDwNz6GCszDwC8gPkKlOB+jEYKPDFjB6Dh6YvvbiqlrU0L4zzus8W28OEX+pTX mAHTiMO6c+LfUB0UeE7p12Uip6qVQlCC7eF5PnHZAw+sC9soAiSjqDy/3M85okdoVHaq HN3PVr3+WOfqJSYh/z7yaehw7RKsBbX1c2KwtaRGM1ScakazWaKrdAj5HjOLuwJJ2Rtv MA== Received: from sc-exch03.marvell.com ([199.233.58.183]) by mx0b-0016f401.pphosted.com with ESMTP id 2yu9rpcc2x-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:35:48 -0700 Received: from SC-EXCH01.marvell.com (10.93.176.81) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:35:46 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:35:46 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id C5EED3F703F; Wed, 18 Mar 2020 14:35:43 -0700 (PDT) From: To: Jerin Jacob , Kiran Kumar K CC: , , , , , , Date: Thu, 19 Mar 2020 03:05:32 +0530 Message-ID: <20200318213551.3489504-8-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 07/26] graph: implement create and destroy APIs X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Jerin Jacob Adding graph specific API implementations like graph create and graph destroy. This detect loops in the graph, check for isolated nodes and operation to verify the validity of graph. Signed-off-by: Jerin Jacob Signed-off-by: Kiran Kumar K Signed-off-by: Pavan Nikhilesh --- lib/librte_graph/graph.c | 321 +++++++++++++++++++++++++ lib/librte_graph/rte_graph_version.map | 2 + 2 files changed, 323 insertions(+) diff --git a/lib/librte_graph/graph.c b/lib/librte_graph/graph.c index e1930b7d2..d060ffe70 100644 --- a/lib/librte_graph/graph.c +++ b/lib/librte_graph/graph.c @@ -2,13 +2,34 @@ * Copyright(C) 2020 Marvell International Ltd. */ +#include +#include + +#include +#include +#include +#include #include +#include #include +#include #include "graph_private.h" +static struct graph_head graph_list = STAILQ_HEAD_INITIALIZER(graph_list); static rte_spinlock_t graph_lock = RTE_SPINLOCK_INITIALIZER; +static rte_graph_t graph_id; int rte_graph_logtype; + +#define GRAPH_ID_CHECK(id) ID_CHECK(id, graph_id) + +/* Private functions */ +struct graph_head * +graph_list_head_get(void) +{ + return &graph_list; +} + void graph_spinlock_lock(void) { @@ -21,6 +42,306 @@ graph_spinlock_unlock(void) rte_spinlock_unlock(&graph_lock); } +static int +graph_node_add(struct graph *graph, struct node *node) +{ + struct graph_node *graph_node; + size_t sz; + + /* Skip the duplicate nodes */ + STAILQ_FOREACH(graph_node, &graph->node_list, next) + if (strncmp(node->name, graph_node->node->name, + RTE_NODE_NAMESIZE) == 0) + return 0; + + /* Allocate new graph node object */ + sz = sizeof(*graph_node) + node->nb_edges * sizeof(struct node *); + graph_node = calloc(1, sz); + + if (graph_node == NULL) + SET_ERR_JMP(ENOMEM, free, "Failed to calloc %s object", + node->name); + + /* Initialize the graph node */ + graph_node->node = node; + + /* Add to graph node list */ + STAILQ_INSERT_TAIL(&graph->node_list, graph_node, next); + return 0; + +free: + free(graph_node); + return -rte_errno; +} + +static struct graph_node * +node_to_graph_node(struct graph *graph, struct node *node) +{ + struct graph_node *graph_node; + + STAILQ_FOREACH(graph_node, &graph->node_list, next) + if (graph_node->node == node) + return graph_node; + + SET_ERR_JMP(ENODEV, fail, "Found isolated node %s", node->name); +fail: + return NULL; +} + +static int +graph_node_edges_add(struct graph *graph) +{ + struct graph_node *graph_node; + struct node *adjacency; + const char *next; + rte_edge_t i; + + STAILQ_FOREACH(graph_node, &graph->node_list, next) { + for (i = 0; i < graph_node->node->nb_edges; i++) { + next = graph_node->node->next_nodes[i]; + adjacency = node_from_name(next); + if (adjacency == NULL) + SET_ERR_JMP(EINVAL, fail, + "Node %s not registered", next); + if (graph_node_add(graph, adjacency)) + goto fail; + } + } + return 0; +fail: + return -rte_errno; +} + +static int +graph_adjacency_list_update(struct graph *graph) +{ + struct graph_node *graph_node, *tmp; + struct node *adjacency; + const char *next; + rte_edge_t i; + + STAILQ_FOREACH(graph_node, &graph->node_list, next) { + for (i = 0; i < graph_node->node->nb_edges; i++) { + next = graph_node->node->next_nodes[i]; + adjacency = node_from_name(next); + if (adjacency == NULL) + SET_ERR_JMP(EINVAL, fail, + "Node %s not registered", next); + tmp = node_to_graph_node(graph, adjacency); + if (tmp == NULL) + goto fail; + graph_node->adjacency_list[i] = tmp; + } + } + + return 0; +fail: + return -rte_errno; +} + +static int +expand_pattern_to_node(struct graph *graph, const char *pattern) +{ + struct node_head *node_head = node_list_head_get(); + bool found = false; + struct node *node; + + /* Check for pattern match */ + STAILQ_FOREACH(node, node_head, next) { + if (fnmatch(pattern, node->name, 0) == 0) { + if (graph_node_add(graph, node)) + goto fail; + found = true; + } + } + if (found == false) + SET_ERR_JMP(EFAULT, fail, "Pattern %s node not found", pattern); + + return 0; +fail: + return -rte_errno; +} + +static void +graph_cleanup(struct graph *graph) +{ + struct graph_node *graph_node; + + while (!STAILQ_EMPTY(&graph->node_list)) { + graph_node = STAILQ_FIRST(&graph->node_list); + STAILQ_REMOVE_HEAD(&graph->node_list, next); + free(graph_node); + } +} + +static int +graph_node_init(struct graph *graph) +{ + struct graph_node *graph_node; + const char *name; + int rc; + + STAILQ_FOREACH(graph_node, &graph->node_list, next) { + if (graph_node->node->init) { + name = graph_node->node->name; + rc = graph_node->node->init( + graph->graph, + graph_node_name_to_ptr(graph->graph, name)); + if (rc) + SET_ERR_JMP(rc, err, "Node %s init() failed", + name); + } + } + + return 0; +err: + return -rte_errno; +} + +static void +graph_node_fini(struct graph *graph) +{ + struct graph_node *graph_node; + + STAILQ_FOREACH(graph_node, &graph->node_list, next) + if (graph_node->node->fini) + graph_node->node->fini( + graph->graph, + graph_node_name_to_ptr(graph->graph, + graph_node->node->name)); +} + +rte_graph_t +rte_graph_create(const char *name, struct rte_graph_param *prm) +{ + struct graph *graph; + const char *pattern; + uint16_t i; + + graph_spinlock_lock(); + + /* Check arguments sanity */ + if (prm == NULL) + SET_ERR_JMP(EINVAL, fail, "Param should not be NULL"); + + if (name == NULL) + SET_ERR_JMP(EINVAL, fail, "Graph name should not be NULL"); + + /* Check for existence of duplicate graph */ + STAILQ_FOREACH(graph, &graph_list, next) + if (strncmp(name, graph->name, RTE_GRAPH_NAMESIZE) == 0) + SET_ERR_JMP(EEXIST, fail, "Found duplicate graph %s", + name); + + /* Create graph object */ + graph = calloc(1, sizeof(*graph)); + if (graph == NULL) + SET_ERR_JMP(ENOMEM, fail, "Failed to calloc graph object"); + + /* Initialize the graph object */ + STAILQ_INIT(&graph->node_list); + if (rte_strscpy(graph->name, name, RTE_GRAPH_NAMESIZE) < 0) + SET_ERR_JMP(E2BIG, free, "Too big name=%s", name); + + /* Expand node pattern and add the nodes to the graph */ + for (i = 0; i < prm->nb_node_patterns; i++) { + pattern = prm->node_patterns[i]; + if (expand_pattern_to_node(graph, pattern)) + goto graph_cleanup; + } + + /* Go over all the nodes edges and add them to the graph */ + if (graph_node_edges_add(graph)) + goto graph_cleanup; + + /* Update adjacency list of all nodes in the graph */ + if (graph_adjacency_list_update(graph)) + goto graph_cleanup; + + /* Make sure at least a source node present in the graph */ + if (!graph_src_nodes_count(graph)) + goto graph_cleanup; + + /* Make sure no node is pointing to source node */ + if (graph_node_has_edge_to_src_node(graph)) + goto graph_cleanup; + + /* Don't allow node has loop to self */ + if (graph_node_has_loop_edge(graph)) + goto graph_cleanup; + + /* Do BFS from src nodes on the graph to find isolated nodes */ + if (graph_has_isolated_node(graph)) + goto graph_cleanup; + + /* Initialize graph object */ + graph->socket = prm->socket_id; + graph->src_node_count = graph_src_nodes_count(graph); + graph->node_count = graph_nodes_count(graph); + graph->id = graph_id; + + /* Allocate the Graph fast path memory and populate the data */ + if (graph_fp_mem_create(graph)) + goto graph_cleanup; + + /* Call init() of the all the nodes in the graph */ + if (graph_node_init(graph)) + goto graph_mem_destroy; + + /* All good, Lets add the graph to the list */ + graph_id++; + STAILQ_INSERT_TAIL(&graph_list, graph, next); + + graph_spinlock_unlock(); + return graph->id; + +graph_mem_destroy: + graph_fp_mem_destroy(graph); +graph_cleanup: + graph_cleanup(graph); +free: + free(graph); +fail: + graph_spinlock_unlock(); + return RTE_GRAPH_ID_INVALID; +} + +rte_graph_t +rte_graph_destroy(const char *graph_name) +{ + rte_graph_t rc = RTE_GRAPH_ID_INVALID; + struct graph *graph, *tmp; + const char *name; + + graph_spinlock_lock(); + + graph = STAILQ_FIRST(&graph_list); + while (graph != NULL) { + tmp = STAILQ_NEXT(graph, next); + name = graph->name; + if (strncmp(name, graph_name, RTE_GRAPH_NAMESIZE) == 0) { + /* Call fini() of the all the nodes in the graph */ + graph_node_fini(graph); + /* Destroy graph fast path memory */ + rc = graph_fp_mem_destroy(graph); + if (rc) + SET_ERR_JMP(rc, done, "MZ %s free failed", + name); + + graph_cleanup(graph); + STAILQ_REMOVE(&graph_list, graph, graph, next); + rc = graph->id; + free(graph); + graph_id--; + goto done; + } + graph = tmp; + } +done: + graph_spinlock_unlock(); + return rc; +} + void __rte_noinline __rte_node_stream_alloc(struct rte_graph *graph, struct rte_node *node) { diff --git a/lib/librte_graph/rte_graph_version.map b/lib/librte_graph/rte_graph_version.map index a9fe1b610..dcbd78c02 100644 --- a/lib/librte_graph/rte_graph_version.map +++ b/lib/librte_graph/rte_graph_version.map @@ -4,6 +4,8 @@ EXPERIMENTAL { __rte_node_register; __rte_node_stream_alloc; + rte_graph_create; + rte_graph_destroy; rte_node_clone; rte_node_dump; rte_node_edge_count; From patchwork Wed Mar 18 21:35:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66902 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 628D5A057D; Wed, 18 Mar 2020 22:36:53 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 391E01C0C5; Wed, 18 Mar 2020 22:35:56 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) by dpdk.org (Postfix) with ESMTP id 0846E1C0C5 for ; Wed, 18 Mar 2020 22:35:54 +0100 (CET) Received: from pps.filterd (m0045851.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILVRWN013835; Wed, 18 Mar 2020 14:35:53 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=OqnK1bezeluE0S/ZWiXWUPQubJuaOoOvjFD0uncyllQ=; b=Mg6g3/5k9XtbBhkEUk1hRK9GZpRNonuMN2SCR2lGAyuxbxD/xYNN7+Z/uHjBWbhu9cr/ hjcajNa/s5FDCtJHXrrFLdmG391T/ZWE29+2jTOVs1mKYMmZEiW8Ygzx5FlWsgS6ZUut dN/qc97hlxy9dcWZOnT96mbxtDzJa2lE2H2W723epcUc+OptaKTwRUQSwkIk/v1GC1XN dK9VwD5hOO11kjdiKv+i2lc4IzUwA76UUGLPQ/iwf9DJjyW/EYKGzTJmg09zpaOYOV3x 9L8DAwDqu76auc8nJiV9StA2JBw+cDRfc/TFnIoMjkR/R5z1dANAJx57bw/Wxu7RO/36 OQ== Received: from sc-exch02.marvell.com ([199.233.58.182]) by mx0b-0016f401.pphosted.com with ESMTP id 2yu9rpcc33-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:35:53 -0700 Received: from DC5-EXCH01.marvell.com (10.69.176.38) by SC-EXCH02.marvell.com (10.93.176.82) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:35:51 -0700 Received: from SC-EXCH03.marvell.com (10.93.176.83) by DC5-EXCH01.marvell.com (10.69.176.38) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:35:50 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:35:50 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id A3F7B3F703F; Wed, 18 Mar 2020 14:35:47 -0700 (PDT) From: To: Jerin Jacob , Kiran Kumar K , Anatoly Burakov CC: , , , , , , Date: Thu, 19 Mar 2020 03:05:33 +0530 Message-ID: <20200318213551.3489504-9-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 08/26] graph: implement graph operation APIs X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Jerin Jacob Adding support for graph specific API implementation like Graph lookup to get graph object, retrieving graph ID From name and graph name from ID. Signed-off-by: Jerin Jacob Signed-off-by: Kiran Kumar K Signed-off-by: Pavan Nikhilesh --- lib/librte_graph/graph.c | 131 +++++++++++++++++++++++++ lib/librte_graph/rte_graph_version.map | 8 ++ 2 files changed, 139 insertions(+) diff --git a/lib/librte_graph/graph.c b/lib/librte_graph/graph.c index d060ffe70..72a82c2a8 100644 --- a/lib/librte_graph/graph.c +++ b/lib/librte_graph/graph.c @@ -211,6 +211,54 @@ graph_node_fini(struct graph *graph) graph_node->node->name)); } +static struct rte_graph * +graph_mem_fixup_node_ctx(struct rte_graph *graph) +{ + struct rte_node *node; + struct node *node_db; + rte_graph_off_t off; + rte_node_t count; + const char *name; + + rte_graph_foreach_node(count, off, graph, node) { + if (node->parent_id == RTE_NODE_ID_INVALID) /* Static node */ + name = node->name; + else /* Cloned node */ + name = node->parent; + + node_db = node_from_name(name); + if (node_db == NULL) + SET_ERR_JMP(ENOLINK, fail, "Node %s not found", name); + node->process = node_db->process; + } + + return graph; +fail: + return NULL; +} + +static struct rte_graph * +graph_mem_fixup_secondray(struct rte_graph *graph) +{ + if (graph == NULL || rte_eal_process_type() == RTE_PROC_PRIMARY) + return graph; + + return graph_mem_fixup_node_ctx(graph); +} + +struct rte_graph * +rte_graph_lookup(const char *name) +{ + const struct rte_memzone *mz; + struct rte_graph *rc = NULL; + + mz = rte_memzone_lookup(name); + if (mz) + rc = mz->addr; + + return graph_mem_fixup_secondray(rc); +} + rte_graph_t rte_graph_create(const char *name, struct rte_graph_param *prm) { @@ -342,6 +390,76 @@ rte_graph_destroy(const char *graph_name) return rc; } +rte_graph_t +rte_graph_from_name(const char *name) +{ + struct graph *graph; + + STAILQ_FOREACH(graph, &graph_list, next) + if (strncmp(graph->name, name, RTE_GRAPH_NAMESIZE) == 0) + return graph->id; + + return RTE_GRAPH_ID_INVALID; +} + +char * +rte_graph_id_to_name(rte_graph_t id) +{ + struct graph *graph; + + GRAPH_ID_CHECK(id); + STAILQ_FOREACH(graph, &graph_list, next) + if (graph->id == id) + return graph->name; + +fail: + return NULL; +} + +struct rte_node * +rte_graph_node_get(rte_graph_t gid, uint32_t nid) +{ + struct rte_node *node; + struct graph *graph; + rte_graph_off_t off; + rte_node_t count; + + GRAPH_ID_CHECK(gid); + STAILQ_FOREACH(graph, &graph_list, next) + if (graph->id == gid) { + rte_graph_foreach_node(count, off, graph->graph, + node) { + if (node->id == nid) + return node; + } + break; + } +fail: + return NULL; +} + +struct rte_node * +rte_graph_node_get_by_name(const char *graph_name, const char *node_name) +{ + struct rte_node *node; + struct graph *graph; + rte_graph_off_t off; + rte_node_t count; + + STAILQ_FOREACH(graph, &graph_list, next) + if (!strncmp(graph->name, graph_name, RTE_GRAPH_NAMESIZE)) { + rte_graph_foreach_node(count, off, graph->graph, + node) { + if (!strncmp(node->name, node_name, + RTE_NODE_NAMESIZE)) + return node; + } + break; + } + + return NULL; +} + void __rte_noinline __rte_node_stream_alloc(struct rte_graph *graph, struct rte_node *node) { @@ -356,3 +474,16 @@ __rte_node_stream_alloc(struct rte_graph *graph, struct rte_node *node) node->size = size; node->realloc_count++; } + +rte_graph_t +rte_graph_max_count(void) +{ + return graph_id; +} + +RTE_INIT(rte_graph_init_log) +{ + rte_graph_logtype = rte_log_register("lib.graph"); + if (rte_graph_logtype >= 0) + rte_log_set_level(rte_graph_logtype, RTE_LOG_INFO); +} diff --git a/lib/librte_graph/rte_graph_version.map b/lib/librte_graph/rte_graph_version.map index dcbd78c02..5a2b13293 100644 --- a/lib/librte_graph/rte_graph_version.map +++ b/lib/librte_graph/rte_graph_version.map @@ -6,6 +6,14 @@ EXPERIMENTAL { rte_graph_create; rte_graph_destroy; + rte_graph_from_name; + rte_graph_id_to_name; + rte_graph_lookup; + rte_graph_list_dump; + rte_graph_max_count; + rte_graph_node_get; + rte_graph_node_get_by_name; + rte_node_clone; rte_node_dump; rte_node_edge_count; From patchwork Wed Mar 18 21:35:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66903 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 1CAE2A057D; Wed, 18 Mar 2020 22:37:03 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 5834A1C0CB; Wed, 18 Mar 2020 22:35:59 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by dpdk.org (Postfix) with ESMTP id A10551C0C7 for ; Wed, 18 Mar 2020 22:35:57 +0100 (CET) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILVs83013171; Wed, 18 Mar 2020 14:35:55 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=VTldYI70K68WOD7kDgbgrDdhtJgW+zvPEQV40VX20eg=; b=y20hbkuDFLdrQWimMidHoJ1BMOdm8HjXcRNscy8UISLbiZ1wpFuG6ez3NEGrJ7hRTQ9R H/BBQekxOrejWfIUjunTm06plALccPsRXB3IP7NJYa13bW+95FO3CsLxozt3BBgXNSTn 7mQ1KpilniwAREijBqS9c0/+mF+Jib4bFExmBWAted8v/lTw2gNpP9QU5bbVfEsTAtn9 jJFuDYrw6525F5pssHgAp/Fwk78JBdEk8FnunMooAGPDEbg987WKc6ykfNuv6cit8GaD wV3Zs0iQ9JXHkkHVyr9mmmG0ItbmzqTjSe1bPapUZpqK8FFyBjll6sypfv87SQ5Fv7nR MA== Received: from sc-exch03.marvell.com ([199.233.58.183]) by mx0a-0016f401.pphosted.com with ESMTP id 2yu8pqmrad-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:35:55 -0700 Received: from SC-EXCH01.marvell.com (10.93.176.81) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:35:54 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:35:54 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id B357A3F703F; Wed, 18 Mar 2020 14:35:51 -0700 (PDT) From: To: Jerin Jacob , Kiran Kumar K CC: , , , , , , Date: Thu, 19 Mar 2020 03:05:34 +0530 Message-ID: <20200318213551.3489504-10-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 09/26] graph: implement Graphviz export X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Jerin Jacob Adding API implementation support exporting the graph object to file. This will export the graph to a file in Graphviz format. It can be viewed in many viewers such as https://dreampuf.github.io/GraphvizOnline/ Signed-off-by: Jerin Jacob Signed-off-by: Kiran Kumar K Signed-off-by: Pavan Nikhilesh --- lib/librte_graph/graph.c | 54 ++++++++++++++++++++++++++ lib/librte_graph/rte_graph_version.map | 1 + 2 files changed, 55 insertions(+) diff --git a/lib/librte_graph/graph.c b/lib/librte_graph/graph.c index 72a82c2a8..ad58673be 100644 --- a/lib/librte_graph/graph.c +++ b/lib/librte_graph/graph.c @@ -475,6 +475,60 @@ __rte_node_stream_alloc(struct rte_graph *graph, struct rte_node *node) node->realloc_count++; } +static int +graph_to_dot(FILE *f, struct graph *graph) +{ + const char *src_edge_color = " [color=blue]\n"; + const char *edge_color = "\n"; + struct graph_node *graph_node; + char *node_name; + rte_edge_t i; + int rc; + + rc = fprintf(f, "Digraph %s {\n\trankdir=LR;\n", graph->name); + if (rc < 0) + goto end; + + STAILQ_FOREACH(graph_node, &graph->node_list, next) { + node_name = graph_node->node->name; + for (i = 0; i < graph_node->node->nb_edges; i++) { + rc = fprintf(f, "\t\"%s\"->\"%s\"%s", node_name, + graph_node->adjacency_list[i]->node->name, + graph_node->node->flags & RTE_NODE_SOURCE_F + ? src_edge_color + : edge_color); + if (rc < 0) + goto end; + } + } + rc = fprintf(f, "}\n"); + if (rc < 0) + goto end; + + return 0; +end: + rte_errno = EBADF; + return -rte_errno; +} + +rte_graph_t +rte_graph_export(const char *name, FILE *f) +{ + rte_graph_t rc = RTE_GRAPH_ID_INVALID; + struct graph *graph; + + STAILQ_FOREACH(graph, &graph_list, next) { + if (strncmp(graph->name, name, RTE_GRAPH_NAMESIZE) == 0) { + rc = graph_to_dot(f, graph); + goto end; + } + } + rte_errno = ENOENT; +end: + return rc; +} + + rte_graph_t rte_graph_max_count(void) { diff --git a/lib/librte_graph/rte_graph_version.map b/lib/librte_graph/rte_graph_version.map index 5a2b13293..2797be044 100644 --- a/lib/librte_graph/rte_graph_version.map +++ b/lib/librte_graph/rte_graph_version.map @@ -6,6 +6,7 @@ EXPERIMENTAL { rte_graph_create; rte_graph_destroy; + rte_graph_export; rte_graph_from_name; rte_graph_id_to_name; rte_graph_lookup; From patchwork Wed Mar 18 21:35:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66904 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id E5919A057D; Wed, 18 Mar 2020 22:37:12 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 8B4451C0BC; Wed, 18 Mar 2020 22:36:02 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by dpdk.org (Postfix) with ESMTP id 6B13C1BF82 for ; Wed, 18 Mar 2020 22:36:01 +0100 (CET) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILV0Z6003373; Wed, 18 Mar 2020 14:35:59 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=65DBIT1s1fgfNLXPCW8K6SsQf9AOyhoAlW8Q3f8U+LA=; b=xraHDoVeoPVZfFZudppr2bkW37JKJ4OK+EL3USSQqsivuSvQmOA+J3pX7iAYuDAg66IO 172J4cGT6y3Egw7FkG7qpwgrtvbFqzVoXX0+8+6sciJJM+0Sivwn2PcVYBHD3R4FeYnf QXnMm78a3HVaaATKl7X4p3PQIlNmWcA/D/ymSx0ZTpu/yeNd2TL8PWmqxQzni9w7TW1G Jd69dkwPEGN2CWBxiEgqz2mXR9Nw2HFLeGqOHxO6brKJXKfjBKHe6+56lVSXFTgYR8ad ty8677qQGuCyfdBrmAB9ND0cfy7LDX5w5reZ6I6JbZnivvnfVkGRFWx/TtRfHYbVyiXh lw== Received: from sc-exch01.marvell.com ([199.233.58.181]) by mx0a-0016f401.pphosted.com with ESMTP id 2yu8pqmrat-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:35:59 -0700 Received: from SC-EXCH03.marvell.com (10.93.176.83) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:35:58 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:35:58 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id 8474B3F7040; Wed, 18 Mar 2020 14:35:55 -0700 (PDT) From: To: Jerin Jacob , Kiran Kumar K CC: , , , , , , Date: Thu, 19 Mar 2020 03:05:35 +0530 Message-ID: <20200318213551.3489504-11-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 10/26] graph: implement debug routines X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Jerin Jacob Adding implementation for graph specific API to dump the Graph information to a file. This API will dump detailed internal info about node objects and graph objects. Signed-off-by: Jerin Jacob Signed-off-by: Kiran Kumar K Signed-off-by: Pavan Nikhilesh --- lib/librte_graph/graph.c | 31 ++++++++++++++ lib/librte_graph/graph_debug.c | 59 ++++++++++++++++++++++++++ lib/librte_graph/graph_private.h | 13 ++++++ lib/librte_graph/rte_graph_version.map | 2 + 4 files changed, 105 insertions(+) diff --git a/lib/librte_graph/graph.c b/lib/librte_graph/graph.c index ad58673be..cc1e523d9 100644 --- a/lib/librte_graph/graph.c +++ b/lib/librte_graph/graph.c @@ -528,6 +528,37 @@ rte_graph_export(const char *name, FILE *f) return rc; } +static void +graph_scan_dump(FILE *f, rte_graph_t id, bool all) +{ + struct graph *graph; + + RTE_VERIFY(f); + GRAPH_ID_CHECK(id); + + STAILQ_FOREACH(graph, &graph_list, next) { + if (all == true) { + graph_dump(f, graph); + } else if (graph->id == id) { + graph_dump(f, graph); + return; + } + } +fail: + return; +} + +void +rte_graph_dump(FILE *f, rte_graph_t id) +{ + graph_scan_dump(f, id, false); +} + +void +rte_graph_list_dump(FILE *f) +{ + graph_scan_dump(f, 0, true); +} rte_graph_t rte_graph_max_count(void) diff --git a/lib/librte_graph/graph_debug.c b/lib/librte_graph/graph_debug.c index 75238e7ca..f8aea16ac 100644 --- a/lib/librte_graph/graph_debug.c +++ b/lib/librte_graph/graph_debug.c @@ -7,6 +7,26 @@ #include "graph_private.h" +void +graph_dump(FILE *f, struct graph *g) +{ + struct graph_node *graph_node; + rte_edge_t i = 0; + + fprintf(f, "graph <%s>\n", g->name); + fprintf(f, " id=%" PRIu32 "\n", g->id); + fprintf(f, " cir_start=%" PRIu32 "\n", g->cir_start); + fprintf(f, " cir_mask=%" PRIu32 "\n", g->cir_mask); + fprintf(f, " addr=%p\n", g); + fprintf(f, " graph=%p\n", g->graph); + fprintf(f, " mem_sz=%zu\n", g->mem_sz); + fprintf(f, " node_count=%" PRIu32 "\n", g->node_count); + fprintf(f, " src_node_count=%" PRIu32 "\n", g->src_node_count); + + STAILQ_FOREACH(graph_node, &g->node_list, next) + fprintf(f, " node[%d] <%s>\n", i++, graph_node->node->name); +} + void node_dump(FILE *f, struct node *n) { @@ -23,3 +43,42 @@ node_dump(FILE *f, struct node *n) fprintf(f, " edge[%d] <%s>\n", i, n->next_nodes[i]); } +void +rte_graph_obj_dump(FILE *f, struct rte_graph *g, bool all) +{ + rte_node_t count; + rte_graph_off_t off; + struct rte_node *n; + rte_edge_t i; + + fprintf(f, "graph <%s> @ %p\n", g->name, g); + fprintf(f, " id=%" PRIu32 "\n", g->id); + fprintf(f, " head=%" PRId32 "\n", (int32_t)g->head); + fprintf(f, " tail=%" PRId32 "\n", (int32_t)g->tail); + fprintf(f, " cir_mask=0x%" PRIx32 "\n", g->cir_mask); + fprintf(f, " nb_nodes=%" PRId32 "\n", g->nb_nodes); + fprintf(f, " socket=%d\n", g->socket); + fprintf(f, " fence=0x%" PRIx64 "\n", g->fence); + fprintf(f, " nodes_start=0x%" PRIx32 "\n", g->nodes_start); + fprintf(f, " cir_start=%p\n", g->cir_start); + + rte_graph_foreach_node(count, off, g, n) { + if (!all && n->idx == 0) + continue; + fprintf(f, " node[%d] <%s>\n", count, n->name); + fprintf(f, " fence=0x%" PRIx64 "\n", n->fence); + fprintf(f, " objs=%p\n", n->objs); + fprintf(f, " process=%p\n", n->process); + fprintf(f, " id=0x%" PRIx32 "\n", n->id); + fprintf(f, " offset=0x%" PRIx32 "\n", n->off); + fprintf(f, " nb_edges=%" PRId32 "\n", n->nb_edges); + fprintf(f, " realloc_count=%d\n", n->realloc_count); + fprintf(f, " size=%d\n", n->size); + fprintf(f, " idx=%d\n", n->idx); + fprintf(f, " total_objs=%" PRId64 "\n", n->total_objs); + fprintf(f, " total_calls=%" PRId64 "\n", n->total_calls); + for (i = 0; i < n->nb_edges; i++) + fprintf(f, " edge[%d] <%s>\n", i, + n->nodes[i]->name); + } +} diff --git a/lib/librte_graph/graph_private.h b/lib/librte_graph/graph_private.h index 051fad53a..397247797 100644 --- a/lib/librte_graph/graph_private.h +++ b/lib/librte_graph/graph_private.h @@ -318,6 +318,19 @@ struct rte_node *graph_node_id_to_ptr(const struct rte_graph *graph, struct rte_node *graph_node_name_to_ptr(const struct rte_graph *graph, const char *node_name); +/* Debug functions */ +/** + * @internal + * + * Dump internal graph object data. + * + * @param f + * FILE pointer to dump the data. + * @param g + * Pointer to the internal graph object. + */ +void graph_dump(FILE *f, struct graph *g); + /** * @internal * diff --git a/lib/librte_graph/rte_graph_version.map b/lib/librte_graph/rte_graph_version.map index 2797be044..851f4772e 100644 --- a/lib/librte_graph/rte_graph_version.map +++ b/lib/librte_graph/rte_graph_version.map @@ -6,6 +6,7 @@ EXPERIMENTAL { rte_graph_create; rte_graph_destroy; + rte_graph_dump; rte_graph_export; rte_graph_from_name; rte_graph_id_to_name; @@ -14,6 +15,7 @@ EXPERIMENTAL { rte_graph_max_count; rte_graph_node_get; rte_graph_node_get_by_name; + rte_graph_obj_dump; rte_node_clone; rte_node_dump; From patchwork Wed Mar 18 21:35:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66905 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 8720BA057D; Wed, 18 Mar 2020 22:37:23 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 1CB121C0D6; Wed, 18 Mar 2020 22:36:09 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by dpdk.org (Postfix) with ESMTP id EA7481AFF for ; Wed, 18 Mar 2020 22:36:06 +0100 (CET) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILUsC4003334; Wed, 18 Mar 2020 14:36:04 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=39sxVdZosq2OvgvEwM6ImbTsvFFhKrSY92dbRNcmhTA=; b=I2NHdVaOfP10NoPqiuwud3qmowb3AiBmxwI2aiDT6Rwb8e/ckh+b8Hk8k3YpD1YCpNix 4l+0J1Uyeo/1T03Z2qadBUB+J71UgXxsNvfCE2p0HetJVrLMivTXkcWUGUsearc2HuDU F4NelzVzPSzjzeDYckFK1Ba2v00S/W6j7fdIiYxoRmM3vvVsbHCDtl+35OsCKuFzyQqI DCxEMmvBYuB4vwrbI1qcEF5q+nFTu1YpByB+yEgxPrVkDl8BHsQWyQ5zgeXTXJL01vba vySHtDo4wAtZ8t6wnXXAGHw11CCl2rJnt+t8I+z8+ZoCaaGnGMUOLBaYI9ov6Z8/X8nt qw== Received: from sc-exch01.marvell.com ([199.233.58.181]) by mx0a-0016f401.pphosted.com with ESMTP id 2yu8pqmrbf-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:36:04 -0700 Received: from DC5-EXCH01.marvell.com (10.69.176.38) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:03 -0700 Received: from SC-EXCH01.marvell.com (10.93.176.81) by DC5-EXCH01.marvell.com (10.69.176.38) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:02 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:36:02 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id 895CE3F703F; Wed, 18 Mar 2020 14:35:59 -0700 (PDT) From: To: Jerin Jacob , Kiran Kumar K CC: , , , , , , Date: Thu, 19 Mar 2020 03:05:36 +0530 Message-ID: <20200318213551.3489504-12-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 11/26] graph: implement stats support X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Jerin Jacob Adding implementation for graph stats collection API. This API will create a cluster for a specified node pattern and aggregate the node runtime stats. Signed-off-by: Jerin Jacob Signed-off-by: Kiran Kumar K Signed-off-by: Pavan Nikhilesh Signed-off-by: Nithin Dabilpuram --- lib/librte_graph/Makefile | 1 + lib/librte_graph/graph_stats.c | 406 +++++++++++++++++++++++++ lib/librte_graph/meson.build | 2 +- lib/librte_graph/rte_graph_version.map | 5 + 4 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 lib/librte_graph/graph_stats.c diff --git a/lib/librte_graph/Makefile b/lib/librte_graph/Makefile index 7bfd7d51f..967c8d9bc 100644 --- a/lib/librte_graph/Makefile +++ b/lib/librte_graph/Makefile @@ -18,6 +18,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += node.c SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += graph.c SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += graph_ops.c SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += graph_debug.c +SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += graph_stats.c SRCS-$(CONFIG_RTE_LIBRTE_GRAPH) += graph_populate.c # install header files diff --git a/lib/librte_graph/graph_stats.c b/lib/librte_graph/graph_stats.c new file mode 100644 index 000000000..125e08d73 --- /dev/null +++ b/lib/librte_graph/graph_stats.c @@ -0,0 +1,406 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#include +#include + +#include +#include +#include + +#include "graph_private.h" + +/* Capture all graphs of cluster */ +struct cluster { + rte_graph_t nb_graphs; + rte_graph_t size; + + struct graph **graphs; +}; + +/* Capture same node ID across cluster */ +struct cluster_node { + struct rte_graph_cluster_node_stats stat; + rte_node_t nb_nodes; + + struct rte_node *nodes[]; +}; + +struct rte_graph_cluster_stats { + /* Header */ + rte_graph_cluster_stats_cb_t fn; + uint32_t cluster_node_size; /* Size of struct cluster_node */ + rte_node_t max_nodes; + int socket_id; + void *cookie; + size_t sz; + + struct cluster_node clusters[]; +} __rte_cache_aligned; + +#define boarder() \ + fprintf(f, "+-------------------------------+---------------+--------" \ + "-------+---------------+---------------+---------------+-" \ + "----------+\n") + +static inline void +print_banner(FILE *f) +{ + boarder(); + fprintf(f, "%-32s%-16s%-16s%-16s%-16s%-16s%-16s\n", "|Node", "|calls", + "|objs", "|realloc_count", "|objs/call", "|objs/sec(10E6)", + "|cycles/call|"); + boarder(); +} + +static inline void +print_node(FILE *f, const struct rte_graph_cluster_node_stats *stat) +{ + double objs_per_call, objs_per_sec, cycles_per_call, ts_per_hz; + const uint64_t prev_calls = stat->prev_calls; + const uint64_t prev_objs = stat->prev_objs; + const uint64_t cycles = stat->cycles; + const uint64_t calls = stat->calls; + const uint64_t objs = stat->objs; + uint64_t call_delta; + + call_delta = calls - prev_calls; + objs_per_call = + call_delta ? (double)((objs - prev_objs) / call_delta) : 0; + cycles_per_call = + call_delta ? (double)((cycles - stat->prev_cycles) / call_delta) + : 0; + ts_per_hz = (double)((stat->ts - stat->prev_ts) / stat->hz); + objs_per_sec = ts_per_hz ? (objs - prev_objs) / ts_per_hz : 0; + objs_per_sec /= 1000000; + + fprintf(f, + "|%-31s|%-15" PRIu64 "|%-15" PRIu64 "|%-15" PRIu64 + "|%-15.3f|%-15.6f|%-11.4f|\n", + stat->name, calls, objs, stat->realloc_count, objs_per_call, + objs_per_sec, cycles_per_call); +} + +static int +graph_cluster_stats_cb(bool is_first, bool is_last, void *cookie, + const struct rte_graph_cluster_node_stats *stat) +{ + FILE *f = cookie; + + if (unlikely(is_first)) + print_banner(f); + if (stat->objs) + print_node(f, stat); + if (unlikely(is_last)) + boarder(); + + return 0; +}; + +static struct rte_graph_cluster_stats * +stats_mem_init(struct cluster *cluster, + const struct rte_graph_cluster_stats_param *prm) +{ + size_t sz = sizeof(struct rte_graph_cluster_stats); + struct rte_graph_cluster_stats *stats; + rte_graph_cluster_stats_cb_t fn; + int socket_id = prm->socket_id; + uint32_t cluster_node_size; + + /* Fix up callback */ + fn = prm->fn; + if (fn == NULL) + fn = graph_cluster_stats_cb; + + cluster_node_size = sizeof(struct cluster_node); + /* For a given cluster, max nodes will be the max number of graphs */ + cluster_node_size += cluster->nb_graphs * sizeof(struct rte_node *); + cluster_node_size = RTE_ALIGN(cluster_node_size, RTE_CACHE_LINE_SIZE); + + stats = realloc(NULL, sz); + memset(stats, 0, sz); + if (stats) { + stats->fn = fn; + stats->cluster_node_size = cluster_node_size; + stats->max_nodes = 0; + stats->socket_id = socket_id; + stats->cookie = prm->cookie; + stats->sz = sz; + } + + return stats; +} + +static int +stats_mem_populate(struct rte_graph_cluster_stats **stats_in, + struct rte_graph *graph, struct graph_node *graph_node) +{ + struct rte_graph_cluster_stats *stats = *stats_in; + rte_node_t id = graph_node->node->id; + struct cluster_node *cluster; + struct rte_node *node; + rte_node_t count; + + cluster = stats->clusters; + + /* Iterate over cluster node array to find node ID match */ + for (count = 0; count < stats->max_nodes; count++) { + /* Found an existing node in the reel */ + if (cluster->stat.id == id) { + node = graph_node_id_to_ptr(graph, id); + if (node == NULL) + SET_ERR_JMP( + ENOENT, err, + "Failed to find node %s in graph %s", + graph_node->node->name, graph->name); + + cluster->nodes[cluster->nb_nodes++] = node; + return 0; + } + cluster = RTE_PTR_ADD(cluster, stats->cluster_node_size); + } + + /* Hey, it is a new node, allocate space for it in the reel */ + stats = realloc(stats, stats->sz + stats->cluster_node_size); + if (stats == NULL) + SET_ERR_JMP(ENOMEM, err, "Realloc failed"); + + /* Clear the new struct cluster_node area */ + cluster = RTE_PTR_ADD(stats, stats->sz), + memset(cluster, 0, stats->cluster_node_size); + memcpy(cluster->stat.name, graph_node->node->name, RTE_NODE_NAMESIZE); + cluster->stat.id = graph_node->node->id; + cluster->stat.hz = rte_get_timer_hz(); + node = graph_node_id_to_ptr(graph, id); + if (node == NULL) + SET_ERR_JMP(ENOENT, err, "Failed to find node %s in graph %s", + graph_node->node->name, graph->name); + cluster->nodes[cluster->nb_nodes++] = node; + + stats->sz += stats->cluster_node_size; + stats->max_nodes++; + *stats_in = stats; + + return 0; +err: + return -rte_errno; +} + +static void +stats_mem_fini(struct rte_graph_cluster_stats *stats) +{ + free(stats); +} + +static void +cluster_init(struct cluster *cluster) +{ + memset(cluster, 0, sizeof(*cluster)); +} + +static int +cluster_add(struct cluster *cluster, struct graph *graph) +{ + rte_graph_t count; + size_t sz; + + /* Skip the if graph is already added to cluster */ + for (count = 0; count < cluster->nb_graphs; count++) + if (cluster->graphs[count] == graph) + return 0; + + /* Expand the cluster if required to store graph objects */ + if (cluster->nb_graphs + 1 > cluster->size) { + cluster->size = RTE_MAX(1, cluster->size * 2); + sz = sizeof(struct graph *) * cluster->size; + cluster->graphs = realloc(cluster->graphs, sz); + if (cluster->graphs == NULL) + SET_ERR_JMP(ENOMEM, free, "Failed to realloc"); + } + + /* Add graph to cluster */ + cluster->graphs[cluster->nb_graphs++] = graph; + return 0; + +free: + return -rte_errno; +} + +static void +cluster_fini(struct cluster *cluster) +{ + if (cluster->graphs) + free(cluster->graphs); +} + +static int +expand_pattern_to_cluster(struct cluster *cluster, const char *pattern) +{ + struct graph_head *graph_head = graph_list_head_get(); + struct graph *graph; + bool found = false; + + /* Check for pattern match */ + STAILQ_FOREACH(graph, graph_head, next) { + if (fnmatch(pattern, graph->name, 0) == 0) { + if (cluster_add(cluster, graph)) + goto fail; + found = true; + } + } + if (found == false) + SET_ERR_JMP(EFAULT, fail, "Pattern %s graph not found", + pattern); + + return 0; +fail: + return -rte_errno; +} + +struct rte_graph_cluster_stats * +rte_graph_cluster_stats_create(const struct rte_graph_cluster_stats_param *prm) +{ + struct rte_graph_cluster_stats *stats, *rc = NULL; + struct graph_node *graph_node; + struct cluster cluster; + struct graph *graph; + const char *pattern; + rte_graph_t i; + + /* Sanity checks */ + if (!rte_graph_has_stats_feature()) + SET_ERR_JMP(EINVAL, fail, "Stats feature is not enabled"); + + if (prm == NULL) + SET_ERR_JMP(EINVAL, fail, "Invalid param"); + + if (prm->graph_patterns == NULL || prm->nb_graph_patterns == 0) + SET_ERR_JMP(EINVAL, fail, "Invalid graph param"); + + cluster_init(&cluster); + + graph_spinlock_lock(); + /* Expand graph pattern and add the graph to the cluster */ + for (i = 0; i < prm->nb_graph_patterns; i++) { + pattern = prm->graph_patterns[i]; + if (expand_pattern_to_cluster(&cluster, pattern)) + goto bad_pattern; + } + + /* Alloc the stats memory */ + stats = stats_mem_init(&cluster, prm); + if (stats == NULL) + SET_ERR_JMP(ENOMEM, bad_pattern, "Failed alloc stats memory"); + + /* Iterate over M(Graph) x N (Nodes in graph) */ + for (i = 0; i < cluster.nb_graphs; i++) { + graph = cluster.graphs[i]; + STAILQ_FOREACH(graph_node, &graph->node_list, next) { + struct rte_graph *graph_fp = graph->graph; + if (stats_mem_populate(&stats, graph_fp, graph_node)) + goto realloc_fail; + } + } + + /* Finally copy to hugepage memory to avoid pressure on rte_realloc */ + rc = rte_malloc_socket(NULL, stats->sz, 0, stats->socket_id); + if (rc) + rte_memcpy(rc, stats, stats->sz); + else + SET_ERR_JMP(ENOMEM, realloc_fail, "rte_malloc failed"); + +realloc_fail: + stats_mem_fini(stats); +bad_pattern: + graph_spinlock_unlock(); + cluster_fini(&cluster); +fail: + return rc; +} + +void +rte_graph_cluster_stats_destroy(struct rte_graph_cluster_stats *stat) +{ + return rte_free(stat); +} + +static inline void +cluster_node_arregate_stats(struct cluster_node *cluster) +{ + uint64_t calls = 0, cycles = 0, objs = 0, realloc_count = 0; + struct rte_graph_cluster_node_stats *stat = &cluster->stat; + struct rte_node *node; + rte_node_t count; + + for (count = 0; count < cluster->nb_nodes; count++) { + node = cluster->nodes[count]; + + calls += node->total_calls; + objs += node->total_objs; + cycles += node->total_cycles; + realloc_count += node->realloc_count; + } + + stat->calls = calls; + stat->objs = objs; + stat->cycles = cycles; + stat->ts = rte_get_timer_cycles(); + stat->realloc_count = realloc_count; +} + +static inline void +cluster_node_store_prev_stats(struct cluster_node *cluster) +{ + struct rte_graph_cluster_node_stats *stat = &cluster->stat; + + stat->prev_ts = stat->ts; + stat->prev_calls = stat->calls; + stat->prev_objs = stat->objs; + stat->prev_cycles = stat->cycles; +} + +void +rte_graph_cluster_stats_get(struct rte_graph_cluster_stats *stat, bool skip_cb) +{ + struct cluster_node *cluster; + rte_node_t count; + int rc = 0; + + cluster = stat->clusters; + + for (count = 0; count < stat->max_nodes; count++) { + cluster_node_arregate_stats(cluster); + if (!skip_cb) + rc = stat->fn(!count, (count == stat->max_nodes - 1), + stat->cookie, &cluster->stat); + cluster_node_store_prev_stats(cluster); + if (rc) + break; + cluster = RTE_PTR_ADD(cluster, stat->cluster_node_size); + } +} + +void +rte_graph_cluster_stats_reset(struct rte_graph_cluster_stats *stat) +{ + struct cluster_node *cluster; + rte_node_t count; + + cluster = stat->clusters; + + for (count = 0; count < stat->max_nodes; count++) { + struct rte_graph_cluster_node_stats *node = &cluster->stat; + + node->ts = 0; + node->calls = 0; + node->objs = 0; + node->cycles = 0; + node->prev_ts = 0; + node->prev_calls = 0; + node->prev_objs = 0; + node->prev_cycles = 0; + node->realloc_count = 0; + cluster = RTE_PTR_ADD(cluster, stat->cluster_node_size); + } +} diff --git a/lib/librte_graph/meson.build b/lib/librte_graph/meson.build index fb203a5e2..929a17f84 100644 --- a/lib/librte_graph/meson.build +++ b/lib/librte_graph/meson.build @@ -4,7 +4,7 @@ name = 'graph' -sources = files('node.c', 'graph.c', 'graph_ops.c', 'graph_debug.c', 'graph_populate.c') +sources = files('node.c', 'graph.c', 'graph_ops.c', 'graph_debug.c', 'graph_stats.c', 'graph_populate.c') headers = files('rte_graph.h', 'rte_graph_worker.h') allow_experimental_apis = true diff --git a/lib/librte_graph/rte_graph_version.map b/lib/librte_graph/rte_graph_version.map index 851f4772e..adf55d406 100644 --- a/lib/librte_graph/rte_graph_version.map +++ b/lib/librte_graph/rte_graph_version.map @@ -17,6 +17,11 @@ EXPERIMENTAL { rte_graph_node_get_by_name; rte_graph_obj_dump; + rte_graph_cluster_stats_create; + rte_graph_cluster_stats_destroy; + rte_graph_cluster_stats_get; + rte_graph_cluster_stats_reset; + rte_node_clone; rte_node_dump; rte_node_edge_count; From patchwork Wed Mar 18 21:35:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66906 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 35167A057D; Wed, 18 Mar 2020 22:37:35 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id A2BB41BF30; Wed, 18 Mar 2020 22:36:12 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by dpdk.org (Postfix) with ESMTP id CDCFA1C10C for ; Wed, 18 Mar 2020 22:36:10 +0100 (CET) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILUsFQ003319; Wed, 18 Mar 2020 14:36:08 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=pp6jdSFAMf3SAdy/Xt8Ba4Iow8bktXBUxAEwOfkD8Yo=; b=xa5Bip77sb6PzlWmkuisGhoeTAd8vZff8xNwmzdEtdwqFIMu+zRKQ867hAOPORokdV6h lS31fPhc1vrT2gGiVG61yb5WMG1E9MHhRgy0QqACgCygqF5qUhvyKi8oyAsVBw8ZDuHo 67z7IIUNQhLw/zbBBVKLJBjm7KogVZ8vH2tsS43sg8x+FphwZp9RVh/peY4MCB5LmvO/ O5UCIGwOHL1J+R4XHSlPmczYz5/E/oGJytuNArEaflheE+1zq23VpU4ABhr0JPCHgR+s wdJQ+W6nOQ8bHB8cUEchrIhsOF7tGmzprlayBz+/803Zy/mRJsPjIzdiVhEF+4OXGdl6 +w== Received: from sc-exch01.marvell.com ([199.233.58.181]) by mx0a-0016f401.pphosted.com with ESMTP id 2yu8pqmrbr-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:36:07 -0700 Received: from SC-EXCH01.marvell.com (10.93.176.81) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:06 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:36:06 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id 6A7173F7041; Wed, 18 Mar 2020 14:36:03 -0700 (PDT) From: To: John McNamara , Marko Kovacevic , Jerin Jacob , Kiran Kumar K CC: , , , , , , Date: Thu, 19 Mar 2020 03:05:37 +0530 Message-ID: <20200318213551.3489504-13-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 12/26] graph: implement fastpath API routines X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Jerin Jacob Adding implementation for rte_graph_walk() API. This will perform a walk on the circular buffer and call the process function of each node and collect the stats if stats collection is enabled. Signed-off-by: Jerin Jacob Signed-off-by: Kiran Kumar K Signed-off-by: Pavan Nikhilesh Signed-off-by: Nithin Dabilpuram --- doc/api/doxy-api-index.md | 1 + lib/librte_graph/graph.c | 16 + lib/librte_graph/rte_graph_version.map | 10 + lib/librte_graph/rte_graph_worker.h | 434 +++++++++++++++++++++++++ 4 files changed, 461 insertions(+) diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md index 5cc50f750..fd2ff64d7 100644 --- a/doc/api/doxy-api-index.md +++ b/doc/api/doxy-api-index.md @@ -160,6 +160,7 @@ The public API headers are grouped by topics: [port_in_action] (@ref rte_port_in_action.h) [table_action] (@ref rte_table_action.h) * [graph] (@ref rte_graph.h): + [graph_worker] (@ref rte_graph_worker.h) - **basic**: [approx fraction] (@ref rte_approx.h), diff --git a/lib/librte_graph/graph.c b/lib/librte_graph/graph.c index cc1e523d9..78bc83c4e 100644 --- a/lib/librte_graph/graph.c +++ b/lib/librte_graph/graph.c @@ -475,6 +475,22 @@ __rte_node_stream_alloc(struct rte_graph *graph, struct rte_node *node) node->realloc_count++; } +void __rte_noinline +__rte_node_stream_alloc_size(struct rte_graph *graph, struct rte_node *node, + uint16_t req_size) +{ + uint16_t size = node->size; + + RTE_VERIFY(size != UINT16_MAX); + /* Allocate double amount of size to avoid immediate realloc */ + size = RTE_MIN(UINT16_MAX, RTE_MAX(RTE_GRAPH_BURST_SIZE, req_size * 2)); + node->objs = rte_realloc_socket(node->objs, size * sizeof(void *), + RTE_CACHE_LINE_SIZE, graph->socket); + RTE_VERIFY(node->objs); + node->size = size; + node->realloc_count++; +} + static int graph_to_dot(FILE *f, struct graph *graph) { diff --git a/lib/librte_graph/rte_graph_version.map b/lib/librte_graph/rte_graph_version.map index adf55d406..13b838752 100644 --- a/lib/librte_graph/rte_graph_version.map +++ b/lib/librte_graph/rte_graph_version.map @@ -3,6 +3,7 @@ EXPERIMENTAL { __rte_node_register; __rte_node_stream_alloc; + __rte_node_stream_alloc_size; rte_graph_create; rte_graph_destroy; @@ -16,6 +17,7 @@ EXPERIMENTAL { rte_graph_node_get; rte_graph_node_get_by_name; rte_graph_obj_dump; + rte_graph_walk; rte_graph_cluster_stats_create; rte_graph_cluster_stats_destroy; @@ -28,10 +30,18 @@ EXPERIMENTAL { rte_node_edge_get; rte_node_edge_shrink; rte_node_edge_update; + rte_node_enqueue; + rte_node_enqueue_x1; + rte_node_enqueue_x2; + rte_node_enqueue_x4; + rte_node_enqueue_next; rte_node_from_name; rte_node_id_to_name; rte_node_list_dump; rte_node_max_count; + rte_node_next_stream_get; + rte_node_next_stream_put; + rte_node_next_stream_move; local: *; }; diff --git a/lib/librte_graph/rte_graph_worker.h b/lib/librte_graph/rte_graph_worker.h index a7c780d4d..8e067e673 100644 --- a/lib/librte_graph/rte_graph_worker.h +++ b/lib/librte_graph/rte_graph_worker.h @@ -100,6 +100,440 @@ struct rte_node { __rte_experimental void __rte_node_stream_alloc(struct rte_graph *graph, struct rte_node *node); +/** + * @internal + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Allocate a stream with requested number of objects. + * + * If stream already exists then re-allocate it to a larger size. + * + * @param graph + * Pointer to the graph object. + * @param node + * Pointer to the node object. + * @param req_size + * Number of objects to be allocated. + */ +__rte_experimental +void __rte_node_stream_alloc_size(struct rte_graph *graph, + struct rte_node *node, uint16_t req_size); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Perform graph walk on the circular buffer and invoke the process function + * of the nodes and collect the stats. + * + * @param graph + * Graph pointer returned from rte_graph_lookup function. + * + * @see rte_graph_lookup() + */ +__rte_experimental +static inline void +rte_graph_walk(struct rte_graph *graph) +{ + const rte_graph_off_t *cir_start = graph->cir_start; + const rte_node_t mask = graph->cir_mask; + uint32_t head = graph->head; + struct rte_node *node; + uint64_t start; + uint16_t rc; + void **objs; + + /* + * Walk on the source node(s) ((cir_start - head) -> cir_start) and then + * on the pending streams (cir_start -> (cir_start + mask) -> cir_start) + * in a circular buffer fashion. + * + * +-----+ <= cir_start - head [number of source nodes] + * | | + * | ... | <= source nodes + * | | + * +-----+ <= cir_start [head = 0] [tail = 0] + * | | + * | ... | <= pending streams + * | | + * +-----+ <= cir_start + mask + */ + while (likely(head != graph->tail)) { + node = RTE_PTR_ADD(graph, cir_start[(int32_t)head++]); + RTE_ASSERT(node->fence == RTE_GRAPH_FENCE); + objs = node->objs; + rte_prefetch0(objs); + + if (rte_graph_has_stats_feature()) { + start = rte_rdtsc(); + rc = node->process(graph, node, objs, node->idx); + node->total_cycles += rte_rdtsc() - start; + node->total_calls++; + node->total_objs += rc; + } else { + node->process(graph, node, objs, node->idx); + } + node->idx = 0; + head = likely((int32_t)head > 0) ? head & mask : head; + } + graph->tail = 0; +} + +/* Fast path helper functions */ + +/** + * @internal + * + * Enqueue a given node to the tail of the graph reel. + * + * @param graph + * Pointer Graph object. + * @param node + * Pointer to node object to be enqueued. + */ +static __rte_always_inline void +__rte_node_enqueue_tail_update(struct rte_graph *graph, struct rte_node *node) +{ + uint32_t tail; + + tail = graph->tail; + graph->cir_start[tail++] = node->off; + graph->tail = tail & graph->cir_mask; +} + +/** + * @internal + * + * Enqueue sequence prologue function. + * + * Updates the node to tail of graph reel and resizes the number of objects + * available in the stream as needed. + * + * @param graph + * Pointer to the graph object. + * @param node + * Pointer to the node object. + * @param idx + * Index at which the object enqueue starts from. + * @param space + * Space required for the object enqueue. + */ +static __rte_always_inline void +__rte_node_enqueue_prologue(struct rte_graph *graph, struct rte_node *node, + const uint16_t idx, const uint16_t space) +{ + + /* Add to the pending stream list if the node is new */ + if (idx == 0) + __rte_node_enqueue_tail_update(graph, node); + + if (unlikely(node->size < (idx + space))) + __rte_node_stream_alloc(graph, node); +} + +/** + * @internal + * + * Get the node pointer from current node edge id. + * + * @param node + * Current node pointer. + * @param next + * Edge id of the required node. + * + * @return + * Pointer to the node denoted by the edge id. + */ +static __rte_always_inline struct rte_node * +__rte_node_next_node_get(struct rte_node *node, rte_edge_t next) +{ + RTE_ASSERT(next < node->nb_edges); + RTE_ASSERT(node->fence == RTE_GRAPH_FENCE); + node = node->nodes[next]; + RTE_ASSERT(node->fence == RTE_GRAPH_FENCE); + + return node; +} + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Enqueue the objs to next node for further processing and set + * the next node to pending state in the circular buffer. + * + * @param graph + * Graph pointer returned from rte_graph_lookup(). + * @param node + * Current node pointer. + * @param next + * Relative next node index to enqueue objs. + * @param objs + * Objs to enqueue. + * @param nb_objs + * Number of objs to enqueue. + */ +__rte_experimental +static inline void +rte_node_enqueue(struct rte_graph *graph, struct rte_node *node, + rte_edge_t next, void **objs, uint16_t nb_objs) +{ + node = __rte_node_next_node_get(node, next); + const uint16_t idx = node->idx; + + __rte_node_enqueue_prologue(graph, node, idx, nb_objs); + + rte_memcpy(&node->objs[idx], objs, nb_objs * sizeof(void *)); + node->idx = idx + nb_objs; +} + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Enqueue only one obj to next node for further processing and + * set the next node to pending state in the circular buffer. + * + * @param graph + * Graph pointer returned from rte_graph_lookup(). + * @param node + * Current node pointer. + * @param next + * Relative next node index to enqueue objs. + * @param obj + * Obj to enqueue. + */ +__rte_experimental +static inline void +rte_node_enqueue_x1(struct rte_graph *graph, struct rte_node *node, + rte_edge_t next, void *obj) +{ + node = __rte_node_next_node_get(node, next); + uint16_t idx = node->idx; + + __rte_node_enqueue_prologue(graph, node, idx, 1); + + node->objs[idx++] = obj; + node->idx = idx; +} + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Enqueue only two objs to next node for further processing and + * set the next node to pending state in the circular buffer. + * Same as rte_node_enqueue_x1 but enqueue two objs. + * + * @param graph + * Graph pointer returned from rte_graph_lookup(). + * @param node + * Current node pointer. + * @param next + * Relative next node index to enqueue objs. + * @param obj0 + * Obj to enqueue. + * @param obj1 + * Obj to enqueue. + */ +__rte_experimental +static inline void +rte_node_enqueue_x2(struct rte_graph *graph, struct rte_node *node, + rte_edge_t next, void *obj0, void *obj1) +{ + node = __rte_node_next_node_get(node, next); + uint16_t idx = node->idx; + + __rte_node_enqueue_prologue(graph, node, idx, 2); + + node->objs[idx++] = obj0; + node->objs[idx++] = obj1; + node->idx = idx; +} + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Enqueue only four objs to next node for further processing and + * set the next node to pending state in the circular buffer. + * Same as rte_node_enqueue_x1 but enqueue four objs. + * + * @param graph + * Graph pointer returned from rte_graph_lookup(). + * @param node + * Current node pointer. + * @param next + * Relative next node index to enqueue objs. + * @param obj0 + * 1st obj to enqueue. + * @param obj1 + * 2nd obj to enqueue. + * @param obj2 + * 3rd obj to enqueue. + * @param obj3 + * 4th obj to enqueue. + */ +__rte_experimental +static inline void +rte_node_enqueue_x4(struct rte_graph *graph, struct rte_node *node, + rte_edge_t next, void *obj0, void *obj1, void *obj2, + void *obj3) +{ + node = __rte_node_next_node_get(node, next); + uint16_t idx = node->idx; + + __rte_node_enqueue_prologue(graph, node, idx, 4); + + node->objs[idx++] = obj0; + node->objs[idx++] = obj1; + node->objs[idx++] = obj2; + node->objs[idx++] = obj3; + node->idx = idx; +} + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Enqueue objs to multiple next nodes for further processing and + * set the next nodes to pending state in the circular buffer. + * objs[i] will be enqueued to nexts[i]. + * + * @param graph + * Graph pointer returned from rte_graph_lookup(). + * @param node + * Current node pointer. + * @param nexts + * List of relative next node indices to enqueue objs. + * @param objs + * List of objs to enqueue. + * @param nb_objs + * Number of objs to enqueue. + */ +__rte_experimental +static inline void +rte_node_enqueue_next(struct rte_graph *graph, struct rte_node *node, + rte_edge_t *nexts, void **objs, uint16_t nb_objs) +{ + uint16_t i; + + for (i = 0; i < nb_objs; i++) + rte_node_enqueue_x1(graph, node, nexts[i], objs[i]); +} + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Get the stream of next node to enqueue the objs. + * Once done with the updating the objs, needs to call + * rte_node_next_stream_put to put the next node to pending state. + * + * @param graph + * Graph pointer returned from rte_graph_lookup(). + * @param node + * Current node pointer. + * @param next + * Relative next node index to get stream. + * @param nb_objs + * Requested free size of the next stream. + * + * @return + * Valid next stream on success. + * + * @see rte_node_next_stream_put(). + */ +__rte_experimental +static inline void ** +rte_node_next_stream_get(struct rte_graph *graph, struct rte_node *node, + rte_edge_t next, uint16_t nb_objs) +{ + node = __rte_node_next_node_get(node, next); + const uint16_t idx = node->idx; + uint16_t free_space = node->size - idx; + + if (unlikely(free_space < nb_objs)) + __rte_node_stream_alloc_size(graph, node, nb_objs); + + return &node->objs[idx]; +} + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Put the next stream to pending state in the circular buffer + * for further processing. Should be invoked followed by + * rte_node_next_stream_get(). + * + * @param graph + * Graph pointer returned from rte_graph_lookup(). + * @param node + * Current node pointer. + * @param next + * Relative next node index.. + * @param idx + * Number of objs updated in the stream after getting the stream using + * rte_node_next_stream_get. + * + * @see rte_node_next_stream_get(). + */ +__rte_experimental +static inline void +rte_node_next_stream_put(struct rte_graph *graph, struct rte_node *node, + rte_edge_t next, uint16_t idx) +{ + if (unlikely(!idx)) + return; + + node = __rte_node_next_node_get(node, next); + if (node->idx == 0) + __rte_node_enqueue_tail_update(graph, node); + + node->idx += idx; +} + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Home run scenario, Enqueue all the objs of current node to next + * node in optimized way by swapping the streams of both nodes. + * Performs good when next node is already not in pending state. + * If next node is already in pending state then normal enqueue + * will be used. + * + * @param graph + * Graph pointer returned from rte_graph_lookup(). + * @param src + * Current node pointer. + * @param next + * Relative next node index. + */ +__rte_experimental +static inline void +rte_node_next_stream_move(struct rte_graph *graph, struct rte_node *src, + rte_edge_t next) +{ + struct rte_node *dst = __rte_node_next_node_get(src, next); + + /* Let swap the pointers if dst don't have valid objs */ + if (likely(dst->idx == 0)) { + void **dobjs = dst->objs; + uint16_t dsz = dst->size; + dst->objs = src->objs; + dst->size = src->size; + src->objs = dobjs; + src->size = dsz; + dst->idx = src->idx; + __rte_node_enqueue_tail_update(graph, dst); + } else { /* Move the objects from src node to dst node */ + rte_node_enqueue(graph, src, next, src->objs, src->idx); + } +} + #ifdef __cplusplus } #endif From patchwork Wed Mar 18 21:35:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66907 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id A0DF8A057D; Wed, 18 Mar 2020 22:37:44 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 253371C113; Wed, 18 Mar 2020 22:36:16 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) by dpdk.org (Postfix) with ESMTP id A15541C10E for ; Wed, 18 Mar 2020 22:36:14 +0100 (CET) Received: from pps.filterd (m0045851.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILVOKi013821; Wed, 18 Mar 2020 14:36:12 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=TserDJ9cX/emdldWVmWjTPBtiHu5IQYero4rhO7Pk18=; b=UMctnVeOzSH6N02n5vZrd32C0G099eB6bOCz/qjtmrLTi1QSP55NXBf6ci12I8WyYeCt BjtOElJvEfqms0KDwoq32/JMITTuYQ7GKYY7H9w3AdoNuhU1E/BM//r5vPSnGLN+hmGz 8RWt5q+4Co9jOpO1RXH/MuMpbXX9NWY9ZSDPStw5+P++dMySSsEixb3pSRpwnjxEsYgW eNMrha5Hwj6iuC0WW4O7TOOITc57STFl5bLA7EmuQ8uncPnLJS45d3OHxugTPG3DafLK 5MLS0nWHRmoRafTiw8Ms8DpJse3Z/yzAzdNm3QAApadMYhfNDlLIrfOSRdu3T1DQJset ag== Received: from sc-exch04.marvell.com ([199.233.58.184]) by mx0b-0016f401.pphosted.com with ESMTP id 2yu9rpcc4d-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:36:12 -0700 Received: from SC-EXCH03.marvell.com (10.93.176.83) by SC-EXCH04.marvell.com (10.93.176.84) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:10 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:36:10 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id BC5E93F7040; Wed, 18 Mar 2020 14:36:07 -0700 (PDT) From: To: CC: , , , , , , , Date: Thu, 19 Mar 2020 03:05:38 +0530 Message-ID: <20200318213551.3489504-14-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 13/26] graph: add unit test case X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Kiran Kumar K Adding the unit test to test the functionality of node and graph APIs. Testing includes registering a node, cloning a node, creating a graph, perform graph walk, collecting stats and all node and graph debug APIs. example command to test: echo "graph_autotest" | sudo ./build/app/test/dpdk-test -c 0x30 Signed-off-by: Kiran Kumar K --- app/test/Makefile | 4 + app/test/meson.build | 10 +- app/test/test_graph.c | 820 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 832 insertions(+), 2 deletions(-) create mode 100644 app/test/test_graph.c diff --git a/app/test/Makefile b/app/test/Makefile index 1f080d162..065582916 100644 --- a/app/test/Makefile +++ b/app/test/Makefile @@ -221,6 +221,10 @@ SRCS-y += test_event_timer_adapter.c SRCS-y += test_event_crypto_adapter.c endif +ifeq ($(CONFIG_RTE_LIBRTE_GRAPH), y) +SRCS-y += test_graph.c +endif + ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y) SRCS-y += test_rawdev.c endif diff --git a/app/test/meson.build b/app/test/meson.build index 0a2ce710f..855403932 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -51,6 +51,7 @@ test_sources = files('commands.c', 'test_fib6_perf.c', 'test_func_reentrancy.c', 'test_flow_classify.c', + 'test_graph.c', 'test_hash.c', 'test_hash_functions.c', 'test_hash_multiwriter.c', @@ -151,7 +152,9 @@ test_deps = ['acl', 'rib', 'ring', 'stack', - 'timer' + 'timer', + 'graph', + 'node' ] fast_test_names = [ @@ -183,6 +186,7 @@ fast_test_names = [ 'fib6_autotest', 'func_reentrancy_autotest', 'flow_classify_autotest', + 'graph_autotest', 'hash_autotest', 'interrupt_autotest', 'logs_autotest', @@ -383,13 +387,15 @@ endforeach test_dep_objs += cc.find_library('execinfo', required: false) link_libs = [] +link_nodes = [] if get_option('default_library') == 'static' link_libs = dpdk_drivers + link_nodes = dpdk_graph_nodes endif dpdk_test = executable('dpdk-test', test_sources, - link_whole: link_libs, + link_whole: link_libs + link_nodes, dependencies: test_dep_objs, c_args: [cflags, '-DALLOW_EXPERIMENTAL_API'], install_rpath: driver_install_path, diff --git a/app/test/test_graph.c b/app/test/test_graph.c new file mode 100644 index 000000000..e0116a9ce --- /dev/null +++ b/app/test/test_graph.c @@ -0,0 +1,820 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "test.h" + +static uint16_t test_node_worker_source(struct rte_graph *graph, + struct rte_node *node, void **objs, + uint16_t nb_objs); + +static uint16_t test_node0_worker(struct rte_graph *graph, + struct rte_node *node, void **objs, + uint16_t nb_objs); + +static uint16_t test_node1_worker(struct rte_graph *graph, + struct rte_node *node, void **objs, + uint16_t nb_objs); + +static uint16_t test_node2_worker(struct rte_graph *graph, + struct rte_node *node, void **objs, + uint16_t nb_objs); + +static uint16_t test_node3_worker(struct rte_graph *graph, + struct rte_node *node, void **objs, + uint16_t nb_objs); + +#define MBUFF_SIZE 512 +#define MAX_NODES 4 + +static struct rte_mbuf mbuf[MAX_NODES + 1][MBUFF_SIZE]; +static void *mbuf_p[MAX_NODES + 1][MBUFF_SIZE]; +static rte_graph_t graph_id; +static uint64_t obj_stats[MAX_NODES + 1]; +static uint64_t fn_calls[MAX_NODES + 1]; + +const char *node_patterns[] = { + "test_node_source1", "test_node00", + "test_node00-test_node11", "test_node00-test_node22", + "test_node00-test_node33", +}; + +const char *node_names[] = { + "test_node00", + "test_node00-test_node11", + "test_node00-test_node22", + "test_node00-test_node33", +}; + +struct test_node_register { +#define NODE_NAMESIZE 64 + char name[NODE_NAMESIZE]; + rte_node_process_t process; + uint16_t nb_edges; + const char *next_nodes[MAX_NODES]; +}; + +typedef struct { + uint32_t idx; + struct test_node_register node; +} test_node_t; + +typedef struct { + test_node_t test_node[MAX_NODES]; +} test_main_t; + +static test_main_t test_main = { + .test_node = { + { + .node = { + .name = "test_node00", + .process = test_node0_worker, + .nb_edges = 2, + .next_nodes = {"test_node00-" + "test_node11", + "test_node00-" + "test_node22"}, + }, + }, + { + .node = { + .name = "test_node11", + .process = test_node1_worker, + .nb_edges = 1, + .next_nodes = {"test_node00-" + "test_node22"}, + }, + }, + { + .node = { + .name = "test_node22", + .process = test_node2_worker, + .nb_edges = 1, + .next_nodes = {"test_node00-" + "test_node33"}, + }, + }, + { + .node = { + .name = "test_node33", + .process = test_node3_worker, + .nb_edges = 1, + .next_nodes = {"test_node00"}, + }, + }, + }, +}; + +static int +node_init(const struct rte_graph *graph, struct rte_node *node) +{ + RTE_SET_USED(graph); + *(uint32_t *)node->ctx = node->id; + + return 0; +} + +static struct rte_node_register test_node_source = { + .name = "test_node_source1", + .process = test_node_worker_source, + .flags = RTE_NODE_SOURCE_F, + .nb_edges = 2, + .init = node_init, + .next_nodes = {"test_node00", "test_node00-test_node11"}, +}; +RTE_NODE_REGISTER(test_node_source); + +static struct rte_node_register test_node0 = { + .name = "test_node00", + .process = test_node0_worker, + .init = node_init, +}; +RTE_NODE_REGISTER(test_node0); + +uint16_t +test_node_worker_source(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + uint32_t obj_node0 = rand() % 100, obj_node1; + test_main_t *tm = &test_main; + struct rte_mbuf *data; + void **next_stream; + rte_node_t next; + uint32_t i; + + RTE_SET_USED(objs); + nb_objs = RTE_GRAPH_BURST_SIZE; + + /* Prepare stream for next node 0 */ + obj_node0 = nb_objs * obj_node0 * 0.01; + next = 0; + next_stream = rte_node_next_stream_get(graph, node, next, obj_node0); + for (i = 0; i < obj_node0; i++) { + data = &mbuf[0][i]; + data->udata64 = ((uint64_t)tm->test_node[0].idx << 32) | i; + if ((i + 1) == obj_node0) + data->udata64 |= (1 << 16); + next_stream[i] = &mbuf[0][i]; + } + rte_node_next_stream_put(graph, node, next, obj_node0); + + /* Prepare stream for next node 1 */ + obj_node1 = nb_objs - obj_node0; + next = 1; + next_stream = rte_node_next_stream_get(graph, node, next, obj_node1); + for (i = 0; i < obj_node1; i++) { + data = &mbuf[0][obj_node0 + i]; + data->udata64 = ((uint64_t)tm->test_node[1].idx << 32) | i; + if ((i + 1) == obj_node1) + data->udata64 |= (1 << 16); + next_stream[i] = &mbuf[0][obj_node0 + i]; + } + + rte_node_next_stream_put(graph, node, next, obj_node1); + obj_stats[0] += nb_objs; + fn_calls[0] += 1; + return nb_objs; +} + +uint16_t +test_node0_worker(struct rte_graph *graph, struct rte_node *node, void **objs, + uint16_t nb_objs) +{ + test_main_t *tm = &test_main; + + if (*(uint32_t *)node->ctx == test_node0.id) { + uint32_t obj_node0 = rand() % 100, obj_node1; + struct rte_mbuf *data; + uint8_t second_pass = 0; + uint32_t count = 0; + uint32_t i; + + obj_stats[1] += nb_objs; + fn_calls[1] += 1; + + for (i = 0; i < nb_objs; i++) { + data = (struct rte_mbuf *)objs[i]; + if ((data->udata64 >> 32) != tm->test_node[0].idx) { + printf("Data idx miss match at node 0, expected" + " = %u got = %u\n", + tm->test_node[0].idx, + (uint32_t)(data->udata64 >> 32)); + goto end; + } + + if ((data->udata64 & 0xffff) != (i - count)) { + printf("Expected buff count miss match at " + "node 0\n"); + goto end; + } + + if (data->udata64 & (0x1 << 16)) + count = i + 1; + if (data->udata64 & (0x1 << 17)) + second_pass = 1; + } + + if (count != i) { + printf("Count mismatch at node 0\n"); + goto end; + } + + obj_node0 = nb_objs * obj_node0 * 0.01; + for (i = 0; i < obj_node0; i++) { + data = &mbuf[1][i]; + data->udata64 = + ((uint64_t)tm->test_node[1].idx << 32) | i; + if ((i + 1) == obj_node0) + data->udata64 |= (1 << 16); + if (second_pass) + data->udata64 |= (1 << 17); + } + rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[1][0], + obj_node0); + + obj_node1 = nb_objs - obj_node0; + for (i = 0; i < obj_node1; i++) { + data = &mbuf[1][obj_node0 + i]; + data->udata64 = + ((uint64_t)tm->test_node[2].idx << 32) | i; + if ((i + 1) == obj_node1) + data->udata64 |= (1 << 16); + if (second_pass) + data->udata64 |= (1 << 17); + } + rte_node_enqueue(graph, node, 1, (void **)&mbuf_p[1][obj_node0], + obj_node1); + + } else if (*(uint32_t *)node->ctx == tm->test_node[1].idx) { + test_node1_worker(graph, node, objs, nb_objs); + } else if (*(uint32_t *)node->ctx == tm->test_node[2].idx) { + test_node2_worker(graph, node, objs, nb_objs); + } else if (*(uint32_t *)node->ctx == tm->test_node[3].idx) { + test_node3_worker(graph, node, objs, nb_objs); + } else { + printf("Unexpected node context\n"); + } + +end: + return nb_objs; +} + +uint16_t +test_node1_worker(struct rte_graph *graph, struct rte_node *node, void **objs, + uint16_t nb_objs) +{ + test_main_t *tm = &test_main; + uint8_t second_pass = 0; + uint32_t obj_node0 = 0; + struct rte_mbuf *data; + uint32_t count = 0; + uint32_t i; + + obj_stats[2] += nb_objs; + fn_calls[2] += 1; + for (i = 0; i < nb_objs; i++) { + data = (struct rte_mbuf *)objs[i]; + if ((data->udata64 >> 32) != tm->test_node[1].idx) { + printf("Data idx miss match at node 1, expected = %u" + " got = %u\n", + tm->test_node[1].idx, + (uint32_t)(data->udata64 >> 32)); + goto end; + } + + if ((data->udata64 & 0xffff) != (i - count)) { + printf("Expected buff count miss match at node 1\n"); + goto end; + } + + if (data->udata64 & (0x1 << 16)) + count = i + 1; + if (data->udata64 & (0x1 << 17)) + second_pass = 1; + } + + if (count != i) { + printf("Count mismatch at node 1\n"); + goto end; + } + + obj_node0 = nb_objs; + for (i = 0; i < obj_node0; i++) { + data = &mbuf[2][i]; + data->udata64 = ((uint64_t)tm->test_node[2].idx << 32) | i; + if ((i + 1) == obj_node0) + data->udata64 |= (1 << 16); + if (second_pass) + data->udata64 |= (1 << 17); + } + rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[2][0], obj_node0); + +end: + return nb_objs; +} + +uint16_t +test_node2_worker(struct rte_graph *graph, struct rte_node *node, void **objs, + uint16_t nb_objs) +{ + test_main_t *tm = &test_main; + uint8_t second_pass = 0; + struct rte_mbuf *data; + uint32_t count = 0; + uint32_t obj_node0; + uint32_t i; + + obj_stats[3] += nb_objs; + fn_calls[3] += 1; + for (i = 0; i < nb_objs; i++) { + data = (struct rte_mbuf *)objs[i]; + if ((data->udata64 >> 32) != tm->test_node[2].idx) { + printf("Data idx miss match at node 2, expected = %u" + " got = %u\n", + tm->test_node[2].idx, + (uint32_t)(data->udata64 >> 32)); + goto end; + } + + if ((data->udata64 & 0xffff) != (i - count)) { + printf("Expected buff count miss match at node 2\n"); + goto end; + } + + if (data->udata64 & (0x1 << 16)) + count = i + 1; + if (data->udata64 & (0x1 << 17)) + second_pass = 1; + } + + if (count != i) { + printf("Count mismatch at node 2\n"); + goto end; + } + + if (!second_pass) { + obj_node0 = nb_objs; + for (i = 0; i < obj_node0; i++) { + data = &mbuf[3][i]; + data->udata64 = + ((uint64_t)tm->test_node[3].idx << 32) | i; + if ((i + 1) == obj_node0) + data->udata64 |= (1 << 16); + } + rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[3][0], + obj_node0); + } + +end: + return nb_objs; +} + +uint16_t +test_node3_worker(struct rte_graph *graph, struct rte_node *node, void **objs, + uint16_t nb_objs) +{ + test_main_t *tm = &test_main; + uint8_t second_pass = 0; + struct rte_mbuf *data; + uint32_t count = 0; + uint32_t obj_node0; + uint32_t i; + + obj_stats[4] += nb_objs; + fn_calls[4] += 1; + for (i = 0; i < nb_objs; i++) { + data = (struct rte_mbuf *)objs[i]; + if ((data->udata64 >> 32) != tm->test_node[3].idx) { + printf("Data idx miss match at node 3, expected = %u" + " got = %u\n", + tm->test_node[3].idx, + (uint32_t)(data->udata64 >> 32)); + goto end; + } + + if ((data->udata64 & 0xffff) != (i - count)) { + printf("Expected buff count miss match at node 3\n"); + goto end; + } + + if (data->udata64 & (0x1 << 16)) + count = i + 1; + if (data->udata64 & (0x1 << 17)) + second_pass = 1; + } + + if (count != i) { + printf("Count mismatch at node 3\n"); + goto end; + } + + if (second_pass) { + printf("Unexpected buffers are at node 3\n"); + goto end; + } else { + obj_node0 = nb_objs * 2; + for (i = 0; i < obj_node0; i++) { + data = &mbuf[4][i]; + data->udata64 = + ((uint64_t)tm->test_node[0].idx << 32) | i; + data->udata64 |= (1 << 17); + if ((i + 1) == obj_node0) + data->udata64 |= (1 << 16); + } + rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[4][0], + obj_node0); + } + +end: + return nb_objs; +} + +static int +test_lookup_functions(void) +{ + test_main_t *tm = &test_main; + int i; + + /* Verify the name with ID */ + for (i = 1; i < MAX_NODES; i++) { + char *name = rte_node_id_to_name(tm->test_node[i].idx); + if (strcmp(name, node_names[i]) != 0) { + printf("Test node name verify by ID = %d failed " + "Expected = %s, got %s\n", + i, node_names[i], name); + return -1; + } + } + + /* Verify by name */ + for (i = 1; i < MAX_NODES; i++) { + uint32_t idx = rte_node_from_name(node_names[i]); + if (idx != tm->test_node[i].idx) { + printf("Test node ID verify by name = %s failed " + "Expected = %d, got %d\n", + node_names[i], tm->test_node[i].idx, idx); + return -1; + } + } + + /* Verify edge count */ + for (i = 1; i < MAX_NODES; i++) { + uint32_t count = rte_node_edge_count(tm->test_node[i].idx); + if (count != tm->test_node[i].node.nb_edges) { + printf("Test number of edges for node = %s failed Expected = %d, got = %d\n", + tm->test_node[i].node.name, + tm->test_node[i].node.nb_edges, count); + return -1; + } + } + + /* Verify edge names */ + for (i = 1; i < MAX_NODES; i++) { + uint32_t j, count; + char **next_edges; + + count = rte_node_edge_get(tm->test_node[i].idx, NULL); + if (count != tm->test_node[i].node.nb_edges * sizeof(char *)) { + printf("Test number of edge count for node = %s failed Expected = %d, got = %d\n", + tm->test_node[i].node.name, + tm->test_node[i].node.nb_edges, count); + return -1; + } + next_edges = malloc(count); + count = rte_node_edge_get(tm->test_node[i].idx, next_edges); + if (count != tm->test_node[i].node.nb_edges) { + printf("Test number of edges for node = %s failed Expected = %d, got %d\n", + tm->test_node[i].node.name, + tm->test_node[i].node.nb_edges, count); + return -1; + } + + for (j = 0; j < count; j++) { + if (strcmp(next_edges[j], + tm->test_node[i].node.next_nodes[j]) != 0) { + printf("Edge name miss match, expected = %s got = %s\n", + tm->test_node[i].node.next_nodes[j], + next_edges[j]); + return -1; + } + } + free(next_edges); + } + + return 0; +} + +static int +test_node_clone(void) +{ + test_main_t *tm = &test_main; + uint32_t node_id, dummy_id; + int i; + + node_id = rte_node_from_name("test_node00"); + tm->test_node[0].idx = node_id; + + /* Clone with same name, should fail */ + dummy_id = rte_node_clone(node_id, "test_node00"); + if (!rte_node_is_invalid(dummy_id)) { + printf("Got valid id when clone with same name, Expecting fail\n"); + return -1; + } + + for (i = 1; i < MAX_NODES; i++) { + tm->test_node[i].idx = + rte_node_clone(node_id, tm->test_node[i].node.name); + if (rte_node_is_invalid(tm->test_node[i].idx)) { + printf("Got invalid node id\n"); + return -1; + } + } + + /* Clone from cloned node should fail */ + dummy_id = rte_node_clone(tm->test_node[1].idx, "dummy_node"); + if (!rte_node_is_invalid(dummy_id)) { + printf("Got valid node id when cloning from cloned node, expected fail\n"); + return -1; + } + + return 0; +} + +static int +test_update_edges(void) +{ + test_main_t *tm = &test_main; + uint32_t node_id; + uint16_t count; + int i; + + node_id = rte_node_from_name("test_node00"); + count = rte_node_edge_update(node_id, 0, + tm->test_node[0].node.next_nodes, + tm->test_node[0].node.nb_edges); + if (count != tm->test_node[0].node.nb_edges) { + printf("Update edges failed expected: %d got = %d\n", + tm->test_node[0].node.nb_edges, count); + return -1; + } + + for (i = 1; i < MAX_NODES; i++) { + count = rte_node_edge_update(tm->test_node[i].idx, 0, + tm->test_node[i].node.next_nodes, + tm->test_node[i].node.nb_edges); + if (count != tm->test_node[i].node.nb_edges) { + printf("Update edges failed expected: %d got = %d\n", + tm->test_node[i].node.nb_edges, count); + return -1; + } + + count = rte_node_edge_shrink(tm->test_node[i].idx, + tm->test_node[i].node.nb_edges); + if (count != tm->test_node[i].node.nb_edges) { + printf("Shrink edges failed\n"); + return -1; + } + } + + return 0; +} + +static int +test_create_graph(void) +{ + static const char *node_patterns_dummy[] = { + "test_node_source1", "test_node00", + "test_node00-test_node11", "test_node00-test_node22", + "test_node00-test_node33", "test_node00-dummy_node", + }; + struct rte_graph_param gconf = { + .socket_id = SOCKET_ID_ANY, + .nb_node_patterns = 6, + .node_patterns = node_patterns_dummy, + }; + uint32_t dummy_node_id; + uint32_t node_id; + + node_id = rte_node_from_name("test_node00"); + dummy_node_id = rte_node_clone(node_id, "dummy_node"); + if (rte_node_is_invalid(dummy_node_id)) { + printf("Got invalid node id\n"); + return -1; + } + + graph_id = rte_graph_create("worker0", &gconf); + if (graph_id != RTE_GRAPH_ID_INVALID) { + printf("Graph creation success with isolated node, expected graph creation fail\n"); + return -1; + } + + gconf.nb_node_patterns = 5; + gconf.node_patterns = node_patterns; + graph_id = rte_graph_create("worker0", &gconf); + if (graph_id == RTE_GRAPH_ID_INVALID) { + printf("Graph creation failed with error = %d\n", rte_errno); + return -1; + } + return 0; +} + +static int +test_graph_walk(void) +{ + struct rte_graph *graph = rte_graph_lookup("worker0"); + int i; + + if (!graph) { + printf("Graph lookup failed\n"); + return -1; + } + + for (i = 0; i < 5; i++) + rte_graph_walk(graph); + return 0; +} + +static int +test_graph_lookup_functions(void) +{ + test_main_t *tm = &test_main; + struct rte_node *node; + int i; + + for (i = 0; i < MAX_NODES; i++) { + node = rte_graph_node_get(graph_id, tm->test_node[i].idx); + if (!node) { + printf("rte_graph_node_get, failed for node = %d\n", + tm->test_node[i].idx); + return -1; + } + + if (tm->test_node[i].idx != node->id) { + printf("Node id didn't match, expected = %d got = %d\n", + tm->test_node[i].idx, node->id); + return 0; + } + + if (strncmp(node->name, node_names[i], RTE_NODE_NAMESIZE)) { + printf("Node name didn't match, expected = %s got %s\n", + node_names[i], node->name); + return -1; + } + } + + for (i = 0; i < MAX_NODES; i++) { + node = rte_graph_node_get_by_name("worker0", node_names[i]); + if (!node) { + printf("rte_graph_node_get, failed for node = %d\n", + tm->test_node[i].idx); + return -1; + } + + if (tm->test_node[i].idx != node->id) { + printf("Node id didn't match, expected = %d got = %d\n", + tm->test_node[i].idx, node->id); + return 0; + } + + if (strncmp(node->name, node_names[i], RTE_NODE_NAMESIZE)) { + printf("Node name didn't match, expected = %s got %s\n", + node_names[i], node->name); + return -1; + } + } + + return 0; +} + +static int +graph_cluster_stats_cb_t(bool is_first, bool is_last, void *cookie, + const struct rte_graph_cluster_node_stats *st) +{ + int i; + + RTE_SET_USED(is_first); + RTE_SET_USED(is_last); + RTE_SET_USED(cookie); + + for (i = 0; i < MAX_NODES + 1; i++) { + rte_node_t id = rte_node_from_name(node_patterns[i]); + if (id == st->id) { + if (obj_stats[i] != st->objs) { + printf("Obj count miss match for node = %s expected = %"PRId64", got=%"PRId64"\n", + node_patterns[i], obj_stats[i], + st->objs); + return -1; + } + + if (fn_calls[i] != st->calls) { + printf("Func call miss match for node = %s expected = %"PRId64", got = %"PRId64"\n", + node_patterns[i], fn_calls[i], + st->calls); + return -1; + } + } + } + return 0; +} + +static int +test_print_stats(void) +{ + struct rte_graph_cluster_stats_param s_param; + struct rte_graph_cluster_stats *stats; + const char *pattern = "worker0"; + + if (!rte_graph_has_stats_feature()) + return 0; + + /* Prepare stats object */ + memset(&s_param, 0, sizeof(s_param)); + s_param.f = stdout; + s_param.socket_id = SOCKET_ID_ANY; + s_param.graph_patterns = &pattern; + s_param.nb_graph_patterns = 1; + s_param.fn = graph_cluster_stats_cb_t; + + stats = rte_graph_cluster_stats_create(&s_param); + if (stats == NULL) { + printf("Unable to get stats\n"); + return -1; + } + /* Clear screen and move to top left */ + rte_graph_cluster_stats_get(stats, 0); + rte_graph_cluster_stats_destroy(stats); + + return 0; +} + +static int +graph_setup(void) +{ + int i, j; + + for (i = 0; i <= MAX_NODES; i++) { + for (j = 0; j < MBUFF_SIZE; j++) + mbuf_p[i][j] = &mbuf[i][j]; + } + if (test_node_clone()) { + printf("test_node_clone: fail\n"); + return -1; + } + printf("test_node_clone: pass\n"); + + return 0; +} + +static void +graph_teardown(void) +{ + rte_graph_t id; + + id = rte_graph_destroy("worker0"); + if (id == RTE_GRAPH_ID_INVALID) + printf("Graph Destroy failed\n"); +} + +static struct unit_test_suite graph_testsuite = { + .suite_name = "Graph library test suite", + .setup = graph_setup, + .teardown = graph_teardown, + .unit_test_cases = { + TEST_CASE(test_update_edges), + TEST_CASE(test_lookup_functions), + TEST_CASE(test_create_graph), + TEST_CASE(test_graph_lookup_functions), + TEST_CASE(test_graph_walk), + TEST_CASE(test_print_stats), + TEST_CASES_END(), /**< NULL terminate unit test array */ + }, +}; + +static int +graph_autotest_fn(void) +{ + return unit_test_suite_runner(&graph_testsuite); +} + +REGISTER_TEST_COMMAND(graph_autotest, graph_autotest_fn); + +static int +test_node_list_dump(void) +{ + rte_node_list_dump(stdout); + + return TEST_SUCCESS; +} +REGISTER_TEST_COMMAND(node_list_dump, test_node_list_dump); + From patchwork Wed Mar 18 21:35:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66908 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 72D24A057D; Wed, 18 Mar 2020 22:37:56 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 8EE911C11C; Wed, 18 Mar 2020 22:36:20 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by dpdk.org (Postfix) with ESMTP id 4A3421C11D for ; Wed, 18 Mar 2020 22:36:19 +0100 (CET) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILUsKC003325; Wed, 18 Mar 2020 14:36:16 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=wnF6SjBJyd/1B7Q5WR6N3VNhTp84x5vVQlVV/XTo9OQ=; b=sZSLo9SdrFY/pdL0wpC4BZdngJf4GZUkM5oEnBKauTB7o8vwfQ8in3kTB+VF/EDOGrxo G2Ta9ZeHhXcm1Q6Hw9wWQE8msThlHXc70qdhnglw/P8hW0iPwTXpUq4D3yyH7K6Ofvr9 bH3uGc4XFlPVdDe24Lm+22KEBn9TIIlu6gLChxfq8Rsn8zb+ioTO+cG4hQpxz+1hVYqZ lfhUbAfJTnMCOXspLCl6iJfe8K6s1YzUwiLSf6SIcuxd4Y8V/lM7OxlXX3QSo3NVz42+ xaRaUKizGWuFwEIVi/9jB10YOxlk7ZHUt9lZmRd7UBzGCPm6+4X8KOSlIdIZ1B6PiMZI xQ== Received: from sc-exch03.marvell.com ([199.233.58.183]) by mx0a-0016f401.pphosted.com with ESMTP id 2yu8pqmrcb-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:36:16 -0700 Received: from DC5-EXCH02.marvell.com (10.69.176.39) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:15 -0700 Received: from SC-EXCH03.marvell.com (10.93.176.83) by DC5-EXCH02.marvell.com (10.69.176.39) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:14 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:36:13 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id 6D85E3F703F; Wed, 18 Mar 2020 14:36:11 -0700 (PDT) From: To: CC: , , , , , , , Date: Thu, 19 Mar 2020 03:05:39 +0530 Message-ID: <20200318213551.3489504-15-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 14/26] graph: add performance testcase X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Pavan Nikhilesh Add unit test framework to create and test performance of various graph models. example command to test: echo "graph_perf_autotest" | sudo ./build/app/test/dpdk-test -c 0x30 Signed-off-by: Pavan Nikhilesh --- app/test/Makefile | 1 + app/test/meson.build | 1 + app/test/test_graph_perf.c | 1057 ++++++++++++++++++++++++++++++++++++ 3 files changed, 1059 insertions(+) create mode 100644 app/test/test_graph_perf.c diff --git a/app/test/Makefile b/app/test/Makefile index 065582916..cd2801427 100644 --- a/app/test/Makefile +++ b/app/test/Makefile @@ -223,6 +223,7 @@ endif ifeq ($(CONFIG_RTE_LIBRTE_GRAPH), y) SRCS-y += test_graph.c +SRCS-y += test_graph_perf.c endif ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y) diff --git a/app/test/meson.build b/app/test/meson.build index 855403932..3fe155778 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -52,6 +52,7 @@ test_sources = files('commands.c', 'test_func_reentrancy.c', 'test_flow_classify.c', 'test_graph.c', + 'test_graph_perf.c', 'test_hash.c', 'test_hash_functions.c', 'test_hash_multiwriter.c', diff --git a/app/test/test_graph_perf.c b/app/test/test_graph_perf.c new file mode 100644 index 000000000..a629f1e35 --- /dev/null +++ b/app/test/test_graph_perf.c @@ -0,0 +1,1057 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test.h" + +#define TEST_GRAPH_PERF_MZ "graph_perf_data" +#define TEST_GRAPH_SRC_NAME "test_graph_perf_source" +#define TEST_GRAPH_SRC_BRST_ONE_NAME "test_graph_perf_source_one" +#define TEST_GRAPH_WRK_NAME "test_graph_perf_worker" +#define TEST_GRAPH_SNK_NAME "test_graph_perf_sink" + +#define SOURCES(map) RTE_DIM(map) +#define STAGES(map) RTE_DIM(map) +#define NODES_PER_STAGE(map) RTE_DIM(map[0]) +#define SINKS(map) RTE_DIM(map[0]) + +#define MAX_EDGES_PER_NODE 7 + +struct test_node_data { + uint8_t node_id; + uint8_t is_sink; + uint8_t next_nodes[MAX_EDGES_PER_NODE]; + uint8_t next_percentage[MAX_EDGES_PER_NODE]; +}; + +struct test_graph_perf { + uint16_t nb_nodes; + rte_graph_t graph_id; + struct test_node_data *node_data; +}; + +struct graph_lcore_data { + uint8_t done; + rte_graph_t graph_id; +}; + +static struct test_node_data * +graph_get_node_data(struct test_graph_perf *graph_data, rte_node_t id) +{ + struct test_node_data *node_data = NULL; + int i; + + for (i = 0; i < graph_data->nb_nodes; i++) + if (graph_data->node_data[i].node_id == id) { + node_data = &graph_data->node_data[i]; + break; + } + + return node_data; +} + +static int +test_node_ctx_init(const struct rte_graph *graph, struct rte_node *node) +{ + struct test_graph_perf *graph_data; + struct test_node_data *node_data; + const struct rte_memzone *mz; + rte_node_t nid = node->id; + rte_edge_t edge = 0; + int i; + + RTE_SET_USED(graph); + + mz = rte_memzone_lookup(TEST_GRAPH_PERF_MZ); + graph_data = mz->addr; + node_data = graph_get_node_data(graph_data, nid); + node->ctx[0] = node->nb_edges; + for (i = 0; i < node->nb_edges && !node_data->is_sink; i++, edge++) { + node->ctx[i + 1] = edge; + node->ctx[i + 9] = node_data->next_percentage[i]; + } + + return 0; +} + +/* Source node function */ +static uint16_t +test_perf_node_worker_source(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + uint16_t count; + int i; + + RTE_SET_USED(objs); + RTE_SET_USED(nb_objs); + + /* Create a proportional stream for every next */ + for (i = 0; i < node->ctx[0]; i++) { + count = (node->ctx[i + 9] * RTE_GRAPH_BURST_SIZE) / 100; + rte_node_next_stream_get(graph, node, node->ctx[i + 1], count); + rte_node_next_stream_put(graph, node, node->ctx[i + 1], count); + } + + return RTE_GRAPH_BURST_SIZE; +} + +static struct rte_node_register test_graph_perf_source = { + .name = TEST_GRAPH_SRC_NAME, + .process = test_perf_node_worker_source, + .flags = RTE_NODE_SOURCE_F, + .init = test_node_ctx_init, +}; + +RTE_NODE_REGISTER(test_graph_perf_source); + +static uint16_t +test_perf_node_worker_source_burst_one(struct rte_graph *graph, + struct rte_node *node, void **objs, + uint16_t nb_objs) +{ + uint16_t count; + int i; + + RTE_SET_USED(objs); + RTE_SET_USED(nb_objs); + + /* Create a proportional stream for every next */ + for (i = 0; i < node->ctx[0]; i++) { + count = (node->ctx[i + 9]) / 100; + rte_node_next_stream_get(graph, node, node->ctx[i + 1], count); + rte_node_next_stream_put(graph, node, node->ctx[i + 1], count); + } + + return 1; +} + +static struct rte_node_register test_graph_perf_source_burst_one = { + .name = TEST_GRAPH_SRC_BRST_ONE_NAME, + .process = test_perf_node_worker_source_burst_one, + .flags = RTE_NODE_SOURCE_F, + .init = test_node_ctx_init, +}; + +RTE_NODE_REGISTER(test_graph_perf_source_burst_one); + +/* Worker node function */ +static uint16_t +test_perf_node_worker(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + uint16_t next = 0; + uint16_t enq = 0; + uint16_t count; + int i; + + /* Move stream for single next node */ + if (node->ctx[0] == 1) { + rte_node_next_stream_move(graph, node, node->ctx[1]); + return nb_objs; + } + + /* Enqueue objects to next nodes proportionally */ + for (i = 0; i < node->ctx[0]; i++) { + next = node->ctx[i + 1]; + count = (node->ctx[i + 9] * nb_objs) / 100; + enq += count; + while (count) { + switch (count & (4 - 1)) { + case 0: + rte_node_enqueue_x4(graph, node, next, objs[0], + objs[1], objs[2], objs[3]); + objs += 4; + count -= 4; + break; + case 1: + rte_node_enqueue_x1(graph, node, next, objs[0]); + objs += 1; + count -= 1; + break; + case 2: + rte_node_enqueue_x2(graph, node, next, objs[0], + objs[1]); + objs += 2; + count -= 2; + break; + case 3: + rte_node_enqueue_x2(graph, node, next, objs[0], + objs[1]); + rte_node_enqueue_x1(graph, node, next, objs[0]); + objs += 3; + count -= 3; + break; + } + } + } + + if (enq != nb_objs) + rte_node_enqueue(graph, node, next, objs, nb_objs - enq); + + return nb_objs; +} + +static struct rte_node_register test_graph_perf_worker = { + .name = TEST_GRAPH_WRK_NAME, + .process = test_perf_node_worker, + .init = test_node_ctx_init, +}; + +RTE_NODE_REGISTER(test_graph_perf_worker); + +/* Last node in graph a.k.a sink node */ +static uint16_t +test_perf_node_sink(struct rte_graph *graph, struct rte_node *node, void **objs, + uint16_t nb_objs) +{ + RTE_SET_USED(graph); + RTE_SET_USED(node); + RTE_SET_USED(objs); + RTE_SET_USED(nb_objs); + + return nb_objs; +} + +static struct rte_node_register test_graph_perf_sink = { + .name = TEST_GRAPH_SNK_NAME, + .process = test_perf_node_sink, + .init = test_node_ctx_init, +}; + +RTE_NODE_REGISTER(test_graph_perf_sink); + +static int +graph_perf_setup(void) +{ + if (rte_lcore_count() < 2) { + printf("Test requires at least 2 lcores\n"); + return TEST_SKIPPED; + } + + return 0; +} + +static void +graph_perf_teardown(void) +{ +} + +static inline rte_node_t +graph_node_get(const char *pname, char *nname) +{ + rte_node_t pnode_id = rte_node_from_name(pname); + char lookup_name[RTE_NODE_NAMESIZE]; + rte_node_t node_id; + + snprintf(lookup_name, RTE_NODE_NAMESIZE, "%s-%s", pname, nname); + node_id = rte_node_from_name(lookup_name); + + if (node_id != RTE_NODE_ID_INVALID) { + if (rte_node_edge_count(node_id)) + rte_node_edge_shrink(node_id, 0); + return node_id; + } + + return rte_node_clone(pnode_id, nname); +} + +static uint16_t +graph_node_count_edges(uint32_t stage, uint16_t node, uint16_t nodes_per_stage, + uint8_t edge_map[][nodes_per_stage][nodes_per_stage], + char *ename[], struct test_node_data *node_data, + rte_node_t **node_map) +{ + uint8_t total_percent = 0; + uint16_t edges = 0; + int i; + + for (i = 0; i < nodes_per_stage && edges < MAX_EDGES_PER_NODE; i++) { + if (edge_map[stage + 1][i][node]) { + ename[edges] = malloc(sizeof(char) * RTE_NODE_NAMESIZE); + snprintf(ename[edges], RTE_NODE_NAMESIZE, "%s", + rte_node_id_to_name(node_map[stage + 1][i])); + node_data->next_nodes[edges] = node_map[stage + 1][i]; + node_data->next_percentage[edges] = + edge_map[stage + 1][i][node]; + edges++; + total_percent += edge_map[stage + 1][i][node]; + } + } + + if (edges >= MAX_EDGES_PER_NODE || (edges && total_percent != 100)) { + for (i = 0; i < edges; i++) + free(ename[i]); + return RTE_EDGE_ID_INVALID; + } + + return edges; +} + +static int +graph_init(const char *gname, uint8_t nb_srcs, uint8_t nb_sinks, + uint32_t stages, uint16_t nodes_per_stage, + uint8_t src_map[][nodes_per_stage], uint8_t snk_map[][nb_sinks], + uint8_t edge_map[][nodes_per_stage][nodes_per_stage], + uint8_t burst_one) +{ + struct test_graph_perf *graph_data; + char nname[RTE_NODE_NAMESIZE / 2]; + struct test_node_data *node_data; + char *ename[nodes_per_stage]; + struct rte_graph_param gconf; + const struct rte_memzone *mz; + uint8_t total_percent = 0; + rte_node_t *src_nodes; + rte_node_t *snk_nodes; + rte_node_t **node_map; + char **node_patterns; + rte_graph_t graph_id; + rte_edge_t edges; + rte_edge_t count; + uint32_t i, j, k; + + mz = rte_memzone_reserve(TEST_GRAPH_PERF_MZ, + sizeof(struct test_graph_perf), 0, 0); + if (mz == NULL) { + printf("Failed to allocate graph common memory\n"); + return -ENOMEM; + } + + graph_data = mz->addr; + graph_data->nb_nodes = 0; + graph_data->node_data = + malloc(sizeof(struct test_node_data) * + (nb_srcs + nb_sinks + stages * nodes_per_stage)); + if (graph_data->node_data == NULL) { + printf("Failed to reserve memzone for graph data\n"); + goto memzone_free; + } + + node_patterns = malloc(sizeof(char *) * + (nb_srcs + nb_sinks + stages * nodes_per_stage)); + if (node_patterns == NULL) { + printf("Failed to reserve memory for node patterns\n"); + goto data_free; + } + + src_nodes = malloc(sizeof(rte_node_t) * nb_srcs); + if (src_nodes == NULL) { + printf("Failed to reserve memory for src nodes\n"); + goto pattern_free; + } + + snk_nodes = malloc(sizeof(rte_node_t) * nb_sinks); + if (snk_nodes == NULL) { + printf("Failed to reserve memory for snk nodes\n"); + goto src_free; + } + + node_map = malloc(sizeof(rte_node_t *) * stages + + sizeof(rte_node_t) * nodes_per_stage * stages); + if (node_map == NULL) { + printf("Failed to reserve memory for node map\n"); + goto snk_free; + } + + /* Setup the Graph */ + for (i = 0; i < stages; i++) { + node_map[i] = + (rte_node_t *)(node_map + stages) + nodes_per_stage * i; + for (j = 0; j < nodes_per_stage; j++) { + total_percent = 0; + for (k = 0; k < nodes_per_stage; k++) + total_percent += edge_map[i][j][k]; + if (!total_percent) + continue; + node_patterns[graph_data->nb_nodes] = + malloc(RTE_NODE_NAMESIZE); + if (node_patterns[graph_data->nb_nodes] == NULL) { + printf("Failed to create memory for pattern\n"); + goto pattern_name_free; + } + + /* Clone a worker node */ + snprintf(nname, sizeof(nname), "%d-%d", i, j); + node_map[i][j] = + graph_node_get(TEST_GRAPH_WRK_NAME, nname); + if (node_map[i][j] == RTE_NODE_ID_INVALID) { + printf("Failed to create node[%s]\n", nname); + graph_data->nb_nodes++; + goto pattern_name_free; + } + snprintf(node_patterns[graph_data->nb_nodes], + RTE_NODE_NAMESIZE, "%s", + rte_node_id_to_name(node_map[i][j])); + node_data = + &graph_data->node_data[graph_data->nb_nodes]; + node_data->node_id = node_map[i][j]; + node_data->is_sink = false; + graph_data->nb_nodes++; + } + } + + for (i = 0; i < stages - 1; i++) { + for (j = 0; j < nodes_per_stage; j++) { + /* Count edges i.e connections of worker node to next */ + node_data = + graph_get_node_data(graph_data, node_map[i][j]); + edges = graph_node_count_edges(i, j, nodes_per_stage, + edge_map, ename, + node_data, node_map); + if (edges == RTE_EDGE_ID_INVALID) { + printf("Invalid edge configuration\n"); + goto pattern_name_free; + } + if (!edges) + continue; + + /* Connect a node in stage 'i' to nodes + * in stage 'i + 1' with edges. + */ + count = rte_node_edge_update( + node_map[i][j], 0, + (const char **)(uintptr_t)ename, edges); + for (k = 0; k < edges; k++) + free(ename[k]); + if (count != edges) { + printf("Couldn't add edges %d %d\n", edges, + count); + goto pattern_name_free; + } + } + } + + /* Setup Source nodes */ + for (i = 0; i < nb_srcs; i++) { + edges = 0; + total_percent = 0; + node_patterns[graph_data->nb_nodes] = malloc(RTE_NODE_NAMESIZE); + if (node_patterns[graph_data->nb_nodes] == NULL) { + printf("Failed to create memory for pattern\n"); + goto pattern_name_free; + } + /* Clone a source node */ + snprintf(nname, sizeof(nname), "%d", i); + src_nodes[i] = + graph_node_get(burst_one ? TEST_GRAPH_SRC_BRST_ONE_NAME + : TEST_GRAPH_SRC_NAME, + nname); + if (src_nodes[i] == RTE_NODE_ID_INVALID) { + printf("Failed to create node[%s]\n", nname); + graph_data->nb_nodes++; + goto pattern_name_free; + } + snprintf(node_patterns[graph_data->nb_nodes], RTE_NODE_NAMESIZE, + "%s", rte_node_id_to_name(src_nodes[i])); + node_data = &graph_data->node_data[graph_data->nb_nodes]; + node_data->node_id = src_nodes[i]; + node_data->is_sink = false; + graph_data->nb_nodes++; + + /* Prepare next node list to connect to */ + for (j = 0; j < nodes_per_stage; j++) { + if (!src_map[i][j]) + continue; + ename[edges] = malloc(sizeof(char) * RTE_NODE_NAMESIZE); + snprintf(ename[edges], RTE_NODE_NAMESIZE, "%s", + rte_node_id_to_name(node_map[0][j])); + node_data->next_nodes[edges] = node_map[0][j]; + node_data->next_percentage[edges] = src_map[i][j]; + edges++; + total_percent += src_map[i][j]; + } + + if (!edges) + continue; + if (edges >= MAX_EDGES_PER_NODE || total_percent != 100) { + printf("Invalid edge configuration\n"); + for (j = 0; j < edges; j++) + free(ename[j]); + goto pattern_name_free; + } + + /* Connect to list of next nodes using edges */ + count = rte_node_edge_update(src_nodes[i], 0, + (const char **)(uintptr_t)ename, + edges); + for (k = 0; k < edges; k++) + free(ename[k]); + if (count != edges) { + printf("Couldn't add edges %d %d\n", edges, count); + goto pattern_name_free; + } + } + + /* Setup Sink nodes */ + for (i = 0; i < nb_sinks; i++) { + node_patterns[graph_data->nb_nodes] = malloc(RTE_NODE_NAMESIZE); + if (node_patterns[graph_data->nb_nodes] == NULL) { + printf("Failed to create memory for pattern\n"); + goto pattern_name_free; + } + + /* Clone a sink node */ + snprintf(nname, sizeof(nname), "%d", i); + snk_nodes[i] = graph_node_get(TEST_GRAPH_SNK_NAME, nname); + if (snk_nodes[i] == RTE_NODE_ID_INVALID) { + printf("Failed to create node[%s]\n", nname); + graph_data->nb_nodes++; + goto pattern_name_free; + } + snprintf(node_patterns[graph_data->nb_nodes], RTE_NODE_NAMESIZE, + "%s", rte_node_id_to_name(snk_nodes[i])); + node_data = &graph_data->node_data[graph_data->nb_nodes]; + node_data->node_id = snk_nodes[i]; + node_data->is_sink = true; + graph_data->nb_nodes++; + } + + /* Connect last stage worker nodes to sink nodes */ + for (i = 0; i < nodes_per_stage; i++) { + edges = 0; + total_percent = 0; + node_data = graph_get_node_data(graph_data, + node_map[stages - 1][i]); + /* Prepare list of sink nodes to connect to */ + for (j = 0; j < nb_sinks; j++) { + if (!snk_map[i][j]) + continue; + ename[edges] = malloc(sizeof(char) * RTE_NODE_NAMESIZE); + snprintf(ename[edges], RTE_NODE_NAMESIZE, "%s", + rte_node_id_to_name(snk_nodes[j])); + node_data->next_nodes[edges] = snk_nodes[j]; + node_data->next_percentage[edges] = snk_map[i][j]; + edges++; + total_percent += snk_map[i][j]; + } + if (!edges) + continue; + if (edges >= MAX_EDGES_PER_NODE || total_percent != 100) { + printf("Invalid edge configuration\n"); + for (j = 0; j < edges; j++) + free(ename[i]); + goto pattern_name_free; + } + + /* Connect a worker node to a list of sink nodes */ + count = rte_node_edge_update(node_map[stages - 1][i], 0, + (const char **)(uintptr_t)ename, + edges); + for (k = 0; k < edges; k++) + free(ename[k]); + if (count != edges) { + printf("Couldn't add edges %d %d\n", edges, count); + goto pattern_name_free; + } + } + + /* Create a Graph */ + gconf.socket_id = SOCKET_ID_ANY; + gconf.nb_node_patterns = graph_data->nb_nodes; + gconf.node_patterns = (const char **)(uintptr_t)node_patterns; + + graph_id = rte_graph_create(gname, &gconf); + if (graph_id == RTE_GRAPH_ID_INVALID) { + printf("Graph creation failed with error = %d\n", rte_errno); + goto pattern_name_free; + } + graph_data->graph_id = graph_id; + + for (i = 0; i < graph_data->nb_nodes; i++) + free(node_patterns[i]); + free(snk_nodes); + free(src_nodes); + free(node_patterns); + return 0; + +pattern_name_free: + for (i = 0; i < graph_data->nb_nodes; i++) + free(node_patterns[i]); +snk_free: + free(snk_nodes); +src_free: + free(src_nodes); +pattern_free: + free(node_patterns); +data_free: + free(graph_data->node_data); +memzone_free: + rte_memzone_free(mz); + return -ENOMEM; +} + +/* Worker thread function */ +static int +_graph_perf_wrapper(void *args) +{ + struct graph_lcore_data *data = args; + struct rte_graph *graph; + + /* Lookup graph */ + graph = rte_graph_lookup(rte_graph_id_to_name(data->graph_id)); + + /* Graph walk until done */ + while (!data->done) + rte_graph_walk(graph); + + return 0; +} + +static int +measure_perf_get(rte_graph_t graph_id) +{ + const char *pattern = rte_graph_id_to_name(graph_id); + uint32_t lcore_id = rte_get_next_lcore(-1, 1, 0); + struct rte_graph_cluster_stats_param param; + struct rte_graph_cluster_stats *stats; + struct graph_lcore_data *data; + + data = rte_zmalloc("Graph_perf", sizeof(struct graph_lcore_data), + RTE_CACHE_LINE_SIZE); + data->graph_id = graph_id; + data->done = 0; + + /* Run graph worker thread function */ + rte_eal_remote_launch(_graph_perf_wrapper, data, lcore_id); + + /* Collect stats for few msecs */ + if (rte_graph_has_stats_feature()) { + memset(¶m, 0, sizeof(param)); + param.f = stdout; + param.socket_id = SOCKET_ID_ANY; + param.graph_patterns = &pattern; + param.nb_graph_patterns = 1; + + stats = rte_graph_cluster_stats_create(¶m); + if (stats == NULL) { + printf("Failed to create stats\n"); + return -ENOMEM; + } + + rte_delay_ms(3E2); + rte_graph_cluster_stats_get(stats, true); + rte_delay_ms(1E3); + rte_graph_cluster_stats_get(stats, false); + rte_graph_cluster_stats_destroy(stats); + } else + rte_delay_ms(1E3); + + data->done = 1; + rte_eal_wait_lcore(lcore_id); + + return 0; +} + +static inline void +graph_fini(void) +{ + const struct rte_memzone *mz = rte_memzone_lookup(TEST_GRAPH_PERF_MZ); + struct test_graph_perf *graph_data; + + if (mz == NULL) + return; + graph_data = mz->addr; + + rte_graph_destroy(rte_graph_id_to_name(graph_data->graph_id)); + free(graph_data->node_data); + rte_memzone_free(rte_memzone_lookup(TEST_GRAPH_PERF_MZ)); +} + +static int +measure_perf(void) +{ + const struct rte_memzone *mz; + struct test_graph_perf *graph_data; + + mz = rte_memzone_lookup(TEST_GRAPH_PERF_MZ); + graph_data = mz->addr; + + return measure_perf_get(graph_data->graph_id); +} + +static inline int +graph_hr_4s_1n_1src_1snk(void) +{ + return measure_perf(); +} + +static inline int +graph_hr_4s_1n_1src_1snk_brst_one(void) +{ + return measure_perf(); +} + +static inline int +graph_hr_4s_1n_2src_1snk(void) +{ + return measure_perf(); +} + +static inline int +graph_hr_4s_1n_1src_2snk(void) +{ + return measure_perf(); +} + +static inline int +graph_tree_4s_4n_1src_4snk(void) +{ + return measure_perf(); +} + +static inline int +graph_reverse_tree_3s_4n_1src_1snk(void) +{ + return measure_perf(); +} + +static inline int +graph_parallel_tree_5s_4n_4src_4snk(void) +{ + return measure_perf(); +} + +/* Graph Topology + * nodes per stage: 1 + * stages: 4 + * src: 1 + * sink: 1 + */ +static inline int +graph_init_hr(void) +{ + uint8_t edge_map[][1][1] = { + { {100} }, + { {100} }, + { {100} }, + { {100} }, + }; + uint8_t src_map[][1] = { {100} }; + uint8_t snk_map[][1] = { {100} }; + + return graph_init("graph_hr", SOURCES(src_map), SINKS(snk_map), + STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map, + snk_map, edge_map, 0); +} + +/* Graph Topology + * nodes per stage: 1 + * stages: 4 + * src: 1 + * sink: 1 + */ +static inline int +graph_init_hr_brst_one(void) +{ + uint8_t edge_map[][1][1] = { + { {100} }, + { {100} }, + { {100} }, + { {100} }, + }; + uint8_t src_map[][1] = { {100} }; + uint8_t snk_map[][1] = { {100} }; + + return graph_init("graph_hr", SOURCES(src_map), SINKS(snk_map), + STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map, + snk_map, edge_map, 1); +} + +/* Graph Topology + * nodes per stage: 1 + * stages: 4 + * src: 2 + * sink: 1 + */ +static inline int +graph_init_hr_multi_src(void) +{ + uint8_t edge_map[][1][1] = { + { {100} }, + { {100} }, + { {100} }, + { {100} }, + }; + uint8_t src_map[][1] = { + {100}, {100} + }; + uint8_t snk_map[][1] = { {100} }; + + return graph_init("graph_hr", SOURCES(src_map), SINKS(snk_map), + STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map, + snk_map, edge_map, 0); +} + +/* Graph Topology + * nodes per stage: 1 + * stages: 4 + * src: 1 + * sink: 2 + */ +static inline int +graph_init_hr_multi_snk(void) +{ + uint8_t edge_map[][1][1] = { + { {100} }, + { {100} }, + { {100} }, + { {100} }, + }; + uint8_t src_map[][1] = { {100} }; + uint8_t snk_map[][2] = { {50, 50} }; + + return graph_init("graph_hr", SOURCES(src_map), SINKS(snk_map), + STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map, + snk_map, edge_map, 0); +} + +/* Graph Topology + * nodes per stage: 4 + * stages: 4 + * src: 1 + * sink: 4 + */ +static inline int +graph_init_tree(void) +{ + uint8_t edge_map[][4][4] = { + { + {100, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + }, + { + {50, 0, 0, 0}, + {50, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + }, + { + {33, 33, 0, 0}, + {34, 34, 0, 0}, + {33, 33, 0, 0}, + {0, 0, 0, 0} + }, + { + {25, 25, 25, 0}, + {25, 25, 25, 0}, + {25, 25, 25, 0}, + {25, 25, 25, 0} + } + }; + uint8_t src_map[][4] = { {100, 0, 0, 0} }; + uint8_t snk_map[][4] = { + {100, 0, 0, 0}, + {0, 100, 0, 0}, + {0, 0, 100, 0}, + {0, 0, 0, 100} + }; + + return graph_init("graph_full_split", SOURCES(src_map), SINKS(snk_map), + STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map, + snk_map, edge_map, 0); +} + +/* Graph Topology + * nodes per stage: 4 + * stages: 3 + * src: 1 + * sink: 1 + */ +static inline int +graph_init_reverse_tree(void) +{ + uint8_t edge_map[][4][4] = { + { + {25, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25} + }, + { + {33, 33, 33, 33}, + {33, 33, 33, 33}, + {34, 34, 34, 34}, + {0, 0, 0, 0} + }, + { + {50, 50, 50, 0}, + {50, 50, 50, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + }, + }; + uint8_t src_map[][4] = { {25, 25, 25, 25} }; + uint8_t snk_map[][1] = { {100}, {100}, {0}, {0} }; + + return graph_init("graph_full_split", SOURCES(src_map), SINKS(snk_map), + STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map, + snk_map, edge_map, 0); +} + +/* Graph Topology + * nodes per stage: 4 + * stages: 5 + * src: 4 + * sink: 4 + */ +static inline int +graph_init_parallel_tree(void) +{ + uint8_t edge_map[][4][4] = { + { + {100, 0, 0, 0}, + {0, 100, 0, 0}, + {0, 0, 100, 0}, + {0, 0, 0, 100} + }, + { + {100, 0, 0, 0}, + {0, 100, 0, 0}, + {0, 0, 100, 0}, + {0, 0, 0, 100} + }, + { + {100, 0, 0, 0}, + {0, 100, 0, 0}, + {0, 0, 100, 0}, + {0, 0, 0, 100} + }, + { + {100, 0, 0, 0}, + {0, 100, 0, 0}, + {0, 0, 100, 0}, + {0, 0, 0, 100} + }, + { + {100, 0, 0, 0}, + {0, 100, 0, 0}, + {0, 0, 100, 0}, + {0, 0, 0, 100} + }, + }; + uint8_t src_map[][4] = { + {100, 0, 0, 0}, + {0, 100, 0, 0}, + {0, 0, 100, 0}, + {0, 0, 0, 100} + }; + uint8_t snk_map[][4] = { + {100, 0, 0, 0}, + {0, 100, 0, 0}, + {0, 0, 100, 0}, + {0, 0, 0, 100} + }; + + return graph_init("graph_parallel", SOURCES(src_map), SINKS(snk_map), + STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map, + snk_map, edge_map, 0); +} + +/** Graph Creation cheat sheet + * edge_map -> dictates graph flow from worker stage 0 to worker stage n-1. + * src_map -> dictates source nodes enqueue percentage to worker stage 0. + * snk_map -> dictates stage n-1 enqueue percentage to sink. + * + * Layout: + * edge_map[][][] + * src_map[][] + * snk_map[][] + * + * The last array dictates the percentage of received objs to enqueue to next + * stage. + * + * Note: edge_map[][0][] will always be unused as it will receive from source + * + * Example: + * Graph: + * http://bit.ly/2PqbqOy + * Each stage(n) connects to all nodes in the next stage in decreasing + * order. + * Since we can't resize the edge_map dynamically we get away by creating + * dummy nodes and assigning 0 percentages. + * Max nodes across all stages = 4 + * stages = 3 + * nb_src = 1 + * nb_snk = 1 + * // Stages + * edge_map[][4][4] = { + * // Nodes per stage + * { + * {25, 25, 25, 25}, + * {25, 25, 25, 25}, + * {25, 25, 25, 25}, + * {25, 25, 25, 25} + * }, // This will be unused. + * { + * // Nodes enabled in current stage + prev stage enq % + * {33, 33, 33, 33}, + * {33, 33, 33, 33}, + * {34, 34, 34, 34}, + * {0, 0, 0, 0} + * }, + * { + * {50, 50, 50, 0}, + * {50, 50, 50, 0}, + * {0, 0, 0, 0}, + * {0, 0, 0, 0} + * }, + * }; + * Above, each stage tells how much it should receive from previous except + * from stage_0. + * + * src_map[][4] = { {25, 25, 25, 25} }; + * Here, we tell each source the % it has to send to stage_0 nodes. In + * case we want 2 source node we can declare as + * src_map[][4] = { {25, 25, 25, 25}, {25, 25, 25, 25} }; + * + * snk_map[][1] = { {100}, {100}, {0}, {0} } + * Here, we tell stage - 1 nodes how much to enqueue to sink_0. + * If we have 2 sinks we can do as follows + * snk_map[][2] = { {50, 50}, {50, 50}, {0, 0}, {0, 0} } + */ + +static struct unit_test_suite graph_perf_testsuite = { + .suite_name = "Graph library performance test suite", + .setup = graph_perf_setup, + .teardown = graph_perf_teardown, + .unit_test_cases = { + TEST_CASE_ST(graph_init_hr, graph_fini, + graph_hr_4s_1n_1src_1snk), + TEST_CASE_ST(graph_init_hr_brst_one, graph_fini, + graph_hr_4s_1n_1src_1snk_brst_one), + TEST_CASE_ST(graph_init_hr_multi_src, graph_fini, + graph_hr_4s_1n_2src_1snk), + TEST_CASE_ST(graph_init_hr_multi_snk, graph_fini, + graph_hr_4s_1n_1src_2snk), + TEST_CASE_ST(graph_init_tree, graph_fini, + graph_tree_4s_4n_1src_4snk), + TEST_CASE_ST(graph_init_reverse_tree, graph_fini, + graph_reverse_tree_3s_4n_1src_1snk), + TEST_CASE_ST(graph_init_parallel_tree, graph_fini, + graph_parallel_tree_5s_4n_4src_4snk), + TEST_CASES_END(), /**< NULL terminate unit test array */ + }, +}; + +static int +test_graph_perf_func(void) +{ + return unit_test_suite_runner(&graph_perf_testsuite); +} + +REGISTER_TEST_COMMAND(graph_perf_autotest, test_graph_perf_func); From patchwork Wed Mar 18 21:35:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66909 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id E7227A057D; Wed, 18 Mar 2020 22:38:07 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 02F2B1C126; Wed, 18 Mar 2020 22:36:24 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by dpdk.org (Postfix) with ESMTP id 1D5F61C118 for ; Wed, 18 Mar 2020 22:36:21 +0100 (CET) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILUsFR003319; Wed, 18 Mar 2020 14:36:20 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=3CNOVBBLK73W/OzwOZflpCNsmAzj7S0ytdVggEVXZJo=; b=YV3d42q+megRO7eDvpR6wj+UCWpiX9X5sObSzMWg3nyGWHJnFs+/rGSQFzZBf77QuHQ7 ibGn6bPfzO62l6POE8lQ+KrQXSohaqrVdWUt9QKxRKGjLXiyL5UYxoJl4lFCzyMkZwbT OQUWzls/+qZOdyTA95GQ7Rfv1TuRXmrvgxg8w/rSV7HJEWSsylmMQz69WNn8eWN+j/Un aD/X0Yl15vDtktZhN1l6fRpDR332BmzqRBRvWs01lpM1SZdLUXs+9TuxQd4YHt9jQY4u bPCEiFfSYPY1ygjKqTBbfk4q9aHNobs0nK+2wy/Oq1fkSwDuPUL3TLzRl403reaB8BjT bQ== Received: from sc-exch01.marvell.com ([199.233.58.181]) by mx0a-0016f401.pphosted.com with ESMTP id 2yu8pqmrcj-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:36:19 -0700 Received: from SC-EXCH01.marvell.com (10.93.176.81) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:18 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:36:18 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id 625043F704A; Wed, 18 Mar 2020 14:36:15 -0700 (PDT) From: To: Thomas Monjalon , John McNamara , Marko Kovacevic , Nithin Dabilpuram , Pavan Nikhilesh , Bruce Richardson CC: , , , , Date: Thu, 19 Mar 2020 03:05:40 +0530 Message-ID: <20200318213551.3489504-16-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 15/26] node: add log infra and null node X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Nithin Dabilpuram Add log infra for node specific logging. Also, add null rte_node that just ignores all the objects directed to it. Signed-off-by: Nithin Dabilpuram Signed-off-by: Pavan Nikhilesh Signed-off-by: Kiran Kumar K --- MAINTAINERS | 5 +++++ config/common_base | 5 +++++ doc/api/doxy-api.conf.in | 1 + lib/Makefile | 3 +++ lib/librte_node/Makefile | 20 ++++++++++++++++++++ lib/librte_node/log.c | 14 ++++++++++++++ lib/librte_node/meson.build | 6 ++++++ lib/librte_node/node_private.h | 22 ++++++++++++++++++++++ lib/librte_node/null.c | 23 +++++++++++++++++++++++ lib/librte_node/rte_node_version.map | 6 ++++++ lib/meson.build | 5 ++++- meson.build | 1 + mk/rte.app.mk | 1 + 13 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 lib/librte_node/Makefile create mode 100644 lib/librte_node/log.c create mode 100644 lib/librte_node/meson.build create mode 100644 lib/librte_node/node_private.h create mode 100644 lib/librte_node/null.c create mode 100644 lib/librte_node/rte_node_version.map diff --git a/MAINTAINERS b/MAINTAINERS index 32d0ea032..3959ed19a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1473,6 +1473,11 @@ M: Jerin Jacob M: Kiran Kumar K F: lib/librte_graph/ +Nodes - EXPERIMENTAL +M: Nithin Dabilpuram +M: Pavan Nikhilesh +F: lib/librte_node/ + Test Applications ----------------- diff --git a/config/common_base b/config/common_base index 04a96aef5..442949ff1 100644 --- a/config/common_base +++ b/config/common_base @@ -1082,6 +1082,11 @@ CONFIG_RTE_LIBRTE_GRAPH=y CONFIG_RTE_GRAPH_BURST_SIZE=256 CONFIG_RTE_LIBRTE_GRAPH_STATS=y +# +# Compile librte_node +# +CONFIG_RTE_LIBRTE_NODE=y + # # Compile the test application # diff --git a/doc/api/doxy-api.conf.in b/doc/api/doxy-api.conf.in index 759a7213e..1d4f1a37d 100644 --- a/doc/api/doxy-api.conf.in +++ b/doc/api/doxy-api.conf.in @@ -49,6 +49,7 @@ INPUT = @TOPDIR@/doc/api/doxy-api-index.md \ @TOPDIR@/lib/librte_mempool \ @TOPDIR@/lib/librte_meter \ @TOPDIR@/lib/librte_metrics \ + @TOPDIR@/lib/librte_node \ @TOPDIR@/lib/librte_net \ @TOPDIR@/lib/librte_pci \ @TOPDIR@/lib/librte_pdump \ diff --git a/lib/Makefile b/lib/Makefile index 1f572b659..50d61a338 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -122,6 +122,9 @@ DEPDIRS-librte_rcu := librte_eal DIRS-$(CONFIG_RTE_LIBRTE_GRAPH) += librte_graph DEPDIRS-librte_graph := librte_eal +DIRS-$(CONFIG_RTE_LIBRTE_NODE) += librte_node +DEPDIRS-librte_node := librte_graph librte_lpm librte_ethdev librte_mbuf + ifeq ($(CONFIG_RTE_EXEC_ENV_LINUX),y) DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni endif diff --git a/lib/librte_node/Makefile b/lib/librte_node/Makefile new file mode 100644 index 000000000..5f9be6c2e --- /dev/null +++ b/lib/librte_node/Makefile @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(C) 2020 Marvell International Ltd. +# + +include $(RTE_SDK)/mk/rte.vars.mk + +# library name +LIB = librte_node.a + +CFLAGS += -O3 -DALLOW_EXPERIMENTAL_API +CFLAGS += $(WERROR_FLAGS) +LDLIBS += -lrte_eal -lrte_graph + +EXPORT_MAP := rte_node_version.map + +# all source are stored in SRCS-y +SRCS-$(CONFIG_RTE_LIBRTE_NODE) += null.c +SRCS-$(CONFIG_RTE_LIBRTE_NODE) += log.c + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/lib/librte_node/log.c b/lib/librte_node/log.c new file mode 100644 index 000000000..f035f91e8 --- /dev/null +++ b/lib/librte_node/log.c @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#include "node_private.h" + +int rte_node_logtype; + +RTE_INIT(rte_node_init_log) +{ + rte_node_logtype = rte_log_register("lib.node"); + if (rte_node_logtype >= 0) + rte_log_set_level(rte_node_logtype, RTE_LOG_INFO); +} diff --git a/lib/librte_node/meson.build b/lib/librte_node/meson.build new file mode 100644 index 000000000..655970614 --- /dev/null +++ b/lib/librte_node/meson.build @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(C) 2020 Marvell International Ltd. + +sources = files('null.c', 'log.c') +allow_experimental_apis = true +deps += ['graph'] diff --git a/lib/librte_node/node_private.h b/lib/librte_node/node_private.h new file mode 100644 index 000000000..f30902a94 --- /dev/null +++ b/lib/librte_node/node_private.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#ifndef __NODE_PRIVATE_H__ +#define __NODE_PRIVATE_H__ + +#include +#include + +extern int rte_node_logtype; +#define NODE_LOG(level, node_name, ...) \ + rte_log(RTE_LOG_##level, rte_node_logtype, \ + RTE_FMT("NODE %s: %s():%u " RTE_FMT_HEAD(__VA_ARGS__, ) "\n", \ + node_name, __func__, __LINE__, \ + RTE_FMT_TAIL(__VA_ARGS__, ))) + +#define node_err(node_name, ...) NODE_LOG(ERR, node_name, __VA_ARGS__) +#define node_info(node_name, ...) NODE_LOG(INFO, node_name, __VA_ARGS__) +#define node_dbg(node_name, ...) NODE_LOG(DEBUG, node_name, __VA_ARGS__) + +#endif /* __NODE_PRIVATE_H__ */ diff --git a/lib/librte_node/null.c b/lib/librte_node/null.c new file mode 100644 index 000000000..c7cd8b6df --- /dev/null +++ b/lib/librte_node/null.c @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#include + +static uint16_t +null(struct rte_graph *graph, struct rte_node *node, void **objs, + uint16_t nb_objs) +{ + RTE_SET_USED(node); + RTE_SET_USED(objs); + RTE_SET_USED(graph); + + return nb_objs; +} + +static struct rte_node_register null_node = { + .name = "null", + .process = null, +}; + +RTE_NODE_REGISTER(null_node); diff --git a/lib/librte_node/rte_node_version.map b/lib/librte_node/rte_node_version.map new file mode 100644 index 000000000..f87163bb9 --- /dev/null +++ b/lib/librte_node/rte_node_version.map @@ -0,0 +1,6 @@ +EXPERIMENTAL { + global: + + rte_node_logtype; + local: *; +}; diff --git a/lib/meson.build b/lib/meson.build index c43d86bb9..147129b0b 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -30,7 +30,7 @@ libraries = [ # add pkt framework libs which use other libs from above 'port', 'table', 'pipeline', # flow_classify lib depends on pkt framework table lib - 'flow_classify', 'bpf', 'graph', 'telemetry'] + 'flow_classify', 'bpf', 'graph', 'node', 'telemetry'] if is_windows libraries = ['kvargs','eal'] # only supported libraries for windows @@ -186,6 +186,9 @@ foreach l:libraries dpdk_libraries = [shared_lib] + dpdk_libraries dpdk_static_libraries = [static_lib] + dpdk_static_libraries + if libname == 'rte_node' + dpdk_graph_nodes = [static_lib] + endif endif # sources.length() > 0 set_variable('shared_rte_' + name, shared_dep) diff --git a/meson.build b/meson.build index b7ae9c8d9..811c96421 100644 --- a/meson.build +++ b/meson.build @@ -16,6 +16,7 @@ cc = meson.get_compiler('c') dpdk_conf = configuration_data() dpdk_libraries = [] dpdk_static_libraries = [] +dpdk_graph_nodes = [] dpdk_driver_classes = [] dpdk_drivers = [] dpdk_extra_ldflags = [] diff --git a/mk/rte.app.mk b/mk/rte.app.mk index b1195f09a..68d7806a4 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -99,6 +99,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder _LDLIBS-$(CONFIG_RTE_LIBRTE_SCHED) += -lrte_sched _LDLIBS-$(CONFIG_RTE_LIBRTE_RCU) += -lrte_rcu _LDLIBS-$(CONFIG_RTE_LIBRTE_GRAPH) += -lrte_graph +_LDLIBS-$(CONFIG_RTE_LIBRTE_NODE) += -lrte_node ifeq ($(CONFIG_RTE_EXEC_ENV_LINUX),y) _LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni From patchwork Wed Mar 18 21:35:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66910 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id CC961A057D; Wed, 18 Mar 2020 22:38:16 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 2F1C91C02A; Wed, 18 Mar 2020 22:36:27 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by dpdk.org (Postfix) with ESMTP id AA95D1C12C for ; Wed, 18 Mar 2020 22:36:25 +0100 (CET) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILVs89013171; Wed, 18 Mar 2020 14:36:23 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=xTk4PxK/Q9XDxGYK9PuT8hzON7sFfCYyLkv0DNsmQvQ=; b=P2zDrb+tJow5xpS6pAoVOmYySUVO5+7OvdVvjbC4B33Y4hoosahISK4V10ONBLI3gfGu fI+Z6GamTQlJytxzC/ATn0ZS0YopGKfrOVXSAulq0XbyLXV6RcmnwmXbegN83bMRID6/ xq5JlnFatVtr+iKxYcyNB7o+YbFnz5oo9H0Wkpu2IGCMoQbJaMhcfaixCYTpgFsObGyC XFNjLbF4Ba3wX4W8oq0qakxFAMVQm+o4ZrX2JY0O+zOhvG4YWurl4+/4ebn/wUs8gWSK VbE+A6cRCKd7hQMCSzZIfxbOhI/zjH57qoeHUNGnC58ZslgCsYMTYTv4NkSxCSPxk9Q4 sQ== Received: from sc-exch04.marvell.com ([199.233.58.184]) by mx0a-0016f401.pphosted.com with ESMTP id 2yu8pqmrcy-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:36:23 -0700 Received: from SC-EXCH03.marvell.com (10.93.176.83) by SC-EXCH04.marvell.com (10.93.176.84) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:22 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:36:22 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id CDF693F703F; Wed, 18 Mar 2020 14:36:19 -0700 (PDT) From: To: Nithin Dabilpuram , Pavan Nikhilesh CC: , , , , , Date: Thu, 19 Mar 2020 03:05:41 +0530 Message-ID: <20200318213551.3489504-17-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 16/26] node: add ethdev Rx node X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Nithin Dabilpuram Add source rte_node ethdev_rx process function and register it. This node is a source node that will be called periodically and when called, performs rte_eth_rx_burst() on a specific (port, queue) pair and enqueue them as stream of objects to next node. Signed-off-by: Nithin Dabilpuram Signed-off-by: Pavan Nikhilesh Signed-off-by: Kiran Kumar K --- lib/librte_node/Makefile | 3 +- lib/librte_node/ethdev_rx.c | 221 +++++++++++++++++++++++++++++++ lib/librte_node/ethdev_rx_priv.h | 81 +++++++++++ lib/librte_node/meson.build | 4 +- 4 files changed, 306 insertions(+), 3 deletions(-) create mode 100644 lib/librte_node/ethdev_rx.c create mode 100644 lib/librte_node/ethdev_rx_priv.h diff --git a/lib/librte_node/Makefile b/lib/librte_node/Makefile index 5f9be6c2e..5a5f589ba 100644 --- a/lib/librte_node/Makefile +++ b/lib/librte_node/Makefile @@ -9,12 +9,13 @@ LIB = librte_node.a CFLAGS += -O3 -DALLOW_EXPERIMENTAL_API CFLAGS += $(WERROR_FLAGS) -LDLIBS += -lrte_eal -lrte_graph +LDLIBS += -lrte_eal -lrte_graph -lrte_ethdev EXPORT_MAP := rte_node_version.map # all source are stored in SRCS-y SRCS-$(CONFIG_RTE_LIBRTE_NODE) += null.c SRCS-$(CONFIG_RTE_LIBRTE_NODE) += log.c +SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ethdev_rx.c include $(RTE_SDK)/mk/rte.lib.mk diff --git a/lib/librte_node/ethdev_rx.c b/lib/librte_node/ethdev_rx.c new file mode 100644 index 000000000..5cc736598 --- /dev/null +++ b/lib/librte_node/ethdev_rx.c @@ -0,0 +1,221 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#include +#include +#include +#include +#include +#include + +#include "ethdev_rx_priv.h" +#include "node_private.h" + +static struct ethdev_rx_node_main ethdev_rx_main; + +static __rte_always_inline uint16_t +ethdev_rx_node_process_inline(struct rte_graph *graph, struct rte_node *node, + uint16_t port, uint16_t queue) +{ + uint16_t count, next_index = ETHDEV_RX_NEXT_IP4_LOOKUP; + + /* Get pkts from port */ + count = rte_eth_rx_burst(port, queue, (struct rte_mbuf **)node->objs, + RTE_GRAPH_BURST_SIZE); + + if (!count) + return 0; + node->idx = count; + /* Enqueue to next node */ + rte_node_next_stream_move(graph, node, next_index); + + return count; +} + +static __rte_always_inline uint16_t +ethdev_rx_node_process(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t cnt) +{ + ethdev_rx_node_ctx_t *ctx = (ethdev_rx_node_ctx_t *)node->ctx; + uint16_t n_pkts = 0; + + RTE_SET_USED(objs); + RTE_SET_USED(cnt); + + n_pkts = ethdev_rx_node_process_inline(graph, node, ctx->port_id, + ctx->queue_id); + return n_pkts; +} + +static inline uint32_t +l3_ptype(uint16_t etype, uint32_t ptype) +{ + ptype = ptype & ~RTE_PTYPE_L3_MASK; + if (etype == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) + ptype |= RTE_PTYPE_L3_IPV4_EXT_UNKNOWN; + else if (etype == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) + ptype |= RTE_PTYPE_L3_IPV6_EXT_UNKNOWN; + return ptype; +} + +/* Callback for soft ptype parsing */ +static uint16_t +eth_pkt_parse_cb(uint16_t port, uint16_t queue, struct rte_mbuf **mbufs, + uint16_t nb_pkts, uint16_t max_pkts, void *user_param) +{ + struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3; + struct rte_ether_hdr *eth_hdr; + uint16_t etype, n_left; + struct rte_mbuf **pkts; + + RTE_SET_USED(port); + RTE_SET_USED(queue); + RTE_SET_USED(max_pkts); + RTE_SET_USED(user_param); + + pkts = mbufs; + n_left = nb_pkts; + while (n_left >= 12) { + + /* Prefetch next-next mbufs */ + rte_prefetch0(pkts[8]); + rte_prefetch0(pkts[9]); + rte_prefetch0(pkts[10]); + rte_prefetch0(pkts[11]); + + /* Prefetch next mbuf data */ + rte_prefetch0( + rte_pktmbuf_mtod(pkts[4], struct rte_ether_hdr *)); + rte_prefetch0( + rte_pktmbuf_mtod(pkts[5], struct rte_ether_hdr *)); + rte_prefetch0( + rte_pktmbuf_mtod(pkts[6], struct rte_ether_hdr *)); + rte_prefetch0( + rte_pktmbuf_mtod(pkts[7], struct rte_ether_hdr *)); + + mbuf0 = pkts[0]; + mbuf1 = pkts[1]; + mbuf2 = pkts[2]; + mbuf3 = pkts[3]; + pkts += 4; + n_left -= 4; + + /* Extract ptype of mbuf0 */ + eth_hdr = rte_pktmbuf_mtod(mbuf0, struct rte_ether_hdr *); + etype = eth_hdr->ether_type; + mbuf0->packet_type = l3_ptype(etype, 0); + + /* Extract ptype of mbuf1 */ + eth_hdr = rte_pktmbuf_mtod(mbuf1, struct rte_ether_hdr *); + etype = eth_hdr->ether_type; + mbuf1->packet_type = l3_ptype(etype, 0); + + /* Extract ptype of mbuf2 */ + eth_hdr = rte_pktmbuf_mtod(mbuf2, struct rte_ether_hdr *); + etype = eth_hdr->ether_type; + mbuf2->packet_type = l3_ptype(etype, 0); + + /* Extract ptype of mbuf3 */ + eth_hdr = rte_pktmbuf_mtod(mbuf3, struct rte_ether_hdr *); + etype = eth_hdr->ether_type; + mbuf3->packet_type = l3_ptype(etype, 0); + } + + while (n_left > 0) { + mbuf0 = pkts[0]; + + pkts += 1; + n_left -= 1; + + /* Extract ptype of mbuf0 */ + eth_hdr = rte_pktmbuf_mtod(mbuf0, struct rte_ether_hdr *); + etype = eth_hdr->ether_type; + mbuf0->packet_type = l3_ptype(etype, 0); + } + + return nb_pkts; +} + +#define MAX_PTYPES 16 +static int +ethdev_ptype_setup(uint16_t port, uint16_t queue) +{ + uint8_t l3_ipv4 = 0, l3_ipv6 = 0; + uint32_t ptypes[MAX_PTYPES]; + int i, rc; + + /* Check IPv4 & IPv6 ptype support */ + rc = rte_eth_dev_get_supported_ptypes(port, RTE_PTYPE_L3_MASK, ptypes, + MAX_PTYPES); + for (i = 0; i < rc; i++) { + if (ptypes[i] & RTE_PTYPE_L3_IPV4) + l3_ipv4 = 1; + if (ptypes[i] & RTE_PTYPE_L3_IPV6) + l3_ipv6 = 1; + } + + if (!l3_ipv4 || !l3_ipv6) { + node_info("ethdev_rx", + "Enabling ptype callback for required ptypes on port %u\n", + port); + + if (!rte_eth_add_rx_callback(port, queue, eth_pkt_parse_cb, + NULL)) { + node_err("ethdev_rx", + "Failed to add rx ptype cb: port=%d, queue=%d\n", + port, queue); + return -EINVAL; + } + } + + return 0; +} + +static int +ethdev_rx_node_init(const struct rte_graph *graph, struct rte_node *node) +{ + ethdev_rx_node_ctx_t *ctx = (ethdev_rx_node_ctx_t *)node->ctx; + ethdev_rx_node_elem_t *elem = ethdev_rx_main.head; + + RTE_SET_USED(graph); + + while (elem) { + if (elem->nid == node->id) { + /* Update node specific context */ + memcpy(ctx, &elem->ctx, sizeof(ethdev_rx_node_ctx_t)); + break; + } + elem = elem->next; + } + + RTE_VERIFY(elem != NULL); + + /* Check and setup ptype */ + return ethdev_ptype_setup(ctx->port_id, ctx->queue_id); +} + +struct ethdev_rx_node_main * +ethdev_rx_get_node_data_get(void) +{ + return ðdev_rx_main; +} + +static struct rte_node_register ethdev_rx_node_base = { + .process = ethdev_rx_node_process, + .flags = RTE_NODE_SOURCE_F, + .name = "ethdev_rx", + + .init = ethdev_rx_node_init, + + .nb_edges = ETHDEV_RX_NEXT_MAX, + .next_nodes = {[ETHDEV_RX_NEXT_IP4_LOOKUP] = "ip4_lookup"}, +}; + +struct rte_node_register * +ethdev_rx_node_get(void) +{ + return ðdev_rx_node_base; +} + +RTE_NODE_REGISTER(ethdev_rx_node_base); diff --git a/lib/librte_node/ethdev_rx_priv.h b/lib/librte_node/ethdev_rx_priv.h new file mode 100644 index 000000000..2d7195a36 --- /dev/null +++ b/lib/librte_node/ethdev_rx_priv.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ +#ifndef __INCLUDE_ETHDEV_RX_PRIV_H__ +#define __INCLUDE_ETHDEV_RX_PRIV_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct ethdev_rx_node_elem; +struct ethdev_rx_node_ctx; +typedef struct ethdev_rx_node_elem ethdev_rx_node_elem_t; +typedef struct ethdev_rx_node_ctx ethdev_rx_node_ctx_t; + +/** + * @internal + * + * Ethernet device Rx node context structure. + */ +struct ethdev_rx_node_ctx { + uint16_t port_id; /**< Port identifier of the Rx node. */ + uint16_t queue_id; /**< Queue identifier of the Rx node. */ +}; + +/** + * @internal + * + * Ethernet device Rx node list element structure. + */ +struct ethdev_rx_node_elem { + struct ethdev_rx_node_elem *next; + /**< Pointer to the next Rx node element. */ + struct ethdev_rx_node_ctx ctx; + /**< Rx node context. */ + rte_node_t nid; + /**< Node identifier of the Rx node. */ +}; + +enum ethdev_rx_next_nodes { + ETHDEV_RX_NEXT_IP4_LOOKUP, + ETHDEV_RX_NEXT_MAX, +}; + +/** + * @internal + * + * Ethernet Rx node main structure. + */ +struct ethdev_rx_node_main { + ethdev_rx_node_elem_t *head; + /**< Pointer to the head Rx node element. */ +}; + +/** + * @internal + * + * Get the Ethernet Rx node data. + * + * @return + * Pointer to Ethernet Rx node data. + */ +struct ethdev_rx_node_main *ethdev_rx_get_node_data_get(void); + +/** + * @internal + * + * Get the Ethernet Rx node. + * + * @retrun + * Pointer to the Ethernet Rx node. + */ +struct rte_node_register *ethdev_rx_node_get(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_ETHDEV_RX_PRIV_H__ */ diff --git a/lib/librte_node/meson.build b/lib/librte_node/meson.build index 655970614..4adfd6580 100644 --- a/lib/librte_node/meson.build +++ b/lib/librte_node/meson.build @@ -1,6 +1,6 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(C) 2020 Marvell International Ltd. -sources = files('null.c', 'log.c') +sources = files('null.c', 'log.c', 'ethdev_rx.c') allow_experimental_apis = true -deps += ['graph'] +deps += ['graph', 'ethdev'] From patchwork Wed Mar 18 21:35:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66911 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 59440A057D; Wed, 18 Mar 2020 22:38:26 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 879641C02D; Wed, 18 Mar 2020 22:36:31 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) by dpdk.org (Postfix) with ESMTP id 3226D1C02D for ; Wed, 18 Mar 2020 22:36:29 +0100 (CET) Received: from pps.filterd (m0045851.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILVOEB013820; Wed, 18 Mar 2020 14:36:27 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=bWkTR4urvrjTMHFnTRJhA1CHcgqJVpdGaYg/foejo20=; b=CdMbuqJb1rCTbpAldiHuywzosESi6wZRZQF8oCqemJfXUIoxgb5apef14clRMuMIhoGa TxM1+RsQ7QnxbNUV8uvQuPqL2gNEO6UOqttRttytaUwvXo0BN49MspvFiMIpJSMo3tHy EyXEakfGG1C/xv20QdiAFLztayUz1kDLE10zKJNIHrifPN8fFfvDfPTmrOLy1VJjMDKs T9ejiAqlKo8wEer+Uav67O729lEW+NDkuMk9HwhxwNKyTzJTedgAgYJBef0POIKCSzLE eocYzs+qLB6HnNt7/o/HpWvzq+zyZs9r6s+DEQWXn+3t0XB/BMVg1eo7H9c0luiAL/KN hA== Received: from sc-exch02.marvell.com ([199.233.58.182]) by mx0b-0016f401.pphosted.com with ESMTP id 2yu9rpcc5c-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:36:27 -0700 Received: from SC-EXCH03.marvell.com (10.93.176.83) by SC-EXCH02.marvell.com (10.93.176.82) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:25 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:36:25 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id 80D263F703F; Wed, 18 Mar 2020 14:36:23 -0700 (PDT) From: To: Nithin Dabilpuram , Pavan Nikhilesh CC: , , , , , Date: Thu, 19 Mar 2020 03:05:42 +0530 Message-ID: <20200318213551.3489504-18-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 17/26] node: add ethdev Tx node X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Nithin Dabilpuram Add rte_node ethdev_tx process function and register it to graph infra. This node has a specific (port, tx-queue) as context and it enqueue's all the packets received to that specific queue pair. When rte_eth_tx_burst() i.e enqueue to queue pair fails, packets are forwarded to pkt_drop node to be free'd. Signed-off-by: Nithin Dabilpuram Signed-off-by: Pavan Nikhilesh Signed-off-by: Kiran Kumar K --- lib/librte_node/Makefile | 3 +- lib/librte_node/ethdev_tx.c | 86 ++++++++++++++++++++++++++++++++ lib/librte_node/ethdev_tx_priv.h | 62 +++++++++++++++++++++++ lib/librte_node/meson.build | 4 +- 4 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 lib/librte_node/ethdev_tx.c create mode 100644 lib/librte_node/ethdev_tx_priv.h diff --git a/lib/librte_node/Makefile b/lib/librte_node/Makefile index 5a5f589ba..14a293982 100644 --- a/lib/librte_node/Makefile +++ b/lib/librte_node/Makefile @@ -9,7 +9,7 @@ LIB = librte_node.a CFLAGS += -O3 -DALLOW_EXPERIMENTAL_API CFLAGS += $(WERROR_FLAGS) -LDLIBS += -lrte_eal -lrte_graph -lrte_ethdev +LDLIBS += -lrte_eal -lrte_graph -lrte_mbuf -lrte_ethdev EXPORT_MAP := rte_node_version.map @@ -17,5 +17,6 @@ EXPORT_MAP := rte_node_version.map SRCS-$(CONFIG_RTE_LIBRTE_NODE) += null.c SRCS-$(CONFIG_RTE_LIBRTE_NODE) += log.c SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ethdev_rx.c +SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ethdev_tx.c include $(RTE_SDK)/mk/rte.lib.mk diff --git a/lib/librte_node/ethdev_tx.c b/lib/librte_node/ethdev_tx.c new file mode 100644 index 000000000..075149089 --- /dev/null +++ b/lib/librte_node/ethdev_tx.c @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#include +#include +#include +#include +#include + +#include "ethdev_tx_priv.h" + +static struct ethdev_tx_node_main ethdev_tx_main; + +static uint16_t +ethdev_tx_node_process(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + ethdev_tx_node_ctx_t *ctx = (ethdev_tx_node_ctx_t *)node->ctx; + uint16_t port, queue; + uint16_t count; + + /* Get Tx port id */ + port = ctx->port; + queue = ctx->queue; + + count = rte_eth_tx_burst(port, queue, (struct rte_mbuf **)objs, + nb_objs); + + /* Redirect unsent pkts to drop node */ + if (count != nb_objs) { + rte_node_enqueue(graph, node, ETHDEV_TX_NEXT_PKT_DROP, + &objs[count], nb_objs - count); + } + + return count; +} + +static int +ethdev_tx_node_init(const struct rte_graph *graph, struct rte_node *node) +{ + ethdev_tx_node_ctx_t *ctx = (ethdev_tx_node_ctx_t *)node->ctx; + uint64_t port_id = RTE_MAX_ETHPORTS; + int i; + + /* Find our port id */ + for (i = 0; i < RTE_MAX_ETHPORTS; i++) { + if (ethdev_tx_main.nodes[i] == node->id) { + port_id = i; + break; + } + } + RTE_VERIFY(port_id < RTE_MAX_ETHPORTS); + + /* Update port and queue */ + ctx->port = port_id; + ctx->queue = graph->id; + + return 0; +} + +struct ethdev_tx_node_main * +ethdev_tx_node_data_get(void) +{ + return ðdev_tx_main; +} + +static struct rte_node_register ethdev_tx_node_base = { + .process = ethdev_tx_node_process, + .name = "ethdev_tx", + + .init = ethdev_tx_node_init, + + .nb_edges = ETHDEV_TX_NEXT_MAX, + .next_nodes = { + [ETHDEV_TX_NEXT_PKT_DROP] = "pkt_drop", + }, +}; + +struct rte_node_register * +ethdev_tx_node_get(void) +{ + return ðdev_tx_node_base; +} + +RTE_NODE_REGISTER(ethdev_tx_node_base); diff --git a/lib/librte_node/ethdev_tx_priv.h b/lib/librte_node/ethdev_tx_priv.h new file mode 100644 index 000000000..586bff44a --- /dev/null +++ b/lib/librte_node/ethdev_tx_priv.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ +#ifndef __INCLUDE_ETHDEV_TX_PRIV_H__ +#define __INCLUDE_ETHDEV_TX_PRIV_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct ethdev_tx_node_ctx; +typedef struct ethdev_tx_node_ctx ethdev_tx_node_ctx_t; + +enum ethdev_tx_next_nodes { + ETHDEV_TX_NEXT_PKT_DROP, + ETHDEV_TX_NEXT_MAX, +}; + +/** + * @internal + * + * Ethernet Tx node context structure. + */ +struct ethdev_tx_node_ctx { + uint16_t port; /**< Port identifier of the Ethernet Tx node. */ + uint16_t queue; /**< Queue identifier of the Ethernet Tx node. */ +}; + +/** + * @internal + * + * Ethernet Tx node main structure. + */ +struct ethdev_tx_node_main { + uint32_t nodes[RTE_MAX_ETHPORTS]; /**< Tx nodes for each ethdev port. */ +}; + +/** + * @internal + * + * Get the Ethernet Tx node data. + * + * @return + * Pointer to Ethernet Tx node data. + */ +struct ethdev_tx_node_main *ethdev_tx_node_data_get(void); + +/** + * @internal + * + * Get the Ethernet Tx node. + * + * @retrun + * Pointer to the Ethernet Tx node. + */ +struct rte_node_register *ethdev_tx_node_get(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_ETHDEV_TX_PRIV_H__ */ diff --git a/lib/librte_node/meson.build b/lib/librte_node/meson.build index 4adfd6580..c3e35276b 100644 --- a/lib/librte_node/meson.build +++ b/lib/librte_node/meson.build @@ -1,6 +1,6 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(C) 2020 Marvell International Ltd. -sources = files('null.c', 'log.c', 'ethdev_rx.c') +sources = files('null.c', 'log.c', 'ethdev_rx.c', 'ethdev_tx.c') allow_experimental_apis = true -deps += ['graph', 'ethdev'] +deps += ['graph', 'mbuf', 'ethdev'] From patchwork Wed Mar 18 21:35:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66912 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id A0562A057D; Wed, 18 Mar 2020 22:38:37 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id CCE811BE51; Wed, 18 Mar 2020 22:36:36 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) by dpdk.org (Postfix) with ESMTP id A556E2E81 for ; Wed, 18 Mar 2020 22:36:35 +0100 (CET) Received: from pps.filterd (m0045851.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILVPcB013826; Wed, 18 Mar 2020 14:36:33 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=PydrtTLgPQmJxFxlgoTWGHb2iNH9vRQNn2K1HCtFQms=; b=bmLfUpp9gZ/U4kkaC8eW+BfHTETCMmuqcXa27MRnsMJ8VNUrQf/hUN7TsoqaK7TX0Miy uCW+WqVgUK/gwJ7a9CS3gz6JekTsoh5M7wiHGK1mch8FYzPXKgwFE5X33NZ7COk9psJr Tuo7eFb/J4P4aq3DWt/BypxHtGcg01qjuw7x1EU2WHcz/h/feyvBoq0V0UMfFUjfjkOs qNzbvmdplEYnhwnOqFHL9f18AXIDQ7nm1hc3BxAROK2s0cqRDEtww1vPctcM1XzD63Yj lwloNTZMr4Tln2EzgyzOGGE0zQX3jSvRwzt6opva9oD0bFnU0ZIxNKJYSqCU3CWqVPpk cQ== Received: from sc-exch04.marvell.com ([199.233.58.184]) by mx0b-0016f401.pphosted.com with ESMTP id 2yu9rpcc5v-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:36:33 -0700 Received: from SC-EXCH03.marvell.com (10.93.176.83) by SC-EXCH04.marvell.com (10.93.176.84) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:30 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:36:29 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id 282F63F7043; Wed, 18 Mar 2020 14:36:26 -0700 (PDT) From: To: John McNamara , Marko Kovacevic , Nithin Dabilpuram , Pavan Nikhilesh CC: , , , , , Date: Thu, 19 Mar 2020 03:05:43 +0530 Message-ID: <20200318213551.3489504-19-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 18/26] node: add ethdev Rx and Tx node ctrl API X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Nithin Dabilpuram Add ctrl api to setup ethdev_rx and ethdev_tx node. This ctrl api clones 'N' number of ethdev_rx and ethdev_tx nodes with specific (port, queue) pairs updated in their context. All the ethdev ports and queues are setup before this api is called. Signed-off-by: Nithin Dabilpuram Signed-off-by: Pavan Nikhilesh Signed-off-by: Kiran Kumar K --- doc/api/doxy-api-index.md | 2 + lib/librte_node/Makefile | 6 +- lib/librte_node/ethdev_ctrl.c | 99 ++++++++++++++++++++++++++++ lib/librte_node/meson.build | 5 +- lib/librte_node/node_private.h | 74 +++++++++++++++++++++ lib/librte_node/rte_node_eth_api.h | 70 ++++++++++++++++++++ lib/librte_node/rte_node_version.map | 1 + 7 files changed, 254 insertions(+), 3 deletions(-) create mode 100644 lib/librte_node/ethdev_ctrl.c create mode 100644 lib/librte_node/rte_node_eth_api.h diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md index fd2ff64d7..1784674df 100644 --- a/doc/api/doxy-api-index.md +++ b/doc/api/doxy-api-index.md @@ -161,6 +161,8 @@ The public API headers are grouped by topics: [table_action] (@ref rte_table_action.h) * [graph] (@ref rte_graph.h): [graph_worker] (@ref rte_graph_worker.h) + * graph_nodes: + [eth_node] (@ref rte_node_eth_api.h), - **basic**: [approx fraction] (@ref rte_approx.h), diff --git a/lib/librte_node/Makefile b/lib/librte_node/Makefile index 14a293982..c7b291c3c 100644 --- a/lib/librte_node/Makefile +++ b/lib/librte_node/Makefile @@ -9,7 +9,7 @@ LIB = librte_node.a CFLAGS += -O3 -DALLOW_EXPERIMENTAL_API CFLAGS += $(WERROR_FLAGS) -LDLIBS += -lrte_eal -lrte_graph -lrte_mbuf -lrte_ethdev +LDLIBS += -lrte_eal -lrte_graph -lrte_mbuf -lrte_ethdev -lrte_mempool EXPORT_MAP := rte_node_version.map @@ -18,5 +18,9 @@ SRCS-$(CONFIG_RTE_LIBRTE_NODE) += null.c SRCS-$(CONFIG_RTE_LIBRTE_NODE) += log.c SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ethdev_rx.c SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ethdev_tx.c +SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ethdev_ctrl.c + +# install header files +SYMLINK-$(CONFIG_RTE_LIBRTE_NODE)-include += rte_node_eth_api.h include $(RTE_SDK)/mk/rte.lib.mk diff --git a/lib/librte_node/ethdev_ctrl.c b/lib/librte_node/ethdev_ctrl.c new file mode 100644 index 000000000..971cf0fb8 --- /dev/null +++ b/lib/librte_node/ethdev_ctrl.c @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#include +#include +#include +#include +#include + +#include "ethdev_rx_priv.h" +#include "ethdev_tx_priv.h" +#include "node_private.h" + +static struct ethdev_ctrl { + uint16_t nb_graphs; +} ctrl; + +int +rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs, + uint16_t nb_graphs) +{ + struct ethdev_tx_node_main *tx_node_data; + uint16_t tx_q_used, rx_q_used, port_id; + struct rte_node_register *tx_node; + char name[RTE_NODE_NAMESIZE]; + struct rte_mempool *mp; + uint32_t id; + int i, j; + + tx_node_data = ethdev_tx_node_data_get(); + tx_node = ethdev_tx_node_get(); + for (i = 0; i < nb_confs; i++) { + port_id = conf[i].port_id; + + if (!rte_eth_dev_is_valid_port(port_id)) + return -EINVAL; + + /* Check for mbuf minimum private size requirement */ + for (j = 0; j < conf[i].mp_count; j++) { + mp = conf[i].mp[j]; + if (!mp) + continue; + /* Check for minimum private space */ + if (rte_pktmbuf_priv_size(mp) < + RTE_NODE_MBUF_PRIV2_SIZE) { + node_err("ethdev", + "Minimum mbuf priv size requirement not met by mp %s", + mp->name); + return -EINVAL; + } + } + + rx_q_used = conf[i].num_rx_queues; + tx_q_used = conf[i].num_tx_queues; + /* Check if we have a txq for each worker */ + if (tx_q_used < nb_graphs) + return -EINVAL; + + /* Create node for each rx port queue pair */ + for (j = 0; j < rx_q_used; j++) { + struct ethdev_rx_node_main *rx_node_data; + struct rte_node_register *rx_node; + ethdev_rx_node_elem_t *elem; + + rx_node_data = ethdev_rx_get_node_data_get(); + rx_node = ethdev_rx_node_get(); + snprintf(name, sizeof(name), "%u-%u", port_id, j); + /* Clone a new rx node with same edges as parent */ + id = rte_node_clone(rx_node->id, name); + if (id == RTE_NODE_ID_INVALID) + return -EIO; + + /* Add it to list of ethdev rx nodes for lookup */ + elem = malloc(sizeof(ethdev_rx_node_elem_t)); + memset(elem, 0, sizeof(ethdev_rx_node_elem_t)); + elem->ctx.port_id = port_id; + elem->ctx.queue_id = j; + elem->nid = id; + elem->next = rx_node_data->head; + rx_node_data->head = elem; + + node_dbg("ethdev", "Rx node %s-%s: is at %u", + rx_node->name, name, id); + } + + /* Create a per port tx node from base node */ + snprintf(name, sizeof(name), "%u", port_id); + /* Clone a new node with same edges as parent */ + id = rte_node_clone(tx_node->id, name); + tx_node_data->nodes[port_id] = id; + + node_dbg("ethdev", "Tx node %s-%s: is at %u", tx_node->name, + name, id); + } + + ctrl.nb_graphs = nb_graphs; + return 0; +} diff --git a/lib/librte_node/meson.build b/lib/librte_node/meson.build index c3e35276b..f34162aa7 100644 --- a/lib/librte_node/meson.build +++ b/lib/librte_node/meson.build @@ -1,6 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(C) 2020 Marvell International Ltd. -sources = files('null.c', 'log.c', 'ethdev_rx.c', 'ethdev_tx.c') +sources = files('null.c', 'log.c', 'ethdev_rx.c', 'ethdev_tx.c', 'ethdev_ctrl.c') +headers = files('rte_node_eth_api.h') allow_experimental_apis = true -deps += ['graph', 'mbuf', 'ethdev'] +deps += ['graph', 'mbuf', 'lpm', 'ethdev', 'mempool', 'cryptodev'] diff --git a/lib/librte_node/node_private.h b/lib/librte_node/node_private.h index f30902a94..141448546 100644 --- a/lib/librte_node/node_private.h +++ b/lib/librte_node/node_private.h @@ -6,7 +6,9 @@ #define __NODE_PRIVATE_H__ #include +#include #include +#include extern int rte_node_logtype; #define NODE_LOG(level, node_name, ...) \ @@ -19,4 +21,76 @@ extern int rte_node_logtype; #define node_info(node_name, ...) NODE_LOG(INFO, node_name, __VA_ARGS__) #define node_dbg(node_name, ...) NODE_LOG(DEBUG, node_name, __VA_ARGS__) +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Node mbuf private data to store next hop, ttl and checksum. + */ +struct rte_node_mbuf_priv1 { + union { + /* IP4 rewrite */ + struct { + uint16_t nh; + uint16_t ttl; + uint32_t cksum; + }; + + uint64_t u; + }; +}; + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Node mbuf private data to store crypto operation. + */ +struct rte_node_mbuf_priv2 { + union { + /* Sym crypto */ + struct { + struct rte_crypto_op op; + }; + }; +} __rte_cache_aligned; + +#define RTE_NODE_MBUF_PRIV2_SIZE sizeof(struct rte_node_mbuf_priv2) + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Get mbuf_priv1 pointer from rte_mbuf. + * + * @param + * Pointer to the rte_mbuf. + * + * @return + * Pointer to the mbuf_priv1. + */ +static __rte_always_inline struct rte_node_mbuf_priv1 * +rte_node_mbuf_priv1(struct rte_mbuf *m) +{ + return (struct rte_node_mbuf_priv1 *)&m->udata64; +} + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Get mbuf_priv2 pointer from rte_mbuf. + * + * @param + * Pointer to the rte_mbuf. + * + * @return + * Pointer to the mbuf_priv2. + */ +static __rte_always_inline struct rte_node_mbuf_priv2 * +rte_node_mbuf_priv2(struct rte_mbuf *m) +{ + return (struct rte_node_mbuf_priv2 *)rte_mbuf_to_priv(m); +} + #endif /* __NODE_PRIVATE_H__ */ diff --git a/lib/librte_node/rte_node_eth_api.h b/lib/librte_node/rte_node_eth_api.h new file mode 100644 index 000000000..39b31b45b --- /dev/null +++ b/lib/librte_node/rte_node_eth_api.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#ifndef __INCLUDE_RTE_NODE_ETH_API_H__ +#define __INCLUDE_RTE_NODE_ETH_API_H__ + +/** + * @file rte_node_eth_api.h + * + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * This API allows to setup ethdev_rx and ethdev_tx nodes + * and its queue associations. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Port config for ethdev_rx and ethdev_tx node. + */ +struct rte_node_ethdev_config { + uint16_t port_id; + /**< Port identifier */ + uint16_t num_rx_queues; + /**< Number of Rx queues. */ + uint16_t num_tx_queues; + /**< Number of Tx queues. */ + struct rte_mempool **mp; + /**< Array of mempools associated to Rx queue. */ + uint16_t mp_count; + /**< Size of mp array. */ +}; + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Initializes ethdev nodes. + * + * @param cfg + * Array of ethdev config that identifies which port's + * ethdev_rx and ethdev_tx nodes need to be created + * and queue association. + * @param cnt + * Size of cfg array. + * @param nb_graphs + * Number of graphs that will be used. + * + * @return + * 0 on successful initialization, negative otherwise. + */ +__rte_experimental +int rte_node_eth_config(struct rte_node_ethdev_config *cfg, + uint16_t cnt, uint16_t nb_graphs); +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_RTE_NODE_ETH_API_H__ */ diff --git a/lib/librte_node/rte_node_version.map b/lib/librte_node/rte_node_version.map index f87163bb9..c6c71bd02 100644 --- a/lib/librte_node/rte_node_version.map +++ b/lib/librte_node/rte_node_version.map @@ -1,6 +1,7 @@ EXPERIMENTAL { global: + rte_node_eth_config; rte_node_logtype; local: *; }; From patchwork Wed Mar 18 21:35:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66913 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 2DFB9A057D; Wed, 18 Mar 2020 22:38:47 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 2AADF1C133; Wed, 18 Mar 2020 22:36:40 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by dpdk.org (Postfix) with ESMTP id BBB401C132 for ; Wed, 18 Mar 2020 22:36:38 +0100 (CET) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILV0CN003368; Wed, 18 Mar 2020 14:36:36 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=3nXBNKGula0eVvcqWeBHzAj0eYbJzRIIsU+ZP2ukoNY=; b=kC4xfzM6eYGdg9Fb9thBepz/OB7GxAHaf1+yV9p5sUA2wwxC0EWvKdKuObvZ6UvVSAu9 5UaC+XN3Ijs8L0VIofOGqwBHaP1u5kAxJBNV7aFvOl8Zio/kC5cY0nxvB0YudkomG1SS +lFB/jQhd2olQuFflSe9eadOcpsdnmHOFIstLl0ZAlBnodRbiy4r3bhwcThgsKlpI/KO r3pPy4/QMcRDm1j+68+smRXdqxTqaZHeZm7K2cAAijvcfN5EUch9J/TQyh6N061deq64 8urcRgqAPWapQUsne48U/+0M48F7jKWRhZr99KXOJTkxYV6Mgp95OZBwqLnlOnsJlHlS lA== Received: from sc-exch02.marvell.com ([199.233.58.182]) by mx0a-0016f401.pphosted.com with ESMTP id 2yu8pqmrde-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:36:36 -0700 Received: from DC5-EXCH01.marvell.com (10.69.176.38) by SC-EXCH02.marvell.com (10.93.176.82) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:35 -0700 Received: from SC-EXCH01.marvell.com (10.93.176.81) by DC5-EXCH01.marvell.com (10.69.176.38) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:34 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:36:34 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id 536CE3F703F; Wed, 18 Mar 2020 14:36:31 -0700 (PDT) From: To: John McNamara , Marko Kovacevic , Nithin Dabilpuram , Pavan Nikhilesh CC: , , , , , Date: Thu, 19 Mar 2020 03:05:44 +0530 Message-ID: <20200318213551.3489504-20-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 19/26] node: ipv4 lookup for arm64 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Nithin Dabilpuram Add arm64 specific IPv4 lookup process function for ip4_lookup node. This node performs LPM lookup on every packet received and forwards it to a next node that is identified by lookup result. Signed-off-by: Nithin Dabilpuram Signed-off-by: Kiran Kumar K Signed-off-by: Pavan Nikhilesh --- doc/api/doxy-api-index.md | 1 + lib/librte_node/Makefile | 4 +- lib/librte_node/ip4_lookup.c | 306 +++++++++++++++++++++++++++++ lib/librte_node/meson.build | 5 +- lib/librte_node/rte_node_ip4_api.h | 43 ++++ 5 files changed, 356 insertions(+), 3 deletions(-) create mode 100644 lib/librte_node/ip4_lookup.c create mode 100644 lib/librte_node/rte_node_ip4_api.h diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md index 1784674df..3908fddde 100644 --- a/doc/api/doxy-api-index.md +++ b/doc/api/doxy-api-index.md @@ -163,6 +163,7 @@ The public API headers are grouped by topics: [graph_worker] (@ref rte_graph_worker.h) * graph_nodes: [eth_node] (@ref rte_node_eth_api.h), + [ip4_node] (@ref rte_node_ip4_api.h) - **basic**: [approx fraction] (@ref rte_approx.h), diff --git a/lib/librte_node/Makefile b/lib/librte_node/Makefile index c7b291c3c..d85a9e9eb 100644 --- a/lib/librte_node/Makefile +++ b/lib/librte_node/Makefile @@ -9,7 +9,7 @@ LIB = librte_node.a CFLAGS += -O3 -DALLOW_EXPERIMENTAL_API CFLAGS += $(WERROR_FLAGS) -LDLIBS += -lrte_eal -lrte_graph -lrte_mbuf -lrte_ethdev -lrte_mempool +LDLIBS += -lrte_eal -lrte_graph -lrte_mbuf -lrte_lpm -lrte_ethdev -lrte_mempool EXPORT_MAP := rte_node_version.map @@ -19,8 +19,10 @@ SRCS-$(CONFIG_RTE_LIBRTE_NODE) += log.c SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ethdev_rx.c SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ethdev_tx.c SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ethdev_ctrl.c +SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ip4_lookup.c # install header files +SYMLINK-$(CONFIG_RTE_LIBRTE_NODE)-include += rte_node_ip4_api.h SYMLINK-$(CONFIG_RTE_LIBRTE_NODE)-include += rte_node_eth_api.h include $(RTE_SDK)/mk/rte.lib.mk diff --git a/lib/librte_node/ip4_lookup.c b/lib/librte_node/ip4_lookup.c new file mode 100644 index 000000000..d7fcd1158 --- /dev/null +++ b/lib/librte_node/ip4_lookup.c @@ -0,0 +1,306 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "node_private.h" + +#define IPV4_L3FWD_LPM_MAX_RULES 1024 +#define IPV4_L3FWD_LPM_NUMBER_TBL8S (1 << 8) + +/* IP4 Lookup global data struct */ +struct ip4_lookup_node_main { + struct rte_lpm *lpm_tbl[RTE_MAX_NUMA_NODES]; +}; + +#if defined(RTE_MACHINE_CPUFLAG_NEON) +/* ARM64 NEON */ +static uint16_t +ip4_lookup_node_process(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts; + struct rte_ipv4_hdr *ipv4_hdr; + struct rte_ether_hdr *eth_hdr; + void **to_next, **from; + uint16_t last_spec = 0; + rte_edge_t next_index; + uint16_t n_left_from; + struct rte_lpm *lpm; + uint16_t held = 0; + uint32_t drop_nh; + rte_xmm_t result; + rte_xmm_t priv01; + rte_xmm_t priv23; + int32x4_t dip; + int rc, i; + + /* Speculative next */ + next_index = RTE_NODE_IP4_LOOKUP_NEXT_REWRITE; + /* Drop node */ + drop_nh = ((uint32_t)RTE_NODE_IP4_LOOKUP_NEXT_PKT_DROP) << 16; + + /* Get socket specific LPM from ctx */ + lpm = *((struct rte_lpm **)node->ctx); + + pkts = (struct rte_mbuf **)objs; + from = objs; + n_left_from = nb_objs; + +#define OBJS_PER_CLINE (RTE_CACHE_LINE_SIZE / sizeof(void *)) + for (i = OBJS_PER_CLINE; i < RTE_GRAPH_BURST_SIZE; i += OBJS_PER_CLINE) + rte_prefetch0(&objs[i]); + + for (i = 0; i < 4 && i < n_left_from; i++) { + rte_prefetch0( + rte_pktmbuf_mtod(pkts[i], struct rte_ether_hdr *) + 1); + } + + /* Get stream for the speculated next node */ + to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs); + while (n_left_from >= 4) { +#if RTE_GRAPH_BURST_SIZE > 64 + /* Prefetch next-next mbufs */ + if (likely(n_left_from >= 11)) { + rte_prefetch0(pkts[8]); + rte_prefetch0(pkts[9]); + rte_prefetch0(pkts[10]); + rte_prefetch0(pkts[11]); + } +#endif + /* Prefetch next mbuf data */ + if (likely(n_left_from >= 7)) { + rte_prefetch0(rte_pktmbuf_mtod(pkts[4], + struct rte_ether_hdr *) + + 1); + rte_prefetch0(rte_pktmbuf_mtod(pkts[5], + struct rte_ether_hdr *) + + 1); + rte_prefetch0(rte_pktmbuf_mtod(pkts[6], + struct rte_ether_hdr *) + + 1); + rte_prefetch0(rte_pktmbuf_mtod(pkts[7], + struct rte_ether_hdr *) + + 1); + } + + mbuf0 = pkts[0]; + mbuf1 = pkts[1]; + mbuf2 = pkts[2]; + mbuf3 = pkts[3]; + + pkts += 4; + n_left_from -= 4; + + /* Extract DIP of mbuf0 */ + eth_hdr = rte_pktmbuf_mtod(mbuf0, struct rte_ether_hdr *); + ipv4_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1); + dip = vsetq_lane_s32(ipv4_hdr->dst_addr, dip, 0); + /* Extract cksum, ttl as ipv4 hdr is in cache */ + priv01.u16[1] = ipv4_hdr->time_to_live; + priv01.u32[1] = ipv4_hdr->hdr_checksum; + + /* Extract DIP of mbuf1 */ + eth_hdr = rte_pktmbuf_mtod(mbuf1, struct rte_ether_hdr *); + ipv4_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1); + dip = vsetq_lane_s32(ipv4_hdr->dst_addr, dip, 1); + /* Extract cksum, ttl as ipv4 hdr is in cache */ + priv01.u16[5] = ipv4_hdr->time_to_live; + priv01.u32[3] = ipv4_hdr->hdr_checksum; + + /* Extract DIP of mbuf2 */ + eth_hdr = rte_pktmbuf_mtod(mbuf2, struct rte_ether_hdr *); + ipv4_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1); + dip = vsetq_lane_s32(ipv4_hdr->dst_addr, dip, 2); + /* Extract cksum, ttl as ipv4 hdr is in cache */ + priv23.u16[1] = ipv4_hdr->time_to_live; + priv23.u32[1] = ipv4_hdr->hdr_checksum; + + /* Extract DIP of mbuf3 */ + eth_hdr = rte_pktmbuf_mtod(mbuf3, struct rte_ether_hdr *); + ipv4_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1); + dip = vsetq_lane_s32(ipv4_hdr->dst_addr, dip, 3); + + dip = vreinterpretq_s32_u8( + vrev32q_u8(vreinterpretq_u8_s32(dip))); + /* Extract cksum, ttl as ipv4 hdr is in cache */ + priv23.u16[5] = ipv4_hdr->time_to_live; + priv23.u32[3] = ipv4_hdr->hdr_checksum; + + /* Perform LPM lookup to get NH and next node */ + rte_lpm_lookupx4(lpm, dip, result.u32, drop_nh); + priv01.u16[0] = result.u16[0]; + priv01.u16[4] = result.u16[2]; + priv23.u16[0] = result.u16[4]; + priv23.u16[4] = result.u16[6]; + + rte_node_mbuf_priv1(mbuf0)->u = priv01.u64[0]; + rte_node_mbuf_priv1(mbuf1)->u = priv01.u64[1]; + rte_node_mbuf_priv1(mbuf2)->u = priv23.u64[0]; + rte_node_mbuf_priv1(mbuf3)->u = priv23.u64[1]; + + /* Enqueue four to next node */ + rte_edge_t fix_spec = ((next_index == result.u16[1]) && + (result.u16[1] == result.u16[3]) && + (result.u16[3] == result.u16[5]) && + (result.u16[5] == result.u16[7])); + + if (unlikely(fix_spec == 0)) { + /* Copy things successfully speculated till now */ + rte_memcpy(to_next, from, last_spec * sizeof(from[0])); + from += last_spec; + to_next += last_spec; + held += last_spec; + last_spec = 0; + + /* Next0 */ + if (next_index == result.u16[1]) { + to_next[0] = from[0]; + to_next++; + held++; + } else { + rte_node_enqueue_x1(graph, node, result.u16[1], + from[0]); + } + + /* Next1 */ + if (next_index == result.u16[3]) { + to_next[0] = from[1]; + to_next++; + held++; + } else { + rte_node_enqueue_x1(graph, node, result.u16[3], + from[1]); + } + + /* Next2 */ + if (next_index == result.u16[5]) { + to_next[0] = from[2]; + to_next++; + held++; + } else { + rte_node_enqueue_x1(graph, node, result.u16[5], + from[2]); + } + + /* Next3 */ + if (next_index == result.u16[7]) { + to_next[0] = from[3]; + to_next++; + held++; + } else { + rte_node_enqueue_x1(graph, node, result.u16[7], + from[3]); + } + + from += 4; + } else { + last_spec += 4; + } + } + + while (n_left_from > 0) { + uint32_t next_hop; + uint16_t next0; + + mbuf0 = pkts[0]; + + pkts += 1; + n_left_from -= 1; + + /* Extract DIP of mbuf0 */ + eth_hdr = rte_pktmbuf_mtod(mbuf0, struct rte_ether_hdr *); + ipv4_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1); + /* Extract cksum, ttl as ipv4 hdr is in cache */ + rte_node_mbuf_priv1(mbuf0)->cksum = ipv4_hdr->hdr_checksum; + rte_node_mbuf_priv1(mbuf0)->ttl = ipv4_hdr->time_to_live; + + rc = rte_lpm_lookup(lpm, rte_be_to_cpu_32(ipv4_hdr->dst_addr), + &next_hop); + next_hop = (rc == 0) ? next_hop : drop_nh; + + rte_node_mbuf_priv1(mbuf0)->nh = (uint16_t)next_hop; + next_hop = next_hop >> 16; + next0 = (uint16_t)next_hop; + + if (unlikely(next_index ^ next0)) { + /* Copy things successfully speculated till now */ + rte_memcpy(to_next, from, last_spec * sizeof(from[0])); + from += last_spec; + to_next += last_spec; + held += last_spec; + last_spec = 0; + + rte_node_enqueue_x1(graph, node, next0, from[0]); + from += 1; + } else { + last_spec += 1; + } + } + + /* !!! Home run !!! */ + if (likely(last_spec == nb_objs)) { + rte_node_next_stream_move(graph, node, next_index); + return nb_objs; + } + held += last_spec; + rte_memcpy(to_next, from, last_spec * sizeof(from[0])); + rte_node_next_stream_put(graph, node, next_index, held); + + return nb_objs; +} + +#else + +static uint16_t +ip4_lookup_node_process(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + RTE_SET_USED(graph); + RTE_SET_USED(node); + RTE_SET_USED(objs); + RTE_SET_USED(nb_objs); + return nb_objs; +} + +#endif + +static int +ip4_lookup_node_init(const struct rte_graph *graph, struct rte_node *node) +{ + RTE_SET_USED(graph); + RTE_SET_USED(node); + + node_dbg("ip4_lookup", "Initialized ip4_lookup node"); + + return 0; +} + +static struct rte_node_register ip4_lookup_node = { + .process = ip4_lookup_node_process, + .name = "ip4_lookup", + + .init = ip4_lookup_node_init, + + .nb_edges = RTE_NODE_IP4_LOOKUP_NEXT_MAX, + .next_nodes = { + [RTE_NODE_IP4_LOOKUP_NEXT_REWRITE] = "ip4_rewrite", + [RTE_NODE_IP4_LOOKUP_NEXT_PKT_DROP] = "pkt_drop", + }, +}; + +RTE_NODE_REGISTER(ip4_lookup_node); diff --git a/lib/librte_node/meson.build b/lib/librte_node/meson.build index f34162aa7..ddea1237a 100644 --- a/lib/librte_node/meson.build +++ b/lib/librte_node/meson.build @@ -1,7 +1,8 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(C) 2020 Marvell International Ltd. -sources = files('null.c', 'log.c', 'ethdev_rx.c', 'ethdev_tx.c', 'ethdev_ctrl.c') -headers = files('rte_node_eth_api.h') +sources = files('null.c', 'log.c', 'ethdev_rx.c', 'ethdev_tx.c', 'ip4_lookup.c', + 'ethdev_ctrl.c') +headers = files('rte_node_ip4_api.h', 'rte_node_eth_api.h') allow_experimental_apis = true deps += ['graph', 'mbuf', 'lpm', 'ethdev', 'mempool', 'cryptodev'] diff --git a/lib/librte_node/rte_node_ip4_api.h b/lib/librte_node/rte_node_ip4_api.h new file mode 100644 index 000000000..37c12bf82 --- /dev/null +++ b/lib/librte_node/rte_node_ip4_api.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#ifndef __INCLUDE_RTE_NODE_IP4_API_H__ +#define __INCLUDE_RTE_NODE_IP4_API_H__ + +/** + * @file rte_node_ip4_api.h + * + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * This API allows to do control path functions of ip4_* nodes + * like ip4_lookup, ip4_rewrite. + * + */ +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * IP4 lookup next nodes. + */ +enum rte_node_ip4_lookup_next { + RTE_NODE_IP4_LOOKUP_NEXT_REWRITE, + /**< Rewrite node. */ + RTE_NODE_IP4_LOOKUP_NEXT_PKT_DROP, + /**< Packet drop node. */ + RTE_NODE_IP4_LOOKUP_NEXT_MAX, + /**< Number of next nodes of lookup node. */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_RTE_NODE_IP4_API_H__ */ From patchwork Wed Mar 18 21:35:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66914 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 10D95A057D; Wed, 18 Mar 2020 22:38:57 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 7A6231C125; Wed, 18 Mar 2020 22:36:44 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) by dpdk.org (Postfix) with ESMTP id 0DAE01C125 for ; Wed, 18 Mar 2020 22:36:42 +0100 (CET) Received: from pps.filterd (m0045851.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILVTaD013858; Wed, 18 Mar 2020 14:36:41 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=7KWZPAmFDz79E4WkBA82Zq3frBiX6YFlBtPg219U+Jg=; b=CfbHK8J337V+NCXrxRd1nh/esz2FjV9HDnivZm81qcAIHd5VBVE3ymRBOgEKnTlyeLfl mNvHxHdFSvU1obC4xbKKEpawQkBp8ZpelnnjwcQNdd8WO8A+zyKwRcW6sKoZnB4t/MNZ Qnzx73i1sqbisWflP/Cx2qDwtbt2RytJH6PAU8WCMcpOGjFF41DNsdpmVI3Ix51RyVcj 6IIUNFj95pvyx7zd+qAoavqQXvkroJXV9ftOowkN25s/M5xM+e4HU9IUKsu9/zMqh9dT 68mVOETdWwa/pPVDXSs5lFM0tPEoybkcYqZ5U4LStwzBbwOqDvd0H32vZ3z0Jf+jhkZ/ ZA== Received: from sc-exch01.marvell.com ([199.233.58.181]) by mx0b-0016f401.pphosted.com with ESMTP id 2yu9rpcc6f-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:36:41 -0700 Received: from DC5-EXCH01.marvell.com (10.69.176.38) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:38 -0700 Received: from SC-EXCH01.marvell.com (10.93.176.81) by DC5-EXCH01.marvell.com (10.69.176.38) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:38 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:36:37 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id 77FF33F703F; Wed, 18 Mar 2020 14:36:35 -0700 (PDT) From: To: Nithin Dabilpuram , Pavan Nikhilesh CC: , , , , , Date: Thu, 19 Mar 2020 03:05:45 +0530 Message-ID: <20200318213551.3489504-21-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 20/26] node: ipv4 lookup for x86 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Pavan Nikhilesh Add IPv4 lookup process function for ip4_lookup rte_node. This node performs LPM lookup using x86_64 vector supported RTE_LPM API on every packet received and forwards it to a next node that is identified by lookup result. Signed-off-by: Pavan Nikhilesh Signed-off-by: Nithin Dabilpuram Signed-off-by: Kiran Kumar K --- lib/librte_node/ip4_lookup.c | 245 +++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) diff --git a/lib/librte_node/ip4_lookup.c b/lib/librte_node/ip4_lookup.c index d7fcd1158..c003e9c91 100644 --- a/lib/librte_node/ip4_lookup.c +++ b/lib/librte_node/ip4_lookup.c @@ -264,6 +264,251 @@ ip4_lookup_node_process(struct rte_graph *graph, struct rte_node *node, return nb_objs; } +#elif defined(RTE_ARCH_X86) + +/* X86 SSE */ +static uint16_t +ip4_lookup_node_process(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts; + rte_edge_t next0, next1, next2, next3, next_index; + struct rte_ipv4_hdr *ipv4_hdr; + struct rte_ether_hdr *eth_hdr; + uint32_t ip0, ip1, ip2, ip3; + void **to_next, **from; + uint16_t last_spec = 0; + uint16_t n_left_from; + struct rte_lpm *lpm; + uint16_t held = 0; + uint32_t drop_nh; + rte_xmm_t dst; + __m128i dip; /* SSE register */ + int rc, i; + + /* Speculative next */ + next_index = RTE_NODE_IP4_LOOKUP_NEXT_REWRITE; + /* Drop node */ + drop_nh = ((uint32_t)RTE_NODE_IP4_LOOKUP_NEXT_PKT_DROP) << 16; + + /* Get socket specific LPM from ctx */ + lpm = *((struct rte_lpm **)node->ctx); + + pkts = (struct rte_mbuf **)objs; + from = objs; + n_left_from = nb_objs; + + if (n_left_from >= 4) { + for (i = 0; i < 4; i++) { + rte_prefetch0(rte_pktmbuf_mtod(pkts[i], + struct rte_ether_hdr *) + + 1); + } + } + + /* Get stream for the speculated next node */ + to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs); + while (n_left_from >= 4) { + /* Prefetch next-next mbufs */ + if (likely(n_left_from >= 11)) { + rte_prefetch0(pkts[8]); + rte_prefetch0(pkts[9]); + rte_prefetch0(pkts[10]); + rte_prefetch0(pkts[11]); + } + + /* Prefetch next mbuf data */ + if (likely(n_left_from >= 7)) { + rte_prefetch0(rte_pktmbuf_mtod(pkts[4], + struct rte_ether_hdr *) + + 1); + rte_prefetch0(rte_pktmbuf_mtod(pkts[5], + struct rte_ether_hdr *) + + 1); + rte_prefetch0(rte_pktmbuf_mtod(pkts[6], + struct rte_ether_hdr *) + + 1); + rte_prefetch0(rte_pktmbuf_mtod(pkts[7], + struct rte_ether_hdr *) + + 1); + } + + mbuf0 = pkts[0]; + mbuf1 = pkts[1]; + mbuf2 = pkts[2]; + mbuf3 = pkts[3]; + + pkts += 4; + n_left_from -= 4; + + /* Extract DIP of mbuf0 */ + eth_hdr = rte_pktmbuf_mtod(mbuf0, struct rte_ether_hdr *); + ipv4_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1); + ip0 = ipv4_hdr->dst_addr; + /* Extract cksum, ttl as ipv4 hdr is in cache */ + rte_node_mbuf_priv1(mbuf0)->cksum = ipv4_hdr->hdr_checksum; + rte_node_mbuf_priv1(mbuf0)->ttl = ipv4_hdr->time_to_live; + + /* Extract DIP of mbuf1 */ + eth_hdr = rte_pktmbuf_mtod(mbuf1, struct rte_ether_hdr *); + ipv4_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1); + ip1 = ipv4_hdr->dst_addr; + /* Extract cksum, ttl as ipv4 hdr is in cache */ + rte_node_mbuf_priv1(mbuf1)->cksum = ipv4_hdr->hdr_checksum; + rte_node_mbuf_priv1(mbuf1)->ttl = ipv4_hdr->time_to_live; + + /* Extract DIP of mbuf2 */ + eth_hdr = rte_pktmbuf_mtod(mbuf2, struct rte_ether_hdr *); + ipv4_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1); + ip2 = ipv4_hdr->dst_addr; + /* Extract cksum, ttl as ipv4 hdr is in cache */ + rte_node_mbuf_priv1(mbuf2)->cksum = ipv4_hdr->hdr_checksum; + rte_node_mbuf_priv1(mbuf2)->ttl = ipv4_hdr->time_to_live; + + /* Extract DIP of mbuf3 */ + eth_hdr = rte_pktmbuf_mtod(mbuf3, struct rte_ether_hdr *); + ipv4_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1); + ip3 = ipv4_hdr->dst_addr; + + /* Prepare for lookup x4 */ + dip = _mm_set_epi32(ip3, ip2, ip1, ip0); + + /* Byte swap 4 IPV4 addresses. */ + const __m128i bswap_mask = _mm_set_epi8( + 12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3); + dip = _mm_shuffle_epi8(dip, bswap_mask); + + /* Extract cksum, ttl as ipv4 hdr is in cache */ + rte_node_mbuf_priv1(mbuf3)->cksum = ipv4_hdr->hdr_checksum; + rte_node_mbuf_priv1(mbuf3)->ttl = ipv4_hdr->time_to_live; + + /* Perform LPM lookup to get NH and next node */ + rte_lpm_lookupx4(lpm, dip, dst.u32, drop_nh); + + /* Extract next node id and NH */ + rte_node_mbuf_priv1(mbuf0)->nh = dst.u32[0] & 0xFFFF; + next0 = (dst.u32[0] >> 16); + + rte_node_mbuf_priv1(mbuf1)->nh = dst.u32[1] & 0xFFFF; + next1 = (dst.u32[1] >> 16); + + rte_node_mbuf_priv1(mbuf2)->nh = dst.u32[2] & 0xFFFF; + next2 = (dst.u32[2] >> 16); + + rte_node_mbuf_priv1(mbuf3)->nh = dst.u32[3] & 0xFFFF; + next3 = (dst.u32[3] >> 16); + + /* Enqueue four to next node */ + rte_edge_t fix_spec = + (next_index ^ next0) | (next_index ^ next1) | + (next_index ^ next2) | (next_index ^ next3); + + if (unlikely(fix_spec)) { + /* Copy things successfully speculated till now */ + rte_memcpy(to_next, from, last_spec * sizeof(from[0])); + from += last_spec; + to_next += last_spec; + held += last_spec; + last_spec = 0; + + /* Next0 */ + if (next_index == next0) { + to_next[0] = from[0]; + to_next++; + held++; + } else { + rte_node_enqueue_x1(graph, node, next0, + from[0]); + } + + /* Next1 */ + if (next_index == next1) { + to_next[0] = from[1]; + to_next++; + held++; + } else { + rte_node_enqueue_x1(graph, node, next1, + from[1]); + } + + /* Next2 */ + if (next_index == next2) { + to_next[0] = from[2]; + to_next++; + held++; + } else { + rte_node_enqueue_x1(graph, node, next2, + from[2]); + } + + /* Next3 */ + if (next_index == next3) { + to_next[0] = from[3]; + to_next++; + held++; + } else { + rte_node_enqueue_x1(graph, node, next3, + from[3]); + } + + from += 4; + + } else { + last_spec += 4; + } + } + + while (n_left_from > 0) { + uint32_t next_hop; + + mbuf0 = pkts[0]; + + pkts += 1; + n_left_from -= 1; + + /* Extract DIP of mbuf0 */ + eth_hdr = rte_pktmbuf_mtod(mbuf0, struct rte_ether_hdr *); + ipv4_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1); + /* Extract cksum, ttl as ipv4 hdr is in cache */ + rte_node_mbuf_priv1(mbuf0)->cksum = ipv4_hdr->hdr_checksum; + rte_node_mbuf_priv1(mbuf0)->ttl = ipv4_hdr->time_to_live; + + rc = rte_lpm_lookup(lpm, rte_be_to_cpu_32(ipv4_hdr->dst_addr), + &next_hop); + next_hop = (rc == 0) ? next_hop : drop_nh; + + rte_node_mbuf_priv1(mbuf0)->nh = next_hop & 0xFFFF; + next0 = (next_hop >> 16); + + if (unlikely(next_index ^ next0)) { + /* Copy things successfully speculated till now */ + rte_memcpy(to_next, from, last_spec * sizeof(from[0])); + from += last_spec; + to_next += last_spec; + held += last_spec; + last_spec = 0; + + rte_node_enqueue_x1(graph, node, next0, from[0]); + from += 1; + } else { + last_spec += 1; + } + } + + /* !!! Home run !!! */ + if (likely(last_spec == nb_objs)) { + rte_node_next_stream_move(graph, node, next_index); + return nb_objs; + } + + held += last_spec; + /* Copy things successfully speculated till now */ + rte_memcpy(to_next, from, last_spec * sizeof(from[0])); + rte_node_next_stream_put(graph, node, next_index, held); + + return nb_objs; +} + #else static uint16_t From patchwork Wed Mar 18 21:35:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66915 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 2FB5DA057D; Wed, 18 Mar 2020 22:39:10 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id ECFA71C197; Wed, 18 Mar 2020 22:36:46 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) by dpdk.org (Postfix) with ESMTP id EA6091C197 for ; Wed, 18 Mar 2020 22:36:45 +0100 (CET) Received: from pps.filterd (m0045851.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILVOKm013821; Wed, 18 Mar 2020 14:36:44 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=luz2GgeuNrw1rNPVYC8yttazxG4egwOdAsQHebgAjas=; b=SjhJlp3pQqreaOQjrmpY6KwZjymOAr9GWu+OmyuFTAFtrf2NZiz7qqJJQKoRQDV37Dtg xBOVFzvJv2iSwjVm26qK2H4648Wt2HfSMNvnmhFjn6j2KDz0FJhEgRs+M1BXFIUySj2t c/28mOHaB0mKvKM7DqWyH3p2y+FyufGAMPNdxLONh7O/4nJF+fIERvL2sy+K2W3NMRDD +SVZT4nPG/cBbGIemrlx3Z3EoaarXlODpU7Ge9X3RuqKeie6cZrl6/HQ5SD0we5TorwQ 7B2LSdVgMU+VGDic09AGJFx2SFgjRRNX0dVMjaL5d2cClo9inX89jMH2IejBbqVu3kpB cw== Received: from sc-exch02.marvell.com ([199.233.58.182]) by mx0b-0016f401.pphosted.com with ESMTP id 2yu9rpcc6k-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:36:44 -0700 Received: from DC5-EXCH02.marvell.com (10.69.176.39) by SC-EXCH02.marvell.com (10.93.176.82) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:42 -0700 Received: from SC-EXCH03.marvell.com (10.93.176.83) by DC5-EXCH02.marvell.com (10.69.176.39) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:41 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:36:41 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id 1F66B3F703F; Wed, 18 Mar 2020 14:36:38 -0700 (PDT) From: To: Nithin Dabilpuram , Pavan Nikhilesh CC: , , , , , Date: Thu, 19 Mar 2020 03:05:46 +0530 Message-ID: <20200318213551.3489504-22-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 21/26] node: add ipv4 rewrite node X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Kiran Kumar K Add ip4 rewrite process function for ip4_rewrite rte_node. On every packet received by this node, header is overwritten with new data before forwarding it to next node. Header data to overwrite with is identified by next hop id passed in mbuf priv data by previous node. Signed-off-by: Kiran Kumar K Signed-off-by: Pavan Nikhilesh Signed-off-by: Nithin Dabilpuram --- lib/librte_node/Makefile | 1 + lib/librte_node/ip4_rewrite.c | 269 +++++++++++++++++++++++++++++ lib/librte_node/ip4_rewrite_priv.h | 55 ++++++ lib/librte_node/meson.build | 2 +- 4 files changed, 326 insertions(+), 1 deletion(-) create mode 100644 lib/librte_node/ip4_rewrite.c create mode 100644 lib/librte_node/ip4_rewrite_priv.h diff --git a/lib/librte_node/Makefile b/lib/librte_node/Makefile index d85a9e9eb..be7e7e338 100644 --- a/lib/librte_node/Makefile +++ b/lib/librte_node/Makefile @@ -20,6 +20,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ethdev_rx.c SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ethdev_tx.c SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ethdev_ctrl.c SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ip4_lookup.c +SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ip4_rewrite.c # install header files SYMLINK-$(CONFIG_RTE_LIBRTE_NODE)-include += rte_node_ip4_api.h diff --git a/lib/librte_node/ip4_rewrite.c b/lib/librte_node/ip4_rewrite.c new file mode 100644 index 000000000..f317f7f4f --- /dev/null +++ b/lib/librte_node/ip4_rewrite.c @@ -0,0 +1,269 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ip4_rewrite_priv.h" +#include "node_private.h" + +static struct ip4_rewrite_node_main *ip4_rewrite_nm; + +static uint16_t +ip4_rewrite_node_process(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts; + struct ip4_rewrite_nh_header *nh = ip4_rewrite_nm->nh; + uint16_t next0, next1, next2, next3, next_index; + struct rte_ipv4_hdr *ip0, *ip1, *ip2, *ip3; + uint16_t n_left_from, held = 0, last_spec = 0; + void *d0, *d1, *d2, *d3; + void **to_next, **from; + rte_xmm_t priv01; + rte_xmm_t priv23; + int i; + + /* Speculative next as last next */ + next_index = *(uint16_t *)node->ctx; + rte_prefetch0(nh); + + pkts = (struct rte_mbuf **)objs; + from = objs; + n_left_from = nb_objs; + + for (i = 0; i < 4 && i < n_left_from; i++) + rte_prefetch0(pkts[i]); + + /* Get stream for the speculated next node */ + to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs); + /* Update Ethernet header of pkts */ + while (n_left_from >= 4) { + if (likely(n_left_from >= 7)) { + /* Prefetch only next-mbuf struct and priv area. + * Data need not be prefetched as we only write. + */ + rte_prefetch0(pkts[4]); + rte_prefetch0(pkts[5]); + rte_prefetch0(pkts[6]); + rte_prefetch0(pkts[7]); + } + + mbuf0 = pkts[0]; + mbuf1 = pkts[1]; + mbuf2 = pkts[2]; + mbuf3 = pkts[3]; + + pkts += 4; + n_left_from -= 4; + priv01.u64[0] = rte_node_mbuf_priv1(mbuf0)->u; + priv01.u64[1] = rte_node_mbuf_priv1(mbuf1)->u; + priv23.u64[0] = rte_node_mbuf_priv1(mbuf2)->u; + priv23.u64[1] = rte_node_mbuf_priv1(mbuf3)->u; + + /* Increment checksum by one. */ + priv01.u32[1] += rte_cpu_to_be_16(0x0100); + priv01.u32[3] += rte_cpu_to_be_16(0x0100); + priv23.u32[1] += rte_cpu_to_be_16(0x0100); + priv23.u32[3] += rte_cpu_to_be_16(0x0100); + + /* Update ttl,cksum rewrite ethernet hdr on mbuf0 */ + d0 = rte_pktmbuf_mtod(mbuf0, void *); + rte_memcpy(d0, nh[priv01.u16[0]].rewrite_data, + nh[priv01.u16[0]].rewrite_len); + + next0 = nh[priv01.u16[0]].tx_node; + ip0 = (struct rte_ipv4_hdr *)((uint8_t *)d0 + + sizeof(struct rte_ether_hdr)); + ip0->time_to_live = priv01.u16[1] - 1; + ip0->hdr_checksum = priv01.u16[2] + priv01.u16[3]; + + /* Update ttl,cksum rewrite ethernet hdr on mbuf1 */ + d1 = rte_pktmbuf_mtod(mbuf1, void *); + rte_memcpy(d1, nh[priv01.u16[4]].rewrite_data, + nh[priv01.u16[4]].rewrite_len); + + next1 = nh[priv01.u16[4]].tx_node; + ip1 = (struct rte_ipv4_hdr *)((uint8_t *)d1 + + sizeof(struct rte_ether_hdr)); + ip1->time_to_live = priv01.u16[5] - 1; + ip1->hdr_checksum = priv01.u16[6] + priv01.u16[7]; + + /* Update ttl,cksum rewrite ethernet hdr on mbuf2 */ + d2 = rte_pktmbuf_mtod(mbuf2, void *); + rte_memcpy(d2, nh[priv23.u16[0]].rewrite_data, + nh[priv23.u16[0]].rewrite_len); + next2 = nh[priv23.u16[0]].tx_node; + ip2 = (struct rte_ipv4_hdr *)((uint8_t *)d2 + + sizeof(struct rte_ether_hdr)); + ip2->time_to_live = priv23.u16[1] - 1; + ip2->hdr_checksum = priv23.u16[2] + priv23.u16[3]; + + /* Update ttl,cksum rewrite ethernet hdr on mbuf3 */ + d3 = rte_pktmbuf_mtod(mbuf3, void *); + rte_memcpy(d3, nh[priv23.u16[4]].rewrite_data, + nh[priv23.u16[4]].rewrite_len); + + next3 = nh[priv23.u16[4]].tx_node; + ip3 = (struct rte_ipv4_hdr *)((uint8_t *)d3 + + sizeof(struct rte_ether_hdr)); + ip3->time_to_live = priv23.u16[5] - 1; + ip3->hdr_checksum = priv23.u16[6] + priv23.u16[7]; + + /* Enqueue four to next node */ + rte_edge_t fix_spec = + ((next_index == next0) && (next0 == next1) && + (next1 == next2) && (next2 == next3)); + + if (unlikely(fix_spec == 0)) { + /* Copy things successfully speculated till now */ + rte_memcpy(to_next, from, last_spec * sizeof(from[0])); + from += last_spec; + to_next += last_spec; + held += last_spec; + last_spec = 0; + + /* next0 */ + if (next_index == next0) { + to_next[0] = from[0]; + to_next++; + held++; + } else { + rte_node_enqueue_x1(graph, node, next0, + from[0]); + } + + /* next1 */ + if (next_index == next1) { + to_next[0] = from[1]; + to_next++; + held++; + } else { + rte_node_enqueue_x1(graph, node, next1, + from[1]); + } + + /* next2 */ + if (next_index == next2) { + to_next[0] = from[2]; + to_next++; + held++; + } else { + rte_node_enqueue_x1(graph, node, next2, + from[2]); + } + + /* next3 */ + if (next_index == next3) { + to_next[0] = from[3]; + to_next++; + held++; + } else { + rte_node_enqueue_x1(graph, node, next3, + from[3]); + } + + from += 4; + + /* Change speculation if last two are same */ + if ((next_index != next3) && (next2 == next3)) { + /* Put the current speculated node */ + rte_node_next_stream_put(graph, node, + next_index, held); + held = 0; + + /* Get next speculated stream */ + next_index = next3; + to_next = rte_node_next_stream_get( + graph, node, next_index, nb_objs); + } + } else { + last_spec += 4; + } + } + + while (n_left_from > 0) { + uint16_t chksum; + + mbuf0 = pkts[0]; + + pkts += 1; + n_left_from -= 1; + + d0 = rte_pktmbuf_mtod(mbuf0, void *); + rte_memcpy(d0, nh[rte_node_mbuf_priv1(mbuf0)->nh].rewrite_data, + nh[rte_node_mbuf_priv1(mbuf0)->nh].rewrite_len); + + next0 = nh[rte_node_mbuf_priv1(mbuf0)->nh].tx_node; + ip0 = (struct rte_ipv4_hdr *)((uint8_t *)d0 + + sizeof(struct rte_ether_hdr)); + chksum = rte_node_mbuf_priv1(mbuf0)->cksum + + rte_cpu_to_be_16(0x0100); + chksum += chksum >= 0xffff; + ip0->hdr_checksum = chksum; + ip0->time_to_live = rte_node_mbuf_priv1(mbuf0)->ttl - 1; + + if (unlikely(next_index ^ next0)) { + /* Copy things successfully speculated till now */ + rte_memcpy(to_next, from, last_spec * sizeof(from[0])); + from += last_spec; + to_next += last_spec; + held += last_spec; + last_spec = 0; + + rte_node_enqueue_x1(graph, node, next0, from[0]); + from += 1; + } else { + last_spec += 1; + } + } + + /* !!! Home run !!! */ + if (likely(last_spec == nb_objs)) { + rte_node_next_stream_move(graph, node, next_index); + return nb_objs; + } + + held += last_spec; + rte_memcpy(to_next, from, last_spec * sizeof(from[0])); + rte_node_next_stream_put(graph, node, next_index, held); + /* Save the last next used */ + *(uint16_t *)node->ctx = next_index; + + return nb_objs; +} + +static int +ip4_rewrite_node_init(const struct rte_graph *graph, struct rte_node *node) +{ + + RTE_SET_USED(graph); + RTE_SET_USED(node); + node_dbg("ip4_rewrite", "Initialized ip4_rewrite node initialized"); + + return 0; +} + +static struct rte_node_register ip4_rewrite_node = { + .process = ip4_rewrite_node_process, + .name = "ip4_rewrite", + /* Default edge i.e '0' is pkt drop */ + .nb_edges = 1, + .next_nodes = { + [0] = "pkt_drop", + }, + .init = ip4_rewrite_node_init, +}; + +RTE_NODE_REGISTER(ip4_rewrite_node); diff --git a/lib/librte_node/ip4_rewrite_priv.h b/lib/librte_node/ip4_rewrite_priv.h new file mode 100644 index 000000000..420996a03 --- /dev/null +++ b/lib/librte_node/ip4_rewrite_priv.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ +#ifndef __INCLUDE_IP4_REWRITE_PRIV_H__ +#define __INCLUDE_IP4_REWRITE_PRIV_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define RTE_GRAPH_IP4_REWRITE_MAX_NH 64 +#define RTE_GRAPH_IP4_REWRITE_MAX_LEN 56 + +/** + * @internal + * + * Ipv4 rewrite next hop header data structure. Used to store port specific + * rewrite data. + */ +struct ip4_rewrite_nh_header { + uint16_t rewrite_len; /**< Header rewrite length. */ + uint16_t tx_node; /**< Tx node next index identifier. */ + uint16_t enabled; /**< NH enable flag */ + uint16_t rsvd; + union { + struct { + struct rte_ether_addr dst; + /**< Destination mac address. */ + struct rte_ether_addr src; + /**< Source mac address. */ + }; + uint8_t rewrite_data[RTE_GRAPH_IP4_REWRITE_MAX_LEN]; + /**< Generic rewrite data */ + }; +}; + +/** + * @internal + * + * Ipv4 node main data structure. + */ +struct ip4_rewrite_node_main { + struct ip4_rewrite_nh_header nh[RTE_GRAPH_IP4_REWRITE_MAX_NH]; + /**< Array of next hop header data */ + uint16_t next_index[RTE_MAX_ETHPORTS]; + /**< Next index of each configured port. */ +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_IP4_REWRITE_PRIV_H__ */ diff --git a/lib/librte_node/meson.build b/lib/librte_node/meson.build index ddea1237a..ef056d9af 100644 --- a/lib/librte_node/meson.build +++ b/lib/librte_node/meson.build @@ -2,7 +2,7 @@ # Copyright(C) 2020 Marvell International Ltd. sources = files('null.c', 'log.c', 'ethdev_rx.c', 'ethdev_tx.c', 'ip4_lookup.c', - 'ethdev_ctrl.c') + 'ip4_rewrite.c', 'ethdev_ctrl.c') headers = files('rte_node_ip4_api.h', 'rte_node_eth_api.h') allow_experimental_apis = true deps += ['graph', 'mbuf', 'lpm', 'ethdev', 'mempool', 'cryptodev'] From patchwork Wed Mar 18 21:35:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66916 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 87189A057D; Wed, 18 Mar 2020 22:39:20 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 1C1631C044; Wed, 18 Mar 2020 22:36:50 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by dpdk.org (Postfix) with ESMTP id 301EC1C044 for ; Wed, 18 Mar 2020 22:36:49 +0100 (CET) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILUs55003328; Wed, 18 Mar 2020 14:36:47 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=+PLRl+g9Pe8IirzZTUm1072cEhR3VsTHq8YMWX3ff9E=; b=Q1qRUU/hEDXtcqy6tJvMIouJFok14tnWCDBOf4lZIWEUJa1CoxGgBoPtO3+2UZRgd5sn B0xD5ySJFoRUg1AbSYwTmLmvC9wLqLau3ZsnwdMVb4bSUtcFHvpy1FrVqMZjtrJYWcLp 7X0VkR6UdMHZDK5Fe42/e/hRzTuwHTVD5abQKdj/Fv7MgkKgNtXpudV5mPW4029cCqAE 79NiiqELf6Mwl+kb9d9pywWM9VWEsyQxw4FqVnAS+ac/MKimUoJhzzX2tGnkXN7ZLO3H eoKZQ+JcnQ32zK8Uf3JIxWb/+hnn/8CqSdLxQguTqWCi611V/+0iH1Ht8IHXIrTQ6Abo 3g== Received: from sc-exch01.marvell.com ([199.233.58.181]) by mx0a-0016f401.pphosted.com with ESMTP id 2yu8pqmrdu-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:36:47 -0700 Received: from SC-EXCH03.marvell.com (10.93.176.83) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:45 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:36:45 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id 165F03F703F; Wed, 18 Mar 2020 14:36:42 -0700 (PDT) From: To: Nithin Dabilpuram , Pavan Nikhilesh CC: , , , , , Date: Thu, 19 Mar 2020 03:05:47 +0530 Message-ID: <20200318213551.3489504-23-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 22/26] node: add ipv4 rewrite and lookup ctrl API X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Nithin Dabilpuram Add ip4_rewrite and ip4_lookup ctrl API. ip4_lookup ctrl API is used to add route entries for LPM lookup with result data containing next hop id and next proto. ip4_rewrite ctrl API is used to add rewrite data for every next hop. Signed-off-by: Nithin Dabilpuram Signed-off-by: Pavan Nikhilesh Signed-off-by: Kiran Kumar K --- lib/librte_node/ethdev_ctrl.c | 18 ++++++- lib/librte_node/ip4_lookup.c | 80 ++++++++++++++++++++++++++++ lib/librte_node/ip4_rewrite.c | 56 +++++++++++++++++++ lib/librte_node/ip4_rewrite_priv.h | 22 ++++++++ lib/librte_node/rte_node_ip4_api.h | 44 +++++++++++++++ lib/librte_node/rte_node_version.map | 2 + 6 files changed, 221 insertions(+), 1 deletion(-) diff --git a/lib/librte_node/ethdev_ctrl.c b/lib/librte_node/ethdev_ctrl.c index 971cf0fb8..48ef8746f 100644 --- a/lib/librte_node/ethdev_ctrl.c +++ b/lib/librte_node/ethdev_ctrl.c @@ -10,6 +10,7 @@ #include "ethdev_rx_priv.h" #include "ethdev_tx_priv.h" +#include "ip4_rewrite_priv.h" #include "node_private.h" static struct ethdev_ctrl { @@ -20,14 +21,17 @@ int rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs, uint16_t nb_graphs) { + struct rte_node_register *ip4_rewrite_node; struct ethdev_tx_node_main *tx_node_data; uint16_t tx_q_used, rx_q_used, port_id; struct rte_node_register *tx_node; char name[RTE_NODE_NAMESIZE]; + const char *next_nodes = name; struct rte_mempool *mp; + int i, j, rc; uint32_t id; - int i, j; + ip4_rewrite_node = ip4_rewrite_node_get(); tx_node_data = ethdev_tx_node_data_get(); tx_node = ethdev_tx_node_get(); for (i = 0; i < nb_confs; i++) { @@ -92,6 +96,18 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs, node_dbg("ethdev", "Tx node %s-%s: is at %u", tx_node->name, name, id); + + /* Prepare the actual name of the cloned node */ + snprintf(name, sizeof(name), "ethdev_tx-%u", port_id); + + /* Add this tx port node as next to ip4_rewrite_node */ + rte_node_edge_update(ip4_rewrite_node->id, RTE_EDGE_ID_INVALID, + &next_nodes, 1); + /* Assuming edge id is the last one alloc'ed */ + rc = ip4_rewrite_set_next( + port_id, rte_node_edge_count(ip4_rewrite_node->id) - 1); + if (rc < 0) + return rc; } ctrl.nb_graphs = nb_graphs; diff --git a/lib/librte_node/ip4_lookup.c b/lib/librte_node/ip4_lookup.c index c003e9c91..fb7090c40 100644 --- a/lib/librte_node/ip4_lookup.c +++ b/lib/librte_node/ip4_lookup.c @@ -27,6 +27,8 @@ struct ip4_lookup_node_main { struct rte_lpm *lpm_tbl[RTE_MAX_NUMA_NODES]; }; +static struct ip4_lookup_node_main ip4_lookup_nm; + #if defined(RTE_MACHINE_CPUFLAG_NEON) /* ARM64 NEON */ static uint16_t @@ -524,12 +526,90 @@ ip4_lookup_node_process(struct rte_graph *graph, struct rte_node *node, #endif +int +rte_node_ip4_route_add(uint32_t ip, uint8_t depth, uint16_t next_hop, + enum rte_node_ip4_lookup_next next_node) +{ + char abuf[INET6_ADDRSTRLEN]; + struct in_addr in; + uint8_t socket; + uint32_t val; + int ret; + + in.s_addr = htonl(ip); + inet_ntop(AF_INET, &in, abuf, sizeof(abuf)); + /* Embedded next node id in next hop */ + val = (next_node << 16) | next_hop; + node_dbg("ip4_lookup", "LPM: Adding route %s / %d nh (0x%x)", abuf, + depth, val); + + for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++) { + if (!ip4_lookup_nm.lpm_tbl[socket]) + continue; + + ret = rte_lpm_add(ip4_lookup_nm.lpm_tbl[socket], ip, depth, + val); + + if (ret < 0) { + node_err("ip4_lookup", + "Unable to add entry %s / %d nh (%x) to LPM table on sock %d, rc=%d\n", + abuf, depth, val, socket, ret); + return ret; + } + } + + return 0; +} + +static int +setup_lpm(struct ip4_lookup_node_main *nm, int socket) +{ + struct rte_lpm_config config_ipv4; + char s[64]; + + /* One LPM table per socket */ + if (nm->lpm_tbl[socket]) + return 0; + + /* create the LPM table */ + config_ipv4.max_rules = IPV4_L3FWD_LPM_MAX_RULES; + config_ipv4.number_tbl8s = IPV4_L3FWD_LPM_NUMBER_TBL8S; + config_ipv4.flags = 0; + snprintf(s, sizeof(s), "IPV4_L3FWD_LPM_%d", socket); + nm->lpm_tbl[socket] = rte_lpm_create(s, socket, &config_ipv4); + if (nm->lpm_tbl[socket] == NULL) + return -rte_errno; + + return 0; +} + static int ip4_lookup_node_init(const struct rte_graph *graph, struct rte_node *node) { + struct rte_lpm **lpm_p = (struct rte_lpm **)&node->ctx; + uint16_t socket, lcore_id; + static uint8_t init_once; + int rc; + RTE_SET_USED(graph); RTE_SET_USED(node); + if (!init_once) { + /* Setup LPM tables for all sockets */ + RTE_LCORE_FOREACH(lcore_id) + { + socket = rte_lcore_to_socket_id(lcore_id); + rc = setup_lpm(&ip4_lookup_nm, socket); + if (rc) { + node_err("ip4_lookup", + "Failed to setup lpm tbl for sock %u, rc=%d", + socket, rc); + return rc; + } + } + init_once = 1; + } + *lpm_p = ip4_lookup_nm.lpm_tbl[graph->socket]; node_dbg("ip4_lookup", "Initialized ip4_lookup node"); return 0; diff --git a/lib/librte_node/ip4_rewrite.c b/lib/librte_node/ip4_rewrite.c index f317f7f4f..14b908ec9 100644 --- a/lib/librte_node/ip4_rewrite.c +++ b/lib/librte_node/ip4_rewrite.c @@ -255,6 +255,56 @@ ip4_rewrite_node_init(const struct rte_graph *graph, struct rte_node *node) return 0; } +int +ip4_rewrite_set_next(uint16_t port_id, uint16_t next_index) +{ + if (ip4_rewrite_nm == NULL) { + ip4_rewrite_nm = rte_zmalloc( + "ip4_rewrite", sizeof(struct ip4_rewrite_node_main), + RTE_CACHE_LINE_SIZE); + if (ip4_rewrite_nm == NULL) + return -ENOMEM; + } + ip4_rewrite_nm->next_index[port_id] = next_index; + + return 0; +} + +int +rte_node_ip4_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data, + uint8_t rewrite_len, uint16_t dst_port) +{ + struct ip4_rewrite_nh_header *nh; + + if (next_hop >= RTE_GRAPH_IP4_REWRITE_MAX_NH) + return -EINVAL; + + if (rewrite_len > RTE_GRAPH_IP4_REWRITE_MAX_LEN) + return -EINVAL; + + if (ip4_rewrite_nm == NULL) { + ip4_rewrite_nm = rte_zmalloc( + "ip4_rewrite", sizeof(struct ip4_rewrite_node_main), + RTE_CACHE_LINE_SIZE); + if (ip4_rewrite_nm == NULL) + return -ENOMEM; + } + + /* Check if dst port doesn't exist as edge */ + if (!ip4_rewrite_nm->next_index[dst_port]) + return -EINVAL; + + /* Update next hop */ + nh = &ip4_rewrite_nm->nh[next_hop]; + + memcpy(nh->rewrite_data, rewrite_data, rewrite_len); + nh->tx_node = ip4_rewrite_nm->next_index[dst_port]; + nh->rewrite_len = rewrite_len; + nh->enabled = true; + + return 0; +} + static struct rte_node_register ip4_rewrite_node = { .process = ip4_rewrite_node_process, .name = "ip4_rewrite", @@ -266,4 +316,10 @@ static struct rte_node_register ip4_rewrite_node = { .init = ip4_rewrite_node_init, }; +struct rte_node_register * +ip4_rewrite_node_get(void) +{ + return &ip4_rewrite_node; +} + RTE_NODE_REGISTER(ip4_rewrite_node); diff --git a/lib/librte_node/ip4_rewrite_priv.h b/lib/librte_node/ip4_rewrite_priv.h index 420996a03..80f0abdc9 100644 --- a/lib/librte_node/ip4_rewrite_priv.h +++ b/lib/librte_node/ip4_rewrite_priv.h @@ -48,6 +48,28 @@ struct ip4_rewrite_node_main { /**< Next index of each configured port. */ }; +/** + * @internal + * + * Get the ipv4 rewrite node. + * + * @retrun + * Pointer to the ipv4 rewrite node. + */ +struct rte_node_register *ip4_rewrite_node_get(void); + +/** + * @internal + * + * Set the Edge index of a given port_id. + * + * @param port_id + * Ethernet port identifier. + * @param next_index + * Edge index of the Given Tx node. + */ +int ip4_rewrite_set_next(uint16_t port_id, uint16_t next_index); + #ifdef __cplusplus } #endif diff --git a/lib/librte_node/rte_node_ip4_api.h b/lib/librte_node/rte_node_ip4_api.h index 37c12bf82..394cac097 100644 --- a/lib/librte_node/rte_node_ip4_api.h +++ b/lib/librte_node/rte_node_ip4_api.h @@ -36,6 +36,50 @@ enum rte_node_ip4_lookup_next { /**< Number of next nodes of lookup node. */ }; +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Add ipv4 route to lookup table. + * + * @param ip + * IP address of route to be added. + * @param depth + * Depth of the rule to be added. + * @param next_hop + * Next hop id of the rule result to be added. + * @param next_node + * Next node to redirect traffic to. + * + * @return + * 0 on success, negative otherwise. + */ +__rte_experimental +int rte_node_ip4_route_add(uint32_t ip, uint8_t depth, uint16_t next_hop, + enum rte_node_ip4_lookup_next next_node); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Add a next hop's rewrite data. + * + * @param next_hop + * Next hop id to add rewrite data to. + * @param rewrite_data + * Rewrite data. + * @param rewrite_len + * Length of rewrite data. + * @param dst_port + * Destination port to redirect traffic to. + * + * @return + * 0 on success, negative otherwise. + */ +__rte_experimental +int rte_node_ip4_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data, + uint8_t rewrite_len, uint16_t dst_port); + #ifdef __cplusplus } #endif diff --git a/lib/librte_node/rte_node_version.map b/lib/librte_node/rte_node_version.map index c6c71bd02..a799b0d38 100644 --- a/lib/librte_node/rte_node_version.map +++ b/lib/librte_node/rte_node_version.map @@ -2,6 +2,8 @@ EXPERIMENTAL { global: rte_node_eth_config; + rte_node_ip4_route_add; + rte_node_ip4_rewrite_add; rte_node_logtype; local: *; }; From patchwork Wed Mar 18 21:35:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66917 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id E8863A057D; Wed, 18 Mar 2020 22:39:30 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 470141C0BD; Wed, 18 Mar 2020 22:36:53 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) by dpdk.org (Postfix) with ESMTP id 291B51C0BD for ; Wed, 18 Mar 2020 22:36:52 +0100 (CET) Received: from pps.filterd (m0045851.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILVTaF013858; Wed, 18 Mar 2020 14:36:51 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=cFW628FuLV0yhhrbg0pJEWbk0EPJ4znLQ3cCNGiHtNI=; b=ZtZTxxK0cjytTgUovjVKfpfIj75MORR+hzD5oO2Ev9Rq0I0SI+H9dr7r/u/rOWbHSPIw o7bFT2IQZmCNPnlQiNOoXF1qPa+mO+SKOc7Qwa6c6gAmLh/JyUnLG8eanFFTrFBPwod5 4rZ71pzhvxb7dURKCMwXjvx4ZeigR71yxyBlChju05E7Cz2kAx1zAZewAdlxAJPtuunE npZdW+3fW5OnX8Ueh50d1lRgv+RqbP1iRGo4u6EjE2MMdLMrkkcQTGcBCoiBrYgDLz6k Ek2akmZt+Y8dV+l7dVsW88nfxCUMGuZ/e63zO/P5xjI23P3HMiYaCYCV6gpkU2FmkxuB 9g== Received: from sc-exch02.marvell.com ([199.233.58.182]) by mx0b-0016f401.pphosted.com with ESMTP id 2yu9rpcc6w-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:36:50 -0700 Received: from SC-EXCH01.marvell.com (10.93.176.81) by SC-EXCH02.marvell.com (10.93.176.82) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:49 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:36:49 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id B8F8D3F703F; Wed, 18 Mar 2020 14:36:46 -0700 (PDT) From: To: Nithin Dabilpuram , Pavan Nikhilesh CC: , , , , , Date: Thu, 19 Mar 2020 03:05:48 +0530 Message-ID: <20200318213551.3489504-24-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 23/26] node: add pkt drop node X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Nithin Dabilpuram Add pkt drop node process function for pkt_drop rte_node. This node simply free's every object received as an rte_mbuf to its rte_pktmbuf pool. Signed-off-by: Nithin Dabilpuram Signed-off-by: Pavan Nikhilesh Signed-off-by: Kiran Kumar K --- lib/librte_node/Makefile | 1 + lib/librte_node/meson.build | 2 +- lib/librte_node/pkt_drop.c | 26 ++++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 lib/librte_node/pkt_drop.c diff --git a/lib/librte_node/Makefile b/lib/librte_node/Makefile index be7e7e338..aaf041580 100644 --- a/lib/librte_node/Makefile +++ b/lib/librte_node/Makefile @@ -21,6 +21,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ethdev_tx.c SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ethdev_ctrl.c SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ip4_lookup.c SRCS-$(CONFIG_RTE_LIBRTE_NODE) += ip4_rewrite.c +SRCS-$(CONFIG_RTE_LIBRTE_NODE) += pkt_drop.c # install header files SYMLINK-$(CONFIG_RTE_LIBRTE_NODE)-include += rte_node_ip4_api.h diff --git a/lib/librte_node/meson.build b/lib/librte_node/meson.build index ef056d9af..59e11e5b4 100644 --- a/lib/librte_node/meson.build +++ b/lib/librte_node/meson.build @@ -2,7 +2,7 @@ # Copyright(C) 2020 Marvell International Ltd. sources = files('null.c', 'log.c', 'ethdev_rx.c', 'ethdev_tx.c', 'ip4_lookup.c', - 'ip4_rewrite.c', 'ethdev_ctrl.c') + 'ip4_rewrite.c', 'pkt_drop.c', 'ethdev_ctrl.c') headers = files('rte_node_ip4_api.h', 'rte_node_eth_api.h') allow_experimental_apis = true deps += ['graph', 'mbuf', 'lpm', 'ethdev', 'mempool', 'cryptodev'] diff --git a/lib/librte_node/pkt_drop.c b/lib/librte_node/pkt_drop.c new file mode 100644 index 000000000..c35001323 --- /dev/null +++ b/lib/librte_node/pkt_drop.c @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#include +#include +#include + +static uint16_t +pkt_drop_process(struct rte_graph *graph, struct rte_node *node, void **objs, + uint16_t nb_objs) +{ + RTE_SET_USED(node); + RTE_SET_USED(graph); + + rte_pktmbuf_free_bulk((struct rte_mbuf **)objs, nb_objs); + + return nb_objs; +} + +static struct rte_node_register pkt_drop_node = { + .process = pkt_drop_process, + .name = "pkt_drop", +}; + +RTE_NODE_REGISTER(pkt_drop_node); From patchwork Wed Mar 18 21:35:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66918 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 8F54AA057D; Wed, 18 Mar 2020 22:39:42 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 0D4691C11B; Wed, 18 Mar 2020 22:37:00 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) by dpdk.org (Postfix) with ESMTP id 40CEA1C06C for ; Wed, 18 Mar 2020 22:36:59 +0100 (CET) Received: from pps.filterd (m0045851.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILVpsJ021913; Wed, 18 Mar 2020 14:36:57 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=FGcX5w97zyXslBA51c/Gg+5mJlxbISYCQE2KHug5WgU=; b=FJ4ExKRlDZYCeJIb/1K9R7Zxum/49G2TeLJAWmbdPtaqE6fdRR0dgClaiXigTW0HKxZn TYj1bT0vGYU4eHYPGwxpUr0k6iiyPfBBULjw9uytnLkYCd72zQqKqJmqH9hTZG9JjwOr g7HGW2zQHKMV3iiax5CHBDusGbSSAWITYGRCr7ieBqfbbIqpsWuLMk8oZ4ZIS0hj4SZX Bg3NL4zJHVuIy5nfH1EBzhXHGEEuhRTEC1dOa6ypL1Q7SETqjno3LmTD45f27KIB7eLA RULjYOXYMCqucsYku4ULNCeTvzgVOPLW8fcPfuEj/lRd+4aHYtY7XWUoEIafCI4j9aSc TA== Received: from sc-exch01.marvell.com ([199.233.58.181]) by mx0b-0016f401.pphosted.com with ESMTP id 2yu9rpcc76-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:36:57 -0700 Received: from SC-EXCH01.marvell.com (10.93.176.81) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:36:54 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:36:54 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id 630A53F703F; Wed, 18 Mar 2020 14:36:50 -0700 (PDT) From: To: Thomas Monjalon , Marko Kovacevic , Ori Kam , Bruce Richardson , Radu Nicolau , "Akhil Goyal" , Tomasz Kantecki , Sunil Kumar Kori , Pavan Nikhilesh , Nithin Dabilpuram CC: , , , , Date: Thu, 19 Mar 2020 03:05:49 +0530 Message-ID: <20200318213551.3489504-25-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 24/26] l3fwd-graph: add graph based l3fwd skeleton X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Nithin Dabilpuram Add graph based l3fwd application skeleton with cmdline parsing support inline with normal l3fwd. Signed-off-by: Nithin Dabilpuram --- MAINTAINERS | 3 + examples/Makefile | 3 + examples/l3fwd-graph/Makefile | 58 ++++ examples/l3fwd-graph/main.c | 528 +++++++++++++++++++++++++++++++ examples/l3fwd-graph/meson.build | 13 + examples/meson.build | 6 +- 6 files changed, 609 insertions(+), 2 deletions(-) create mode 100644 examples/l3fwd-graph/Makefile create mode 100644 examples/l3fwd-graph/main.c create mode 100644 examples/l3fwd-graph/meson.build diff --git a/MAINTAINERS b/MAINTAINERS index 3959ed19a..73debcd6d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1580,6 +1580,9 @@ F: doc/guides/sample_app_ug/l2_forward_event.rst F: examples/l3fwd/ F: doc/guides/sample_app_ug/l3_forward.rst +M: Nithin Dabilpuram +F: examples/l3fwd-graph/ + F: examples/link_status_interrupt/ F: doc/guides/sample_app_ug/link_status_intr.rst diff --git a/examples/Makefile b/examples/Makefile index feff79784..b7e99a2f7 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -51,6 +51,9 @@ DIRS-$(CONFIG_RTE_LIBRTE_ACL) += l3fwd-acl ifeq ($(CONFIG_RTE_LIBRTE_LPM)$(CONFIG_RTE_LIBRTE_HASH),yy) DIRS-$(CONFIG_RTE_LIBRTE_POWER) += l3fwd-power endif +ifeq ($(CONFIG_RTE_LIBRTE_GRAPH),y) +DIRS-y += l3fwd-graph +endif DIRS-y += link_status_interrupt DIRS-y += multi_process DIRS-y += ntb diff --git a/examples/l3fwd-graph/Makefile b/examples/l3fwd-graph/Makefile new file mode 100644 index 000000000..f3cf275ec --- /dev/null +++ b/examples/l3fwd-graph/Makefile @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(C) 2020 Marvell International Ltd. + +# binary name +APP = l3fwd-graph + +# all source are stored in SRCS-y +SRCS-y := main.c + +# Build using pkg-config variables if possible +ifeq ($(shell pkg-config --exists libdpdk && echo 0),0) + +all: shared +.PHONY: shared static +shared: build/$(APP)-shared + ln -sf $(APP)-shared build/$(APP) +static: build/$(APP)-static + ln -sf $(APP)-static build/$(APP) + +PKGCONF=pkg-config --define-prefix + +PC_FILE := $(shell $(PKGCONF) --path libdpdk) +CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk) -DALLOW_EXPERIMENTAL_API +LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk) +LDFLAGS_STATIC = -Wl,-Bstatic $(shell $(PKGCONF) --static --libs libdpdk) + +build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build + $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED) + +build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build + $(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC) + +build: + @mkdir -p $@ + +.PHONY: clean +clean: + rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared + test -d build && rmdir -p build || true + +else # Build using legacy build system + +ifeq ($(RTE_SDK),) +$(error "Please define RTE_SDK environment variable") +endif + +# Default target, detect a build directory, by looking for a path with a .config +RTE_TARGET ?= $(notdir $(abspath $(dir $(firstword $(wildcard $(RTE_SDK)/*/.config))))) + +include $(RTE_SDK)/mk/rte.vars.mk + +CFLAGS += -DALLOW_EXPERIMENTAL_API +CFLAGS += -I$(SRCDIR) +CFLAGS += -O3 $(USER_FLAGS) +CFLAGS += $(WERROR_FLAGS) + +include $(RTE_SDK)/mk/rte.extapp.mk +endif diff --git a/examples/l3fwd-graph/main.c b/examples/l3fwd-graph/main.c new file mode 100644 index 000000000..8cee8bebd --- /dev/null +++ b/examples/l3fwd-graph/main.c @@ -0,0 +1,528 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ + +#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 + +/* Log type */ +#define RTE_LOGTYPE_L3FWD_GRAPH RTE_LOGTYPE_USER1 + +/* + * Configurable number of RX/TX ring descriptors + */ +#define RTE_TEST_RX_DESC_DEFAULT 1024 +#define RTE_TEST_TX_DESC_DEFAULT 1024 + +#define MAX_TX_QUEUE_PER_PORT RTE_MAX_ETHPORTS +#define MAX_RX_QUEUE_PER_PORT 128 + +#define MAX_RX_QUEUE_PER_LCORE 16 + +#define MAX_LCORE_PARAMS 1024 + +#define NB_SOCKETS 8 + +/**< Ports set in promiscuous mode off by default. */ +static int promiscuous_on; + +static int numa_on = 1; /**< NUMA is enabled by default. */ +static int per_port_pool; /**< Use separate buffer pools per port; disabled */ + /**< by default */ + +static volatile bool force_quit; + +/* Ethernet addresses of ports */ +static uint64_t dest_eth_addr[RTE_MAX_ETHPORTS]; +xmm_t val_eth[RTE_MAX_ETHPORTS]; + +/* Mask of enabled ports */ +static uint32_t enabled_port_mask; + +struct lcore_rx_queue { + uint16_t port_id; + uint8_t queue_id; +}; + +/* Lcore conf */ +struct lcore_conf { + uint16_t n_rx_queue; + struct lcore_rx_queue rx_queue_list[MAX_RX_QUEUE_PER_LCORE]; +} __rte_cache_aligned; + +static struct lcore_conf lcore_conf[RTE_MAX_LCORE]; + +struct lcore_params { + uint16_t port_id; + uint8_t queue_id; + uint8_t lcore_id; +} __rte_cache_aligned; + +static struct lcore_params lcore_params_array[MAX_LCORE_PARAMS]; +static struct lcore_params lcore_params_array_default[] = { + {0, 0, 2}, {0, 1, 2}, {0, 2, 2}, {1, 0, 2}, {1, 1, 2}, + {1, 2, 2}, {2, 0, 2}, {3, 0, 3}, {3, 1, 3}, +}; + +static struct lcore_params *lcore_params = lcore_params_array_default; +static uint16_t nb_lcore_params = RTE_DIM(lcore_params_array_default); + +static struct rte_eth_conf port_conf = { + .rxmode = { + .mq_mode = ETH_MQ_RX_RSS, + .max_rx_pkt_len = RTE_ETHER_MAX_LEN, + .split_hdr_size = 0, + }, + .rx_adv_conf = { + .rss_conf = { + .rss_key = NULL, + .rss_hf = ETH_RSS_IP, + }, + }, + .txmode = { + .mq_mode = ETH_MQ_TX_NONE, + }, +}; + +static int +check_lcore_params(void) +{ + uint8_t queue, lcore; + int socketid; + uint16_t i; + + for (i = 0; i < nb_lcore_params; ++i) { + queue = lcore_params[i].queue_id; + if (queue >= MAX_RX_QUEUE_PER_PORT) { + printf("Invalid queue number: %hhu\n", queue); + return -1; + } + lcore = lcore_params[i].lcore_id; + if (!rte_lcore_is_enabled(lcore)) { + printf("Error: lcore %hhu is not enabled in lcore mask\n", + lcore); + return -1; + } + + if (lcore == rte_get_master_lcore()) { + printf("Error: lcore %u is master lcore\n", lcore); + return -1; + } + socketid = rte_lcore_to_socket_id(lcore); + if ((socketid != 0) && (numa_on == 0)) { + printf("Warning: lcore %hhu is on socket %d with numa off\n", + lcore, socketid); + } + } + + return 0; +} + +static int +check_port_config(void) +{ + uint16_t portid; + uint16_t i; + + for (i = 0; i < nb_lcore_params; ++i) { + portid = lcore_params[i].port_id; + if ((enabled_port_mask & (1 << portid)) == 0) { + printf("Port %u is not enabled in port mask\n", portid); + return -1; + } + if (!rte_eth_dev_is_valid_port(portid)) { + printf("Port %u is not present on the board\n", portid); + return -1; + } + } + + return 0; +} + +static int +init_lcore_rx_queues(void) +{ + uint16_t i, nb_rx_queue; + uint8_t lcore; + + for (i = 0; i < nb_lcore_params; ++i) { + lcore = lcore_params[i].lcore_id; + nb_rx_queue = lcore_conf[lcore].n_rx_queue; + if (nb_rx_queue >= MAX_RX_QUEUE_PER_LCORE) { + printf("Error: too many queues (%u) for lcore: %u\n", + (unsigned int)nb_rx_queue + 1, + (unsigned int)lcore); + return -1; + } + + lcore_conf[lcore].rx_queue_list[nb_rx_queue].port_id = + lcore_params[i].port_id; + lcore_conf[lcore].rx_queue_list[nb_rx_queue].queue_id = + lcore_params[i].queue_id; + lcore_conf[lcore].n_rx_queue++; + } + + return 0; +} + +/* Display usage */ +static void +print_usage(const char *prgname) +{ + fprintf(stderr, + "%s [EAL options] --" + " -p PORTMASK" + " [-P]" + " [-E]" + " [-L]" + " --config (port,queue,lcore)[,(port,queue,lcore)]" + " [--eth-dest=X,MM:MM:MM:MM:MM:MM]" + " [--enable-jumbo [--max-pkt-len PKTLEN]]" + " [--no-numa]" + " [--per-port-pool]\n\n" + + " -p PORTMASK: Hexadecimal bitmask of ports to configure\n" + " -P : Enable promiscuous mode\n" + " --config (port,queue,lcore): Rx queue configuration\n" + " --eth-dest=X,MM:MM:MM:MM:MM:MM: Ethernet destination for " + "port X\n" + " --enable-jumbo: Enable jumbo frames\n" + " --max-pkt-len: Under the premise of enabling jumbo,\n" + " maximum packet length in decimal (64-9600)\n" + " --no-numa: Disable numa awareness\n" + " --per-port-pool: Use separate buffer pool per port\n\n", + prgname); +} + +static int +parse_max_pkt_len(const char *pktlen) +{ + unsigned long len; + char *end = NULL; + + /* Parse decimal string */ + len = strtoul(pktlen, &end, 10); + if ((pktlen[0] == '\0') || (end == NULL) || (*end != '\0')) + return -1; + + if (len == 0) + return -1; + + return len; +} + +static int +parse_portmask(const char *portmask) +{ + char *end = NULL; + unsigned long pm; + + /* Parse hexadecimal string */ + pm = strtoul(portmask, &end, 16); + if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) + return -1; + + if (pm == 0) + return -1; + + return pm; +} + +static int +parse_config(const char *q_arg) +{ + enum fieldnames { FLD_PORT = 0, FLD_QUEUE, FLD_LCORE, _NUM_FLD }; + unsigned long int_fld[_NUM_FLD]; + const char *p, *p0 = q_arg; + char *str_fld[_NUM_FLD]; + uint32_t size; + char s[256]; + char *end; + int i; + + nb_lcore_params = 0; + + while ((p = strchr(p0, '(')) != NULL) { + ++p; + p0 = strchr(p, ')'); + if (p0 == NULL) + return -1; + + size = p0 - p; + if (size >= sizeof(s)) + return -1; + + snprintf(s, sizeof(s), "%.*s", size, p); + if (rte_strsplit(s, sizeof(s), str_fld, _NUM_FLD, ',') != + _NUM_FLD) + return -1; + for (i = 0; i < _NUM_FLD; i++) { + errno = 0; + int_fld[i] = strtoul(str_fld[i], &end, 0); + if (errno != 0 || end == str_fld[i] || int_fld[i] > 255) + return -1; + } + if (nb_lcore_params >= MAX_LCORE_PARAMS) { + printf("Exceeded max number of lcore params: %hu\n", + nb_lcore_params); + return -1; + } + lcore_params_array[nb_lcore_params].port_id = + (uint8_t)int_fld[FLD_PORT]; + lcore_params_array[nb_lcore_params].queue_id = + (uint8_t)int_fld[FLD_QUEUE]; + lcore_params_array[nb_lcore_params].lcore_id = + (uint8_t)int_fld[FLD_LCORE]; + ++nb_lcore_params; + } + lcore_params = lcore_params_array; + + return 0; +} + +static void +parse_eth_dest(const char *optarg) +{ + uint8_t c, *dest, peer_addr[6]; + uint16_t portid; + char *port_end; + + errno = 0; + portid = strtoul(optarg, &port_end, 10); + if (errno != 0 || port_end == optarg || *port_end++ != ',') + rte_exit(EXIT_FAILURE, "Invalid eth-dest: %s", optarg); + if (portid >= RTE_MAX_ETHPORTS) + rte_exit(EXIT_FAILURE, + "eth-dest: port %d >= RTE_MAX_ETHPORTS(%d)\n", portid, + RTE_MAX_ETHPORTS); + + if (cmdline_parse_etheraddr(NULL, port_end, &peer_addr, + sizeof(peer_addr)) < 0) + rte_exit(EXIT_FAILURE, "Invalid ethernet address: %s\n", + port_end); + dest = (uint8_t *)&dest_eth_addr[portid]; + for (c = 0; c < 6; c++) + dest[c] = peer_addr[c]; + *(uint64_t *)(val_eth + portid) = dest_eth_addr[portid]; +} + +#define MAX_JUMBO_PKT_LEN 9600 +#define MEMPOOL_CACHE_SIZE 256 + +static const char short_options[] = "p:" /* portmask */ + "P" /* promiscuous */ + "L" /* enable long prefix match */ + "E" /* enable exact match */ + ; + +#define CMD_LINE_OPT_CONFIG "config" +#define CMD_LINE_OPT_ETH_DEST "eth-dest" +#define CMD_LINE_OPT_NO_NUMA "no-numa" +#define CMD_LINE_OPT_ENABLE_JUMBO "enable-jumbo" +#define CMD_LINE_OPT_PER_PORT_POOL "per-port-pool" +enum { + /* Long options mapped to a short option */ + + /* First long only option value must be >= 256, so that we won't + * conflict with short options + */ + CMD_LINE_OPT_MIN_NUM = 256, + CMD_LINE_OPT_CONFIG_NUM, + CMD_LINE_OPT_ETH_DEST_NUM, + CMD_LINE_OPT_NO_NUMA_NUM, + CMD_LINE_OPT_ENABLE_JUMBO_NUM, + CMD_LINE_OPT_PARSE_PER_PORT_POOL, +}; + +static const struct option lgopts[] = { + {CMD_LINE_OPT_CONFIG, 1, 0, CMD_LINE_OPT_CONFIG_NUM}, + {CMD_LINE_OPT_ETH_DEST, 1, 0, CMD_LINE_OPT_ETH_DEST_NUM}, + {CMD_LINE_OPT_NO_NUMA, 0, 0, CMD_LINE_OPT_NO_NUMA_NUM}, + {CMD_LINE_OPT_ENABLE_JUMBO, 0, 0, CMD_LINE_OPT_ENABLE_JUMBO_NUM}, + {CMD_LINE_OPT_PER_PORT_POOL, 0, 0, CMD_LINE_OPT_PARSE_PER_PORT_POOL}, + {NULL, 0, 0, 0}, +}; + +/* + * This expression is used to calculate the number of mbufs needed + * depending on user input, taking into account memory for rx and + * tx hardware rings, cache per lcore and mtable per port per lcore. + * RTE_MAX is used to ensure that NB_MBUF never goes below a minimum + * value of 8192 + */ +#define NB_MBUF(nports) \ + RTE_MAX((nports * nb_rx_queue * nb_rxd + \ + nports * nb_lcores * RTE_GRAPH_BURST_SIZE + \ + nports * n_tx_queue * nb_txd + \ + nb_lcores * MEMPOOL_CACHE_SIZE), 8192u) + +/* Parse the argument given in the command line of the application */ +static int +parse_args(int argc, char **argv) +{ + char *prgname = argv[0]; + int option_index; + char **argvopt; + int opt, ret; + + argvopt = argv; + + /* Error or normal output strings. */ + while ((opt = getopt_long(argc, argvopt, short_options, lgopts, + &option_index)) != EOF) { + + switch (opt) { + /* Portmask */ + case 'p': + enabled_port_mask = parse_portmask(optarg); + if (enabled_port_mask == 0) { + fprintf(stderr, "Invalid portmask\n"); + print_usage(prgname); + return -1; + } + break; + + case 'P': + promiscuous_on = 1; + break; + + /* Long options */ + case CMD_LINE_OPT_CONFIG_NUM: + ret = parse_config(optarg); + if (ret) { + fprintf(stderr, "Invalid config\n"); + print_usage(prgname); + return -1; + } + break; + + case CMD_LINE_OPT_ETH_DEST_NUM: + parse_eth_dest(optarg); + break; + + case CMD_LINE_OPT_NO_NUMA_NUM: + numa_on = 0; + break; + + case CMD_LINE_OPT_ENABLE_JUMBO_NUM: { + const struct option lenopts = {"max-pkt-len", + required_argument, 0, 0}; + + port_conf.rxmode.offloads |= DEV_RX_OFFLOAD_JUMBO_FRAME; + port_conf.txmode.offloads |= DEV_TX_OFFLOAD_MULTI_SEGS; + + /* + * if no max-pkt-len set, use the default + * value RTE_ETHER_MAX_LEN. + */ + if (getopt_long(argc, argvopt, "", &lenopts, + &option_index) == 0) { + ret = parse_max_pkt_len(optarg); + if (ret < 64 || ret > MAX_JUMBO_PKT_LEN) { + fprintf(stderr, "Invalid maximum " + "packet length\n"); + print_usage(prgname); + return -1; + } + port_conf.rxmode.max_rx_pkt_len = ret; + } + break; + } + + case CMD_LINE_OPT_PARSE_PER_PORT_POOL: + printf("Per port buffer pool is enabled\n"); + per_port_pool = 1; + break; + + default: + print_usage(prgname); + return -1; + } + } + + if (optind >= 0) + argv[optind - 1] = prgname; + ret = optind - 1; + optind = 1; /* Reset getopt lib */ + + return ret; +} + +static void +signal_handler(int signum) +{ + if (signum == SIGINT || signum == SIGTERM) { + printf("\n\nSignal %d received, preparing to exit...\n", + signum); + force_quit = true; + } +} + +int +main(int argc, char **argv) +{ + uint16_t portid; + int ret; + + /* Init EAL */ + ret = rte_eal_init(argc, argv); + if (ret < 0) + rte_exit(EXIT_FAILURE, "Invalid EAL parameters\n"); + argc -= ret; + argv += ret; + + force_quit = false; + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + + /* Pre-init dst MACs for all ports to 02:00:00:00:00:xx */ + for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { + dest_eth_addr[portid] = + RTE_ETHER_LOCAL_ADMIN_ADDR + ((uint64_t)portid << 40); + *(uint64_t *)(val_eth + portid) = dest_eth_addr[portid]; + } + + /* Parse application arguments (after the EAL ones) */ + ret = parse_args(argc, argv); + if (ret < 0) + rte_exit(EXIT_FAILURE, "Invalid L3FWD_GRAPH parameters\n"); + + if (check_lcore_params() < 0) + rte_exit(EXIT_FAILURE, "check_lcore_params() failed\n"); + + ret = init_lcore_rx_queues(); + if (ret < 0) + rte_exit(EXIT_FAILURE, "init_lcore_rx_queues() failed\n"); + + if (check_port_config() < 0) + rte_exit(EXIT_FAILURE, "check_port_config() failed\n"); + + printf("Bye...\n"); + + return ret; +} diff --git a/examples/l3fwd-graph/meson.build b/examples/l3fwd-graph/meson.build new file mode 100644 index 000000000..a816bd890 --- /dev/null +++ b/examples/l3fwd-graph/meson.build @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(C) 2020 Marvell International Ltd. + +# meson file, for building this example as part of a main DPDK build. +# +# To build this example as a standalone application with an already-installed +# DPDK instance, use 'make' + +deps += ['graph', 'eal', 'lpm', 'ethdev', 'node' ] +sources = files( + 'main.c' +) +allow_experimental_apis = true diff --git a/examples/meson.build b/examples/meson.build index 1f2b6f516..3b540012f 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -2,8 +2,10 @@ # Copyright(c) 2017-2019 Intel Corporation driver_libs = [] +node_libs = [] if get_option('default_library') == 'static' driver_libs = dpdk_drivers + node_libs = dpdk_graph_nodes endif execinfo = cc.find_library('execinfo', required: false) @@ -23,7 +25,7 @@ all_examples = [ 'l2fwd', 'l2fwd-cat', 'l2fwd-event', 'l2fwd-crypto', 'l2fwd-jobstats', 'l2fwd-keepalive', 'l3fwd', - 'l3fwd-acl', 'l3fwd-power', + 'l3fwd-acl', 'l3fwd-power', 'l3fwd-graph', 'link_status_interrupt', 'multi_process/client_server_mp/mp_client', 'multi_process/client_server_mp/mp_server', @@ -99,7 +101,7 @@ foreach example: examples endif executable('dpdk-' + name, sources, include_directories: includes, - link_whole: driver_libs, + link_whole: driver_libs + node_libs, link_args: dpdk_extra_ldflags, c_args: cflags, dependencies: dep_objs) From patchwork Wed Mar 18 21:35:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66919 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id F2450A0580; Wed, 18 Mar 2020 22:39:51 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id A81A11C06D; Wed, 18 Mar 2020 22:37:06 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by dpdk.org (Postfix) with ESMTP id 9DE241C06D for ; Wed, 18 Mar 2020 22:37:04 +0100 (CET) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILUsFY003319; Wed, 18 Mar 2020 14:37:02 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=YymAPkemPiYohTkqYpIwXbpzCI7RWc3+lCg28zNFd/8=; b=GTgv4n/AeOULNAsXzvRvHVhOfSGfIXuS36ZgLGIWaZLuqm4I6ho9Eyfee6SakFFBPw0c Jg3FF1aTr6svTSSBEArPEGbKqgwDoCc5791QCoCljQqDo/36djNGbKZCYKSxb/8DdD73 1GnV3SyFbe9v05mgkQouaXyHkuVRErTpBTRVoPbMjPSOjw51YPn+hEjr2lepNPouZ6Qa 6hsN4aHVJc0VtBaq0a/o/zVtJrEAq8f5vgipXFG3p6JZ86BsEx7NGJ7iea7/zZjw1zn5 wSw1cqED2HHrVfsd+lb4CUud5ZW7MM06jvhtFikR/bXxcTGXpYc9r0UNqBhfB/lyaOAP pg== Received: from sc-exch04.marvell.com ([199.233.58.184]) by mx0a-0016f401.pphosted.com with ESMTP id 2yu8pqmrff-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:37:02 -0700 Received: from DC5-EXCH01.marvell.com (10.69.176.38) by SC-EXCH04.marvell.com (10.93.176.84) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:37:01 -0700 Received: from SC-EXCH03.marvell.com (10.93.176.83) by DC5-EXCH01.marvell.com (10.69.176.38) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:37:00 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:37:00 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id 1BC473F703F; Wed, 18 Mar 2020 14:36:55 -0700 (PDT) From: To: Marko Kovacevic , Ori Kam , Bruce Richardson , Radu Nicolau , Akhil Goyal , Tomasz Kantecki , Sunil Kumar Kori , "Pavan Nikhilesh" , Nithin Dabilpuram CC: , , , , , Date: Thu, 19 Mar 2020 03:05:50 +0530 Message-ID: <20200318213551.3489504-26-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 25/26] l3fwd-graph: add ethdev configuration changes X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Nithin Dabilpuram Add changes to ethdev port and queue configuration based on command line parameters for l3fwd graph application. Signed-off-by: Nithin Dabilpuram --- examples/l3fwd-graph/main.c | 350 +++++++++++++++++++++++++++++++++++- 1 file changed, 349 insertions(+), 1 deletion(-) diff --git a/examples/l3fwd-graph/main.c b/examples/l3fwd-graph/main.c index 8cee8bebd..436987877 100644 --- a/examples/l3fwd-graph/main.c +++ b/examples/l3fwd-graph/main.c @@ -19,8 +19,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -48,6 +50,10 @@ #define NB_SOCKETS 8 +/* Static global variables used within this file. */ +static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; +static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; + /**< Ports set in promiscuous mode off by default. */ static int promiscuous_on; @@ -59,6 +65,7 @@ static volatile bool force_quit; /* Ethernet addresses of ports */ static uint64_t dest_eth_addr[RTE_MAX_ETHPORTS]; +static struct rte_ether_addr ports_eth_addr[RTE_MAX_ETHPORTS]; xmm_t val_eth[RTE_MAX_ETHPORTS]; /* Mask of enabled ports */ @@ -109,6 +116,8 @@ static struct rte_eth_conf port_conf = { }, }; +static struct rte_mempool *pktmbuf_pool[RTE_MAX_ETHPORTS][NB_SOCKETS]; + static int check_lcore_params(void) { @@ -164,6 +173,27 @@ check_port_config(void) return 0; } +static uint8_t +get_port_n_rx_queues(const uint16_t port) +{ + int queue = -1; + uint16_t i; + + for (i = 0; i < nb_lcore_params; ++i) { + if (lcore_params[i].port_id == port) { + if (lcore_params[i].queue_id == queue + 1) + queue = lcore_params[i].queue_id; + else + rte_exit(EXIT_FAILURE, + "Queue ids of the port %d must be" + " in sequence and must start with 0\n", + lcore_params[i].port_id); + } + } + + return (uint8_t)(++queue); +} + static int init_lcore_rx_queues(void) { @@ -473,6 +503,120 @@ parse_args(int argc, char **argv) return ret; } +static void +print_ethaddr(const char *name, const struct rte_ether_addr *eth_addr) +{ + char buf[RTE_ETHER_ADDR_FMT_SIZE]; + rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr); + printf("%s%s", name, buf); +} + +static int +init_mem(uint16_t portid, uint32_t nb_mbuf) +{ + uint32_t lcore_id; + int socketid; + char s[64]; + + for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { + if (rte_lcore_is_enabled(lcore_id) == 0) + continue; + + if (numa_on) + socketid = rte_lcore_to_socket_id(lcore_id); + else + socketid = 0; + + if (socketid >= NB_SOCKETS) { + rte_exit(EXIT_FAILURE, + "Socket %d of lcore %u is out of range %d\n", + socketid, lcore_id, NB_SOCKETS); + } + + if (pktmbuf_pool[portid][socketid] == NULL) { + snprintf(s, sizeof(s), "mbuf_pool_%d:%d", portid, + socketid); + /* Create a pool with priv size of a cacheline */ + pktmbuf_pool[portid][socketid] = + rte_pktmbuf_pool_create( + s, nb_mbuf, MEMPOOL_CACHE_SIZE, + RTE_CACHE_LINE_SIZE, + RTE_MBUF_DEFAULT_BUF_SIZE, socketid); + if (pktmbuf_pool[portid][socketid] == NULL) + rte_exit(EXIT_FAILURE, + "Cannot init mbuf pool on socket %d\n", + socketid); + else + printf("Allocated mbuf pool on socket %d\n", + socketid); + } + } + + return 0; +} + +/* Check the link status of all ports in up to 9s, and print them finally */ +static void +check_all_ports_link_status(uint32_t port_mask) +{ +#define CHECK_INTERVAL 100 /* 100ms */ +#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ + uint8_t count, all_ports_up, print_flag = 0; + struct rte_eth_link link; + uint16_t portid; + + printf("\nChecking link status"); + fflush(stdout); + for (count = 0; count <= MAX_CHECK_TIME; count++) { + if (force_quit) + return; + all_ports_up = 1; + RTE_ETH_FOREACH_DEV(portid) + { + if (force_quit) + return; + if ((port_mask & (1 << portid)) == 0) + continue; + memset(&link, 0, sizeof(link)); + rte_eth_link_get_nowait(portid, &link); + /* Print link status if flag set */ + if (print_flag == 1) { + if (link.link_status) + printf("Port%d Link Up. Speed %u Mbps " + "-%s\n", + portid, link.link_speed, + (link.link_duplex == + ETH_LINK_FULL_DUPLEX) + ? ("full-duplex") + : ("half-duplex\n")); + else + printf("Port %d Link Down\n", portid); + continue; + } + /* Clear all_ports_up flag if any link down */ + if (link.link_status == ETH_LINK_DOWN) { + all_ports_up = 0; + break; + } + } + /* After finally printing all link status, get out */ + if (print_flag == 1) + break; + + if (all_ports_up == 0) { + printf("."); + fflush(stdout); + rte_delay_ms(CHECK_INTERVAL); + } + + /* Set the print_flag if all ports up or timeout */ + if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { + print_flag = 1; + printf("Done\n"); + } + } +} + static void signal_handler(int signum) { @@ -486,7 +630,14 @@ signal_handler(int signum) int main(int argc, char **argv) { - uint16_t portid; + uint8_t nb_rx_queue, queue, socketid; + struct rte_eth_dev_info dev_info; + uint32_t n_tx_queue, nb_lcores; + struct rte_eth_txconf *txconf; + uint16_t queueid, portid; + struct lcore_conf *qconf; + uint32_t lcore_id; + uint32_t nb_ports; int ret; /* Init EAL */ @@ -522,6 +673,203 @@ main(int argc, char **argv) if (check_port_config() < 0) rte_exit(EXIT_FAILURE, "check_port_config() failed\n"); + nb_ports = rte_eth_dev_count_avail(); + nb_lcores = rte_lcore_count(); + + /* Initialize all ports */ + RTE_ETH_FOREACH_DEV(portid) + { + struct rte_eth_conf local_port_conf = port_conf; + + /* Skip ports that are not enabled */ + if ((enabled_port_mask & (1 << portid)) == 0) { + printf("\nSkipping disabled port %d\n", portid); + continue; + } + + /* Init port */ + printf("Initializing port %d ... ", portid); + fflush(stdout); + + nb_rx_queue = get_port_n_rx_queues(portid); + n_tx_queue = nb_lcores; + if (n_tx_queue > MAX_TX_QUEUE_PER_PORT) + n_tx_queue = MAX_TX_QUEUE_PER_PORT; + printf("Creating queues: nb_rxq=%d nb_txq=%u... ", + nb_rx_queue, n_tx_queue); + + rte_eth_dev_info_get(portid, &dev_info); + if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) + local_port_conf.txmode.offloads |= + DEV_TX_OFFLOAD_MBUF_FAST_FREE; + + local_port_conf.rx_adv_conf.rss_conf.rss_hf &= + dev_info.flow_type_rss_offloads; + if (local_port_conf.rx_adv_conf.rss_conf.rss_hf != + port_conf.rx_adv_conf.rss_conf.rss_hf) { + printf("Port %u modified RSS hash function based on " + "hardware support," + "requested:%#" PRIx64 " configured:%#" PRIx64 + "\n", + portid, port_conf.rx_adv_conf.rss_conf.rss_hf, + local_port_conf.rx_adv_conf.rss_conf.rss_hf); + } + + ret = rte_eth_dev_configure(portid, nb_rx_queue, + n_tx_queue, &local_port_conf); + if (ret < 0) + rte_exit(EXIT_FAILURE, + "Cannot configure device: err=%d, port=%d\n", + ret, portid); + + ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, + &nb_txd); + if (ret < 0) + rte_exit(EXIT_FAILURE, + "Cannot adjust number of descriptors: err=%d, " + "port=%d\n", + ret, portid); + + rte_eth_macaddr_get(portid, &ports_eth_addr[portid]); + print_ethaddr(" Address:", &ports_eth_addr[portid]); + printf(", "); + print_ethaddr( + "Destination:", + (const struct rte_ether_addr *)&dest_eth_addr[portid]); + printf(", "); + + /* + * prepare src MACs for each port. + */ + rte_ether_addr_copy( + &ports_eth_addr[portid], + (struct rte_ether_addr *)(val_eth + portid) + 1); + + /* Init memory */ + if (!per_port_pool) { + /* portid = 0; this is *not* signifying the first port, + * rather, it signifies that portid is ignored. + */ + ret = init_mem(0, NB_MBUF(nb_ports)); + } else { + ret = init_mem(portid, NB_MBUF(1)); + } + if (ret < 0) + rte_exit(EXIT_FAILURE, "init_mem() failed\n"); + + /* Init one TX queue per couple (lcore,port) */ + queueid = 0; + for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { + if (rte_lcore_is_enabled(lcore_id) == 0) + continue; + + qconf = &lcore_conf[lcore_id]; + + if (numa_on) + socketid = (uint8_t)rte_lcore_to_socket_id( + lcore_id); + else + socketid = 0; + + printf("txq=%u,%d,%d ", lcore_id, queueid, socketid); + fflush(stdout); + + txconf = &dev_info.default_txconf; + txconf->offloads = local_port_conf.txmode.offloads; + ret = rte_eth_tx_queue_setup(portid, queueid, nb_txd, + socketid, txconf); + if (ret < 0) + rte_exit(EXIT_FAILURE, + "rte_eth_tx_queue_setup: err=%d, " + "port=%d\n", + ret, portid); + queueid++; + } + + printf("\n"); + } + + for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { + if (rte_lcore_is_enabled(lcore_id) == 0) + continue; + qconf = &lcore_conf[lcore_id]; + printf("\nInitializing rx queues on lcore %u ... ", lcore_id); + fflush(stdout); + /* Init RX queues */ + for (queue = 0; queue < qconf->n_rx_queue; ++queue) { + struct rte_eth_rxconf rxq_conf; + + portid = qconf->rx_queue_list[queue].port_id; + queueid = qconf->rx_queue_list[queue].queue_id; + + if (numa_on) + socketid = (uint8_t)rte_lcore_to_socket_id( + lcore_id); + else + socketid = 0; + + printf("rxq=%d,%d,%d ", portid, queueid, socketid); + fflush(stdout); + + rte_eth_dev_info_get(portid, &dev_info); + rxq_conf = dev_info.default_rxconf; + rxq_conf.offloads = port_conf.rxmode.offloads; + if (!per_port_pool) + ret = rte_eth_rx_queue_setup( + portid, queueid, nb_rxd, socketid, + &rxq_conf, pktmbuf_pool[0][socketid]); + else + ret = rte_eth_rx_queue_setup( + portid, queueid, nb_rxd, socketid, + &rxq_conf, + pktmbuf_pool[portid][socketid]); + if (ret < 0) + rte_exit(EXIT_FAILURE, + "rte_eth_rx_queue_setup: err=%d, " + "port=%d\n", + ret, portid); + + } + } + + printf("\n"); + + /* Start ports */ + RTE_ETH_FOREACH_DEV(portid) + { + if ((enabled_port_mask & (1 << portid)) == 0) + continue; + + /* Start device */ + ret = rte_eth_dev_start(portid); + if (ret < 0) + rte_exit(EXIT_FAILURE, + "rte_eth_dev_start: err=%d, port=%d\n", ret, + portid); + + /* + * If enabled, put device in promiscuous mode. + * This allows IO forwarding mode to forward packets + * to itself through 2 cross-connected ports of the + * target machine. + */ + if (promiscuous_on) + rte_eth_promiscuous_enable(portid); + } + + printf("\n"); + + check_all_ports_link_status(enabled_port_mask); + + /* Stop ports */ + RTE_ETH_FOREACH_DEV(portid) { + if ((enabled_port_mask & (1 << portid)) == 0) + continue; + printf("Closing port %d...", portid); + rte_eth_dev_stop(portid); + rte_eth_dev_close(portid); + printf(" Done\n"); + } printf("Bye...\n"); return ret; From patchwork Wed Mar 18 21:35:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerin Jacob Kollanukkaran X-Patchwork-Id: 66920 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 5F06CA057D; Wed, 18 Mar 2020 22:40:03 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 144131C122; Wed, 18 Mar 2020 22:37:10 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) by dpdk.org (Postfix) with ESMTP id A473C1C122 for ; Wed, 18 Mar 2020 22:37:08 +0100 (CET) Received: from pps.filterd (m0045851.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 02ILVPcI013826; Wed, 18 Mar 2020 14:37:07 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=cVckand9r0/Jr1ZOG/cJPu2sIw6GxkaHUkL6apEIsAI=; b=OomCpZPuZhHQMnL8anrJmzvyCwoanS4L4GC7/jGt+0crEFvhxA/qeeC9PRwZpRkNrVsO fW0N6BDx8X9a8fhOcfCEQ6L7UWeZdy9gITGAItF9pXsWoHsxHT0dxeobd5AfaE5L+28P Ntj898PrAwteULUuf/zzuBlwSNLru34mViYAaLAdRJbrxoigHDLwW7cEMvl2TjuTBf2O YKU8MXb+QvEvq6FMfi/g07xfrYcduLjbLubml1cKuaiDFJUFtTEK5GzwozqRYhUO0Lj1 bHnPs8d6N7z9dCL0L/GclwYbWQsjggOetz/Vatps41qSMyl87cFRS10g8FHzErgvEAhO tw== Received: from sc-exch01.marvell.com ([199.233.58.181]) by mx0b-0016f401.pphosted.com with ESMTP id 2yu9rpcc7y-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Wed, 18 Mar 2020 14:37:07 -0700 Received: from SC-EXCH01.marvell.com (10.93.176.81) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Wed, 18 Mar 2020 14:37:05 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Wed, 18 Mar 2020 14:37:05 -0700 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id 847843F704E; Wed, 18 Mar 2020 14:37:01 -0700 (PDT) From: To: Marko Kovacevic , Ori Kam , Bruce Richardson , Radu Nicolau , Akhil Goyal , Tomasz Kantecki , Sunil Kumar Kori , "Pavan Nikhilesh" , Nithin Dabilpuram CC: , , , , , Date: Thu, 19 Mar 2020 03:05:51 +0530 Message-ID: <20200318213551.3489504-27-jerinj@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200318213551.3489504-1-jerinj@marvell.com> References: <20200318213551.3489504-1-jerinj@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.645 definitions=2020-03-18_07:2020-03-18, 2020-03-18 signatures=0 Subject: [dpdk-dev] [PATCH v1 26/26] l3fwd-graph: add graph config and main loop X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Nithin Dabilpuram Add graph creation, configuration logic and graph main loop. This graph main loop is run on every slave lcore and calls rte_graph_walk() to walk over lcore specific rte_graph. Master core accumulates and prints graph walk stats of all the lcore's graph's. Signed-off-by: Nithin Dabilpuram --- examples/l3fwd-graph/main.c | 241 +++++++++++++++++++++++++++++++++++- 1 file changed, 239 insertions(+), 2 deletions(-) diff --git a/examples/l3fwd-graph/main.c b/examples/l3fwd-graph/main.c index 436987877..104a4d8db 100644 --- a/examples/l3fwd-graph/main.c +++ b/examples/l3fwd-graph/main.c @@ -22,9 +22,13 @@ #include #include #include +#include +#include #include #include #include +#include +#include #include #include #include @@ -74,12 +78,17 @@ static uint32_t enabled_port_mask; struct lcore_rx_queue { uint16_t port_id; uint8_t queue_id; + char node_name[RTE_NODE_NAMESIZE]; }; /* Lcore conf */ struct lcore_conf { uint16_t n_rx_queue; struct lcore_rx_queue rx_queue_list[MAX_RX_QUEUE_PER_LCORE]; + + struct rte_graph *graph; + char name[RTE_GRAPH_NAMESIZE]; + rte_graph_t graph_id; } __rte_cache_aligned; static struct lcore_conf lcore_conf[RTE_MAX_LCORE]; @@ -118,6 +127,25 @@ static struct rte_eth_conf port_conf = { static struct rte_mempool *pktmbuf_pool[RTE_MAX_ETHPORTS][NB_SOCKETS]; +static struct rte_node_ethdev_config ethdev_conf[RTE_MAX_ETHPORTS]; + +struct ipv4_l3fwd_lpm_route { + uint32_t ip; + uint8_t depth; + uint8_t if_out; +}; + +#define IPV4_L3FWD_LPM_NUM_ROUTES \ + (sizeof(ipv4_l3fwd_lpm_route_array) / \ + sizeof(ipv4_l3fwd_lpm_route_array[0])) +/* 198.18.0.0/16 are set aside for RFC2544 benchmarking. */ +static struct ipv4_l3fwd_lpm_route ipv4_l3fwd_lpm_route_array[] = { + {RTE_IPV4(198, 18, 0, 0), 24, 0}, {RTE_IPV4(198, 18, 1, 0), 24, 1}, + {RTE_IPV4(198, 18, 2, 0), 24, 2}, {RTE_IPV4(198, 18, 3, 0), 24, 3}, + {RTE_IPV4(198, 18, 4, 0), 24, 4}, {RTE_IPV4(198, 18, 5, 0), 24, 5}, + {RTE_IPV4(198, 18, 6, 0), 24, 6}, {RTE_IPV4(198, 18, 7, 0), 24, 7}, +}; + static int check_lcore_params(void) { @@ -627,17 +655,87 @@ signal_handler(int signum) } } +static void +print_stats(void) +{ + const char topLeft[] = {27, '[', '1', ';', '1', 'H', '\0'}; + const char clr[] = {27, '[', '2', 'J', '\0'}; + struct rte_graph_cluster_stats_param s_param; + struct rte_graph_cluster_stats *stats; + const char *pattern = "worker_*"; + + /* Prepare stats object */ + memset(&s_param, 0, sizeof(s_param)); + s_param.f = stdout; + s_param.socket_id = SOCKET_ID_ANY; + s_param.graph_patterns = &pattern; + s_param.nb_graph_patterns = 1; + + stats = rte_graph_cluster_stats_create(&s_param); + if (stats == NULL) + rte_exit(EXIT_FAILURE, "Unable to create stats object\n"); + + while (!force_quit) { + /* Clear screen and move to top left */ + printf("%s%s", clr, topLeft); + rte_graph_cluster_stats_get(stats, 0); + rte_delay_ms(1E3); + } + + rte_graph_cluster_stats_destroy(stats); +} + +/* Main processing loop */ +static int +graph_main_loop(void *conf) +{ + struct lcore_conf *qconf; + struct rte_graph *graph; + uint32_t lcore_id; + + RTE_SET_USED(conf); + + lcore_id = rte_lcore_id(); + qconf = &lcore_conf[lcore_id]; + graph = qconf->graph; + + if (!graph) { + RTE_LOG(INFO, L3FWD_GRAPH, "Lcore %u has nothing to do\n", + lcore_id); + return 0; + } + + RTE_LOG(INFO, L3FWD_GRAPH, + "Entering main loop on lcore %u, graph %s(%p)\n", lcore_id, + qconf->name, graph); + + while (likely(!force_quit)) + rte_graph_walk(graph); + + return 0; +} + int main(int argc, char **argv) { + const char *node_patterns[64] = { + "ip4*", + "ethdev_tx-*", + "pkt_drop", + }; + uint8_t rewrite_data[2 * sizeof(struct rte_ether_addr)]; uint8_t nb_rx_queue, queue, socketid; + struct rte_graph_param graph_conf; struct rte_eth_dev_info dev_info; + uint32_t nb_ports, nb_conf = 0; uint32_t n_tx_queue, nb_lcores; struct rte_eth_txconf *txconf; - uint16_t queueid, portid; + uint16_t queueid, portid, i; struct lcore_conf *qconf; + uint16_t nb_patterns = 3; + uint16_t nb_graphs = 0; + uint8_t rewrite_len; uint32_t lcore_id; - uint32_t nb_ports; int ret; /* Init EAL */ @@ -786,6 +884,18 @@ main(int argc, char **argv) queueid++; } + /* Setup ethdev node config */ + ethdev_conf[nb_conf].port_id = portid; + ethdev_conf[nb_conf].num_rx_queues = nb_rx_queue; + ethdev_conf[nb_conf].num_tx_queues = n_tx_queue; + if (!per_port_pool) + ethdev_conf[nb_conf].mp = pktmbuf_pool[0]; + + else + ethdev_conf[nb_conf].mp = pktmbuf_pool[portid]; + ethdev_conf[nb_conf].mp_count = NB_SOCKETS; + + nb_conf++; printf("\n"); } @@ -829,11 +939,26 @@ main(int argc, char **argv) "port=%d\n", ret, portid); + /* Add this queue node to its graph */ + snprintf(qconf->rx_queue_list[queue].node_name, + RTE_NODE_NAMESIZE, "ethdev_rx-%u-%u", portid, + queueid); + } + + /* Alloc a graph to this lcore only if source exists */ + if (qconf->n_rx_queue) { + qconf->graph_id = nb_graphs; + nb_graphs++; } } printf("\n"); + /* Ethdev node config, skip rx queue mapping */ + ret = rte_node_eth_config(ethdev_conf, nb_conf, nb_graphs); + if (ret) + rte_exit(EXIT_FAILURE, "rte_node_eth_config: err=%d\n", ret); + /* Start ports */ RTE_ETH_FOREACH_DEV(portid) { @@ -861,6 +986,118 @@ main(int argc, char **argv) check_all_ports_link_status(enabled_port_mask); + /* Graph Initialization */ + memset(&graph_conf, 0, sizeof(graph_conf)); + graph_conf.node_patterns = node_patterns; + + for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { + rte_graph_t graph_id; + rte_edge_t i; + + if (rte_lcore_is_enabled(lcore_id) == 0) + continue; + + qconf = &lcore_conf[lcore_id]; + + /* Skip graph creation if no source exists */ + if (!qconf->n_rx_queue) + continue; + + /* Add rx node patterns of this lcore */ + for (i = 0; i < qconf->n_rx_queue; i++) { + graph_conf.node_patterns[nb_patterns + i] = + qconf->rx_queue_list[i].node_name; + } + + graph_conf.nb_node_patterns = nb_patterns + i; + graph_conf.socket_id = rte_lcore_to_socket_id(lcore_id); + + snprintf(qconf->name, sizeof(qconf->name), "worker_%u", + lcore_id); + + graph_id = rte_graph_create(qconf->name, &graph_conf); + if (graph_id != qconf->graph_id) + rte_exit(EXIT_FAILURE, + "rte_graph_create(): graph_id=%d not " + " as expected for lcore %u(%u\n", + graph_id, lcore_id, qconf->graph_id); + + qconf->graph = rte_graph_lookup(qconf->name); + if (!qconf->graph) + rte_exit(EXIT_FAILURE, + "rte_graph_lookup(): graph %s not found\n", + qconf->name); + } + + memset(&rewrite_data, 0, sizeof(rewrite_data)); + rewrite_len = sizeof(rewrite_data); + + /* Add route to ip4 graph infra */ + for (i = 0; i < IPV4_L3FWD_LPM_NUM_ROUTES; i++) { + char route_str[INET6_ADDRSTRLEN * 4]; + char abuf[INET6_ADDRSTRLEN]; + struct in_addr in; + uint32_t dst_port; + uint16_t next_hop; + + /* Skip unused ports */ + if ((1 << ipv4_l3fwd_lpm_route_array[i].if_out & + enabled_port_mask) == 0) + continue; + + dst_port = ipv4_l3fwd_lpm_route_array[i].if_out; + next_hop = i; + + in.s_addr = htonl(ipv4_l3fwd_lpm_route_array[i].ip); + snprintf(route_str, sizeof(route_str), "%s / %d (%d)", + inet_ntop(AF_INET, &in, abuf, sizeof(abuf)), + ipv4_l3fwd_lpm_route_array[i].depth, + ipv4_l3fwd_lpm_route_array[i].if_out); + + ret = rte_node_ip4_route_add( + ipv4_l3fwd_lpm_route_array[i].ip, + ipv4_l3fwd_lpm_route_array[i].depth, next_hop, + RTE_NODE_IP4_LOOKUP_NEXT_REWRITE); + + if (ret < 0) + rte_exit(EXIT_FAILURE, + "Unable to add ip4 route %s to graph\n", + route_str); + + memcpy(rewrite_data, val_eth + dst_port, rewrite_len); + + /* Add next hop for a given destination */ + ret = rte_node_ip4_rewrite_add(next_hop, rewrite_data, + rewrite_len, dst_port); + if (ret < 0) + rte_exit(EXIT_FAILURE, + "Unable to add next hop %u for " + "route %s\n", + next_hop, route_str); + + RTE_LOG(INFO, L3FWD_GRAPH, "Added route %s, next_hop %u\n", + route_str, next_hop); + } + + /* Launch per-lcore init on every slave lcore */ + rte_eal_mp_remote_launch(graph_main_loop, NULL, SKIP_MASTER); + + /* Accumulate and print stats on master until exit */ + if (rte_graph_has_stats_feature()) + print_stats(); + + /* Wait for slave cores to exit */ + ret = 0; + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + ret = rte_eal_wait_lcore(lcore_id); + /* Destroy graph */ + rte_graph_destroy(lcore_conf[lcore_id].name); + if (ret < 0) { + ret = -1; + break; + } + } + /* Stop ports */ RTE_ETH_FOREACH_DEV(portid) { if ((enabled_port_mask & (1 << portid)) == 0)