get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 73686,
    "url": "http://patchwork.dpdk.org/api/patches/73686/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/20200710070226.6045-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": "<20200710070226.6045-3-i.dyukov@samsung.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20200710070226.6045-3-i.dyukov@samsung.com",
    "date": "2020-07-10T07:02:00",
    "name": "[v7,02/25] ethdev: add a link status text representation",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "f766db6be8b354cb8dcb90c8243be1343ecc7770",
    "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/20200710070226.6045-3-i.dyukov@samsung.com/mbox/",
    "series": [
        {
            "id": 10941,
            "url": "http://patchwork.dpdk.org/api/series/10941/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dpdk/list/?series=10941",
            "date": "2020-07-10T07:01:58",
            "name": "ethdev: allow unknown link speed",
            "version": 7,
            "mbox": "http://patchwork.dpdk.org/series/10941/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/73686/comments/",
    "check": "fail",
    "checks": "http://patchwork.dpdk.org/api/patches/73686/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 C066FA0526;\n\tFri, 10 Jul 2020 09:02:58 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 14AF51DB6D;\n\tFri, 10 Jul 2020 09:02:45 +0200 (CEST)",
            "from mailout1.w1.samsung.com (mailout1.w1.samsung.com\n [210.118.77.11]) by dpdk.org (Postfix) with ESMTP id 51C321DB7F\n for <dev@dpdk.org>; Fri, 10 Jul 2020 09:02:43 +0200 (CEST)",
            "from eucas1p1.samsung.com (unknown [182.198.249.206])\n by mailout1.w1.samsung.com (KnoxPortal) with ESMTP id\n 20200710070243euoutp01e4207aac0f207980b88087849585c7bb~gUh90QCIm2059620596euoutp01L;\n Fri, 10 Jul 2020 07:02:43 +0000 (GMT)",
            "from eusmges2new.samsung.com (unknown [203.254.199.244]) by\n eucas1p2.samsung.com (KnoxPortal) with ESMTP id\n 20200710070242eucas1p279dbca2b89ef66d5427f65a73631488c~gUh9kSEC11909719097eucas1p2N;\n Fri, 10 Jul 2020 07:02:42 +0000 (GMT)",
            "from eucas1p2.samsung.com ( [182.198.249.207]) by\n eusmges2new.samsung.com (EUCPMTA) with SMTP id 7E.28.05997.292180F5; Fri, 10\n Jul 2020 08:02:42 +0100 (BST)",
            "from eusmtrp2.samsung.com (unknown [182.198.249.139]) by\n eucas1p2.samsung.com (KnoxPortal) with ESMTPA id\n 20200710070242eucas1p2d638073836aab0f37966a801996ee08b~gUh9Plofk1196811968eucas1p22;\n Fri, 10 Jul 2020 07:02:42 +0000 (GMT)",
            "from eusmgms1.samsung.com (unknown [182.198.249.179]) by\n eusmtrp2.samsung.com (KnoxPortal) with ESMTP id\n 20200710070242eusmtrp23bbb0804ebf7522745653d1f8b34f4bf~gUh9OcYbF2959129591eusmtrp2p;\n Fri, 10 Jul 2020 07:02:42 +0000 (GMT)",
            "from eusmtip1.samsung.com ( [203.254.199.221]) by\n eusmgms1.samsung.com (EUCPMTA) with SMTP id C4.74.06314.292180F5; Fri, 10\n Jul 2020 08:02:42 +0100 (BST)",
            "from idyukov.rnd.samsung.ru (unknown [106.109.129.29]) by\n eusmtip1.samsung.com (KnoxPortal) with ESMTPA id\n 20200710070240eusmtip1d9ae3559becbdbe677d9254270457f56~gUh7Wlos11462214622eusmtip13;\n Fri, 10 Jul 2020 07:02:40 +0000 (GMT)"
        ],
        "DKIM-Filter": "OpenDKIM Filter v2.11.0 mailout1.w1.samsung.com\n 20200710070243euoutp01e4207aac0f207980b88087849585c7bb~gUh90QCIm2059620596euoutp01L",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com;\n s=mail20170921; t=1594364563;\n bh=2H/ERU8W5zPS4t5Hj4oIefSk0veb6FZ+kOzsHfJho/0=;\n h=From:To:Subject:Date:In-Reply-To:Reply-To:References:From;\n b=K4BPjK+skMmT2oEgaBcgZ7WVLhVEgjk9aopSzrmaWntJNAiHpYXKjc5qoJhtIccW4\n BEGRJHCuoi3mdrz69w2c6ir2J7QFfTlNPtQIBa6niKTRwj1PzorE/VAs5aGbQAAjC5\n KV65r0Y5WA/WaULyyRDggYI82Dbf1SP3w8zKdy5A=",
        "X-AuditID": "cbfec7f4-677ff7000000176d-fe-5f08129229c9",
        "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": "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": [
            "\n H4sIAAAAAAAAA0WSf2wTZRjH89xd726VmqOgPE4yYiMRiYL4K4+GODQmXEhEiUoIUUaFc6Br\n Ib1tDky0ma5pOthcXSRO0s1OXdkwY7Pd2rkR3Mx+WNgvM0bj2BacQXBsdGy6QWfd7Ub87/P9\n Pt/v875584qs2cunigft2YrDbs2y8EauoX2u53GvWcx4omVgE9We9wFdGa5kabT0Mk+FNz9l\n 6FJ1OjU3njSQd8TJUJE3zlBjwMPT+Gg+RxNTjQwNtUQFKuvPF2iq9apAx3u+ArqauM7SlxW3\n gHp8IQPN/dTE02TCz1HR7QGg4mAnUMexOEelkTCQyyPRzVNVAlUOpdHUaCdH0dgPAp2e6WMp\n dH4eqKSjFuiCK2nY8pB8u+Jbg1zZfI2RP/+6j5XbY18I8rEuHyPXTYQZefLsAC8XBatB/uVK\n ISvXjM3yrxl3GzfvV7IO5iqOjS/sNR745Pcq9vCID/Jm2+YNTrj4kQdSRJSext/GvbzGZikA\n ON633QPGBZ4G/LH3DOjiFuD0TJy/23B2+Rl9UAX4/Tea0OozgBdd2zTmpXUYdfsWQyulOh4b\n E4MLQhRXSFsxMqlqyElrMTyapsVNEmF/fYjT96/BmjPnWI1TpOewwOMX9PVpOFg+vbgSpV4R\n u38tFPTCyxgvCBh0XoHXO4JL/mpMRsoZnT/Ef+oHBb3sBhz2FyyF0jH4V7egXYiVHsXapo26\n /SJWuVoWbZTuxUs3lms2u4DehhOsbpvQ7TLraQue6+pfshHn7yzTbRn/KKlZesJmwPjlfMNn\n sKbs/7MqAKphlZKj2jIV9Um78sEG1WpTc+yZG/YdstXDwk+N/tsxHYamxDutIIlgWWbaO89n\n mA3WXPWIrRVQZC0rTS9diO4xm/ZbjxxVHIcyHDlZitoKD4qcZZXpKf+1t81SpjVbeV9RDiuO\n u1NGTEl1wlvxzMgO6bvAw8+OnHwvVrdjm3H9UMt9tgfa8sIx79/lewKrJ4++edbo/rMztbuk\n awoigeTPj5mG83q5j9PndkbJnhJ8nhkI2J0TdwLPHN/yCFWWvX5/MfOq5UTe2A1PLFS8q+GV\n 2d1t9+T2x3rbx97duj25jxJj6cE3Tm9Olma7QxZOPWDdtJ51qNb/AM9KaYylAwAA",
            "\n H4sIAAAAAAAAAzWSf0yMcRzHfZ/nued5ah2PE74LyVnTTJfr+vE582v84ekP1og/JOdWzyq6\n LvdcrTBLkXYlpBnFSY1+UUrpzjAdCldrshD9OGka0S9aaSX9mP/e2/v1fu+zfd4sKRuh3Njo\n WKNgiNXGyGlnyv63ocM7W8Zq1hePLYGKRjOC7s5CEhw5HTRkDJ4m4EPpFnhUe00C2V3JBGRl\n DxFQW2yi4YcjhYL+4VoC2h/bGchtSWFg2NbLwLnmPAS9E99JuJr/C0GzuUYCf+oe0jAwUUBB\n 1ngrgvPVLxE0ZA5RkGO1IEgzcTBYUsRAYbs7DDteUmBvu8/AnZE3JNQ0TiK42FCBoCltSrJ1\n FT+ef0vCFz76RvCXbr4h+fq2ywyf+cpM8JX9FoIfeNJK81nVpYh/3Z1B8mU9Y3Sw837FRoM+\n 3ih4ROlF4yZ5qBJ8FUo1KHz91AqlKjBsg6+/3GfzxgghJjpBMPhsPqSISv1SRMZ1mVHi2LNJ\n STJ6d9KEnFjM+eHkVwWECTmzMu4Wwp0Tk8iE2GkD474eco5ZhCfemeg55hfC57+Pzho054Xt\n 6ebZsCv3icZvz56iZsKLuB3YOiDOSIrzxBaH+wwu5QC3VNVQc50rcdm9p7M1TpwanzEVMDNa\n xkVh2+BtNKfd8fsbv4kLaH4+mleKXIV4URepE5UKUasT42MjFeF6XRWafvmD+j/3Lailco8N\n cSySu0gtU7RGJtEmiEk6G8IsKXeVbmuyH5RJI7RJxwSDXmOIjxFEG/Kfvu8i6bY4XD89oFij\n RumvDAS1MlAVqAoA+VJpOld3QMZFao3CEUGIEwz/cwTr5JaMTjDbNX0Hnqvez5f6FboHXPdY\n +DGndHnIvAV/r38NDibXDV1rSgpaPerWuF8fKl2xTEjtTrzis7uE2ns3rNkzryvPeyTEuHM0\n 9+DRmJ97ynd7Vv5UHXd1CY6uSC8f7e1jrHU9Q5C9D8eFefFLz1lzXuiCyleHVDtaUw637NrW\n 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>\n <20200710070226.6045-1-i.dyukov@samsung.com>\n <CGME20200710070242eucas1p2d638073836aab0f37966a801996ee08b@eucas1p2.samsung.com>",
        "Subject": "[dpdk-dev] [PATCH v7 02/25] 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": "This commit add 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              | 299 +++++++++++++++++++++++\n lib/librte_ethdev/rte_ethdev.c           | 174 +++++++++++++\n lib/librte_ethdev/rte_ethdev.h           |  54 ++++\n lib/librte_ethdev/rte_ethdev_version.map |   4 +\n 7 files changed, 537 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..8a2f133c0\n--- /dev/null\n+++ b/app/test/test_ethdev_link.c\n@@ -0,0 +1,299 @@\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+\tret = rte_eth_link_strf(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_strf(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_strf(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+\tret = rte_eth_link_strf(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+\tfor (i = 0; i < 128; i++)\n+\t\ttext[i] = 'Y';\n+\ttext[127] = '\\0';\n+\n+\tret = rte_eth_link_strf(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_strf(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_strf(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_strf(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_strf(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_strf(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+\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_strf(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_strf(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_strf(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_strf(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+\tfor (i = 0; i < 128; i++)\n+\t\ttext[i] = 'Y';\n+\ttext[127] = '\\0';\n+\tret = rte_eth_link_strf(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_strf(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_strf(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_strf(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+\tret = rte_eth_link_strf(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_strf(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_strf(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_strf(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+\tret = rte_eth_link_strf(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_strf(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_strf(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_strf(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..38332b1e4 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_strf_parser(char *str, size_t len, const char *const fmt,\n+\t\t\t   const struct rte_eth_link *link)\n+{\n+\tsize_t offset = 0;\n+\tconst char *fmt_cur = fmt;\n+\tchar *str_cur = str;\n+\tdouble gbits = (double)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\", 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 - 1)) {\n+\t\t\tstr[len - 1] = '\\0';\n+\t\t\treturn -1;\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\t*str_cur = '\\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 (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 (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, 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, 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, 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\tdefault:\n+\t\t\t\t*str_cur = '%';\n+\t\t\t\toffset++;\n+\t\t\t\tfmt_cur--;\n+\t\t\t\tbreak;\n+\n+\t\t\t}\n+\t\t\tif (offset > (len - 1))\n+\t\t\t\treturn -1;\n+\n+\t\t\tstr_cur = str + offset;\n+\t\t} else {\n+\t\t\t*str_cur++ = *fmt_cur;\n+\t\t\toffset++;\n+\t\t}\n+\t\tfmt_cur++;\n+\t}\n+\t*str_cur = '\\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 *link)\n+{\n+\tchar text[200];\n+\tint ret;\n+\n+\tret = rte_eth_link_strf(text, 200, fmt, link);\n+\tif (ret > 0)\n+\t\tprintf(\"%s\", text);\n+\treturn ret;\n+}\n+\n+int\n+rte_eth_link_strf(char *str, size_t len, const char *const fmt,\n+\t\t    const struct rte_eth_link *link)\n+{\n+\tsize_t offset = 0;\n+\tdouble gbits = (double)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+\tif (str == NULL || len == 0)\n+\t\treturn -1;\n+\t/* default format string, if no fmt is specified */\n+\tif (fmt == NULL) {\n+\t\tif (link->link_status == ETH_LINK_DOWN) {\n+\t\t\tif (sizeof(link_down_str) > len)\n+\t\t\t\treturn -1;\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, 20, \"%u %s \", link->link_speed,\n+\t\t\t mbits_str);\n+\t\tsnprintf(speed_gbits_str, 20, \"%.1f %s \", 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 - 1))\n+\t\t\treturn -1;\n+\t\t/* link speed */\n+\t\tif (link->link_speed == ETH_SPEED_NUM_UNKNOWN) {\n+\t\t\toffset = strlcat(str, unknown_speed_str, len);\n+\t\t\tif (offset > (len - 1))\n+\t\t\t\treturn -1;\n+\t\t} else {\n+\t\t\tif (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 - 1))\n+\t\t\t\t\treturn -1;\n+\t\t\t} else {\n+\t\t\t\toffset = strlcat(str, speed_gbits_str, len);\n+\t\t\t\tif (offset > (len - 1))\n+\t\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t}\n+\t\t/* link duplex */\n+\t\toffset = strlcat(str, link->link_duplex ?\n+\t\t\t       fdx_str : hdx_str, len);\n+\t\tif (offset > (len - 1))\n+\t\t\treturn -1;\n+\t\t/* link autonegotiation */\n+\t\toffset = strlcat(str, link->link_autoneg ?\n+\t\t\t       autoneg_str : fixed_str, len);\n+\t\tif (offset > (len - 1))\n+\t\t\treturn -1;\n+\t/* Formatted status */\n+\t} else\n+\t\toffset = rte_eth_link_strf_parser(str, len, fmt, 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..9afb566b3 100644\n--- a/lib/librte_ethdev/rte_ethdev.h\n+++ b/lib/librte_ethdev/rte_ethdev.h\n@@ -2295,6 +2295,60 @@ 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 threats 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 allow to format link status. If NULL is provided\n+ *   , 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 link\n+ *   Link status provided by rte_eth_link_get function\n+ * @return\n+ *   - Number of bytes written to stdout. In case of error, -1 is returned.\n+ *\n+ */\n+__rte_experimental\n+int rte_eth_link_printf(const char *const fmt,\n+\t\t\tconst struct rte_eth_link *link);\n+\n+/**\n+ * Format link status to textual representation. This function threats 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 allow to format link status. If NULL is provided\n+ *   , 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 link\n+ *   Link status provided by rte_eth_link_get function\n+ * @return\n+ *   - Number of bytes written to str array. In case of error, -1 is returned.\n+ *\n+ */\n+__rte_experimental\n+int rte_eth_link_strf(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..6c80597d1 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_strf;\n+\trte_eth_link_printf;\n };\n",
    "prefixes": [
        "v7",
        "02/25"
    ]
}