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 9DEFBA0528; Sat, 11 Jul 2020 12:44:46 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id E85431D9A5; Sat, 11 Jul 2020 12:44:33 +0200 (CEST) Received: from mailout1.w1.samsung.com (mailout1.w1.samsung.com [210.118.77.11]) by dpdk.org (Postfix) with ESMTP id 7494F1D9A4 for ; Sat, 11 Jul 2020 12:44:32 +0200 (CEST) Received: from eucas1p2.samsung.com (unknown [182.198.249.207]) by mailout1.w1.samsung.com (KnoxPortal) with ESMTP id 20200711104431euoutp01c78639d696c6cd2658f7a0e16e47b9a4~grM64uewo0814408144euoutp01b; Sat, 11 Jul 2020 10:44:31 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout1.w1.samsung.com 20200711104431euoutp01c78639d696c6cd2658f7a0e16e47b9a4~grM64uewo0814408144euoutp01b DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1594464271; bh=IaBbS8jYu3jf7vBVTgc6LzlYJDJhZg404Kl8o0dQZ9M=; h=From:To:Subject:Date:In-Reply-To:Reply-To:References:From; b=KCye8FkCUanZN+Ijft7189kt8jqC1pVuoZ6PyAWvn9+2PXDnNlVHb7Ur60P9FI+7s W5WHqTJyxzEVxg4UxWd2ch4imYEVr8UzIGJxtt09ZBJB4uNdNueB+HdCFlyDDs6PdZ ActkghLsFjnzn3aMThh93VrApcS81FOKZJgHFrr4= Received: from eusmges2new.samsung.com (unknown [203.254.199.244]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20200711104430eucas1p1d6bcb6318fa4d3f81f465024af2ad95f~grM56TiA81561415614eucas1p1r; Sat, 11 Jul 2020 10:44:30 +0000 (GMT) Received: from eucas1p1.samsung.com ( [182.198.249.206]) by eusmges2new.samsung.com (EUCPMTA) with SMTP id 45.1F.05997.E08990F5; Sat, 11 Jul 2020 11:44:30 +0100 (BST) Received: from eusmtrp1.samsung.com (unknown [182.198.249.138]) by eucas1p1.samsung.com (KnoxPortal) with ESMTPA id 20200711104429eucas1p167ce2c188865529b784a9c4e53fad2f6~grM4yFCtI1619116191eucas1p1o; Sat, 11 Jul 2020 10:44:29 +0000 (GMT) Received: from eusmgms1.samsung.com (unknown [182.198.249.179]) by eusmtrp1.samsung.com (KnoxPortal) with ESMTP id 20200711104429eusmtrp1b6dbc65a87ec6744b665108584138c9d~grM4xOTsa2954729547eusmtrp11; Sat, 11 Jul 2020 10:44:29 +0000 (GMT) X-AuditID: cbfec7f4-677ff7000000176d-32-5f09980eb1a6 Received: from eusmtip1.samsung.com ( [203.254.199.221]) by eusmgms1.samsung.com (EUCPMTA) with SMTP id EB.07.06314.D08990F5; Sat, 11 Jul 2020 11:44:29 +0100 (BST) Received: from idyukov.rnd.samsung.ru (unknown [106.109.129.29]) by eusmtip1.samsung.com (KnoxPortal) with ESMTPA id 20200711104427eusmtip1facab9a916db3e94365711109ace1928~grM29Y8RU0882108821eusmtip1j; Sat, 11 Jul 2020 10:44:27 +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: Sat, 11 Jul 2020 13:43:49 +0300 Message-Id: <20200711104414.15422-3-i.dyukov@samsung.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200711104414.15422-1-i.dyukov@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA0VSe0xTdxTOuff23ku1eFdJPFEHWRMTdVr3cMlRN3Fmye5fZokmJmQOO7kD HA/Tis5HFMloSGXQAaubUx5lizzMCgiWEVTsiOjK02iKoSoiSUcFQR5xYJmjvSz77zvf43y/ nPxEVl/CrxRTMw4r5gxTmoHXcldvzXZvjP4xKvGd6uBmcnWWAg09qmRpsOQhT2cnvmWovyae Wt0XNFT0OJuhgqIXDLmrbDyNDuZw9HzSzZD/mleg83dzBJr0BAT6rudnoEAoyNJP5VNAPaVN Gpq92cLTeMjJUcHcfaDCxttAHfkvOCr5vRnIapNoovqSQJX+WJocvM2R98EVgS7P9LHU1DkP 9H2HC6jL+lqz4y15rvxXjVzZOsLIxRV9rHzrgUOQ8++UMnL982ZGHr9+n5cLGmtA/nPoLCvX Dv/Nf6ZN0H6YpKSlHlHMm7bv16ZU9Qe4Qz1O+OaJc0c22HPABqKI0mb0PkuwgVbUS1WAwYF2 UIdpwO65l4w6TAEWFjsWlKhIomwopFGFS4ADU77FYQbwYdDBhV28tBa9eaWReIxUz6M75GPC hculT9E/sD/s4aQ16PqlPbJVJ23B10UuRm2Iw9q6NjaMo6StOD/eG8F6KRZ9ZdORnSh1ivjU buXVwCd45ocKTsXLMdjRKKh4NXqL8xf5E/iywSeo4TzAR87cRVM8Nj7rFsKPY6V16GrZpNIf Y6fdw6hHisb+sTfCNLsAi66eY1Vah3lWveo2YNudu4s04vyrpSoto/tGgaCe5xrg3NhFsEPc +f+7ygFqYIWSZUlPVizvZShHjRZTuiUrI9l4IDO9ARb+qvefjulmaAl96QFJBMNSXblJTNRr TEcsx9I9gCJriNHt7PJ+odclmY4dV8yZieasNMXigVUiZ1ihe985sk8vJZsOK18ryiHF/J/K iFErs2FDX8XRwJvGwoakuIMfrIKtb9vG5nd97jgZ91Gv/NVOjbGsrZ5d8sdewMzkU12zDvv1 x7aU9qerE3L9ufsMNdF+25NtsUZ2d9VvqX+dTh2sHZ641yae0gadgcKDB4bvLYvvPRGzZMtQ 66hv47kZK3O8ztbexMXr141kZ+3Zu8tVF2PgLCmmd9ezZovpXztOPQOnAwAA X-Brightmail-Tracker: H4sIAAAAAAAAAzWSa0hTcRjG+59zdnYmTQ5L6Y+B1SgKq9mcutcwtSI6fQm7ENFtLj2o5Fzu TMuCMCkdU6dZdGctTSotvKYrTcoirU2WRjbxLpVl5VIrSizzQt8e+D3P+7zwvgwp+0n5MYnJ Rt6QrE2S016U429zzxrpJYlmbb5nGZQ7rQgGe4tJ6D/fQ0POt9MEuEsjoaHumggK+zIIsBSO ElB320zDl/5MCkbG6gjofuQQw5X2TDGMNQ2JIc91FcHQ5DAJl23jCFzW+yL4/eQhDZ7JIgos E28Q5Ne0IGjOHaXg/AM7giwzC9/u3BJDcbc/jPW3UODorBbD3R9tJNx3/kFwtrkcQWvWlChq KTdhKxFxxQ2fCO7cjTaSe955QczlvrASXOWIneA8jW9ozlJTiriXgzkkV/buFx3ttVcRbtCn GvklCXrBuF6+TwlBCmUYKIKCwxRKlfrAuqAQeWBEeByflJjGGwIjYhQJt91D1BFXETo2UBSV gQoykRlJGMwG4+uDkyIz8mJkbAnCL/vyKDNipgHGn9+Rc54FeLLDTM95xhG+V+umZwDNrsQO k5WYAT5sF41fZ5+aDS9gt+DurpgZD8Uux+U3n82WSdkwPFVYTswNXYzLKh7PFkjYdfiP59Ws lrGJ2OU+g+a0P357/TtRgLxtaF4p8uFTBV28TlAqBK1OSE2OV8TqdVVo+ua1z39X21F75c4m xDJIPl9q0zIamUibJqTrmhBmSLmPdGOr46BMGqdNP84b9BpDahIvNKGQ6QXPkn6+sfrpD0o2 apQhSjWEKdUqtSoU5AulJvbJfhkbrzXyh3n+CG/4nyMYiV8Got93HEWVofaL0c80ppOmE9uj ErYtU1tumtK+mlqzjfWFG6boo6beFvJCtOzXeFyE3jTcUCUf2bQ7futEUMXmGLB/2pN3MqfR 1+zr/KIqIlFkvf/qD1mvt3p7AtY+2pZiq7WXAbbscDtaV2WlOVOing4s2q3Y9fAqt8La/PGQ Tk4JCVplAGkQtP8Amvz+pgkDAAA= X-CMS-MailID: 20200711104429eucas1p167ce2c188865529b784a9c4e53fad2f6 X-Msg-Generator: CA Content-Type: text/plain; charset="utf-8" X-RootMTR: 20200711104429eucas1p167ce2c188865529b784a9c4e53fad2f6 X-EPHeader: CA CMS-TYPE: 201P X-CMS-RootMailID: 20200711104429eucas1p167ce2c188865529b784a9c4e53fad2f6 References: <20200427095737.11082-1-i.dyukov@samsung.com> <20200711104414.15422-1-i.dyukov@samsung.com> Subject: [dpdk-dev] [PATCH v8 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. 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. Signed-off-by: Ivan Dyukov --- MAINTAINERS | 1 + app/test/Makefile | 3 + app/test/meson.build | 2 + app/test/test_ethdev_link.c | 306 +++++++++++++++++++++++ lib/librte_ethdev/rte_ethdev.c | 174 +++++++++++++ lib/librte_ethdev/rte_ethdev.h | 56 +++++ lib/librte_ethdev/rte_ethdev_version.map | 4 + 7 files changed, 546 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..01e57a0f3 --- /dev/null +++ b/app/test/test_ethdev_link.c @@ -0,0 +1,306 @@ +/* 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_to_str(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_to_str(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_to_str(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_to_str(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_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..d844a5b7b 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_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_printf(const char *const fmt, + const struct rte_eth_link *eth_link) +{ + char text[200]; + int ret; + + ret = rte_eth_link_to_str(text, 200, fmt, eth_link); + if (ret > 0) + printf("%s", text); + return ret; +} + +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\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 -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..eeb6ac50c 100644 --- a/lib/librte_ethdev/rte_ethdev.h +++ b/lib/librte_ethdev/rte_ethdev.h @@ -2295,6 +2295,62 @@ 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 treats all + * special values like ETH_SPEED_NUM_UNKNOWN, ETH_LINK_DOWN etc. and convert + * them to textual representation. + * + * @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 stdout. + * - (-EINVAL) if fmt is too long + * + */ +__rte_experimental +int rte_eth_link_printf(const char *const fmt, + const struct rte_eth_link *eth_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. + * @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..79eb99ccd 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_to_str; + rte_eth_link_printf; }; -- 2.17.1