get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 125148,
    "url": "https://patches.dpdk.org/api/patches/125148/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20230315170342.214127-2-mattias.ronnblom@ericsson.com/",
    "project": {
        "id": 1,
        "url": "https://patches.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": "<20230315170342.214127-2-mattias.ronnblom@ericsson.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20230315170342.214127-2-mattias.ronnblom@ericsson.com",
    "date": "2023-03-15T17:03:41",
    "name": "[RFC,v2,1/2] eal: add bitset type",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "295b1f0d237ccccdd99922f2f1ce054d85398299",
    "submitter": {
        "id": 1077,
        "url": "https://patches.dpdk.org/api/people/1077/?format=api",
        "name": "Mattias Rönnblom",
        "email": "mattias.ronnblom@ericsson.com"
    },
    "delegate": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/20230315170342.214127-2-mattias.ronnblom@ericsson.com/mbox/",
    "series": [
        {
            "id": 27404,
            "url": "https://patches.dpdk.org/api/series/27404/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=27404",
            "date": "2023-03-15T17:03:40",
            "name": "Add high-performance timer facility",
            "version": 2,
            "mbox": "https://patches.dpdk.org/series/27404/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/125148/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/125148/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 mails.dpdk.org (mails.dpdk.org [217.70.189.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 2035341EA2;\n\tWed, 15 Mar 2023 18:09:45 +0100 (CET)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id E6341427F2;\n\tWed, 15 Mar 2023 18:09:42 +0100 (CET)",
            "from EUR01-VE1-obe.outbound.protection.outlook.com\n (mail-ve1eur01on2055.outbound.protection.outlook.com [40.107.14.55])\n by mails.dpdk.org (Postfix) with ESMTP id EE85342686\n for <dev@dpdk.org>; Wed, 15 Mar 2023 18:09:41 +0100 (CET)",
            "from FR3P281CA0127.DEUP281.PROD.OUTLOOK.COM (2603:10a6:d10:94::13)\n by DB5PR07MB9417.eurprd07.prod.outlook.com (2603:10a6:10:3c1::21) with\n Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6178.26; Wed, 15 Mar\n 2023 17:09:39 +0000",
            "from VI1EUR02FT046.eop-EUR02.prod.protection.outlook.com\n (2603:10a6:d10:94:cafe::ea) by FR3P281CA0127.outlook.office365.com\n (2603:10a6:d10:94::13) with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6178.27 via Frontend\n Transport; Wed, 15 Mar 2023 17:09:39 +0000",
            "from oa.msg.ericsson.com (192.176.1.74) by\n VI1EUR02FT046.mail.protection.outlook.com (10.13.60.169) with Microsoft SMTP\n Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) id\n 15.20.6199.16 via Frontend Transport; Wed, 15 Mar 2023 17:09:38 +0000",
            "from ESESBMB501.ericsson.se (153.88.183.168) by\n ESESBMB504.ericsson.se (153.88.183.171) with Microsoft SMTP Server\n (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id\n 15.1.2507.17; Wed, 15 Mar 2023 18:09:36 +0100",
            "from seliicinfr00050.seli.gic.ericsson.se (153.88.183.153) by\n smtp.internal.ericsson.com (153.88.183.184) with Microsoft SMTP Server id\n 15.1.2507.17 via Frontend Transport; Wed, 15 Mar 2023 18:09:37 +0100",
            "from breslau.. (seliicwb00002.seli.gic.ericsson.se [10.156.25.100])\n by seliicinfr00050.seli.gic.ericsson.se (Postfix) with ESMTP id\n 215041C006A; Wed, 15 Mar 2023 18:09:37 +0100 (CET)"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;\n b=Ijl9UgyEoy9E/7nwHn7BP4snUhwUxrsc9F7060/5WFJlTf1zP/0FGUbqVZuAT8liqVbgRY41IqBQcaVsgC/MKnOMd3aDxjlnbE3Dz+2c70oOgMDlV5OYUuLQl5f0BM6rfxKgoaugbZQ0DXbkhjUNL4Up8JKj7tHSzEGsXH5bWcypsUSNMY+/yG44Q2mmep+iMApAXoMd7iebDPMxzab1gGBkFga13GwWoQeorgVqeRtQDmLjVi8iIW0pC1+1om+GABFGlKvxBvScbqn4lsRPIwLqawVeIPXG8M82L8LiwFDff3Jok5NYzuLRT0poj0pu/Uvp+jlfRSU6CeB+h3Ntqg==",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n s=arcselector9901;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1;\n bh=audp6M7QIR2+6H2bkOF/vBFM6DJ9VDWWhKbaV4PPiSM=;\n b=FC8EsLjGspGvXcYBiVIvsah0g2rOofJMG/0xqHsJLw+lnNyRzx2IhbZmQpeetlkaknPdXrpAS+5VIZ/aEIZ94jLNYRFcgqjw6VSlbkGw83oNY0U6Ioynj5RA4AkXZDxa0ZTqL2W3cALkepLElolijRBoZpMwHzNT4IkG7lY6Zlpnt4tDJIz/ULKafMa+BTIc09DcT1mUS6LOduvVY05uJaHFTkxTjV5UsT89MAQP42ZRbZ3AeDMRTXcbiTmmZ28LYtlFcemAvUXQkwPcfgPfpLqElI9JpYwztO2BRm4DGMz/0UnYviQC2DwPwvFB19ScJU7M8oS0G9OaXzvm1JiFVQ==",
        "ARC-Authentication-Results": "i=1; mx.microsoft.com 1; spf=pass (sender ip is\n 192.176.1.74) smtp.rcpttodomain=dpdk.org smtp.mailfrom=ericsson.com;\n dmarc=pass (p=reject sp=reject pct=100) action=none header.from=ericsson.com;\n dkim=none (message not signed); arc=none",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=ericsson.com;\n s=selector1;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n bh=audp6M7QIR2+6H2bkOF/vBFM6DJ9VDWWhKbaV4PPiSM=;\n b=IDPg825O7KJ48zJMFDY1jB0GqH23UUhRrvwHoNgv4vIGBQexoLyex13u7o0sV41N45nkxCeFWKyCcqj1ps8fKPoI+5phrqjwI7MMhqjfKi3sam4AuL4hXesNDFeAK9O9SBYHXTu8FYSyRO7RKGbu+MhwjRoAe7c1v4sloeujfOg=",
        "X-MS-Exchange-Authentication-Results": "spf=pass (sender IP is 192.176.1.74)\n smtp.mailfrom=ericsson.com; dkim=none (message not signed)\n header.d=none;dmarc=pass action=none header.from=ericsson.com;",
        "Received-SPF": "Pass (protection.outlook.com: domain of ericsson.com designates\n 192.176.1.74 as permitted sender)\n receiver=protection.outlook.com;\n client-ip=192.176.1.74; helo=oa.msg.ericsson.com; pr=C",
        "From": "=?utf-8?q?Mattias_R=C3=B6nnblom?= <mattias.ronnblom@ericsson.com>",
        "To": "<dev@dpdk.org>",
        "CC": "Erik Gabriel Carrillo <erik.g.carrillo@intel.com>,\n David Marchand <david.marchand@redhat.com>, <maria.lingemark@ericsson.com>,\n Stefan Sundkvist <stefan.sundkvist@ericsson.com>,\n Stephen Hemminger <stephen@networkplumber.org>, =?utf-8?q?Morten_Br=C3=B8ru?=\n\t=?utf-8?q?p?= <mb@smartsharesystems.com>,\n Tyler Retzlaff <roretzla@linux.microsoft.com>, =?utf-8?q?Mattias_R=C3=B6nnb?=\n\t=?utf-8?q?lom?= <mattias.ronnblom@ericsson.com>",
        "Subject": "[RFC v2 1/2] eal: add bitset type",
        "Date": "Wed, 15 Mar 2023 18:03:41 +0100",
        "Message-ID": "<20230315170342.214127-2-mattias.ronnblom@ericsson.com>",
        "X-Mailer": "git-send-email 2.34.1",
        "In-Reply-To": "<20230315170342.214127-1-mattias.ronnblom@ericsson.com>",
        "References": "<20230228093916.87206-1-mattias.ronnblom@ericsson.com>\n <20230315170342.214127-1-mattias.ronnblom@ericsson.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"UTF-8\"",
        "Content-Transfer-Encoding": "8bit",
        "X-EOPAttributedMessage": "0",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-TrafficTypeDiagnostic": "VI1EUR02FT046:EE_|DB5PR07MB9417:EE_",
        "X-MS-Office365-Filtering-Correlation-Id": "1964feb9-8878-4651-1465-08db25780f90",
        "X-MS-Exchange-SenderADCheck": "1",
        "X-MS-Exchange-AntiSpam-Relay": "0",
        "X-Microsoft-Antispam": "BCL:0;",
        "X-Microsoft-Antispam-Message-Info": "\n 6E0el1Ulz33A23EtOaULvVXUBfGKByEkGY9o61v5ShoKofQmGZ9efFe7ENMjHnlOaX4e0Vvmzks3J0LI6ZIrhFrdh8kX2snC3EHaoBTSwN+baS4MXgPyn4YP0BT9QMeAhdn2qmVWYR3xI0AwAIsQL7FDv+1npfFOOmB6J3Dx45trWwEbeZdEZaokelb32cEY5JRg7OgAQMTADbd0c+HIagTSGMCKQDJGBBpO5ZdQnlpYz/JFwv9oIm8ACfqk+yLuHOUI73iprHOI1fUrl9c/uEXNwx9drHk1PJisJkobNpN+QJIPQULMsa7znmyo2x3AInXzfPbuNTppxHWclIypDCGGIHT6y6/aMWbgqGT121VtuMk1eZjV2NUnNxWHiJ4dcq95wgmrh+z+HWoA1Dl2faTEhnxjEO5K50JR4WDphLoYng1Exox3k92SU2q5Lv+QEzX5U/Dg2HiBLPMANkEqNo5xxvLqrGqySlj9Ubgo/z7OXUw0HqT86iwnTk5iZrKNqazv2K5zaa0hy/Pa/p0o+BDnx52RG+hGUxCEWl/UXDZKatZnZeU+igRZ/x1L8rCgcLjfM40sFUVmPC4spMRgE4ykP9j+w5qjX59ARvwU9gnjvKpBhkbekiBZbY7ekyEyfOpMdmZ3vCxoiLMqPue3RYH9/ktls1o8ZVpBHUF/EjMa7oedA1cBGFzfgzILjpKrlS+SN01TjNQt46bS0X//pflmST0BkADTUkiQFDJKWjv2OKF8S58cbBGVCxBcMFMU0+/pi7HEGGr4dD40l3QCrA==",
        "X-Forefront-Antispam-Report": "CIP:192.176.1.74; CTRY:SE; LANG:en; SCL:1; SRV:;\n IPV:NLI; SFV:NSPM; H:oa.msg.ericsson.com; PTR:office365.se.ericsson.net;\n CAT:NONE;\n SFS:(13230025)(4636009)(39860400002)(136003)(376002)(346002)(396003)(451199018)(40470700004)(46966006)(36840700001)(36756003)(2906002)(5660300002)(8936002)(30864003)(36860700001)(86362001)(82960400001)(82740400003)(356005)(7636003)(41300700001)(478600001)(8676002)(70206006)(70586007)(6916009)(4326008)(40480700001)(6266002)(2616005)(40460700003)(316002)(82310400005)(54906003)(66574015)(336012)(83380400001)(26005)(1076003)(186003)(47076005)(107886003)(6666004)(21314003)(579004);\n DIR:OUT; SFP:1101;",
        "X-OriginatorOrg": "ericsson.com",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "15 Mar 2023 17:09:38.9523 (UTC)",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n 1964feb9-8878-4651-1465-08db25780f90",
        "X-MS-Exchange-CrossTenant-Id": "92e84ceb-fbfd-47ab-be52-080c6b87953f",
        "X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp": "\n TenantId=92e84ceb-fbfd-47ab-be52-080c6b87953f; Ip=[192.176.1.74];\n Helo=[oa.msg.ericsson.com]",
        "X-MS-Exchange-CrossTenant-AuthSource": "\n VI1EUR02FT046.eop-EUR02.prod.protection.outlook.com",
        "X-MS-Exchange-CrossTenant-AuthAs": "Anonymous",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "HybridOnPrem",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "DB5PR07MB9417",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "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"
    },
    "content": "Introduce a set of functions and macros that operate on sets of bits,\nkept in arrays of 64-bit elements.\n\nRTE bitset is designed for bitsets which are larger than what fits in\na single machine word (i.e., 64 bits). For very large bitsets, the\n<rte_bitmap.h> API may be a more appropriate choice.\n\nRFC v2:\n * Replaced <sys/types.h> with <stddef.h> include, to properly get\n   size_t typedef.\n * Add <rte_compat.h> to get __rte_experimental in <rte_bitset.h>.\n\nSigned-off-by: Mattias Rönnblom <mattias.ronnblom@ericsson.com>\n---\n app/test/meson.build         |   4 +-\n app/test/test_bitset.c       | 645 +++++++++++++++++++++++++\n lib/eal/common/meson.build   |   1 +\n lib/eal/common/rte_bitset.c  |  29 ++\n lib/eal/include/meson.build  |   1 +\n lib/eal/include/rte_bitset.h | 879 +++++++++++++++++++++++++++++++++++\n lib/eal/version.map          |   3 +\n 7 files changed, 1561 insertions(+), 1 deletion(-)\n create mode 100644 app/test/test_bitset.c\n create mode 100644 lib/eal/common/rte_bitset.c\n create mode 100644 lib/eal/include/rte_bitset.h",
    "diff": "diff --git a/app/test/meson.build b/app/test/meson.build\nindex f34d19e3c3..03811ff692 100644\n--- a/app/test/meson.build\n+++ b/app/test/meson.build\n@@ -13,8 +13,9 @@ test_sources = files(\n         'test_alarm.c',\n         'test_atomic.c',\n         'test_barrier.c',\n-        'test_bitops.c',\n         'test_bitmap.c',\n+        'test_bitset.c',\n+        'test_bitops.c',\n         'test_bpf.c',\n         'test_byteorder.c',\n         'test_cksum.c',\n@@ -164,6 +165,7 @@ fast_tests = [\n         ['bpf_autotest', true, true],\n         ['bpf_convert_autotest', true, true],\n         ['bitops_autotest', true, true],\n+        ['bitset_autotest', true, true],\n         ['byteorder_autotest', true, true],\n         ['cksum_autotest', true, true],\n         ['cmdline_autotest', true, true],\ndiff --git a/app/test/test_bitset.c b/app/test/test_bitset.c\nnew file mode 100644\nindex 0000000000..8c75b38575\n--- /dev/null\n+++ b/app/test/test_bitset.c\n@@ -0,0 +1,645 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2023 Ericsson AB\n+ */\n+\n+#include <stdlib.h>\n+#include <inttypes.h>\n+\n+#include <rte_random.h>\n+\n+#include <rte_bitset.h>\n+\n+#include \"test.h\"\n+\n+#define MAGIC UINT64_C(0xdeadbeefdeadbeef)\n+\n+static void\n+rand_buf(void *buf, size_t n)\n+{\n+\tsize_t i;\n+\n+\tfor (i = 0; i < n; i++)\n+\t\t((char *)buf)[i] = (char)rte_rand();\n+}\n+\n+static uint64_t *\n+alloc_bitset(size_t size)\n+{\n+\tuint64_t *p;\n+\n+\tp = malloc(RTE_BITSET_SIZE(size) + 2 * sizeof(uint64_t));\n+\n+\tif (p == NULL)\n+\t\trte_panic(\"Unable to allocate memory\\n\");\n+\n+\trand_buf(&p[0], RTE_BITSET_SIZE(size));\n+\n+\tp[0] = MAGIC;\n+\tp[RTE_BITSET_NUM_WORDS(size) + 1] = MAGIC;\n+\n+\treturn p + 1;\n+}\n+\n+\n+static int\n+free_bitset(uint64_t *bitset, size_t size)\n+{\n+\tuint64_t *p;\n+\n+\tp = bitset - 1;\n+\n+\tif (p[0] != MAGIC)\n+\t\treturn TEST_FAILED;\n+\n+\tif (p[RTE_BITSET_NUM_WORDS(size) + 1] != MAGIC)\n+\t\treturn TEST_FAILED;\n+\n+\tfree(p);\n+\n+\treturn TEST_SUCCESS;\n+}\n+\n+static bool\n+rand_bool(void)\n+{\n+\treturn rte_rand_max(2);\n+}\n+\n+static void\n+rand_bool_ary(bool *ary, size_t len)\n+{\n+\tsize_t i;\n+\n+\tfor (i = 0; i < len; i++)\n+\t\tary[i] = rand_bool();\n+}\n+\n+static int\n+test_test_set_size(size_t size)\n+{\n+\tsize_t i;\n+\tbool reference[size];\n+\tuint64_t *bitset;\n+\n+\trand_bool_ary(reference, size);\n+\n+\tbitset = alloc_bitset(size);\n+\n+\tif (bitset == NULL)\n+\t\treturn TEST_FAILED;\n+\n+\trte_bitset_init(bitset, size);\n+\n+\tfor (i = 0; i < size; i++) {\n+\t\tif (reference[i])\n+\t\t\trte_bitset_set(bitset, i);\n+\t\telse\n+\t\t\trte_bitset_clear(bitset, i);\n+\t}\n+\n+\tfor (i = 0; i < size; i++)\n+\t\tif (reference[i] != rte_bitset_test(bitset, i))\n+\t\t\treturn TEST_FAILED;\n+\n+\tif (free_bitset(bitset, size) != TEST_SUCCESS)\n+\t\treturn TEST_FAILED;\n+\n+\treturn TEST_SUCCESS;\n+}\n+\n+#define RAND_ITERATIONS (10000)\n+#define RAND_SET_MAX_SIZE (1000)\n+\n+static int\n+test_test_set(void)\n+{\n+\tsize_t i;\n+\n+\tfor (i = 0; i < RAND_ITERATIONS; i++) {\n+\t\tsize_t size = 1 + rte_rand_max(RAND_SET_MAX_SIZE - 1);\n+\n+\t\tif (test_test_set_size(size) != TEST_SUCCESS)\n+\t\t\treturn TEST_FAILED;\n+\t}\n+\n+\treturn TEST_SUCCESS;\n+}\n+\n+static ssize_t\n+find(const bool *ary, size_t num_bools, size_t start, size_t len, bool set)\n+{\n+\tsize_t i;\n+\n+\tfor (i = 0; i < len; i++) {\n+\t\tssize_t idx = (start + i) % num_bools;\n+\n+\t\tif (ary[idx] == set)\n+\t\t\treturn idx;\n+\t}\n+\n+\treturn -1;\n+}\n+\n+static ssize_t\n+find_set(const bool *ary, size_t num_bools, size_t start, size_t len)\n+{\n+\treturn find(ary, num_bools, start, len, true);\n+}\n+\n+static ssize_t\n+find_clear(const bool *ary, size_t num_bools, size_t start, size_t len)\n+{\n+\treturn find(ary, num_bools, start, len, false);\n+}\n+\n+#define FFS_ITERATIONS (100)\n+\n+static int\n+test_find_size(size_t size, bool set)\n+{\n+\tuint64_t *bitset;\n+\tbool reference[size];\n+\tsize_t i;\n+\n+\tbitset = alloc_bitset(size);\n+\n+\tif (bitset == NULL)\n+\t\treturn TEST_FAILED;\n+\n+\trte_bitset_init(bitset, size);\n+\n+\tfor (i = 0; i < size; i++) {\n+\t\tbool bit = rand_bool();\n+\t\treference[i] = bit;\n+\n+\t\tif (bit)\n+\t\t\trte_bitset_set(bitset, i);\n+\t\telse /* redundant, still useful for testing */\n+\t\t\trte_bitset_clear(bitset, i);\n+\t}\n+\n+\tfor (i = 0; i < FFS_ITERATIONS; i++) {\n+\t\tsize_t start_bit = rte_rand_max(size);\n+\t\tsize_t len = rte_rand_max(size + 1);\n+\t\tbool full_range = len == size && start_bit == 0;\n+\t\tbool wraps = start_bit + len > size;\n+\t\tssize_t rc;\n+\n+\t\tif (set) {\n+\t\t\tif (full_range && rand_bool())\n+\t\t\t\trc = rte_bitset_find_first_set(bitset,\n+\t\t\t\t\t\t\t       size);\n+\t\t\telse if (wraps || rand_bool()) {\n+\t\t\t\trc = rte_bitset_find_set_wrap(bitset, size,\n+\t\t\t\t\t\t\t      start_bit, len);\n+\n+\t\t\t} else\n+\t\t\t\trc = rte_bitset_find_set(bitset, size,\n+\t\t\t\t\t\t\t start_bit, len);\n+\n+\t\t\tif (rc != find_set(reference, size, start_bit,\n+\t\t\t\t\t   len))\n+\t\t\t\treturn TEST_FAILED;\n+\t\t} else {\n+\t\t\tif (full_range && rand_bool())\n+\t\t\t\trc = rte_bitset_find_first_clear(bitset,\n+\t\t\t\t\t\t\t\t size);\n+\t\t\telse if (wraps || rand_bool())\n+\t\t\t\trc = rte_bitset_find_clear_wrap(bitset,\n+\t\t\t\t\t\t\t\tsize,\n+\t\t\t\t\t\t\t\tstart_bit, len);\n+\t\t\telse\n+\t\t\t\trc = rte_bitset_find_clear(bitset, size,\n+\t\t\t\t\t\t\t   start_bit, len);\n+\n+\t\t\tif (rc != find_clear(reference, size, start_bit,\n+\t\t\t\t\t     len))\n+\t\t\t\treturn TEST_FAILED;\n+\t\t}\n+\n+\t}\n+\n+\tif (free_bitset(bitset, size) != TEST_SUCCESS)\n+\t\treturn TEST_FAILED;\n+\n+\treturn TEST_SUCCESS;\n+}\n+\n+static int\n+test_find_set_size(size_t size)\n+{\n+\treturn test_find_size(size, true);\n+}\n+\n+static int\n+test_find_clear_size(size_t size)\n+{\n+\treturn test_find_size(size, false);\n+}\n+\n+static int\n+test_find(void)\n+{\n+\tsize_t i;\n+\n+\tfor (i = 0; i < RAND_ITERATIONS; i++) {\n+\t\tsize_t size = 2 + rte_rand_max(RAND_SET_MAX_SIZE - 2);\n+\n+\t\tif (test_find_set_size(size) != TEST_SUCCESS)\n+\t\t\treturn TEST_FAILED;\n+\n+\t\tif (test_find_clear_size(size) != TEST_SUCCESS)\n+\t\t\treturn TEST_FAILED;\n+\t}\n+\n+\treturn TEST_SUCCESS;\n+}\n+\n+static int\n+record_match(ssize_t match_idx, size_t size, int *calls)\n+{\n+\tif (match_idx < 0 || (size_t)match_idx >= size)\n+\t\treturn TEST_FAILED;\n+\n+\tcalls[match_idx]++;\n+\n+\treturn TEST_SUCCESS;\n+}\n+\n+static int\n+test_foreach_size(ssize_t size, bool may_wrap, bool set)\n+{\n+\tbool reference[size];\n+\tint calls[size];\n+\tuint64_t *bitset;\n+\tssize_t i;\n+\tssize_t start_bit;\n+\tssize_t len;\n+\tbool full_range;\n+\tsize_t total_calls = 0;\n+\n+\trand_bool_ary(reference, size);\n+\n+\tbitset = alloc_bitset(size);\n+\n+\tif (bitset == NULL)\n+\t\treturn TEST_FAILED;\n+\n+\tmemset(calls, 0, sizeof(calls));\n+\n+\tstart_bit = rte_rand_max(size);\n+\tlen = may_wrap ? rte_rand_max(size + 1) :\n+\t\trte_rand_max(size - start_bit + 1);\n+\n+\trte_bitset_init(bitset, size);\n+\n+\t/* random data in the unused bits should not matter */\n+\trand_buf(bitset, RTE_BITSET_SIZE(size));\n+\n+\tfor (i = start_bit; i < start_bit + len; i++) {\n+\t\tsize_t idx = i % size;\n+\n+\t\tif (reference[idx])\n+\t\t\trte_bitset_set(bitset, idx);\n+\t\telse\n+\t\t\trte_bitset_clear(bitset, idx);\n+\n+\t\tif (rte_bitset_test(bitset, idx) != reference[idx])\n+\t\t\treturn TEST_FAILED;\n+\t}\n+\n+\tfull_range = (len == size && start_bit == 0);\n+\n+\t/* XXX: verify iteration order as well */\n+\tif (set) {\n+\t\tif (full_range && rand_bool()) {\n+\t\t\tRTE_BITSET_FOREACH_SET(i, bitset, size) {\n+\t\t\t\tif (record_match(i, size, calls) !=\n+\t\t\t\t    TEST_SUCCESS)\n+\t\t\t\t\treturn TEST_FAILED;\n+\t\t\t}\n+\t\t} else if (may_wrap) {\n+\t\t\tRTE_BITSET_FOREACH_SET_WRAP(i, bitset, size,\n+\t\t\t\t\t\t    start_bit, len) {\n+\t\t\t\tif (record_match(i, size, calls) !=\n+\t\t\t\t    TEST_SUCCESS) {\n+\t\t\t\t\tprintf(\"failed\\n\");\n+\t\t\t\t\treturn TEST_FAILED;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t} else {\n+\t\t\tRTE_BITSET_FOREACH_SET_RANGE(i, bitset, size,\n+\t\t\t\t\t\t     start_bit, len) {\n+\t\t\t\tif (record_match(i, size, calls) !=\n+\t\t\t\t    TEST_SUCCESS)\n+\t\t\t\t\treturn TEST_FAILED;\n+\t\t\t}\n+\t\t}\n+\t} else {\n+\t\tif (full_range && rand_bool()) {\n+\t\t\tRTE_BITSET_FOREACH_CLEAR(i, bitset, size)\n+\t\t\t\tif (record_match(i, size, calls) !=\n+\t\t\t\t    TEST_SUCCESS)\n+\t\t\t\t\treturn TEST_FAILED;\n+\t\t} else if (may_wrap) {\n+\t\t\tRTE_BITSET_FOREACH_CLEAR_WRAP(i, bitset, size,\n+\t\t\t\t\t\t      start_bit, len) {\n+\t\t\t\tif (record_match(i, size, calls) !=\n+\t\t\t\t    TEST_SUCCESS)\n+\t\t\t\t\treturn TEST_FAILED;\n+\t\t\t}\n+\t\t} else {\n+\t\t\tRTE_BITSET_FOREACH_CLEAR_RANGE(i, bitset, size,\n+\t\t\t\t\t\t       start_bit, len)\n+\t\t\t\tif (record_match(i, size, calls) !=\n+\t\t\t\t    TEST_SUCCESS)\n+\t\t\t\t\treturn TEST_FAILED;\n+\t\t}\n+\t}\n+\n+\tfor (i = 0; i < len; i++) {\n+\t\tsize_t idx = (start_bit + i) % size;\n+\n+\t\tif (reference[idx] == set && calls[idx] != 1) {\n+\t\t\tprintf(\"bit %zd shouldn't have been found %d \"\n+\t\t\t       \"times\\n\", idx, calls[idx]);\n+\t\t\treturn TEST_FAILED;\n+\t\t}\n+\n+\t\tif (reference[idx] != set && calls[idx] != 0) {\n+\t\t\tputs(\"bar\");\n+\t\t\treturn TEST_FAILED;\n+\t\t}\n+\n+\t\ttotal_calls += calls[idx];\n+\t}\n+\n+\tif (full_range) {\n+\t\tsize_t count;\n+\n+\t\tcount = set ? rte_bitset_count_set(bitset, size) :\n+\t\t\trte_bitset_count_clear(bitset, size);\n+\n+\t\tif (count != total_calls)\n+\t\t\treturn TEST_FAILED;\n+\t}\n+\n+\tif (free_bitset(bitset, size) != TEST_SUCCESS)\n+\t\treturn TEST_FAILED;\n+\n+\treturn TEST_SUCCESS;\n+}\n+\n+static int\n+test_foreach(void)\n+{\n+\tsize_t i;\n+\n+\tfor (i = 0; i < RAND_ITERATIONS; i++) {\n+\t\tsize_t size = 1 + rte_rand_max(RAND_SET_MAX_SIZE - 1);\n+\n+\t\tif (test_foreach_size(size, false, true) != TEST_SUCCESS)\n+\t\t\treturn TEST_FAILED;\n+\n+\t\tif (test_foreach_size(size, false, false) != TEST_SUCCESS)\n+\t\t\treturn TEST_FAILED;\n+\n+\t\tif (test_foreach_size(size, true, true) != TEST_SUCCESS)\n+\t\t\treturn TEST_FAILED;\n+\n+\t\tif (test_foreach_size(size, true, false) != TEST_SUCCESS)\n+\t\t\treturn TEST_FAILED;\n+\t}\n+\n+\treturn TEST_SUCCESS;\n+}\n+\n+static int\n+test_count_size(size_t size)\n+{\n+\tuint64_t *bitset;\n+\n+\tbitset = alloc_bitset(size);\n+\n+\tif (bitset == NULL)\n+\t\treturn TEST_FAILED;\n+\n+\trte_bitset_init(bitset, size);\n+\n+\tif (rte_bitset_count_set(bitset, size) != 0)\n+\t\treturn TEST_FAILED;\n+\n+\tif (rte_bitset_count_clear(bitset, size) != size)\n+\t\treturn TEST_FAILED;\n+\n+\trte_bitset_set_all(bitset, size);\n+\n+\tif (rte_bitset_count_set(bitset, size) != size)\n+\t\treturn TEST_FAILED;\n+\n+\tif (rte_bitset_count_clear(bitset, size) != 0)\n+\t\treturn TEST_FAILED;\n+\n+\trte_bitset_clear_all(bitset, size);\n+\n+\tif (rte_bitset_count_set(bitset, size) != 0)\n+\t\treturn TEST_FAILED;\n+\n+\tif (rte_bitset_count_clear(bitset, size) != size)\n+\t\treturn TEST_FAILED;\n+\n+\trte_bitset_set(bitset, rte_rand_max(size));\n+\n+\tif (rte_bitset_count_set(bitset, size) != 1)\n+\t\treturn TEST_FAILED;\n+\n+\tif (rte_bitset_count_clear(bitset, size) != (size - 1))\n+\t\treturn TEST_FAILED;\n+\n+\trte_bitset_clear_all(bitset, size);\n+\tif (rte_bitset_count_set(bitset, size) != 0)\n+\t\treturn TEST_FAILED;\n+\tif (rte_bitset_count_clear(bitset, size) != size)\n+\t\treturn TEST_FAILED;\n+\n+\trte_bitset_set_all(bitset, size);\n+\tif (rte_bitset_count_set(bitset, size) != size)\n+\t\treturn TEST_FAILED;\n+\tif (rte_bitset_count_clear(bitset, size) != 0)\n+\t\treturn TEST_FAILED;\n+\n+\tif (free_bitset(bitset, size) != TEST_SUCCESS)\n+\t\treturn TEST_FAILED;\n+\n+\treturn TEST_SUCCESS;\n+}\n+\n+static int\n+test_count(void)\n+{\n+\tsize_t i;\n+\n+\tif (test_count_size(128) != TEST_SUCCESS)\n+\t\treturn TEST_FAILED;\n+\tif (test_count_size(1) != TEST_SUCCESS)\n+\t\treturn TEST_FAILED;\n+\tif (test_count_size(63) != TEST_SUCCESS)\n+\t\treturn TEST_FAILED;\n+\tif (test_count_size(64) != TEST_SUCCESS)\n+\t\treturn TEST_FAILED;\n+\tif (test_count_size(65) != TEST_SUCCESS)\n+\t\treturn TEST_FAILED;\n+\n+\tfor (i = 0; i < RAND_ITERATIONS; i++) {\n+\t\tsize_t size = 1 + rte_rand_max(RAND_SET_MAX_SIZE - 1);\n+\n+\t\tif (test_count_size(size) != TEST_SUCCESS)\n+\t\t\treturn TEST_FAILED;\n+\t}\n+\n+\treturn TEST_SUCCESS;\n+}\n+\n+#define GEN_DECLARE(size)\t\t\t\t\t\t\\\n+\t{\t\t\t\t\t\t\t\t\\\n+\t\tRTE_BITSET_DECLARE(bitset, size);\t\t\t\\\n+\t\tsize_t idx;\t\t\t\t\t\t\\\n+\t\t\t\t\t\t\t\t\t\\\n+\t\tidx = rte_rand_max(size);\t\t\t\t\\\n+\t\trte_bitset_init(bitset, size);\t\t\t\t\\\n+\t\t\t\t\t\t\t\t\t\\\n+\t\trte_bitset_set(bitset, idx);\t\t\t\t\\\n+\t\tif (!rte_bitset_test(bitset, idx))\t\t\t\\\n+\t\t\treturn TEST_FAILED;\t\t\t\t\\\n+\t\tif (rte_bitset_count_set(bitset, size) != 1)\t\t\\\n+\t\t\treturn TEST_FAILED;\t\t\t\t\\\n+\t\treturn TEST_SUCCESS;\t\t\t\t\t\\\n+\t}\n+\n+static int\n+test_define(void)\n+{\n+\tGEN_DECLARE(1);\n+\tGEN_DECLARE(64);\n+\tGEN_DECLARE(65);\n+\tGEN_DECLARE(4097);\n+}\n+\n+static int\n+test_equal(void)\n+{\n+\tconst size_t size = 100;\n+\tRTE_BITSET_DECLARE(bitset_a, size);\n+\tRTE_BITSET_DECLARE(bitset_b, size);\n+\n+\trand_buf(bitset_a, RTE_BITSET_SIZE(size));\n+\trand_buf(bitset_b, RTE_BITSET_SIZE(size));\n+\n+\trte_bitset_init(bitset_a, size);\n+\trte_bitset_init(bitset_b, size);\n+\n+\trte_bitset_set(bitset_a, 9);\n+\trte_bitset_set(bitset_b, 9);\n+\trte_bitset_set(bitset_a, 90);\n+\trte_bitset_set(bitset_b, 90);\n+\n+\tif (!rte_bitset_equal(bitset_a, bitset_b, size))\n+\t\treturn TEST_FAILED;\n+\n+\t/* set unused bit, which should be ignored */\n+\trte_bitset_set(&bitset_a[1], 60);\n+\n+\tif (!rte_bitset_equal(bitset_a, bitset_b, size))\n+\t\treturn TEST_FAILED;\n+\n+\treturn TEST_SUCCESS;\n+}\n+\n+static int\n+test_copy(void)\n+{\n+\tconst size_t size = 100;\n+\tRTE_BITSET_DECLARE(bitset_a, size);\n+\tRTE_BITSET_DECLARE(bitset_b, size);\n+\n+\trand_buf(bitset_a, RTE_BITSET_SIZE(size));\n+\trand_buf(bitset_b, RTE_BITSET_SIZE(size));\n+\n+\tif (rte_bitset_equal(bitset_a, bitset_b, size))\n+\t\treturn TEST_FAILED;\n+\n+\trte_bitset_copy(bitset_a, bitset_b, size);\n+\n+\tif (!rte_bitset_equal(bitset_a, bitset_b, size))\n+\t\treturn TEST_FAILED;\n+\n+\treturn TEST_SUCCESS;\n+}\n+\n+static int\n+test_to_str(void)\n+{\n+\tchar buf[1024];\n+\tRTE_BITSET_DECLARE(bitset, 128);\n+\n+\trte_bitset_init(bitset, 128);\n+\trte_bitset_set(bitset, 1);\n+\n+\tif (rte_bitset_to_str(bitset, 2, buf, 3) != 3)\n+\t\treturn TEST_FAILED;\n+\tif (strcmp(buf, \"10\") != 0)\n+\t\treturn TEST_FAILED;\n+\n+\trte_bitset_set(bitset, 0);\n+\n+\tif (rte_bitset_to_str(bitset, 1, buf, sizeof(buf)) != 2)\n+\t\treturn TEST_FAILED;\n+\tif (strcmp(buf, \"1\") != 0)\n+\t\treturn TEST_FAILED;\n+\n+\trte_bitset_init(bitset, 99);\n+\trte_bitset_set(bitset, 98);\n+\n+\tif (rte_bitset_to_str(bitset, 99, buf, sizeof(buf)) != 100)\n+\t\treturn TEST_FAILED;\n+\n+\tif (buf[0] != '1' || strchr(&buf[1], '1') != NULL)\n+\t\treturn TEST_FAILED;\n+\n+\tif (rte_bitset_to_str(bitset, 128, buf, 64) != -EINVAL)\n+\t\treturn TEST_FAILED;\n+\n+\treturn TEST_SUCCESS;\n+}\n+\n+static int\n+test_bitset(void)\n+{\n+\tif (test_test_set() != TEST_SUCCESS)\n+\t\treturn TEST_FAILED;\n+\n+\tif (test_find() != TEST_SUCCESS)\n+\t\treturn TEST_FAILED;\n+\n+\tif (test_foreach() != TEST_SUCCESS)\n+\t\treturn TEST_FAILED;\n+\n+\tif (test_count() != TEST_SUCCESS)\n+\t\treturn TEST_FAILED;\n+\n+\tif (test_define() != TEST_SUCCESS)\n+\t\treturn TEST_FAILED;\n+\n+\tif (test_equal() != TEST_SUCCESS)\n+\t\treturn TEST_FAILED;\n+\n+\tif (test_copy() != TEST_SUCCESS)\n+\t\treturn TEST_FAILED;\n+\n+\tif (test_to_str() != TEST_SUCCESS)\n+\t\treturn TEST_FAILED;\n+\n+\treturn TEST_SUCCESS;\n+}\n+\n+REGISTER_TEST_COMMAND(bitset_autotest, test_bitset);\ndiff --git a/lib/eal/common/meson.build b/lib/eal/common/meson.build\nindex 917758cc65..687ae51d87 100644\n--- a/lib/eal/common/meson.build\n+++ b/lib/eal/common/meson.build\n@@ -32,6 +32,7 @@ sources += files(\n         'eal_common_uuid.c',\n         'malloc_elem.c',\n         'malloc_heap.c',\n+        'rte_bitset.c',\n         'rte_malloc.c',\n         'rte_random.c',\n         'rte_reciprocal.c',\ndiff --git a/lib/eal/common/rte_bitset.c b/lib/eal/common/rte_bitset.c\nnew file mode 100644\nindex 0000000000..35e55a64db\n--- /dev/null\n+++ b/lib/eal/common/rte_bitset.c\n@@ -0,0 +1,29 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2023 Ericsson AB\n+ */\n+\n+#include <errno.h>\n+\n+#include \"rte_bitset.h\"\n+\n+ssize_t\n+rte_bitset_to_str(const uint64_t *bitset, size_t num_bits, char *buf,\n+\t\t  size_t capacity)\n+{\n+\tsize_t i;\n+\n+\tif (capacity < (num_bits + 1))\n+\t\treturn -EINVAL;\n+\n+\tfor (i = 0; i < num_bits; i++) {\n+\t\tbool value;\n+\n+\t\tvalue = rte_bitset_test(bitset, num_bits - 1 - i);\n+\n+\t\tbuf[i] = value ? '1' : '0';\n+\t}\n+\n+\tbuf[num_bits] = '\\0';\n+\n+\treturn num_bits + 1;\n+}\ndiff --git a/lib/eal/include/meson.build b/lib/eal/include/meson.build\nindex b0db9b3b3a..fa3cb884e9 100644\n--- a/lib/eal/include/meson.build\n+++ b/lib/eal/include/meson.build\n@@ -5,6 +5,7 @@ includes += include_directories('.')\n \n headers += files(\n         'rte_alarm.h',\n+        'rte_bitset.h',\n         'rte_bitmap.h',\n         'rte_bitops.h',\n         'rte_branch_prediction.h',\ndiff --git a/lib/eal/include/rte_bitset.h b/lib/eal/include/rte_bitset.h\nnew file mode 100644\nindex 0000000000..4e59053b2d\n--- /dev/null\n+++ b/lib/eal/include/rte_bitset.h\n@@ -0,0 +1,879 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2023 Ericsson AB\n+ */\n+\n+#ifndef _RTE_BITSET_H_\n+#define _RTE_BITSET_H_\n+\n+/**\n+ * @file\n+ * RTE Bitset\n+ *\n+ * This file provides functions and macros for querying and\n+ * manipulating sets of bits kept in arrays of @c uint64_t-sized\n+ * elements.\n+ *\n+ * The bits in a bitset are numbered from 0 to @c size - 1, with the\n+ * lowest index being the least significant bit.\n+ *\n+ * The bitset array must be properly aligned.\n+ *\n+ * For optimal performance, the @c size parameter, required by\n+ * many of the API's functions, should be a compile-time constant.\n+ *\n+ * For large bitsets, the rte_bitmap.h API may be more appropriate.\n+ *\n+ * @warning\n+ * All functions modifying a bitset may overwrite any unused bits of\n+ * the last word. Such unused bits are ignored by all functions reading\n+ * bits.\n+ *\n+ */\n+\n+#include <limits.h>\n+#include <stdbool.h>\n+#include <stddef.h>\n+#include <stdint.h>\n+\n+#include <rte_branch_prediction.h>\n+#include <rte_common.h>\n+#include <rte_compat.h>\n+#include <rte_debug.h>\n+#include <rte_memcpy.h>\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+/**\n+ * The size (in bytes) of each element in the array used to represent\n+ * a bitset.\n+ */\n+#define RTE_BITSET_WORD_SIZE (sizeof(uint64_t))\n+\n+/**\n+ * The size (in bits) of each element in the array used to represent\n+ * a bitset.\n+ */\n+#define RTE_BITSET_WORD_BITS (RTE_BITSET_WORD_SIZE * CHAR_BIT)\n+\n+/**\n+ * Computes the number of words required to store @c size bits.\n+ */\n+#define RTE_BITSET_NUM_WORDS(size)\t\t\t       \\\n+\t((size + RTE_BITSET_WORD_BITS - 1) / RTE_BITSET_WORD_BITS)\n+\n+/**\n+ * Computes the amount of memory (in bytes) required to fit a bitset\n+ * holding @c size bits.\n+ */\n+#define RTE_BITSET_SIZE(size)\t\t\t\t\t\\\n+\t((size_t)(RTE_BITSET_NUM_WORDS(size) * RTE_BITSET_WORD_SIZE))\n+\n+#define __RTE_BITSET_WORD_IDX(bit_num) ((bit_num) / RTE_BITSET_WORD_BITS)\n+#define __RTE_BITSET_BIT_OFFSET(bit_num) ((bit_num) % RTE_BITSET_WORD_BITS)\n+#define __RTE_BITSET_UNUSED(size)\t\t\t\t\\\n+\t((RTE_BITSET_NUM_WORDS(size) * RTE_BITSET_WORD_BITS) \\\n+\t - (size))\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Declare a bitset.\n+ *\n+ * Declare (e.g., as a struct field) or define (e.g., as a stack\n+ * variable) a bitset of the specified size.\n+ *\n+ * @param size\n+ *   The number of bits the bitset must be able to represent. Must be\n+ *   a compile-time constant.\n+ * @param name\n+ *   The field or variable name of the resulting definition.\n+ */\n+#define RTE_BITSET_DECLARE(name, size)\t\t\\\n+\tuint64_t name[RTE_BITSET_NUM_WORDS(size)]\n+\n+/* XXX: should one include flags here and use to avoid a comparison? */\n+/* XXX: would this be better off as a function? */\n+\n+#define __RTE_BITSET_FOREACH_LEFT(var, size, start_bit, len)\t\\\n+\t((len) - 1 - ((var) >= (start_bit) ? (var) - (start_bit) :\t\\\n+\t\t  (size) - (start_bit) + (var)))\n+\n+#define __RTE_BITSET_FOREACH(var, bitset, size, start_bit, len, flags) \\\n+\tfor ((var) = __rte_bitset_find(bitset, size, start_bit, len, \\\n+\t\t\t\t       flags);\t\t\t\t\\\n+\t     (var) != -1;\t\t\t\t\t\t\\\n+\t     (var) = __RTE_BITSET_FOREACH_LEFT(var, size, start_bit, \\\n+\t\t\t\t\t       len) > 0\t?\t\t\\\n+\t\t     __rte_bitset_find(bitset, size,\t\t\\\n+\t\t\t\t       ((var) + 1) % (size),\t\\\n+\t\t\t\t       __RTE_BITSET_FOREACH_LEFT(var,\t\\\n+\t\t\t\t\t\t\t\t size, \\\n+\t\t\t\t\t\t\t\t start_bit, \\\n+\t\t\t\t\t\t\t\t len),\t\\\n+\t\t\t\t       flags) : -1)\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Iterate over all bits set.\n+ *\n+ * This macro iterates over all bits set (i.e., all ones) in the\n+ * bitset, in the forward direction (i.e., starting with the least\n+ * significant '1').\n+ *\n+ * @param var\n+ *   An iterator variable of type @c ssize_t. For each successive\n+ *   iteration, this variable will hold the bit index of a set bit.\n+ * @param bitset\n+ *   A <tt>const uint64_t *</tt> pointer to the bitset array.\n+ * @param size\n+ *   The size of the bitset (in bits).\n+ */\n+\n+#define RTE_BITSET_FOREACH_SET(var, bitset, size)\t\t\t\\\n+\t__RTE_BITSET_FOREACH(var, bitset, size, 0, size, 0)\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Iterate over all bits cleared.\n+ *\n+ * This macro iterates over all bits cleared in the bitset, in the\n+ * forward direction (i.e., starting with the lowest-indexed set bit).\n+ *\n+ * @param var\n+ *   An iterator variable of type @c ssize_t. For each successive iteration,\n+ *   this variable will hold the bit index of a cleared bit.\n+ * @param bitset\n+ *   A <tt>const uint64_t *</tt> pointer to the bitset array.\n+ * @param size\n+ *   The size of the bitset (in bits).\n+ */\n+\n+#define RTE_BITSET_FOREACH_CLEAR(var, bitset, size)\t\t\t\\\n+\t__RTE_BITSET_FOREACH(var, bitset, size, 0, size,\t\\\n+\t\t\t     __RTE_BITSET_FIND_FLAG_FIND_CLEAR)\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Iterate over all bits set within a range.\n+ *\n+ * This macro iterates over all bits set (i.e., all ones) in the\n+ * specified range, in the forward direction (i.e., starting with the\n+ * least significant '1').\n+ *\n+ * @param var\n+ *   An iterator variable of type @c ssize_t. For each successive iteration,\n+ *   this variable will hold the bit index of a set bit.\n+ * @param bitset\n+ *   A <tt>const uint64_t *</tt> pointer to the bitset array.\n+ * @param size\n+ *   The size of the bitset (in bits).\n+ * @param start_bit\n+ *   The index of the first bit to check. Must be less than @c size.\n+ * @param len\n+ *   The length (in bits) of the range. @c start_bit + @c len must be less\n+ *   than or equal to @c size.\n+ */\n+\n+#define RTE_BITSET_FOREACH_SET_RANGE(var, bitset, size, start_bit, \\\n+\t\t\t\t     len)\t\t\t       \\\n+\t__RTE_BITSET_FOREACH(var, bitset, size, start_bit, len, 0)\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Iterate over all cleared bits within a range.\n+ *\n+ * This macro iterates over all bits cleared (i.e., all zeroes) in the\n+ * specified range, in the forward direction (i.e., starting with the\n+ * least significant '0').\n+ *\n+ * @param var\n+ *   An iterator variable of type @c ssize_t. For each successive iteration,\n+ *   this variable will hold the bit index of a set bit.\n+ * @param bitset\n+ *   A <tt>const uint64_t *</tt> pointer to the bitset array.\n+ * @param size\n+ *   The size of the bitset (in bits).\n+ * @param start_bit\n+ *   The index of the first bit to check. Must be less than @c size.\n+ * @param len\n+ *   The length (in bits) of the range. @c start_bit + @c len must be less\n+ *   than or equal to @c size.\n+ */\n+\n+#define RTE_BITSET_FOREACH_CLEAR_RANGE(var, bitset, size, start_bit,\t\\\n+\t\t\t\t       len)\t\t\t\t\\\n+\t__RTE_BITSET_FOREACH(var, bitset, size, start_bit, len,\t\\\n+\t\t\t     __RTE_BITSET_FIND_FLAG_FIND_CLEAR)\n+\n+#define RTE_BITSET_FOREACH_SET_WRAP(var, bitset, size, start_bit,  \\\n+\t\t\t\t    len)\t\t\t       \\\n+\t__RTE_BITSET_FOREACH(var, bitset, size, start_bit, len,    \\\n+\t\t\t     __RTE_BITSET_FIND_FLAG_WRAP)\n+\n+#define RTE_BITSET_FOREACH_CLEAR_WRAP(var, bitset, size, start_bit, \\\n+\t\t\t\t       len)\t\t\t\t\\\n+\t__RTE_BITSET_FOREACH(var, bitset, size, start_bit, len,\t\\\n+\t\t\t     __RTE_BITSET_FIND_FLAG_WRAP |\t\t\\\n+\t\t\t     __RTE_BITSET_FIND_FLAG_FIND_CLEAR)\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Initializes a bitset.\n+ *\n+ * All bits are cleared.\n+ *\n+ * @param bitset\n+ *   A pointer to the array of bitset 64-bit words.\n+ * @param size\n+ *   The size of the bitset (in bits).\n+ */\n+\n+__rte_experimental\n+static inline void\n+rte_bitset_init(uint64_t *bitset, size_t size)\n+{\n+\tmemset(bitset, 0, RTE_BITSET_SIZE(size));\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Set a bit in the bitset.\n+ *\n+ * Bits are numbered from 0 to (size - 1) (inclusive).\n+ *\n+ * @param bitset\n+ *   A pointer to the array words making up the bitset.\n+ * @param bit_num\n+ *   The index of the bit to be set.\n+ */\n+\n+__rte_experimental\n+static inline void\n+rte_bitset_set(uint64_t *bitset, size_t bit_num)\n+{\n+\tsize_t word;\n+\tsize_t offset;\n+\tuint64_t mask;\n+\n+\tword = __RTE_BITSET_WORD_IDX(bit_num);\n+\toffset = __RTE_BITSET_BIT_OFFSET(bit_num);\n+\tmask = UINT64_C(1) << offset;\n+\n+\tbitset[word] |= mask;\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Clear a bit in the bitset.\n+ *\n+ * Bits are numbered 0 to (size - 1) (inclusive).\n+ *\n+ * @param bitset\n+ *   A pointer to the array words making up the bitset.\n+ * @param bit_num\n+ *   The index of the bit to be cleared.\n+ */\n+\n+__rte_experimental\n+static inline void\n+rte_bitset_clear(uint64_t *bitset, size_t bit_num)\n+{\n+\tsize_t word;\n+\tsize_t offset;\n+\tuint64_t mask;\n+\n+\tword = __RTE_BITSET_WORD_IDX(bit_num);\n+\toffset = __RTE_BITSET_BIT_OFFSET(bit_num);\n+\tmask = ~(UINT64_C(1) << offset);\n+\n+\tbitset[word] &= mask;\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Set all bits in the bitset.\n+ *\n+ * @param bitset\n+ *   A pointer to the array of words making up the bitset.\n+ * @param size\n+ *   The size of the bitset (in bits).\n+ */\n+\n+__rte_experimental\n+static inline void\n+rte_bitset_set_all(uint64_t *bitset, size_t size)\n+{\n+\tmemset(bitset, 0xFF, RTE_BITSET_SIZE(size));\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Clear all bits in the bitset.\n+ *\n+ * @param bitset\n+ *   A pointer to the array of words making up the bitset.\n+ * @param size\n+ *   The size of the bitset (in bits).\n+ */\n+\n+__rte_experimental\n+static inline void\n+rte_bitset_clear_all(uint64_t *bitset, size_t size)\n+{\n+\trte_bitset_init(bitset, size);\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Count all set bits.\n+ *\n+ * @param bitset\n+ *   A pointer to the array of words making up the bitset.\n+ * @param size\n+ *   The size of the bitset (in bits).\n+ * @return\n+ *   Returns the number of '1' bits in the bitset.\n+ */\n+\n+__rte_experimental\n+static inline size_t\n+rte_bitset_count_set(const uint64_t *bitset, size_t size)\n+{\n+\tsize_t i;\n+\tsize_t total = 0;\n+\tuint64_t unused_mask;\n+\n+\t/*\n+\t * Unused bits in a rte_bitset are always '0', and thus are\n+\t * not included in this count.\n+\t */\n+\tfor (i = 0; i < RTE_BITSET_NUM_WORDS(size) - 1; i++)\n+\t\ttotal += __builtin_popcountll(bitset[i]);\n+\n+\tunused_mask = UINT64_MAX >> __RTE_BITSET_UNUSED(size);\n+\ttotal += __builtin_popcountll(bitset[i] & unused_mask);\n+\n+\treturn total;\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Count all cleared bits.\n+ *\n+ * @param bitset\n+ *   A pointer to the array of words making up the bitset.\n+ * @param size\n+ *   The size of the bitset (in bits).\n+ * @return\n+ *   Returns the number of '0' bits in the bitset.\n+ */\n+\n+__rte_experimental\n+static inline size_t\n+rte_bitset_count_clear(const uint64_t *bitset, size_t size)\n+{\n+\treturn size - rte_bitset_count_set(bitset, size);\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Test if a bit is set.\n+ *\n+ * @param bitset\n+ *   A pointer to the array of words making up the bitset.\n+ * @param bit_num\n+ *   Index of the bit to test. Index 0 is the least significant bit.\n+ * @return\n+ *   Returns true if the bit is '1', and false if the bit is '0'.\n+ */\n+\n+__rte_experimental\n+static inline bool\n+rte_bitset_test(const uint64_t *bitset, size_t bit_num)\n+{\n+\tsize_t word;\n+\tsize_t offset;\n+\n+\tword = __RTE_BITSET_WORD_IDX(bit_num);\n+\toffset = __RTE_BITSET_BIT_OFFSET(bit_num);\n+\n+\treturn (bitset[word] >> offset) & 1;\n+}\n+\n+#define __RTE_BITSET_FIND_FLAG_FIND_CLEAR (1U << 0)\n+#define __RTE_BITSET_FIND_FLAG_WRAP (1U << 1)\n+\n+__rte_experimental\n+static inline ssize_t\n+__rte_bitset_find_nowrap(const uint64_t *bitset, size_t __rte_unused size,\n+\t\t\t size_t start_bit, size_t len, bool find_clear)\n+{\n+\tsize_t word_idx;\n+\tsize_t offset;\n+\tsize_t end_bit = start_bit + len;\n+\n+\tRTE_ASSERT(end_bit <= size);\n+\n+\tif (unlikely(len == 0))\n+\t\treturn -1;\n+\n+\tword_idx = __RTE_BITSET_WORD_IDX(start_bit);\n+\toffset = __RTE_BITSET_BIT_OFFSET(start_bit);\n+\n+\twhile (word_idx <= __RTE_BITSET_WORD_IDX(end_bit - 1)) {\n+\t\tuint64_t word;\n+\t\tint word_ffs;\n+\n+\t\tword = bitset[word_idx];\n+\t\tif (find_clear)\n+\t\t\tword = ~word;\n+\n+\t\tword >>= offset;\n+\n+\t\tword_ffs = __builtin_ffsll(word);\n+\n+\t\tif (word_ffs != 0) {\n+\t\t\tssize_t ffs = start_bit + word_ffs - 1;\n+\n+\t\t\t/*\n+\t\t\t * Check if set bit were among the last,\n+\t\t\t * unused bits, in the last word.\n+\t\t\t */\n+\t\t\tif (unlikely(ffs >= (ssize_t)end_bit))\n+\t\t\t\treturn -1;\n+\n+\t\t\treturn ffs;\n+\t\t}\n+\n+\t\tstart_bit += (RTE_BITSET_WORD_BITS - offset);\n+\t\tword_idx++;\n+\t\toffset = 0;\n+\t}\n+\n+\treturn -1;\n+\n+}\n+\n+__rte_experimental\n+static inline ssize_t\n+__rte_bitset_find(const uint64_t *bitset, size_t size, size_t start_bit,\n+\t\t  size_t len, unsigned int flags)\n+{\n+\tbool find_clear = flags & __RTE_BITSET_FIND_FLAG_FIND_CLEAR;\n+\tbool may_wrap = flags & __RTE_BITSET_FIND_FLAG_WRAP;\n+\tbool does_wrap = (start_bit + len) > size;\n+\tssize_t rc;\n+\n+\tRTE_ASSERT(len <= size);\n+\tif (!may_wrap)\n+\t\tRTE_ASSERT(!does_wrap);\n+\n+\tif (may_wrap && does_wrap) {\n+\t\tsize_t len0 = size - start_bit;\n+\t\tsize_t len1 = len - len0;\n+\n+\t\trc = __rte_bitset_find_nowrap(bitset, size, start_bit, len0,\n+\t\t\t\t\t      find_clear);\n+\t\tif (rc < 0)\n+\t\t\trc =  __rte_bitset_find_nowrap(bitset, size,\n+\t\t\t\t\t\t       0, len1, find_clear);\n+\t} else\n+\t\trc = __rte_bitset_find_nowrap(bitset, size, start_bit,\n+\t\t\t\t\t      len, find_clear);\n+\n+\treturn rc;\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Find first bit set.\n+ *\n+ * Scans the bitset in the forward direction (i.e., starting at the\n+ * least significant bit), and returns the index of the first '1'.\n+ *\n+ * @param bitset\n+ *   A pointer to the array of words making up the bitset.\n+ * @param size\n+ *   The size of the bitset (in bits).\n+ * @return\n+ *   Returns the index of the least significant '1', or -1 if all\n+ *   bits are '0'.\n+ */\n+\n+__rte_experimental\n+static inline ssize_t\n+rte_bitset_find_first_set(const uint64_t *bitset, size_t size)\n+{\n+\treturn __rte_bitset_find(bitset, size, 0, size, 0);\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Find first bit set at offset.\n+ *\n+ * Scans the bitset in the forward direction (i.e., starting at the\n+ * least significant bit), starting at an offset @c start_bit into the\n+ * bitset, and returns the index of the first '1' encountered.\n+ *\n+ * @param bitset\n+ *   A pointer to the array of words making up the bitset.\n+ * @param size\n+ *   The size of the bitset (in bits).\n+ * @param start_bit\n+ *   The index of the first bit to check. Must be less than @c size.\n+ * @param len\n+ *   The number of bits to scan. @c start_bit + @c len must be less\n+ *   than or equal to @c size.\n+ * @return\n+ *   Returns the index of the least significant '1', or -1 if all\n+ *   bits are '0'.\n+ */\n+\n+__rte_experimental\n+static inline ssize_t\n+rte_bitset_find_set(const uint64_t *bitset, size_t size,\n+\t\t    size_t start_bit, size_t len)\n+{\n+\treturn __rte_bitset_find(bitset, size, start_bit, len, 0);\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Find first bit set at offset, with wrap-around.\n+ *\n+ * Scans the bitset in the forward direction (i.e., starting at the\n+ * least significant bit), starting at an offset @c start_bit into the\n+ * bitset. If no '1' is encountered before the end of the bitset, the search\n+ * will continue at index 0.\n+ *\n+ * @param bitset\n+ *   A pointer to the array of words making up the bitset.\n+ * @param size\n+ *   The size of the bitset (in bits).\n+ * @param start_bit\n+ *   The index of the first bit to check. Must be less than @c size.\n+ * @param len\n+ *   The number of bits to scan. @c start_bit + @c len must be less\n+ *   than or equal to @c size.\n+ * @return\n+ *   Returns the index of the least significant '1', or -1 if all\n+ *   bits are '0'.\n+ */\n+\n+__rte_experimental\n+static inline ssize_t\n+rte_bitset_find_set_wrap(const uint64_t *bitset, size_t size,\n+\t\t\t size_t start_bit, size_t len)\n+{\n+\treturn __rte_bitset_find(bitset, size, start_bit, len,\n+\t\t\t\t __RTE_BITSET_FIND_FLAG_WRAP);\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Find first cleared bit.\n+ *\n+ * Scans the bitset in the forward direction (i.e., starting at the\n+ * least significant bit), and returns the index of the first '0'.\n+ *\n+ * @param bitset\n+ *   A pointer to the array of words making up the bitset.\n+ * @param size\n+ *   The size of the bitset (in bits).\n+ * @return\n+ *   Returns the index of the least significant '0', or -1 if all\n+ *   bits are '1'.\n+ */\n+\n+__rte_experimental\n+static inline ssize_t\n+rte_bitset_find_first_clear(const uint64_t *bitset, size_t size)\n+{\n+\treturn __rte_bitset_find(bitset, size, 0, size,\n+\t\t\t\t __RTE_BITSET_FIND_FLAG_FIND_CLEAR);\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Find first cleared bit at offset.\n+ *\n+ * Scans the bitset in the forward direction (i.e., starting at the\n+ * least significant bit), starting at an offset @c start_bit into the\n+ * bitset, and returns the index of the first '0' encountered.\n+ *\n+ * @param bitset\n+ *   A pointer to the array of words making up the bitset.\n+ * @param size\n+ *   The size of the bitset (in bits).\n+ * @param start_bit\n+ *   The index of the first bit to check. Must be less than @c size.\n+ * @param len\n+ *   The number of bits to scan. @c start_bit + @c len must be less\n+ *   than or equal to @c size.\n+ * @return\n+ *   Returns the index of the least significant '0', or -1 if all\n+ *   bits are '1'.\n+ */\n+\n+__rte_experimental\n+static inline ssize_t\n+rte_bitset_find_clear(const uint64_t *bitset, size_t size,\n+\t\t\t   size_t start_bit, size_t len)\n+{\n+\treturn __rte_bitset_find(bitset, size, start_bit, len,\n+\t\t\t\t __RTE_BITSET_FIND_FLAG_FIND_CLEAR);\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Find first cleared bit at offset, with wrap-around.\n+ *\n+ * Scans the bitset in the forward direction (i.e., starting at the\n+ * least significant bit), starting at an offset @c start_bit into the\n+ * bitset. If no '0' is encountered before the end of the bitset, the\n+ * search will continue at index 0.\n+ *\n+ * @param bitset\n+ *   A pointer to the array of words making up the bitset.\n+ * @param size\n+ *   The size of the bitset (in bits).\n+ * @param start_bit\n+ *   The index of the first bit to check. Must be less than @c size.\n+ * @param len\n+ *   The number of bits to scan. @c start_bit + @c len must be less\n+ *   than or equal to @c size.\n+ * @return\n+ *   Returns the index of the least significant '0', or -1 if all\n+ *   bits are '1'.\n+ */\n+\n+__rte_experimental\n+static inline ssize_t\n+rte_bitset_find_clear_wrap(const uint64_t *bitset, size_t size,\n+\t\t\t   size_t start_bit, size_t len)\n+{\n+\treturn __rte_bitset_find(bitset, size, start_bit, len,\n+\t\t\t\t __RTE_BITSET_FIND_FLAG_FIND_CLEAR |\n+\t\t\t\t __RTE_BITSET_FIND_FLAG_WRAP);\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Copy bitset.\n+ *\n+ * Copy the bits of the @c src_bitset to the @c dst_bitset.\n+ *\n+ * The bitsets may not overlap and must be of equal size.\n+ *\n+ * @param dst_bitset\n+ *   A pointer to the array of words making up the bitset.\n+ * @param src_bitset\n+ *   A pointer to the array of words making up the bitset.\n+ * @param size\n+ *   The size of the bitsets (in bits).\n+ */\n+\n+__rte_experimental\n+static inline void\n+rte_bitset_copy(uint64_t *__rte_restrict dst_bitset,\n+\t\tconst uint64_t *__rte_restrict src_bitset,\n+\t\tsize_t size)\n+{\n+\trte_memcpy(dst_bitset, src_bitset, RTE_BITSET_SIZE(size));\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Bitwise or two bitsets.\n+ *\n+ * Perform a bitwise OR operation on all bits in the two equal-size\n+ * bitsets @c dst_bitset and @c src_bitset, and store the results in\n+ * @c dst_bitset.\n+ *\n+ * @param dst_bitset\n+ *   A pointer to the destination bitset.\n+ * @param src_bitset\n+ *   A pointer to the source bitset.\n+ * @param size\n+ *   The size of the bitsets (in bits).\n+ */\n+\n+__rte_experimental\n+static inline void\n+rte_bitset_or(uint64_t *dst_bitset, const uint64_t *src_bitset, size_t size)\n+{\n+\tsize_t i;\n+\n+\tfor (i = 0; i < RTE_BITSET_NUM_WORDS(size); i++)\n+\t\tdst_bitset[i] |= src_bitset[i];\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Bitwise and two bitsets.\n+ *\n+ * Perform a bitwise AND operation on all bits in the two equal-size\n+ * bitsets @c dst_bitset and @c src_bitset, and store the results in\n+ * @c dst_bitset.\n+ *\n+ * @param dst_bitset\n+ *   A pointer to the destination bitset.\n+ * @param src_bitset\n+ *   A pointer to the source bitset.\n+ * @param size\n+ *   The size of the bitsets (in bits).\n+ */\n+\n+__rte_experimental\n+static inline void\n+rte_bitset_and(uint64_t *dst_bitset, const uint64_t *src_bitset, size_t size)\n+{\n+\tsize_t i;\n+\n+\tfor (i = 0; i < RTE_BITSET_NUM_WORDS(size); i++)\n+\t\tdst_bitset[i] &= src_bitset[i];\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Bitwise xor two bitsets.\n+ *\n+ * Perform a bitwise XOR operation on all bits in the two equal-size\n+ * bitsets @c dst_bitset and @c src_bitset, and store the results in\n+ * @c dst_bitset.\n+ *\n+ * @param dst_bitset\n+ *   A pointer to the destination bitset.\n+ * @param src_bitset\n+ *   A pointer to the source bitset.\n+ * @param size\n+ *   The size of the bitsets (in bits).\n+ */\n+\n+__rte_experimental\n+static inline void\n+rte_bitset_xor(uint64_t *__rte_restrict dst_bitset,\n+\t       const uint64_t *__rte_restrict src_bitset, size_t size)\n+{\n+\tsize_t i;\n+\n+\tfor (i = 0; i < RTE_BITSET_NUM_WORDS(size); i++)\n+\t\tdst_bitset[i] ^= src_bitset[i];\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Compare two bitsets.\n+ *\n+ * Compare two bitsets for equality.\n+ *\n+ * @param bitset_a\n+ *   A pointer to the destination bitset.\n+ * @param bitset_b\n+ *   A pointer to the source bitset.\n+ * @param size\n+ *   The size of the bitsets (in bits).\n+ */\n+\n+__rte_experimental\n+static inline bool\n+rte_bitset_equal(const uint64_t *bitset_a, const uint64_t *bitset_b,\n+\t\t size_t size)\n+{\n+\tsize_t i;\n+\tuint64_t last_a, last_b;\n+\n+\tfor (i = 0; i < RTE_BITSET_NUM_WORDS(size) - 1; i++)\n+\t\tif (bitset_a[i] != bitset_b[i])\n+\t\t\treturn false;\n+\n+\tlast_a = bitset_a[i] << __RTE_BITSET_UNUSED(size);\n+\tlast_b = bitset_b[i] << __RTE_BITSET_UNUSED(size);\n+\n+\treturn last_a == last_b;\n+}\n+\n+/**\n+ * @warning\n+ * @b EXPERIMENTAL: this API may change without prior notice.\n+ *\n+ * Converts a bitset to a string.\n+ *\n+ * This function prints a string representation of the bitstring to\n+ * the supplied buffer.\n+ *\n+ * Each bit is represented either by '0' or '1' in the output. The\n+ * resulting string is NUL terminated.\n+ *\n+ * @param bitset\n+ *   A pointer to the array of bitset 64-bit words.\n+ * @param size\n+ *   The number of bits the bitset represent.\n+ * @param buf\n+ *   A buffer to hold the output.\n+ * @param capacity\n+ *   The size of the buffer. Must be @c size + 1 or larger.\n+ * @return\n+ *   Returns the number of bytes written (i.e., @c size + 1), or -EINVAL\n+ *   in case the buffer capacity was too small.\n+ */\n+\n+__rte_experimental\n+ssize_t\n+rte_bitset_to_str(const uint64_t *bitset, size_t size, char *buf,\n+\t\t  size_t capacity);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif /* _RTE_BITSET_H_ */\ndiff --git a/lib/eal/version.map b/lib/eal/version.map\nindex 6d6978f108..9136a71c73 100644\n--- a/lib/eal/version.map\n+++ b/lib/eal/version.map\n@@ -430,6 +430,9 @@ EXPERIMENTAL {\n \trte_thread_create_control;\n \trte_thread_set_name;\n \t__rte_eal_trace_generic_blob;\n+\n+\t# added in X.Y\n+\trte_bitset_to_str;\n };\n \n INTERNAL {\n",
    "prefixes": [
        "RFC",
        "v2",
        "1/2"
    ]
}