From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 89E5FA04AF; Tue, 11 Aug 2020 10:53:32 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id B236C1C0B4; Tue, 11 Aug 2020 10:53:09 +0200 (CEST) Received: from mailout1.w1.samsung.com (mailout1.w1.samsung.com [210.118.77.11]) by dpdk.org (Postfix) with ESMTP id 7D4BD1C027 for ; Tue, 11 Aug 2020 10:53:06 +0200 (CEST) Received: from eucas1p2.samsung.com (unknown [182.198.249.207]) by mailout1.w1.samsung.com (KnoxPortal) with ESMTP id 20200811085305euoutp017700cab035e83a88ec695f868dc2cb04~qKreMUUiq0826508265euoutp01Z; Tue, 11 Aug 2020 08:53:05 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout1.w1.samsung.com 20200811085305euoutp017700cab035e83a88ec695f868dc2cb04~qKreMUUiq0826508265euoutp01Z DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1597135985; bh=yjuhr21wJK56U6WY1nzuFW3DUMB8s5LfzNkDjUmUCik=; h=From:To:Subject:Date:In-Reply-To:Reply-To:References:From; b=Gnwp6ehTrK/CQjsgWOka/Qwp2BBAUhfjKjcf8xIYo4LxRgOf7meb1R+7onw3zD6xX Gr5jkdI2efxm57lIxeX1qMiZ8EYloZLgJPu1C5ON1a0OyWF7xfrUXpzute/yxnrQlv ZegS9wV1XQkVio8JSZ1nziuZNDhUQZKBhUDBpQ7Q= Received: from eusmges1new.samsung.com (unknown [203.254.199.242]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20200811085305eucas1p26c584841ada9b17f6673d234840c64b2~qKrd7rdl90327403274eucas1p2n; Tue, 11 Aug 2020 08:53:05 +0000 (GMT) Received: from eucas1p2.samsung.com ( [182.198.249.207]) by eusmges1new.samsung.com (EUCPMTA) with SMTP id D2.A1.06456.17C523F5; Tue, 11 Aug 2020 09:53:05 +0100 (BST) Received: from eusmtrp1.samsung.com (unknown [182.198.249.138]) by eucas1p1.samsung.com (KnoxPortal) with ESMTPA id 20200811085304eucas1p150bf23b6f183a28fbceca06b0bced5af~qKrdZOCc11585315853eucas1p1r; Tue, 11 Aug 2020 08:53:04 +0000 (GMT) Received: from eusmgms2.samsung.com (unknown [182.198.249.180]) by eusmtrp1.samsung.com (KnoxPortal) with ESMTP id 20200811085304eusmtrp1009d3c2447cf63ad5568125e233dd0f9~qKrdYWuwe1603916039eusmtrp1S; Tue, 11 Aug 2020 08:53:04 +0000 (GMT) X-AuditID: cbfec7f2-7efff70000001938-dd-5f325c71eb62 Received: from eusmtip1.samsung.com ( [203.254.199.221]) by eusmgms2.samsung.com (EUCPMTA) with SMTP id 5E.3D.06017.07C523F5; Tue, 11 Aug 2020 09:53:04 +0100 (BST) Received: from idyukov.rnd.samsung.ru (unknown [106.109.129.29]) by eusmtip1.samsung.com (KnoxPortal) with ESMTPA id 20200811085302eusmtip18b20bc89818035a60d5f97482751c7f9~qKrbkxqD51792217922eusmtip1H; Tue, 11 Aug 2020 08:53:02 +0000 (GMT) From: Ivan Dyukov To: dev@dpdk.org, i.dyukov@samsung.com, v.kuramshin@samsung.com, thomas@monjalon.net, david.marchand@redhat.com, ferruh.yigit@intel.com, arybchenko@solarflare.com, wei.zhao1@intel.com, jia.guo@intel.com, beilei.xing@intel.com, qiming.yang@intel.com, wenzhuo.lu@intel.com, mb@smartsharesystems.com, stephen@networkplumber.org, nicolas.chautru@intel.com, bruce.richardson@intel.com, konstantin.ananyev@intel.com, cristian.dumitrescu@intel.com, radu.nicolau@intel.com, akhil.goyal@nxp.com, declan.doherty@intel.com, skori@marvell.com, pbhagavatula@marvell.com, jerinj@marvell.com, kirankumark@marvell.com, david.hunt@intel.com, anatoly.burakov@intel.com, xiaoyun.li@intel.com, jingjing.wu@intel.com, john.mcnamara@intel.com, jasvinder.singh@intel.com, byron.marohn@intel.com, yipeng1.wang@intel.com Date: Tue, 11 Aug 2020 11:52:21 +0300 Message-Id: <20200811085246.28735-3-i.dyukov@samsung.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200811085246.28735-1-i.dyukov@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA0VSf0wTdxTPu7veXRvqjsLCC3MSmpBsmqlsmrzpNpxZtksMi8n+Ic4Nz3lB M36tBTaXbEFwzJWuQtVtwCwIGGhLxM7KD6MD6wKygp0Yo0RGiWFrFH9WCOBgjnqY/ff5+d7L N1+RNR3hk8U9+UWqJV/JNfMGrqNvLvTKZ9tfzV57oyqe2gddQDfHmlgaP/wnT5UP9jN03ZNB Zzt/1pEzXMqQw/mQoc5WG093xss4uhftZGj0XFCg2uEygaKBiEDfh+qAIvO3WappeAQUcp3W 0dz5Mzzdn2/kyPH4KtBB/0WgfvtDjg53dwFV2CR64G4RqGl0BUXHL3IUHDklUNv0ZZZODy4A Vfe3Aw1VPNFtSpUfNxzXyU1nbzHyoWOXWblv5AdBtg+4GNl3r4uR7/96lZcdfg/Iv9+sZGXv xCy/1bDN8MYuNXdPiWpZ89YOw263z84XXmiEL8JDQaYUQmVgA72I0jqcOTGziA2iSWoFtA/U 8xqZAgwdaRY08giwdbiHeVbpHq0WYtgktQA6Jwu10DTgidYaLmbw0ksYPOBiYkai5OOxc/7a 03aC9B6WT+zT2UAUOSkNDy4kx6BReh0dgXe1+SnoPdnLxrBe2oDeujCr7VqB1+qnno5E6Q8R x2tDnFZ4B/1j7qXjEvB2v1/Q8HIMHrJzWuFbwOqOU4JGqgDL6+4upTLQP3lJiF3BSi9j+5k1 mvw2tkU8TExGaRlevxsfk9lF6Oz4kdVkIx6oMGlpM/YODC/JiAv/xGmyjLNzI0sPeg7wN69d qIKU2v93NQB4IEkttublqNb0fPXz1VYlz1qcn7P6k4K8X2Dxswb/7Y92wfTwzgBIIpjjjIUb 07NNOqXEujcvACiy5kTj5qHgxybjLmXvl6qlINtSnKtaA/CCyJmTjK813vrIJOUoReqnqlqo Wp65jKhPLoX1bXNpLVuHohU9NZU3Vq1/sTqjrd7hmU+y7Zz5K+LdmDC1xb2vSN2fWf7muuzE k66So74nvi0LYxvavzOnO43elXETV37K3NzzYVVaynMzvYlMVnM339yhj4T/Lij5OnXwfeWD 845vUrM2Xfiq9ooy7a1/Pmtt36X4JndmeHa5ftmdSTNn3a2kr2QtVuU/XXXU/agDAAA= X-Brightmail-Tracker: H4sIAAAAAAAAAzWSa0hTYRjHe885OztKi8OyevOD5ckiAmdnaj6aWkSXQxAoRR/MsqUHldxm O1OyhHSJybSZZkW35aXIS1JeSg3LWqHVFLF7qTnEkDKmeSPFSy7p2x9+/+fHA8/DkMpJypNJ 1BlFg06TxNHulH2urdc3OVods/nruC/cb7ci6P9WRoKjqJeG3JEsAj5XboPmhhsyKOzLIMBS +JuAhnIzDb8cJgqcow0E9Dyxy+HaW5McRm2DcjjfeR3B4MxPEq4WjyHotD6UwdTzxzQMz5RS YJn+gCC//hWCtrzfFBQ1NSLINrMwUnFXDmU9XjDqeEWB/UudHO5NdJHwsH0WQUHbfQQd2fOy 7d7CdPEdmVDW/IMQLpZ0kULrl8tyIe+1lRBqnI2EMPz0Ay1Y6iuR8KY/lxSqBv7QEe5RqlCD PsUork3QS8Yw7hAPahUfDCp1QLCK9w86HKIO5PzCQ+PEpMRU0eAXflSVUFGTRye/KEUn+zrs RAbqNCEzcmMwG4CbegrkZuTOKNk7CBdmzZNmxCwAjIcGyMXOcjzz0UwvdsYQvtjQTbgAzW7E 9hwr4QIebDeN353LpFxgObsHnx3IlLlEFLse5896uqKCDcYW2+5F5xpc9eDZP78bG4Krrvf9 y0o2EWf2NtGL2Qt/ujVOXEDLitGSSuQhpkjaeK2kVkkarZSii1fF6rW1aOHmj1qn6huR2bnf hlgGcUsVyVv5GKVMkyqlaW0IMyTnodjRYT+iVMRp0k6JBn2MISVJlGwocGG9AtJzRax+4YN0 xhg+kA+CYD7IP8h/C3CrFDns82glG68xisdFMVk0/J8jGDfPDJRv8itZGVqKOb+d8yd4XZ30 ZsPesi3H979XD6TvjexqXdaiiTKs/n7m4NSJkyMVPsb3PuLpm46Mfd5du3SVs7Xd3ybjjl7p cEy8jDf5OHe2HLhNbZpkLlXLIjzU/GVn1etE98ihnJJ1x4rSvS3lt6vZfXP6sN3PGtubV+QG cNZ7ARwlJWj4TaRB0vwFQ1amWAkDAAA= X-CMS-MailID: 20200811085304eucas1p150bf23b6f183a28fbceca06b0bced5af X-Msg-Generator: CA Content-Type: text/plain; charset="utf-8" X-RootMTR: 20200811085304eucas1p150bf23b6f183a28fbceca06b0bced5af X-EPHeader: CA CMS-TYPE: 201P X-CMS-RootMailID: 20200811085304eucas1p150bf23b6f183a28fbceca06b0bced5af References: <20200427095737.11082-1-i.dyukov@samsung.com> <20200811085246.28735-1-i.dyukov@samsung.com> Subject: [dpdk-dev] [PATCH v9 02/24] ethdev: add a link status text representation X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list Reply-To: i.dyukov@samsung.com List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Link status structure keeps complicated values which are hard to represent to end user. e.g. link_speed has INT_MAX value which means that speed is unknown, link_duplex equal to 0 means 'half-duplex' etc. To simplify processing of the values in application, new dpdk function is introduced. This commit adds function which treat link status structure and format it to text representation. User may create custom link status string using format string. If format string is NULL, the function construct standard link status string. Signed-off-by: Ivan Dyukov --- MAINTAINERS | 1 + app/test/Makefile | 3 + app/test/meson.build | 2 + app/test/test_ethdev_link.c | 315 +++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev.c | 160 ++++++++++++ lib/librte_ethdev/rte_ethdev.h | 32 +++ lib/librte_ethdev/rte_ethdev_version.map | 3 + 7 files changed, 516 insertions(+) create mode 100644 app/test/test_ethdev_link.c diff --git a/MAINTAINERS b/MAINTAINERS index 5e706cd7e..f4fb31ea2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -393,6 +393,7 @@ T: git://dpdk.org/next/dpdk-next-net F: lib/librte_ethdev/ F: devtools/test-null.sh F: doc/guides/prog_guide/switch_representation.rst +F: app/test/test_ethdev* Flow API M: Ori Kam diff --git a/app/test/Makefile b/app/test/Makefile index e5440774b..9f43b8c3c 100644 --- a/app/test/Makefile +++ b/app/test/Makefile @@ -251,6 +251,9 @@ SRCS-$(CONFIG_RTE_LIBRTE_SECURITY) += test_security.c SRCS-$(CONFIG_RTE_LIBRTE_IPSEC) += test_ipsec.c test_ipsec_perf.c SRCS-$(CONFIG_RTE_LIBRTE_IPSEC) += test_ipsec_sad.c + +SRCS-$(CONFIG_RTE_LIBRTE_ETHER) += test_ethdev_link.c + ifeq ($(CONFIG_RTE_LIBRTE_IPSEC),y) LDLIBS += -lrte_ipsec endif diff --git a/app/test/meson.build b/app/test/meson.build index 56591db4e..1e6acf701 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -39,6 +39,7 @@ test_sources = files('commands.c', 'test_efd.c', 'test_efd_perf.c', 'test_errno.c', + 'test_ethdev_link.c', 'test_event_crypto_adapter.c', 'test_event_eth_rx_adapter.c', 'test_event_ring.c', @@ -199,6 +200,7 @@ fast_tests = [ ['eal_flags_misc_autotest', false], ['eal_fs_autotest', true], ['errno_autotest', true], + ['ethdev_link_status', true], ['event_ring_autotest', true], ['fib_autotest', true], ['fib6_autotest', true], diff --git a/app/test/test_ethdev_link.c b/app/test/test_ethdev_link.c new file mode 100644 index 000000000..b501deefe --- /dev/null +++ b/app/test/test_ethdev_link.c @@ -0,0 +1,315 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + */ + +#include +#include + +#include +#include "test.h" + + +static int32_t +test_link_status_up_default(void) +{ + int ret = 0; + struct rte_eth_link link_status = { + .link_speed = ETH_SPEED_NUM_2_5G, + .link_status = ETH_LINK_UP, + .link_autoneg = ETH_LINK_AUTONEG, + .link_duplex = ETH_LINK_FULL_DUPLEX + }; + char text[RTE_ETH_LINK_MAX_STR_LEN + 1]; + + ret = rte_eth_link_to_str(text, sizeof(text), NULL, &link_status); + RTE_TEST_ASSERT(ret > 0, "Failed to format default string\n"); + printf("Default link up #1: %s\n", text); + TEST_ASSERT_BUFFERS_ARE_EQUAL("Link up at 2.5 Gbit/s FDX Autoneg", + text, strlen(text), "Invalid default link status string"); + + link_status.link_duplex = ETH_LINK_HALF_DUPLEX; + link_status.link_autoneg = ETH_LINK_FIXED; + link_status.link_speed = ETH_SPEED_NUM_10M, + ret = rte_eth_link_to_str(text, sizeof(text), NULL, &link_status); + printf("Default link up #2: %s\n", text); + RTE_TEST_ASSERT(ret > 0, "Failed to format default string\n"); + TEST_ASSERT_BUFFERS_ARE_EQUAL("Link up at 10 Mbit/s HDX Fixed", + text, strlen(text), "Invalid default link status " + "string with HDX"); + + link_status.link_speed = ETH_SPEED_NUM_UNKNOWN; + ret = rte_eth_link_to_str(text, sizeof(text), NULL, &link_status); + printf("Default link up #3: %s\n", text); + RTE_TEST_ASSERT(ret > 0, "Failed to format default string\n"); + TEST_ASSERT_BUFFERS_ARE_EQUAL("Link up at Unknown speed HDX Fixed", + text, strlen(text), "Invalid default link status " + "string with HDX"); + + /* test max str len */ + link_status.link_speed = ETH_SPEED_NUM_UNKNOWN - 1; + link_status.link_duplex = ETH_LINK_HALF_DUPLEX; + link_status.link_autoneg = ETH_LINK_AUTONEG; + ret = rte_eth_link_to_str(text, sizeof(text), NULL, &link_status); + printf("Default link up #4:len = %d, %s\n", ret, text); + RTE_TEST_ASSERT(ret > RTE_ETH_LINK_MAX_STR_LEN, + "String length exceeds max allowed value\n"); + return TEST_SUCCESS; +} + +static int32_t +test_link_status_down_default(void) +{ + int ret = 0; + struct rte_eth_link link_status = { + .link_speed = ETH_SPEED_NUM_2_5G, + .link_status = ETH_LINK_DOWN, + .link_autoneg = ETH_LINK_AUTONEG, + .link_duplex = ETH_LINK_FULL_DUPLEX + }; + char text[RTE_ETH_LINK_MAX_STR_LEN]; + + ret = rte_eth_link_to_str(text, sizeof(text), NULL, &link_status); + RTE_TEST_ASSERT(ret > 0, "Failed to format default string\n"); + TEST_ASSERT_BUFFERS_ARE_EQUAL("Link down", + text, strlen(text), "Invalid default link status string"); + + return TEST_SUCCESS; +} + +static int32_t +test_link_status_string_overflow(void) +{ + int ret = 0; + struct rte_eth_link link_status = { + .link_speed = ETH_SPEED_NUM_2_5G, + .link_status = ETH_LINK_UP, + .link_autoneg = ETH_LINK_AUTONEG, + .link_duplex = ETH_LINK_FULL_DUPLEX + }; + char text[128]; + int i = 0; + + for (i = 0; i < 128; i++) + text[i] = 'Y'; + text[127] = '\0'; + + ret = rte_eth_link_to_str(NULL, 2, "status %S, %G Gbits/s", + &link_status); + RTE_TEST_ASSERT(ret < 0, "Format string should fail, but it's ok\n"); + + ret = rte_eth_link_to_str(text, 2, "status %S, %G Gbits/s", + &link_status); + RTE_TEST_ASSERT(ret < 0, "Format string should fail, but it's ok\n"); + RTE_TEST_ASSERT(text[2] == 'Y', "String1 overflow\n"); + + ret = rte_eth_link_to_str(text, 8, NULL, + &link_status); + RTE_TEST_ASSERT(ret < 0, "Default format string should fail," + " but it's ok\n"); + RTE_TEST_ASSERT(text[8] == 'Y', "String1 overflow\n"); + + ret = rte_eth_link_to_str(text, 10, NULL, + &link_status); + RTE_TEST_ASSERT(ret < 0, "Default format string should fail," + " but it's ok\n"); + RTE_TEST_ASSERT(text[10] == 'Y', "String1 overflow\n"); + + text[1] = 'Y'; + ret = rte_eth_link_to_str(text, 1, "%S", + &link_status); + RTE_TEST_ASSERT(ret < 0, "Status string should fail, but it's ok\n"); + RTE_TEST_ASSERT(text[1] == 'Y', "String1 overflow\n"); + + text[1] = 'Y'; + ret = rte_eth_link_to_str(text, 1, "%s", + &link_status); + RTE_TEST_ASSERT(ret < 0, "Status string should fail, but it's ok\n"); + RTE_TEST_ASSERT(text[1] == 'Y', "String1 overflow\n"); + + + return TEST_SUCCESS; +} + +static int32_t +test_link_status_format(void) +{ + int ret = 0; + struct rte_eth_link link_status = { + .link_speed = ETH_SPEED_NUM_40G, + .link_status = ETH_LINK_UP, + .link_autoneg = ETH_LINK_AUTONEG, + .link_duplex = ETH_LINK_FULL_DUPLEX + }; + char text[128]; + int i = 0; + + for (i = 0; i < 128; i++) + text[i] = 'Y'; + text[127] = '\0'; + printf("status format #1: %s\n", text); + ret = rte_eth_link_to_str(text, 128, "status = %S, duplex = %D\n", + &link_status); + printf("status format #2: %s\n", text); + RTE_TEST_ASSERT(ret > 0, "Failed to format string\n"); + TEST_ASSERT_BUFFERS_ARE_EQUAL("status = Up, duplex = FDX\n", + text, strlen(text), "Invalid status string1."); + + ret = rte_eth_link_to_str(text, 128, "%A", &link_status); + printf("status format #3: %s\n", text); + RTE_TEST_ASSERT(ret > 0, "Failed to format string\n"); + TEST_ASSERT_BUFFERS_ARE_EQUAL("Autoneg", + text, strlen(text), "Invalid status string2."); + + ret = rte_eth_link_to_str(text, 128, + "%G", + &link_status); + printf("status format #4: %s\n", text); + RTE_TEST_ASSERT(ret > 0, "Failed to format string\n"); + TEST_ASSERT_BUFFERS_ARE_EQUAL("40.0", + text, strlen(text), "Invalid status string3."); + + ret = rte_eth_link_to_str(text, 128, + "%d %M %", + &link_status); + printf("status format #5: %s\n", text); + RTE_TEST_ASSERT(ret > 0, "Failed to format string\n"); + TEST_ASSERT_BUFFERS_ARE_EQUAL("%d 40000 %", + text, strlen(text), "Invalid status string4."); + return TEST_SUCCESS; +} + +static int32_t +test_link_status_return_value(void) +{ + int ret = 0; + struct rte_eth_link link_status = { + .link_speed = ETH_SPEED_NUM_40G, + .link_status = ETH_LINK_UP, + .link_autoneg = ETH_LINK_AUTONEG, + .link_duplex = ETH_LINK_FULL_DUPLEX + }; + char text[128]; + int i = 0; + + for (i = 0; i < 128; i++) + text[i] = 'Y'; + text[127] = '\0'; + ret = rte_eth_link_to_str(text, 128, "status = %S, ", + &link_status); + printf("return value #1:ret=%u, text=%s\n", ret, text); + ret += rte_eth_link_to_str(text + ret, 128 - ret, + "%A", + &link_status); + printf("return value #2:ret=%u, text=%s\n", ret, text); + ret += rte_eth_link_to_str(text + ret, 128 - ret, + ", duplex = %D\n", + &link_status); + printf("return value #3:ret=%u, text=%s\n", ret, text); + ret += rte_eth_link_to_str(text + ret, 128 - ret, + "%M Mbits/s\n", + &link_status); + printf("return value #4:ret=%u, text=%s\n", ret, text); + RTE_TEST_ASSERT(ret > 0, "Failed to format string\n"); + TEST_ASSERT_BUFFERS_ARE_EQUAL("status = Up, Autoneg, duplex = FDX\n" + "40000 Mbits/s\n", + text, strlen(text), "Invalid status string"); + + return TEST_SUCCESS; +} + +static int32_t +test_link_status_unknown_specifier(void) +{ + int ret = 0; + struct rte_eth_link link_status = { + .link_speed = ETH_SPEED_NUM_40G, + .link_status = ETH_LINK_UP, + .link_autoneg = ETH_LINK_AUTONEG, + .link_duplex = ETH_LINK_FULL_DUPLEX + }; + char text[128]; + + ret = rte_eth_link_to_str(text, 128, "status = %", + &link_status); + RTE_TEST_ASSERT(ret > 0, "Status string1 is failed\n"); + TEST_ASSERT_BUFFERS_ARE_EQUAL("status = %", + text, strlen(text), "Invalid status string1"); + + ret = rte_eth_link_to_str(text, 128, + ", duplex = %d\n", + &link_status); + RTE_TEST_ASSERT(ret > 0, "Status string2 is failed\n"); + TEST_ASSERT_BUFFERS_ARE_EQUAL(", duplex = %d\n", + text, strlen(text), "Invalid status string2"); + + ret = rte_eth_link_to_str(text, 128, + "% Mbits/s\n", + &link_status); + RTE_TEST_ASSERT(ret > 0, "Status string3 is failed\n"); + TEST_ASSERT_BUFFERS_ARE_EQUAL("% Mbits/s\n", + text, strlen(text), "Invalid status string3"); + + ret = rte_eth_link_to_str(text, 128, + "%w Mbits/s\n", + &link_status); + RTE_TEST_ASSERT(ret > 0, "Status string4 should be ok, but it's fail\n"); + TEST_ASSERT_BUFFERS_ARE_EQUAL("%w Mbits/s\n", + text, strlen(text), "Invalid status string4"); + return TEST_SUCCESS; +} + +static int32_t +test_link_status_format_edges(void) +{ + int ret = 0; + struct rte_eth_link link_status = { + .link_speed = ETH_SPEED_NUM_UNKNOWN, + .link_status = ETH_LINK_DOWN, + .link_autoneg = ETH_LINK_AUTONEG, + .link_duplex = ETH_LINK_HALF_DUPLEX + }; + char text[128]; + + ret = rte_eth_link_to_str(text, 4, "%S", &link_status); + printf("format edges #1: %s\n", text); + RTE_TEST_ASSERT(ret < 0, "It should fail. No space for " + "zero terminator\n"); + ret = rte_eth_link_to_str(text, 6, "123%D", &link_status); + printf("format edges #2: %s\n", text); + RTE_TEST_ASSERT(ret < 0, "It should fail. No space for " + "zero terminator\n"); + ret = rte_eth_link_to_str(text, 7, "%A", &link_status); + printf("format edges #3: %s\n", text); + RTE_TEST_ASSERT(ret < 0, "It should fail. No space for " + "zero terminator\n"); + ret = rte_eth_link_to_str(text, 8, "%A", &link_status); + printf("format edges #4: %s\n", text); + RTE_TEST_ASSERT(ret > 0, "It should ok, but it fails\n"); + return TEST_SUCCESS; +} +static struct unit_test_suite link_status_testsuite = { + .suite_name = "link status formatting", + .setup = NULL, + .teardown = NULL, + .unit_test_cases = { + TEST_CASE(test_link_status_up_default), + TEST_CASE(test_link_status_down_default), + TEST_CASE(test_link_status_string_overflow), + TEST_CASE(test_link_status_format), + TEST_CASE(test_link_status_format_edges), + TEST_CASE(test_link_status_unknown_specifier), + TEST_CASE(test_link_status_return_value), + TEST_CASES_END() /**< NULL terminate unit test array */ + } +}; + +static int +test_link_status(void) +{ + rte_log_set_global_level(RTE_LOG_DEBUG); + rte_log_set_level(RTE_LOGTYPE_EAL, RTE_LOG_DEBUG); + + return unit_test_suite_runner(&link_status_testsuite); +} + +REGISTER_TEST_COMMAND(ethdev_link_status, test_link_status); diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c index d06b7f9b1..3c00ee7ee 100644 --- a/lib/librte_ethdev/rte_ethdev.c +++ b/lib/librte_ethdev/rte_ethdev.c @@ -2383,6 +2383,166 @@ rte_eth_link_get_nowait(uint16_t port_id, struct rte_eth_link *eth_link) return 0; } +static int +rte_eth_link_to_str_parser(char *str, size_t len, const char *const fmt, + const struct rte_eth_link *eth_link) +{ + size_t offset = 0; + const char *fmt_cur = fmt; + double gbits = (double)eth_link->link_speed / 1000.; + static const char autoneg_str[] = "Autoneg"; + static const char fixed_str[] = "Fixed"; + static const char fdx_str[] = "FDX"; + static const char hdx_str[] = "HDX"; + static const char unknown_str[] = "Unknown"; + static const char up_str[] = "Up"; + static const char down_str[] = "Down"; + char gbits_str[20]; + char mbits_str[20]; + + /* preformat complex formatting to easily concatinate it further */ + snprintf(mbits_str, sizeof(mbits_str), "%u", eth_link->link_speed); + snprintf(gbits_str, sizeof(gbits_str), "%.1f", gbits); + /* init str before formatting */ + str[0] = 0; + while (*fmt_cur) { + /* check str bounds */ + if (offset >= len) { + str[len - 1] = '\0'; + return -EINVAL; + } + if (*fmt_cur == '%') { + /* set null terminator to current position, + * it's required for strlcat + */ + str[offset] = '\0'; + switch (*++fmt_cur) { + /* Speed in Mbits/s */ + case 'M': + if (eth_link->link_speed == + ETH_SPEED_NUM_UNKNOWN) + offset = strlcat(str, unknown_str, + len); + else + offset = strlcat(str, mbits_str, len); + break; + /* Speed in Gbits/s */ + case 'G': + if (eth_link->link_speed == + ETH_SPEED_NUM_UNKNOWN) + offset = strlcat(str, unknown_str, + len); + else + offset = strlcat(str, gbits_str, len); + break; + /* Link status */ + case 'S': + offset = strlcat(str, eth_link->link_status ? + up_str : down_str, len); + break; + /* Link autoneg */ + case 'A': + offset = strlcat(str, eth_link->link_autoneg ? + autoneg_str : fixed_str, len); + break; + /* Link duplex */ + case 'D': + offset = strlcat(str, eth_link->link_duplex ? + fdx_str : hdx_str, len); + break; + /* ignore unknown specifier + * just copy it to target str + */ + default: + str[offset++] = '%'; + fmt_cur--; + break; + + } + if (offset >= len) + return -EINVAL; + + } else { + str[offset++] = *fmt_cur; + } + fmt_cur++; + } + str[offset] = '\0'; + return offset; +} + +int +rte_eth_link_to_str(char *str, size_t len, const char *const fmt, + const struct rte_eth_link *eth_link) +{ + size_t offset = 0; + double gbits = (double)eth_link->link_speed / 1000.; + char speed_gbits_str[20]; + char speed_mbits_str[20]; + /* TBD: make it international? */ + static const char link_down_str[] = "Link down"; + static const char link_up_str[] = "Link up at "; + static const char unknown_speed_str[] = "Unknown speed "; + static const char mbits_str[] = "Mbit/s"; + static const char gbits_str[] = "Gbit/s"; + static const char fdx_str[] = "FDX "; + static const char hdx_str[] = "HDX "; + static const char autoneg_str[] = "Autoneg"; + static const char fixed_str[] = "Fixed"; + + if (str == NULL || len == 0) + return -EINVAL; + /* default format string, if no fmt is specified */ + if (fmt == NULL) { + if (eth_link->link_status == ETH_LINK_DOWN) { + if (sizeof(link_down_str) > len) + return -EINVAL; + return strlcpy(str, link_down_str, len); + } + + /* preformat complex strings to easily concatinate it further */ + snprintf(speed_mbits_str, sizeof(speed_mbits_str), "%u %s ", + eth_link->link_speed, mbits_str); + snprintf(speed_gbits_str, sizeof(speed_gbits_str), "%.1f %s ", + gbits, gbits_str); + + offset = strlcpy(str, link_up_str, len); + /* reserve one byte to null terminator */ + if (offset >= len) + return -EINVAL; + /* link speed */ + if (eth_link->link_speed == ETH_SPEED_NUM_UNKNOWN) { + offset = strlcat(str, unknown_speed_str, len); + if (offset >= len) + return -EINVAL; + } else { + if (eth_link->link_speed < ETH_SPEED_NUM_1G) { + offset = strlcat(str, speed_mbits_str, len); + if (offset >= len) + return -EINVAL; + } else { + offset = strlcat(str, speed_gbits_str, len); + if (offset >= len) + return -EINVAL; + } + } + /* link duplex */ + offset = strlcat(str, eth_link->link_duplex ? + fdx_str : hdx_str, len); + if (offset >= len) + return -EINVAL; + /* link autonegotiation */ + offset = strlcat(str, eth_link->link_autoneg ? + autoneg_str : fixed_str, len); + if (offset >= len) + return -EINVAL; + /* Formatted status */ + } else + offset = rte_eth_link_to_str_parser(str, len, fmt, eth_link); + + return offset; +} + int rte_eth_stats_get(uint16_t port_id, struct rte_eth_stats *stats) { diff --git a/lib/librte_ethdev/rte_ethdev.h b/lib/librte_ethdev/rte_ethdev.h index 2090af501..4e8fdc891 100644 --- a/lib/librte_ethdev/rte_ethdev.h +++ b/lib/librte_ethdev/rte_ethdev.h @@ -323,6 +323,7 @@ struct rte_eth_link { #define ETH_LINK_UP 1 /**< Link is up (see link_status). */ #define ETH_LINK_FIXED 0 /**< No autonegotiation (see link_autoneg). */ #define ETH_LINK_AUTONEG 1 /**< Autonegotiated (see link_autoneg). */ +#define ETH_LINK_MAX_STR_LEN 60 /**< Max length of default link string. */ /** * A structure used to configure the ring threshold registers of an RX/TX @@ -2295,6 +2296,37 @@ int rte_eth_link_get(uint16_t port_id, struct rte_eth_link *link); */ int rte_eth_link_get_nowait(uint16_t port_id, struct rte_eth_link *link); +/** + * Format link status to textual representation. This function treats all + * special values like ETH_SPEED_NUM_UNKNOWN, ETH_LINK_DOWN etc. and convert + * them to textual representation. + * + * @param str + * A pointer to a string to be filled with textual representation of + * device status. At least ETH_LINK_MAX_STR_LEN bytes should be allocated to + * store default link status text. + * @param len + * Length of available memory at 'str' string. + * @param fmt + * Format string which allows to format link status. + * If NULL is provided, default formatting will be applied. + * Following specifiers are available: + * - '%M' link speed in Mbits/s + * - '%G' link speed in Gbits/s + * - '%S' link status. e.g. Up or Down + * - '%A' link autonegotiation state + * - '%D' link duplex state + * @param eth_link + * Link status provided by rte_eth_link_get function + * @return + * - Number of bytes written to str array. + * - (-EINVAL) if size of target buffer is too small for the string + * + */ +__rte_experimental +int rte_eth_link_to_str(char *str, size_t len, const char *const fmt, + const struct rte_eth_link *eth_link); + /** * Retrieve the general I/O statistics of an Ethernet device. * diff --git a/lib/librte_ethdev/rte_ethdev_version.map b/lib/librte_ethdev/rte_ethdev_version.map index 715505604..afdfd59d6 100644 --- a/lib/librte_ethdev/rte_ethdev_version.map +++ b/lib/librte_ethdev/rte_ethdev_version.map @@ -241,4 +241,7 @@ EXPERIMENTAL { __rte_ethdev_trace_rx_burst; __rte_ethdev_trace_tx_burst; rte_flow_get_aged_flows; + + # added in 20.11 + rte_eth_link_to_str; }; -- 2.17.1