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 C066FA0526; Fri, 10 Jul 2020 09:02:58 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 14AF51DB6D; Fri, 10 Jul 2020 09:02:45 +0200 (CEST) Received: from mailout1.w1.samsung.com (mailout1.w1.samsung.com [210.118.77.11]) by dpdk.org (Postfix) with ESMTP id 51C321DB7F for ; Fri, 10 Jul 2020 09:02:43 +0200 (CEST) Received: from eucas1p1.samsung.com (unknown [182.198.249.206]) by mailout1.w1.samsung.com (KnoxPortal) with ESMTP id 20200710070243euoutp01e4207aac0f207980b88087849585c7bb~gUh90QCIm2059620596euoutp01L; Fri, 10 Jul 2020 07:02:43 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout1.w1.samsung.com 20200710070243euoutp01e4207aac0f207980b88087849585c7bb~gUh90QCIm2059620596euoutp01L DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1594364563; bh=2H/ERU8W5zPS4t5Hj4oIefSk0veb6FZ+kOzsHfJho/0=; h=From:To:Subject:Date:In-Reply-To:Reply-To:References:From; b=K4BPjK+skMmT2oEgaBcgZ7WVLhVEgjk9aopSzrmaWntJNAiHpYXKjc5qoJhtIccW4 BEGRJHCuoi3mdrz69w2c6ir2J7QFfTlNPtQIBa6niKTRwj1PzorE/VAs5aGbQAAjC5 KV65r0Y5WA/WaULyyRDggYI82Dbf1SP3w8zKdy5A= Received: from eusmges2new.samsung.com (unknown [203.254.199.244]) by eucas1p2.samsung.com (KnoxPortal) with ESMTP id 20200710070242eucas1p279dbca2b89ef66d5427f65a73631488c~gUh9kSEC11909719097eucas1p2N; Fri, 10 Jul 2020 07:02:42 +0000 (GMT) Received: from eucas1p2.samsung.com ( [182.198.249.207]) by eusmges2new.samsung.com (EUCPMTA) with SMTP id 7E.28.05997.292180F5; Fri, 10 Jul 2020 08:02:42 +0100 (BST) Received: from eusmtrp2.samsung.com (unknown [182.198.249.139]) by eucas1p2.samsung.com (KnoxPortal) with ESMTPA id 20200710070242eucas1p2d638073836aab0f37966a801996ee08b~gUh9Plofk1196811968eucas1p22; Fri, 10 Jul 2020 07:02:42 +0000 (GMT) Received: from eusmgms1.samsung.com (unknown [182.198.249.179]) by eusmtrp2.samsung.com (KnoxPortal) with ESMTP id 20200710070242eusmtrp23bbb0804ebf7522745653d1f8b34f4bf~gUh9OcYbF2959129591eusmtrp2p; Fri, 10 Jul 2020 07:02:42 +0000 (GMT) X-AuditID: cbfec7f4-677ff7000000176d-fe-5f08129229c9 Received: from eusmtip1.samsung.com ( [203.254.199.221]) by eusmgms1.samsung.com (EUCPMTA) with SMTP id C4.74.06314.292180F5; Fri, 10 Jul 2020 08:02:42 +0100 (BST) Received: from idyukov.rnd.samsung.ru (unknown [106.109.129.29]) by eusmtip1.samsung.com (KnoxPortal) with ESMTPA id 20200710070240eusmtip1d9ae3559becbdbe677d9254270457f56~gUh7Wlos11462214622eusmtip13; Fri, 10 Jul 2020 07:02:40 +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: Fri, 10 Jul 2020 10:02:00 +0300 Message-Id: <20200710070226.6045-3-i.dyukov@samsung.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200710070226.6045-1-i.dyukov@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA0WSf2wTZRjH89xd726VmqOgPE4yYiMRiYL4K4+GODQmXEhEiUoIUUaFc6Br Ib1tDky0ma5pOthcXSRO0s1OXdkwY7Pd2rkR3Mx+WNgvM0bj2BacQXBsdGy6QWfd7Ub87/P9 Pt/v875584qs2cunigft2YrDbs2y8EauoX2u53GvWcx4omVgE9We9wFdGa5kabT0Mk+FNz9l 6FJ1OjU3njSQd8TJUJE3zlBjwMPT+Gg+RxNTjQwNtUQFKuvPF2iq9apAx3u+ArqauM7SlxW3 gHp8IQPN/dTE02TCz1HR7QGg4mAnUMexOEelkTCQyyPRzVNVAlUOpdHUaCdH0dgPAp2e6WMp dH4eqKSjFuiCK2nY8pB8u+Jbg1zZfI2RP/+6j5XbY18I8rEuHyPXTYQZefLsAC8XBatB/uVK ISvXjM3yrxl3GzfvV7IO5iqOjS/sNR745Pcq9vCID/Jm2+YNTrj4kQdSRJSext/GvbzGZikA ON633QPGBZ4G/LH3DOjiFuD0TJy/23B2+Rl9UAX4/Tea0OozgBdd2zTmpXUYdfsWQyulOh4b E4MLQhRXSFsxMqlqyElrMTyapsVNEmF/fYjT96/BmjPnWI1TpOewwOMX9PVpOFg+vbgSpV4R u38tFPTCyxgvCBh0XoHXO4JL/mpMRsoZnT/Ef+oHBb3sBhz2FyyF0jH4V7egXYiVHsXapo26 /SJWuVoWbZTuxUs3lms2u4DehhOsbpvQ7TLraQue6+pfshHn7yzTbRn/KKlZesJmwPjlfMNn sKbs/7MqAKphlZKj2jIV9Um78sEG1WpTc+yZG/YdstXDwk+N/tsxHYamxDutIIlgWWbaO89n mA3WXPWIrRVQZC0rTS9diO4xm/ZbjxxVHIcyHDlZitoKD4qcZZXpKf+1t81SpjVbeV9RDiuO u1NGTEl1wlvxzMgO6bvAw8+OnHwvVrdjm3H9UMt9tgfa8sIx79/lewKrJ4++edbo/rMztbuk awoigeTPj5mG83q5j9PndkbJnhJ8nhkI2J0TdwLPHN/yCFWWvX5/MfOq5UTe2A1PLFS8q+GV 2d1t9+T2x3rbx97duj25jxJj6cE3Tm9Olma7QxZOPWDdtJ51qNb/AM9KaYylAwAA X-Brightmail-Tracker: H4sIAAAAAAAAAzWSf0yMcRzHfZ/nued5ah2PE74LyVnTTJfr+vE582v84ekP1og/JOdWzyq6 LvdcrTBLkXYlpBnFSY1+UUrpzjAdCldrshD9OGka0S9aaSX9mP/e2/v1fu+zfd4sKRuh3Njo WKNgiNXGyGlnyv63ocM7W8Zq1hePLYGKRjOC7s5CEhw5HTRkDJ4m4EPpFnhUe00C2V3JBGRl DxFQW2yi4YcjhYL+4VoC2h/bGchtSWFg2NbLwLnmPAS9E99JuJr/C0GzuUYCf+oe0jAwUUBB 1ngrgvPVLxE0ZA5RkGO1IEgzcTBYUsRAYbs7DDteUmBvu8/AnZE3JNQ0TiK42FCBoCltSrJ1 FT+ef0vCFz76RvCXbr4h+fq2ywyf+cpM8JX9FoIfeNJK81nVpYh/3Z1B8mU9Y3Sw837FRoM+ 3ih4ROlF4yZ5qBJ8FUo1KHz91AqlKjBsg6+/3GfzxgghJjpBMPhsPqSISv1SRMZ1mVHi2LNJ STJ6d9KEnFjM+eHkVwWECTmzMu4Wwp0Tk8iE2GkD474eco5ZhCfemeg55hfC57+Pzho054Xt 6ebZsCv3icZvz56iZsKLuB3YOiDOSIrzxBaH+wwu5QC3VNVQc50rcdm9p7M1TpwanzEVMDNa xkVh2+BtNKfd8fsbv4kLaH4+mleKXIV4URepE5UKUasT42MjFeF6XRWafvmD+j/3Lailco8N cSySu0gtU7RGJtEmiEk6G8IsKXeVbmuyH5RJI7RJxwSDXmOIjxFEG/Kfvu8i6bY4XD89oFij RumvDAS1MlAVqAoA+VJpOld3QMZFao3CEUGIEwz/cwTr5JaMTjDbNX0Hnqvez5f6FboHXPdY +DGndHnIvAV/r38NDibXDV1rSgpaPerWuF8fKl2xTEjtTrzis7uE2ns3rNkzryvPeyTEuHM0 9+DRmJ97ynd7Vv5UHXd1CY6uSC8f7e1jrHU9Q5C9D8eFefFLz1lzXuiCyleHVDtaUw637NrW 9nlNqJwSo7TKtaRB1P4DY4v1zAgDAAA= X-CMS-MailID: 20200710070242eucas1p2d638073836aab0f37966a801996ee08b X-Msg-Generator: CA Content-Type: text/plain; charset="utf-8" X-RootMTR: 20200710070242eucas1p2d638073836aab0f37966a801996ee08b X-EPHeader: CA CMS-TYPE: 201P X-CMS-RootMailID: 20200710070242eucas1p2d638073836aab0f37966a801996ee08b References: <20200427095737.11082-1-i.dyukov@samsung.com> <20200710070226.6045-1-i.dyukov@samsung.com> Subject: [dpdk-dev] [PATCH v7 02/25] 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" This commit add function which treat link status structure and format it to text representation. Signed-off-by: Ivan Dyukov --- MAINTAINERS | 1 + app/test/Makefile | 3 + app/test/meson.build | 2 + app/test/test_ethdev_link.c | 299 +++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev.c | 174 +++++++++++++ lib/librte_ethdev/rte_ethdev.h | 54 ++++ lib/librte_ethdev/rte_ethdev_version.map | 4 + 7 files changed, 537 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..8a2f133c0 --- /dev/null +++ b/app/test/test_ethdev_link.c @@ -0,0 +1,299 @@ +/* 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[128]; + ret = rte_eth_link_strf(text, 128, 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\n", + 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_strf(text, 128, 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\n", + text, strlen(text), "Invalid default link status " + "string with HDX"); + + link_status.link_speed = ETH_SPEED_NUM_UNKNOWN, + ret = rte_eth_link_strf(text, 128, 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\n", + text, strlen(text), "Invalid default link status " + "string with HDX"); + 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[128]; + ret = rte_eth_link_strf(text, 128, NULL, &link_status); + RTE_TEST_ASSERT(ret > 0, "Failed to format default string\n"); + TEST_ASSERT_BUFFERS_ARE_EQUAL("Link down\n", + 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_strf(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_strf(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_strf(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_strf(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_strf(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_strf(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_strf(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_strf(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_strf(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_strf(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_strf(text, 128, "status = %S, ", + &link_status); + printf("return value #1:ret=%u, text=%s\n", ret, text); + ret += rte_eth_link_strf(text + ret, 128 - ret, + "%A", + &link_status); + printf("return value #2:ret=%u, text=%s\n", ret, text); + ret += rte_eth_link_strf(text + ret, 128 - ret, + ", duplex = %D\n", + &link_status); + printf("return value #3:ret=%u, text=%s\n", ret, text); + ret += rte_eth_link_strf(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_strf(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_strf(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_strf(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_strf(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_strf(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_strf(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_strf(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_strf(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..38332b1e4 100644 --- a/lib/librte_ethdev/rte_ethdev.c +++ b/lib/librte_ethdev/rte_ethdev.c @@ -2383,6 +2383,180 @@ rte_eth_link_get_nowait(uint16_t port_id, struct rte_eth_link *eth_link) return 0; } +static int +rte_eth_link_strf_parser(char *str, size_t len, const char *const fmt, + const struct rte_eth_link *link) +{ + size_t offset = 0; + const char *fmt_cur = fmt; + char *str_cur = str; + double gbits = (double)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", 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 - 1)) { + str[len - 1] = '\0'; + return -1; + } + if (*fmt_cur == '%') { + /* set null terminator to current position, + * it's required for strlcat + */ + *str_cur = '\0'; + switch (*++fmt_cur) { + /* Speed in Mbits/s */ + case 'M': + if (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 (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, link->link_status ? + up_str : down_str, len); + break; + /* Link autoneg */ + case 'A': + offset = strlcat(str, link->link_autoneg ? + autoneg_str : fixed_str, len); + break; + /* Link duplex */ + case 'D': + offset = strlcat(str, link->link_duplex ? + fdx_str : hdx_str, len); + break; + /* ignore unknown specifier */ + default: + *str_cur = '%'; + offset++; + fmt_cur--; + break; + + } + if (offset > (len - 1)) + return -1; + + str_cur = str + offset; + } else { + *str_cur++ = *fmt_cur; + offset++; + } + fmt_cur++; + } + *str_cur = '\0'; + return offset; +} + +int +rte_eth_link_printf(const char *const fmt, + const struct rte_eth_link *link) +{ + char text[200]; + int ret; + + ret = rte_eth_link_strf(text, 200, fmt, link); + if (ret > 0) + printf("%s", text); + return ret; +} + +int +rte_eth_link_strf(char *str, size_t len, const char *const fmt, + const struct rte_eth_link *link) +{ + size_t offset = 0; + double gbits = (double)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\n"; + 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 "; + /* autoneg is latest param in default string, so add '\n' */ + static const char autoneg_str[] = "Autoneg\n"; + static const char fixed_str[] = "Fixed\n"; + if (str == NULL || len == 0) + return -1; + /* default format string, if no fmt is specified */ + if (fmt == NULL) { + if (link->link_status == ETH_LINK_DOWN) { + if (sizeof(link_down_str) > len) + return -1; + return strlcpy(str, link_down_str, len); + } + + /* preformat complex strings to easily concatinate it further */ + snprintf(speed_mbits_str, 20, "%u %s ", link->link_speed, + mbits_str); + snprintf(speed_gbits_str, 20, "%.1f %s ", gbits, gbits_str); + + offset = strlcpy(str, link_up_str, len); + /* reserve one byte to null terminator */ + if (offset > (len - 1)) + return -1; + /* link speed */ + if (link->link_speed == ETH_SPEED_NUM_UNKNOWN) { + offset = strlcat(str, unknown_speed_str, len); + if (offset > (len - 1)) + return -1; + } else { + if (link->link_speed < ETH_SPEED_NUM_1G) { + offset = strlcat(str, speed_mbits_str, len); + if (offset > (len - 1)) + return -1; + } else { + offset = strlcat(str, speed_gbits_str, len); + if (offset > (len - 1)) + return -1; + } + } + /* link duplex */ + offset = strlcat(str, link->link_duplex ? + fdx_str : hdx_str, len); + if (offset > (len - 1)) + return -1; + /* link autonegotiation */ + offset = strlcat(str, link->link_autoneg ? + autoneg_str : fixed_str, len); + if (offset > (len - 1)) + return -1; + /* Formatted status */ + } else + offset = rte_eth_link_strf_parser(str, len, fmt, 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..9afb566b3 100644 --- a/lib/librte_ethdev/rte_ethdev.h +++ b/lib/librte_ethdev/rte_ethdev.h @@ -2295,6 +2295,60 @@ 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); + +/** + * print formatted link status to stdout. This function threats all + * special values like ETH_SPEED_NUM_UNKNOWN, ETH_LINK_DOWN etc. and convert + * them to textual representation. + * + * @param fmt + * Format string which allow 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 link + * Link status provided by rte_eth_link_get function + * @return + * - Number of bytes written to stdout. In case of error, -1 is returned. + * + */ +__rte_experimental +int rte_eth_link_printf(const char *const fmt, + const struct rte_eth_link *link); + +/** + * Format link status to textual representation. This function threats 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. + * @param len + * Length of available memory at 'str' string. + * @param fmt + * Format string which allow 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 link + * Link status provided by rte_eth_link_get function + * @return + * - Number of bytes written to str array. In case of error, -1 is returned. + * + */ +__rte_experimental +int rte_eth_link_strf(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..6c80597d1 100644 --- a/lib/librte_ethdev/rte_ethdev_version.map +++ b/lib/librte_ethdev/rte_ethdev_version.map @@ -241,4 +241,8 @@ EXPERIMENTAL { __rte_ethdev_trace_rx_burst; __rte_ethdev_trace_tx_burst; rte_flow_get_aged_flows; + + # added in 20.08 + rte_eth_link_strf; + rte_eth_link_printf; }; -- 2.17.1