get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 75388,
    "url": "http://patchwork.dpdk.org/api/patches/75388/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/20200811085246.28735-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": "<20200811085246.28735-3-i.dyukov@samsung.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20200811085246.28735-3-i.dyukov@samsung.com",
    "date": "2020-08-11T08:52:21",
    "name": "[v9,02/24] ethdev: add a link status text representation",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "04d3f1a852629531060ae2bd4eaa9eafdaef2330",
    "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/20200811085246.28735-3-i.dyukov@samsung.com/mbox/",
    "series": [
        {
            "id": 11591,
            "url": "http://patchwork.dpdk.org/api/series/11591/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dpdk/list/?series=11591",
            "date": "2020-08-11T08:52:19",
            "name": "ethdev: allow unknown link speed",
            "version": 9,
            "mbox": "http://patchwork.dpdk.org/series/11591/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/75388/comments/",
    "check": "success",
    "checks": "http://patchwork.dpdk.org/api/patches/75388/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 89E5FA04AF;\n\tTue, 11 Aug 2020 10:53:32 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id B236C1C0B4;\n\tTue, 11 Aug 2020 10:53:09 +0200 (CEST)",
            "from mailout1.w1.samsung.com (mailout1.w1.samsung.com\n [210.118.77.11]) by dpdk.org (Postfix) with ESMTP id 7D4BD1C027\n for <dev@dpdk.org>; Tue, 11 Aug 2020 10:53:06 +0200 (CEST)",
            "from eucas1p2.samsung.com (unknown [182.198.249.207])\n by mailout1.w1.samsung.com (KnoxPortal) with ESMTP id\n 20200811085305euoutp017700cab035e83a88ec695f868dc2cb04~qKreMUUiq0826508265euoutp01Z;\n Tue, 11 Aug 2020 08:53:05 +0000 (GMT)",
            "from eusmges1new.samsung.com (unknown [203.254.199.242]) by\n eucas1p2.samsung.com (KnoxPortal) with ESMTP id\n 20200811085305eucas1p26c584841ada9b17f6673d234840c64b2~qKrd7rdl90327403274eucas1p2n;\n Tue, 11 Aug 2020 08:53:05 +0000 (GMT)",
            "from eucas1p2.samsung.com ( [182.198.249.207]) by\n eusmges1new.samsung.com (EUCPMTA) with SMTP id D2.A1.06456.17C523F5; Tue, 11\n Aug 2020 09:53:05 +0100 (BST)",
            "from eusmtrp1.samsung.com (unknown [182.198.249.138]) by\n eucas1p1.samsung.com (KnoxPortal) with ESMTPA id\n 20200811085304eucas1p150bf23b6f183a28fbceca06b0bced5af~qKrdZOCc11585315853eucas1p1r;\n Tue, 11 Aug 2020 08:53:04 +0000 (GMT)",
            "from eusmgms2.samsung.com (unknown [182.198.249.180]) by\n eusmtrp1.samsung.com (KnoxPortal) with ESMTP id\n 20200811085304eusmtrp1009d3c2447cf63ad5568125e233dd0f9~qKrdYWuwe1603916039eusmtrp1S;\n Tue, 11 Aug 2020 08:53:04 +0000 (GMT)",
            "from eusmtip1.samsung.com ( [203.254.199.221]) by\n eusmgms2.samsung.com (EUCPMTA) with SMTP id 5E.3D.06017.07C523F5; Tue, 11\n Aug 2020 09:53:04 +0100 (BST)",
            "from idyukov.rnd.samsung.ru (unknown [106.109.129.29]) by\n eusmtip1.samsung.com (KnoxPortal) with ESMTPA id\n 20200811085302eusmtip18b20bc89818035a60d5f97482751c7f9~qKrbkxqD51792217922eusmtip1H;\n Tue, 11 Aug 2020 08:53:02 +0000 (GMT)"
        ],
        "DKIM-Filter": "OpenDKIM Filter v2.11.0 mailout1.w1.samsung.com\n 20200811085305euoutp017700cab035e83a88ec695f868dc2cb04~qKreMUUiq0826508265euoutp01Z",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com;\n s=mail20170921; t=1597135985;\n bh=yjuhr21wJK56U6WY1nzuFW3DUMB8s5LfzNkDjUmUCik=;\n h=From:To:Subject:Date:In-Reply-To:Reply-To:References:From;\n b=Gnwp6ehTrK/CQjsgWOka/Qwp2BBAUhfjKjcf8xIYo4LxRgOf7meb1R+7onw3zD6xX\n Gr5jkdI2efxm57lIxeX1qMiZ8EYloZLgJPu1C5ON1a0OyWF7xfrUXpzute/yxnrQlv\n ZegS9wV1XQkVio8JSZ1nziuZNDhUQZKBhUDBpQ7Q=",
        "X-AuditID": "cbfec7f2-7efff70000001938-dd-5f325c71eb62",
        "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": "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": [
            "\n H4sIAAAAAAAAA0VSf0wTdxTPu7veXRvqjsLCC3MSmpBsmqlsmrzpNpxZtksMi8n+Ic4Nz3lB\n M36tBTaXbEFwzJWuQtVtwCwIGGhLxM7KD6MD6wKygp0Yo0RGiWFrFH9WCOBgjnqY/ff5+d7L\n N1+RNR3hk8U9+UWqJV/JNfMGrqNvLvTKZ9tfzV57oyqe2gddQDfHmlgaP/wnT5UP9jN03ZNB\n Zzt/1pEzXMqQw/mQoc5WG093xss4uhftZGj0XFCg2uEygaKBiEDfh+qAIvO3WappeAQUcp3W\n 0dz5Mzzdn2/kyPH4KtBB/0WgfvtDjg53dwFV2CR64G4RqGl0BUXHL3IUHDklUNv0ZZZODy4A\n Vfe3Aw1VPNFtSpUfNxzXyU1nbzHyoWOXWblv5AdBtg+4GNl3r4uR7/96lZcdfg/Iv9+sZGXv\n xCy/1bDN8MYuNXdPiWpZ89YOw263z84XXmiEL8JDQaYUQmVgA72I0jqcOTGziA2iSWoFtA/U\n 8xqZAgwdaRY08giwdbiHeVbpHq0WYtgktQA6Jwu10DTgidYaLmbw0ksYPOBiYkai5OOxc/7a\n 03aC9B6WT+zT2UAUOSkNDy4kx6BReh0dgXe1+SnoPdnLxrBe2oDeujCr7VqB1+qnno5E6Q8R\n x2tDnFZ4B/1j7qXjEvB2v1/Q8HIMHrJzWuFbwOqOU4JGqgDL6+4upTLQP3lJiF3BSi9j+5k1\n mvw2tkU8TExGaRlevxsfk9lF6Oz4kdVkIx6oMGlpM/YODC/JiAv/xGmyjLNzI0sPeg7wN69d\n qIKU2v93NQB4IEkttublqNb0fPXz1VYlz1qcn7P6k4K8X2Dxswb/7Y92wfTwzgBIIpjjjIUb\n 07NNOqXEujcvACiy5kTj5qHgxybjLmXvl6qlINtSnKtaA/CCyJmTjK813vrIJOUoReqnqlqo\n Wp65jKhPLoX1bXNpLVuHohU9NZU3Vq1/sTqjrd7hmU+y7Zz5K+LdmDC1xb2vSN2fWf7muuzE\n k66So74nvi0LYxvavzOnO43elXETV37K3NzzYVVaynMzvYlMVnM339yhj4T/Lij5OnXwfeWD\n 845vUrM2Xfiq9ooy7a1/Pmtt36X4JndmeHa5ftmdSTNn3a2kr2QtVuU/XXXU/agDAAA=",
            "\n H4sIAAAAAAAAAzWSa0hTYRjHe885OztKi8OyevOD5ckiAmdnaj6aWkSXQxAoRR/MsqUHldxm\n O1OyhHSJybSZZkW35aXIS1JeSg3LWqHVFLF7qTnEkDKmeSPFSy7p2x9+/+fHA8/DkMpJypNJ\n 1BlFg06TxNHulH2urdc3OVods/nruC/cb7ci6P9WRoKjqJeG3JEsAj5XboPmhhsyKOzLIMBS\n +JuAhnIzDb8cJgqcow0E9Dyxy+HaW5McRm2DcjjfeR3B4MxPEq4WjyHotD6UwdTzxzQMz5RS\n YJn+gCC//hWCtrzfFBQ1NSLINrMwUnFXDmU9XjDqeEWB/UudHO5NdJHwsH0WQUHbfQQd2fOy\n 7d7CdPEdmVDW/IMQLpZ0kULrl8tyIe+1lRBqnI2EMPz0Ay1Y6iuR8KY/lxSqBv7QEe5RqlCD\n PsUork3QS8Yw7hAPahUfDCp1QLCK9w86HKIO5PzCQ+PEpMRU0eAXflSVUFGTRye/KEUn+zrs\n RAbqNCEzcmMwG4CbegrkZuTOKNk7CBdmzZNmxCwAjIcGyMXOcjzz0UwvdsYQvtjQTbgAzW7E\n 9hwr4QIebDeN353LpFxgObsHnx3IlLlEFLse5896uqKCDcYW2+5F5xpc9eDZP78bG4Krrvf9\n y0o2EWf2NtGL2Qt/ujVOXEDLitGSSuQhpkjaeK2kVkkarZSii1fF6rW1aOHmj1qn6huR2bnf\n hlgGcUsVyVv5GKVMkyqlaW0IMyTnodjRYT+iVMRp0k6JBn2MISVJlGwocGG9AtJzRax+4YN0\n xhg+kA+CYD7IP8h/C3CrFDns82glG68xisdFMVk0/J8jGDfPDJRv8itZGVqKOb+d8yd4XZ30\n ZsPesi3H979XD6TvjexqXdaiiTKs/n7m4NSJkyMVPsb3PuLpm46Mfd5du3SVs7Xd3ybjjl7p\n cEy8jDf5OHe2HLhNbZpkLlXLIjzU/GVn1etE98ihnJJ1x4rSvS3lt6vZfXP6sN3PGtubV+QG\n 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>\n <20200811085246.28735-1-i.dyukov@samsung.com>\n <CGME20200811085304eucas1p150bf23b6f183a28fbceca06b0bced5af@eucas1p1.samsung.com>",
        "Subject": "[dpdk-dev] [PATCH v9 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, link_duplex equal to 0 means\n'half-duplex' etc. 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. User may create custom\nlink status string using format string. If format string is NULL,\nthe function construct standard link status string.\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              | 315 +++++++++++++++++++++++\n lib/librte_ethdev/rte_ethdev.c           | 160 ++++++++++++\n lib/librte_ethdev/rte_ethdev.h           |  32 +++\n lib/librte_ethdev/rte_ethdev_version.map |   3 +\n 7 files changed, 516 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..b501deefe\n--- /dev/null\n+++ b/app/test/test_ethdev_link.c\n@@ -0,0 +1,315 @@\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[RTE_ETH_LINK_MAX_STR_LEN + 1];\n+\n+\tret = rte_eth_link_to_str(text, sizeof(text), 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+\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, sizeof(text), 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+\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, sizeof(text), 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+\t\ttext, strlen(text), \"Invalid default link status \"\n+\t\t\"string with HDX\");\n+\n+\t/* test max str len */\n+\tlink_status.link_speed = ETH_SPEED_NUM_UNKNOWN - 1;\n+\tlink_status.link_duplex = ETH_LINK_HALF_DUPLEX;\n+\tlink_status.link_autoneg = ETH_LINK_AUTONEG;\n+\tret = rte_eth_link_to_str(text, sizeof(text), NULL, &link_status);\n+\tprintf(\"Default link up #4:len = %d, %s\\n\", ret, text);\n+\tRTE_TEST_ASSERT(ret > RTE_ETH_LINK_MAX_STR_LEN,\n+\t\t\"String length exceeds max allowed value\\n\");\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[RTE_ETH_LINK_MAX_STR_LEN];\n+\n+\tret = rte_eth_link_to_str(text, sizeof(text), NULL, &link_status);\n+\tRTE_TEST_ASSERT(ret > 0, \"Failed to format default string\\n\");\n+\tTEST_ASSERT_BUFFERS_ARE_EQUAL(\"Link down\",\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..3c00ee7ee 100644\n--- a/lib/librte_ethdev/rte_ethdev.c\n+++ b/lib/librte_ethdev/rte_ethdev.c\n@@ -2383,6 +2383,166 @@ 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_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+\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+\tstatic const char autoneg_str[]       = \"Autoneg\";\n+\tstatic const char fixed_str[]         = \"Fixed\";\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..4e8fdc891 100644\n--- a/lib/librte_ethdev/rte_ethdev.h\n+++ b/lib/librte_ethdev/rte_ethdev.h\n@@ -323,6 +323,7 @@ struct rte_eth_link {\n #define ETH_LINK_UP          1 /**< Link is up (see link_status). */\n #define ETH_LINK_FIXED       0 /**< No autonegotiation (see link_autoneg). */\n #define ETH_LINK_AUTONEG     1 /**< Autonegotiated (see link_autoneg). */\n+#define ETH_LINK_MAX_STR_LEN 60 /**< Max length of default link string. */\n \n /**\n  * A structure used to configure the ring threshold registers of an RX/TX\n@@ -2295,6 +2296,37 @@ 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+ * 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. At least ETH_LINK_MAX_STR_LEN bytes should be allocated to\n+ *   store default link status text.\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..afdfd59d6 100644\n--- a/lib/librte_ethdev/rte_ethdev_version.map\n+++ b/lib/librte_ethdev/rte_ethdev_version.map\n@@ -241,4 +241,7 @@ 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.11\n+\trte_eth_link_to_str;\n };\n",
    "prefixes": [
        "v9",
        "02/24"
    ]
}