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 E6E35465EF; Mon, 21 Apr 2025 17:18:13 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id F3F4B4066C; Mon, 21 Apr 2025 17:17:45 +0200 (CEST) Received: from mx0a-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by mails.dpdk.org (Postfix) with ESMTP id 5B7F440673 for ; Mon, 21 Apr 2025 17:17:44 +0200 (CEST) Received: from pps.filterd (m0431384.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 53LAFTkX005784; Mon, 21 Apr 2025 08:17:41 -0700 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=m 0pt7fpuKSDHRRm5MIM2hdUQ7M5/z0owxCC/hXke0M4=; b=CzxUXKOHPUUFUAw3n gqmRKjzEepMHZToR0wnB+p6wf0JA8TJ20/FPtukAg3NsfqzEr9/WzJHkMaY6kJS5 yM2TiTqacEETMw8zj4qEW31fMZWlLJtPLohFaanWtYFjdxiGNkBkySWf2S8ZkH9F wR+RdZb5CQvJSdKDgDGkaln9K1Gvx/6mLVIae/h+RcFDPzKxZo8HhmIrPHo7mmcO k/gsyEacIhkqZZsqpi85XzbzjEJtgGVFcwU91JQQfIdxA6BcEe94k+e1Rk58nuR2 WV6N3WlCLloY9UKnDU3PuvAlNvKDYXxabKJDbJdqkzawL0dhTvoWugFUuISP+noA rQG9w== Received: from dc6wp-exch02.marvell.com ([4.21.29.225]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 46503c20x2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Mon, 21 Apr 2025 08:17:40 -0700 (PDT) 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; Mon, 21 Apr 2025 08:17:39 -0700 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; Mon, 21 Apr 2025 08:17:39 -0700 Received: from cavium-PowerEdge-R640.. (unknown [10.28.36.207]) by maili.marvell.com (Postfix) with ESMTP id 981343F7066; Mon, 21 Apr 2025 08:17:36 -0700 (PDT) From: Nitin Saxena To: Jerin Jacob , Kiran Kumar K , Nithin Dabilpuram , Zhirun Yan , Robin Jarry , Christophe Fontaine CC: , Nitin Saxena Subject: [PATCH v9 5/5] test/graph_feature_arc: add functional tests Date: Mon, 21 Apr 2025 20:47:16 +0530 Message-ID: <20250421151718.2172470-6-nsaxena@marvell.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250421151718.2172470-1-nsaxena@marvell.com> References: <20250103060612.2671836-1-nsaxena@marvell.com> <20250421151718.2172470-1-nsaxena@marvell.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain X-Proofpoint-ORIG-GUID: EDku6oAkA1eEvIkclRsXgvigrjGZrjw7 X-Authority-Analysis: v=2.4 cv=WMh/XmsR c=1 sm=1 tr=0 ts=68066194 cx=c_pps a=gIfcoYsirJbf48DBMSPrZA==:117 a=gIfcoYsirJbf48DBMSPrZA==:17 a=XR8D0OoHHMoA:10 a=M5GUcnROAAAA:8 a=GOki7qIE3wekRYxQ8yUA:9 a=OBjm3rFKGHvpk9ecZwUJ:22 X-Proofpoint-GUID: EDku6oAkA1eEvIkclRsXgvigrjGZrjw7 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1095,Hydra:6.0.680,FMLib:17.12.68.34 definitions=2025-04-21_07,2025-04-21_02,2024-11-22_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 functional unit test case for verifying feature arc control plane and fast path APIs How to run: $ echo "graph_feature_arc_autotest" | ./bin/dpdk-test Signed-off-by: Nitin Saxena --- app/test/meson.build | 1 + app/test/test_graph_feature_arc.c | 1374 +++++++++++++++++++++++++++++ 2 files changed, 1375 insertions(+) create mode 100644 app/test/test_graph_feature_arc.c diff --git a/app/test/meson.build b/app/test/meson.build index b6285a6b45..acb0d36c6b 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -90,6 +90,7 @@ source_file_deps = { 'test_func_reentrancy.c': ['hash', 'lpm'], 'test_graph.c': ['graph'], 'test_graph_perf.c': ['graph'], + 'test_graph_feature_arc.c': ['graph'], 'test_hash.c': ['net', 'hash'], 'test_hash_functions.c': ['hash'], 'test_hash_multiwriter.c': ['hash'], diff --git a/app/test/test_graph_feature_arc.c b/app/test/test_graph_feature_arc.c new file mode 100644 index 0000000000..b46ab4457e --- /dev/null +++ b/app/test/test_graph_feature_arc.c @@ -0,0 +1,1374 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2024 Marvell International Ltd. + */ + +#include "test.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef RTE_EXEC_ENV_WINDOWS +#include +#include +#include +#include +#include +#include +#include + +#define MBUF_NUM 256 +#define TEST_ARC1_NAME "arc1" +#define TEST_ARC2_NAME "arc2" +#define TEST_FAILED_ARC "failed_arc" +#define MAX_INDEXES 10 +#define OVERRIDE_MAX_INDEX MBUF_NUM +#define MAX_FEATURES 5 + +#define dbg(...) + +#define SOURCE1 "arc_source1_node" +#define INPUT_STATIC "arc_input_static_node" +#define OUTPUT_STATIC "arc_output_static_node" +#define PKT_FREE_STATIC "arc_pkt_free_static_node" +#define ARC1_FEATURE1 "arc1_feature1_node" +#define ARC1_FEATURE2 "arc1_feature2_node" +#define ARC2_FEATURE1 "arc2_feature1_node" +#define ARC2_FEATURE2 "arc2_feature2_node" +#define ARC2_FEATURE3 "arc2_feature3_node" +#define DUMMY1_STATIC "arc_dummy1_static_node" +#define DUMMY2_STATIC "arc_dummy2_static_node" + +#define feature_cast(x) ((rte_graph_feature_t)(x)) + +/* (Node index, Node Name, feature app_cookie base */ +#define FOREACH_TEST_NODE_ARC { \ + R(0, SOURCE1, 64) \ + R(1, INPUT_STATIC, 128) \ + R(2, OUTPUT_STATIC, 256) \ + R(3, PKT_FREE_STATIC, 512) \ + R(4, ARC1_FEATURE1, 1024) \ + R(5, ARC1_FEATURE2, 2048) \ + R(6, ARC2_FEATURE1, 4096) \ + R(7, ARC2_FEATURE2, 8192) \ + R(8, ARC2_FEATURE3, 16384) \ + R(9, DUMMY1_STATIC, 32768) \ + R(10, DUMMY2_STATIC, 65536) \ + } + +/** + * ARC1: Feature arc on ingress interface + * ARC2: Feature arc on egress interface + * XX_static: Static nodes + * XX_featureX: Feature X on arc + * + * -----> ARC1_FEATURE1 + * | | | + * | | v + * | | ARC1_FEATURE2 + * | | | + * | v v + * SOURCE1 ->-----> INPUT_STATIC --> OUTPUT_STATIC -----> PKT_FREE_STATIC + * | | | ^ ^ ^ + * | | | | | | + * | | --> ARC2_FEATURE1 | | + * | | ^ ^ | | + * | | | | | | + * | ----------c-> ARC2_FEATURE2 | + * | | ^ | + * | | | | + * ----------> ARC2_FEATURE3 ------- + */ +const char *node_names_feature_arc[] = { + SOURCE1, INPUT_STATIC, OUTPUT_STATIC, PKT_FREE_STATIC, + ARC1_FEATURE1, ARC1_FEATURE2, ARC2_FEATURE1, ARC2_FEATURE2, ARC2_FEATURE3, + DUMMY1_STATIC, DUMMY2_STATIC +}; + +const char *arc_names[] = { + TEST_ARC1_NAME, TEST_ARC2_NAME, +}; + +const char *arc1_feature_seq[] = { + ARC1_FEATURE1, ARC1_FEATURE2, INPUT_STATIC, +}; + +const char *arc2_feature_seq[] = { + ARC2_FEATURE1, ARC2_FEATURE2, ARC2_FEATURE3, PKT_FREE_STATIC, +}; + +#define MAX_NODES RTE_DIM(node_names_feature_arc) + +typedef enum { + START_NODE, + INTERMEDIATE_FEATURE, + END_FEATURE, +} fp_node_type_t; + +static int fp_test_case_result_failed; +static const char *fp_error_node; +static uint64_t fp_end_feature_counters; +static uint64_t sp_enable_counters, sp_enable_cb_counters; +static uint64_t sp_disable_counters, sp_disable_cb_counters; + +/* Function declarations */ +static uint16_t +source1_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs); +static uint16_t +input_fa_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs); +static uint16_t +output_fa_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs); +static uint16_t +pkt_free_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs); +static uint16_t +pkt_free_fa_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs); +static uint16_t +dummy1_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs); +static uint16_t +dummy2_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs); +static uint16_t +arc1_feature1_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs); +static uint16_t +arc1_feature1_fa_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs); +static uint16_t +arc1_feature2_fa_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs); +static uint16_t +arc2_feature1_fa_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs); +static uint16_t +arc2_feature2_fa_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs); +static uint16_t +arc2_feature3_fa_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs); +static int +common_arc1_init(const struct rte_graph *graph, struct rte_node *node); +static int +common_arc2_init(const struct rte_graph *graph, struct rte_node *node); +static uint16_t +common_process_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs, uint16_t max_indexes, + uint16_t mbuf_arr_offset, fp_node_type_t type); + +typedef struct test_node_priv { + int stop_enqueue; + + /* rte_graph node id */ + uint32_t node_id; + + rte_graph_feature_arc_t arc; +} test_node_priv_t; + +typedef struct { + rte_graph_feature_t feature; + uint16_t egress_interface; + uint16_t ingress_interface; +} graph_dynfield_t; + +#define MAX_FEATURE_ARCS 4 +static rte_graph_feature_arc_t arcs[MAX_FEATURE_ARCS]; +static struct rte_mbuf mbufs[MAX_NODES + 1][MBUF_NUM]; +static void *mbuf_p[MAX_NODES + 1][MBUF_NUM]; +static rte_graph_t graph_id = RTE_GRAPH_ID_INVALID; + +static uint16_t +compute_unique_user_data(const char *parent, const char *child, uint32_t interface_index) +{ + uint16_t user_data = interface_index; + + RTE_SET_USED(parent); +#define R(idx, node, node_cookie) { \ + if (!strcmp(child, node)) { \ + user_data += node_cookie + idx; \ + } \ + } + + FOREACH_TEST_NODE_ARC +#undef R + + return user_data; +} + +static void update_sp_counters(const char *arc_name, const char *feature_name, + rte_node_t feature_node_id, uint32_t index, + bool enable_disable, uint16_t app_cookie) + +{ + RTE_SET_USED(feature_node_id); + + if (app_cookie != UINT16_MAX) { + if (app_cookie != compute_unique_user_data(arc_name, feature_name, index)) { + printf("cb():%s/%s/%u: app_cookie mismatch %u != %u\n", + arc_name, feature_name, index, app_cookie, + compute_unique_user_data(arc_name, feature_name, index)); + sp_enable_counters = UINT16_MAX; + sp_disable_counters = UINT16_MAX; + } + } + if (enable_disable) + sp_enable_cb_counters++; + else + sp_disable_cb_counters++; +} + + + +static int +get_edge(struct rte_node_register *parent_node, + struct rte_node_register *child_node, rte_edge_t *_edge) +{ + char **next_edges = NULL; + uint32_t count, i; + + count = rte_node_edge_get(parent_node->id, NULL); + + if (!count) + return -1; + + next_edges = malloc(count); + + if (!next_edges) + return -1; + + count = rte_node_edge_get(parent_node->id, next_edges); + for (i = 0; i < count; i++) { + if (strstr(child_node->name, next_edges[i])) { + if (_edge) + *_edge = (rte_edge_t)i; + + free(next_edges); + return 0; + } + } + free(next_edges); + + return -1; +} + +int +common_arc1_init(const struct rte_graph *graph, struct rte_node *node) +{ + test_node_priv_t *priv = (test_node_priv_t *)node->ctx; + + RTE_SET_USED(graph); + + priv->node_id = node->id; + priv->stop_enqueue = 0; + if (rte_graph_feature_arc_lookup_by_name(TEST_ARC1_NAME, &priv->arc) < 0) + return -1; + + return 0; +} + +int +common_arc2_init(const struct rte_graph *graph, struct rte_node *node) +{ + test_node_priv_t *priv = (test_node_priv_t *)node->ctx; + + RTE_SET_USED(graph); + + priv->node_id = node->id; + if (rte_graph_feature_arc_lookup_by_name(TEST_ARC2_NAME, &priv->arc) < 0) + return -1; + + return 0; +} + +uint16_t +common_process_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs, uint16_t max_indexes, + uint16_t mbuf_arr_offset, + fp_node_type_t ndtype) +{ + test_node_priv_t *priv = (test_node_priv_t *)node->ctx; + struct rte_graph_feature_arc *arc = + rte_graph_feature_arc_get(priv->arc); + struct rte_graph_feature_arc_mbuf_dynfields *mbfields = NULL; + struct rte_mbuf *bufs[MBUF_NUM]; + rte_edge_t edges[MBUF_NUM]; + uint32_t i, idx; + + RTE_SET_USED(objs); + if (priv->stop_enqueue) + return 0; + + if (ndtype == START_NODE) + nb_objs = MBUF_NUM; + + for (i = 0; i < nb_objs; i++) { + switch (ndtype) { + case START_NODE: + edges[i] = UINT16_MAX; + bufs[i] = mbuf_p[mbuf_arr_offset][i]; + break; + case INTERMEDIATE_FEATURE: + edges[i] = UINT16_MAX; + bufs[i] = (struct rte_mbuf *)objs[i]; + break; + default: + edges[i] = 0; + bufs[i] = (struct rte_mbuf *)objs[i]; + break; + } + mbfields = rte_graph_feature_arc_mbuf_dynfields_get(bufs[i], arc->mbuf_dyn_offset); + if (ndtype == START_NODE) { + idx = i % max_indexes; + if (!rte_graph_feature_data_first_feature_get(arc, idx, + &mbfields->feature_data, + &edges[i])) { + fp_test_case_result_failed = 1; + fp_error_node = node->name; + priv->stop_enqueue = 1; + return i; + } + } else if (ndtype == INTERMEDIATE_FEATURE) { + if (!rte_graph_feature_data_next_feature_get(arc, + &mbfields->feature_data, + &edges[i])) { + fp_test_case_result_failed = 1; + fp_error_node = node->name; + return i; + } + } else { + /* Send pkts from arc1_end to arc2_start*/ + if (mbuf_arr_offset == 0) + edges[i] = 0; + fp_end_feature_counters++; + } + if (edges[i] == UINT16_MAX) + RTE_VERIFY(0); + } + if (ndtype == START_NODE) + priv->stop_enqueue = 1; + + if (!fp_test_case_result_failed && (!mbuf_arr_offset || (ndtype != END_FEATURE))) + rte_node_enqueue_next(graph, node, edges, (void **)bufs, nb_objs); + + return nb_objs; +} + +uint16_t +source1_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + return common_process_fn(graph, node, objs, nb_objs, MAX_INDEXES, 0, START_NODE); +} + +static struct rte_node_register node_source1 = { + .name = SOURCE1, + .process = source1_fn, + .flags = RTE_NODE_SOURCE_F, + .nb_edges = 3, + .init = common_arc1_init, + .next_nodes = {INPUT_STATIC, DUMMY1_STATIC, DUMMY2_STATIC}, +}; +RTE_NODE_REGISTER(node_source1); + +uint16_t +input_fa_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + return common_process_fn(graph, node, objs, nb_objs, MAX_INDEXES, 0, END_FEATURE); +} + +static struct rte_node_register node_input = { + .name = INPUT_STATIC, + .process = input_fa_fn, + .nb_edges = 2, + .init = common_arc1_init, + .next_nodes = {OUTPUT_STATIC, DUMMY1_STATIC}, +}; +RTE_NODE_REGISTER(node_input); + +struct rte_graph_feature_register arc1_end_feature = { + .feature_name = INPUT_STATIC, + .arc_name = TEST_ARC1_NAME, + .feature_process_fn = input_fa_fn, + .feature_node = &node_input, + .notifier_cb = update_sp_counters, +}; + +static struct rte_graph_feature_arc_register arc1_input = { + .arc_name = TEST_ARC1_NAME, + .max_indexes = MAX_INDEXES, + .max_features = MAX_FEATURES, + .start_node = &node_source1, + .start_node_feature_process_fn = source1_fn, + .end_feature = &arc1_end_feature, +}; + +uint16_t +output_fa_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + return common_process_fn(graph, node, objs, nb_objs, + OVERRIDE_MAX_INDEX, 1, START_NODE); +} + +static struct rte_node_register node_output = { + .name = OUTPUT_STATIC, + .process = output_fa_fn, + .nb_edges = 3, + .init = common_arc2_init, + .next_nodes = {DUMMY1_STATIC, PKT_FREE_STATIC, DUMMY2_STATIC}, +}; +RTE_NODE_REGISTER(node_output); + +uint16_t +pkt_free_fn(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); + + fp_test_case_result_failed = 1; + fp_error_node = node->name; + return 0; +} + +uint16_t +pkt_free_fa_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + return common_process_fn(graph, node, objs, nb_objs, + OVERRIDE_MAX_INDEX, 1, END_FEATURE); +} + +static struct rte_node_register node_pkt_free = { + .name = PKT_FREE_STATIC, + .process = pkt_free_fn, + .nb_edges = 1, + .init = common_arc2_init, + .next_nodes = {DUMMY1_STATIC}, +}; +RTE_NODE_REGISTER(node_pkt_free); + +static uint16_t override_arc2_index(void) +{ + return OVERRIDE_MAX_INDEX; +} + +struct rte_graph_feature_register arc2_end_feature = { + .feature_name = PKT_FREE_STATIC, + .arc_name = TEST_ARC2_NAME, + .feature_process_fn = pkt_free_fa_fn, + .feature_node = &node_pkt_free, + .notifier_cb = update_sp_counters, +}; + +static struct rte_graph_feature_arc_register arc2_output = { + .arc_name = TEST_ARC2_NAME, + .max_indexes = 1, /* Let feature override with bigger value */ + /* max_features not provided. End feature is a feature hence should work*/ + .start_node = &node_output, + .start_node_feature_process_fn = output_fa_fn, + .end_feature = &arc2_end_feature, +}; +RTE_GRAPH_FEATURE_ARC_REGISTER(arc2_output); + +/** Dummy nodes */ +uint16_t +dummy1_fn(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 0; +} + +static struct rte_node_register dummy1 = { + .name = DUMMY1_STATIC, + .process = dummy1_fn, + .nb_edges = 0, + .init = common_arc2_init, +}; +RTE_NODE_REGISTER(dummy1); + +uint16_t +dummy2_fn(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 0; +} + +static struct rte_node_register dummy2 = { + .name = DUMMY2_STATIC, + .process = dummy2_fn, + .nb_edges = 5, + .init = common_arc2_init, + .next_nodes = { ARC1_FEATURE1, ARC1_FEATURE2, ARC2_FEATURE1, + ARC2_FEATURE2, ARC2_FEATURE3}, +}; +RTE_NODE_REGISTER(dummy2); + +/** Failed registrations */ + +struct rte_graph_feature_register sink_valid_feature = { + .feature_name = "sink_valid_feature", + .arc_name = TEST_FAILED_ARC, + .feature_process_fn = dummy2_fn, + .feature_node = &dummy2, +}; + +struct rte_graph_feature_register sink_mismatch_arc_name = { + .feature_name = "sink_mismatch_arc_name", + .arc_name = "mismatch_arc_name", + .feature_process_fn = dummy2_fn, + .feature_node = &dummy2, +}; + +struct rte_graph_feature_register sink_no_feature_node = { + .feature_name = "sink_no_feature_node", + .arc_name = TEST_FAILED_ARC, + .feature_process_fn = dummy2_fn, +}; + +struct rte_graph_feature_register sink_no_feature_fn = { + .feature_name = "sink_no_feature_fn", + .arc_name = TEST_FAILED_ARC, + .feature_node = &dummy2, +}; + +/* failed_arc1 + * - max_features not provided + * - end_feature not provided + */ +static struct rte_graph_feature_arc_register failed_arc1 = { + .arc_name = TEST_FAILED_ARC, + .max_indexes = 1, /* Let features override it*/ + /* max_features field is missing */ + /* end_feature missing */ + .start_node = &dummy1, + .start_node_feature_process_fn = dummy1_fn, +}; +RTE_GRAPH_FEATURE_ARC_REGISTER(failed_arc1); + +/* failed_arc2 + * - max_indexes not provided + */ +static struct rte_graph_feature_arc_register failed_arc2 = { + .arc_name = TEST_FAILED_ARC, + .end_feature = &sink_valid_feature, + /* max_index not provided and neither override_index_cb() in any feature */ + .start_node = &dummy1, + .start_node_feature_process_fn = dummy1_fn, +}; +RTE_GRAPH_FEATURE_ARC_REGISTER(failed_arc2); + +/* failed_arc3 + * - start_node not provided + */ +static struct rte_graph_feature_arc_register failed_arc3 = { + .arc_name = TEST_FAILED_ARC, + .end_feature = &sink_valid_feature, + .max_indexes = 1, + /* start_node not provided */ + .start_node_feature_process_fn = dummy1_fn, +}; +RTE_GRAPH_FEATURE_ARC_REGISTER(failed_arc3) + +/* failed_arc4 + * - start_node not provided + */ +static struct rte_graph_feature_arc_register failed_arc4 = { + .arc_name = TEST_FAILED_ARC, + .end_feature = &sink_valid_feature, + .max_indexes = 5, + .start_node = &dummy1, + /* start_node fn not provided */ +}; +RTE_GRAPH_FEATURE_ARC_REGISTER(failed_arc4); + +/* failed_arc5 + * - end_feature has mismatch arc_name + */ +static struct rte_graph_feature_arc_register failed_arc5 = { + .arc_name = TEST_FAILED_ARC, + .end_feature = &sink_mismatch_arc_name, + .max_indexes = 5, + .start_node = &dummy1, + .start_node_feature_process_fn = dummy1_fn, +}; +RTE_GRAPH_FEATURE_ARC_REGISTER(failed_arc5); + +/* failed_arc6 + * - end_feature does not have feature_node + */ +static struct rte_graph_feature_arc_register failed_arc6 = { + .arc_name = TEST_FAILED_ARC, + .end_feature = &sink_no_feature_node, + .max_indexes = 5, + .start_node = &dummy1, + .start_node_feature_process_fn = dummy1_fn, +}; +RTE_GRAPH_FEATURE_ARC_REGISTER(failed_arc6); + +/* failed_arc7 + * - end_feature does not have feature_fn + */ +static struct rte_graph_feature_arc_register failed_arc7 = { + .arc_name = TEST_FAILED_ARC, + .end_feature = &sink_no_feature_fn, + .max_indexes = 5, + .start_node = &dummy1, + .start_node_feature_process_fn = dummy1_fn, +}; +RTE_GRAPH_FEATURE_ARC_REGISTER(failed_arc7); + +uint16_t +arc1_feature1_fn(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); + + /* Feature on an arc cannot be called if feature arc is disabled */ + fp_test_case_result_failed = 1; + fp_error_node = node->name; + return 0; +} + +uint16_t +arc1_feature1_fa_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + return common_process_fn(graph, node, objs, nb_objs, + MAX_INDEXES, 0, INTERMEDIATE_FEATURE); +} + +static struct rte_node_register arc1_feature1 = { + .name = ARC1_FEATURE1, + .process = arc1_feature1_fn, + .nb_edges = 0, + .init = common_arc1_init, +}; +RTE_NODE_REGISTER(arc1_feature1); + +static struct rte_graph_feature_register feat_arc1_feature1 = { + .feature_name = ARC1_FEATURE1, + .arc_name = TEST_ARC1_NAME, + .feature_process_fn = arc1_feature1_fa_fn, + .feature_node = &arc1_feature1, + .override_index_cb = override_arc2_index, + .notifier_cb = update_sp_counters, +}; +RTE_GRAPH_FEATURE_REGISTER(feat_arc1_feature1); + +uint16_t +arc1_feature2_fa_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + return common_process_fn(graph, node, objs, nb_objs, + MAX_INDEXES, 0, INTERMEDIATE_FEATURE); +} + +static struct rte_node_register arc1_feature2 = { + .name = ARC1_FEATURE2, + .process = arc1_feature2_fa_fn, + .nb_edges = 0, + .init = common_arc1_init, +}; +RTE_NODE_REGISTER(arc1_feature2); + +/* add arc1_feature2 later using rte_graph_feature_add()*/ +static struct rte_graph_feature_register feat_arc1_feature2 = { + .feature_name = ARC1_FEATURE2, + .arc_name = TEST_ARC1_NAME, + .feature_process_fn = arc1_feature2_fa_fn, + .feature_node = &arc1_feature2, + .runs_after = ARC1_FEATURE1, + .notifier_cb = update_sp_counters, +}; + +uint16_t +arc2_feature1_fa_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + return common_process_fn(graph, node, objs, nb_objs, + OVERRIDE_MAX_INDEX, 1, INTERMEDIATE_FEATURE); +} + +static struct rte_node_register arc2_feature1 = { + .name = ARC2_FEATURE1, + .process = arc2_feature1_fa_fn, + .nb_edges = 0, + .init = common_arc2_init, +}; +RTE_NODE_REGISTER(arc2_feature1); + +static struct rte_graph_feature_register feat_arc2_feature1 = { + .feature_name = ARC2_FEATURE1, + .arc_name = TEST_ARC2_NAME, + .feature_process_fn = arc2_feature1_fa_fn, + .feature_node = &arc2_feature1, + .notifier_cb = update_sp_counters, +}; +RTE_GRAPH_FEATURE_REGISTER(feat_arc2_feature1); + +uint16_t +arc2_feature2_fa_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + return common_process_fn(graph, node, objs, nb_objs, + OVERRIDE_MAX_INDEX, 1, INTERMEDIATE_FEATURE); +} + +static struct rte_node_register arc2_feature2 = { + .name = ARC2_FEATURE2, + .process = arc2_feature2_fa_fn, + .nb_edges = 0, + .init = common_arc2_init, +}; +RTE_NODE_REGISTER(arc2_feature2); + +static struct rte_graph_feature_register feat_arc2_feature2 = { + .feature_name = ARC2_FEATURE2, + .arc_name = TEST_ARC2_NAME, + .feature_process_fn = arc2_feature2_fa_fn, + .feature_node = &arc2_feature2, + .runs_after = ARC2_FEATURE1, + .runs_before = ARC2_FEATURE3, + .override_index_cb = override_arc2_index, + .notifier_cb = update_sp_counters, +}; +RTE_GRAPH_FEATURE_REGISTER(feat_arc2_feature2); + +uint16_t +arc2_feature3_fa_fn(struct rte_graph *graph, struct rte_node *node, + void **objs, uint16_t nb_objs) +{ + return common_process_fn(graph, node, objs, nb_objs, + OVERRIDE_MAX_INDEX, 1, INTERMEDIATE_FEATURE); +} + +static struct rte_node_register arc2_feature3 = { + .name = ARC2_FEATURE3, + .process = arc2_feature3_fa_fn, + .nb_edges = 0, + .init = common_arc2_init, +}; +RTE_NODE_REGISTER(arc2_feature3); + +static struct rte_graph_feature_register feat_arc2_feature3 = { + .feature_name = ARC2_FEATURE3, + .arc_name = TEST_ARC2_NAME, + .feature_process_fn = arc2_feature3_fa_fn, + .feature_node = &arc2_feature3, + .runs_after = ARC2_FEATURE1, + .notifier_cb = update_sp_counters, +}; +RTE_GRAPH_FEATURE_REGISTER(feat_arc2_feature3); + +static int +create_graph(void) +{ + struct rte_graph_param gconf = { + .socket_id = SOCKET_ID_ANY, + .nb_node_patterns = RTE_DIM(node_names_feature_arc), + .node_patterns = node_names_feature_arc, + }; + + 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 TEST_FAILED; + } + + return TEST_SUCCESS; +} + +static int +destroy_graph(void) +{ + if (graph_id != RTE_GRAPH_ID_INVALID) { + rte_graph_destroy(graph_id); + graph_id = RTE_GRAPH_ID_INVALID; + } + + return TEST_SUCCESS; +} + +static int test_perf(uint64_t end_feature_counters) +{ + struct rte_graph *graph = NULL; + int i; + + fp_test_case_result_failed = 0; + fp_error_node = NULL; + fp_end_feature_counters = 0; + + if (create_graph() < 0) { + printf("Graph creation failed while walk\n"); + return TEST_FAILED; + } + graph = rte_graph_lookup("worker0"); + if (graph) { + for (i = 0; i < 10; i++) + rte_graph_walk(graph); + } + if (destroy_graph() < 0) { + printf("Graph destroy failed while walk\n"); + return TEST_FAILED; + } + if (fp_test_case_result_failed) { + printf("Feature arc test failed for node %s\n", fp_error_node); + return TEST_FAILED; + } + + if (sp_enable_counters && + (sp_enable_cb_counters != sp_enable_counters)) { + printf("sp_enable_cb_counters mismatch %"PRIu64" != %"PRIu64"\n", + sp_enable_cb_counters, sp_enable_counters); + return TEST_FAILED; + } + if (sp_disable_counters && + (sp_disable_cb_counters != sp_disable_counters)) { + printf("sp_disable_cb_counters mismatch %"PRIu64" != %"PRIu64"\n", + sp_disable_cb_counters, sp_disable_counters); + return TEST_FAILED; + } + if (fp_end_feature_counters != end_feature_counters) { + printf("end_bufs_counters mismatch %"PRIu64" != %"PRIu64"\n", + fp_end_feature_counters, end_feature_counters); + return TEST_FAILED; + } + sp_enable_counters = 0; + sp_enable_cb_counters = 0; + sp_disable_counters = 0; + sp_disable_cb_counters = 0; + return TEST_SUCCESS; +} + +static int +__test_create_feature_arc(rte_graph_feature_arc_t *arcs, uint16_t max_arcs) +{ + struct rte_graph_feature_arc_register reg; + struct rte_graph_feature_register feat; + rte_graph_feature_arc_t arc; + const char *sample_arc_name = "sample_arc"; + char arc_name[256]; + int n_arcs; + + if (rte_graph_feature_arc_init(max_arcs) < 0) { + printf("Feature arc creation failed for arc: %u\n", max_arcs); + return TEST_FAILED; + } + + feat.feature_name = DUMMY2_STATIC; + feat.feature_process_fn = dummy2_fn; + feat.feature_node = &dummy2; + feat.feature_node_id = dummy2.id; + feat.runs_after = NULL; + feat.runs_before = NULL; + + reg.max_indexes = MAX_INDEXES; + reg.max_features = 3; + reg.start_node = &dummy1; + reg.start_node_feature_process_fn = dummy1_fn; + reg.end_feature = &feat; + for (n_arcs = 0; n_arcs < max_arcs; n_arcs++) { + snprintf(arc_name, sizeof(arc_name), "%s-%u", sample_arc_name, n_arcs); + feat.arc_name = arc_name; + reg.arc_name = arc_name; + if (rte_graph_feature_arc_create(®, &arcs[n_arcs]) < 0) { + printf("%s: Test failed for creating arc at index %u\n", arc_name, n_arcs); + return TEST_FAILED; + } + } + + if (rte_graph_feature_arc_create(&arc2_output, NULL) == 0) { + printf("Failure: Feature arc %s should have already been created\n", + arc2_output.arc_name); + return TEST_FAILED; + } + /* Verify feature arc created more than max_arcs must fail */ + for (n_arcs = 0; n_arcs < max_arcs; n_arcs++) { + snprintf(arc_name, sizeof(arc_name), "%s-%u", sample_arc_name, n_arcs); + arc = RTE_GRAPH_FEATURE_ARC_INITIALIZER; + if (rte_graph_feature_arc_lookup_by_name(arc_name, &arc) == 0) { + if (arc != arcs[n_arcs]) { + printf("%s: Feature arc lookup mismatch for arc [%u, exp: %u]\n", + arc_name, arc, arcs[n_arcs]); + return TEST_FAILED; + } + dbg("Feature arc lookup %s succeeded\n", arc_name); + } else { + printf("Feature arc lookup %s failed after creation\n", arc_name); + return TEST_FAILED; + } + } + return TEST_SUCCESS; +} + +static int +test_graph_feature_arc_create(void) +{ + int ret = 0; + + ret = __test_create_feature_arc(arcs, MAX_FEATURE_ARCS); + if (ret) { + printf("Feature arc creation test failed for %u number of arc create\n", + MAX_FEATURE_ARCS); + goto test_failed; + } + if (rte_graph_feature_arc_lookup_by_name(TEST_FAILED_ARC, NULL) == 0) { + printf("Feature arc %s should not have been created\n", TEST_FAILED_ARC); + goto test_failed; + } + + /* Cleanup to verify recreation */ + rte_graph_feature_arc_cleanup(); + + dbg("Feature arc cleanup done\n"); + + return TEST_SUCCESS; + +test_failed: + return TEST_FAILED; +} + +static int +graph_feature_arc_setup(void) +{ + unsigned long i, j; + + for (i = 0; i <= MAX_NODES; i++) { + for (j = 0; j < MBUF_NUM; j++) + mbuf_p[i][j] = &mbufs[i][j]; + } + + return TEST_SUCCESS; + +} +static int +test_graph_feature_arc_features_add(void) +{ + struct rte_graph_feature_arc *arc = NULL; + rte_graph_feature_t temp; + + if (rte_graph_feature_arc_init(1) < 0) { + printf("Feature arc creation failed just for adding features\n"); + return TEST_FAILED; + } + + /* see if duplicates fails */ + if (rte_graph_feature_add(&feat_arc2_feature1) == 0) { + printf("%s: Feature add failed for adding feature %s\n", + feat_arc2_feature1.arc_name, feat_arc2_feature1.feature_name); + goto test_failed; + } + + /* Create new arc1 */ + arc1_input.end_feature->feature_node_id = arc1_input.end_feature->feature_node->id; + if (rte_graph_feature_arc_create(&arc1_input, &arcs[0]) < 0) { + printf("%s: Feature arc creation failed\n", TEST_ARC2_NAME); + goto test_failed; + } + + /* Add features to arc1 */ + feat_arc1_feature1.feature_node_id = feat_arc1_feature1.feature_node->id; + if (rte_graph_feature_add(&feat_arc1_feature1) < 0) { + printf("%s: Feature add failed for adding feature %s\n", + feat_arc1_feature1.arc_name, feat_arc1_feature1.feature_name); + goto test_failed; + } + + feat_arc1_feature2.feature_node_id = feat_arc1_feature2.feature_node->id; + if (rte_graph_feature_add(&feat_arc1_feature2) < 0) { + printf("%s: Feature add failed for adding feature %s\n", + feat_arc1_feature2.arc_name, feat_arc1_feature2.feature_name); + } + + if (rte_graph_feature_arc_lookup_by_name(TEST_ARC2_NAME, &arcs[1]) < 0) { + printf("%s: Feature arc lookup failed while adding features\n", + TEST_ARC2_NAME); + goto test_failed; + } + + arc = rte_graph_feature_arc_get(arcs[1]); + if (!arc) { + printf("%s: Feature arc ptr cannot be NULL\n", + TEST_ARC2_NAME); + goto test_failed; + } + + /* Make sure number of indexes are overridden by feature*/ + if (arc->max_indexes < OVERRIDE_MAX_INDEX) { + printf("%s: Feature arc max_indexes mismatch %u < %u\n", + TEST_ARC2_NAME, arc->max_indexes, OVERRIDE_MAX_INDEX); + goto test_failed; + } + + /* arc1_feature1 must be first feature to arcs[0] */ + if (!strstr(ARC1_FEATURE1, + rte_graph_feature_arc_feature_to_name(arcs[0], + feature_cast(0)))) { + printf("%s: %s is not the first feature instead %s\n", + TEST_ARC1_NAME, ARC1_FEATURE1, + rte_graph_feature_arc_feature_to_name(arcs[0], feature_cast(0))); + goto test_failed; + } + + /* arc1_feature2 must be second feature to arcs[0] */ + if (!strstr(ARC1_FEATURE2, + rte_graph_feature_arc_feature_to_name(arcs[0], + feature_cast(1)))) { + printf("%s: %s is not the second feature instead %s\n", + TEST_ARC1_NAME, ARC1_FEATURE2, + rte_graph_feature_arc_feature_to_name(arcs[0], feature_cast(1))); + goto test_failed; + } + + /* Make sure INPUT_STATIC is the last feature in arcs[0] */ + temp = rte_graph_feature_arc_num_features(arcs[0]); + if (!strstr(INPUT_STATIC, + rte_graph_feature_arc_feature_to_name(arcs[0], + temp - feature_cast(1)))) { + printf("%s: %s is not the last feature instead %s\n", + TEST_ARC1_NAME, INPUT_STATIC, + rte_graph_feature_arc_feature_to_name(arcs[0], + temp - feature_cast(1))); + goto test_failed; + } + + /* arc2_feature1 must be first feature to arcs[1] */ + if (!strstr(ARC2_FEATURE1, + rte_graph_feature_arc_feature_to_name(arcs[1], + feature_cast(0)))) { + printf("%s: %s is not the first feature instead %s\n", + TEST_ARC2_NAME, ARC2_FEATURE1, + rte_graph_feature_arc_feature_to_name(arcs[1], feature_cast(0))); + goto test_failed; + } + + /* arc2_feature2 must be second feature to arcs[1] */ + if (!strstr(ARC2_FEATURE2, + rte_graph_feature_arc_feature_to_name(arcs[1], + feature_cast(1)))) { + printf("%s: %s is not the second feature instead %s\n", + TEST_ARC2_NAME, ARC2_FEATURE2, + rte_graph_feature_arc_feature_to_name(arcs[1], feature_cast(1))); + goto test_failed; + } + + /* arc2_feature3 must be third feature to arcs[1] */ + if (!strstr(ARC2_FEATURE3, + rte_graph_feature_arc_feature_to_name(arcs[1], + feature_cast(2)))) { + printf("%s: %s is not the third feature instead %s\n", + TEST_ARC2_NAME, ARC2_FEATURE3, + rte_graph_feature_arc_feature_to_name(arcs[1], feature_cast(2))); + goto test_failed; + } + + /* Make sure PKT_FREE is the last feature in arcs[1] */ + temp = rte_graph_feature_arc_num_features(arcs[1]); + if (!strstr(PKT_FREE_STATIC, + rte_graph_feature_arc_feature_to_name(arcs[1], + temp - feature_cast(1)))) { + printf("%s: %s is not the last feature instead %s\n", + TEST_ARC2_NAME, PKT_FREE_STATIC, + rte_graph_feature_arc_feature_to_name(arcs[1], + temp - feature_cast(1))); + goto test_failed; + } + + /* Make sure feature is connected to end feature */ + if (get_edge(&arc2_feature1, &node_pkt_free, NULL)) { + printf("%s: Edge not found between %s and %s\n", + TEST_ARC2_NAME, ARC2_FEATURE1, PKT_FREE_STATIC); + goto test_failed; + } + + if (create_graph() < 0) { + printf("Graph creation failed while adding features\n"); + goto test_failed; + } + if (destroy_graph() < 0) { + printf("Graph destroy failed while adding features\n"); + goto test_failed; + } + return TEST_SUCCESS; +test_failed: + rte_graph_feature_arc_cleanup(); + return TEST_FAILED; +} + +static int +test_graph_feature_arc_feature_enable(void) +{ + uint32_t n_indexes, n_features, count = 0; + struct rte_node_register *parent, *child; + struct rte_graph_feature_arc *arc; + rte_graph_feature_data_t fdata; + char *feature_name = NULL; + rte_edge_t edge1, edge2; + uint16_t user_data; + + if (rte_graph_feature_arc_lookup_by_name(TEST_ARC1_NAME, &arcs[0]) < 0) { + printf("%s: Feature arc lookup failed while adding features\n", + TEST_ARC1_NAME); + return TEST_FAILED; + } + + arc = rte_graph_feature_arc_get(arcs[0]); + + if (rte_graph_feature_arc_is_any_feature_enabled(arc)) { + printf("%s: Feature arc should not have any feature enabled by now\n", + TEST_ARC1_NAME); + return TEST_FAILED; + } + + if (rte_graph_feature_arc_num_enabled_features(arcs[0])) { + printf("%s: Feature arc should not have any_feature() enabled by now\n", + TEST_ARC1_NAME); + return TEST_FAILED; + } + /* + * On interface 0, enable feature 0, + * On interface 1, enable feature 1 and so on so forth + * + * later verify first feature on every interface index is unique + * and check [rte_edge, user_data] retrieved via fast path APIs + */ + for (n_indexes = 0; n_indexes < arc->max_indexes; n_indexes++) { + n_features = n_indexes % RTE_DIM(arc1_feature_seq); + feature_name = rte_graph_feature_arc_feature_to_name(arcs[0], n_features); + if (strncmp(feature_name, arc1_feature_seq[n_features], + RTE_GRAPH_NAMESIZE)) { + printf("%s: Feature(%u) seq mismatch [found: %s, exp: %s]\n", + TEST_ARC1_NAME, n_features, feature_name, + arc1_feature_seq[n_features]); + return TEST_FAILED; + } + user_data = compute_unique_user_data(arc->start_node->name, feature_name, + n_indexes); + /* negative test case. enable feature on invalid index */ + if (!n_indexes && (rte_graph_feature_enable(arcs[0], 65535, feature_name, + user_data, NULL) == 0)) { + printf("%s: Feature %s should not be enabled on invalid index\n", + TEST_ARC1_NAME, feature_name); + return TEST_FAILED; + } + if (rte_graph_feature_enable(arcs[0], n_indexes, feature_name, + user_data, NULL) < 0) { + printf("%s: Feature enable failed for %s on index %u\n", + TEST_ARC1_NAME, feature_name, n_indexes); + return TEST_FAILED; + } + sp_enable_counters++; + /* has any feature should be valid */ + if (!rte_graph_feature_arc_is_any_feature_enabled(arc)) { + printf("%s: Feature arc should have any_feature enabled by now\n", + TEST_ARC1_NAME); + return TEST_FAILED; + } + if ((count + 1) != rte_graph_feature_arc_num_enabled_features(arcs[0])) { + printf("%s: Number of enabled mismatches [found: %u, exp: %u]\n", + TEST_ARC1_NAME, + rte_graph_feature_arc_num_enabled_features(arcs[0]), + count + 1); + return TEST_FAILED; + } + count++; + } + /* Negative test case */ + user_data = compute_unique_user_data(arc->start_node->name, ARC2_FEATURE1, 1); + if (!rte_graph_feature_enable(arcs[0], 1 /* index */, ARC2_FEATURE1, user_data, NULL)) { + printf("%s: Invalid feature %s is enabled on index 1\n", + TEST_ARC1_NAME, ARC2_FEATURE1); + return TEST_FAILED; + } + /* Duplicate enable */ + if (!rte_graph_feature_enable(arcs[0], 1 /* index */, ARC1_FEATURE2, user_data, NULL)) { + printf("%s: Duplicate feature %s shouldn't be enabled again on index 1\n", + TEST_ARC1_NAME, ARC1_FEATURE2); + return TEST_FAILED; + } + for (n_indexes = 0; n_indexes < arc->max_indexes; n_indexes++) { + if (!rte_graph_feature_data_first_feature_get(arc, n_indexes, &fdata, &edge2)) { + printf("%s: FP first feature data get failed for index %u\n", + TEST_ARC1_NAME, n_indexes); + return TEST_FAILED; + } + parent = arc->start_node; + if (0 == (n_indexes % RTE_DIM(arc1_feature_seq))) + child = &arc1_feature1; + else if (1 == (n_indexes % RTE_DIM(arc1_feature_seq))) + child = &arc1_feature2; + else + child = &node_input; + + if (get_edge(parent, child, &edge1)) { + printf("%s: Edge not found between %s and %s\n", + TEST_ARC1_NAME, parent->name, child->name); + return TEST_FAILED; + } + if (edge1 != edge2) { + printf("%s: Edge mismatch for first feature on index %u [%u, exp: %u]\n", + TEST_ARC1_NAME, n_indexes, edge2, edge1); + return TEST_FAILED; + } + if (compute_unique_user_data(parent->name, child->name, n_indexes) != + rte_graph_feature_data_app_cookie_get(arc, fdata)) { + printf("%s/idx: %u: Cookie mismatch for first feature [%u, exp: %u]\n", + TEST_ARC1_NAME, n_indexes, + rte_graph_feature_data_app_cookie_get(arc, fdata), + compute_unique_user_data(parent->name, child->name, n_indexes)); + return TEST_FAILED; + } + } + arc = rte_graph_feature_arc_get(arcs[1]); + for (n_indexes = 0; n_indexes < arc->max_indexes; n_indexes++) { + n_features = n_indexes % RTE_DIM(arc2_feature_seq); + feature_name = rte_graph_feature_arc_feature_to_name(arcs[1], n_features); + if (strncmp(feature_name, arc2_feature_seq[n_features], + RTE_GRAPH_NAMESIZE)) { + printf("%s: Feature(%u) seq mismatch [found: %s, exp: %s]\n", + arc->feature_arc_name, n_features, feature_name, + arc2_feature_seq[n_features]); + return TEST_FAILED; + } + user_data = compute_unique_user_data(arc->start_node->name, feature_name, + n_indexes); + if (rte_graph_feature_enable(arcs[1], n_indexes, feature_name, + user_data, NULL) < 0) { + printf("%s: Feature enable failed for %s on index %u\n", + TEST_ARC2_NAME, feature_name, n_indexes); + return TEST_FAILED; + } + sp_enable_counters++; + } + + return test_perf((2 * MBUF_NUM)); +} + +static int +test_graph_feature_arc_feature_disable(void) +{ + struct rte_graph_feature_arc *arc; + uint32_t n_indexes, n_features; + char *feature_name = NULL; + + arc = rte_graph_feature_arc_get(arcs[0]); + for (n_indexes = 0; n_indexes < arc->max_indexes; n_indexes++) { + n_features = n_indexes % RTE_DIM(arc1_feature_seq); + feature_name = rte_graph_feature_arc_feature_to_name(arcs[0], n_features); + if (rte_graph_feature_disable(arcs[0], n_indexes, feature_name, NULL)) { + printf("%s: feature disable failed for %s on index %u\n", + arc->feature_arc_name, feature_name, n_indexes); + return TEST_FAILED; + } + sp_disable_counters++; + } + + arc = rte_graph_feature_arc_get(arcs[1]); + for (n_indexes = 0; n_indexes < arc->max_indexes; n_indexes++) { + n_features = n_indexes % RTE_DIM(arc2_feature_seq); + feature_name = rte_graph_feature_arc_feature_to_name(arcs[1], n_features); + if (rte_graph_feature_disable(arcs[1], n_indexes, feature_name, NULL)) { + printf("%s: feature disable failed for %s on index %u\n", + arc->feature_arc_name, feature_name, n_indexes); + return TEST_FAILED; + } + sp_disable_counters++; + } + /* All packets should exit */ + return test_perf((2 * MBUF_NUM)); +} + +static int +test_graph_feature_arc_destroy(void) +{ + rte_graph_feature_arc_t arc; + + if (rte_graph_feature_arc_lookup_by_name(TEST_ARC1_NAME, &arc)) { + printf("Feature arc lookup failed for %s\n", TEST_ARC1_NAME); + return TEST_FAILED; + } + + if (arc != arcs[0]) { + printf("Feature arc lookup mismatch for %s [%u, exp: %u]\n", + TEST_ARC1_NAME, arc, arcs[0]); + return TEST_FAILED; + } + + if (rte_graph_feature_arc_destroy(arc)) { + printf("Feature arc destroy failed for %s\n", TEST_ARC1_NAME); + return TEST_FAILED; + } + + if (rte_graph_feature_arc_lookup_by_name(TEST_ARC2_NAME, &arc)) { + printf("Feature arc lookup success after destroy for %s\n", TEST_ARC2_NAME); + return TEST_FAILED; + } + + if (arc != arcs[1]) { + printf("Feature arc lookup mismatch for %s [%u, exp: %u]\n", + TEST_ARC2_NAME, arc, arcs[1]); + return TEST_FAILED; + } + if (rte_graph_feature_arc_destroy(arc)) { + printf("Feature arc destroy failed for %s\n", TEST_ARC2_NAME); + return TEST_FAILED; + } + return TEST_SUCCESS; +} + +static void +graph_feature_arc_teardown(void) +{ + if (graph_id != RTE_GRAPH_ID_INVALID) + rte_graph_destroy(graph_id); + + rte_graph_feature_arc_cleanup(); +} + +static struct unit_test_suite graph_feature_arc_testsuite = { + .suite_name = "Graph Feature arc library test suite", + .setup = graph_feature_arc_setup, + .teardown = graph_feature_arc_teardown, + .unit_test_cases = { + TEST_CASE(test_graph_feature_arc_create), + TEST_CASE(test_graph_feature_arc_features_add), + TEST_CASE(test_graph_feature_arc_feature_enable), + TEST_CASE(test_graph_feature_arc_feature_disable), + TEST_CASE(test_graph_feature_arc_destroy), + TEST_CASES_END(), /**< NULL terminate unit test array */ + }, +}; + +static int +graph_feature_arc_autotest_fn(void) +{ + return unit_test_suite_runner(&graph_feature_arc_testsuite); +} + +REGISTER_FAST_TEST(graph_feature_arc_autotest, true, true, graph_feature_arc_autotest_fn); +#endif /* !RTE_EXEC_ENV_WINDOWS */ -- 2.43.0