From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 30ED245FD0; Fri, 3 Jan 2025 07:07:02 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 4336140615; Fri, 3 Jan 2025 07:06:35 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) by mails.dpdk.org (Postfix) with ESMTP id 59A8B402F2 for ; Fri, 3 Jan 2025 07:06:33 +0100 (CET) Received: from pps.filterd (m0431383.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 5034F5AI003128; Thu, 2 Jan 2025 22:06:30 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pfpt0220; bh=x EXww6iK4U85O5rHh4pfBzRY0qrbx+F9ke0duhJE0eU=; b=VglGDwaKBQA/KqWx8 2BcneT5lxT6fLeVuoPRQT4hyzhbi98aXDiv8Cx6r2pKxMQXZiFr6c5xogXDb9Ro8 sWnW2MNwOwiNXOPCEjw+nBOjCY6xuDRigvE9osarpTFfMecsiD4q6KTnIXXSaT73 GeWWo33Uz0gIVumO2rrWIGk1rg/UYEBau831y4SPWoGDEw0Nz+ySCKH7QBihadUP oyEW6ItWXfho4tLH/TOxogkHQ7ubikjk6aotFKJ1tRK5XJM6Nl9QEpZD5RUD1QdJ w+Hrr3ZhcVelJhAEzglgX+pQkPGFEFWgX2veLeZrJp6Sr540173Wk3bA1OiARE3+ M/2ag== Received: from dc6wp-exch02.marvell.com ([4.21.29.225]) by mx0b-0016f401.pphosted.com (PPS) with ESMTPS id 43x8pr84wc-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 02 Jan 2025 22:06:29 -0800 (PST) Received: from DC6WP-EXCH02.marvell.com (10.76.176.209) by DC6WP-EXCH02.marvell.com (10.76.176.209) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.4; Thu, 2 Jan 2025 22:06:29 -0800 Received: from maili.marvell.com (10.69.176.80) by DC6WP-EXCH02.marvell.com (10.76.176.209) with Microsoft SMTP Server id 15.2.1544.4 via Frontend Transport; Thu, 2 Jan 2025 22:06:29 -0800 Received: from cavium-PowerEdge-R640.. (unknown [10.28.36.207]) by maili.marvell.com (Postfix) with ESMTP id 656C13F7084; Thu, 2 Jan 2025 22:06:26 -0800 (PST) From: Nitin Saxena To: Jerin Jacob , Kiran Kumar K , Nithin Dabilpuram , Zhirun Yan , Robin Jarry , Christophe Fontaine CC: , Nitin Saxena Subject: [PATCH v6 4/4] app/graph: add custom feature nodes for ip4 output arc Date: Fri, 3 Jan 2025 11:36:07 +0530 Message-ID: <20250103060612.2671836-5-nsaxena@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250103060612.2671836-1-nsaxena@marvell.com> References: <20241014143401.3135897-1-nsaxena@marvell.com> <20250103060612.2671836-1-nsaxena@marvell.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain X-Proofpoint-GUID: U70vTAR4ICij6KY7Djj8JonlRUVVoyDM X-Proofpoint-ORIG-GUID: U70vTAR4ICij6KY7Djj8JonlRUVVoyDM X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.687,Hydra:6.0.235,FMLib:17.0.607.475 definitions=2020-10-13_15,2020-10-13_02,2020-04-07_01 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org - Added cmdline argument "--enable-graph-feature-arc" to call rte_graph_feature_arc_init() before rte_graph_create() which creates in-built arcs and feature nodes - Added custom feature nodes in app/graph which are added to ip4 output arc. - Custom features can be enabled/disabled at runtime on any ethdev via CLI. graph> help feature graph> feature enable graph> feature disable graph> graph stats show Signed-off-by: Nitin Saxena --- app/graph/commands.list | 6 ++ app/graph/feature.c | 141 ++++++++++++++++++++++++++++++ app/graph/feature.h | 13 +++ app/graph/graph.c | 4 + app/graph/ip4_output_hook.c | 169 ++++++++++++++++++++++++++++++++++++ app/graph/main.c | 15 +++- app/graph/meson.build | 2 + app/graph/module_api.h | 2 + 8 files changed, 351 insertions(+), 1 deletion(-) create mode 100644 app/graph/feature.c create mode 100644 app/graph/feature.h create mode 100644 app/graph/ip4_output_hook.c diff --git a/app/graph/commands.list b/app/graph/commands.list index c027f73b0e..49d81f50ae 100644 --- a/app/graph/commands.list +++ b/app/graph/commands.list @@ -31,3 +31,9 @@ help ipv6_lookup # Print help on ipv6_lo neigh add ipv4 ip mac # Add static neighbour for IPv4 neigh add ipv6 ip mac # Add static neighbour for IPv6 help neigh # Print help on neigh commands + +feature arcs # show all feature arcs +feature name show # Show feature arc details +feature enable arc_name feature_name interface # Enable feature on interface +feature disable arc_name feature_name interface # Disable feature on interface +help feature # Print help on feature command diff --git a/app/graph/feature.c b/app/graph/feature.c new file mode 100644 index 0000000000..2cf21b11ce --- /dev/null +++ b/app/graph/feature.c @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2025 Marvell International Ltd. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "module_api.h" + +static const char +cmd_feature_arcs_help[] = "feature arcs # Display all feature arcs"; + +static const char +cmd_feature_show_help[] = "feature show # Display features within an arc"; + +static const char +cmd_feature_enable_help[] = "feature enable "; + +static const char +cmd_feature_disable_help[] = "feature disable "; + +static void +feature_show(const char *arc_name) +{ + rte_graph_feature_arc_t _arc; + uint32_t length, count, i; + + length = strlen(conn->msg_out); + conn->msg_out += length; + + if (rte_graph_feature_arc_lookup_by_name(arc_name, &_arc) < 0) + return; + + count = rte_graph_feature_arc_num_features(_arc); + + if (count) { + snprintf(conn->msg_out, conn->msg_out_len_max, "\n%s%s%s\n", + "----------------------------- feature arc: ", + rte_graph_feature_arc_get(_arc)->feature_arc_name, + " -----------------------------"); + for (i = 0; i < count; i++) + snprintf(conn->msg_out + strlen(conn->msg_out), + conn->msg_out_len_max, "%s\n", + rte_graph_feature_arc_feature_to_name(_arc, i)); + } + length = strlen(conn->msg_out); + conn->msg_out_len_max -= length; +} + +static void +feature_arcs_show(void) +{ + uint32_t length, count, i; + char **names; + + length = strlen(conn->msg_out); + conn->msg_out += length; + + count = rte_graph_feature_arc_names_get(NULL); + + if (count) { + names = malloc(count); + if (!names) { + snprintf(conn->msg_out, conn->msg_out_len_max, "Failed to allocate memory\n"); + return; + } + count = rte_graph_feature_arc_names_get(names); + snprintf(conn->msg_out, conn->msg_out_len_max, "\n%s\n", + "----------------------------- feature arcs -----------------------------"); + for (i = 0; i < count; i++) + feature_show(names[i]); + free(names); + } + length = strlen(conn->msg_out); + conn->msg_out_len_max -= length; +} + +void +cmd_feature_parsed(void *parsed_result, __rte_unused struct cmdline *cl, + __rte_unused void *data) +{ + struct cmd_feature_result *res = parsed_result; + + feature_show(res->name); +} + + +void +cmd_feature_arcs_parsed(__rte_unused void *parsed_result, __rte_unused struct cmdline *cl, + __rte_unused void *data) +{ + feature_arcs_show(); +} + +void +cmd_feature_enable_parsed(void *parsed_result, __rte_unused struct cmdline *cl, + __rte_unused void *data) +{ + struct cmd_feature_enable_result *res = parsed_result; + rte_graph_feature_arc_t arc; + + if (!rte_graph_feature_arc_lookup_by_name(res->arc_name, &arc)) + rte_graph_feature_enable(arc, res->interface, res->feature_name, + res->interface, NULL); +} + +void +cmd_feature_disable_parsed(void *parsed_result, __rte_unused struct cmdline *cl, + __rte_unused void *data) +{ + struct cmd_feature_disable_result *res = parsed_result; + rte_graph_feature_arc_t arc; + + if (!rte_graph_feature_arc_lookup_by_name(res->arc_name, &arc)) + rte_graph_feature_disable(arc, res->interface, res->feature_name, NULL); + +} + +void +cmd_help_feature_parsed(__rte_unused void *parsed_result, __rte_unused struct cmdline *cl, + __rte_unused void *data) +{ + size_t len; + + len = strlen(conn->msg_out); + conn->msg_out += len; + snprintf(conn->msg_out, conn->msg_out_len_max, "\n%s\n%s\n%s\n%s\n%s\n", + "----------------------------- feature command help -----------------------------", + cmd_feature_arcs_help, cmd_feature_show_help, cmd_feature_enable_help, + cmd_feature_disable_help); + + len = strlen(conn->msg_out); + conn->msg_out_len_max -= len; +} diff --git a/app/graph/feature.h b/app/graph/feature.h new file mode 100644 index 0000000000..76393dabc6 --- /dev/null +++ b/app/graph/feature.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2025 Marvell International Ltd. + */ + +#ifndef APP_GRAPH_FEATURE_H +#define APP_GRAPH_FEATURE_H + +#include +#include + +int feature_enable(const char *arc_name, const char *feature_name, uint16_t portid); +int feature_disable(const char *arc_name, const char *feature_name, uint16_t portid); +#endif diff --git a/app/graph/graph.c b/app/graph/graph.c index 3af031cbaf..3ccd702ed9 100644 --- a/app/graph/graph.c +++ b/app/graph/graph.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "graph_priv.h" @@ -265,6 +266,9 @@ cmd_graph_start_parsed(__rte_unused void *parsed_result, __rte_unused struct cmd uint32_t nb_graphs = 0, nb_conf, i; int rc = -EINVAL; + if (app_graph_feature_arc_enabled()) + rte_graph_feature_arc_init(); + conf = graph_rxtx_node_config_get(&nb_conf, &nb_graphs); for (i = 0; i < MAX_GRAPH_USECASES; i++) { if (!strcmp(graph_config.usecases[i].name, "l3fwd")) { diff --git a/app/graph/ip4_output_hook.c b/app/graph/ip4_output_hook.c new file mode 100644 index 0000000000..1a389f1113 --- /dev/null +++ b/app/graph/ip4_output_hook.c @@ -0,0 +1,169 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2025 Marvell International Ltd. + */ + +#include +#include +#include + +#include "rte_node_ip4_api.h" + +#define IP4_OUTPUT_HOOK_FEATURE1_NAME "app_graph_ip4_output_hook_f1" +#define IP4_OUTPUT_HOOK_FEATURE2_NAME "app_graph_ip4_output_hook_f2" + +struct output_hook_node_ctx { + rte_graph_feature_arc_t out_arc; + uint16_t last_index; +}; + +#define OUTPUT_HOOK_FEATURE_ARC(ctx) \ + (((struct output_hook_node_ctx *)ctx)->out_arc) + +#define OUTPUT_HOOK_LAST_NEXT_INDEX(ctx) \ + (((struct output_hook_node_ctx *)ctx)->last_index) + +static int +__app_graph_ip4_output_hook_node_init(const struct rte_graph *graph, struct rte_node *node) +{ + rte_graph_feature_arc_t feature; + + RTE_SET_USED(graph); + + rte_graph_feature_arc_lookup_by_name(RTE_IP4_OUTPUT_FEATURE_ARC_NAME, &feature); + + OUTPUT_HOOK_FEATURE_ARC(node->ctx) = feature; + /* pkt_drop */ + OUTPUT_HOOK_LAST_NEXT_INDEX(node->ctx) = 0; + + return 0; +} + +static __rte_always_inline uint16_t +__app_graph_ip4_output_hook_node_process(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + struct rte_graph_feature_arc *arc = + rte_graph_feature_arc_get(OUTPUT_HOOK_FEATURE_ARC(node->ctx)); + int feat_dyn_off = rte_graph_feature_arc_mbuf_dynfield_offset_get(); + struct rte_graph_feature_arc_mbuf_dynfields *mbfields = NULL; + rte_graph_feature_data_t fdata; + void **to_next, **from; + uint16_t last_spec = 0; + rte_edge_t next_index; + struct rte_mbuf *mbuf; + uint16_t held = 0; + uint16_t next; + int i; + + /* Speculative next */ + next_index = OUTPUT_HOOK_LAST_NEXT_INDEX(node->ctx); + + from = objs; + to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs); + for (i = 0; i < nb_objs; i++) { + + mbuf = (struct rte_mbuf *)objs[i]; + + /* Send mbuf to next enabled feature */ + mbfields = rte_graph_feature_arc_mbuf_dynfields_get(mbuf, feat_dyn_off); + fdata = rte_graph_feature_data_next_feature_get(arc, mbfields->feature_data); + next = rte_graph_feature_data_edge_get(arc, fdata); + + if (unlikely(next_index != next)) { + /* 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, next, 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); + OUTPUT_HOOK_LAST_NEXT_INDEX(node->ctx) = next; + + return nb_objs; +} + +static int +app_graph_ip4_output_hook_node1_init(const struct rte_graph *graph, struct rte_node *node) +{ + return __app_graph_ip4_output_hook_node_init(graph, node); +} + +static __rte_always_inline uint16_t +app_graph_ip4_output_hook_node1_process(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + return __app_graph_ip4_output_hook_node_process(graph, node, objs, nb_objs); +} + +static struct rte_node_register app_graph_ip4_output_hook_node1 = { + .process = app_graph_ip4_output_hook_node1_process, + .init = app_graph_ip4_output_hook_node1_init, + .name = "app_graph_ip4_output_hook_node1", + .nb_edges = 1, + .next_nodes = { + [0] = "pkt_drop", + }, +}; + +RTE_NODE_REGISTER(app_graph_ip4_output_hook_node1); + +static int +app_graph_ip4_output_hook_node2_init(const struct rte_graph *graph, struct rte_node *node) +{ + return __app_graph_ip4_output_hook_node_init(graph, node); +} + +static __rte_always_inline uint16_t +app_graph_ip4_output_hook_node2_process(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + return __app_graph_ip4_output_hook_node_process(graph, node, objs, nb_objs); +} + +static struct rte_node_register app_graph_ip4_output_hook_node2 = { + .process = app_graph_ip4_output_hook_node2_process, + .init = app_graph_ip4_output_hook_node2_init, + .name = "app_graph_ip4_output_hook_node2", + .nb_edges = 1, + .next_nodes = { + [0] = "pkt_drop", + }, +}; + +RTE_NODE_REGISTER(app_graph_ip4_output_hook_node2); + +/* if feature1 */ +struct rte_graph_feature_register app_graph_ip4_output_hook_feature1 = { + .feature_name = IP4_OUTPUT_HOOK_FEATURE1_NAME, + .arc_name = RTE_IP4_OUTPUT_FEATURE_ARC_NAME, + /* Same as regular function */ + .feature_process_fn = app_graph_ip4_output_hook_node1_process, + .feature_node = &app_graph_ip4_output_hook_node1, + .runs_before = IP4_OUTPUT_HOOK_FEATURE2_NAME, +}; + +/* if feature2 (same as f1) */ +struct rte_graph_feature_register app_graph_ip4_output_hook_feature2 = { + .feature_name = IP4_OUTPUT_HOOK_FEATURE2_NAME, + .arc_name = RTE_IP4_OUTPUT_FEATURE_ARC_NAME, + /* Same as regular function */ + .feature_node = &app_graph_ip4_output_hook_node2, + .feature_process_fn = app_graph_ip4_output_hook_node2_process, +}; + +RTE_GRAPH_FEATURE_REGISTER(app_graph_ip4_output_hook_feature1); +RTE_GRAPH_FEATURE_REGISTER(app_graph_ip4_output_hook_feature2); diff --git a/app/graph/main.c b/app/graph/main.c index 465376425c..56294f2693 100644 --- a/app/graph/main.c +++ b/app/graph/main.c @@ -28,6 +28,7 @@ static struct app_params { struct conn_params conn; char *script_name; bool enable_graph_stats; + bool enable_feature_arc; } app = { .conn = { .welcome = "\nWelcome!\n\n", @@ -42,6 +43,7 @@ static struct app_params { }, .script_name = NULL, .enable_graph_stats = false, + .enable_feature_arc = false, }; static void @@ -59,6 +61,7 @@ app_args_parse(int argc, char **argv) struct option lgopts[] = { {"help", 0, 0, 'H'}, {"enable-graph-stats", 0, 0, 'g'}, + {"enable-graph-feature-arc", 0, 0, 'f'}, }; int h_present, p_present, s_present, n_args, i; char *app_name = argv[0]; @@ -81,7 +84,7 @@ app_args_parse(int argc, char **argv) p_present = 0; s_present = 0; - while ((opt = getopt_long(argc, argv, "h:p:s:", lgopts, &option_index)) != EOF) { + while ((opt = getopt_long(argc, argv, "h:p:s:f", lgopts, &option_index)) != EOF) { switch (opt) { case 'h': if (h_present) { @@ -142,6 +145,10 @@ app_args_parse(int argc, char **argv) "--enable-graph-stats"); break; + case 'f': + app.enable_feature_arc = true; + break; + case 'H': default: printf(usage, app_name); @@ -159,6 +166,12 @@ app_graph_stats_enabled(void) return app.enable_graph_stats; } +bool +app_graph_feature_arc_enabled(void) +{ + return app.enable_feature_arc; +} + bool app_graph_exit(void) { diff --git a/app/graph/meson.build b/app/graph/meson.build index 344e4a418f..d7e8c431ea 100644 --- a/app/graph/meson.build +++ b/app/graph/meson.build @@ -24,6 +24,8 @@ sources = files( 'mempool.c', 'neigh.c', 'utils.c', + 'feature.c', + 'ip4_output_hook.c' ) cmd_h = custom_target('commands_hdr', diff --git a/app/graph/module_api.h b/app/graph/module_api.h index b872872dc1..25f88e28de 100644 --- a/app/graph/module_api.h +++ b/app/graph/module_api.h @@ -20,6 +20,7 @@ #include "neigh.h" #include "route.h" #include "utils.h" +#include "feature.h" /* * Externs @@ -28,6 +29,7 @@ extern volatile bool force_quit; extern struct conn *conn; bool app_graph_stats_enabled(void); +bool app_graph_feature_arc_enabled(void); bool app_graph_exit(void); #endif -- 2.43.0