From patchwork Tue Dec 14 14:12:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronan Randles X-Patchwork-Id: 105131 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id A8967A00C3; Tue, 14 Dec 2021 15:12:57 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 436384114A; Tue, 14 Dec 2021 15:12:51 +0100 (CET) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by mails.dpdk.org (Postfix) with ESMTP id D1ADD4003C for ; Tue, 14 Dec 2021 15:12:48 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1639491169; x=1671027169; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=sXddrN5qu5q5oylC1x8jKFCSM0mTtRG7Zn1BKIFH4uo=; b=NlHdy7IXGV/vTXhTNEytnZpMyA3NFtTkuSRN6aerEEZzzb2W6vLFAcx+ VIQyngyjY6WoD6NoJyQJLv/z12hBVVNo4r33AZclpWOsQ8/NGXsHSACMS 1mCiiQDYoSlHBPSX2G4m1RBxT2noPUaQ243R+UI+WPnoOe0QaW0kuRBsR jnc5Sy/Ons/1/8J2+9ErbfuTqJSiXi8s1iZ0p/9au3zJLjOqS9WC2zgVo onQJKsWNCfGGNIWG3pM6ANv4UdF+9TpyqKAE7/tcgNHSt5WJuwxWNgfrc ja1G/IkkNLBhjCyqE/uAiDI+iKYUE+hEEWDGeufSs4TcJM0ehiIv6DEb4 Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10197"; a="302362300" X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="302362300" Received: from orsmga006.jf.intel.com ([10.7.209.51]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Dec 2021 06:12:47 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="465104081" Received: from silpixa00401120.ir.intel.com ([10.55.129.95]) by orsmga006.jf.intel.com with ESMTP; 14 Dec 2021 06:12:46 -0800 From: Ronan Randles To: dev@dpdk.org Cc: harry.van.haaren@intel.com, Ronan Randles Subject: [PATCH 01/12] net: add string to IPv4 parse function Date: Tue, 14 Dec 2021 14:12:31 +0000 Message-Id: <20211214141242.3383831-2-ronan.randles@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211214141242.3383831-1-ronan.randles@intel.com> References: <20211214141242.3383831-1-ronan.randles@intel.com> MIME-Version: 1.0 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 function that accepts ip string as a parameter and returns an ip address represented by a uint32_t. Relevant unit test for this function is also included. Signed-off-by: Harry van Haaren Signed-off-by: Ronan Randles --- app/test/meson.build | 2 ++ app/test/test_net.c | 61 ++++++++++++++++++++++++++++++++++++++++++++ lib/net/meson.build | 1 + lib/net/rte_ip.c | 43 +++++++++++++++++++++++++++++++ lib/net/rte_ip.h | 18 +++++++++++++ lib/net/version.map | 8 ++++++ 6 files changed, 133 insertions(+) create mode 100644 app/test/test_net.c create mode 100644 lib/net/rte_ip.c diff --git a/app/test/meson.build b/app/test/meson.build index 2b480adfba..4cf540fc74 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -100,6 +100,7 @@ test_sources = files( 'test_meter.c', 'test_mcslock.c', 'test_mp_secondary.c', + 'test_net.c', 'test_per_lcore.c', 'test_pflock.c', 'test_pmd_perf.c', @@ -177,6 +178,7 @@ test_deps = [ 'ipsec', 'lpm', 'member', + 'net', 'node', 'pipeline', 'port', diff --git a/app/test/test_net.c b/app/test/test_net.c new file mode 100644 index 0000000000..2cb7d3e1c9 --- /dev/null +++ b/app/test/test_net.c @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Intel Corporation + */ + +#include +#include + +#include +#include +#include "test.h" + +static int +test_rte_ip_parse_addr(void) +{ + printf("Running IP parsing tests...\n"); + + struct str_ip_t { + const char *str; + uint32_t exp_output; + uint32_t expected_to_fail; + } str_ip_tests[] = { + { .str = "1.2.3.4", .exp_output = RTE_IPV4(1, 2, 3, 4)}, + { .str = "192.168.255.255", .exp_output = + RTE_IPV4(192, 168, 255, 255)}, + { .str = "172.16.0.9", .exp_output = + RTE_IPV4(172, 16, 0, 9)}, + { .str = "1.2.3", .expected_to_fail = 1}, + { .str = "1.2.3.4.5", .expected_to_fail = 1}, + { .str = "fail.1.2.3", .expected_to_fail = 1}, + { .str = "", .expected_to_fail = 1}, + { .str = "1.2.3.fail", .expected_to_fail = 1} + }; + + uint32_t i; + for (i = 0; i < RTE_DIM(str_ip_tests); i++) { + uint32_t test_addr; + int32_t err = rte_ip_parse_addr(str_ip_tests[i].str, + &test_addr); + if (!test_addr) { + if (str_ip_tests[i].expected_to_fail != 1) + return -1; + } + + if (err || test_addr != str_ip_tests[i].exp_output) { + if (str_ip_tests[i].expected_to_fail != 1) + return -1; + } + } + + + return 0; +} + +static int +test_net_tests(void) +{ + int ret = test_rte_ip_parse_addr(); + return ret; +} + +REGISTER_TEST_COMMAND(net_autotest, test_net_tests); diff --git a/lib/net/meson.build b/lib/net/meson.build index e899846578..b2577a7592 100644 --- a/lib/net/meson.build +++ b/lib/net/meson.build @@ -26,6 +26,7 @@ headers = files( sources = files( 'rte_arp.c', 'rte_ether.c', + 'rte_ip.c', 'rte_net.c', 'rte_net_crc.c', ) diff --git a/lib/net/rte_ip.c b/lib/net/rte_ip.c new file mode 100644 index 0000000000..b859dfb640 --- /dev/null +++ b/lib/net/rte_ip.c @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Intel Corporation + */ + +#include +#include + +int32_t +rte_ip_parse_addr(const char *src_ip, uint32_t *output_addr) +{ + int32_t ret = 0; + char *current_position; + + if (src_ip == NULL) + return -1; + + char *tok = strdup(src_ip); + if (tok == NULL) + return -1; + + char *current_digit = strtok_r(tok, ".", ¤t_position); + + *output_addr = 0; + uint32_t i = 0; + while (current_digit) { + uint32_t shift = ((3 - i) * 8); + unsigned long parsed_value = strtoul(current_digit, NULL, 0) + << shift; + + if (parsed_value == 0 && strcmp(current_digit, "0")) + break; + + *output_addr |= parsed_value; + current_digit = strtok_r(NULL, ".", ¤t_position); + i++; + + } + if (i != 4) + return -1; + + free(tok); + return ret; +} diff --git a/lib/net/rte_ip.h b/lib/net/rte_ip.h index c575250852..188054fda4 100644 --- a/lib/net/rte_ip.h +++ b/lib/net/rte_ip.h @@ -426,6 +426,24 @@ rte_ipv4_udptcp_cksum_verify(const struct rte_ipv4_hdr *ipv4_hdr, return 0; } +/** + * IP address parser. + * + * @param src_ip + * The IP address to be parsed. + * @param output_addr + * The array in which the parsed digits will be saved. + * + * @retval 0 + * Success. + * @retval -1 + * Failure due to invalid input arguments. + */ + +__rte_experimental +int32_t +rte_ip_parse_addr(const char *src_ip, uint32_t *output_addr); + /** * IPv6 Header */ diff --git a/lib/net/version.map b/lib/net/version.map index 4f4330d1c4..3e5a307e48 100644 --- a/lib/net/version.map +++ b/lib/net/version.map @@ -12,3 +12,11 @@ DPDK_22 { local: *; }; + +EXPERIMENTAL { + global: + + rte_net_skip_ip6_ext; + rte_ether_unformat_addr; + rte_ip_parse_addr; +}; From patchwork Tue Dec 14 14:12:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronan Randles X-Patchwork-Id: 105132 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id C3539A00C3; Tue, 14 Dec 2021 15:13:04 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 9984641151; Tue, 14 Dec 2021 15:12:52 +0100 (CET) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by mails.dpdk.org (Postfix) with ESMTP id 5B4AE410E4 for ; Tue, 14 Dec 2021 15:12:50 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1639491170; x=1671027170; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=wOqgJavZuJODwkZCtBBRtyUQznJztXAEEPL7JpEuFs8=; b=Y4cxdItgomr8u3ylS5M7y8igl9/lLrgm7p5NhqP1m0ViNhZH83vH4kl3 cYqIe0/GJeHPcI9O1CqMtc7eyfRmbT+9gImKkBB5kdJsSMdrFoYAJxT+/ QGCduada53VaX+9zW194gTtyAh86Cx9PXxMd3Hv35LcfxISR7So8i4aAQ 6Ux/QEdq7BDhHp5am/tg6dXKQd2zkjM9jSYfxh3MC/GHgh7ToCUBHNLIN 1uC/+z4ciax7jTm3yXcSUACf36SgPRpiLU/7Q9JJ9Mh035uxeNojAyplx 7b5dzvmS5dF+ScT8PCIjTkv3KWHEGxd5tHHUMByXqnC5oEUaDBP9+x910 Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10197"; a="302362304" X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="302362304" Received: from orsmga006.jf.intel.com ([10.7.209.51]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Dec 2021 06:12:49 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="465104094" Received: from silpixa00401120.ir.intel.com ([10.55.129.95]) by orsmga006.jf.intel.com with ESMTP; 14 Dec 2021 06:12:48 -0800 From: Ronan Randles To: dev@dpdk.org Cc: harry.van.haaren@intel.com, Ronan Randles Subject: [PATCH 02/12] net: add function to pretty print IPv4 Date: Tue, 14 Dec 2021 14:12:32 +0000 Message-Id: <20211214141242.3383831-3-ronan.randles@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211214141242.3383831-1-ronan.randles@intel.com> References: <20211214141242.3383831-1-ronan.randles@intel.com> MIME-Version: 1.0 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 This function accepts an uint32_t representation of an IP address and produces a string representation stored in a char * buffer. Realavent unit tests also included. Signed-off-by: Ronan Randles --- app/test/test_net.c | 26 ++++++++++++++++++++++++++ lib/net/rte_ip.c | 15 +++++++++++++++ lib/net/rte_ip.h | 20 ++++++++++++++++++++ lib/net/version.map | 1 + 4 files changed, 62 insertions(+) diff --git a/app/test/test_net.c b/app/test/test_net.c index 2cb7d3e1c9..75beeea671 100644 --- a/app/test/test_net.c +++ b/app/test/test_net.c @@ -46,7 +46,32 @@ test_rte_ip_parse_addr(void) return -1; } } + return 0; +} + +static int +test_rte_ip_print_addr(void) +{ + printf("Running IP printing tests...\n"); + char buffer[128]; + struct ip_str_t { + uint32_t ip_addr; + const char *exp_output; + } ip_str_tests[] = { + { .ip_addr = 16909060, .exp_output = "1.2.3.4"}, + { .ip_addr = 3232301055, . exp_output = "192.168.255.255"}, + { .ip_addr = 2886729737, .exp_output = "172.16.0.9"} + }; + + uint32_t i; + for (i = 0; i < RTE_DIM(ip_str_tests); i++) { + int32_t err = rte_ip_print_addr(ip_str_tests[i].ip_addr, + buffer, 128); + + if (err || strcmp(buffer, ip_str_tests[i].exp_output)) + return -1; + } return 0; } @@ -55,6 +80,7 @@ static int test_net_tests(void) { int ret = test_rte_ip_parse_addr(); + ret += test_rte_ip_print_addr(); return ret; } diff --git a/lib/net/rte_ip.c b/lib/net/rte_ip.c index b859dfb640..fbd9161317 100644 --- a/lib/net/rte_ip.c +++ b/lib/net/rte_ip.c @@ -41,3 +41,18 @@ rte_ip_parse_addr(const char *src_ip, uint32_t *output_addr) free(tok); return ret; } + +int32_t +rte_ip_print_addr(uint32_t ip_addr, char *buffer, uint32_t buffer_size) +{ + if (buffer == NULL) + return -1; + + snprintf(buffer, buffer_size, "%u.%u.%u.%u", + (ip_addr >> 24), + (ip_addr >> 16) & UINT8_MAX, + (ip_addr >> 8) & UINT8_MAX, + ip_addr & UINT8_MAX); + + return 0; +} diff --git a/lib/net/rte_ip.h b/lib/net/rte_ip.h index 188054fda4..e46f0b41ba 100644 --- a/lib/net/rte_ip.h +++ b/lib/net/rte_ip.h @@ -444,6 +444,26 @@ __rte_experimental int32_t rte_ip_parse_addr(const char *src_ip, uint32_t *output_addr); + +/** + * Print IP address from 32 bit int into char * buffer. + * + * @param ip_addr + * ip address to be printed. + * @param buffer + * The buffer the string will be saved into. + * @param buffer_size + * size of buffer to be used. + * + * @retval 0 + * Success. + * @retval -1 + * Failure due to invalid input arguments. + */ +__rte_experimental +int32_t +rte_ip_print_addr(uint32_t ip_addr, char *buffer, uint32_t buffer_size); + /** * IPv6 Header */ diff --git a/lib/net/version.map b/lib/net/version.map index 3e5a307e48..25028f28ff 100644 --- a/lib/net/version.map +++ b/lib/net/version.map @@ -19,4 +19,5 @@ EXPERIMENTAL { rte_net_skip_ip6_ext; rte_ether_unformat_addr; rte_ip_parse_addr; + rte_ip_print_addr; }; From patchwork Tue Dec 14 14:12:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronan Randles X-Patchwork-Id: 105133 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 0E161A00C3; Tue, 14 Dec 2021 15:13:11 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 8B4E841154; Tue, 14 Dec 2021 15:12:53 +0100 (CET) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by mails.dpdk.org (Postfix) with ESMTP id F177341144 for ; Tue, 14 Dec 2021 15:12:50 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1639491171; x=1671027171; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=cRqIAjEh/bn9SIrN0q/HDxXwevFEETN9iAflOuH2jxM=; b=K4ue8ESfO2p+6reHJZ5+fnGGYSOM1pT0Qt5g9+RyWfOD7QOt0mwelyWu vJ0KaGwDqOeVuRiAZZXo5eS2mTPHvX+QoCHKMFHPEnQ5VD0s0F0//eZlN UtvcUsqBylX3LmcobTENW3nV3P8VHKHKc/uENnt4z4XlqA3FF9mhDKxXx b85NIIw1j/aNjKrCs8v7RiMfHCyN0hRmPd74tzOR4p2d851ZSfeqr+TIn pio5n7xcytPNGE2TW25zLc8uzvRVqe225LoO2iAjtG/lvcPakVPTzbq4i SCOP1S0Ga1ZOlEsSFVvRJz/eDYxn02tiSdk/Ny4hOowXoqtzAARXhVBCh g==; X-IronPort-AV: E=McAfee;i="6200,9189,10197"; a="302362306" X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="302362306" Received: from orsmga006.jf.intel.com ([10.7.209.51]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Dec 2021 06:12:50 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="465104103" Received: from silpixa00401120.ir.intel.com ([10.55.129.95]) by orsmga006.jf.intel.com with ESMTP; 14 Dec 2021 06:12:49 -0800 From: Ronan Randles To: dev@dpdk.org Cc: harry.van.haaren@intel.com Subject: [PATCH 03/12] gen: add files for initial traffic generation library Date: Tue, 14 Dec 2021 14:12:33 +0000 Message-Id: <20211214141242.3383831-4-ronan.randles@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211214141242.3383831-1-ronan.randles@intel.com> References: <20211214141242.3383831-1-ronan.randles@intel.com> MIME-Version: 1.0 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 From: Harry van Haaren This commit adds empty files to the DPDK build for a traffic generation library, including the bare create and destroy functions. Unit testing infrastructure is added for the create function. Signed-off-by: Harry van Haaren --- app/test/meson.build | 2 ++ app/test/test_gen.c | 55 +++++++++++++++++++++++++++++++++++++++ doc/api/doxy-api-index.md | 3 ++- doc/api/doxy-api.conf.in | 1 + lib/gen/meson.build | 5 ++++ lib/gen/rte_gen.c | 33 +++++++++++++++++++++++ lib/gen/rte_gen.h | 44 +++++++++++++++++++++++++++++++ lib/gen/version.map | 6 +++++ lib/meson.build | 1 + 9 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 app/test/test_gen.c create mode 100644 lib/gen/meson.build create mode 100644 lib/gen/rte_gen.c create mode 100644 lib/gen/rte_gen.h create mode 100644 lib/gen/version.map diff --git a/app/test/meson.build b/app/test/meson.build index 4cf540fc74..0e4f3b810d 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -66,6 +66,7 @@ test_sources = files( 'test_fib6_perf.c', 'test_func_reentrancy.c', 'test_flow_classify.c', + 'test_gen.c', 'test_graph.c', 'test_graph_perf.c', 'test_hash.c', @@ -173,6 +174,7 @@ test_deps = [ 'eventdev', 'fib', 'flow_classify', + 'gen', 'graph', 'hash', 'ipsec', diff --git a/app/test/test_gen.c b/app/test/test_gen.c new file mode 100644 index 0000000000..f53f4a6608 --- /dev/null +++ b/app/test/test_gen.c @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Intel Corporation + */ + +#include +#include +#include + +#include "test.h" + +static struct rte_mempool *mp; + +static int +testsuite_setup(void) +{ + if (!mp) { + mp = rte_pktmbuf_pool_create("test_gen_mp", 8192, 256, 0, 2048, + SOCKET_ID_ANY); + } + return mp ? TEST_SUCCESS : TEST_FAILED; +} + +static void +testsuite_teardown(void) +{ + rte_mempool_free(mp); +} + +static int +test_gen_create(void) +{ + struct rte_gen *gen = rte_gen_create(mp); + TEST_ASSERT_FAIL(gen, "Expected valid pointer after create()"); + + rte_gen_destroy(gen); + return 0; +} + +static struct unit_test_suite gen_suite = { + .suite_name = "gen: packet generator unit test suite", + .setup = testsuite_setup, + .teardown = testsuite_teardown, + .unit_test_cases = { + TEST_CASE_ST(NULL, NULL, test_gen_create), + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static int +test_gen_suite(void) +{ + return unit_test_suite_runner(&gen_suite); +} + +REGISTER_TEST_COMMAND(gen_autotest, test_gen_suite); diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md index 4245b9635c..f7ddadd21a 100644 --- a/doc/api/doxy-api-index.md +++ b/doc/api/doxy-api-index.md @@ -220,7 +220,8 @@ The public API headers are grouped by topics: [log] (@ref rte_log.h), [errno] (@ref rte_errno.h), [trace] (@ref rte_trace.h), - [trace_point] (@ref rte_trace_point.h) + [trace_point] (@ref rte_trace_point.h), + [gen] (@ref rte_gen.h) - **misc**: [EAL config] (@ref rte_eal.h), diff --git a/doc/api/doxy-api.conf.in b/doc/api/doxy-api.conf.in index db2ca9b6ed..6344e949d9 100644 --- a/doc/api/doxy-api.conf.in +++ b/doc/api/doxy-api.conf.in @@ -41,6 +41,7 @@ INPUT = @TOPDIR@/doc/api/doxy-api-index.md \ @TOPDIR@/lib/eventdev \ @TOPDIR@/lib/fib \ @TOPDIR@/lib/flow_classify \ + @TOPDIR@/lib/gen \ @TOPDIR@/lib/gpudev \ @TOPDIR@/lib/graph \ @TOPDIR@/lib/gro \ diff --git a/lib/gen/meson.build b/lib/gen/meson.build new file mode 100644 index 0000000000..3c5d854645 --- /dev/null +++ b/lib/gen/meson.build @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2021 Intel Corporation + +sources = files('rte_gen.c') +headers = files('rte_gen.h') diff --git a/lib/gen/rte_gen.c b/lib/gen/rte_gen.c new file mode 100644 index 0000000000..d993772422 --- /dev/null +++ b/lib/gen/rte_gen.c @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Intel Corporation + */ + +#include "rte_gen.h" + +#include + +/** Structure that represents a traffic generator. */ +struct rte_gen { + /* Mempool that buffers are retrieved from. */ + struct rte_mempool *mp; +}; + +/* Allocate and initialize a traffic generator instance. */ +struct rte_gen * +rte_gen_create(struct rte_mempool *mempool) +{ + struct rte_gen *gen = rte_zmalloc(NULL, sizeof(*gen), 0); + if (gen == NULL) + return NULL; + + gen->mp = mempool; + + return gen; +} + +/* Free a traffic generator instance. */ +void +rte_gen_destroy(struct rte_gen *gen) +{ + rte_free(gen); +} diff --git a/lib/gen/rte_gen.h b/lib/gen/rte_gen.h new file mode 100644 index 0000000000..5b30430f9e --- /dev/null +++ b/lib/gen/rte_gen.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Intel Corporation + */ + +#ifndef _RTE_GEN_H_ +#define _RTE_GEN_H_ + +/** + * @file + * RTE gen + * + * A library for the generation of packets, to allow easy generation + * of various flows of packets. + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/** Structure that represents a logical traffic generator. */ +struct rte_gen; + +/* Forward declarations for DPDK componeents. */ +struct rte_mempool; + +/* Allocate and initialize a traffic generator instance. */ +__rte_experimental +struct rte_gen * +rte_gen_create(struct rte_mempool *mempool); + +/* Free a traffic generator instance. */ +__rte_experimental +void +rte_gen_destroy(struct rte_gen *gen); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTE_GEN_H_ */ diff --git a/lib/gen/version.map b/lib/gen/version.map new file mode 100644 index 0000000000..d8a26eb53a --- /dev/null +++ b/lib/gen/version.map @@ -0,0 +1,6 @@ +EXPERIMENTAL { + global: + + rte_gen_create; + rte_gen_destroy; +}; diff --git a/lib/meson.build b/lib/meson.build index 018976df17..5b28cd3a89 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -35,6 +35,7 @@ libraries = [ 'efd', 'eventdev', 'gpudev', + 'gen', 'gro', 'gso', 'ip_frag', From patchwork Tue Dec 14 14:12:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronan Randles X-Patchwork-Id: 105134 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 4FBF7A00C3; Tue, 14 Dec 2021 15:13:17 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 8FACD41159; Tue, 14 Dec 2021 15:12:54 +0100 (CET) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by mails.dpdk.org (Postfix) with ESMTP id DA4D54114E for ; Tue, 14 Dec 2021 15:12:51 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1639491172; x=1671027172; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=WAsB5mXVwWeKQGOlTBvfEyGz03MD12da3+NZ+S40ePA=; b=AcB6eXtNnF/juefYnKgfVfk40CIu8Umiz0pru5NcqT/0ThzIIsQgOYoC 3fgXkZHFhpkRuxkJ60XrDmvIym8u0ldTMX3xGPQV5NP2cNsaf3QbuX9wn pTLnTXuUGScQwAHT3M/PSeWzTkVdFpJQcpzzsxG/gxUznYyWiVRUrWc+A KlXPSQdipoKb9KlWGyniE+adjBQA8HaMbyjZOvPyXRBcYr9HdcvYk3DDa AcpBj4HpjqqWwH0Ih2zLOP7zewioKTRmdpx4Q2fFKtTEkzAM7U/6F4cYg yZCuBIsXal5G5vEKNwVG411/OP1oPB2E+DXhD+4NI9SgA2o11Ex7f75vF Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10197"; a="302362309" X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="302362309" Received: from orsmga006.jf.intel.com ([10.7.209.51]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Dec 2021 06:12:51 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="465104113" Received: from silpixa00401120.ir.intel.com ([10.55.129.95]) by orsmga006.jf.intel.com with ESMTP; 14 Dec 2021 06:12:50 -0800 From: Ronan Randles To: dev@dpdk.org Cc: harry.van.haaren@intel.com, Ronan Randles Subject: [PATCH 04/12] gen: add basic Rx and Tx routines and tests Date: Tue, 14 Dec 2021 14:12:34 +0000 Message-Id: <20211214141242.3383831-5-ronan.randles@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211214141242.3383831-1-ronan.randles@intel.com> References: <20211214141242.3383831-1-ronan.randles@intel.com> MIME-Version: 1.0 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 From: Harry van Haaren This commit introduces functions for basic mbuf rx and tx. This commit also contains a unit test that calls rte_gen_rx_burst and rte_gen_tx_burst to send bursts of 32 packets repeatedly in order to verify their functionality Signed-off-by: Harry van Haaren Signed-off-by: Ronan Randles --- app/test/test_gen.c | 46 ++++++++++++++++++++++++++++++++++++++++++ lib/gen/meson.build | 1 + lib/gen/rte_gen.c | 43 +++++++++++++++++++++++++++++++++++++++ lib/gen/rte_gen.h | 49 +++++++++++++++++++++++++++++++++++++++++++++ lib/gen/version.map | 2 ++ 5 files changed, 141 insertions(+) diff --git a/app/test/test_gen.c b/app/test/test_gen.c index f53f4a6608..ceacd8c7c4 100644 --- a/app/test/test_gen.c +++ b/app/test/test_gen.c @@ -8,6 +8,8 @@ #include "test.h" +#define BURST_MAX 32 + static struct rte_mempool *mp; static int @@ -36,12 +38,56 @@ test_gen_create(void) return 0; } +static int +test_gen_basic_rxtx(void) +{ + struct rte_gen *gen = rte_gen_create(mp); + TEST_ASSERT_FAIL(gen, "Expected valid pointer after create()"); + + struct rte_mbuf *bufs[BURST_MAX]; + uint16_t nb_rx = rte_gen_rx_burst(gen, bufs, BURST_MAX); + TEST_ASSERT_EQUAL(nb_rx, BURST_MAX, "Expected rx packet burst."); + + uint64_t latency[BURST_MAX]; + uint16_t nb_tx = rte_gen_tx_burst(gen, bufs, latency, BURST_MAX); + TEST_ASSERT_EQUAL(nb_tx, BURST_MAX, "Expected tx packet burst."); + + rte_gen_destroy(gen); + return 0; +} + +static int +test_gen_loop_rxtx(void) +{ + struct rte_gen *gen = rte_gen_create(mp); + TEST_ASSERT_FAIL(gen, "Expected valid pointer after create()"); + + uint32_t total_sent = 0; + + while (total_sent < 1000000) { + struct rte_mbuf *bufs[BURST_MAX]; + uint16_t nb_rx = rte_gen_rx_burst(gen, bufs, BURST_MAX); + TEST_ASSERT_EQUAL(nb_rx, BURST_MAX, "Expected rx packet burst."); + + uint64_t latency[BURST_MAX]; + uint16_t nb_tx = rte_gen_tx_burst(gen, bufs, latency, nb_rx); + TEST_ASSERT_EQUAL(nb_tx, BURST_MAX, "Expected tx packet burst."); + + total_sent += nb_tx; + } + + rte_gen_destroy(gen); + return 0; +} + static struct unit_test_suite gen_suite = { .suite_name = "gen: packet generator unit test suite", .setup = testsuite_setup, .teardown = testsuite_teardown, .unit_test_cases = { TEST_CASE_ST(NULL, NULL, test_gen_create), + TEST_CASE_ST(NULL, NULL, test_gen_basic_rxtx), + TEST_CASE_ST(NULL, NULL, test_gen_loop_rxtx), TEST_CASES_END() /**< NULL terminate unit test array */ } }; diff --git a/lib/gen/meson.build b/lib/gen/meson.build index 3c5d854645..753984cbba 100644 --- a/lib/gen/meson.build +++ b/lib/gen/meson.build @@ -3,3 +3,4 @@ sources = files('rte_gen.c') headers = files('rte_gen.h') +deps += ['mempool', 'mbuf'] diff --git a/lib/gen/rte_gen.c b/lib/gen/rte_gen.c index d993772422..f0ad57fa81 100644 --- a/lib/gen/rte_gen.c +++ b/lib/gen/rte_gen.c @@ -4,8 +4,11 @@ #include "rte_gen.h" +#include #include +#define GEN_MAX_BURST 32 + /** Structure that represents a traffic generator. */ struct rte_gen { /* Mempool that buffers are retrieved from. */ @@ -31,3 +34,43 @@ rte_gen_destroy(struct rte_gen *gen) { rte_free(gen); } + +uint16_t +rte_gen_rx_burst(struct rte_gen *gen, + struct rte_mbuf **rx_pkts, + const uint16_t nb_pkts) +{ + /* Get a bulk of nb_pkts from the mempool. */ + int err = rte_mempool_get_bulk(gen->mp, (void **)rx_pkts, nb_pkts); + if (err) + return 0; + + const uint32_t pkt_len = 64; + + uint32_t i; + for (i = 0; i < nb_pkts; i++) { + struct rte_mbuf *m = rx_pkts[i]; + uint8_t *pkt_data = rte_pktmbuf_mtod(m, uint8_t *); + + memset(pkt_data, 0, pkt_len); + + m->pkt_len = pkt_len; + m->data_len = pkt_len; + } + + return nb_pkts; +} + +uint16_t +rte_gen_tx_burst(struct rte_gen *gen, + struct rte_mbuf **tx_pkts, + uint64_t *pkt_latencies, + const uint16_t nb_pkts) +{ + RTE_SET_USED(gen); + RTE_SET_USED(pkt_latencies); + + rte_pktmbuf_free_bulk(tx_pkts, nb_pkts); + + return nb_pkts; +} diff --git a/lib/gen/rte_gen.h b/lib/gen/rte_gen.h index 5b30430f9e..09ee1e8872 100644 --- a/lib/gen/rte_gen.h +++ b/lib/gen/rte_gen.h @@ -25,6 +25,7 @@ extern "C" { struct rte_gen; /* Forward declarations for DPDK componeents. */ +struct rte_mbuf; struct rte_mempool; /* Allocate and initialize a traffic generator instance. */ @@ -37,6 +38,54 @@ __rte_experimental void rte_gen_destroy(struct rte_gen *gen); +/** + * Call to receive a burst of generated packets + * + * @param gen + * Gen instance to be used. + * @param rx_pkts + * mbuf where packets will be generated. + * @param nb_pkts + * number of packets to be generated + * + * @retval nb_pkts + * On success the number of rx'ed packets will be returned + * @retval 0 + * Failure. + */ +__rte_experimental +uint16_t +rte_gen_rx_burst(struct rte_gen *gen, + struct rte_mbuf **rx_pkts, + const uint16_t nb_pkts); + +/** Call to transmit a burst of traffic back to the generator. + * This allows the generator to calculate stats/properties of the stream. + * + * If the pkt_latencies parameter is not NULL, it is expected to be a pointer + * to an array of uint64_t values that has nb_pkts in length. Each individual + * packet latency will be stored to the array. + * + * @param gen + * Gen instance to be used. + * @param tx_pkts + * mbuf to be used to tx packets + * @param pkt_latencies + * Array to store latencies of sent packets + * @param nb_pkts + * The number of packets to be tx'ed + * + * @retval nb_pkts + * On success the number of packets tx'ed is returned + */ +__rte_experimental +uint16_t +rte_gen_tx_burst(struct rte_gen *gen, + struct rte_mbuf **tx_pkts, + uint64_t *pkt_latencies, + const uint16_t nb_pkts); + + #ifdef __cplusplus } #endif diff --git a/lib/gen/version.map b/lib/gen/version.map index d8a26eb53a..bdd25add6f 100644 --- a/lib/gen/version.map +++ b/lib/gen/version.map @@ -3,4 +3,6 @@ EXPERIMENTAL { rte_gen_create; rte_gen_destroy; + rte_gen_rx_burst; + rte_gen_tx_burst; }; From patchwork Tue Dec 14 14:12:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronan Randles X-Patchwork-Id: 105135 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 897CBA00C3; Tue, 14 Dec 2021 15:13:23 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 8DAF441161; Tue, 14 Dec 2021 15:12:57 +0100 (CET) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by mails.dpdk.org (Postfix) with ESMTP id BBAE241160 for ; Tue, 14 Dec 2021 15:12:55 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1639491175; x=1671027175; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=AjG5/zvos2AGIL5tqXhozcqeUzARK5umEsMt7TorXVw=; b=GbKCi/X9iFaHI/KGGAhJfLJK8QwSWLcMXINZfJ0oSkZbyiAS/hxzk9Ph LYGs9mz2j6vAb0tC7tHLyTEcCG+wGmHNfzOZw6pgolicvpKFG6gpgs+95 iYbci/6WufbPm5yvs/4KXboG82DfVyrIw9Xjri7RGEiKdvwffDEp1kswF IwGx9Vs6YBsES9V6d6UdTVGUn0a128DmaFW/u/a+uDgsOimy5GNHJiknF FL6j43e//HvxXoSCTk2+1Aw5eTB2zuUriykPUrkxwBH9/brQ8rW37XUNx 39air66v/fIIO6CmXvvCo2uAhdZk2ca47DQiyPOGOgX3UEa5b4J0WHa0q w==; X-IronPort-AV: E=McAfee;i="6200,9189,10197"; a="302362322" X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="302362322" Received: from orsmga006.jf.intel.com ([10.7.209.51]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Dec 2021 06:12:55 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="465104132" Received: from silpixa00401120.ir.intel.com ([10.55.129.95]) by orsmga006.jf.intel.com with ESMTP; 14 Dec 2021 06:12:51 -0800 From: Ronan Randles To: dev@dpdk.org Cc: harry.van.haaren@intel.com Subject: [PATCH 05/12] gen: add raw packet data API and tests Date: Tue, 14 Dec 2021 14:12:35 +0000 Message-Id: <20211214141242.3383831-6-ronan.randles@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211214141242.3383831-1-ronan.randles@intel.com> References: <20211214141242.3383831-1-ronan.randles@intel.com> MIME-Version: 1.0 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 From: Harry van Haaren This commit adds a new API to gen, allowing the caller to set raw packet data with a size. Tests are added to test the new API with randomized packet data. Signed-off-by: Harry van Haaren --- app/test/test_gen.c | 33 ++++++++++++++++++++++++ lib/gen/rte_gen.c | 62 +++++++++++++++++++++++++++++++++++++++++---- lib/gen/rte_gen.h | 9 +++++++ lib/gen/version.map | 1 + 4 files changed, 100 insertions(+), 5 deletions(-) diff --git a/app/test/test_gen.c b/app/test/test_gen.c index ceacd8c7c4..b60ceaef8a 100644 --- a/app/test/test_gen.c +++ b/app/test/test_gen.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "test.h" @@ -75,6 +76,37 @@ test_gen_loop_rxtx(void) total_sent += nb_tx; } + rte_gen_destroy(gen); + return 0; +} + +static int +test_gen_packet_set_raw(void) +{ + struct rte_gen *gen = rte_gen_create(mp); + TEST_ASSERT_FAIL(gen, "Expected valid pointer after create()"); + + /* Set a raw packet payload, and ensure the next received packet has + * that packet data as contents and size. + */ + uint64_t pkt_data[8]; + uint32_t i; + for (i = 0; i < 8; i++) + pkt_data[i] = rte_rand(); + + int32_t err = rte_gen_packet_set_raw(gen, (void *)pkt_data, 64); + TEST_ASSERT_EQUAL(err, 0, "Expected set raw() to return success."); + + struct rte_mbuf *bufs[BURST_MAX]; + uint16_t nb_rx = rte_gen_rx_burst(gen, bufs, 1); + TEST_ASSERT_EQUAL(nb_rx, 1, "Expected rx packet burst."); + + void *mbuf_data = rte_pktmbuf_mtod(bufs[0], void *); + int32_t data_equal = memcmp(pkt_data, mbuf_data, 64) == 0; + TEST_ASSERT_EQUAL(data_equal, 1, + "Expected packet data equal to input data."); + + rte_pktmbuf_free(bufs[0]); rte_gen_destroy(gen); return 0; @@ -88,6 +120,7 @@ static struct unit_test_suite gen_suite = { TEST_CASE_ST(NULL, NULL, test_gen_create), TEST_CASE_ST(NULL, NULL, test_gen_basic_rxtx), TEST_CASE_ST(NULL, NULL, test_gen_loop_rxtx), + TEST_CASE_ST(NULL, NULL, test_gen_packet_set_raw), TEST_CASES_END() /**< NULL terminate unit test array */ } }; diff --git a/lib/gen/rte_gen.c b/lib/gen/rte_gen.c index f0ad57fa81..432be65f1a 100644 --- a/lib/gen/rte_gen.c +++ b/lib/gen/rte_gen.c @@ -6,13 +6,25 @@ #include #include +#include +#include + +RTE_LOG_REGISTER(gen_logtype, lib.gen, NOTICE); + +#define TGEN_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, gen_logtype, "%s(): " fmt, \ + __func__, ## args) #define GEN_MAX_BURST 32 +#define GEN_INIT_PKT_SIZE 64 /** Structure that represents a traffic generator. */ struct rte_gen { /* Mempool that buffers are retrieved from. */ struct rte_mempool *mp; + + /* Packet template to send. */ + struct rte_mbuf *base_pkt; }; /* Allocate and initialize a traffic generator instance. */ @@ -25,6 +37,15 @@ rte_gen_create(struct rte_mempool *mempool) gen->mp = mempool; + uint8_t data[GEN_INIT_PKT_SIZE]; + memset(data, 0, GEN_INIT_PKT_SIZE); + int32_t err = rte_gen_packet_set_raw(gen, data, GEN_INIT_PKT_SIZE); + if (err) { + TGEN_LOG(ERR, "Failed to set initial packet\n"); + rte_free(gen); + return NULL; + } + return gen; } @@ -32,9 +53,37 @@ rte_gen_create(struct rte_mempool *mempool) void rte_gen_destroy(struct rte_gen *gen) { + rte_pktmbuf_free(gen->base_pkt); rte_free(gen); } +int32_t +rte_gen_packet_set_raw(struct rte_gen *gen, + const uint8_t *raw_data, + uint32_t raw_data_size) +{ + + struct rte_mbuf *new_pkt = rte_pktmbuf_alloc(gen->mp); + if (!new_pkt) { + TGEN_LOG(ERR, "Failed to retireve mbuf for parser\n"); + return -ENOMEM; + } + + uint8_t *base_data = rte_pktmbuf_mtod(new_pkt, uint8_t *); + new_pkt->pkt_len = raw_data_size; + new_pkt->data_len = raw_data_size; + rte_memcpy(base_data, raw_data, raw_data_size); + + /* If old packet exists, free it. */ + struct rte_mbuf *old_pkt = gen->base_pkt; + gen->base_pkt = new_pkt; + + if (old_pkt) + rte_pktmbuf_free(old_pkt); + + return 0; +} + uint16_t rte_gen_rx_burst(struct rte_gen *gen, struct rte_mbuf **rx_pkts, @@ -45,17 +94,20 @@ rte_gen_rx_burst(struct rte_gen *gen, if (err) return 0; - const uint32_t pkt_len = 64; + if (!gen->base_pkt) + return 0; + + const uint32_t base_size = gen->base_pkt->pkt_len; + const uint8_t *base_data = rte_pktmbuf_mtod(gen->base_pkt, uint8_t *); uint32_t i; for (i = 0; i < nb_pkts; i++) { struct rte_mbuf *m = rx_pkts[i]; uint8_t *pkt_data = rte_pktmbuf_mtod(m, uint8_t *); - memset(pkt_data, 0, pkt_len); - - m->pkt_len = pkt_len; - m->data_len = pkt_len; + rte_memcpy(pkt_data, base_data, base_size); + m->pkt_len = base_size; + m->data_len = base_size; } return nb_pkts; diff --git a/lib/gen/rte_gen.h b/lib/gen/rte_gen.h index 09ee1e8872..c8d85a5b72 100644 --- a/lib/gen/rte_gen.h +++ b/lib/gen/rte_gen.h @@ -85,6 +85,15 @@ rte_gen_tx_burst(struct rte_gen *gen, uint64_t *pkt_latencies, const uint16_t nb_pkts); +/* Update the packet being sent to the provided raw data. + * @retval 0 Success. + * @retval -ENOMEM No memory available. + */ +int32_t +__rte_experimental +rte_gen_packet_set_raw(struct rte_gen *gen, + const uint8_t *raw_data, + uint32_t raw_data_size); #ifdef __cplusplus } diff --git a/lib/gen/version.map b/lib/gen/version.map index bdd25add6f..d75e0b4bac 100644 --- a/lib/gen/version.map +++ b/lib/gen/version.map @@ -5,4 +5,5 @@ EXPERIMENTAL { rte_gen_destroy; rte_gen_rx_burst; rte_gen_tx_burst; + rte_gen_packet_set_raw; }; From patchwork Tue Dec 14 14:12:36 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronan Randles X-Patchwork-Id: 105136 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 2C6EBA00C3; Tue, 14 Dec 2021 15:13:32 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 036F941174; Tue, 14 Dec 2021 15:12:59 +0100 (CET) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by mails.dpdk.org (Postfix) with ESMTP id 0DCC541160 for ; Tue, 14 Dec 2021 15:12:56 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1639491177; x=1671027177; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ypT+HuKf923gPNTXD4Isc9GzIvf2Asw/23Jt7emBTNs=; b=fdBPadcxPVNr6mFVdH8T+nhUTcrnpMQq+3RGxisU4mWvnG0hlgqe3z5Z dZOwRZgsm4J4qB/1TUfFW82yiIHFZIxEVwu8oNLoLosXZeWUp/Cgd2Bnc PmmPTLppMr1f8IP0wUM7/HffSP9BZ8lnJiwooC5DVfHazBsuiFhM9Nu8t Ti+9DkV0eGgWOVlZIlkgQGBCjYcm8Xmwm9+KCCKZe+/wCgP0a5NHfO8DI yDtOoIUgJLkFctiC/RMIlpRj/h9KrUULeNKtTFnhgK2T9zn9MDczfQ4wq tLZHSqPSpVAOV0f5EAauUIBgAblETNSxH0KUCgtyiI4mPr/7a1nNLOXY6 A==; X-IronPort-AV: E=McAfee;i="6200,9189,10197"; a="302362329" X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="302362329" Received: from orsmga006.jf.intel.com ([10.7.209.51]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Dec 2021 06:12:56 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="465104141" Received: from silpixa00401120.ir.intel.com ([10.55.129.95]) by orsmga006.jf.intel.com with ESMTP; 14 Dec 2021 06:12:55 -0800 From: Ronan Randles To: dev@dpdk.org Cc: harry.van.haaren@intel.com Subject: [PATCH 06/12] gen: add parsing infrastructure and Ether protocol Date: Tue, 14 Dec 2021 14:12:36 +0000 Message-Id: <20211214141242.3383831-7-ronan.randles@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211214141242.3383831-1-ronan.randles@intel.com> References: <20211214141242.3383831-1-ronan.randles@intel.com> MIME-Version: 1.0 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 From: Harry van Haaren This commit adds parsing infrastructure and support for Ether parsing. Appropriate unit tests are also added Signed-off-by: Harry van Haaren --- app/test/test_gen.c | 29 +++++ lib/gen/meson.build | 2 +- lib/gen/rte_gen.c | 281 ++++++++++++++++++++++++++++++++++++++++++++ lib/gen/rte_gen.h | 14 ++- lib/gen/version.map | 1 + 5 files changed, 325 insertions(+), 2 deletions(-) diff --git a/app/test/test_gen.c b/app/test/test_gen.c index b60ceaef8a..324582d0a5 100644 --- a/app/test/test_gen.c +++ b/app/test/test_gen.c @@ -112,6 +112,34 @@ test_gen_packet_set_raw(void) return 0; } +static int +test_gen_packet_parse_string(void) +{ + struct rte_gen *gen = rte_gen_create(mp); + TEST_ASSERT_FAIL(gen, "Expected valid pointer after create()"); + + struct str_parse_t { + const char *str; + } pkt_strings[] = { + { .str = "Ether()"}, + { .str = "Ether()/"}, + { .str = "/Ether()"}, + { .str = "/Ether()/"} + }; + + uint32_t i; + for (i = 0; i < RTE_DIM(pkt_strings); i++) { + const char *pkt_str = pkt_strings[i].str; + int32_t err = rte_gen_packet_parse_string(gen, pkt_str, NULL); + TEST_ASSERT_EQUAL(err, 0, "Expected string %s to parse.", + pkt_str); + } + + rte_gen_destroy(gen); + return 0; +} + + static struct unit_test_suite gen_suite = { .suite_name = "gen: packet generator unit test suite", .setup = testsuite_setup, @@ -121,6 +149,7 @@ static struct unit_test_suite gen_suite = { TEST_CASE_ST(NULL, NULL, test_gen_basic_rxtx), TEST_CASE_ST(NULL, NULL, test_gen_loop_rxtx), TEST_CASE_ST(NULL, NULL, test_gen_packet_set_raw), + TEST_CASE_ST(NULL, NULL, test_gen_packet_parse_string), TEST_CASES_END() /**< NULL terminate unit test array */ } }; diff --git a/lib/gen/meson.build b/lib/gen/meson.build index 753984cbba..b3a55564f4 100644 --- a/lib/gen/meson.build +++ b/lib/gen/meson.build @@ -3,4 +3,4 @@ sources = files('rte_gen.c') headers = files('rte_gen.h') -deps += ['mempool', 'mbuf'] +deps += ['mempool', 'mbuf', 'net'] diff --git a/lib/gen/rte_gen.c b/lib/gen/rte_gen.c index 432be65f1a..ab73120791 100644 --- a/lib/gen/rte_gen.c +++ b/lib/gen/rte_gen.c @@ -9,12 +9,18 @@ #include #include +#include + RTE_LOG_REGISTER(gen_logtype, lib.gen, NOTICE); #define TGEN_LOG(level, fmt, args...) \ rte_log(RTE_LOG_ ## level, gen_logtype, "%s(): " fmt, \ __func__, ## args) +/* Don't prefix with function name, breaks the Scapy style formatting. */ +#define TGEN_LOG_PROTOCOL(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, gen_logtype, fmt, ## args) + #define GEN_MAX_BURST 32 #define GEN_INIT_PKT_SIZE 64 @@ -126,3 +132,278 @@ rte_gen_tx_burst(struct rte_gen *gen, return nb_pkts; } + +enum GEN_PROTO { + GEN_PROTO_INVALID, + GEN_PROTO_ETHER, + + /* Must be last. */ + GEN_PROTO_COUNT, +}; + +typedef void (*gen_log_func)(void *data, const char *indent); + +/* Structure for holding offset and function pointers for protocol. */ +struct protocol_meta { + /* Byte offset into packet where this protocol starts. */ + uint32_t offset; + /* Function to call to log the packet's information. */ + gen_log_func log_func; +}; + +/* Allow up to 32 nexted '/' characters in the protocol string. */ +#define GEN_PROTO_PARSE_MAX 16 + +/* Structure to hold state required while parsing. */ +struct gen_parser { + /* Mbuf the parsed data is being put into. */ + struct rte_mbuf *mbuf; + uint8_t *mbuf_data; + + /* Offset into the packet data to parse to next. */ + uint32_t buf_write_offset; + + /* Parsing state. */ + uint8_t parse_iter; + char indent_str[(GEN_PROTO_PARSE_MAX * 2) + 1]; + + /* String being parsed. */ + char *parse_string; + char *parse_strtok_save_ptr; + + /* Store metadata for parse/display of protocols. */ + struct protocol_meta proto_meta[GEN_PROTO_PARSE_MAX]; + + /* Per protocol hit counters. */ + uint32_t proto_hit_counters[GEN_PROTO_COUNT]; +}; + +/* Forward declaration of recursive parsing function. + * @param inner reports back the inner protocol that was handled. This is often + * required for the outer protocol to indicate what the inner protocol is. + */ +static int32_t +gen_parser_parse_next(struct gen_parser *parser, enum GEN_PROTO *inner); + +/* Return void pointer to the position in the data buffer to parse into. */ +static inline void * +gen_parser_get_data_ptr(struct gen_parser *parser) +{ + return &parser->mbuf_data[parser->buf_write_offset]; +} + +/* Initialize a parser structure. */ +static int32_t +gen_parser_init(struct gen_parser *parser, struct rte_gen *gen, + const char *pkt_string) +{ + /* Initialize own memory to zero. */ + memset(parser, 0, sizeof(*parser)); + + /* Duplicate string for tokenizing string. */ + parser->parse_string = strdup(pkt_string); + if (!parser->parse_string) + goto error; + + /* Allocate mbuf to parse packet into. */ + parser->mbuf = rte_pktmbuf_alloc(gen->mp); + if (!parser->mbuf) + goto error; + + parser->mbuf_data = rte_pktmbuf_mtod(parser->mbuf, uint8_t *); + + return 0; + +error: + free(parser->parse_string); + return -ENOMEM; +} + +static void +gen_log_ether(void *data, const char *indent) +{ + struct rte_ether_hdr *eth = data; + char src[64]; + char dst[64]; + + rte_ether_format_addr(src, 64, ð->src_addr); + rte_ether_format_addr(dst, 64, ð->dst_addr); + const char *type_str; + switch (rte_be_to_cpu_16(eth->ether_type)) { + case RTE_ETHER_TYPE_IPV4: + type_str = "IPv4"; + break; + default: + type_str = "0x9000"; + break; + }; + TGEN_LOG_PROTOCOL(DEBUG, + "###[ Ethernet ]###\n%sdst= %s\n%ssrc= %s\n%stype= %s\n", + indent, dst, indent, src, indent, type_str); +} + +/* Ether(...) string detected, supports parameters: + * - dst : Destination MAC in 00:11:22:33:44:55 or 0011:2233:4455 forms. + * - src : Source MAC in the same forms. + * Note: + * - type is set based on the next header + */ +static int32_t +gen_parse_ether(struct gen_parser *parser, char *protocol_str) +{ + struct rte_ether_hdr *eth = gen_parser_get_data_ptr(parser); + + char *dst_ptr = strstr(protocol_str, "dst="); + if (dst_ptr) { + char *dup = strdup(dst_ptr); + rte_ether_unformat_addr(&dup[4], ð->dst_addr); + free(dup); + } else + rte_ether_unformat_addr("ff:ff:ff:ff:ff:ff", ð->dst_addr); + + char *src_ptr = strstr(protocol_str, "src="); + if (src_ptr) + rte_ether_unformat_addr(&src_ptr[4], ð->src_addr); + else + rte_ether_unformat_addr("00:00:00:00:00:00", ð->src_addr); + + /* Move up write pointer in packet. */ + parser->buf_write_offset += sizeof(*eth); + + /* Recurse and handle inner protocol. */ + enum GEN_PROTO inner; + int32_t err = gen_parser_parse_next(parser, &inner); + if (err) { + TGEN_LOG(ERR, "parser parse next() error %d\n", err); + return err; + } + + switch (inner) { + default: + eth->ether_type = rte_cpu_to_be_16(0x9000); + break; + }; + return 0; +} + +/* (Name, Function-pointer) pairs for supported parse types */ +typedef int32_t (*gen_parse_func)(struct gen_parser *parser, + char *protocol_str); + +struct gen_parse_func_t { + const char *name; + enum GEN_PROTO proto; + gen_parse_func parse_func; + gen_log_func log_func; +}; + +/* Mapping from string to function to parse that protocol. */ +static struct gen_parse_func_t gen_protocols[] = { + { + .name = "Ether(", + .proto = GEN_PROTO_ETHER, + .parse_func = gen_parse_ether, + .log_func = gen_log_ether, + } +}; + +/* Function to tokenize and parse each segment of a string. + * @param outer indicates the protocol before this one. + * @param inner returns the protocol that is parsed here/now. + */ +static int32_t +gen_parser_parse_next(struct gen_parser *parser, + enum GEN_PROTO *inner_proto) +{ + /* Tokenize the input string based on '/' character. */ + char *tok_str = (parser->parse_iter == 0) ? + parser->parse_string : NULL; + parser->parse_string = strtok_r(tok_str, "/", + &parser->parse_strtok_save_ptr); + + /* End protocol parsing recursion when parse_string is NULL, or max + * protocol recursion depth is reached. + */ + if (!parser->parse_string || + parser->parse_iter >= GEN_PROTO_PARSE_MAX) { + struct rte_mbuf *mbuf = parser->mbuf; + mbuf->data_len = parser->buf_write_offset; + mbuf->pkt_len = parser->buf_write_offset; + TGEN_LOG(DEBUG, "packet length %d\n", mbuf->pkt_len); + return 0; + } + + uint32_t i; + /* Loop over protocols, and identify the parse function to call. */ + for (i = 0; i < RTE_DIM(gen_protocols); i++) { + const char *proto = gen_protocols[i].name; + uint32_t proto_len = strlen(proto); + if (strncmp(proto, parser->parse_string, proto_len)) + continue; + + /* Store the log function pointer to output later. */ + uint32_t iter = parser->parse_iter; + parser->proto_hit_counters[i]++; + struct protocol_meta *meta = &parser->proto_meta[iter]; + meta->log_func = gen_protocols[i].log_func; + meta->offset = parser->buf_write_offset; + + /* Handle protocol recursively. */ + parser->parse_iter++; + int err = gen_protocols[i].parse_func(parser, + parser->parse_string); + *inner_proto = gen_protocols[i].proto; + + return err; + } + + TGEN_LOG(ERR, "parser does not understand protocol %s\n", + parser->parse_string); + return -1; +} + +int32_t +rte_gen_packet_parse_string(struct rte_gen *gen, + const char *pkt_string, + struct rte_mbuf **old_mbuf_to_user) +{ + struct gen_parser parser; + int32_t err = gen_parser_init(&parser, gen, pkt_string); + if (err) { + TGEN_LOG(ERR, "error with parser_init(), %d\n", err); + return -1; + }; + + /* Recursively parse each protocol. */ + enum GEN_PROTO inner; + err = gen_parser_parse_next(&parser, &inner); + if (err) { + TGEN_LOG(ERR, "Error in parsing packet string. " + "Set \"gen\" log level to debug for more info.\n"); + return -1; + } + + uint32_t i; + /* Iterate the per protocol stored metadata to log output. */ + for (i = 0; i < parser.parse_iter; i++) { + snprintf(parser.indent_str, 2 + i * 2, + " " /* 32 spaces. */); + void *buf_off = parser.mbuf_data + parser.proto_meta[i].offset; + parser.proto_meta[i].log_func(buf_off, parser.indent_str); + } + + if (inner != GEN_PROTO_ETHER) { + TGEN_LOG(WARNING, + "Outer protocol of frame is not Ethernet.\n"); + } + + /* Free the currently in use mbuf. */ + if (old_mbuf_to_user) + *old_mbuf_to_user = gen->base_pkt; + else + rte_pktmbuf_free(gen->base_pkt); + + /* TODO: HVH design race-condition above vs rx/tx*/ + gen->base_pkt = parser.mbuf; + return 0; +} diff --git a/lib/gen/rte_gen.h b/lib/gen/rte_gen.h index c8d85a5b72..93b3346436 100644 --- a/lib/gen/rte_gen.h +++ b/lib/gen/rte_gen.h @@ -89,12 +89,24 @@ rte_gen_tx_burst(struct rte_gen *gen, * @retval 0 Success. * @retval -ENOMEM No memory available. */ -int32_t __rte_experimental +int32_t rte_gen_packet_set_raw(struct rte_gen *gen, const uint8_t *raw_data, uint32_t raw_data_size); +/* Parse a string description of a packet. + * + * The optional out parameter supplies the previously being sent mbuf to + * the user to be freed later. If this argument is not provided, then the + * mbuf is freed by this function. + */ +__rte_experimental +int32_t +rte_gen_packet_parse_string(struct rte_gen *gen, + const char *pkt_string, + struct rte_mbuf **old_mbuf_to_user); + #ifdef __cplusplus } #endif diff --git a/lib/gen/version.map b/lib/gen/version.map index d75e0b4bac..e335c608ee 100644 --- a/lib/gen/version.map +++ b/lib/gen/version.map @@ -6,4 +6,5 @@ EXPERIMENTAL { rte_gen_rx_burst; rte_gen_tx_burst; rte_gen_packet_set_raw; + rte_gen_packet_parse_string; }; From patchwork Tue Dec 14 14:12:37 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronan Randles X-Patchwork-Id: 105137 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 742EAA00C3; Tue, 14 Dec 2021 15:13:38 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 01E0F4117D; Tue, 14 Dec 2021 15:13:00 +0100 (CET) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by mails.dpdk.org (Postfix) with ESMTP id 5EF7641165 for ; Tue, 14 Dec 2021 15:12:58 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1639491178; x=1671027178; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ZVGj9WVyV3dmDaAfl8IZeyPRexyBoc/wXqkUbabpWxs=; b=OeYc4fEiz1K3VJrc1x9oPuqGtpQa89DYMdlDhibHP1ev0BzjdPvKTnbK j0/yYkVzofWZdQvNLzjRuwSnkbjuEzqoufQdCSzRZx1KIoIlLMzcuhH7h 2iJvrIVVAsI2DnKFpOj2FKTgDJcreRIOGS6WB5nb7mB4GgLcxLSSr+UIq +xC1t548MWQbiAn77NAF0N3zJcZFJOBDp2ERitBfqYBhZLiSBoBWBFMuF wGCf0eTqWIpSmA4PPuTekp4stEZfawWPqH/EsCbcgVmqbcj0dbIXlSnzH 1iGw4sbySj8RzQ2kQO/Lrhcd6egCP0Qx7PFDc6dwMGpZ0FGWXyDnd1kQb w==; X-IronPort-AV: E=McAfee;i="6200,9189,10197"; a="302362333" X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="302362333" Received: from orsmga006.jf.intel.com ([10.7.209.51]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Dec 2021 06:12:57 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="465104146" Received: from silpixa00401120.ir.intel.com ([10.55.129.95]) by orsmga006.jf.intel.com with ESMTP; 14 Dec 2021 06:12:56 -0800 From: Ronan Randles To: dev@dpdk.org Cc: harry.van.haaren@intel.com, Ronan Randles Subject: [PATCH 07/12] gen: add gen IP parsing Date: Tue, 14 Dec 2021 14:12:37 +0000 Message-Id: <20211214141242.3383831-8-ronan.randles@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211214141242.3383831-1-ronan.randles@intel.com> References: <20211214141242.3383831-1-ronan.randles@intel.com> MIME-Version: 1.0 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 From: Harry van Haaren This commit adds support for the parsing of "IP(src=...,dst=...)" strings. Parse string API improvement for app RCU. Appropriate unit tests also added. Signed-off-by: Harry van Haaren Signed-off-by: Ronan Randles --- app/test/test_gen.c | 29 +++++++-- lib/gen/rte_gen.c | 146 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 170 insertions(+), 5 deletions(-) diff --git a/app/test/test_gen.c b/app/test/test_gen.c index 324582d0a5..7b67835c80 100644 --- a/app/test/test_gen.c +++ b/app/test/test_gen.c @@ -117,26 +117,47 @@ test_gen_packet_parse_string(void) { struct rte_gen *gen = rte_gen_create(mp); TEST_ASSERT_FAIL(gen, "Expected valid pointer after create()"); - struct str_parse_t { const char *str; + uint32_t expected_to_fail; } pkt_strings[] = { { .str = "Ether()"}, { .str = "Ether()/"}, { .str = "/Ether()"}, - { .str = "/Ether()/"} + { .str = "/Ether()/"}, + { .str = "Ether()/IP()"}, + { .str = "Ether()/IP(src=1.2.3.4,dst=5.6.7.8)"}, + { .str = "Ether()/IP(src=1.2.3.4,dst=192.168.255.255)"}, + { .str = "Ether()/IP(dst=172.16.0.9,src=1.2.3.4)"}, + { .str = "Ether()/IP(src=1.2.3.4)"}, + { .str = "Ether()/IP(srdst=5.6.7.8)", .expected_to_fail = 1}, + { .str = "Ether()/IP(src=1.2.3.4,ds=)", .expected_to_fail = 1}, + { .str = "Ether()/IP(src=1.2.3.4,dst=)", .expected_to_fail = 1}, + { .str = "Ether()/IP(src=,dst=5.6.7.8)", .expected_to_fail = 1}, + { .str = "Ether()/IP(sr=,dst=5.6.7.8)", .expected_to_fail = 1}, + { .str = "Ether()/IP(src=1.2.3.fail,dst=5.6.7.8)", + .expected_to_fail = 1}, }; uint32_t i; for (i = 0; i < RTE_DIM(pkt_strings); i++) { const char *pkt_str = pkt_strings[i].str; int32_t err = rte_gen_packet_parse_string(gen, pkt_str, NULL); - TEST_ASSERT_EQUAL(err, 0, "Expected string %s to parse.", - pkt_str); + + if (err && pkt_strings[i].expected_to_fail != 1) { + printf("Expected string %s to parse.", pkt_str); + return -1; + } + /* False pass if reached with no err when e_t_f = 1 */ + if (!err && pkt_strings[i].expected_to_fail) { + printf("False Pass on string: %s\n", pkt_str); + return -1; + } } rte_gen_destroy(gen); return 0; + } diff --git a/lib/gen/rte_gen.c b/lib/gen/rte_gen.c index ab73120791..3dac436cff 100644 --- a/lib/gen/rte_gen.c +++ b/lib/gen/rte_gen.c @@ -10,6 +10,7 @@ #include #include +#include RTE_LOG_REGISTER(gen_logtype, lib.gen, NOTICE); @@ -136,6 +137,7 @@ rte_gen_tx_burst(struct rte_gen *gen, enum GEN_PROTO { GEN_PROTO_INVALID, GEN_PROTO_ETHER, + GEN_PROTO_IPV4, /* Must be last. */ GEN_PROTO_COUNT, @@ -219,6 +221,140 @@ gen_parser_init(struct gen_parser *parser, struct rte_gen *gen, return -ENOMEM; } +static void +gen_log_ipv4(void *data, const char *indent) +{ + struct rte_ipv4_hdr *ip = data; + + const char *proto_str; + switch (ip->next_proto_id) { + case 0: + proto_str = "hopopt"; + break; + default: + proto_str = "unknown next proto"; + break; + } + + TGEN_LOG_PROTOCOL(DEBUG, + "###[ IP ]###\n%sversion = %d\n%sihl = %d\n%stos = %d\n" + "%slen = %d\n%sid = %d\n%sflags = 0x%x\n%sfrag = %d\n" + "%sttl = %d\n%sproto = %s (%d)\n%schksum 0x%x\n%ssrc = 0x%x\n" + "%sdst = 0x%x\n%soptions = %s\n", + indent, ip->version_ihl >> 4, + indent, ip->version_ihl & RTE_IPV4_HDR_IHL_MASK, + indent, ip->type_of_service, + indent, rte_be_to_cpu_16(ip->total_length), + indent, rte_be_to_cpu_16(ip->packet_id), /* TODO: Scapy ID? */ + indent, rte_be_to_cpu_16(ip->packet_id), /*TODO: Scapy Flags?*/ + indent, rte_be_to_cpu_16(ip->fragment_offset), + indent, ip->time_to_live, + indent, proto_str, ip->next_proto_id, + indent, rte_be_to_cpu_16(ip->hdr_checksum), + indent, rte_be_to_cpu_32(ip->src_addr), + indent, rte_be_to_cpu_32(ip->dst_addr), + indent, "notImplemented"); +} + +static int32_t +gen_parse_ipv4_params(char *protocol_str, struct rte_ipv4_hdr *ip) +{ + /* Strings to look for. */ + static const char * const items[] = { + "src=", + "dst=", + }; + const uint32_t num_items = RTE_DIM(items); + + char *tok_ptr; + uint32_t err = 0; + uint32_t i; + for (i = 0; i < num_items; i++) { + /* Print input string into local buffer for processing. */ + char buffer[1024]; + int chars_printed = snprintf(buffer, 1024, "%s", protocol_str); + if (chars_printed >= 1024) + return -1; + + /* Find substring (e.g. src=) if not found skip to next one. */ + char *start = strstr(buffer, items[i]); + char check_previous[32]; + if (start != NULL) { + snprintf(check_previous, 32, "%.1s", start - 1); + if (strcmp(&check_previous[0], "(") && + strcmp(&check_previous[0], ",")) + return -EINVAL; + } + + if (!start) { + if (!strstr(buffer, ",")) + continue; + else + return -EINVAL; + } + /* get from start of string till first , character. */ + char *item = strtok_r(start, ",", &tok_ptr); + + if (strcmp(item, items[i]) == 0) + return -EINVAL; + /* skip past the src= prefix. We know string is long enough as + * otherwise strstr() wouldn't have matched it. + */ + item = &item[4]; + + if (strcmp(items[i], "src=") == 0) { + err = rte_ip_parse_addr(item, &ip->src_addr); + ip->src_addr = rte_cpu_to_be_32(ip->src_addr); + } else { + err = rte_ip_parse_addr(item, &ip->dst_addr); + ip->dst_addr = rte_cpu_to_be_32(ip->dst_addr); + } + if (err) { + TGEN_LOG(ERR, "parser ip_parse_addr error %d\n", err); + return err; + } + } + return 0; +} + +static int32_t +gen_parse_ipv4(struct gen_parser *parser, char *protocol_str) +{ + struct rte_ipv4_hdr *ip = gen_parser_get_data_ptr(parser); + memset(ip, 0, sizeof(*ip)); + ip->version_ihl = RTE_IPV4_VHL_DEF; + + /* default addrs */ + ip->src_addr = RTE_IPV4(127, 0, 0, 1); + ip->dst_addr = RTE_IPV4(127, 0, 0, 1); + + uint32_t err = 0; + if (strcmp("IP()", protocol_str)) + err = gen_parse_ipv4_params(protocol_str, ip); + + if (err) { + TGEN_LOG(ERR, "parser parse ipv4 params error %d\n", err); + return err; + } + + /* Move up write pointer in packet, recurse to next. */ + enum GEN_PROTO inner; + parser->buf_write_offset += rte_ipv4_hdr_len(ip); + err = gen_parser_parse_next(parser, &inner); + if (err) { + TGEN_LOG(ERR, "parser parse next() error %d\n", err); + return err; + } + + switch (inner) { + default: + /* Default protocol is hopopt (0). */ + break; + }; + + return 0; +} + static void gen_log_ether(void *data, const char *indent) { @@ -304,7 +440,14 @@ static struct gen_parse_func_t gen_protocols[] = { .proto = GEN_PROTO_ETHER, .parse_func = gen_parse_ether, .log_func = gen_log_ether, - } + }, + { + .name = "IP(", + .proto = GEN_PROTO_IPV4, + .parse_func = gen_parse_ipv4, + .log_func = gen_log_ipv4, + }, + }; /* Function to tokenize and parse each segment of a string. @@ -380,6 +523,7 @@ rte_gen_packet_parse_string(struct rte_gen *gen, if (err) { TGEN_LOG(ERR, "Error in parsing packet string. " "Set \"gen\" log level to debug for more info.\n"); + rte_pktmbuf_free(parser.mbuf); return -1; } From patchwork Tue Dec 14 14:12:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronan Randles X-Patchwork-Id: 105138 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 5F27DA00C3; Tue, 14 Dec 2021 15:13:44 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id DD9E04116A; Tue, 14 Dec 2021 15:13:01 +0100 (CET) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by mails.dpdk.org (Postfix) with ESMTP id 7380541178 for ; Tue, 14 Dec 2021 15:12:59 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1639491179; x=1671027179; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=IIKYW+Z+43Ib9qY+rOCVzyISxAjcRPtzp3o2kDYSWf4=; b=NCxqnqFAas8c/7SdHeyyiWUWmw/3OjYC3Lsit3E1QnxPCodBeEZk+eVP QPP/g7HVTbSoSV40SXw7iXTUTjnrr7aa/t3m1qtX6d30D8CsWTSjLDkK7 rsq3xcRvdSUtK4HyJxvSyB4+FdfBIryQcnmeUMGgOG8PsEeTi17vmyslc am1oYPWDDpQKtE6qk9jv+X99ddNlEum0cXYgxaBwQJoQrOpewI7C8hXIu 8CRqNkUKEUDAj1bQLarGfZ7P8OAxEMfedsSDu4NohwXxhPb4cnxxrpzTr bJkz7gyDxLW2vgB//Qqz/yxUrMmmaMWi37itn24gFOzbcVfmppiGpeRL4 A==; X-IronPort-AV: E=McAfee;i="6200,9189,10197"; a="302362335" X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="302362335" Received: from orsmga006.jf.intel.com ([10.7.209.51]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Dec 2021 06:12:59 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="465104155" Received: from silpixa00401120.ir.intel.com ([10.55.129.95]) by orsmga006.jf.intel.com with ESMTP; 14 Dec 2021 06:12:57 -0800 From: Ronan Randles To: dev@dpdk.org Cc: harry.van.haaren@intel.com, Ronan Randles Subject: [PATCH 08/12] examples/generator: import code from basicfwd.c Date: Tue, 14 Dec 2021 14:12:38 +0000 Message-Id: <20211214141242.3383831-9-ronan.randles@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211214141242.3383831-1-ronan.randles@intel.com> References: <20211214141242.3383831-1-ronan.randles@intel.com> MIME-Version: 1.0 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 From: Harry van Haaren Import files from basicfwd.c to act as starting point for gen library sample app Signed-off-by: Harry van Haaren Signed-off-by: Ronan Randles --- examples/generator/main.c | 226 +++++++++++++++++++++++++++++++++ examples/generator/meson.build | 12 ++ 2 files changed, 238 insertions(+) create mode 100644 examples/generator/main.c create mode 100644 examples/generator/meson.build diff --git a/examples/generator/main.c b/examples/generator/main.c new file mode 100644 index 0000000000..0082f588b4 --- /dev/null +++ b/examples/generator/main.c @@ -0,0 +1,226 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2015 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include + +#define RX_RING_SIZE 1024 +#define TX_RING_SIZE 1024 + +#define NUM_MBUFS 8191 +#define MBUF_CACHE_SIZE 256 +#define BURST_SIZE 32 + +/* Configuration of ethernet ports. 8< */ +static const struct rte_eth_conf port_conf_default = { + .rxmode = { + .max_lro_pkt_size = RTE_ETHER_MAX_LEN, + }, +}; +/* >8 End of configuration of ethernet ports. */ + +/* basicfwd.c: Basic DPDK skeleton forwarding example. */ + +/* + * Initializes a given port using global settings and with the RX buffers + * coming from the mbuf_pool passed as a parameter. + */ + +/* Main functional part of port initialization. 8< */ +static inline int +port_init(uint16_t port, struct rte_mempool *mbuf_pool) +{ + struct rte_eth_conf port_conf = port_conf_default; + const uint16_t rx_rings = 1, tx_rings = 1; + uint16_t nb_rxd = RX_RING_SIZE; + uint16_t nb_txd = TX_RING_SIZE; + int retval; + uint16_t q; + struct rte_eth_dev_info dev_info; + struct rte_eth_txconf txconf; + + if (!rte_eth_dev_is_valid_port(port)) + return -1; + + retval = rte_eth_dev_info_get(port, &dev_info); + if (retval != 0) { + printf("Error during getting device (port %u) info: %s\n", + port, strerror(-retval)); + return retval; + } + + if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) + port_conf.txmode.offloads |= + DEV_TX_OFFLOAD_MBUF_FAST_FREE; + + /* Configure the Ethernet device. */ + retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf); + if (retval != 0) + return retval; + + retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd); + if (retval != 0) + return retval; + + /* Allocate and set up 1 RX queue per Ethernet port. */ + for (q = 0; q < rx_rings; q++) { + retval = rte_eth_rx_queue_setup(port, q, nb_rxd, + rte_eth_dev_socket_id(port), NULL, mbuf_pool); + if (retval < 0) + return retval; + } + + txconf = dev_info.default_txconf; + txconf.offloads = port_conf.txmode.offloads; + /* Allocate and set up 1 TX queue per Ethernet port. */ + for (q = 0; q < tx_rings; q++) { + retval = rte_eth_tx_queue_setup(port, q, nb_txd, + rte_eth_dev_socket_id(port), &txconf); + if (retval < 0) + return retval; + } + + /* Starting Ethernet port. 8< */ + retval = rte_eth_dev_start(port); + /* >8 End of starting of ethernet port. */ + if (retval < 0) + return retval; + + /* Display the port MAC address. */ + struct rte_ether_addr addr; + retval = rte_eth_macaddr_get(port, &addr); + if (retval != 0) + return retval; + + printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8 + " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n", + port, RTE_ETHER_ADDR_BYTES(&addr)); + + /* Enable RX in promiscuous mode for the Ethernet device. */ + retval = rte_eth_promiscuous_enable(port); + /* End of setting RX port in promiscuous mode. */ + if (retval != 0) + return retval; + + return 0; +} +/* >8 End of main functional part of port initialization. */ + +/* + * The lcore main. This is the main thread that does the work, reading from + * an input port and writing to an output port. + */ + + /* Basic forwarding application lcore. 8< */ +static __rte_noreturn void +lcore_main(void) +{ + uint16_t port; + + /* + * Check that the port is on the same NUMA node as the polling thread + * for best performance. + */ + RTE_ETH_FOREACH_DEV(port) + if (rte_eth_dev_socket_id(port) >= 0 && + rte_eth_dev_socket_id(port) != + (int)rte_socket_id()) + printf("WARNING, port %u is on remote NUMA node to " + "polling thread.\n\tPerformance will " + "not be optimal.\n", port); + + printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n", + rte_lcore_id()); + + /* Main work of application loop. 8< */ + for (;;) { + /* + * Receive packets on a port and forward them on the paired + * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc. + */ + RTE_ETH_FOREACH_DEV(port) { + + /* Get burst of RX packets, from first port of pair. */ + struct rte_mbuf *bufs[BURST_SIZE]; + const uint16_t nb_rx = rte_eth_rx_burst(port, 0, + bufs, BURST_SIZE); + + if (unlikely(nb_rx == 0)) + continue; + + /* Send burst of TX packets, to second port of pair. */ + const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0, + bufs, nb_rx); + + /* Free any unsent packets. */ + if (unlikely(nb_tx < nb_rx)) { + uint16_t buf; + for (buf = nb_tx; buf < nb_rx; buf++) + rte_pktmbuf_free(bufs[buf]); + } + } + } + /* >8 End of loop. */ +} +/* >8 End Basic forwarding application lcore. */ + +/* + * The main function, which does initialization and calls the per-lcore + * functions. + */ +int +main(int argc, char *argv[]) +{ + struct rte_mempool *mbuf_pool; + unsigned int nb_ports; + uint16_t portid; + + /* Initializion the Environment Abstraction Layer (EAL). 8< */ + int ret = rte_eal_init(argc, argv); + if (ret < 0) + rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); + /* >8 End of initializion the Environment Abstraction Layer (EAL). */ + + argc -= ret; + argv += ret; + + /* Check that there is an even number of ports to send/receive on. */ + nb_ports = rte_eth_dev_count_avail(); + if (nb_ports < 2 || (nb_ports & 1)) + rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n"); + + /* Creates a new mempool in memory to hold the mbufs. */ + + /* Allocates mempool to hold the mbufs. 8< */ + mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports, + MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); + /* >8 End of allocating mempool to hold mbuf. */ + + if (mbuf_pool == NULL) + rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n"); + + /* Initializing all ports. 8< */ + RTE_ETH_FOREACH_DEV(portid) + if (port_init(portid, mbuf_pool) != 0) + rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu16 "\n", + portid); + /* >8 End of initializing all ports. */ + + if (rte_lcore_count() > 1) + printf("\nWARNING: Too many lcores enabled. Only 1 used.\n"); + + /* Call lcore_main on the main core only. Called on single lcore. 8< */ + lcore_main(); + /* >8 End of called on single lcore. */ + + /* clean up the EAL */ + rte_eal_cleanup(); + + return 0; +} diff --git a/examples/generator/meson.build b/examples/generator/meson.build new file mode 100644 index 0000000000..441678bbe5 --- /dev/null +++ b/examples/generator/meson.build @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2017 Intel Corporation + +# 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' + +allow_experimental_apis = true +sources = files( + 'main.c', +) From patchwork Tue Dec 14 14:12:39 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronan Randles X-Patchwork-Id: 105142 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 437CAA00C3; Tue, 14 Dec 2021 15:14:09 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 5862F411CB; Tue, 14 Dec 2021 15:13:17 +0100 (CET) Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by mails.dpdk.org (Postfix) with ESMTP id 0B5E34114D for ; Tue, 14 Dec 2021 15:13:12 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1639491193; x=1671027193; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=A4TR+Iv3bwbzdF1neNp9lNkV6o0Wa4LZudFokwIVJD8=; b=XM0y/XxwKo8NjIX84NjEYgtIVBjBRkqXtirrHk9jKj3+S9jYcezkHj98 c4IFlmrWi1WrDvDX5X7C721sHu8egCUnvsy+mHfNoLVbeAnm/eETwEMTA gWzX+NnH/XlIcFrsaRrfkLS2Cfz7cIG6SYvHbrfsRvK0HpE2RfUceJ0CW 3s4IaoIRpp/0PHmhD0I+iENie+LaYyAVn1ym3eHS3YgvGX3haL2pVuxD/ lqFOUAQj9rkIDrQF/U2dJ5VMDpxAk0lUgGUWHkygMKDNeBZJq4cFc19Fp TtbgE1WzP55KHFBSSQGvnf/gCBKRCfmxn6SuHKdAFiaD+ZVK2ujVwF13A A==; X-IronPort-AV: E=McAfee;i="6200,9189,10197"; a="263123887" X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="263123887" Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Dec 2021 06:13:11 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="465104165" Received: from silpixa00401120.ir.intel.com ([10.55.129.95]) by orsmga006.jf.intel.com with ESMTP; 14 Dec 2021 06:12:59 -0800 From: Ronan Randles To: dev@dpdk.org Cc: harry.van.haaren@intel.com, Ronan Randles Subject: [PATCH 09/12] examples/generator: enable gen library for traffic gen Date: Tue, 14 Dec 2021 14:12:39 +0000 Message-Id: <20211214141242.3383831-10-ronan.randles@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211214141242.3383831-1-ronan.randles@intel.com> References: <20211214141242.3383831-1-ronan.randles@intel.com> MIME-Version: 1.0 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 This commit shows the steps necessary to enable traffic generation using the gen library Signed-off-by: Ronan Randles --- examples/generator/main.c | 175 ++++++++++++++++++++++----------- examples/generator/meson.build | 1 + examples/meson.build | 1 + 3 files changed, 120 insertions(+), 57 deletions(-) diff --git a/examples/generator/main.c b/examples/generator/main.c index 0082f588b4..1ddf4c1603 100644 --- a/examples/generator/main.c +++ b/examples/generator/main.c @@ -1,14 +1,18 @@ /* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2010-2015 Intel Corporation + * Copyright(c) 2021 Intel Corporation */ #include #include +#include +#include + #include #include #include #include #include +#include #define RX_RING_SIZE 1024 #define TX_RING_SIZE 1024 @@ -16,23 +20,23 @@ #define NUM_MBUFS 8191 #define MBUF_CACHE_SIZE 256 #define BURST_SIZE 32 +#define MIN_THREADS 3 -/* Configuration of ethernet ports. 8< */ static const struct rte_eth_conf port_conf_default = { .rxmode = { .max_lro_pkt_size = RTE_ETHER_MAX_LEN, }, }; -/* >8 End of configuration of ethernet ports. */ -/* basicfwd.c: Basic DPDK skeleton forwarding example. */ +static volatile int done; +static struct rte_mempool *mbuf_pool; +struct rte_gen *gen; + +static void handle_sigint(int sig); -/* - * Initializes a given port using global settings and with the RX buffers +/* Initializes a given port using global settings and with the RX buffers * coming from the mbuf_pool passed as a parameter. */ - -/* Main functional part of port initialization. 8< */ static inline int port_init(uint16_t port, struct rte_mempool *mbuf_pool) { @@ -68,6 +72,12 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool) if (retval != 0) return retval; + int lcore_available_count = rte_lcore_count(); + if (lcore_available_count < MIN_THREADS) { + printf("Not enough threads available\n"); + return -1; + } + /* Allocate and set up 1 RX queue per Ethernet port. */ for (q = 0; q < rx_rings; q++) { retval = rte_eth_rx_queue_setup(port, q, nb_rxd, @@ -86,9 +96,8 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool) return retval; } - /* Starting Ethernet port. 8< */ + /* Start the Ethernet port. */ retval = rte_eth_dev_start(port); - /* >8 End of starting of ethernet port. */ if (retval < 0) return retval; @@ -104,27 +113,67 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool) /* Enable RX in promiscuous mode for the Ethernet device. */ retval = rte_eth_promiscuous_enable(port); - /* End of setting RX port in promiscuous mode. */ if (retval != 0) return retval; return 0; } -/* >8 End of main functional part of port initialization. */ -/* - * The lcore main. This is the main thread that does the work, reading from +/* The lcore main. This is the main thread that does the work, reading from * an input port and writing to an output port. */ +static int +lcore_producer(__rte_unused void *arg) +{ + uint16_t port; + + /* Check that the port is on the same NUMA node as the polling thread + * for best performance. + */ + RTE_ETH_FOREACH_DEV(port) + if (rte_eth_dev_socket_id(port) >= 0 && + rte_eth_dev_socket_id(port) != + (int)rte_socket_id()) + printf("WARNING, port %u is on remote NUMA node to " + "polling thread.\n\tPerformance will " + "not be optimal.\n", port); - /* Basic forwarding application lcore. 8< */ -static __rte_noreturn void -lcore_main(void) + /* Run until the application is quit or killed. */ + while (!done) { + struct rte_mbuf *bufs[BURST_SIZE]; + int i; + /* Receive packets from gen and then tx them over port */ + RTE_ETH_FOREACH_DEV(port) { + int nb_recieved = rte_gen_rx_burst(gen, bufs, + BURST_SIZE); + for (i = 0; i < nb_recieved; i++) { + bufs[i]->pkt_len = 64; + bufs[i]->data_len = 64; + } + + uint16_t nb_tx = rte_eth_tx_burst(port, 0, bufs, + nb_recieved); + if (nb_tx != nb_recieved) + rte_pktmbuf_free_bulk(&bufs[nb_tx], + (nb_recieved - nb_tx)); + + if (unlikely(nb_tx == 0)) + continue; + + } + } + return 0; +} + +/* The lcore main. This is the main thread that does the work, reading from + * an input port and writing to an output port. + */ +static int +lcore_consumer(__rte_unused void *arg) { uint16_t port; - /* - * Check that the port is on the same NUMA node as the polling thread + /* Check that the port is on the same NUMA node as the polling thread * for best performance. */ RTE_ETH_FOREACH_DEV(port) @@ -135,57 +184,53 @@ lcore_main(void) "polling thread.\n\tPerformance will " "not be optimal.\n", port); - printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n", - rte_lcore_id()); + /* Run until the application is quit or killed. */ + while (!done) { + struct rte_mbuf *bufs[BURST_SIZE]; - /* Main work of application loop. 8< */ - for (;;) { - /* - * Receive packets on a port and forward them on the paired - * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc. + /* Receive packets over port and then tx them to gen library + * for stats */ RTE_ETH_FOREACH_DEV(port) { + uint64_t latency[BURST_SIZE]; + uint16_t nb_rx = rte_eth_rx_burst(port, 0, bufs, + BURST_SIZE); + rte_gen_tx_burst(gen, bufs, latency, nb_rx); - /* Get burst of RX packets, from first port of pair. */ - struct rte_mbuf *bufs[BURST_SIZE]; - const uint16_t nb_rx = rte_eth_rx_burst(port, 0, - bufs, BURST_SIZE); + int nb_sent = rte_gen_tx_burst(gen, bufs, + latency, nb_rx); + if (nb_sent != nb_rx) + rte_panic("invalid tx quantity\n"); if (unlikely(nb_rx == 0)) continue; - /* Send burst of TX packets, to second port of pair. */ - const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0, - bufs, nb_rx); - - /* Free any unsent packets. */ - if (unlikely(nb_tx < nb_rx)) { - uint16_t buf; - for (buf = nb_tx; buf < nb_rx; buf++) - rte_pktmbuf_free(bufs[buf]); - } } } - /* >8 End of loop. */ + return 0; } -/* >8 End Basic forwarding application lcore. */ -/* - * The main function, which does initialization and calls the per-lcore +void handle_sigint(int sig) +{ + RTE_SET_USED(sig); + printf("\nExiting...\n"); + done = 1; +} + +/* The main function, which does initialization and calls the per-lcore * functions. */ int main(int argc, char *argv[]) { - struct rte_mempool *mbuf_pool; + signal(SIGINT, handle_sigint); unsigned int nb_ports; uint16_t portid; - /* Initializion the Environment Abstraction Layer (EAL). 8< */ + /* Initialize the Environment Abstraction Layer (EAL). */ int ret = rte_eal_init(argc, argv); if (ret < 0) rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); - /* >8 End of initializion the Environment Abstraction Layer (EAL). */ argc -= ret; argv += ret; @@ -196,28 +241,44 @@ main(int argc, char *argv[]) rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n"); /* Creates a new mempool in memory to hold the mbufs. */ - - /* Allocates mempool to hold the mbufs. 8< */ mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports, MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); - /* >8 End of allocating mempool to hold mbuf. */ if (mbuf_pool == NULL) rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n"); - /* Initializing all ports. 8< */ + /* Initialize all ports. */ RTE_ETH_FOREACH_DEV(portid) if (port_init(portid, mbuf_pool) != 0) rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu16 "\n", portid); - /* >8 End of initializing all ports. */ - if (rte_lcore_count() > 1) - printf("\nWARNING: Too many lcores enabled. Only 1 used.\n"); + gen = rte_gen_create(mbuf_pool); + if (!gen) + rte_panic("Gen failed to initialize\n"); + + int err = rte_gen_packet_parse_string(gen, "Ether()/IP()", NULL); + if (err) + rte_panic("Failed to parse input args"); + + /* launch lcore functions */ + uint32_t lcore_count = 0; + uint32_t lcore_id = 0; + RTE_LCORE_FOREACH_WORKER(lcore_id) { + if (lcore_count == 0) + rte_eal_remote_launch(lcore_producer, NULL, lcore_id); + else if (lcore_count == 1) + rte_eal_remote_launch(lcore_consumer, NULL, lcore_id); + else + break; + + lcore_count++; + } + /* Stall the main thread until all other threads have returned. */ + rte_eal_mp_wait_lcore(); - /* Call lcore_main on the main core only. Called on single lcore. 8< */ - lcore_main(); - /* >8 End of called on single lcore. */ + /* All threads returned, safe to destroy gen instance */ + rte_gen_destroy(gen); /* clean up the EAL */ rte_eal_cleanup(); diff --git a/examples/generator/meson.build b/examples/generator/meson.build index 441678bbe5..15d84674a5 100644 --- a/examples/generator/meson.build +++ b/examples/generator/meson.build @@ -10,3 +10,4 @@ allow_experimental_apis = true sources = files( 'main.c', ) +deps += 'gen' \ No newline at end of file diff --git a/examples/meson.build b/examples/meson.build index bac9b76007..79ce36d02b 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -18,6 +18,7 @@ all_examples = [ 'fips_validation', 'flow_classify', 'flow_filtering', + 'generator', 'helloworld', 'ip_fragmentation', 'ip_pipeline', From patchwork Tue Dec 14 14:12:40 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronan Randles X-Patchwork-Id: 105139 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id C0CFFA00C3; Tue, 14 Dec 2021 15:13:51 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 5DC594116D; Tue, 14 Dec 2021 15:13:13 +0100 (CET) Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by mails.dpdk.org (Postfix) with ESMTP id BF2144113E for ; Tue, 14 Dec 2021 15:13:11 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1639491192; x=1671027192; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=blrv1Ml9lglykgpd1bZI3k3TjycHzHs86fbrdnx7Lu0=; b=KS2QSKhkgsNv/Uhncu9OPqgO8CJfyRCOQrmql88+T05vAc7v04+dyCHZ 0Ch4WvNG7vEOCkAF3C/cW90EOBV2PEWukYu5zRM8hhJVTGS7gAuFBpIVi Dgl1PzYsvH0PqeA1hqw0FQqTOc+f02fH+woWS/NRAwe8YVc743LXznx54 HzCjxQ9S2t3ckDty6KOXwS5W+/5QVqJOLev2qdMNTVGpkD5GosZfRXM98 pndV8RaJV+r/ppOiFTsbEE0U/iwn3X11r4rHeZiAvwpjeM8Vf9vEdgHTG qajbifYhCgBiDPNlhH5VPf5RX1YsU0NxcfhTTCbbmNA9BV7v9zP2csfTH Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10197"; a="263123883" X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="263123883" Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Dec 2021 06:13:10 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="465104177" Received: from silpixa00401120.ir.intel.com ([10.55.129.95]) by orsmga006.jf.intel.com with ESMTP; 14 Dec 2021 06:13:00 -0800 From: Ronan Randles To: dev@dpdk.org Cc: harry.van.haaren@intel.com, Ronan Randles Subject: [PATCH 10/12] examples/generator: telemetry support Date: Tue, 14 Dec 2021 14:12:40 +0000 Message-Id: <20211214141242.3383831-11-ronan.randles@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211214141242.3383831-1-ronan.randles@intel.com> References: <20211214141242.3383831-1-ronan.randles@intel.com> MIME-Version: 1.0 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 This commit adds telemetry introducing the callback functions and returning measured values Signed-off-by: Ronan Randles --- examples/generator/main.c | 159 ++++++++++++++++++++++++++++++++------ 1 file changed, 135 insertions(+), 24 deletions(-) diff --git a/examples/generator/main.c b/examples/generator/main.c index 1ddf4c1603..2525d34b6e 100644 --- a/examples/generator/main.c +++ b/examples/generator/main.c @@ -13,6 +13,7 @@ #include #include #include +#include #define RX_RING_SIZE 1024 #define TX_RING_SIZE 1024 @@ -32,6 +33,29 @@ static volatile int done; static struct rte_mempool *mbuf_pool; struct rte_gen *gen; +struct gen_args { + /* Inputs */ + struct rte_gen *gen; + + /* Outputs */ + uint64_t tx_total_packets; + uint64_t rx_total_packets; + uint64_t rx_missed_total; + uint64_t tx_failed; + uint64_t last_tx_total; + uint64_t measured_tx_pps; + + +} __rte_cache_aligned; +/* Expose a struct as a global so the telemetry callbacks can access the + * data required to provide stats etc. + */ +struct telemetry_userdata { + struct gen_args *prod; + struct gen_args *cons; +}; +static struct telemetry_userdata telemetry_userdata; + static void handle_sigint(int sig); /* Initializes a given port using global settings and with the RX buffers @@ -123,10 +147,11 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool) * an input port and writing to an output port. */ static int -lcore_producer(__rte_unused void *arg) +lcore_producer(void *arg) { + struct gen_args *args = arg; + struct rte_gen *gen = args->gen; uint16_t port; - /* Check that the port is on the same NUMA node as the polling thread * for best performance. */ @@ -138,25 +163,34 @@ lcore_producer(__rte_unused void *arg) "polling thread.\n\tPerformance will " "not be optimal.\n", port); + uint64_t tsc_hz = rte_get_tsc_hz(); + uint64_t last_tsc_reading = 0; + uint64_t last_tx_total = 0; + /* Run until the application is quit or killed. */ while (!done) { struct rte_mbuf *bufs[BURST_SIZE]; - int i; + uint16_t nb_tx = 0; /* Receive packets from gen and then tx them over port */ RTE_ETH_FOREACH_DEV(port) { - int nb_recieved = rte_gen_rx_burst(gen, bufs, + int nb_generated = rte_gen_rx_burst(gen, bufs, BURST_SIZE); - for (i = 0; i < nb_recieved; i++) { - bufs[i]->pkt_len = 64; - bufs[i]->data_len = 64; - } - uint16_t nb_tx = rte_eth_tx_burst(port, 0, bufs, - nb_recieved); - if (nb_tx != nb_recieved) - rte_pktmbuf_free_bulk(&bufs[nb_tx], - (nb_recieved - nb_tx)); + uint64_t start_tsc = rte_rdtsc(); + if (start_tsc > last_tsc_reading + tsc_hz) { + args->measured_tx_pps = args->tx_total_packets - + last_tx_total; + last_tx_total = args->tx_total_packets; + last_tsc_reading = start_tsc; + } + nb_tx = rte_eth_tx_burst(port, 0, bufs, nb_generated); + args->tx_total_packets += nb_tx; + uint64_t tx_failed = nb_generated - nb_tx; + if (nb_tx != nb_generated) { + rte_pktmbuf_free_bulk(&bufs[nb_tx], tx_failed); + args->tx_failed += tx_failed; + } if (unlikely(nb_tx == 0)) continue; @@ -169,10 +203,11 @@ lcore_producer(__rte_unused void *arg) * an input port and writing to an output port. */ static int -lcore_consumer(__rte_unused void *arg) +lcore_consumer(void *arg) { + struct gen_args *args = arg; + struct rte_gen *gen = args->gen; uint16_t port; - /* Check that the port is on the same NUMA node as the polling thread * for best performance. */ @@ -195,16 +230,16 @@ lcore_consumer(__rte_unused void *arg) uint64_t latency[BURST_SIZE]; uint16_t nb_rx = rte_eth_rx_burst(port, 0, bufs, BURST_SIZE); - rte_gen_tx_burst(gen, bufs, latency, nb_rx); + if (unlikely(nb_rx == 0)) + continue; + + args->rx_total_packets += nb_rx; int nb_sent = rte_gen_tx_burst(gen, bufs, latency, nb_rx); if (nb_sent != nb_rx) rte_panic("invalid tx quantity\n"); - if (unlikely(nb_rx == 0)) - continue; - } } return 0; @@ -217,6 +252,58 @@ void handle_sigint(int sig) done = 1; } +static int +tele_gen_packet(const char *cmd, const char *params, struct rte_tel_data *d) +{ + RTE_SET_USED(cmd); + RTE_SET_USED(params); + RTE_SET_USED(d); + + rte_tel_data_string(d, "Ether()/IP()"); + return 0; +} + +static int +tele_gen_mpps(const char *cmd, const char *params, struct rte_tel_data *d) +{ + struct gen_args *args = telemetry_userdata.prod; + RTE_SET_USED(cmd); + if (params) { + rte_tel_data_add_dict_int(d, "TEST", + (args->measured_tx_pps/1000000)); + } + rte_tel_data_start_dict(d); + rte_tel_data_add_dict_int(d, "mpps", + (args->measured_tx_pps/1000000)); + return 0; +} + +static int +tele_gen_stats(const char *cmd, const char *params, struct rte_tel_data *d) +{ + RTE_SET_USED(cmd); + RTE_SET_USED(params); + + struct gen_args *args_prod = telemetry_userdata.prod; + struct gen_args *args_cons = telemetry_userdata.cons; + rte_tel_data_start_dict(d); + static const char * const stats[] = { + "tx_total_packets", + "rx_total_packets", + "measured_tx_pps" + }; + + uint64_t values[RTE_DIM(stats)] = {0}; + values[0] = args_prod->tx_total_packets; + values[1] = args_cons->rx_total_packets; + values[2] = args_prod->measured_tx_pps; + + uint32_t i; + for (i = 0; i < RTE_DIM(stats); i++) + rte_tel_data_add_dict_int(d, stats[i], values[i]); + + return 0; +} /* The main function, which does initialization and calls the per-lcore * functions. */ @@ -224,6 +311,10 @@ int main(int argc, char *argv[]) { signal(SIGINT, handle_sigint); + + #define CORE_COUNT 2 + struct gen_args core_launch_args[CORE_COUNT]; + unsigned int nb_ports; uint16_t portid; @@ -253,7 +344,7 @@ main(int argc, char *argv[]) rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu16 "\n", portid); - gen = rte_gen_create(mbuf_pool); + struct rte_gen *gen = rte_gen_create(mbuf_pool); if (!gen) rte_panic("Gen failed to initialize\n"); @@ -261,19 +352,39 @@ main(int argc, char *argv[]) if (err) rte_panic("Failed to parse input args"); + memset(core_launch_args, 0, sizeof(struct gen_args) * CORE_COUNT); /* launch lcore functions */ uint32_t lcore_count = 0; uint32_t lcore_id = 0; RTE_LCORE_FOREACH_WORKER(lcore_id) { - if (lcore_count == 0) - rte_eal_remote_launch(lcore_producer, NULL, lcore_id); - else if (lcore_count == 1) - rte_eal_remote_launch(lcore_consumer, NULL, lcore_id); + core_launch_args[lcore_count].gen = gen; + if (lcore_count == 0) { + telemetry_userdata.prod = + &core_launch_args[lcore_count]; + rte_eal_remote_launch(lcore_producer, + telemetry_userdata.prod, + lcore_id); + } else if (lcore_count == 1) { + telemetry_userdata.cons = + &core_launch_args[lcore_count]; + rte_eal_remote_launch(lcore_consumer, + telemetry_userdata.cons, + lcore_id); + } else break; lcore_count++; } + + /* Export stats via Telemetry */ + rte_telemetry_register_cmd("/gen/stats", tele_gen_stats, + "Return statistics of the Gen instance."); + rte_telemetry_register_cmd("/gen/packet", tele_gen_packet, + "Return the Gen string packet being sent."); + rte_telemetry_register_cmd("/gen/mpps", tele_gen_mpps, + "Get/Set the mpps rate"); + /* Stall the main thread until all other threads have returned. */ rte_eal_mp_wait_lcore(); From patchwork Tue Dec 14 14:12:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronan Randles X-Patchwork-Id: 105140 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 8C05DA00C3; Tue, 14 Dec 2021 15:13:57 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 667E541155; Tue, 14 Dec 2021 15:13:14 +0100 (CET) Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by mails.dpdk.org (Postfix) with ESMTP id 8F5BD4113E for ; Tue, 14 Dec 2021 15:13:12 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1639491192; x=1671027192; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=pJwgtgPDAa76cI6LGrsSGCMlAYxRRljoTl6XxGmmILo=; b=dtHy81VU5CxAodSatC11eu7BeLgYsfoHLfhA14vw5Zn0zws7fBI4CT5q kmhtdpPkUJsZNRa9rEuxAYuHxd9fkB0KG0j14zyngfDigTArvzcK5+42x MrS7/+aUzdNv0gmK0fXJVORPeHXZZTd+tz+0RLZhi11HIXj7z73pCNF0T js7f0auqjhdw++P7PTB5Q327pp7NgTGc+A2UFcFN+3P/NTUobTzfwRb7B ZS5b23LmCKhZiF69Qx9W27kD2ERpCZVvufWkhei9U8cryWneKs3VQrt2v wbjqTmoQH5MTA+jWXpVx7D5QfVKZzlfNyx4Zc08d1RItvAOw7B9IV8dml Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10197"; a="263123885" X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="263123885" Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Dec 2021 06:13:11 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="465104187" Received: from silpixa00401120.ir.intel.com ([10.55.129.95]) by orsmga006.jf.intel.com with ESMTP; 14 Dec 2021 06:13:01 -0800 From: Ronan Randles To: dev@dpdk.org Cc: harry.van.haaren@intel.com, Ronan Randles Subject: [PATCH 11/12] examples/generator: link status check added Date: Tue, 14 Dec 2021 14:12:41 +0000 Message-Id: <20211214141242.3383831-12-ronan.randles@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211214141242.3383831-1-ronan.randles@intel.com> References: <20211214141242.3383831-1-ronan.randles@intel.com> MIME-Version: 1.0 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 This commit brings in a link status check so that the generator will only start sending packets once there is something on the other end of the link. Signed-off-by: Ronan Randles --- examples/generator/main.c | 70 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/examples/generator/main.c b/examples/generator/main.c index 2525d34b6e..f11110e528 100644 --- a/examples/generator/main.c +++ b/examples/generator/main.c @@ -27,9 +27,13 @@ static const struct rte_eth_conf port_conf_default = { .rxmode = { .max_lro_pkt_size = RTE_ETHER_MAX_LEN, }, + .intr_conf = { + .lsc = 1, /**< lsc interrupt */ + }, }; static volatile int done; +static volatile int link_status[RTE_MAX_ETHPORTS]; static struct rte_mempool *mbuf_pool; struct rte_gen *gen; @@ -58,6 +62,30 @@ static struct telemetry_userdata telemetry_userdata; static void handle_sigint(int sig); +static int +link_status_change_cb(uint16_t port_id, enum rte_eth_event_type type, + void *param, void *ret_param) +{ + if (unlikely(port_id >= RTE_DIM(link_status))) + rte_panic("got LSC interrupt for unknown port id\n"); + + RTE_SET_USED(type); + RTE_SET_USED(param); + RTE_SET_USED(ret_param); + + struct rte_eth_link link; + int ret = rte_eth_link_get_nowait(port_id, &link); + if (ret < 0) { + printf("Failed link get on port %d: %s\n", + port_id, rte_strerror(-ret)); + return ret; + } + + printf("Link status change port %i\n", port_id); + link_status[port_id] = link.link_status; + return 0; +} + /* Initializes a given port using global settings and with the RX buffers * coming from the mbuf_pool passed as a parameter. */ @@ -101,6 +129,9 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool) printf("Not enough threads available\n"); return -1; } + /* Register the LinkStatusChange callback */ + rte_eth_dev_callback_register(port, RTE_ETH_EVENT_INTR_LSC, + link_status_change_cb, NULL); /* Allocate and set up 1 RX queue per Ethernet port. */ for (q = 0; q < rx_rings; q++) { @@ -140,6 +171,16 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool) if (retval != 0) return retval; + struct rte_eth_link link; + int ret = rte_eth_link_get_nowait(port, &link); + if (ret < 0) { + printf("Failed link get on port %d: %s\n", port, + rte_strerror(-ret)); + return ret; + } + + link_status[port] = link.link_status; + return 0; } @@ -166,12 +207,26 @@ lcore_producer(void *arg) uint64_t tsc_hz = rte_get_tsc_hz(); uint64_t last_tsc_reading = 0; uint64_t last_tx_total = 0; + uint16_t nb_tx = 0; + + /* Ensure all available ports are up before generating packets */ + uint16_t nb_eth_ports = rte_eth_dev_count_avail(); + uint16_t nb_links_up = 0; + while (!done && nb_links_up < nb_eth_ports) { + if (link_status[nb_links_up]) + nb_links_up++; + + rte_delay_us_block(100); + } + if (!done) + printf("Generating packets...\n"); /* Run until the application is quit or killed. */ while (!done) { + struct rte_mbuf *bufs[BURST_SIZE]; - uint16_t nb_tx = 0; /* Receive packets from gen and then tx them over port */ + RTE_ETH_FOREACH_DEV(port) { int nb_generated = rte_gen_rx_burst(gen, bufs, BURST_SIZE); @@ -219,8 +274,19 @@ lcore_consumer(void *arg) "polling thread.\n\tPerformance will " "not be optimal.\n", port); + /* Ensure all available ports are up before generating packets */ + uint16_t nb_eth_ports = rte_eth_dev_count_avail(); + uint16_t nb_links_up = 0; + while (!done && nb_links_up < nb_eth_ports) { + if (link_status[nb_links_up]) + nb_links_up++; + + rte_delay_us_block(100); + } + /* Run until the application is quit or killed. */ while (!done) { + struct rte_mbuf *bufs[BURST_SIZE]; /* Receive packets over port and then tx them to gen library @@ -257,8 +323,6 @@ tele_gen_packet(const char *cmd, const char *params, struct rte_tel_data *d) { RTE_SET_USED(cmd); RTE_SET_USED(params); - RTE_SET_USED(d); - rte_tel_data_string(d, "Ether()/IP()"); return 0; } From patchwork Tue Dec 14 14:12:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronan Randles X-Patchwork-Id: 105141 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id BAA6BA00C3; Tue, 14 Dec 2021 15:14:03 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 55C9E41165; Tue, 14 Dec 2021 15:13:16 +0100 (CET) Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by mails.dpdk.org (Postfix) with ESMTP id 433204113E for ; Tue, 14 Dec 2021 15:13:13 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1639491193; x=1671027193; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=CdycJcAYeHM3OgHS/fagPgCLHQVDaTX4QYJINF2j4I0=; b=ZGqfstuqs/SM3qt0Cvl0BbqQhz3SeWS//w/bdMqn8CTcU6k4WkIYjcG0 Mb/6KZnLKajPTO+5uF+ZD5xDNbZtTroeVv6RCxg6P0Ug63BttRiu4PO0d 8m2RLpo0KurXM04ANPIB0R6sts9sC1G/z0jFyshoout5od6tgWES65pNc Ejw0/xYrRR6/gDMXipu4iyPM9ej8MM2DZc6Cu7eRIAxBhg1rZnVSHpZjZ Nuk0/Q2Pbc1DFqdid/v4zkX4V+sepmBeXHeiuzpEQ7d9c28e5Ix6Qro0N MN+yPp8WRkqqoRsrzIWNMJZwhPeYVy1j7rWEpx/J47NIgYld9al555cT4 g==; X-IronPort-AV: E=McAfee;i="6200,9189,10197"; a="263123889" X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="263123889" Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Dec 2021 06:13:11 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="465104210" Received: from silpixa00401120.ir.intel.com ([10.55.129.95]) by orsmga006.jf.intel.com with ESMTP; 14 Dec 2021 06:13:02 -0800 From: Ronan Randles To: dev@dpdk.org Cc: harry.van.haaren@intel.com, Ronan Randles Subject: [PATCH 12/12] examples/generator: line rate limiting Date: Tue, 14 Dec 2021 14:12:42 +0000 Message-Id: <20211214141242.3383831-13-ronan.randles@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211214141242.3383831-1-ronan.randles@intel.com> References: <20211214141242.3383831-1-ronan.randles@intel.com> MIME-Version: 1.0 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 This commit introduces line rate limiting using a token passing method. The target traffic rate default is currently hard coded, this can be set using telemetry. Signed-off-by: Ronan Randles --- examples/generator/main.c | 77 +++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 28 deletions(-) diff --git a/examples/generator/main.c b/examples/generator/main.c index f11110e528..3847cde755 100644 --- a/examples/generator/main.c +++ b/examples/generator/main.c @@ -40,6 +40,7 @@ struct rte_gen *gen; struct gen_args { /* Inputs */ struct rte_gen *gen; + uint64_t target_tx_pps; /* Outputs */ uint64_t tx_total_packets; @@ -205,9 +206,11 @@ lcore_producer(void *arg) "not be optimal.\n", port); uint64_t tsc_hz = rte_get_tsc_hz(); + float tsc_hz_f = (float)tsc_hz; uint64_t last_tsc_reading = 0; uint64_t last_tx_total = 0; uint16_t nb_tx = 0; + float tokens = 0; /* Ensure all available ports are up before generating packets */ uint16_t nb_eth_ports = rte_eth_dev_count_avail(); @@ -221,34 +224,52 @@ lcore_producer(void *arg) if (!done) printf("Generating packets...\n"); + uint64_t token_last_add_tsc = rte_rdtsc(); + /* Run until the application is quit or killed. */ while (!done) { - struct rte_mbuf *bufs[BURST_SIZE]; - /* Receive packets from gen and then tx them over port */ - - RTE_ETH_FOREACH_DEV(port) { - int nb_generated = rte_gen_rx_burst(gen, bufs, - BURST_SIZE); - - uint64_t start_tsc = rte_rdtsc(); - if (start_tsc > last_tsc_reading + tsc_hz) { - args->measured_tx_pps = args->tx_total_packets - - last_tx_total; - last_tx_total = args->tx_total_packets; - last_tsc_reading = start_tsc; + /* Track time since last token add and calculate number + * of tokens to give per second to implement line rate limiting + */ + uint64_t now = rte_rdtsc(); + uint64_t tsc_delta = now - token_last_add_tsc; + float token_scalar = (float)tsc_delta / tsc_hz_f; + float add_tokens = args->target_tx_pps * token_scalar; + /* If there are tokens to be added and we haven't exceeded + * the target rate then we add tokens + */ + if (add_tokens > 1.f) { + if (tokens < args->target_tx_pps) { + tokens += add_tokens; + token_last_add_tsc = now; } - nb_tx = rte_eth_tx_burst(port, 0, bufs, nb_generated); - args->tx_total_packets += nb_tx; - - uint64_t tx_failed = nb_generated - nb_tx; - if (nb_tx != nb_generated) { - rte_pktmbuf_free_bulk(&bufs[nb_tx], tx_failed); - args->tx_failed += tx_failed; + } + /* Receive packets from gen and then tx them over port */ + if (tokens >= BURST_SIZE) { + RTE_ETH_FOREACH_DEV(port) { + int nb_generated = rte_gen_rx_burst(gen, bufs, + BURST_SIZE); + + uint64_t start_tsc = rte_rdtsc(); + if (start_tsc > last_tsc_reading + tsc_hz) { + args->measured_tx_pps = + args->tx_total_packets - last_tx_total; + last_tx_total = args->tx_total_packets; + last_tsc_reading = start_tsc; + } + nb_tx = rte_eth_tx_burst(port, 0, bufs, + nb_generated); + args->tx_total_packets += nb_tx; + tokens -= nb_tx; + + uint64_t tx_failed = nb_generated - nb_tx; + if (nb_tx != nb_generated) { + rte_pktmbuf_free_bulk(&bufs[nb_tx], + tx_failed); + args->tx_failed += tx_failed; + } } - if (unlikely(nb_tx == 0)) - continue; - } } return 0; @@ -298,7 +319,6 @@ lcore_consumer(void *arg) BURST_SIZE); if (unlikely(nb_rx == 0)) continue; - args->rx_total_packets += nb_rx; int nb_sent = rte_gen_tx_burst(gen, bufs, @@ -333,12 +353,11 @@ tele_gen_mpps(const char *cmd, const char *params, struct rte_tel_data *d) struct gen_args *args = telemetry_userdata.prod; RTE_SET_USED(cmd); if (params) { - rte_tel_data_add_dict_int(d, "TEST", - (args->measured_tx_pps/1000000)); + args->target_tx_pps = atoi(params) * 1000000; + printf("Packet rate set: %li\n", args->target_tx_pps); } rte_tel_data_start_dict(d); - rte_tel_data_add_dict_int(d, "mpps", - (args->measured_tx_pps/1000000)); + rte_tel_data_add_dict_int(d, "mpps", args->target_tx_pps); return 0; } @@ -425,6 +444,8 @@ main(int argc, char *argv[]) if (lcore_count == 0) { telemetry_userdata.prod = &core_launch_args[lcore_count]; + /* Default traffic rate */ + telemetry_userdata.prod->target_tx_pps = 20000000; rte_eal_remote_launch(lcore_producer, telemetry_userdata.prod, lcore_id);