get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/73811/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 73811,
    "url": "http://patchwork.dpdk.org/api/patches/73811/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/20200711104414.15422-3-i.dyukov@samsung.com/",
    "project": {
        "id": 1,
        "url": "http://patchwork.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20200711104414.15422-3-i.dyukov@samsung.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20200711104414.15422-3-i.dyukov@samsung.com",
    "date": "2020-07-11T10:43:49",
    "name": "[v8,02/24] ethdev: add a link status text representation",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "daaa50476f9e3eb4aa197a5278da54ba6487cdd5",
    "submitter": {
        "id": 783,
        "url": "http://patchwork.dpdk.org/api/people/783/?format=api",
        "name": "Ivan Dyukov",
        "email": "i.dyukov@samsung.com"
    },
    "delegate": {
        "id": 319,
        "url": "http://patchwork.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "http://patchwork.dpdk.org/project/dpdk/patch/20200711104414.15422-3-i.dyukov@samsung.com/mbox/",
    "series": [
        {
            "id": 10970,
            "url": "http://patchwork.dpdk.org/api/series/10970/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dpdk/list/?series=10970",
            "date": "2020-07-11T10:43:47",
            "name": "ethdev: allow unknown link speed",
            "version": 8,
            "mbox": "http://patchwork.dpdk.org/series/10970/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/73811/comments/",
    "check": "success",
    "checks": "http://patchwork.dpdk.org/api/patches/73811/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 9DEFBA0528;\n\tSat, 11 Jul 2020 12:44:46 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id E85431D9A5;\n\tSat, 11 Jul 2020 12:44:33 +0200 (CEST)",
            "from mailout1.w1.samsung.com (mailout1.w1.samsung.com\n [210.118.77.11]) by dpdk.org (Postfix) with ESMTP id 7494F1D9A4\n for <dev@dpdk.org>; Sat, 11 Jul 2020 12:44:32 +0200 (CEST)",
            "from eucas1p2.samsung.com (unknown [182.198.249.207])\n by mailout1.w1.samsung.com (KnoxPortal) with ESMTP id\n 20200711104431euoutp01c78639d696c6cd2658f7a0e16e47b9a4~grM64uewo0814408144euoutp01b;\n Sat, 11 Jul 2020 10:44:31 +0000 (GMT)",
            "from eusmges2new.samsung.com (unknown [203.254.199.244]) by\n eucas1p1.samsung.com (KnoxPortal) with ESMTP id\n 20200711104430eucas1p1d6bcb6318fa4d3f81f465024af2ad95f~grM56TiA81561415614eucas1p1r;\n Sat, 11 Jul 2020 10:44:30 +0000 (GMT)",
            "from eucas1p1.samsung.com ( [182.198.249.206]) by\n eusmges2new.samsung.com (EUCPMTA) with SMTP id 45.1F.05997.E08990F5; Sat, 11\n Jul 2020 11:44:30 +0100 (BST)",
            "from eusmtrp1.samsung.com (unknown [182.198.249.138]) by\n eucas1p1.samsung.com (KnoxPortal) with ESMTPA id\n 20200711104429eucas1p167ce2c188865529b784a9c4e53fad2f6~grM4yFCtI1619116191eucas1p1o;\n Sat, 11 Jul 2020 10:44:29 +0000 (GMT)",
            "from eusmgms1.samsung.com (unknown [182.198.249.179]) by\n eusmtrp1.samsung.com (KnoxPortal) with ESMTP id\n 20200711104429eusmtrp1b6dbc65a87ec6744b665108584138c9d~grM4xOTsa2954729547eusmtrp11;\n Sat, 11 Jul 2020 10:44:29 +0000 (GMT)",
            "from eusmtip1.samsung.com ( [203.254.199.221]) by\n eusmgms1.samsung.com (EUCPMTA) with SMTP id EB.07.06314.D08990F5; Sat, 11\n Jul 2020 11:44:29 +0100 (BST)",
            "from idyukov.rnd.samsung.ru (unknown [106.109.129.29]) by\n eusmtip1.samsung.com (KnoxPortal) with ESMTPA id\n 20200711104427eusmtip1facab9a916db3e94365711109ace1928~grM29Y8RU0882108821eusmtip1j;\n Sat, 11 Jul 2020 10:44:27 +0000 (GMT)"
        ],
        "DKIM-Filter": "OpenDKIM Filter v2.11.0 mailout1.w1.samsung.com\n 20200711104431euoutp01c78639d696c6cd2658f7a0e16e47b9a4~grM64uewo0814408144euoutp01b",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com;\n s=mail20170921; t=1594464271;\n bh=IaBbS8jYu3jf7vBVTgc6LzlYJDJhZg404Kl8o0dQZ9M=;\n h=From:To:Subject:Date:In-Reply-To:Reply-To:References:From;\n b=KCye8FkCUanZN+Ijft7189kt8jqC1pVuoZ6PyAWvn9+2PXDnNlVHb7Ur60P9FI+7s\n W5WHqTJyxzEVxg4UxWd2ch4imYEVr8UzIGJxtt09ZBJB4uNdNueB+HdCFlyDDs6PdZ\n ActkghLsFjnzn3aMThh93VrApcS81FOKZJgHFrr4=",
        "X-AuditID": "cbfec7f4-677ff7000000176d-32-5f09980eb1a6",
        "From": "Ivan Dyukov <i.dyukov@samsung.com>",
        "To": "dev@dpdk.org, i.dyukov@samsung.com, v.kuramshin@samsung.com,\n thomas@monjalon.net, david.marchand@redhat.com, ferruh.yigit@intel.com,\n arybchenko@solarflare.com, wei.zhao1@intel.com, jia.guo@intel.com,\n beilei.xing@intel.com, qiming.yang@intel.com, wenzhuo.lu@intel.com,\n mb@smartsharesystems.com, stephen@networkplumber.org,\n nicolas.chautru@intel.com, bruce.richardson@intel.com,\n konstantin.ananyev@intel.com, cristian.dumitrescu@intel.com,\n radu.nicolau@intel.com, akhil.goyal@nxp.com, declan.doherty@intel.com,\n skori@marvell.com, pbhagavatula@marvell.com, jerinj@marvell.com,\n kirankumark@marvell.com, david.hunt@intel.com, anatoly.burakov@intel.com,\n xiaoyun.li@intel.com, jingjing.wu@intel.com, john.mcnamara@intel.com,\n 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": [
            "\n H4sIAAAAAAAAA0VSe0xTdxTOuff23ku1eFdJPFEHWRMTdVr3cMlRN3Fmye5fZokmJmQOO7kD\n HA/Tis5HFMloSGXQAaubUx5lizzMCgiWEVTsiOjK02iKoSoiSUcFQR5xYJmjvSz77zvf43y/\n nPxEVl/CrxRTMw4r5gxTmoHXcldvzXZvjP4xKvGd6uBmcnWWAg09qmRpsOQhT2cnvmWovyae\n Wt0XNFT0OJuhgqIXDLmrbDyNDuZw9HzSzZD/mleg83dzBJr0BAT6rudnoEAoyNJP5VNAPaVN\n Gpq92cLTeMjJUcHcfaDCxttAHfkvOCr5vRnIapNoovqSQJX+WJocvM2R98EVgS7P9LHU1DkP\n 9H2HC6jL+lqz4y15rvxXjVzZOsLIxRV9rHzrgUOQ8++UMnL982ZGHr9+n5cLGmtA/nPoLCvX\n Dv/Nf6ZN0H6YpKSlHlHMm7bv16ZU9Qe4Qz1O+OaJc0c22HPABqKI0mb0PkuwgVbUS1WAwYF2\n UIdpwO65l4w6TAEWFjsWlKhIomwopFGFS4ADU77FYQbwYdDBhV28tBa9eaWReIxUz6M75GPC\n hculT9E/sD/s4aQ16PqlPbJVJ23B10UuRm2Iw9q6NjaMo6StOD/eG8F6KRZ9ZdORnSh1ivjU\n buXVwCd45ocKTsXLMdjRKKh4NXqL8xf5E/iywSeo4TzAR87cRVM8Nj7rFsKPY6V16GrZpNIf\n Y6fdw6hHisb+sTfCNLsAi66eY1Vah3lWveo2YNudu4s04vyrpSoto/tGgaCe5xrg3NhFsEPc\n +f+7ygFqYIWSZUlPVizvZShHjRZTuiUrI9l4IDO9ARb+qvefjulmaAl96QFJBMNSXblJTNRr\n TEcsx9I9gCJriNHt7PJ+odclmY4dV8yZieasNMXigVUiZ1ihe985sk8vJZsOK18ryiHF/J/K\n iFErs2FDX8XRwJvGwoakuIMfrIKtb9vG5nd97jgZ91Gv/NVOjbGsrZ5d8sdewMzkU12zDvv1\n x7aU9qerE3L9ufsMNdF+25NtsUZ2d9VvqX+dTh2sHZ641yae0gadgcKDB4bvLYvvPRGzZMtQ\n 66hv47kZK3O8ztbexMXr141kZ+3Zu8tVF2PgLCmmd9ezZovpXztOPQOnAwAA",
            "\n H4sIAAAAAAAAAzWSa0hTcRjG+59zdnYmTQ5L6Y+B1SgKq9mcutcwtSI6fQm7ENFtLj2o5Fzu\n TMuCMCkdU6dZdGctTSotvKYrTcoirU2WRjbxLpVl5VIrSizzQt8e+D3P+7zwvgwp+0n5MYnJ\n Rt6QrE2S016U429zzxrpJYlmbb5nGZQ7rQgGe4tJ6D/fQ0POt9MEuEsjoaHumggK+zIIsBSO\n ElB320zDl/5MCkbG6gjofuQQw5X2TDGMNQ2JIc91FcHQ5DAJl23jCFzW+yL4/eQhDZ7JIgos\n E28Q5Ne0IGjOHaXg/AM7giwzC9/u3BJDcbc/jPW3UODorBbD3R9tJNx3/kFwtrkcQWvWlChq\n KTdhKxFxxQ2fCO7cjTaSe955QczlvrASXOWIneA8jW9ozlJTiriXgzkkV/buFx3ttVcRbtCn\n GvklCXrBuF6+TwlBCmUYKIKCwxRKlfrAuqAQeWBEeByflJjGGwIjYhQJt91D1BFXETo2UBSV\n gQoykRlJGMwG4+uDkyIz8mJkbAnCL/vyKDNipgHGn9+Rc54FeLLDTM95xhG+V+umZwDNrsQO\n k5WYAT5sF41fZ5+aDS9gt+DurpgZD8Uux+U3n82WSdkwPFVYTswNXYzLKh7PFkjYdfiP59Ws\n lrGJ2OU+g+a0P357/TtRgLxtaF4p8uFTBV28TlAqBK1OSE2OV8TqdVVo+ua1z39X21F75c4m\n xDJIPl9q0zIamUibJqTrmhBmSLmPdGOr46BMGqdNP84b9BpDahIvNKGQ6QXPkn6+sfrpD0o2\n apQhSjWEKdUqtSoU5AulJvbJfhkbrzXyh3n+CG/4nyMYiV8Got93HEWVofaL0c80ppOmE9uj\n ErYtU1tumtK+mlqzjfWFG6boo6beFvJCtOzXeFyE3jTcUCUf2bQ7futEUMXmGLB/2pN3MqfR\n 1+zr/KIqIlFkvf/qD1mvt3p7AtY+2pZiq7WXAbbscDtaV2WlOVOing4s2q3Y9fAqt8La/PGQ\n 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>\n <20200711104414.15422-1-i.dyukov@samsung.com>\n <CGME20200711104429eucas1p167ce2c188865529b784a9c4e53fad2f6@eucas1p1.samsung.com>",
        "Subject": "[dpdk-dev] [PATCH v8 02/24] ethdev: add a link status text\n\trepresentation",
        "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 <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "link status structure keeps complicated values which are hard to\nrepresent to end user. e.g. link_speed has INT_MAX value which\nmeans that speed is unknown. To simplify processing of the values\nin application, new dpdk function is introduced.\n\nThis commit adds function which treat link status structure\nand format it to text representation.\n\nSigned-off-by: Ivan Dyukov <i.dyukov@samsung.com>\n---\n MAINTAINERS                              |   1 +\n app/test/Makefile                        |   3 +\n app/test/meson.build                     |   2 +\n app/test/test_ethdev_link.c              | 306 +++++++++++++++++++++++\n lib/librte_ethdev/rte_ethdev.c           | 174 +++++++++++++\n lib/librte_ethdev/rte_ethdev.h           |  56 +++++\n lib/librte_ethdev/rte_ethdev_version.map |   4 +\n 7 files changed, 546 insertions(+)\n create mode 100644 app/test/test_ethdev_link.c",
    "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex 5e706cd7e..f4fb31ea2 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -393,6 +393,7 @@ T: git://dpdk.org/next/dpdk-next-net\n F: lib/librte_ethdev/\n F: devtools/test-null.sh\n F: doc/guides/prog_guide/switch_representation.rst\n+F: app/test/test_ethdev*\n \n Flow API\n M: Ori Kam <orika@mellanox.com>\ndiff --git a/app/test/Makefile b/app/test/Makefile\nindex e5440774b..9f43b8c3c 100644\n--- a/app/test/Makefile\n+++ b/app/test/Makefile\n@@ -251,6 +251,9 @@ SRCS-$(CONFIG_RTE_LIBRTE_SECURITY) += test_security.c\n \n SRCS-$(CONFIG_RTE_LIBRTE_IPSEC) += test_ipsec.c test_ipsec_perf.c\n SRCS-$(CONFIG_RTE_LIBRTE_IPSEC) += test_ipsec_sad.c\n+\n+SRCS-$(CONFIG_RTE_LIBRTE_ETHER) += test_ethdev_link.c\n+\n ifeq ($(CONFIG_RTE_LIBRTE_IPSEC),y)\n LDLIBS += -lrte_ipsec\n endif\ndiff --git a/app/test/meson.build b/app/test/meson.build\nindex 56591db4e..1e6acf701 100644\n--- a/app/test/meson.build\n+++ b/app/test/meson.build\n@@ -39,6 +39,7 @@ test_sources = files('commands.c',\n \t'test_efd.c',\n \t'test_efd_perf.c',\n \t'test_errno.c',\n+\t'test_ethdev_link.c',\n \t'test_event_crypto_adapter.c',\n \t'test_event_eth_rx_adapter.c',\n \t'test_event_ring.c',\n@@ -199,6 +200,7 @@ fast_tests = [\n         ['eal_flags_misc_autotest', false],\n         ['eal_fs_autotest', true],\n         ['errno_autotest', true],\n+        ['ethdev_link_status', true],\n         ['event_ring_autotest', true],\n         ['fib_autotest', true],\n         ['fib6_autotest', true],\ndiff --git a/app/test/test_ethdev_link.c b/app/test/test_ethdev_link.c\nnew file mode 100644\nindex 000000000..01e57a0f3\n--- /dev/null\n+++ b/app/test/test_ethdev_link.c\n@@ -0,0 +1,306 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved\n+ */\n+\n+#include <rte_log.h>\n+#include <rte_ethdev.h>\n+\n+#include <rte_test.h>\n+#include \"test.h\"\n+\n+\n+static int32_t\n+test_link_status_up_default(void)\n+{\n+\tint ret = 0;\n+\tstruct rte_eth_link link_status = {\n+\t\t.link_speed = ETH_SPEED_NUM_2_5G,\n+\t\t.link_status = ETH_LINK_UP,\n+\t\t.link_autoneg = ETH_LINK_AUTONEG,\n+\t\t.link_duplex = ETH_LINK_FULL_DUPLEX\n+\t};\n+\tchar text[128];\n+\n+\tret = rte_eth_link_to_str(text, 128, NULL, &link_status);\n+\tRTE_TEST_ASSERT(ret > 0, \"Failed to format default string\\n\");\n+\tprintf(\"Default link up #1: %s\\n\", text);\n+\tTEST_ASSERT_BUFFERS_ARE_EQUAL(\"Link up at 2.5 Gbit/s FDX Autoneg\\n\",\n+\t\ttext, strlen(text), \"Invalid default link status string\");\n+\n+\tlink_status.link_duplex = ETH_LINK_HALF_DUPLEX;\n+\tlink_status.link_autoneg = ETH_LINK_FIXED;\n+\tlink_status.link_speed = ETH_SPEED_NUM_10M,\n+\tret = rte_eth_link_to_str(text, 128, NULL, &link_status);\n+\tprintf(\"Default link up #2: %s\\n\", text);\n+\tRTE_TEST_ASSERT(ret > 0, \"Failed to format default string\\n\");\n+\tTEST_ASSERT_BUFFERS_ARE_EQUAL(\"Link up at 10 Mbit/s HDX Fixed\\n\",\n+\t\ttext, strlen(text), \"Invalid default link status \"\n+\t\t\"string with HDX\");\n+\n+\tlink_status.link_speed = ETH_SPEED_NUM_UNKNOWN,\n+\tret = rte_eth_link_to_str(text, 128, NULL, &link_status);\n+\tprintf(\"Default link up #3: %s\\n\", text);\n+\tRTE_TEST_ASSERT(ret > 0, \"Failed to format default string\\n\");\n+\tTEST_ASSERT_BUFFERS_ARE_EQUAL(\"Link up at Unknown speed HDX Fixed\\n\",\n+\t\ttext, strlen(text), \"Invalid default link status \"\n+\t\t\"string with HDX\");\n+\treturn TEST_SUCCESS;\n+}\n+\n+static int32_t\n+test_link_status_down_default(void)\n+{\n+\tint ret = 0;\n+\tstruct rte_eth_link link_status = {\n+\t\t.link_speed = ETH_SPEED_NUM_2_5G,\n+\t\t.link_status = ETH_LINK_DOWN,\n+\t\t.link_autoneg = ETH_LINK_AUTONEG,\n+\t\t.link_duplex = ETH_LINK_FULL_DUPLEX\n+\t};\n+\tchar text[128];\n+\n+\tret = rte_eth_link_to_str(text, 128, NULL, &link_status);\n+\tRTE_TEST_ASSERT(ret > 0, \"Failed to format default string\\n\");\n+\tTEST_ASSERT_BUFFERS_ARE_EQUAL(\"Link down\\n\",\n+\t\ttext, strlen(text), \"Invalid default link status string\");\n+\n+\treturn TEST_SUCCESS;\n+}\n+\n+static int32_t\n+test_link_status_string_overflow(void)\n+{\n+\tint ret = 0;\n+\tstruct rte_eth_link link_status = {\n+\t\t.link_speed = ETH_SPEED_NUM_2_5G,\n+\t\t.link_status = ETH_LINK_UP,\n+\t\t.link_autoneg = ETH_LINK_AUTONEG,\n+\t\t.link_duplex = ETH_LINK_FULL_DUPLEX\n+\t};\n+\tchar text[128];\n+\tint i = 0;\n+\n+\tfor (i = 0; i < 128; i++)\n+\t\ttext[i] = 'Y';\n+\ttext[127] = '\\0';\n+\n+\tret = rte_eth_link_to_str(NULL, 2, \"status %S, %G Gbits/s\",\n+\t\t&link_status);\n+\tRTE_TEST_ASSERT(ret < 0, \"Format string should fail, but it's ok\\n\");\n+\n+\tret = rte_eth_link_to_str(text, 2, \"status %S, %G Gbits/s\",\n+\t\t&link_status);\n+\tRTE_TEST_ASSERT(ret < 0, \"Format string should fail, but it's ok\\n\");\n+\tRTE_TEST_ASSERT(text[2] == 'Y', \"String1 overflow\\n\");\n+\n+\tret = rte_eth_link_to_str(text, 8, NULL,\n+\t\t&link_status);\n+\tRTE_TEST_ASSERT(ret < 0, \"Default format string should fail,\"\n+\t\t\t\" but it's ok\\n\");\n+\tRTE_TEST_ASSERT(text[8] == 'Y', \"String1 overflow\\n\");\n+\n+\tret = rte_eth_link_to_str(text, 10, NULL,\n+\t\t&link_status);\n+\tRTE_TEST_ASSERT(ret < 0, \"Default format string should fail,\"\n+\t\t\t\" but it's ok\\n\");\n+\tRTE_TEST_ASSERT(text[10] == 'Y', \"String1 overflow\\n\");\n+\n+\ttext[1] = 'Y';\n+\tret = rte_eth_link_to_str(text, 1, \"%S\",\n+\t\t&link_status);\n+\tRTE_TEST_ASSERT(ret < 0, \"Status string should fail, but it's ok\\n\");\n+\tRTE_TEST_ASSERT(text[1] == 'Y', \"String1 overflow\\n\");\n+\n+\ttext[1] = 'Y';\n+\tret = rte_eth_link_to_str(text, 1, \"%s\",\n+\t\t&link_status);\n+\tRTE_TEST_ASSERT(ret < 0, \"Status string should fail, but it's ok\\n\");\n+\tRTE_TEST_ASSERT(text[1] == 'Y', \"String1 overflow\\n\");\n+\n+\n+\treturn TEST_SUCCESS;\n+}\n+\n+static int32_t\n+test_link_status_format(void)\n+{\n+\tint ret = 0;\n+\tstruct rte_eth_link link_status = {\n+\t\t.link_speed = ETH_SPEED_NUM_40G,\n+\t\t.link_status = ETH_LINK_UP,\n+\t\t.link_autoneg = ETH_LINK_AUTONEG,\n+\t\t.link_duplex = ETH_LINK_FULL_DUPLEX\n+\t};\n+\tchar text[128];\n+\tint i = 0;\n+\n+\tfor (i = 0; i < 128; i++)\n+\t\ttext[i] = 'Y';\n+\ttext[127] = '\\0';\n+\tprintf(\"status format #1: %s\\n\", text);\n+\tret = rte_eth_link_to_str(text, 128, \"status = %S, duplex = %D\\n\",\n+\t\t&link_status);\n+\tprintf(\"status format #2: %s\\n\", text);\n+\tRTE_TEST_ASSERT(ret > 0, \"Failed to format string\\n\");\n+\tTEST_ASSERT_BUFFERS_ARE_EQUAL(\"status = Up, duplex = FDX\\n\",\n+\t\ttext, strlen(text), \"Invalid status string1.\");\n+\n+\tret = rte_eth_link_to_str(text, 128, \"%A\", &link_status);\n+\tprintf(\"status format #3: %s\\n\", text);\n+\tRTE_TEST_ASSERT(ret > 0, \"Failed to format string\\n\");\n+\tTEST_ASSERT_BUFFERS_ARE_EQUAL(\"Autoneg\",\n+\t\ttext, strlen(text), \"Invalid status string2.\");\n+\n+\tret = rte_eth_link_to_str(text, 128,\n+\t\t\"%G\",\n+\t\t&link_status);\n+\tprintf(\"status format #4: %s\\n\", text);\n+\tRTE_TEST_ASSERT(ret > 0, \"Failed to format string\\n\");\n+\tTEST_ASSERT_BUFFERS_ARE_EQUAL(\"40.0\",\n+\t\ttext, strlen(text), \"Invalid status string3.\");\n+\n+\tret = rte_eth_link_to_str(text, 128,\n+\t\t\"%d %M %\",\n+\t\t&link_status);\n+\tprintf(\"status format #5: %s\\n\", text);\n+\tRTE_TEST_ASSERT(ret > 0, \"Failed to format string\\n\");\n+\tTEST_ASSERT_BUFFERS_ARE_EQUAL(\"%d 40000 %\",\n+\t\ttext, strlen(text), \"Invalid status string4.\");\n+\treturn TEST_SUCCESS;\n+}\n+\n+static int32_t\n+test_link_status_return_value(void)\n+{\n+\tint ret = 0;\n+\tstruct rte_eth_link link_status = {\n+\t\t.link_speed = ETH_SPEED_NUM_40G,\n+\t\t.link_status = ETH_LINK_UP,\n+\t\t.link_autoneg = ETH_LINK_AUTONEG,\n+\t\t.link_duplex = ETH_LINK_FULL_DUPLEX\n+\t};\n+\tchar text[128];\n+\tint i = 0;\n+\n+\tfor (i = 0; i < 128; i++)\n+\t\ttext[i] = 'Y';\n+\ttext[127] = '\\0';\n+\tret = rte_eth_link_to_str(text, 128, \"status = %S, \",\n+\t\t&link_status);\n+\tprintf(\"return value #1:ret=%u, text=%s\\n\", ret, text);\n+\tret += rte_eth_link_to_str(text + ret, 128 - ret,\n+\t\t\"%A\",\n+\t\t&link_status);\n+\tprintf(\"return value #2:ret=%u, text=%s\\n\", ret, text);\n+\tret += rte_eth_link_to_str(text + ret, 128 - ret,\n+\t\t\", duplex = %D\\n\",\n+\t\t&link_status);\n+\tprintf(\"return value #3:ret=%u, text=%s\\n\", ret, text);\n+\tret += rte_eth_link_to_str(text + ret, 128 - ret,\n+\t\t\"%M Mbits/s\\n\",\n+\t\t&link_status);\n+\tprintf(\"return value #4:ret=%u, text=%s\\n\", ret, text);\n+\tRTE_TEST_ASSERT(ret > 0, \"Failed to format string\\n\");\n+\tTEST_ASSERT_BUFFERS_ARE_EQUAL(\"status = Up, Autoneg, duplex = FDX\\n\"\n+\t\t\"40000 Mbits/s\\n\",\n+\t\ttext, strlen(text), \"Invalid status string\");\n+\n+\treturn TEST_SUCCESS;\n+}\n+\n+static int32_t\n+test_link_status_unknown_specifier(void)\n+{\n+\tint ret = 0;\n+\tstruct rte_eth_link link_status = {\n+\t\t.link_speed = ETH_SPEED_NUM_40G,\n+\t\t.link_status = ETH_LINK_UP,\n+\t\t.link_autoneg = ETH_LINK_AUTONEG,\n+\t\t.link_duplex = ETH_LINK_FULL_DUPLEX\n+\t};\n+\tchar text[128];\n+\n+\tret = rte_eth_link_to_str(text, 128, \"status = %\",\n+\t\t&link_status);\n+\tRTE_TEST_ASSERT(ret > 0, \"Status string1 is failed\\n\");\n+\tTEST_ASSERT_BUFFERS_ARE_EQUAL(\"status = %\",\n+\t\ttext, strlen(text), \"Invalid status string1\");\n+\n+\tret = rte_eth_link_to_str(text, 128,\n+\t\t\", duplex = %d\\n\",\n+\t\t&link_status);\n+\tRTE_TEST_ASSERT(ret > 0, \"Status string2 is failed\\n\");\n+\tTEST_ASSERT_BUFFERS_ARE_EQUAL(\", duplex = %d\\n\",\n+\t\ttext, strlen(text), \"Invalid status string2\");\n+\n+\tret = rte_eth_link_to_str(text, 128,\n+\t\t\"% Mbits/s\\n\",\n+\t\t&link_status);\n+\tRTE_TEST_ASSERT(ret > 0, \"Status string3 is failed\\n\");\n+\tTEST_ASSERT_BUFFERS_ARE_EQUAL(\"% Mbits/s\\n\",\n+\t\ttext, strlen(text), \"Invalid status string3\");\n+\n+\tret = rte_eth_link_to_str(text, 128,\n+\t\t\"%w Mbits/s\\n\",\n+\t\t&link_status);\n+\tRTE_TEST_ASSERT(ret > 0, \"Status string4 should be ok, but it's fail\\n\");\n+\tTEST_ASSERT_BUFFERS_ARE_EQUAL(\"%w Mbits/s\\n\",\n+\t\ttext, strlen(text), \"Invalid status string4\");\n+\treturn TEST_SUCCESS;\n+}\n+\n+static int32_t\n+test_link_status_format_edges(void)\n+{\n+\tint ret = 0;\n+\tstruct rte_eth_link link_status = {\n+\t\t.link_speed = ETH_SPEED_NUM_UNKNOWN,\n+\t\t.link_status = ETH_LINK_DOWN,\n+\t\t.link_autoneg = ETH_LINK_AUTONEG,\n+\t\t.link_duplex = ETH_LINK_HALF_DUPLEX\n+\t};\n+\tchar text[128];\n+\n+\tret = rte_eth_link_to_str(text, 4, \"%S\", &link_status);\n+\tprintf(\"format edges #1: %s\\n\", text);\n+\tRTE_TEST_ASSERT(ret < 0, \"It should fail. No space for \"\n+\t\t\t\t \"zero terminator\\n\");\n+\tret = rte_eth_link_to_str(text, 6, \"123%D\", &link_status);\n+\tprintf(\"format edges #2: %s\\n\", text);\n+\tRTE_TEST_ASSERT(ret < 0, \"It should fail. No space for \"\n+\t\t\t\t \"zero terminator\\n\");\n+\tret = rte_eth_link_to_str(text, 7, \"%A\", &link_status);\n+\tprintf(\"format edges #3: %s\\n\", text);\n+\tRTE_TEST_ASSERT(ret < 0, \"It should fail. No space for \"\n+\t\t\t\t \"zero terminator\\n\");\n+\tret = rte_eth_link_to_str(text, 8, \"%A\", &link_status);\n+\tprintf(\"format edges #4: %s\\n\", text);\n+\tRTE_TEST_ASSERT(ret > 0, \"It should ok, but it fails\\n\");\n+\treturn TEST_SUCCESS;\n+}\n+static struct unit_test_suite link_status_testsuite = {\n+\t.suite_name = \"link status formatting\",\n+\t.setup = NULL,\n+\t.teardown = NULL,\n+\t.unit_test_cases = {\n+\t\tTEST_CASE(test_link_status_up_default),\n+\t\tTEST_CASE(test_link_status_down_default),\n+\t\tTEST_CASE(test_link_status_string_overflow),\n+\t\tTEST_CASE(test_link_status_format),\n+\t\tTEST_CASE(test_link_status_format_edges),\n+\t\tTEST_CASE(test_link_status_unknown_specifier),\n+\t\tTEST_CASE(test_link_status_return_value),\n+\t\tTEST_CASES_END() /**< NULL terminate unit test array */\n+\t}\n+};\n+\n+static int\n+test_link_status(void)\n+{\n+\trte_log_set_global_level(RTE_LOG_DEBUG);\n+\trte_log_set_level(RTE_LOGTYPE_EAL, RTE_LOG_DEBUG);\n+\n+\treturn unit_test_suite_runner(&link_status_testsuite);\n+}\n+\n+REGISTER_TEST_COMMAND(ethdev_link_status, test_link_status);\ndiff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c\nindex d06b7f9b1..d844a5b7b 100644\n--- a/lib/librte_ethdev/rte_ethdev.c\n+++ b/lib/librte_ethdev/rte_ethdev.c\n@@ -2383,6 +2383,180 @@ rte_eth_link_get_nowait(uint16_t port_id, struct rte_eth_link *eth_link)\n \treturn 0;\n }\n \n+static int\n+rte_eth_link_to_str_parser(char *str, size_t len, const char *const fmt,\n+\t\t\t   const struct rte_eth_link *eth_link)\n+{\n+\tsize_t offset = 0;\n+\tconst char *fmt_cur = fmt;\n+\tdouble gbits = (double)eth_link->link_speed / 1000.;\n+\tstatic const char autoneg_str[]       = \"Autoneg\";\n+\tstatic const char fixed_str[]         = \"Fixed\";\n+\tstatic const char fdx_str[]           = \"FDX\";\n+\tstatic const char hdx_str[]           = \"HDX\";\n+\tstatic const char unknown_str[]       = \"Unknown\";\n+\tstatic const char up_str[]            = \"Up\";\n+\tstatic const char down_str[]          = \"Down\";\n+\tchar gbits_str[20];\n+\tchar mbits_str[20];\n+\n+\t/* preformat complex formatting to easily concatinate it further */\n+\tsnprintf(mbits_str, sizeof(mbits_str), \"%u\", eth_link->link_speed);\n+\tsnprintf(gbits_str, sizeof(gbits_str), \"%.1f\", gbits);\n+\t/* init str before formatting */\n+\tstr[0] = 0;\n+\twhile (*fmt_cur) {\n+\t\t/* check str bounds */\n+\t\tif (offset >= len) {\n+\t\t\tstr[len - 1] = '\\0';\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\tif (*fmt_cur == '%') {\n+\t\t\t/* set null terminator to current position,\n+\t\t\t * it's required for strlcat\n+\t\t\t */\n+\t\t\tstr[offset] = '\\0';\n+\t\t\tswitch (*++fmt_cur) {\n+\t\t\t/* Speed in Mbits/s */\n+\t\t\tcase 'M':\n+\t\t\t\tif (eth_link->link_speed ==\n+\t\t\t\t    ETH_SPEED_NUM_UNKNOWN)\n+\t\t\t\t\toffset = strlcat(str, unknown_str,\n+\t\t\t\t\t\t\t len);\n+\t\t\t\telse\n+\t\t\t\t\toffset = strlcat(str, mbits_str, len);\n+\t\t\t\tbreak;\n+\t\t\t/* Speed in Gbits/s */\n+\t\t\tcase 'G':\n+\t\t\t\tif (eth_link->link_speed ==\n+\t\t\t\t    ETH_SPEED_NUM_UNKNOWN)\n+\t\t\t\t\toffset = strlcat(str, unknown_str,\n+\t\t\t\t\t\t\t len);\n+\t\t\t\telse\n+\t\t\t\t\toffset = strlcat(str, gbits_str, len);\n+\t\t\t\tbreak;\n+\t\t\t/* Link status */\n+\t\t\tcase 'S':\n+\t\t\t\toffset = strlcat(str, eth_link->link_status ?\n+\t\t\t\t\tup_str : down_str, len);\n+\t\t\t\tbreak;\n+\t\t\t/* Link autoneg */\n+\t\t\tcase 'A':\n+\t\t\t\toffset = strlcat(str, eth_link->link_autoneg ?\n+\t\t\t\t\tautoneg_str : fixed_str, len);\n+\t\t\t\tbreak;\n+\t\t\t/* Link duplex */\n+\t\t\tcase 'D':\n+\t\t\t\toffset = strlcat(str, eth_link->link_duplex ?\n+\t\t\t\t\tfdx_str : hdx_str, len);\n+\t\t\t\tbreak;\n+\t\t\t/* ignore unknown specifier\n+\t\t\t * just copy it to target str\n+\t\t\t */\n+\t\t\tdefault:\n+\t\t\t\tstr[offset++] = '%';\n+\t\t\t\tfmt_cur--;\n+\t\t\t\tbreak;\n+\n+\t\t\t}\n+\t\t\tif (offset >= len)\n+\t\t\t\treturn -EINVAL;\n+\n+\t\t} else {\n+\t\t\tstr[offset++] = *fmt_cur;\n+\t\t}\n+\t\tfmt_cur++;\n+\t}\n+\tstr[offset] = '\\0';\n+\treturn offset;\n+}\n+\n+int\n+rte_eth_link_printf(const char *const fmt,\n+\t\t    const struct rte_eth_link *eth_link)\n+{\n+\tchar text[200];\n+\tint ret;\n+\n+\tret = rte_eth_link_to_str(text, 200, fmt, eth_link);\n+\tif (ret > 0)\n+\t\tprintf(\"%s\", text);\n+\treturn ret;\n+}\n+\n+int\n+rte_eth_link_to_str(char *str, size_t len, const char *const fmt,\n+\t\t    const struct rte_eth_link *eth_link)\n+{\n+\tsize_t offset = 0;\n+\tdouble gbits = (double)eth_link->link_speed / 1000.;\n+\tchar speed_gbits_str[20];\n+\tchar speed_mbits_str[20];\n+\t/* TBD: make it international? */\n+\tstatic const char link_down_str[]     = \"Link down\\n\";\n+\tstatic const char link_up_str[]       = \"Link up at \";\n+\tstatic const char unknown_speed_str[] = \"Unknown speed \";\n+\tstatic const char mbits_str[]\t      = \"Mbit/s\";\n+\tstatic const char gbits_str[]\t      = \"Gbit/s\";\n+\tstatic const char fdx_str[]           = \"FDX \";\n+\tstatic const char hdx_str[]           = \"HDX \";\n+\t/* autoneg is latest param in default string, so add '\\n' */\n+\tstatic const char autoneg_str[]       = \"Autoneg\\n\";\n+\tstatic const char fixed_str[]         = \"Fixed\\n\";\n+\n+\tif (str == NULL || len == 0)\n+\t\treturn -EINVAL;\n+\t/* default format string, if no fmt is specified */\n+\tif (fmt == NULL) {\n+\t\tif (eth_link->link_status == ETH_LINK_DOWN) {\n+\t\t\tif (sizeof(link_down_str) > len)\n+\t\t\t\treturn -EINVAL;\n+\t\t\treturn strlcpy(str, link_down_str, len);\n+\t\t}\n+\n+\t\t/* preformat complex strings to easily concatinate it further */\n+\t\tsnprintf(speed_mbits_str, sizeof(speed_mbits_str), \"%u %s \",\n+\t\t\t eth_link->link_speed, mbits_str);\n+\t\tsnprintf(speed_gbits_str, sizeof(speed_gbits_str), \"%.1f %s \",\n+\t\t\t gbits, gbits_str);\n+\n+\t\toffset = strlcpy(str, link_up_str, len);\n+\t\t/* reserve one byte to null terminator */\n+\t\tif (offset >= len)\n+\t\t\treturn -EINVAL;\n+\t\t/* link speed */\n+\t\tif (eth_link->link_speed == ETH_SPEED_NUM_UNKNOWN) {\n+\t\t\toffset = strlcat(str, unknown_speed_str, len);\n+\t\t\tif (offset >= len)\n+\t\t\t\treturn -EINVAL;\n+\t\t} else {\n+\t\t\tif (eth_link->link_speed < ETH_SPEED_NUM_1G) {\n+\t\t\t\toffset = strlcat(str, speed_mbits_str, len);\n+\t\t\t\tif (offset >= len)\n+\t\t\t\t\treturn -EINVAL;\n+\t\t\t} else {\n+\t\t\t\toffset = strlcat(str, speed_gbits_str, len);\n+\t\t\t\tif (offset >= len)\n+\t\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t}\n+\t\t/* link duplex */\n+\t\toffset = strlcat(str, eth_link->link_duplex ?\n+\t\t\t       fdx_str : hdx_str, len);\n+\t\tif (offset >= len)\n+\t\t\treturn -EINVAL;\n+\t\t/* link autonegotiation */\n+\t\toffset = strlcat(str, eth_link->link_autoneg ?\n+\t\t\t       autoneg_str : fixed_str, len);\n+\t\tif (offset >= len)\n+\t\t\treturn -EINVAL;\n+\t/* Formatted status */\n+\t} else\n+\t\toffset = rte_eth_link_to_str_parser(str, len, fmt, eth_link);\n+\n+\treturn offset;\n+}\n+\n int\n rte_eth_stats_get(uint16_t port_id, struct rte_eth_stats *stats)\n {\ndiff --git a/lib/librte_ethdev/rte_ethdev.h b/lib/librte_ethdev/rte_ethdev.h\nindex 2090af501..eeb6ac50c 100644\n--- a/lib/librte_ethdev/rte_ethdev.h\n+++ b/lib/librte_ethdev/rte_ethdev.h\n@@ -2295,6 +2295,62 @@ int rte_eth_link_get(uint16_t port_id, struct rte_eth_link *link);\n  */\n int rte_eth_link_get_nowait(uint16_t port_id, struct rte_eth_link *link);\n \n+\n+/**\n+ * print formatted link status to stdout. This function treats all\n+ * special values like ETH_SPEED_NUM_UNKNOWN, ETH_LINK_DOWN etc. and convert\n+ * them to textual representation.\n+ *\n+ * @param fmt\n+ *   Format string which allows to format link status.\n+ *   If NULL is provided, default formatting will be applied.\n+ *   Following specifiers are available:\n+ *    - '%M' link speed in Mbits/s\n+ *    - '%G' link speed in Gbits/s\n+ *    - '%S' link status. e.g. Up or Down\n+ *    - '%A' link autonegotiation state\n+ *    - '%D' link duplex state\n+ * @param eth_link\n+ *   Link status provided by rte_eth_link_get function\n+ * @return\n+ *   - Number of bytes written to stdout.\n+ *   - (-EINVAL) if fmt is too long\n+ *\n+ */\n+__rte_experimental\n+int rte_eth_link_printf(const char *const fmt,\n+\t\t\tconst struct rte_eth_link *eth_link);\n+\n+/**\n+ * Format link status to textual representation. This function treats all\n+ * special values like ETH_SPEED_NUM_UNKNOWN, ETH_LINK_DOWN etc. and convert\n+ * them to textual representation.\n+ *\n+ * @param str\n+ *   A pointer to a string to be filled with textual representation of\n+ *   device status.\n+ * @param len\n+ *   Length of available memory at 'str' string.\n+ * @param fmt\n+ *   Format string which allows to format link status.\n+ *   If NULL is provided, default formatting will be applied.\n+ *   Following specifiers are available:\n+ *    - '%M' link speed in Mbits/s\n+ *    - '%G' link speed in Gbits/s\n+ *    - '%S' link status. e.g. Up or Down\n+ *    - '%A' link autonegotiation state\n+ *    - '%D' link duplex state\n+ * @param eth_link\n+ *   Link status provided by rte_eth_link_get function\n+ * @return\n+ *   - Number of bytes written to str array.\n+ *   - (-EINVAL) if size of target buffer is too small for the string\n+ *\n+ */\n+__rte_experimental\n+int rte_eth_link_to_str(char *str, size_t len, const char *const fmt,\n+\t\t\tconst struct rte_eth_link *eth_link);\n+\n /**\n  * Retrieve the general I/O statistics of an Ethernet device.\n  *\ndiff --git a/lib/librte_ethdev/rte_ethdev_version.map b/lib/librte_ethdev/rte_ethdev_version.map\nindex 715505604..79eb99ccd 100644\n--- a/lib/librte_ethdev/rte_ethdev_version.map\n+++ b/lib/librte_ethdev/rte_ethdev_version.map\n@@ -241,4 +241,8 @@ EXPERIMENTAL {\n \t__rte_ethdev_trace_rx_burst;\n \t__rte_ethdev_trace_tx_burst;\n \trte_flow_get_aged_flows;\n+\n+\t# added in 20.08\n+\trte_eth_link_to_str;\n+\trte_eth_link_printf;\n };\n",
    "prefixes": [
        "v8",
        "02/24"
    ]
}