From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 1A294A0524; Sun, 30 May 2021 09:27:42 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id BA52540040; Sun, 30 May 2021 09:27:40 +0200 (CEST) Received: from NAM11-CO1-obe.outbound.protection.outlook.com (mail-co1nam11on2072.outbound.protection.outlook.com [40.107.220.72]) by mails.dpdk.org (Postfix) with ESMTP id 267284003E for ; Sun, 30 May 2021 09:27:39 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=MTDG6EgRkrNo9psiNUzBMRQcqGukFhAr9Ryx85LHTdSF//dImGjnSnHmtR5zY2VBYRMip7B9fZpJq8zgBWet2CotjhUAWBA4Kr7o4OImiAFAB3CNKmz88mMRYT2Jmyejr11s/r84V3R7M1rLCLpl7nVkzxUL9KlMkRYqsv0mnQFBOsb2G2tjem423oAQxZdD/ijY9vezi9bnLF6r+10kFSZNOYuFSydMMaovSp5xDsA9m0AjuTTsSSwLCkvvald1yqWNjq+HWvmZfVOzlG8TGu8zlQ7rm+3MamnE+0HKLD1+DeJnTB+tYRlHxlJoTU/9o1gUvsm7jDG/uJVbggcYzA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=xATVyRQ58oNWo5wZMPrCerXsEoBjgHbj5vc6ZtzYht4=; b=QpqBLM0yMEb34d5FQztYVn0y0AWEVcMl7qRsEkLBut4qySvrYO0uZMsRgXrLfsDNXMhCaplje8oUZeJnGhSDNq/I4gdsGMGgdjZg36pPCS0rSWfwfcCiFOpJCAN7jMVqz8uWm29zHw3W9Qemn4EXk0D4Qho50VzNckrJIs7M6mnAghxh8kke/wyxYTh0i/Sr0KO5xgSp9BN+KEfpeYOaMlZC4kEgexhSoWG9bpO1W56XEzNujwErOqdQVIF+l3vLtPJZZMCBJh6kOvXiMSxlPK7q222HzLG318AmNg/72rxWReUirxNcKR4g0UAfN0V2R+FEOqiUa2K7apht32KdFg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=xATVyRQ58oNWo5wZMPrCerXsEoBjgHbj5vc6ZtzYht4=; b=lTrWfXuso7hEHo8rtFYB6jPia8UlSzTGs09nHgX88UHo3vVPTj8gUYL8u+l9KrfVzph2M3IMFLTofbLYPLWBO0WYcOA05OKFcmMOelb+cnU9zrMJYlRPfMVzYxqTstSQFS5jdPS4Xy0teyew3ozUZGHrDUBtyW1044xU8SJmrRhN05R3h0pfk4p9+dC4EoWIBT90xcjND7BQUjUidGvASkkNqO8vhowEvubRB9t2PpQvAj1Hms0EdoMQIskZdr+R771qt3d2qAml8cbdl3/h6F6dwgs2Ww06HJUQa6ke7YjLLBKGCwflmFQ148B4GlSsfryr0HR39M6eJsckhyiRbA== Received: from BL1PR12MB5335.namprd12.prod.outlook.com (2603:10b6:208:317::19) by BL0PR12MB5539.namprd12.prod.outlook.com (2603:10b6:208:1c3::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4173.20; Sun, 30 May 2021 07:27:33 +0000 Received: from BL1PR12MB5335.namprd12.prod.outlook.com ([fe80::6130:4ca:e5b6:4a36]) by BL1PR12MB5335.namprd12.prod.outlook.com ([fe80::6130:4ca:e5b6:4a36%7]) with mapi id 15.20.4173.029; Sun, 30 May 2021 07:27:32 +0000 From: Ori Kam To: Ivan Malov , "dev@dpdk.org" CC: NBU-Contact-Thomas Monjalon , Ferruh Yigit , Andrew Rybchenko , Ray Kinsella , Neil Horman Thread-Topic: [RFC PATCH] ethdev: add support for testpmd-compliant flow rule dumping Thread-Index: AQHXUtHTVmOnBGTM6UKpSaUBdRK75qr7mK5Q Date: Sun, 30 May 2021 07:27:32 +0000 Message-ID: References: <20210527082504.3495-1-ivan.malov@oktetlabs.ru> In-Reply-To: <20210527082504.3495-1-ivan.malov@oktetlabs.ru> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: oktetlabs.ru; dkim=none (message not signed) header.d=none;oktetlabs.ru; dmarc=none action=none header.from=nvidia.com; x-originating-ip: [2a00:7c40:c360:2a4:2404:2a16:a61f:c1ef] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: 52ce58bb-a4b6-480a-41bc-08d9233c63ce x-ms-traffictypediagnostic: BL0PR12MB5539: x-ld-processed: 43083d15-7273-40c1-b7db-39efd9ccc17a,ExtAddr x-microsoft-antispam-prvs: x-ms-oob-tlc-oobclassifiers: OLM:240; x-ms-exchange-senderadcheck: 1 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: ng+UzRLddX17E62zAw2Mc+LZ2iPkomO4CVKiR10TyDaXzn1XxCdu+wB1CPc+FFowxrqLl7hIbMp98j3K1LgRXC5UPgssRWtvEXiKb9RwBCAZTks8CQ81pBe1TsZiqcisR92qV0Vb0CiKUG2gNcXpql4RNW9hauhxcKMEndAHBlR+RRcHO7ctpLGL9+D4YXe51s2QyAmRRcK5+uH1KABrbhRJmgzDlSNqa0vNPa2A9K3/aoK3dFuqbxcdprj6Y/ekMROPHgziLHk3iLKNdFgtxB2ynhw/yYuw9sBrQIQbKZvoNOpzzwoNQtcYzDqAF6AYLWn2pc+00OVNQyuePLq5F6sexrYKLZNsN8wflvy2r22ijOm7/ZtggZ6rxm2Pg01uVCrr2d1yyfXHTjUU30Tp43OrlYn4jG5QlaWjnS8sC3w7eWgSVLgQXYPT8ASxIngNFs0UZGydu5dYcAce2oQ4rIkLeIJcB/+KU6ssX8QS7MasS1yXb6PDO7TJoKLQiNDvMW2C4E0meLY/ccRVo5Euxv7rNXEVlglESFYQsBA9+f0aENo1dyQKpmR2A38UpYKIbV81dwnOSIwezi2yGAx9Nir4BdiDcaNyxPWLnvYMlUo= x-forefront-antispam-report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:BL1PR12MB5335.namprd12.prod.outlook.com; PTR:; CAT:NONE; SFS:(4636009)(346002)(136003)(376002)(396003)(39860400002)(366004)(52536014)(83380400001)(5660300002)(30864003)(76116006)(186003)(66946007)(122000001)(66476007)(66556008)(66446008)(64756008)(2906002)(33656002)(316002)(110136005)(54906003)(53546011)(7696005)(6506007)(71200400001)(38100700002)(9686003)(86362001)(4326008)(8676002)(8936002)(55016002)(478600001)(579004)(559001); DIR:OUT; SFP:1101; x-ms-exchange-antispam-messagedata: =?us-ascii?Q?SP1zS9qAhYgn//ENkOxnL3yqlEtE/2NvSprMvvlonpBazfC+iQq49iYFDPAq?= =?us-ascii?Q?vM0LepVBJB2BNEBAzx8MO1iG/dVGbhZ1CGQB4Y1/e6zum1ABDJh1ohRSBTd4?= =?us-ascii?Q?W7lO6+FaSUH/QfgA9ucYt2xgQczcvYoOMVU6t70+rCfpaTWSta8JTSkRdMEV?= =?us-ascii?Q?7bH0PUgxsoiEbyFisnCyIa3sSh2AQ7G82tSjZSB71fmIQ1tRa+OrU6qJw2Se?= =?us-ascii?Q?d3tyhww1AX3nW7GDHrpezwr0y5NmJfZzXAOjqeQyMbLk2Z4gZp934I4WMyoa?= =?us-ascii?Q?fv/fPg7XhF+thgakVZIfiIO5msVFewCy7rO1MidEi90vH7TWHL20fbfA8NhN?= =?us-ascii?Q?BBgudP5eoqcjMwAczQnRs8m8ldMnaj/QAwtAPQgg7l0o65iobxrChGtx8A70?= =?us-ascii?Q?BwGeOk50PhJ+18cdY3RBa1p4jL/ATgpzWpMnGc7vTkpUQKf3IateIM4lmIE7?= =?us-ascii?Q?A8BzxAsi3mNNzy27Zim6BcFERxD0fZoS/tYoymwqTcYjuFOUScL11Ifp651L?= =?us-ascii?Q?lX6RLQ5vLTXdt5WXfv4z5BEnhRjn6CSyC/5BaW/OOFciiDzqI1MXYQFqDd5F?= =?us-ascii?Q?zxXO8c6eMe0kwrcKOEsbdhfp4MSueQ6j0yyHfdnakkkJNcIZF7W2iZsOl0Tc?= =?us-ascii?Q?kyTydvN41uOylBBc7r+Y63GAqqOG89nOL/xxT/tObUY8IFMBqZFcZkbQxoHW?= =?us-ascii?Q?7EAA+C3lgoo2hUwElcL2g6j0rwczaxqLuAEeJWACZopijbB1GIhuPzzXYYNc?= =?us-ascii?Q?JyI6dFt9ge0k8Vr/ICT1did91lJ61zgBPXI4etxwSqwGkTEz/i4y3ddXCBTV?= =?us-ascii?Q?A/+6wGgevENrvcWa0F4WMcbnX2XZTlndMtrRusUA4/+LtBVHPB6gEs4LfZCg?= =?us-ascii?Q?iPkOe48l17SfOf2dRiKM5NKw8rh3Ksw7SSawVQrsf1KUysds6B+NmZmOzKKS?= =?us-ascii?Q?G4OWPueKvPK3rq3C8h7RldP7rKPeJ9iZueSRJzFVSVpNIHJyU1N+okyh6gHJ?= =?us-ascii?Q?cv1Mm325PuJocOOlG3wWgpkEFOBY0V4rigL+Lpq4vwJMgxLbCknINOUhZ1yX?= =?us-ascii?Q?lLixr8fXRaNTkU3bgY3i0h6IFjPMOg1kcd6NTk+nsWiGYkKSR3qBWVPQYgD7?= =?us-ascii?Q?B2QL/vSKf8vjgkROBmDCxmq07BooQTPw+JsBruUSbwdOSFXLXNsb7wOJS/UV?= =?us-ascii?Q?W96csun554j2PjrX5PJ2wRlEi2JyxSf4rKWfwzroag90rsDHuA7sPE4T2L9T?= =?us-ascii?Q?lRDOPGLnUdOxztIltKR3A2nEjaMEEbMAZ+rYXv8hjtuS8loChtBvw/qHLfnG?= =?us-ascii?Q?NJ98V6olNk4Bl1LvddyWL74Awn48c4uvmD7E3BPwcA0luI8QwV+HuQ/5VoNY?= =?us-ascii?Q?HksAtCKEovce1JkCqMIwr4ZSFD0r?= x-ms-exchange-transport-forked: True Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: BL1PR12MB5335.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 52ce58bb-a4b6-480a-41bc-08d9233c63ce X-MS-Exchange-CrossTenant-originalarrivaltime: 30 May 2021 07:27:32.6727 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: +9XqsZxymjbx+VCxUyLlezMgvZsMBtWIMDz1NznlznYn/IHWzAAQIHIEuM5/lgT3MUcURhAUK74kwV1K+eh+ew== X-MS-Exchange-Transport-CrossTenantHeadersStamped: BL0PR12MB5539 Subject: Re: [dpdk-dev] [RFC PATCH] ethdev: add support for testpmd-compliant flow rule dumping X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Hi Ivan, First nice idea and thanks for the picking up the ball. Before a detail review,=20 The main thing I'm concerned about is that this print will be partially sup= ported, I know that you covered this issue by printing unknown for unsupported item= /actions, but this will mean that it is enough that one item/action is not supported = and already the=20 flow can't be used in testpmd. To get full support it means that the developer needs to add such print wit= h each new item/action. I agree it is possible, but it has high overhead for each feat= ure. Maybe we should somehow create a macros for the prints or other easier to s= upport ways. For example, just printing the ipv4 has 7 function calls inside of it each = one with error checking, and I'm not counting the dedicated functions.=20 Best, Ori > -----Original Message----- > From: Ivan Malov > Sent: Thursday, May 27, 2021 11:25 AM > To: dev@dpdk.org > Cc: NBU-Contact-Thomas Monjalon ; Ferruh Yigit > ; Andrew Rybchenko > ; Ori Kam ; Ray > Kinsella ; Neil Horman > Subject: [RFC PATCH] ethdev: add support for testpmd-compliant flow rule > dumping >=20 > DPDK applications (for example, OvS) or tests which use RTE flow API need= to > log created or rejected flow rules to help to recognise what goes right o= r > wrong. From this standpoint, testpmd-compliant format is nice for the > purpose because it allows to copy-paste the flow rules and debug using > testpmd. >=20 > Recognisable pattern items: > VOID, VF, PF, PHY_PORT, PORT_ID, ETH, VLAN, IPV4, IPV6, UDP, TCP, VXLAN, > NVGRE, GENEVE, MARK, PPPOES, PPPOED. >=20 > Recognisable actions: > VOID, JUMP, MARK, FLAG, QUEUE, DROP, COUNT, RSS, PF, VF, PHY_PORT, > PORT_ID, OF_POP_VLAN, OF_PUSH_VLAN, OF_SET_VLAN_VID, > OF_SET_VLAN_PCP, VXLAN_ENCAP, VXLAN_DECAP. >=20 > Recognisable RSS types (action RSS): > IPV4, FRAG_IPV4, NONFRAG_IPV4_TCP, NONFRAG_IPV4_UDP, > NONFRAG_IPV4_OTHER, IPV6, FRAG_IPV6, NONFRAG_IPV6_TCP, > NONFRAG_IPV6_UDP, NONFRAG_IPV6_OTHER, IPV6_EX, IPV6_TCP_EX, > IPV6_UDP_EX, L3_SRC_ONLY, L3_DST_ONLY, L4_SRC_ONLY, L4_DST_ONLY. >=20 > Unrecognised parts of the flow specification are represented by tokens > "{unknown}" and "{unknown bits}". Interested parties are welcome to > extend this tool to recognise more items and actions. >=20 > Signed-off-by: Ivan Malov > --- > lib/ethdev/meson.build | 1 + > lib/ethdev/rte_flow.h | 33 + > lib/ethdev/rte_flow_snprint.c | 1681 > +++++++++++++++++++++++++++++++++ > lib/ethdev/version.map | 3 + > 4 files changed, 1718 insertions(+) > create mode 100644 lib/ethdev/rte_flow_snprint.c >=20 > diff --git a/lib/ethdev/meson.build b/lib/ethdev/meson.build index > 0205c853df..97bba4fa1b 100644 > --- a/lib/ethdev/meson.build > +++ b/lib/ethdev/meson.build > @@ -8,6 +8,7 @@ sources =3D files( > 'rte_class_eth.c', > 'rte_ethdev.c', > 'rte_flow.c', > + 'rte_flow_snprint.c', > 'rte_mtr.c', > 'rte_tm.c', > ) > diff --git a/lib/ethdev/rte_flow.h b/lib/ethdev/rte_flow.h index > 961a5884fe..cd5e9ef631 100644 > --- a/lib/ethdev/rte_flow.h > +++ b/lib/ethdev/rte_flow.h > @@ -4288,6 +4288,39 @@ rte_flow_tunnel_item_release(uint16_t port_id, > struct rte_flow_item *items, > uint32_t num_of_items, > struct rte_flow_error *error); > + > +/** > + * @warning > + * @b EXPERIMENTAL: this API may change without prior notice > + * > + * Dump testpmd-compliant textual representation of the flow rule. > + * Invoke this with zero-size buffer to learn the string size and > + * invoke this for the second time to actually dump the flow rule. > + * The buffer size on the second invocation =3D the string size + 1. > + * > + * @param[out] buf > + * Buffer to save the dump in, or NULL > + * @param buf_size > + * Buffer size, or 0 > + * @param[out] nb_chars_total > + * Resulting string size (excluding the terminating null byte) > + * @param[in] attr > + * Flow rule attributes. > + * @param[in] pattern > + * Pattern specification (list terminated by the END pattern item). > + * @param[in] actions > + * Associated actions (list terminated by the END action). > + * > + * @return > + * 0 on success, a negative errno value otherwise > + */ > +__rte_experimental > +int > +rte_flow_snprint(char *buf, size_t buf_size, size_t *nb_chars_total, > + const struct rte_flow_attr *attr, > + const struct rte_flow_item pattern[], > + const struct rte_flow_action actions[]); > + > #ifdef __cplusplus > } > #endif > diff --git a/lib/ethdev/rte_flow_snprint.c b/lib/ethdev/rte_flow_snprint.= c > new file mode 100644 index 0000000000..513886528b > --- /dev/null > +++ b/lib/ethdev/rte_flow_snprint.c > @@ -0,0 +1,1681 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * > + * Copyright(c) 2021 Xilinx, Inc. > + */ > + > +#include > +#include > +#include > + > +#include > +#include "rte_ethdev.h" > +#include "rte_flow.h" > + > +static int > +rte_flow_snprint_str(char *buf, size_t buf_size, size_t *nb_chars_total, > + const void *value_ptr) > +{ > + const char *str =3D value_ptr; > + size_t write_size_max; > + int retv; > + > + write_size_max =3D buf_size - RTE_MIN(buf_size, *nb_chars_total); > + retv =3D snprintf(buf + *nb_chars_total, write_size_max, " %s", str); > + if (retv < 0) > + return -EFAULT; > + > + *nb_chars_total +=3D retv; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_ether_addr(char *buf, size_t buf_size, size_t > *nb_chars_total, > + const void *value_ptr) > +{ > + const struct rte_ether_addr *ea =3D value_ptr; > + const uint8_t *ab =3D ea->addr_bytes; > + size_t write_size_max; > + int retv; > + > + write_size_max =3D buf_size - RTE_MIN(buf_size, *nb_chars_total); > + retv =3D snprintf(buf + *nb_chars_total, write_size_max, > + " %02x:%02x:%02x:%02x:%02x:%02x", > + ab[0], ab[1], ab[2], ab[3], ab[4], ab[5]); > + if (retv < 0) > + return -EFAULT; > + > + *nb_chars_total +=3D retv; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_ipv4_addr(char *buf, size_t buf_size, size_t > *nb_chars_total, > + const void *value_ptr) > +{ > + char addr_str[INET_ADDRSTRLEN]; > + > + if (inet_ntop(AF_INET, value_ptr, addr_str, sizeof(addr_str)) =3D=3D > NULL) > + return -EFAULT; > + > + return rte_flow_snprint_str(buf, buf_size, nb_chars_total, addr_str); > +} > + > +static int > +rte_flow_snprint_ipv6_addr(char *buf, size_t buf_size, size_t > *nb_chars_total, > + const void *value_ptr) > +{ > + char addr_str[INET6_ADDRSTRLEN]; > + > + if (inet_ntop(AF_INET6, value_ptr, addr_str, sizeof(addr_str)) =3D=3D > NULL) > + return -EFAULT; > + > + return rte_flow_snprint_str(buf, buf_size, nb_chars_total, addr_str); > +} > + > +#define SNPRINT(_type, _fmt) \ > + do { \ > + const _type *vp =3D value_ptr; \ > + size_t write_size_max; \ > + int retv; \ > + \ > + write_size_max =3D buf_size - \ > + RTE_MIN(buf_size, *nb_chars_total); \ > + retv =3D snprintf(buf + *nb_chars_total, write_size_max, > \ > + _fmt, *vp); \ > + if (retv < 0) \ > + return -EFAULT; > \ > + \ > + *nb_chars_total +=3D retv; \ > + \ > + return 0; \ > + } while (0) > + > +static int > +rte_flow_snprint_uint32(char *buf, size_t buf_size, size_t *nb_chars_tot= al, > + const void *value_ptr) > +{ > + SNPRINT(uint32_t, " %u"); > +} > + > +static int > +rte_flow_snprint_hex32(char *buf, size_t buf_size, size_t *nb_chars_tota= l, > + const void *value_ptr) > +{ > + SNPRINT(uint32_t, " 0x%08x"); > +} > + > +static int > +rte_flow_snprint_hex24(char *buf, size_t buf_size, size_t *nb_chars_tota= l, > + const void *value_ptr) > +{ > + SNPRINT(uint32_t, " 0x%06x"); > +} > + > +static int > +rte_flow_snprint_hex20(char *buf, size_t buf_size, size_t *nb_chars_tota= l, > + const void *value_ptr) > +{ > + SNPRINT(uint32_t, " 0x%05x"); > +} > + > +static int > +rte_flow_snprint_uint16(char *buf, size_t buf_size, size_t *nb_chars_tot= al, > + const void *value_ptr) > +{ > + SNPRINT(uint16_t, " %hu"); > +} > + > +static int > +rte_flow_snprint_uint16_be2cpu(char *buf, size_t buf_size, > + size_t *nb_chars_total, const void *value_ptr) { > + const uint16_t *valuep =3D value_ptr; > + uint16_t value =3D rte_be_to_cpu_16(*valuep); > + > + value_ptr =3D &value; > + > + SNPRINT(uint16_t, " %hu"); > +} > + > +static int > +rte_flow_snprint_hex16_be2cpu(char *buf, size_t buf_size, > + size_t *nb_chars_total, const void *value_ptr) { > + const uint16_t *valuep =3D value_ptr; > + uint16_t value =3D rte_be_to_cpu_16(*valuep); > + > + value_ptr =3D &value; > + > + SNPRINT(uint16_t, " 0x%04x"); > +} > + > +static int > +rte_flow_snprint_uint8(char *buf, size_t buf_size, size_t *nb_chars_tota= l, > + const void *value_ptr) > +{ > + SNPRINT(uint8_t, " %hhu"); > +} > + > +static int > +rte_flow_snprint_hex8(char *buf, size_t buf_size, size_t *nb_chars_total= , > + const void *value_ptr) > +{ > + SNPRINT(uint8_t, " 0x%02x"); > +} > + > +static int > +rte_flow_snprint_byte(char *buf, size_t buf_size, size_t *nb_chars_total= , > + const void *value_ptr) > +{ > + SNPRINT(uint8_t, "%02x"); > +} > + > +#undef SNPRINT > + > +static int > +rte_flow_snprint_attr(char *buf, size_t buf_size, size_t *nb_chars_total= , > + const struct rte_flow_attr *attr) { > + int rc; > + > + if (attr =3D=3D NULL) > + return 0; > + > + if (attr->group !=3D 0) { > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + "group"); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_uint32(buf, buf_size, nb_chars_total, > + &attr->group); > + if (rc !=3D 0) > + return rc; > + } > + > + if (attr->priority !=3D 0) { > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + "priority"); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_uint32(buf, buf_size, nb_chars_total, > + &attr->priority); > + if (rc !=3D 0) > + return rc; > + } > + > + if (attr->transfer) { > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + "transfer"); > + if (rc !=3D 0) > + return rc; > + } > + > + if (attr->ingress) { > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + "ingress"); > + if (rc !=3D 0) > + return rc; > + } > + > + if (attr->egress) { > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + "egress"); > + if (rc !=3D 0) > + return rc; > + } > + > + return 0; > +} > + > +static void > +rte_flow_item_init_parse(const struct rte_flow_item *item, size_t > item_size, > + void *spec, void *last, void *mask) { > + if (item->spec !=3D NULL) > + memcpy(spec, item->spec, item_size); > + else > + memset(spec, 0, item_size); > + > + if (item->last !=3D NULL) > + memcpy(last, item->last, item_size); > + else > + memset(last, 0, item_size); > + > + if (item->mask !=3D NULL) > + memcpy(mask, item->mask, item_size); > + else > + memset(mask, 0, item_size); > +} > + > +static bool > +rte_flow_buf_is_all_zeros(const void *buf_ptr, size_t buf_size) { > + const uint8_t *buf =3D buf_ptr; > + unsigned int i; > + uint8_t t =3D 0; > + > + for (i =3D 0; i < buf_size; ++i) > + t |=3D buf[i]; > + > + return (t =3D=3D 0); > +} > + > +static bool > +rte_flow_buf_is_all_ones(const void *buf_ptr, size_t buf_size) { > + const uint8_t *buf =3D buf_ptr; > + unsigned int i; > + uint8_t t =3D ~0; > + > + for (i =3D 0; i < buf_size; ++i) > + t &=3D buf[i]; > + > + return (t =3D=3D (uint8_t)(~0)); > +} > + > +static int > +rte_flow_snprint_item_field(char *buf, size_t buf_size, size_t > *nb_chars_total, > + int (*value_dump_cb)(char *, size_t, size_t *, > + const void *), > + int (*mask_dump_cb)(char *, size_t, size_t *, > + const void *), > + const char *field_name, size_t field_size, > + void *field_spec, void *field_last, > + void *field_mask, void *field_full_mask) { > + bool mask_is_all_ones; > + bool last_is_futile; > + int rc; > + > + if (rte_flow_buf_is_all_zeros(field_mask, field_size)) > + return 0; > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > field_name); > + if (rc !=3D 0) > + return rc; > + > + if (field_full_mask !=3D NULL) { > + mask_is_all_ones =3D (memcmp(field_mask, field_full_mask, > + field_size) =3D=3D 0); > + } else { > + mask_is_all_ones =3D rte_flow_buf_is_all_ones(field_mask, > + field_size); > + } > + last_is_futile =3D rte_flow_buf_is_all_zeros(field_last, field_size) || > + (memcmp(field_spec, field_last, field_size) =3D=3D 0); > + > + if (mask_is_all_ones && last_is_futile) { > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "is"); > + if (rc !=3D 0) > + return rc; > + > + rc =3D value_dump_cb(buf, buf_size, nb_chars_total, > field_spec); > + if (rc !=3D 0) > + return rc; > + > + goto done; > + } > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "spec"); > + if (rc !=3D 0) > + return rc; > + > + rc =3D value_dump_cb(buf, buf_size, nb_chars_total, field_spec); > + if (rc !=3D 0) > + return rc; > + > + if (!last_is_futile) { > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + field_name); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + "last"); > + if (rc !=3D 0) > + return rc; > + > + rc =3D value_dump_cb(buf, buf_size, nb_chars_total, > field_last); > + if (rc !=3D 0) > + return rc; > + } > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > field_name); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "mask"); > + if (rc !=3D 0) > + return rc; > + > + rc =3D mask_dump_cb(buf, buf_size, nb_chars_total, field_mask); > + if (rc !=3D 0) > + return rc; > + > +done: > + /* > + * Zeroise the printed field. When all item fields have been printed, > + * the corresponding item handler will make sure that the whole item > + * mask is all-zeros. This is needed to highlight unsupported fields. > + * > + * If the provided field mask pointer refers to a separate container > + * rather than to the field in the item mask directly, it's the duty > + * of the item handler to clear the field in the item mask correctly. > + */ > + memset(field_mask, 0, field_size); > + > + return 0; > +} > + > +static int > +rte_flow_snprint_item_vf(char *buf, size_t buf_size, size_t > *nb_chars_total, > + void *spec_ptr, void *last_ptr, void *mask_ptr) { > + struct rte_flow_item_vf *spec =3D spec_ptr; > + struct rte_flow_item_vf *last =3D last_ptr; > + struct rte_flow_item_vf *mask =3D mask_ptr; > + int rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint32, > + rte_flow_snprint_hex32, "id", > + sizeof(spec->id), &spec->id, &last- > >id, > + &mask->id, NULL); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_item_phy_port(char *buf, size_t buf_size, > + size_t *nb_chars_total, void *spec_ptr, > + void *last_ptr, void *mask_ptr) { > + struct rte_flow_item_phy_port *spec =3D spec_ptr; > + struct rte_flow_item_phy_port *last =3D last_ptr; > + struct rte_flow_item_phy_port *mask =3D mask_ptr; > + int rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint32, > + rte_flow_snprint_hex32, "index", > + sizeof(spec->index), &spec->index, > + &last->index, &mask->index, NULL); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_item_port_id(char *buf, size_t buf_size, > + size_t *nb_chars_total, void *spec_ptr, > + void *last_ptr, void *mask_ptr) { > + struct rte_flow_item_port_id *spec =3D spec_ptr; > + struct rte_flow_item_port_id *last =3D last_ptr; > + struct rte_flow_item_port_id *mask =3D mask_ptr; > + int rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint32, > + rte_flow_snprint_hex32, "id", > + sizeof(spec->id), &spec->id, &last- > >id, > + &mask->id, NULL); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_item_eth(char *buf, size_t buf_size, size_t > *nb_chars_total, > + void *spec_ptr, void *last_ptr, void *mask_ptr) { > + struct rte_flow_item_eth *spec =3D spec_ptr; > + struct rte_flow_item_eth *last =3D last_ptr; > + struct rte_flow_item_eth *mask =3D mask_ptr; > + uint8_t has_vlan_full_mask =3D 1; > + uint8_t has_vlan_spec; > + uint8_t has_vlan_last; > + uint8_t has_vlan_mask; > + int rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_ether_addr, > + rte_flow_snprint_ether_addr, "dst", > + sizeof(spec->hdr.d_addr), > + &spec->hdr.d_addr, &last- > >hdr.d_addr, > + &mask->hdr.d_addr, NULL); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_ether_addr, > + rte_flow_snprint_ether_addr, "src", > + sizeof(spec->hdr.s_addr), > + &spec->hdr.s_addr, &last- > >hdr.s_addr, > + &mask->hdr.s_addr, NULL); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_hex16_be2cpu, > + rte_flow_snprint_hex16_be2cpu, > "type", > + sizeof(spec->hdr.ether_type), > + &spec->hdr.ether_type, > + &last->hdr.ether_type, > + &mask->hdr.ether_type, NULL); > + if (rc !=3D 0) > + return rc; > + > + has_vlan_spec =3D spec->has_vlan; > + has_vlan_last =3D last->has_vlan; > + has_vlan_mask =3D mask->has_vlan; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint8, > + rte_flow_snprint_uint8, "has_vlan", > + sizeof(has_vlan_spec), > &has_vlan_spec, > + &has_vlan_last, &has_vlan_mask, > + &has_vlan_full_mask); > + if (rc !=3D 0) > + return rc; > + > + mask->has_vlan =3D 0; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_item_vlan(char *buf, size_t buf_size, size_t > *nb_chars_total, > + void *spec_ptr, void *last_ptr, void *mask_ptr) { > + struct rte_flow_item_vlan *spec =3D spec_ptr; > + struct rte_flow_item_vlan *last =3D last_ptr; > + struct rte_flow_item_vlan *mask =3D mask_ptr; > + uint8_t has_more_vlan_full_mask =3D 1; > + uint8_t has_more_vlan_spec; > + uint8_t has_more_vlan_last; > + uint8_t has_more_vlan_mask; > + int rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint16_be2cpu, > + rte_flow_snprint_hex16_be2cpu, > "tci", > + sizeof(spec->hdr.vlan_tci), > + &spec->hdr.vlan_tci, > + &last->hdr.vlan_tci, > + &mask->hdr.vlan_tci, NULL); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_hex16_be2cpu, > + rte_flow_snprint_hex16_be2cpu, > + "inner_type", > + sizeof(spec->hdr.eth_proto), > + &spec->hdr.eth_proto, > + &last->hdr.eth_proto, > + &mask->hdr.eth_proto, NULL); > + if (rc !=3D 0) > + return rc; > + > + has_more_vlan_spec =3D spec->has_more_vlan; > + has_more_vlan_last =3D last->has_more_vlan; > + has_more_vlan_mask =3D mask->has_more_vlan; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint8, > + rte_flow_snprint_uint8, > + "has_more_vlan", > + sizeof(has_more_vlan_spec), > + &has_more_vlan_spec, > + &has_more_vlan_last, > + &has_more_vlan_mask, > + &has_more_vlan_full_mask); > + if (rc !=3D 0) > + return rc; > + > + mask->has_more_vlan =3D 0; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_item_ipv4(char *buf, size_t buf_size, size_t > *nb_chars_total, > + void *spec_ptr, void *last_ptr, void *mask_ptr) { > + struct rte_flow_item_ipv4 *spec =3D spec_ptr; > + struct rte_flow_item_ipv4 *last =3D last_ptr; > + struct rte_flow_item_ipv4 *mask =3D mask_ptr; > + int rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_hex8, > + rte_flow_snprint_hex8, "tos", > + sizeof(spec->hdr.type_of_service), > + &spec->hdr.type_of_service, > + &last->hdr.type_of_service, > + &mask->hdr.type_of_service, > NULL); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint16_be2cpu, > + rte_flow_snprint_hex16_be2cpu, > + "packet_id", > + sizeof(spec->hdr.packet_id), > + &spec->hdr.packet_id, > + &last->hdr.packet_id, > + &mask->hdr.packet_id, NULL); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint16_be2cpu, > + rte_flow_snprint_hex16_be2cpu, > + "fragment_offset", > + sizeof(spec->hdr.fragment_offset), > + &spec->hdr.fragment_offset, > + &last->hdr.fragment_offset, > + &mask->hdr.fragment_offset, > NULL); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint8, > + rte_flow_snprint_hex8, "ttl", > + sizeof(spec->hdr.time_to_live), > + &spec->hdr.time_to_live, > + &last->hdr.time_to_live, > + &mask->hdr.time_to_live, NULL); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint8, > + rte_flow_snprint_hex8, "proto", > + sizeof(spec->hdr.next_proto_id), > + &spec->hdr.next_proto_id, > + &last->hdr.next_proto_id, > + &mask->hdr.next_proto_id, NULL); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_ipv4_addr, > + rte_flow_snprint_ipv4_addr, "src", > + sizeof(spec->hdr.src_addr), > + &spec->hdr.src_addr, > + &last->hdr.src_addr, > + &mask->hdr.src_addr, NULL); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_ipv4_addr, > + rte_flow_snprint_ipv4_addr, "dst", > + sizeof(spec->hdr.dst_addr), > + &spec->hdr.dst_addr, > + &last->hdr.dst_addr, > + &mask->hdr.dst_addr, NULL); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_item_ipv6(char *buf, size_t buf_size, size_t > *nb_chars_total, > + void *spec_ptr, void *last_ptr, void *mask_ptr) { > + uint32_t tc_full_mask =3D (RTE_IPV6_HDR_TC_MASK >> > RTE_IPV6_HDR_TC_SHIFT); > + uint32_t fl_full_mask =3D (RTE_IPV6_HDR_FL_MASK >> > RTE_IPV6_HDR_FL_SHIFT); > + struct rte_flow_item_ipv6 *spec =3D spec_ptr; > + struct rte_flow_item_ipv6 *last =3D last_ptr; > + struct rte_flow_item_ipv6 *mask =3D mask_ptr; > + uint8_t has_frag_ext_full_mask =3D 1; > + uint8_t has_frag_ext_spec; > + uint8_t has_frag_ext_last; > + uint8_t has_frag_ext_mask; > + uint32_t vtc_flow; > + uint32_t fl_spec; > + uint32_t fl_last; > + uint32_t fl_mask; > + uint32_t tc_spec; > + uint32_t tc_last; > + uint32_t tc_mask; > + int rc; > + > + vtc_flow =3D rte_be_to_cpu_32(spec->hdr.vtc_flow); > + tc_spec =3D (vtc_flow & RTE_IPV6_HDR_TC_MASK) >> > RTE_IPV6_HDR_TC_SHIFT; > + fl_spec =3D (vtc_flow & RTE_IPV6_HDR_FL_MASK) >> > RTE_IPV6_HDR_FL_SHIFT; > + > + vtc_flow =3D rte_be_to_cpu_32(last->hdr.vtc_flow); > + tc_last =3D (vtc_flow & RTE_IPV6_HDR_TC_MASK) >> > RTE_IPV6_HDR_TC_SHIFT; > + fl_last =3D (vtc_flow & RTE_IPV6_HDR_FL_MASK) >> > RTE_IPV6_HDR_FL_SHIFT; > + > + vtc_flow =3D rte_be_to_cpu_32(mask->hdr.vtc_flow); > + tc_mask =3D (vtc_flow & RTE_IPV6_HDR_TC_MASK) >> > RTE_IPV6_HDR_TC_SHIFT; > + fl_mask =3D (vtc_flow & RTE_IPV6_HDR_FL_MASK) >> > RTE_IPV6_HDR_FL_SHIFT; > + > + mask->hdr.vtc_flow &=3D > ~rte_cpu_to_be_32(RTE_IPV6_HDR_TC_MASK | > + RTE_IPV6_HDR_FL_MASK); > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_hex8, > + rte_flow_snprint_hex8, "tc", > + sizeof(tc_spec), &tc_spec, &tc_last, > + &tc_mask, &tc_full_mask); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint32, > + rte_flow_snprint_hex20, "flow", > + sizeof(fl_spec), &fl_spec, &fl_last, > + &fl_mask, &fl_full_mask); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint8, > + rte_flow_snprint_hex8, "proto", > + sizeof(spec->hdr.proto), > + &spec->hdr.proto, > + &last->hdr.proto, > + &mask->hdr.proto, NULL); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint8, > + rte_flow_snprint_hex8, "hop", > + sizeof(spec->hdr.hop_limits), > + &spec->hdr.hop_limits, > + &last->hdr.hop_limits, > + &mask->hdr.hop_limits, NULL); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_ipv6_addr, > + rte_flow_snprint_ipv6_addr, "src", > + sizeof(spec->hdr.src_addr), > + &spec->hdr.src_addr, > + &last->hdr.src_addr, > + &mask->hdr.src_addr, NULL); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_ipv6_addr, > + rte_flow_snprint_ipv6_addr, "dst", > + sizeof(spec->hdr.dst_addr), > + &spec->hdr.dst_addr, > + &last->hdr.dst_addr, > + &mask->hdr.dst_addr, NULL); > + > + has_frag_ext_spec =3D spec->has_frag_ext; > + has_frag_ext_last =3D last->has_frag_ext; > + has_frag_ext_mask =3D mask->has_frag_ext; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint8, > + rte_flow_snprint_uint8, > "has_frag_ext", > + sizeof(has_frag_ext_spec), > + &has_frag_ext_spec, > &has_frag_ext_last, > + &has_frag_ext_mask, > + &has_frag_ext_full_mask); > + if (rc !=3D 0) > + return rc; > + > + mask->has_frag_ext =3D 0; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_item_udp(char *buf, size_t buf_size, size_t > *nb_chars_total, > + void *spec_ptr, void *last_ptr, void *mask_ptr) { > + struct rte_flow_item_udp *spec =3D spec_ptr; > + struct rte_flow_item_udp *last =3D last_ptr; > + struct rte_flow_item_udp *mask =3D mask_ptr; > + int rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint16_be2cpu, > + rte_flow_snprint_hex16_be2cpu, > "src", > + sizeof(spec->hdr.src_port), > + &spec->hdr.src_port, > + &last->hdr.src_port, > + &mask->hdr.src_port, NULL); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint16_be2cpu, > + rte_flow_snprint_hex16_be2cpu, > "dst", > + sizeof(spec->hdr.dst_port), > + &spec->hdr.dst_port, > + &last->hdr.dst_port, > + &mask->hdr.dst_port, NULL); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_item_tcp(char *buf, size_t buf_size, size_t > *nb_chars_total, > + void *spec_ptr, void *last_ptr, void *mask_ptr) { > + struct rte_flow_item_tcp *spec =3D spec_ptr; > + struct rte_flow_item_tcp *last =3D last_ptr; > + struct rte_flow_item_tcp *mask =3D mask_ptr; > + int rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint16_be2cpu, > + rte_flow_snprint_hex16_be2cpu, > "src", > + sizeof(spec->hdr.src_port), > + &spec->hdr.src_port, > + &last->hdr.src_port, > + &mask->hdr.src_port, NULL); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint16_be2cpu, > + rte_flow_snprint_hex16_be2cpu, > "dst", > + sizeof(spec->hdr.dst_port), > + &spec->hdr.dst_port, > + &last->hdr.dst_port, > + &mask->hdr.dst_port, NULL); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_hex8, > + rte_flow_snprint_hex8, "flags", > + sizeof(spec->hdr.tcp_flags), > + &spec->hdr.tcp_flags, > + &last->hdr.tcp_flags, > + &mask->hdr.tcp_flags, NULL); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_item_vxlan(char *buf, size_t buf_size, size_t > *nb_chars_total, > + void *spec_ptr, void *last_ptr, void *mask_ptr) { > + struct rte_flow_item_vxlan *spec =3D spec_ptr; > + struct rte_flow_item_vxlan *last =3D last_ptr; > + struct rte_flow_item_vxlan *mask =3D mask_ptr; > + uint32_t vni_full_mask =3D 0xffffff; > + uint32_t vni_spec; > + uint32_t vni_last; > + uint32_t vni_mask; > + int rc; > + > + vni_spec =3D rte_be_to_cpu_32(spec->hdr.vx_vni) >> 8; > + vni_last =3D rte_be_to_cpu_32(last->hdr.vx_vni) >> 8; > + vni_mask =3D rte_be_to_cpu_32(mask->hdr.vx_vni) >> 8; > + > + mask->hdr.vx_vni &=3D ~RTE_BE32(0xffffff00); > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint32, > + rte_flow_snprint_hex24, "vni", > + sizeof(vni_spec), &vni_spec, > + &vni_last, &vni_mask, > + &vni_full_mask); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_item_nvgre(char *buf, size_t buf_size, size_t > *nb_chars_total, > + void *spec_ptr, void *last_ptr, void *mask_ptr) { > + struct rte_flow_item_nvgre *spec =3D spec_ptr; > + struct rte_flow_item_nvgre *last =3D last_ptr; > + struct rte_flow_item_nvgre *mask =3D mask_ptr; > + uint32_t *tni_and_flow_id_specp =3D (uint32_t *)spec->tni; > + uint32_t *tni_and_flow_id_lastp =3D (uint32_t *)last->tni; > + uint32_t *tni_and_flow_id_maskp =3D (uint32_t *)mask->tni; > + uint32_t tni_full_mask =3D 0xffffff; > + uint32_t tni_spec; > + uint32_t tni_last; > + uint32_t tni_mask; > + int rc; > + > + tni_spec =3D rte_be_to_cpu_32(*tni_and_flow_id_specp) >> 8; > + tni_last =3D rte_be_to_cpu_32(*tni_and_flow_id_lastp) >> 8; > + tni_mask =3D rte_be_to_cpu_32(*tni_and_flow_id_maskp) >> 8; > + > + memset(mask->tni, 0, sizeof(mask->tni)); > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint32, > + rte_flow_snprint_hex24, "tni", > + sizeof(tni_spec), &tni_spec, > + &tni_last, &tni_mask, > + &tni_full_mask); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_item_geneve(char *buf, size_t buf_size, size_t > *nb_chars_total, > + void *spec_ptr, void *last_ptr, void *mask_ptr) { > + struct rte_flow_item_geneve *spec =3D spec_ptr; > + struct rte_flow_item_geneve *last =3D last_ptr; > + struct rte_flow_item_geneve *mask =3D mask_ptr; > + uint32_t *vni_and_rsvd_specp =3D (uint32_t *)spec->vni; > + uint32_t *vni_and_rsvd_lastp =3D (uint32_t *)last->vni; > + uint32_t *vni_and_rsvd_maskp =3D (uint32_t *)mask->vni; > + uint32_t vni_full_mask =3D 0xffffff; > + uint16_t optlen_full_mask =3D 0x3f; > + uint16_t optlen_spec; > + uint16_t optlen_last; > + uint16_t optlen_mask; > + uint32_t vni_spec; > + uint32_t vni_last; > + uint32_t vni_mask; > + int rc; > + > + optlen_spec =3D rte_be_to_cpu_16(spec->ver_opt_len_o_c_rsvd0) & > 0x3f00; > + optlen_spec >>=3D 8; > + > + optlen_last =3D rte_be_to_cpu_16(last->ver_opt_len_o_c_rsvd0) & > 0x3f00; > + optlen_last >>=3D 8; > + > + optlen_mask =3D rte_be_to_cpu_16(mask->ver_opt_len_o_c_rsvd0) > & 0x3f00; > + optlen_mask >>=3D 8; > + > + mask->ver_opt_len_o_c_rsvd0 &=3D ~RTE_BE16(0x3f00); > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint16, > + rte_flow_snprint_hex8, "optlen", > + sizeof(optlen_spec), &optlen_spec, > + &optlen_last, &optlen_mask, > + &optlen_full_mask); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_hex16_be2cpu, > + rte_flow_snprint_hex16_be2cpu, > + "protocol", sizeof(spec->protocol), > + &spec->protocol, &last->protocol, > + &mask->protocol, NULL); > + if (rc !=3D 0) > + return rc; > + > + vni_spec =3D rte_be_to_cpu_32(*vni_and_rsvd_specp) >> 8; > + vni_last =3D rte_be_to_cpu_32(*vni_and_rsvd_lastp) >> 8; > + vni_mask =3D rte_be_to_cpu_32(*vni_and_rsvd_maskp) >> 8; > + > + memset(mask->vni, 0, sizeof(mask->vni)); > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint32, > + rte_flow_snprint_hex24, "vni", > + sizeof(vni_spec), &vni_spec, > + &vni_last, &vni_mask, > + &vni_full_mask); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_item_mark(char *buf, size_t buf_size, size_t > *nb_chars_total, > + void *spec_ptr, void *last_ptr, void *mask_ptr) { > + struct rte_flow_item_mark *spec =3D spec_ptr; > + struct rte_flow_item_mark *last =3D last_ptr; > + struct rte_flow_item_mark *mask =3D mask_ptr; > + int rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint32, > + rte_flow_snprint_hex32, "id", > + sizeof(spec->id), &spec->id, > + &last->id, &mask->id, NULL); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_item_pppoed(char *buf, size_t buf_size, size_t > *nb_chars_total, > + void *spec_ptr, void *last_ptr, void *mask_ptr) { > + struct rte_flow_item_pppoe *spec =3D spec_ptr; > + struct rte_flow_item_pppoe *last =3D last_ptr; > + struct rte_flow_item_pppoe *mask =3D mask_ptr; > + int rc; > + > + rc =3D rte_flow_snprint_item_field(buf, buf_size, nb_chars_total, > + rte_flow_snprint_uint16_be2cpu, > + rte_flow_snprint_hex16_be2cpu, > + "seid", sizeof(spec->session_id), > + &spec->session_id, &last- > >session_id, > + &mask->session_id, NULL); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static const struct { > + const char *name; > + int (*parse_cb)(char *buf, size_t buf_size, size_t *nb_char_total, > + void *spec_ptr, void *last_ptr, void *mask_ptr); > + size_t size; > +} item_table[] =3D { > + [RTE_FLOW_ITEM_TYPE_VOID] =3D { > + .name =3D "void" > + }, > + [RTE_FLOW_ITEM_TYPE_PF] =3D { > + .name =3D "pf" > + }, > + [RTE_FLOW_ITEM_TYPE_PPPOES] =3D { > + .name =3D "pppoes" > + }, > + [RTE_FLOW_ITEM_TYPE_PPPOED] =3D { > + .name =3D "pppoed", > + .parse_cb =3D rte_flow_snprint_item_pppoed, > + .size =3D sizeof(struct rte_flow_item_pppoe) > + }, > + > +#define ITEM(_name_uppercase, _name_lowercase) \ > + [RTE_FLOW_ITEM_TYPE_##_name_uppercase] =3D { > \ > + .name =3D #_name_lowercase, \ > + .parse_cb =3D rte_flow_snprint_item_##_name_lowercase, > \ > + .size =3D sizeof(struct rte_flow_item_##_name_lowercase) > \ > + } > + > + ITEM(VF, vf), > + ITEM(PHY_PORT, phy_port), > + ITEM(PORT_ID, port_id), > + ITEM(ETH, eth), > + ITEM(VLAN, vlan), > + ITEM(IPV4, ipv4), > + ITEM(IPV6, ipv6), > + ITEM(UDP, udp), > + ITEM(TCP, tcp), > + ITEM(VXLAN, vxlan), > + ITEM(NVGRE, nvgre), > + ITEM(GENEVE, geneve), > + ITEM(MARK, mark), > + > +#undef ITEM > +}; > + > +static int > +rte_flow_snprint_item(char *buf, size_t buf_size, size_t *nb_chars_total= , > + const struct rte_flow_item *item) { > + int rc; > + > + if (item->type < 0 || item->type >=3D RTE_DIM(item_table) || > + item_table[item->type].name =3D=3D NULL) { > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + "{unknown}"); > + if (rc !=3D 0) > + return rc; > + > + goto out; > + } > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + item_table[item->type].name); > + if (rc !=3D 0) > + return rc; > + > + if (item_table[item->type].parse_cb !=3D NULL) { > + size_t item_size =3D item_table[item->type].size; > + uint8_t spec[item_size]; > + uint8_t last[item_size]; > + uint8_t mask[item_size]; > + > + rte_flow_item_init_parse(item, item_size, spec, last, mask); > + > + rc =3D item_table[item->type].parse_cb(buf, buf_size, > + nb_chars_total, > + spec, last, mask); > + if (rc !=3D 0) > + return rc; > + > + if (!rte_flow_buf_is_all_zeros(mask, item_size)) { > + rc =3D rte_flow_snprint_str(buf, buf_size, > + nb_chars_total, > + "{unknown bits}"); > + if (rc !=3D 0) > + return rc; > + } > + } > + > +out: > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "/"); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_pattern(char *buf, size_t buf_size, size_t > *nb_chars_total, > + const struct rte_flow_item pattern[]) { > + const struct rte_flow_item *item; > + int rc; > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "pattern"); > + if (rc !=3D 0) > + return rc; > + > + if (pattern =3D=3D NULL) > + goto end; > + > + for (item =3D pattern; > + item->type !=3D RTE_FLOW_ITEM_TYPE_END; ++item) { > + rc =3D rte_flow_snprint_item(buf, buf_size, nb_chars_total, > item); > + if (rc !=3D 0) > + return rc; > + } > + > +end: > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "end"); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_action_jump(char *buf, size_t buf_size, size_t > *nb_chars_total, > + const void *conf_ptr) > +{ > + const struct rte_flow_action_jump *conf =3D conf_ptr; > + int rc; > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "group"); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_uint32(buf, buf_size, nb_chars_total, > + &conf->group); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_action_mark(char *buf, size_t buf_size, size_t > *nb_chars_total, > + const void *conf_ptr) > +{ > + const struct rte_flow_action_mark *conf =3D conf_ptr; > + int rc; > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "id"); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_uint32(buf, buf_size, nb_chars_total, &conf- > >id); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_action_queue(char *buf, size_t buf_size, > + size_t *nb_chars_total, const void *conf_ptr) { > + const struct rte_flow_action_queue *conf =3D conf_ptr; > + int rc; > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "index"); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_uint16(buf, buf_size, nb_chars_total, > + &conf->index); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_action_count(char *buf, size_t buf_size, > + size_t *nb_chars_total, const void *conf_ptr) { > + const struct rte_flow_action_count *conf =3D conf_ptr; > + int rc; > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "identifier"= ); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_uint32(buf, buf_size, nb_chars_total, &conf- > >id); > + if (rc !=3D 0) > + return rc; > + > + if (conf->shared) { > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + "shared"); > + if (rc !=3D 0) > + return rc; > + } > + > + return 0; > +} > + > +static int > +rte_flow_snprint_action_rss_func(char *buf, size_t buf_size, > + size_t *nb_chars_total, > + enum rte_eth_hash_function func) > +{ > + int rc; > + > + if (func =3D=3D RTE_ETH_HASH_FUNCTION_DEFAULT) > + return 0; > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "func"); > + if (rc !=3D 0) > + return rc; > + > + switch (func) { > + case RTE_ETH_HASH_FUNCTION_TOEPLITZ: > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + "toeplitz"); > + break; > + case RTE_ETH_HASH_FUNCTION_SIMPLE_XOR: > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + "simple_xor"); > + break; > + case RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ: > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + "symmetric_toeplitz"); > + break; > + default: > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + "{unknown}"); > + break; > + } > + > + return rc; > +} > + > +static int > +rte_flow_snprint_action_rss_level(char *buf, size_t buf_size, > + size_t *nb_chars_total, uint32_t level) { > + int rc; > + > + if (level =3D=3D 0) > + return 0; > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "level"); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_uint32(buf, buf_size, nb_chars_total, &level); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static const struct { > + const char *name; > + uint64_t flag; > +} rss_type_table[] =3D { > + { "ipv4", ETH_RSS_IPV4 }, > + { "ipv4-frag", ETH_RSS_FRAG_IPV4 }, > + { "ipv4-tcp", ETH_RSS_NONFRAG_IPV4_TCP }, > + { "ipv4-udp", ETH_RSS_NONFRAG_IPV4_UDP }, > + { "ipv4-other", ETH_RSS_NONFRAG_IPV4_OTHER }, > + { "ipv6", ETH_RSS_IPV6 }, > + { "ipv6-frag", ETH_RSS_FRAG_IPV6 }, > + { "ipv6-tcp", ETH_RSS_NONFRAG_IPV6_TCP }, > + { "ipv6-udp", ETH_RSS_NONFRAG_IPV6_UDP }, > + { "ipv6-other", ETH_RSS_NONFRAG_IPV6_OTHER }, > + { "ipv6-ex", ETH_RSS_IPV6_EX }, > + { "ipv6-tcp-ex", ETH_RSS_IPV6_TCP_EX }, > + { "ipv6-udp-ex", ETH_RSS_IPV6_UDP_EX }, > + > + { "l3-src-only", ETH_RSS_L3_SRC_ONLY }, > + { "l3-dst-only", ETH_RSS_L3_DST_ONLY }, > + { "l4-src-only", ETH_RSS_L4_SRC_ONLY }, > + { "l4-dst-only", ETH_RSS_L4_DST_ONLY }, }; > + > +static int > +rte_flow_snprint_action_rss_types(char *buf, size_t buf_size, > + size_t *nb_chars_total, uint64_t types) { > + unsigned int i; > + int rc; > + > + if (types =3D=3D 0) > + return 0; > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "types"); > + if (rc !=3D 0) > + return rc; > + > + for (i =3D 0; i < RTE_DIM(rss_type_table); ++i) { > + uint64_t flag =3D rss_type_table[i].flag; > + > + if ((types & flag) =3D=3D 0) > + continue; > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + rss_type_table[i].name); > + if (rc !=3D 0) > + return rc; > + > + types &=3D ~flag; > + } > + > + if (types !=3D 0) { > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + "{unknown}"); > + if (rc !=3D 0) > + return rc; > + } > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "end"); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_action_rss_queues(char *buf, size_t buf_size, > + size_t *nb_chars_total, > + const uint16_t *queues, > + unsigned int nb_queues) > +{ > + unsigned int i; > + int rc; > + > + if (nb_queues =3D=3D 0) > + return 0; > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "queues"); > + if (rc !=3D 0) > + return rc; > + > + for (i =3D 0; i < nb_queues; ++i) { > + rc =3D rte_flow_snprint_uint16(buf, buf_size, nb_chars_total, > + &queues[i]); > + if (rc !=3D 0) > + return rc; > + } > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "end"); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_action_rss(char *buf, size_t buf_size, size_t > *nb_chars_total, > + const void *conf_ptr) > +{ > + const struct rte_flow_action_rss *conf =3D conf_ptr; > + int rc; > + > + rc =3D rte_flow_snprint_action_rss_func(buf, buf_size, nb_chars_total, > + conf->func); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_action_rss_level(buf, buf_size, > nb_chars_total, > + conf->level); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_action_rss_types(buf, buf_size, > nb_chars_total, > + conf->types); > + if (rc !=3D 0) > + return rc; > + > + if (conf->key_len !=3D 0) { > + if (conf->key !=3D NULL) { > + unsigned int i; > + > + rc =3D rte_flow_snprint_str(buf, buf_size, > nb_chars_total, > + "" /* results in space */); > + if (rc !=3D 0) > + return rc; > + > + for (i =3D 0; i < conf->key_len; ++i) { > + rc =3D rte_flow_snprint_byte(buf, buf_size, > + nb_chars_total, > + &conf->key[i]); > + if (rc !=3D 0) > + return rc; > + } > + } > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + "key_len"); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_uint32(buf, buf_size, nb_chars_total, > + &conf->key_len); > + if (rc !=3D 0) > + return rc; > + } > + > + rc =3D rte_flow_snprint_action_rss_queues(buf, buf_size, > nb_chars_total, > + conf->queue, conf- > >queue_num); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_action_vf(char *buf, size_t buf_size, size_t > *nb_chars_total, > + const void *conf_ptr) > +{ > + const struct rte_flow_action_vf *conf =3D conf_ptr; > + int rc; > + > + if (conf->original) { > + return rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + "original on"); > + } > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "id"); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_uint32(buf, buf_size, nb_chars_total, &conf- > >id); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_action_phy_port(char *buf, size_t buf_size, > + size_t *nb_chars_total, const void > *conf_ptr) { > + const struct rte_flow_action_phy_port *conf =3D conf_ptr; > + int rc; > + > + if (conf->original) { > + return rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + "original on"); > + } > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "index"); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_uint32(buf, buf_size, nb_chars_total, > + &conf->index); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_action_port_id(char *buf, size_t buf_size, > + size_t *nb_chars_total, const void *conf_ptr) > { > + const struct rte_flow_action_port_id *conf =3D conf_ptr; > + int rc; > + > + if (conf->original) { > + return rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + "original on"); > + } > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "id"); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_uint32(buf, buf_size, nb_chars_total, &conf- > >id); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_action_of_push_vlan(char *buf, size_t buf_size, > + size_t *nb_chars_total, > + const void *conf_ptr) > +{ > + const struct rte_flow_action_of_push_vlan *conf =3D conf_ptr; > + int rc; > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > "ethertype"); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_hex16_be2cpu(buf, buf_size, nb_chars_total, > + &conf->ethertype); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_action_of_set_vlan_vid(char *buf, size_t buf_size, > + size_t *nb_chars_total, > + const void *conf_ptr) > +{ > + const struct rte_flow_action_of_set_vlan_vid *conf =3D conf_ptr; > + int rc; > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "vlan_vid"); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_uint16_be2cpu(buf, buf_size, nb_chars_total, > + &conf->vlan_vid); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_action_of_set_vlan_pcp(char *buf, size_t buf_size, > + size_t *nb_chars_total, > + const void *conf_ptr) > +{ > + const struct rte_flow_action_of_set_vlan_pcp *conf =3D conf_ptr; > + int rc; > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "vlan_pcp"); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_uint8(buf, buf_size, nb_chars_total, > + &conf->vlan_pcp); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static const struct { > + const char *name; > + int (*parse_cb)(char *buf, size_t buf_size, size_t *nb_chars_total, > + const void *conf_ptr); > +} action_table[] =3D { > + [RTE_FLOW_ACTION_TYPE_VOID] =3D { > + .name =3D "void" > + }, > + [RTE_FLOW_ACTION_TYPE_FLAG] =3D { > + .name =3D "flag" > + }, > + [RTE_FLOW_ACTION_TYPE_DROP] =3D { > + .name =3D "drop" > + }, > + [RTE_FLOW_ACTION_TYPE_PF] =3D { > + .name =3D "pf" > + }, > + [RTE_FLOW_ACTION_TYPE_OF_POP_VLAN] =3D { > + .name =3D "of_pop_vlan" > + }, > + [RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP] =3D { > + .name =3D "vxlan_encap" > + }, > + [RTE_FLOW_ACTION_TYPE_VXLAN_DECAP] =3D { > + .name =3D "vxlan_decap" > + }, > + > +#define ACTION(_name_uppercase, _name_lowercase) \ > + [RTE_FLOW_ACTION_TYPE_##_name_uppercase] =3D { > \ > + .name =3D #_name_lowercase, \ > + .parse_cb =3D rte_flow_snprint_action_##_name_lowercase, > \ > + } > + > + ACTION(JUMP, jump), > + ACTION(MARK, mark), > + ACTION(QUEUE, queue), > + ACTION(COUNT, count), > + ACTION(RSS, rss), > + ACTION(VF, vf), > + ACTION(PHY_PORT, phy_port), > + ACTION(PORT_ID, port_id), > + ACTION(OF_PUSH_VLAN, of_push_vlan), > + ACTION(OF_SET_VLAN_VID, of_set_vlan_vid), > + ACTION(OF_SET_VLAN_PCP, of_set_vlan_pcp), > + > +#undef ACTION > +}; > + > +static int > +rte_flow_snprint_action(char *buf, size_t buf_size, size_t *nb_chars_tot= al, > + const struct rte_flow_action *action) { > + int rc; > + > + if (action->type < 0 || action->type >=3D RTE_DIM(action_table) || > + action_table[action->type].name =3D=3D NULL) { > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + "{unknown}"); > + if (rc !=3D 0) > + return rc; > + > + goto out; > + } > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, > + action_table[action->type].name); > + if (rc !=3D 0) > + return rc; > + > + if (action_table[action->type].parse_cb !=3D NULL && > + action->conf !=3D NULL) { > + rc =3D action_table[action->type].parse_cb(buf, buf_size, > + nb_chars_total, > + action->conf); > + if (rc !=3D 0) > + return rc; > + } > + > +out: > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "/"); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +static int > +rte_flow_snprint_actions(char *buf, size_t buf_size, size_t > *nb_chars_total, > + const struct rte_flow_action actions[]) { > + const struct rte_flow_action *action; > + int rc; > + > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "actions"); > + if (rc !=3D 0) > + return rc; > + > + if (actions =3D=3D NULL) > + goto end; > + > + for (action =3D actions; > + action->type !=3D RTE_FLOW_ACTION_TYPE_END; ++action) { > + rc =3D rte_flow_snprint_action(buf, buf_size, nb_chars_total, > + action); > + if (rc !=3D 0) > + return rc; > + } > + > +end: > + rc =3D rte_flow_snprint_str(buf, buf_size, nb_chars_total, "end"); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > + > +int > +rte_flow_snprint(char *buf, size_t buf_size, size_t *nb_chars_total, > + const struct rte_flow_attr *attr, > + const struct rte_flow_item pattern[], > + const struct rte_flow_action actions[]) { > + int rc; > + > + if (buf =3D=3D NULL && buf_size !=3D 0) > + return -EINVAL; > + > + *nb_chars_total =3D 0; > + > + rc =3D rte_flow_snprint_attr(buf, buf_size, nb_chars_total, attr); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_pattern(buf, buf_size, nb_chars_total, > pattern); > + if (rc !=3D 0) > + return rc; > + > + rc =3D rte_flow_snprint_actions(buf, buf_size, nb_chars_total, > actions); > + if (rc !=3D 0) > + return rc; > + > + return 0; > +} > diff --git a/lib/ethdev/version.map b/lib/ethdev/version.map index > 44d30b05ae..a626cac944 100644 > --- a/lib/ethdev/version.map > +++ b/lib/ethdev/version.map > @@ -249,6 +249,9 @@ EXPERIMENTAL { > rte_mtr_meter_policy_delete; > rte_mtr_meter_policy_update; > rte_mtr_meter_policy_validate; > + > + # added in 21.08 > + rte_flow_snprint; > }; >=20 > INTERNAL { > -- > 2.20.1