get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 103732,
    "url": "https://patches.dpdk.org/api/patches/103732/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/20211104104918.490051-2-wojciechx.liguzinski@intel.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": "<20211104104918.490051-2-wojciechx.liguzinski@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20211104104918.490051-2-wojciechx.liguzinski@intel.com",
    "date": "2021-11-04T10:49:16",
    "name": "[v22,1/3] sched: add PIE based congestion management",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "e9d6af7dda117805a802f7321012a7ff3f8acabe",
    "submitter": {
        "id": 2195,
        "url": "https://patches.dpdk.org/api/people/2195/?format=api",
        "name": "Liguzinski, WojciechX",
        "email": "wojciechx.liguzinski@intel.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/20211104104918.490051-2-wojciechx.liguzinski@intel.com/mbox/",
    "series": [
        {
            "id": 20304,
            "url": "https://patches.dpdk.org/api/series/20304/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=20304",
            "date": "2021-11-04T10:49:15",
            "name": "Add PIE support for HQoS library",
            "version": 22,
            "mbox": "https://patches.dpdk.org/series/20304/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/103732/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/103732/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 ADC0CA0548;\n\tThu,  4 Nov 2021 11:49:28 +0100 (CET)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 9324841238;\n\tThu,  4 Nov 2021 11:49:27 +0100 (CET)",
            "from mga07.intel.com (mga07.intel.com [134.134.136.100])\n by mails.dpdk.org (Postfix) with ESMTP id D84A54121E\n for <dev@dpdk.org>; Thu,  4 Nov 2021 11:49:25 +0100 (CET)",
            "from fmsmga004.fm.intel.com ([10.253.24.48])\n by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 04 Nov 2021 03:49:25 -0700",
            "from silpixa00400629.ir.intel.com ([10.237.213.30])\n by fmsmga004.fm.intel.com with ESMTP; 04 Nov 2021 03:49:23 -0700"
        ],
        "X-IronPort-AV": [
            "E=McAfee;i=\"6200,9189,10157\"; a=\"295127951\"",
            "E=Sophos;i=\"5.87,208,1631602800\"; d=\"scan'208\";a=\"295127951\"",
            "E=Sophos;i=\"5.87,208,1631602800\"; d=\"scan'208\";a=\"561223563\""
        ],
        "X-ExtLoop1": "1",
        "From": "\"Liguzinski, WojciechX\" <wojciechx.liguzinski@intel.com>",
        "To": "dev@dpdk.org,\n\tjasvinder.singh@intel.com,\n\tcristian.dumitrescu@intel.com",
        "Cc": "megha.ajmera@intel.com,\n Wojciech Liguzinski <wojciechx.liguzinski@intel.com>",
        "Date": "Thu,  4 Nov 2021 10:49:16 +0000",
        "Message-Id": "<20211104104918.490051-2-wojciechx.liguzinski@intel.com>",
        "X-Mailer": "git-send-email 2.25.1",
        "In-Reply-To": "<20211104104918.490051-1-wojciechx.liguzinski@intel.com>",
        "References": "<20211104104059.489528-1-wojciechx.liguzinski@intel.com>\n <20211104104918.490051-1-wojciechx.liguzinski@intel.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[dpdk-dev] [PATCH v22 1/3] sched: add PIE based congestion\n management",
        "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",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: Wojciech Liguzinski <wojciechx.liguzinski@intel.com>\n\nImplement PIE based congestion management based on rfc8033.\n\nThe Proportional Integral Controller Enhanced (PIE) algorithm works\nby proactively dropping packets randomly.\nPIE is implemented as more advanced queue management is required to\naddress the bufferbloat problem and provide desirable quality of\nservice to users.\n\nTests for PIE code added to test application.\nAdded PIE related information to documentation.\n\nSigned-off-by: Wojciech Liguzinski <wojciechx.liguzinski@intel.com>\nAcked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>\nAcked-by: Jasvinder Singh <jasvinder.singh@intel.com>\n\n--\nChanges in V22:\n- Coding style fixed\n\nChanges in V21:\n- Coding style fixed\n- Patches reorganized according to comments\n\nChanges in V20:\n- Removed API conditional compilation\n- Added flag to indicate cman enabled/disabled\n- Fixed submitter data in patches\n\nChanges in V19:\n- ACKs included in patches\n\nChanges in V18:\n- Resolved merge conflict in lib/sched/meson.build after rebasing ontop of main\n- Reverted whitespace change in app_thread.c - comment from Stephen Hemminger\n\nChanges in V17:\n- Corrected paragraph link naming in qos_framework.rst to fix CI builds\n\nChanges in V16:\n- Fixed 'title underline too short' error in qos_framework.rst\n- Applied __rte_unused macro to parameters in rte_sched_port_pie_dequeue()\n\n---\n app/test/meson.build                         |    4 +\n app/test/test_pie.c                          | 1065 ++++++++++++++++++\n doc/guides/prog_guide/glossary.rst           |    3 +\n doc/guides/prog_guide/qos_framework.rst      |   64 +-\n doc/guides/prog_guide/traffic_management.rst |   13 +-\n drivers/net/softnic/rte_eth_softnic_tm.c     |    6 +-\n lib/sched/meson.build                        |    3 +-\n lib/sched/rte_pie.c                          |   86 ++\n lib/sched/rte_pie.h                          |  398 +++++++\n lib/sched/rte_sched.c                        |  255 +++--\n lib/sched/rte_sched.h                        |   64 +-\n lib/sched/version.map                        |    4 +\n 12 files changed, 1861 insertions(+), 104 deletions(-)\n create mode 100644 app/test/test_pie.c\n create mode 100644 lib/sched/rte_pie.c\n create mode 100644 lib/sched/rte_pie.h",
    "diff": "diff --git a/app/test/meson.build b/app/test/meson.build\nindex 3d9470df23..fe2ceee42a 100644\n--- a/app/test/meson.build\n+++ b/app/test/meson.build\n@@ -115,6 +115,7 @@ test_sources = files(\n         'test_reciprocal_division.c',\n         'test_reciprocal_division_perf.c',\n         'test_red.c',\n+        'test_pie.c',\n         'test_reorder.c',\n         'test_rib.c',\n         'test_rib6.c',\n@@ -249,6 +250,7 @@ fast_tests = [\n         ['prefetch_autotest', true],\n         ['rcu_qsbr_autotest', true],\n         ['red_autotest', true],\n+        ['pie_autotest', true],\n         ['rib_autotest', true],\n         ['rib6_autotest', true],\n         ['ring_autotest', true],\n@@ -300,6 +302,7 @@ perf_test_names = [\n         'fib_slow_autotest',\n         'fib_perf_autotest',\n         'red_all',\n+        'pie_all',\n         'barrier_autotest',\n         'hash_multiwriter_autotest',\n         'timer_racecond_autotest',\n@@ -313,6 +316,7 @@ perf_test_names = [\n         'fib6_perf_autotest',\n         'rcu_qsbr_perf_autotest',\n         'red_perf',\n+        'pie_perf',\n         'distributor_perf_autotest',\n         'pmd_perf_autotest',\n         'stack_perf_autotest',\ndiff --git a/app/test/test_pie.c b/app/test/test_pie.c\nnew file mode 100644\nindex 0000000000..dfa69d1c7e\n--- /dev/null\n+++ b/app/test/test_pie.c\n@@ -0,0 +1,1065 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2010-2014 Intel Corporation\n+ */\n+\n+#include <stdlib.h>\n+#include <stdio.h>\n+#include <string.h>\n+#include <stdint.h>\n+#include <unistd.h>\n+#include <inttypes.h>\n+#include <sys/time.h>\n+#include <time.h>\n+#include <math.h>\n+\n+#include \"test.h\"\n+\n+#include <rte_pie.h>\n+\n+#ifdef __INTEL_COMPILER\n+#pragma warning(disable:2259)       /* conversion may lose significant bits */\n+#pragma warning(disable:181)        /* Arg incompatible with format string */\n+#endif\n+\n+/**< structures for testing rte_pie performance and function */\n+struct test_rte_pie_config {        /**< Test structure for RTE_PIE config */\n+\tstruct rte_pie_config *pconfig; /**< RTE_PIE configuration parameters */\n+\tuint8_t num_cfg;                /**< Number of RTE_PIE configs to test */\n+\tuint16_t qdelay_ref;            /**< Latency Target (milliseconds) */\n+\tuint16_t *dp_update_interval;   /**< Update interval for drop probability\n+\t\t\t\t\t  * (milliseconds)\n+\t\t\t\t\t  */\n+\tuint16_t *max_burst;            /**< Max Burst Allowance (milliseconds) */\n+\tuint16_t tailq_th;              /**< Tailq drop threshold (packet counts) */\n+};\n+\n+struct test_queue {                 /**< Test structure for RTE_PIE Queues */\n+\tstruct rte_pie *pdata_in;       /**< RTE_PIE runtime data input */\n+\tstruct rte_pie *pdata_out;\t\t/**< RTE_PIE runtime data output*/\n+\tuint32_t num_queues;            /**< Number of RTE_PIE queues to test */\n+\tuint32_t *qlen;                 /**< Queue size */\n+\tuint32_t q_ramp_up;             /**< Num of enqueues to ramp up the queue */\n+\tdouble drop_tolerance;          /**< Drop tolerance of packets not enqueued */\n+};\n+\n+struct test_var {                   /**< Test variables used for testing RTE_PIE */\n+\tuint32_t num_iterations;        /**< Number of test iterations */\n+\tuint32_t num_ops;               /**< Number of test operations */\n+\tuint64_t clk_freq;              /**< CPU clock frequency */\n+\tuint32_t *dropped;              /**< Test operations dropped */\n+\tuint32_t *enqueued;             /**< Test operations enqueued */\n+\tuint32_t *dequeued;             /**< Test operations dequeued */\n+};\n+\n+struct test_config {                /**< Primary test structure for RTE_PIE */\n+\tconst char *ifname;             /**< Interface name */\n+\tconst char *msg;                /**< Test message for display */\n+\tconst char *htxt;               /**< Header txt display for result output */\n+\tstruct test_rte_pie_config *tconfig; /**< Test structure for RTE_PIE config */\n+\tstruct test_queue *tqueue;      /**< Test structure for RTE_PIE Queues */\n+\tstruct test_var *tvar;          /**< Test variables used for testing RTE_PIE */\n+\tuint32_t *tlevel;               /**< Queue levels */\n+};\n+\n+enum test_result {\n+\tFAIL = 0,\n+\tPASS\n+};\n+\n+/**< Test structure to define tests to run */\n+struct tests {\n+\tstruct test_config *testcfg;\n+\tenum test_result (*testfn)(struct test_config *cfg);\n+};\n+\n+struct rdtsc_prof {\n+\tuint64_t clk_start;\n+\tuint64_t clk_min;               /**< min clocks */\n+\tuint64_t clk_max;               /**< max clocks */\n+\tuint64_t clk_avgc;              /**< count to calc average */\n+\tdouble clk_avg;                 /**< cumulative sum to calc average */\n+\tconst char *name;\n+};\n+\n+static const uint64_t port_speed_bytes = (10ULL*1000ULL*1000ULL*1000ULL)/8ULL;\n+static double inv_cycles_per_byte;\n+\n+static void init_port_ts(uint64_t cpu_clock)\n+{\n+\tdouble cycles_per_byte = (double)(cpu_clock) / (double)(port_speed_bytes);\n+\tinv_cycles_per_byte = 1.0 / cycles_per_byte;\n+}\n+\n+static uint64_t get_port_ts(void)\n+{\n+\treturn (uint64_t)((double)rte_rdtsc() * inv_cycles_per_byte);\n+}\n+\n+static void rdtsc_prof_init(struct rdtsc_prof *p, const char *name)\n+{\n+\tp->clk_min = (uint64_t)(-1LL);\n+\tp->clk_max = 0;\n+\tp->clk_avg = 0;\n+\tp->clk_avgc = 0;\n+\tp->name = name;\n+}\n+\n+static inline void rdtsc_prof_start(struct rdtsc_prof *p)\n+{\n+\tp->clk_start = rte_rdtsc_precise();\n+}\n+\n+static inline void rdtsc_prof_end(struct rdtsc_prof *p)\n+{\n+\tuint64_t clk_start = rte_rdtsc() - p->clk_start;\n+\n+\tp->clk_avgc++;\n+\tp->clk_avg += (double) clk_start;\n+\n+\tif (clk_start > p->clk_max)\n+\t\tp->clk_max = clk_start;\n+\tif (clk_start < p->clk_min)\n+\t\tp->clk_min = clk_start;\n+}\n+\n+static void rdtsc_prof_print(struct rdtsc_prof *p)\n+{\n+\tif (p->clk_avgc > 0) {\n+\t\tprintf(\"RDTSC stats for %s: n=%\" PRIu64 \", min=%\" PRIu64\n+\t\t\t\t\t\t\",max=%\" PRIu64 \", avg=%.1f\\n\",\n+\t\t\tp->name,\n+\t\t\tp->clk_avgc,\n+\t\t\tp->clk_min,\n+\t\t\tp->clk_max,\n+\t\t\t(p->clk_avg / ((double) p->clk_avgc)));\n+\t}\n+}\n+\n+static uint16_t rte_pie_get_active(const struct rte_pie_config *pie_cfg,\n+\t\t\t\t    struct rte_pie *pie)\n+{\n+    /**< Flag for activating/deactivating pie */\n+\tRTE_SET_USED(pie_cfg);\n+\treturn pie->active;\n+}\n+\n+static void rte_pie_set_active(const struct rte_pie_config *pie_cfg,\n+\t\t\t\t\tstruct rte_pie *pie,\n+\t\t\t\t\tuint16_t active)\n+{\n+    /**< Flag for activating/deactivating pie */\n+\tRTE_SET_USED(pie_cfg);\n+\tpie->active = active;\n+}\n+\n+/**\n+ * Read the drop probability\n+ */\n+static double rte_pie_get_drop_prob(const struct rte_pie_config *pie_cfg,\n+\t\t\t\t    struct rte_pie *pie)\n+{\n+    /**< Current packet drop probability */\n+\tRTE_SET_USED(pie_cfg);\n+\treturn pie->drop_prob;\n+}\n+\n+static double rte_pie_get_avg_dq_time(const struct rte_pie_config *pie_cfg,\n+\t\t\t\t    struct rte_pie *pie)\n+{\n+    /**< Current packet drop probability */\n+\tRTE_SET_USED(pie_cfg);\n+\treturn pie->avg_dq_time;\n+}\n+\n+static double calc_drop_rate(uint32_t enqueued, uint32_t dropped)\n+{\n+\treturn (double)dropped / ((double)enqueued + (double)dropped);\n+}\n+\n+/**\n+ *  check if drop rate matches drop probability within tolerance\n+ */\n+static int check_drop_rate(double *diff, double drop_rate, double drop_prob,\n+\t\t\t\t\t\t\tdouble tolerance)\n+{\n+\tdouble abs_diff = 0.0;\n+\tint ret = 1;\n+\n+\tabs_diff = fabs(drop_rate - drop_prob);\n+\tif ((int)abs_diff == 0) {\n+\t\t*diff = 0.0;\n+\t} else {\n+\t\t*diff = (abs_diff / drop_prob) * 100.0;\n+\t\tif (*diff > tolerance)\n+\t\t\tret = 0;\n+\t}\n+\treturn ret;\n+}\n+\n+/**\n+ * initialize the test rte_pie config\n+ */\n+static enum test_result\n+test_rte_pie_init(struct test_config *tcfg)\n+{\n+\tunsigned int i = 0;\n+\n+\ttcfg->tvar->clk_freq = rte_get_timer_hz();\n+\tinit_port_ts(tcfg->tvar->clk_freq);\n+\n+\tfor (i = 0; i < tcfg->tconfig->num_cfg; i++) {\n+\t\tif (rte_pie_config_init(&tcfg->tconfig->pconfig[i],\n+\t\t\t\t\t(uint16_t)tcfg->tconfig->qdelay_ref,\n+\t\t\t\t\t(uint16_t)tcfg->tconfig->dp_update_interval[i],\n+\t\t\t\t\t(uint16_t)tcfg->tconfig->max_burst[i],\n+\t\t\t\t\t(uint16_t)tcfg->tconfig->tailq_th) != 0) {\n+\t\t\treturn FAIL;\n+\t\t}\n+\t}\n+\n+\t*tcfg->tqueue->qlen = 0;\n+\t*tcfg->tvar->dropped = 0;\n+\t*tcfg->tvar->enqueued = 0;\n+\n+\treturn PASS;\n+}\n+\n+/**\n+ * enqueue until actual queue size reaches target level\n+ */\n+static int\n+increase_qsize(struct rte_pie_config *pie_cfg,\n+\t\t\t\tstruct rte_pie *pie,\n+\t\t\t\tuint32_t *qlen,\n+\t\t\t\tuint32_t pkt_len,\n+\t\t\t\tuint32_t attempts)\n+{\n+\tuint32_t i = 0;\n+\n+\t\tfor (i = 0; i < attempts; i++) {\n+\t\t\tint ret = 0;\n+\n+\t\t\t/**\n+\t\t\t * enqueue\n+\t\t\t */\n+\t\t\tret = rte_pie_enqueue(pie_cfg, pie, *qlen, pkt_len, get_port_ts());\n+\t\t\t/**\n+\t\t\t * check if target actual queue size has been reached\n+\t\t\t */\n+\t\t\tif (ret == 0)\n+\t\t\t\treturn 0;\n+\t\t}\n+\t\t/**\n+\t\t * no success\n+\t\t */\n+\t\treturn -1;\n+}\n+\n+/**\n+ * functional test enqueue/dequeue packets\n+ */\n+static void\n+enqueue_dequeue_func(struct rte_pie_config *pie_cfg,\n+\t\t\t\t\tstruct rte_pie *pie,\n+\t\t\t\t\tuint32_t *qlen,\n+\t\t\t\t\tuint32_t num_ops,\n+\t\t\t\t\tuint32_t *enqueued,\n+\t\t\t\t\tuint32_t *dropped)\n+{\n+\tuint32_t i = 0;\n+\n+\tfor (i = 0; i < num_ops; i++) {\n+\t\tint ret = 0;\n+\n+\t\t/**\n+\t\t * enqueue\n+\t\t */\n+\t\tret = rte_pie_enqueue(pie_cfg, pie, *qlen, sizeof(uint32_t),\n+\t\t\t\t\t\t\tget_port_ts());\n+\t\tif (ret == 0)\n+\t\t\t(*enqueued)++;\n+\t\telse\n+\t\t\t(*dropped)++;\n+\t}\n+}\n+\n+/**\n+ * setup default values for the Functional test structures\n+ */\n+static struct rte_pie_config ft_wpconfig[1];\n+static struct rte_pie ft_rtdata[1];\n+static uint32_t  ft_q[] = {0};\n+static uint32_t  ft_dropped[] = {0};\n+static uint32_t  ft_enqueued[] = {0};\n+static uint16_t ft_max_burst[] = {64};\n+static uint16_t ft_dp_update_interval[] = {150};\n+\n+static struct test_rte_pie_config ft_tconfig =  {\n+\t.pconfig = ft_wpconfig,\n+\t.num_cfg = RTE_DIM(ft_wpconfig),\n+\t.qdelay_ref = 15,\n+\t.dp_update_interval = ft_dp_update_interval,\n+\t.max_burst = ft_max_burst,\n+\t.tailq_th = 15,\n+};\n+\n+static struct test_queue ft_tqueue = {\n+\t.pdata_in = ft_rtdata,\n+\t.num_queues = RTE_DIM(ft_rtdata),\n+\t.qlen = ft_q,\n+\t.q_ramp_up = 10,\n+\t.drop_tolerance = 0,\n+};\n+\n+static struct test_var ft_tvar = {\n+\t.num_iterations = 0,\n+\t.num_ops = 10000,\n+\t.clk_freq = 0,\n+\t.dropped = ft_dropped,\n+\t.enqueued = ft_enqueued,\n+};\n+\n+/**\n+ * Test F1: functional test 1\n+ */\n+static uint32_t ft_tlevels[] =  {6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66,\n+\t\t\t\t72, 78, 84, 90, 96, 102, 108, 114, 120, 126, 132, 138, 144};\n+\n+static struct test_config func_test_config1 = {\n+\t.ifname = \"functional test interface\",\n+\t.msg = \"functional test : use one pie configuration\\n\\n\",\n+\t.htxt = \"                \"\n+\t\"drop probability \"\n+\t\"enqueued    \"\n+\t\"dropped     \"\n+\t\"drop prob % \"\n+\t\"drop rate % \"\n+\t\"diff %      \"\n+\t\"tolerance % \"\n+\t\"active  \"\n+\t\"\\n\",\n+\t.tconfig = &ft_tconfig,\n+\t.tqueue = &ft_tqueue,\n+\t.tvar = &ft_tvar,\n+\t.tlevel = ft_tlevels,\n+};\n+\n+static enum test_result func_test1(struct test_config *tcfg)\n+{\n+\tenum test_result result = PASS;\n+\tuint32_t i = 0;\n+\n+\tprintf(\"%s\", tcfg->msg);\n+\n+\tif (test_rte_pie_init(tcfg) != PASS) {\n+\t\tresult = FAIL;\n+\t\tgoto out;\n+\t}\n+\n+\tprintf(\"%s\", tcfg->htxt);\n+\n+\t/**\n+\t * reset rte_pie run-time data\n+\t */\n+\trte_pie_rt_data_init(tcfg->tqueue->pdata_in);\n+\trte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1);\n+\t*tcfg->tvar->enqueued = 0;\n+\t*tcfg->tvar->dropped = 0;\n+\n+\tif (increase_qsize(&tcfg->tconfig->pconfig[i],\n+\t\t\t\ttcfg->tqueue->pdata_in,\n+\t\t\t\ttcfg->tqueue->qlen,\n+\t\t\t\ttcfg->tlevel[i],\n+\t\t\t\ttcfg->tqueue->q_ramp_up) != 0) {\n+\t\tfprintf(stderr, \"Fail: increase qsize\\n\");\n+\t\tresult = FAIL;\n+\t\tgoto out;\n+\t}\n+\n+\tfor (i = 0; i < RTE_DIM(ft_tlevels); i++) {\n+\t\tconst char *label = NULL;\n+\t\tuint16_t prob = 0;\n+\t\tuint16_t active = 0;\n+\t\tdouble drop_rate = 1.0;\n+\t\tdouble drop_prob = 0.0;\n+\t\tdouble diff = 0.0;\n+\n+\t\tenqueue_dequeue_func(&tcfg->tconfig->pconfig[i],\n+\t\t\t\t     tcfg->tqueue->pdata_in,\n+\t\t\t\t     tcfg->tqueue->qlen,\n+\t\t\t\t     tcfg->tvar->num_ops,\n+\t\t\t\t     tcfg->tvar->enqueued,\n+\t\t\t\t     tcfg->tvar->dropped);\n+\n+\t\tdrop_rate = calc_drop_rate(*tcfg->tvar->enqueued,\n+\t\t\t\t\t\t\t*tcfg->tvar->dropped);\n+\t\tdrop_prob = rte_pie_get_drop_prob(NULL, tcfg->tqueue->pdata_in);\n+\n+\t\tif (drop_prob != 0) {\n+\t\t\tfprintf(stderr, \"Fail: check drop prob\\n\");\n+\t\t\tresult = FAIL;\n+\t\t}\n+\n+\t\tif (drop_rate != 0) {\n+\t\t\tfprintf(stderr, \"Fail: check drop rate\\n\");\n+\t\t\tresult = FAIL;\n+\t\t}\n+\n+\t\tlabel = \"Summary           \";\n+\t\tactive = rte_pie_get_active(NULL, tcfg->tqueue->pdata_in);\n+\t\tprintf(\"%s%-16u%-12u%-12u%-12.4lf%-12.4lf%-12.4lf%-12.4lf%-8i\\n\",\n+\t\t\t\tlabel, prob, *tcfg->tvar->enqueued, *tcfg->tvar->dropped,\n+\t\t\t\tdrop_prob * 100.0, drop_rate * 100.0, diff,\n+\t\t\t\t(double)tcfg->tqueue->drop_tolerance, active);\n+\t}\n+out:\n+\treturn result;\n+}\n+\n+/**\n+ * Test F2: functional test 2\n+ */\n+static uint32_t ft2_tlevel[] = {127};\n+static uint16_t ft2_max_burst[] = {1, 2, 8, 16, 32, 64, 128, 256, 512, 1024};\n+static uint16_t ft2_dp_update_interval[] = {\n+\t\t\t\t10, 20, 50, 150, 300, 600, 900, 1200, 1500, 3000};\n+static struct rte_pie_config ft2_pconfig[10];\n+\n+static struct test_rte_pie_config ft2_tconfig =  {\n+\t.pconfig = ft2_pconfig,\n+\t.num_cfg = RTE_DIM(ft2_pconfig),\n+\t.qdelay_ref = 15,\n+\t.dp_update_interval = ft2_dp_update_interval,\n+\t.max_burst = ft2_max_burst,\n+\t.tailq_th = 15,\n+};\n+\n+static struct test_config func_test_config2 = {\n+\t.ifname = \"functional test 2 interface\",\n+\t.msg = \"functional test 2 : use several PIE configurations,\\n\"\n+\t\"\t\t    compare drop rate to drop probability\\n\\n\",\n+\t.htxt = \"PIE config     \"\n+\t\"avg queue size \"\n+\t\"enqueued       \"\n+\t\"dropped        \"\n+\t\"drop prob %    \"\n+\t\"drop rate %    \"\n+\t\"diff %         \"\n+\t\"tolerance %    \"\n+\t\"\\n\",\n+\t.tconfig = &ft2_tconfig,\n+\t.tqueue = &ft_tqueue,\n+\t.tvar = &ft_tvar,\n+\t.tlevel = ft2_tlevel,\n+};\n+\n+static enum test_result func_test2(struct test_config *tcfg)\n+{\n+\tenum test_result result = PASS;\n+\tuint32_t i = 0;\n+\n+\tprintf(\"%s\", tcfg->msg);\n+\n+\tprintf(\"%s\", tcfg->htxt);\n+\n+\tfor (i = 0; i < tcfg->tconfig->num_cfg; i++) {\n+\t\tuint32_t avg = 0;\n+\t\tdouble drop_rate = 0.0;\n+\t\tdouble drop_prob = 0.0;\n+\t\tdouble diff = 0.0;\n+\n+\t\tif (test_rte_pie_init(tcfg) != PASS) {\n+\t\t\tresult = FAIL;\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\trte_pie_rt_data_init(tcfg->tqueue->pdata_in);\n+\t\trte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1);\n+\t\t*tcfg->tvar->enqueued = 0;\n+\t\t*tcfg->tvar->dropped = 0;\n+\n+\t\tif (increase_qsize(&tcfg->tconfig->pconfig[i],\n+\t\t\t\t\ttcfg->tqueue->pdata_in,\n+\t\t\t\t\ttcfg->tqueue->qlen,\n+\t\t\t\t\t*tcfg->tlevel,\n+\t\t\t\t\ttcfg->tqueue->q_ramp_up) != 0) {\n+\t\t\tresult = FAIL;\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tenqueue_dequeue_func(&tcfg->tconfig->pconfig[i],\n+\t\t\t\t     tcfg->tqueue->pdata_in,\n+\t\t\t\t     tcfg->tqueue->qlen,\n+\t\t\t\t     tcfg->tvar->num_ops,\n+\t\t\t\t     tcfg->tvar->enqueued,\n+\t\t\t\t     tcfg->tvar->dropped);\n+\n+\t\tavg = rte_pie_get_avg_dq_time(NULL, tcfg->tqueue->pdata_in);\n+\n+\t\tdrop_rate = calc_drop_rate(*tcfg->tvar->enqueued,\n+\t\t\t\t\t\t\t*tcfg->tvar->dropped);\n+\t\tdrop_prob = rte_pie_get_drop_prob(NULL, tcfg->tqueue->pdata_in);\n+\n+\t\tif (!check_drop_rate(&diff, drop_rate, drop_prob,\n+\t\t\t\t (double)tcfg->tqueue->drop_tolerance)) {\n+\t\t\tfprintf(stderr, \"Fail: drop rate outside tolerance\\n\");\n+\t\t\tresult = FAIL;\n+\t\t}\n+\n+\t\tprintf(\"%-15u%-15u%-15u%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf\\n\",\n+\t\t\t\ti, avg, *tcfg->tvar->enqueued, *tcfg->tvar->dropped,\n+\t\t\t\tdrop_prob * 100.0, drop_rate * 100.0, diff,\n+\t\t\t\t(double)tcfg->tqueue->drop_tolerance);\n+\t}\n+out:\n+\treturn result;\n+}\n+\n+static uint32_t ft3_qlen[] = {100};\n+\n+static struct test_rte_pie_config ft3_tconfig =  {\n+\t.pconfig = ft_wpconfig,\n+\t.num_cfg = RTE_DIM(ft_wpconfig),\n+\t.qdelay_ref = 15,\n+\t.dp_update_interval = ft_dp_update_interval,\n+\t.max_burst = ft_max_burst,\n+\t.tailq_th = 15,\n+};\n+\n+static struct test_queue ft3_tqueue = {\n+\t.pdata_in = ft_rtdata,\n+\t.num_queues = RTE_DIM(ft_rtdata),\n+\t.qlen = ft3_qlen,\n+\t.q_ramp_up = 10,\n+\t.drop_tolerance = 0,\n+};\n+\n+static struct test_var ft3_tvar = {\n+\t.num_iterations = 0,\n+\t.num_ops = 10000,\n+\t.clk_freq = 0,\n+\t.dropped = ft_dropped,\n+\t.enqueued = ft_enqueued,\n+};\n+\n+/**\n+ * Test F3: functional test 3\n+ */\n+static uint32_t ft3_tlevels[] =  {64, 127, 222};\n+\n+static struct test_config func_test_config3 = {\n+\t.ifname = \"functional test interface\",\n+\t.msg = \"functional test 2 : use one pie configuration\\n\"\n+\t\t\t\"using non zero qlen\\n\\n\",\n+\t.htxt = \"                \"\n+\t\"drop probability \"\n+\t\"enqueued    \"\n+\t\"dropped     \"\n+\t\"drop prob % \"\n+\t\"drop rate % \"\n+\t\"diff %      \"\n+\t\"tolerance % \"\n+\t\"active  \"\n+\t\"\\n\",\n+\t.tconfig = &ft3_tconfig,\n+\t.tqueue = &ft3_tqueue,\n+\t.tvar = &ft3_tvar,\n+\t.tlevel = ft3_tlevels,\n+};\n+\n+static enum test_result func_test3(struct test_config *tcfg)\n+{\n+\tenum test_result result = PASS;\n+\tuint32_t i = 0;\n+\n+\tprintf(\"%s\", tcfg->msg);\n+\n+\tif (test_rte_pie_init(tcfg) != PASS) {\n+\t\tresult = FAIL;\n+\t\tgoto out;\n+\t}\n+\n+\tprintf(\"%s\", tcfg->htxt);\n+\n+\t/**\n+\t * reset rte_pie run-time data\n+\t */\n+\trte_pie_rt_data_init(tcfg->tqueue->pdata_in);\n+\trte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1);\n+\t*tcfg->tvar->enqueued = 0;\n+\t*tcfg->tvar->dropped = 0;\n+\n+\tif (increase_qsize(&tcfg->tconfig->pconfig[i],\n+\t\t\t\ttcfg->tqueue->pdata_in,\n+\t\t\t\ttcfg->tqueue->qlen,\n+\t\t\t\ttcfg->tlevel[i],\n+\t\t\t\ttcfg->tqueue->q_ramp_up) != 0) {\n+\t\tfprintf(stderr, \"Fail: increase qsize\\n\");\n+\t\tresult = FAIL;\n+\t\tgoto out;\n+\t}\n+\n+\tfor (i = 0; i < RTE_DIM(ft_tlevels); i++) {\n+\t\tconst char *label = NULL;\n+\t\tuint16_t prob = 0;\n+\t\tuint16_t active = 0;\n+\t\tdouble drop_rate = 1.0;\n+\t\tdouble drop_prob = 0.0;\n+\t\tdouble diff = 0.0;\n+\n+\t\tenqueue_dequeue_func(&tcfg->tconfig->pconfig[i],\n+\t\t\t\t     tcfg->tqueue->pdata_in,\n+\t\t\t\t     tcfg->tqueue->qlen,\n+\t\t\t\t     tcfg->tvar->num_ops,\n+\t\t\t\t     tcfg->tvar->enqueued,\n+\t\t\t\t     tcfg->tvar->dropped);\n+\n+\t\tdrop_rate = calc_drop_rate(*tcfg->tvar->enqueued,\n+\t\t\t\t\t\t*tcfg->tvar->dropped);\n+\t\tdrop_prob = rte_pie_get_drop_prob(NULL, tcfg->tqueue->pdata_in);\n+\n+\t\tif (drop_prob != 0) {\n+\t\t\tfprintf(stderr, \"Fail: check drop prob\\n\");\n+\t\t\tresult = FAIL;\n+\t\t}\n+\n+\t\tif (drop_rate != 0) {\n+\t\t\tfprintf(stderr, \"Fail: check drop rate\\n\");\n+\t\t\tresult = FAIL;\n+\t\t}\n+\n+\t\tlabel = \"Summary           \";\n+\t\tactive = rte_pie_get_active(NULL, tcfg->tqueue->pdata_in);\n+\t\tprintf(\"%s%-16u%-12u%-12u%-12.4lf%-12.4lf%-12.4lf%-12.4lf%-8i\\n\",\n+\t\t\t\tlabel, prob, *tcfg->tvar->enqueued, *tcfg->tvar->dropped,\n+\t\t\t\tdrop_prob * 100.0, drop_rate * 100.0, diff,\n+\t\t\t\t(double)tcfg->tqueue->drop_tolerance, active);\n+\t}\n+out:\n+\treturn result;\n+}\n+\n+/**\n+ * setup default values for the Performance test structures\n+ */\n+static struct rte_pie_config pt_wrconfig[1];\n+static struct rte_pie pt_rtdata[1];\n+static struct rte_pie pt_wtdata[1];\n+static uint32_t pt_q[] = {0};\n+static uint32_t pt_dropped[] = {0};\n+static uint32_t pt_enqueued[] = {0};\n+static uint32_t pt_dequeued[] = {0};\n+static uint16_t pt_max_burst[] = {64};\n+static uint16_t pt_dp_update_interval[] = {150};\n+\n+static struct test_rte_pie_config pt_tconfig =  {\n+\t.pconfig = pt_wrconfig,\n+\t.num_cfg = RTE_DIM(pt_wrconfig),\n+\t.qdelay_ref = 15,\n+\t.dp_update_interval = pt_dp_update_interval,\n+\t.max_burst = pt_max_burst,\n+\t.tailq_th = 150,\n+};\n+\n+static struct test_queue pt_tqueue = {\n+\t.pdata_in = pt_rtdata,\n+\t.num_queues = RTE_DIM(pt_rtdata),\n+\t.qlen = pt_q,\n+\t.q_ramp_up = 1000000,\n+\t.drop_tolerance = 0,  /* 0 percent */\n+};\n+\n+static struct test_rte_pie_config pt_tconfig2 =  {\n+\t.pconfig = pt_wrconfig,\n+\t.num_cfg = RTE_DIM(pt_wrconfig),\n+\t.qdelay_ref = 15,\n+\t.dp_update_interval = pt_dp_update_interval,\n+\t.max_burst = pt_max_burst,\n+\t.tailq_th = 150,\n+};\n+\n+static struct test_queue pt_tqueue2 = {\n+\t.pdata_in = pt_rtdata,\n+\t.pdata_out = pt_wtdata,\n+\t.num_queues = RTE_DIM(pt_rtdata),\n+\t.qlen = pt_q,\n+\t.q_ramp_up = 1000000,\n+\t.drop_tolerance = 0,  /* 0 percent */\n+};\n+\n+/**\n+ * enqueue/dequeue packets\n+ * aka\n+ *  rte_sched_port_enqueue(port, in_mbufs, 10);\n+ *\trte_sched_port_dequeue(port, out_mbufs, 10);\n+ */\n+static void enqueue_dequeue_perf(struct rte_pie_config *pie_cfg,\n+\t\t\t\t struct rte_pie *pie_in,\n+\t\t\t\t struct rte_pie *pie_out,\n+\t\t\t\t uint32_t *qlen,\n+\t\t\t\t uint32_t num_ops,\n+\t\t\t\t uint32_t *enqueued,\n+\t\t\t\t uint32_t *dropped,\n+\t\t\t\t uint32_t *dequeued,\n+\t\t\t\t struct rdtsc_prof *prof)\n+{\n+\tuint32_t i = 0;\n+\n+\tif (pie_cfg == NULL) {\n+\t\tprintf(\"%s: Error: PIE configuration cannot be empty.\\n\", __func__);\n+\t\treturn;\n+\t}\n+\n+\tif (pie_in == NULL) {\n+\t\tprintf(\"%s: Error: PIE enqueue data cannot be empty.\\n\", __func__);\n+\t\treturn;\n+\t}\n+\n+\tfor (i = 0; i < num_ops; i++) {\n+\t\tuint64_t ts = 0;\n+\t\tint ret = 0;\n+\n+\t\t/**\n+\t\t * enqueue\n+\t\t */\n+\t\tts = get_port_ts();\n+\t\trdtsc_prof_start(prof);\n+\t\tret = rte_pie_enqueue(pie_cfg, pie_in, *qlen,\n+\t\t\t\t\t\t\t\t1000*sizeof(uint32_t), ts);\n+\t\trdtsc_prof_end(prof);\n+\n+\t\tif (ret == 0)\n+\t\t\t(*enqueued)++;\n+\t\telse\n+\t\t\t(*dropped)++;\n+\n+\t\tif (pie_out != NULL) {\n+\t\t\tts = get_port_ts();\n+\t\t\trdtsc_prof_start(prof);\n+\t\t\trte_pie_dequeue(pie_out, 1000*sizeof(uint32_t), ts);\n+\t\t\trdtsc_prof_end(prof);\n+\n+\t\t\t(*dequeued)++;\n+\t\t}\n+\t}\n+}\n+\n+/**\n+ * Setup test structures for tests P1\n+ * performance tests 1\n+ */\n+static uint32_t pt1_tlevel[] = {80};\n+\n+static struct test_var perf1_tvar = {\n+\t.num_iterations = 0,\n+\t.num_ops = 30000,\n+\t.clk_freq = 0,\n+\t.dropped = pt_dropped,\n+\t.enqueued = pt_enqueued\n+};\n+\n+static struct test_config perf_test_config = {\n+\t.ifname = \"performance test 1 interface\",\n+\t.msg = \"performance test 1 : use one PIE configuration,\\n\"\n+\t\"\t\t     measure enqueue performance\\n\\n\",\n+\t.tconfig = &pt_tconfig,\n+\t.tqueue = &pt_tqueue,\n+\t.tvar = &perf1_tvar,\n+\t.tlevel = pt1_tlevel,\n+};\n+\n+/**\n+ * Performance test function to measure enqueue performance.\n+ *\n+ */\n+static enum test_result perf_test(struct test_config *tcfg)\n+{\n+\tenum test_result result = PASS;\n+\tstruct rdtsc_prof prof = {0, 0, 0, 0, 0.0, NULL};\n+\tuint32_t total = 0;\n+\n+\tprintf(\"%s\", tcfg->msg);\n+\n+\trdtsc_prof_init(&prof, \"enqueue\");\n+\n+\tif (test_rte_pie_init(tcfg) != PASS) {\n+\t\tresult = FAIL;\n+\t\tgoto out;\n+\t}\n+\n+\t/**\n+\t * initialize the rte_pie run time data structure\n+\t */\n+\trte_pie_rt_data_init(tcfg->tqueue->pdata_in);\n+\trte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1);\n+\t*tcfg->tvar->enqueued = 0;\n+\t*tcfg->tvar->dropped = 0;\n+\n+\tenqueue_dequeue_perf(tcfg->tconfig->pconfig,\n+\t\t\t     tcfg->tqueue->pdata_in,\n+\t\t\t\t NULL,\n+\t\t\t     tcfg->tqueue->qlen,\n+\t\t\t     tcfg->tvar->num_ops,\n+\t\t\t     tcfg->tvar->enqueued,\n+\t\t\t     tcfg->tvar->dropped,\n+\t\t\t\t tcfg->tvar->dequeued,\n+\t\t\t     &prof);\n+\n+\ttotal = *tcfg->tvar->enqueued + *tcfg->tvar->dropped;\n+\n+\tprintf(\"\\ntotal: %u, enqueued: %u (%.2lf%%), dropped: %u (%.2lf%%)\\n\",\n+\t\t\ttotal, *tcfg->tvar->enqueued,\n+\t\t\t((double)(*tcfg->tvar->enqueued) / (double)total) * 100.0,\n+\t\t\t*tcfg->tvar->dropped,\n+\t\t\t((double)(*tcfg->tvar->dropped) / (double)total) * 100.0);\n+\n+\trdtsc_prof_print(&prof);\n+out:\n+\treturn result;\n+}\n+\n+\n+\n+/**\n+ * Setup test structures for tests P2\n+ * performance tests 2\n+ */\n+static uint32_t pt2_tlevel[] = {80};\n+\n+static struct test_var perf2_tvar = {\n+\t.num_iterations = 0,\n+\t.num_ops = 30000,\n+\t.clk_freq = 0,\n+\t.dropped = pt_dropped,\n+\t.enqueued = pt_enqueued,\n+\t.dequeued = pt_dequeued\n+};\n+\n+static struct test_config perf_test_config2 = {\n+\t.ifname = \"performance test 2 interface\",\n+\t.msg = \"performance test 2 : use one PIE configuration,\\n\"\n+\t\"\t\t     measure enqueue & dequeue performance\\n\\n\",\n+\t.tconfig = &pt_tconfig2,\n+\t.tqueue = &pt_tqueue2,\n+\t.tvar = &perf2_tvar,\n+\t.tlevel = pt2_tlevel,\n+};\n+\n+/**\n+ * Performance test function to measure enqueue & dequeue performance.\n+ *\n+ */\n+static enum test_result perf_test2(struct test_config *tcfg)\n+{\n+\tenum test_result result = PASS;\n+\tstruct rdtsc_prof prof = {0, 0, 0, 0, 0.0, NULL};\n+\tuint32_t total = 0;\n+\n+\tprintf(\"%s\", tcfg->msg);\n+\n+\trdtsc_prof_init(&prof, \"enqueue\");\n+\n+\tif (test_rte_pie_init(tcfg) != PASS) {\n+\t\tresult = FAIL;\n+\t\tgoto out;\n+\t}\n+\n+\t/**\n+\t * initialize the rte_pie run time data structure\n+\t */\n+\trte_pie_rt_data_init(tcfg->tqueue->pdata_in);\n+\trte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1);\n+\t*tcfg->tvar->enqueued = 0;\n+\t*tcfg->tvar->dequeued = 0;\n+\t*tcfg->tvar->dropped = 0;\n+\n+\tenqueue_dequeue_perf(tcfg->tconfig->pconfig,\n+\t\t\t\t tcfg->tqueue->pdata_in,\n+\t\t\t\t tcfg->tqueue->pdata_out,\n+\t\t\t\t tcfg->tqueue->qlen,\n+\t\t\t\t tcfg->tvar->num_ops,\n+\t\t\t\t tcfg->tvar->enqueued,\n+\t\t\t\t tcfg->tvar->dropped,\n+\t\t\t\t tcfg->tvar->dequeued,\n+\t\t\t\t &prof);\n+\n+\ttotal = *tcfg->tvar->enqueued + *tcfg->tvar->dropped;\n+\n+\tprintf(\"\\ntotal: %u, dequeued: %u (%.2lf%%), dropped: %u (%.2lf%%)\\n\",\n+\t\t\ttotal, *tcfg->tvar->dequeued,\n+\t\t\t((double)(*tcfg->tvar->dequeued) / (double)total) * 100.0,\n+\t\t\t*tcfg->tvar->dropped,\n+\t\t\t((double)(*tcfg->tvar->dropped) / (double)total) * 100.0);\n+\n+\trdtsc_prof_print(&prof);\n+out:\n+\treturn result;\n+}\n+\n+/**\n+ * define the functional tests to be executed fast\n+ */\n+struct tests func_pie_tests_quick[] = {\n+\t{ &func_test_config1, func_test1 },\n+\t{ &func_test_config2, func_test2 },\n+};\n+\n+/**\n+ * define the functional and performance tests to be executed\n+ */\n+struct tests func_pie_tests[] = {\n+\t{ &func_test_config1, func_test1 },\n+\t{ &func_test_config2, func_test2 },\n+\t{ &func_test_config3, func_test3 },\n+};\n+\n+struct tests perf_pie_tests[] = {\n+\t{ &perf_test_config, perf_test },\n+\t{ &perf_test_config2, perf_test2 },\n+};\n+\n+/**\n+ * function to execute the required pie tests\n+ */\n+static void run_tests(struct tests *test_type, uint32_t test_count,\n+\t\t\t\t\t\tuint32_t *num_tests, uint32_t *num_pass)\n+{\n+\tenum test_result result = PASS;\n+\tuint32_t i = 0;\n+\tstatic const char *bar_str = \"-------------------------------------\"\n+\t\t\t\t\t\t\"-------------------------------------------\";\n+\tstatic const char *bar_pass_str = \"-------------------------------------\"\n+\t\t\t\t\t\t\"<pass>-------------------------------------\";\n+\tstatic const char *bar_fail_str = \"-------------------------------------\"\n+\t\t\t\t\t\t\"<fail>-------------------------------------\";\n+\n+\tfor (i = 0; i < test_count; i++) {\n+\t\tprintf(\"\\n%s\\n\", bar_str);\n+\t\tresult = test_type[i].testfn(test_type[i].testcfg);\n+\t\t(*num_tests)++;\n+\t\tif (result == PASS) {\n+\t\t\t(*num_pass)++;\n+\t\t\t\tprintf(\"%s\\n\", bar_pass_str);\n+\t\t} else {\n+\t\t\tprintf(\"%s\\n\", bar_fail_str);\n+\t\t}\n+\t}\n+}\n+\n+/**\n+ * check if functions accept invalid parameters\n+ *\n+ * First, all functions will be called without initialized PIE\n+ * Then, all of them will be called with NULL/invalid parameters\n+ *\n+ * Some functions are not tested as they are performance-critical and thus\n+ * don't do any parameter checking.\n+ */\n+static int\n+test_invalid_parameters(void)\n+{\n+\tstruct rte_pie_config config;\n+\tstatic const char *shf_str = \"rte_pie_config_init should have failed!\";\n+\tstatic const char *shf_rt_str = \"rte_pie_rt_data_init should have failed!\";\n+\n+\t/* NULL config */\n+\tif (rte_pie_rt_data_init(NULL) == 0) {\n+\t\tprintf(\"%i: %s\\n\", __LINE__, shf_rt_str);\n+\t\treturn -1;\n+\t}\n+\n+\t/* NULL config */\n+\tif (rte_pie_config_init(NULL, 0, 0, 0, 0) == 0) {\n+\t\tprintf(\"%i%s\\n\", __LINE__, shf_str);\n+\t\treturn -1;\n+\t}\n+\n+\t/* qdelay_ref <= 0 */\n+\tif (rte_pie_config_init(&config, 0, 1, 1, 1) == 0) {\n+\t\tprintf(\"%i%s\\n\", __LINE__, shf_str);\n+\t\treturn -1;\n+\t}\n+\n+\t/* dp_update_interval <= 0 */\n+\tif (rte_pie_config_init(&config, 1, 0, 1, 1) == 0) {\n+\t\tprintf(\"%i%s\\n\", __LINE__, shf_str);\n+\t\treturn -1;\n+\t}\n+\n+\t/* max_burst <= 0 */\n+\tif (rte_pie_config_init(&config, 1, 1, 0, 1) == 0) {\n+\t\tprintf(\"%i%s\\n\", __LINE__, shf_str);\n+\t\treturn -1;\n+\t}\n+\n+\t/* tailq_th <= 0 */\n+\tif (rte_pie_config_init(&config, 1, 1, 1, 0) == 0) {\n+\t\tprintf(\"%i%s\\n\", __LINE__, shf_str);\n+\t\treturn -1;\n+\t}\n+\n+\tRTE_SET_USED(config);\n+\n+\treturn 0;\n+}\n+\n+static void\n+show_stats(const uint32_t num_tests, const uint32_t num_pass)\n+{\n+\tif (num_pass == num_tests)\n+\t\tprintf(\"[total: %u, pass: %u]\\n\", num_tests, num_pass);\n+\telse\n+\t\tprintf(\"[total: %u, pass: %u, fail: %u]\\n\", num_tests, num_pass,\n+\t\t       num_tests - num_pass);\n+}\n+\n+static int\n+tell_the_result(const uint32_t num_tests, const uint32_t num_pass)\n+{\n+\treturn (num_pass == num_tests) ? 0 : 1;\n+}\n+\n+static int\n+test_pie(void)\n+{\n+\tuint32_t num_tests = 0;\n+\tuint32_t num_pass = 0;\n+\n+\tif (test_invalid_parameters() < 0)\n+\t\treturn -1;\n+\n+\trun_tests(func_pie_tests_quick, RTE_DIM(func_pie_tests_quick),\n+\t\t  &num_tests, &num_pass);\n+\tshow_stats(num_tests, num_pass);\n+\treturn tell_the_result(num_tests, num_pass);\n+}\n+\n+static int\n+test_pie_perf(void)\n+{\n+\tuint32_t num_tests = 0;\n+\tuint32_t num_pass = 0;\n+\n+\trun_tests(perf_pie_tests, RTE_DIM(perf_pie_tests), &num_tests, &num_pass);\n+\tshow_stats(num_tests, num_pass);\n+\treturn tell_the_result(num_tests, num_pass);\n+}\n+\n+static int\n+test_pie_all(void)\n+{\n+\tuint32_t num_tests = 0;\n+\tuint32_t num_pass = 0;\n+\n+\tif (test_invalid_parameters() < 0)\n+\t\treturn -1;\n+\n+\trun_tests(func_pie_tests, RTE_DIM(func_pie_tests), &num_tests, &num_pass);\n+\trun_tests(perf_pie_tests, RTE_DIM(perf_pie_tests), &num_tests, &num_pass);\n+\tshow_stats(num_tests, num_pass);\n+\treturn tell_the_result(num_tests, num_pass);\n+}\n+\n+REGISTER_TEST_COMMAND(pie_autotest, test_pie);\n+REGISTER_TEST_COMMAND(pie_perf, test_pie_perf);\n+REGISTER_TEST_COMMAND(pie_all, test_pie_all);\ndiff --git a/doc/guides/prog_guide/glossary.rst b/doc/guides/prog_guide/glossary.rst\nindex 7044a7df2a..fb0910ba5b 100644\n--- a/doc/guides/prog_guide/glossary.rst\n+++ b/doc/guides/prog_guide/glossary.rst\n@@ -158,6 +158,9 @@ PCI\n PHY\n    An abbreviation for the physical layer of the OSI model.\n \n+PIE\n+   Proportional Integral Controller Enhanced (RFC8033)\n+\n pktmbuf\n    An *mbuf* carrying a network packet.\n \ndiff --git a/doc/guides/prog_guide/qos_framework.rst b/doc/guides/prog_guide/qos_framework.rst\nindex 3b8a1184b0..7c37b78804 100644\n--- a/doc/guides/prog_guide/qos_framework.rst\n+++ b/doc/guides/prog_guide/qos_framework.rst\n@@ -56,7 +56,8 @@ A functional description of each block is provided in the following table.\n    |   |                        |                                                                                |\n    +---+------------------------+--------------------------------------------------------------------------------+\n    | 7 | Dropper                | Congestion management using the Random Early Detection (RED) algorithm         |\n-   |   |                        | (specified by the Sally Floyd - Van Jacobson paper) or Weighted RED (WRED).    |\n+   |   |                        | (specified by the Sally Floyd - Van Jacobson paper) or Weighted RED (WRED)     |\n+   |   |                        | or Proportional Integral Controller Enhanced (PIE).                            |\n    |   |                        | Drop packets based on the current scheduler queue load level and packet        |\n    |   |                        | priority. When congestion is experienced, lower priority packets are dropped   |\n    |   |                        | first.                                                                         |\n@@ -421,7 +422,7 @@ No input packet can be part of more than one pipeline stage at a given time.\n The congestion management scheme implemented by the enqueue pipeline described above is very basic:\n packets are enqueued until a specific queue becomes full,\n then all the packets destined to the same queue are dropped until packets are consumed (by the dequeue operation).\n-This can be improved by enabling RED/WRED as part of the enqueue pipeline which looks at the queue occupancy and\n+This can be improved by enabling RED/WRED or PIE as part of the enqueue pipeline which looks at the queue occupancy and\n packet priority in order to yield the enqueue/drop decision for a specific packet\n (as opposed to enqueuing all packets / dropping all packets indiscriminately).\n \n@@ -1155,13 +1156,13 @@ If the number of queues is small,\n then the performance of the port scheduler for the same level of active traffic is expected to be worse than\n the performance of a small set of message passing queues.\n \n-.. _Dropper:\n+.. _Droppers:\n \n-Dropper\n--------\n+Droppers\n+--------\n \n The purpose of the DPDK dropper is to drop packets arriving at a packet scheduler to avoid congestion.\n-The dropper supports the Random Early Detection (RED),\n+The dropper supports the Proportional Integral Controller Enhanced (PIE), Random Early Detection (RED),\n Weighted Random Early Detection (WRED) and tail drop algorithms.\n :numref:`figure_blk_diag_dropper` illustrates how the dropper integrates with the scheduler.\n The DPDK currently does not support congestion management\n@@ -1174,9 +1175,13 @@ so the dropper provides the only method for congestion avoidance.\n    High-level Block Diagram of the DPDK Dropper\n \n \n-The dropper uses the Random Early Detection (RED) congestion avoidance algorithm as documented in the reference publication.\n-The purpose of the RED algorithm is to monitor a packet queue,\n+The dropper uses one of two congestion avoidance algorithms:\n+   - the Random Early Detection (RED) as documented in the reference publication.\n+   - the Proportional Integral Controller Enhanced (PIE) as documented in RFC8033 publication.\n+\n+The purpose of the RED/PIE algorithm is to monitor a packet queue,\n determine the current congestion level in the queue and decide whether an arriving packet should be enqueued or dropped.\n+\n The RED algorithm uses an Exponential Weighted Moving Average (EWMA) filter to compute average queue size which\n gives an indication of the current congestion level in the queue.\n \n@@ -1192,7 +1197,7 @@ This occurs when a packet queue has reached maximum capacity and cannot store an\n In this situation, all arriving packets are dropped.\n \n The flow through the dropper is illustrated in :numref:`figure_flow_tru_droppper`.\n-The RED/WRED algorithm is exercised first and tail drop second.\n+The RED/WRED/PIE algorithm is exercised first and tail drop second.\n \n .. _figure_flow_tru_droppper:\n \n@@ -1200,6 +1205,16 @@ The RED/WRED algorithm is exercised first and tail drop second.\n \n    Flow Through the Dropper\n \n+The PIE algorithm periodically updates the drop probability based on the latency samples.\n+The current latency sample but also analyze whether the latency is trending up or down.\n+This is the classical Proportional Integral (PI) controller method, which is known for\n+eliminating steady state errors.\n+\n+When a congestion period ends, we might be left with a high drop probability with light\n+packet arrivals. Hence, the PIE algorithm includes a mechanism by which the drop probability\n+decays exponentially (rather than linearly) when the system is not congested.\n+This would help the drop probability converge to 0 more quickly, while the PI controller ensures\n+that it would eventually reach zero.\n \n The use cases supported by the dropper are:\n \n@@ -1253,6 +1268,35 @@ to a mark probability of 1/10 (that is, 1 in 10 packets will be dropped).\n The EWMA filter weight parameter is specified as an inverse log value,\n for example, a filter weight parameter value of 9 corresponds to a filter weight of 1/29.\n \n+A PIE configuration contains the parameters given in :numref:`table_qos_16a`.\n+\n+.. _table_qos_16a:\n+\n+.. table:: PIE Configuration Parameters\n+\n+   +--------------------------+---------+---------+------------------+\n+   | Parameter                | Minimum | Maximum | Default          |\n+   |                          |         |         |                  |\n+   +==========================+=========+=========+==================+\n+   | Queue delay reference    | 1       | uint16  | 15               |\n+   | Latency Target Value     |         |         |                  |\n+   | Unit: ms                 |         |         |                  |\n+   +--------------------------+---------+---------+------------------+\n+   | Max Burst Allowance      | 1       | uint16  | 150              |\n+   | Unit: ms                 |         |         |                  |\n+   +--------------------------+---------+---------+------------------+\n+   | Tail Drop Threshold      | 1       | uint16  | 64               |\n+   | Unit: bytes              |         |         |                  |\n+   +--------------------------+---------+---------+------------------+\n+   | Period to calculate      | 1       | uint16  | 15               |\n+   | drop probability         |         |         |                  |\n+   | Unit: ms                 |         |         |                  |\n+   +--------------------------+---------+---------+------------------+\n+\n+The meaning of these parameters is explained in more detail in the next sections.\n+The format of these parameters as specified to the dropper module API.\n+They could made self calculated for fine tuning, within the apps.\n+\n .. _Enqueue_Operation:\n \n Enqueue Operation\n@@ -1396,7 +1440,7 @@ As can be seen, the floating-point implementation achieved the worst performance\n    | Method                                                                             | Relative Performance |\n    |                                                                                    |                      |\n    +====================================================================================+======================+\n-   | Current dropper method (see :ref:`Section 23.3.2.1.3 <Dropper>`)                   | 100%                 |\n+   | Current dropper method (see :ref:`Section 23.3.2.1.3 <Droppers>`)                  | 100%                 |\n    |                                                                                    |                      |\n    +------------------------------------------------------------------------------------+----------------------+\n    | Fixed-point method with small (512B) look-up table                                 | 148%                 |\ndiff --git a/doc/guides/prog_guide/traffic_management.rst b/doc/guides/prog_guide/traffic_management.rst\nindex 05b34d93a5..c356791a45 100644\n--- a/doc/guides/prog_guide/traffic_management.rst\n+++ b/doc/guides/prog_guide/traffic_management.rst\n@@ -22,6 +22,7 @@ Main features:\n   shared (by multiple nodes) shapers\n * Congestion management for hierarchy leaf nodes: algorithms of tail drop, head\n   drop, WRED, private (per node) and shared (by multiple nodes) WRED contexts\n+  and PIE.\n * Packet marking: IEEE 802.1q (VLAN DEI), IETF RFC 3168 (IPv4/IPv6 ECN for TCP\n   and SCTP), IETF RFC 2597 (IPv4 / IPv6 DSCP)\n \n@@ -103,8 +104,9 @@ Congestion Management\n Congestion management is used to control the admission of packets into a packet\n queue or group of packet queues on congestion. The congestion management\n algorithms that are supported are: Tail Drop, Head Drop and Weighted Random\n-Early Detection (WRED). They are made available for every leaf node in the\n-hierarchy, subject to the specific implementation supporting them.\n+Early Detection (WRED), Proportional Integral Controller Enhanced (PIE).\n+They are made available for every leaf node in the hierarchy, subject to\n+the specific implementation supporting them.\n On request of writing a new packet into the current queue while the queue is\n full, the Tail Drop algorithm drops the new packet while leaving the queue\n unmodified, as opposed to the Head Drop* algorithm, which drops the packet\n@@ -128,6 +130,13 @@ The configuration of WRED private and shared contexts is done through the\n definition of WRED profiles. Any WRED profile can be used by one or several\n WRED contexts (either private or shared).\n \n+The Proportional Integral Controller Enhanced (PIE) algorithm works by proactively\n+dropping packets randomly. Calculated drop probability is updated periodically,\n+based on latency measured and desired and whether the queuing latency is currently\n+trending up or down. Queuing latency can be obtained using direct measurement or\n+on estimations calculated from the queue length and dequeue rate. The random drop\n+is triggered by a packet's arrival before enqueuing into a queue.\n+\n \n Packet Marking\n --------------\ndiff --git a/drivers/net/softnic/rte_eth_softnic_tm.c b/drivers/net/softnic/rte_eth_softnic_tm.c\nindex 90baba15ce..e74092ce7f 100644\n--- a/drivers/net/softnic/rte_eth_softnic_tm.c\n+++ b/drivers/net/softnic/rte_eth_softnic_tm.c\n@@ -420,7 +420,7 @@ pmd_tm_node_type_get(struct rte_eth_dev *dev,\n \treturn 0;\n }\n \n-#ifdef RTE_SCHED_RED\n+#ifdef RTE_SCHED_CMAN\n #define WRED_SUPPORTED\t\t\t\t\t\t1\n #else\n #define WRED_SUPPORTED\t\t\t\t\t\t0\n@@ -2306,7 +2306,7 @@ tm_tc_wred_profile_get(struct rte_eth_dev *dev, uint32_t tc_id)\n \treturn NULL;\n }\n \n-#ifdef RTE_SCHED_RED\n+#ifdef RTE_SCHED_CMAN\n \n static void\n wred_profiles_set(struct rte_eth_dev *dev, uint32_t subport_id)\n@@ -2321,7 +2321,7 @@ wred_profiles_set(struct rte_eth_dev *dev, uint32_t subport_id)\n \tfor (tc_id = 0; tc_id < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; tc_id++)\n \t\tfor (color = RTE_COLOR_GREEN; color < RTE_COLORS; color++) {\n \t\t\tstruct rte_red_params *dst =\n-\t\t\t\t&pp->red_params[tc_id][color];\n+\t\t\t\t&pp->cman_params->red_params[tc_id][color];\n \t\t\tstruct tm_wred_profile *src_wp =\n \t\t\t\ttm_tc_wred_profile_get(dev, tc_id);\n \t\t\tstruct rte_tm_red_params *src =\ndiff --git a/lib/sched/meson.build b/lib/sched/meson.build\nindex 8ced4547aa..df75db51ed 100644\n--- a/lib/sched/meson.build\n+++ b/lib/sched/meson.build\n@@ -7,11 +7,12 @@ if is_windows\n     subdir_done()\n endif\n \n-sources = files('rte_sched.c', 'rte_red.c', 'rte_approx.c')\n+sources = files('rte_sched.c', 'rte_red.c', 'rte_approx.c', 'rte_pie.c')\n headers = files(\n         'rte_approx.h',\n         'rte_red.h',\n         'rte_sched.h',\n         'rte_sched_common.h',\n+        'rte_pie.h',\n )\n deps += ['mbuf', 'meter']\ndiff --git a/lib/sched/rte_pie.c b/lib/sched/rte_pie.c\nnew file mode 100644\nindex 0000000000..934e9aee50\n--- /dev/null\n+++ b/lib/sched/rte_pie.c\n@@ -0,0 +1,86 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2020 Intel Corporation\n+ */\n+\n+#include <stdlib.h>\n+\n+#include \"rte_pie.h\"\n+#include <rte_common.h>\n+#include <rte_cycles.h>\n+#include <rte_malloc.h>\n+\n+#ifdef __INTEL_COMPILER\n+#pragma warning(disable:2259) /* conversion may lose significant bits */\n+#endif\n+\n+int\n+rte_pie_rt_data_init(struct rte_pie *pie)\n+{\n+\tif (pie == NULL) {\n+\t\t/* Allocate memory to use the PIE data structure */\n+\t\tpie = rte_malloc(NULL, sizeof(struct rte_pie), 0);\n+\n+\t\tif (pie == NULL)\n+\t\t\tRTE_LOG(ERR, SCHED, \"%s: Memory allocation fails\\n\", __func__);\n+\n+\t\treturn -1;\n+\t}\n+\n+\tpie->active = 0;\n+\tpie->in_measurement = 0;\n+\tpie->departed_bytes_count = 0;\n+\tpie->start_measurement = 0;\n+\tpie->last_measurement = 0;\n+\tpie->qlen = 0;\n+\tpie->avg_dq_time = 0;\n+\tpie->burst_allowance = 0;\n+\tpie->qdelay_old = 0;\n+\tpie->drop_prob = 0;\n+\tpie->accu_prob = 0;\n+\n+\treturn 0;\n+}\n+\n+int\n+rte_pie_config_init(struct rte_pie_config *pie_cfg,\n+\tconst uint16_t qdelay_ref,\n+\tconst uint16_t dp_update_interval,\n+\tconst uint16_t max_burst,\n+\tconst uint16_t tailq_th)\n+{\n+\tuint64_t tsc_hz = rte_get_tsc_hz();\n+\n+\tif (pie_cfg == NULL)\n+\t\treturn -1;\n+\n+\tif (qdelay_ref <= 0) {\n+\t\tRTE_LOG(ERR, SCHED,\n+\t\t\t\"%s: Incorrect value for qdelay_ref\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (dp_update_interval <= 0) {\n+\t\tRTE_LOG(ERR, SCHED,\n+\t\t\t\"%s: Incorrect value for dp_update_interval\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (max_burst <= 0) {\n+\t\tRTE_LOG(ERR, SCHED,\n+\t\t\t\"%s: Incorrect value for max_burst\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (tailq_th <= 0) {\n+\t\tRTE_LOG(ERR, SCHED,\n+\t\t\t\"%s: Incorrect value for tailq_th\\n\", __func__);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tpie_cfg->qdelay_ref = (tsc_hz * qdelay_ref) / 1000;\n+\tpie_cfg->dp_update_interval = (tsc_hz * dp_update_interval) / 1000;\n+\tpie_cfg->max_burst = (tsc_hz * max_burst) / 1000;\n+\tpie_cfg->tailq_th = tailq_th;\n+\n+\treturn 0;\n+}\ndiff --git a/lib/sched/rte_pie.h b/lib/sched/rte_pie.h\nnew file mode 100644\nindex 0000000000..68f1b96192\n--- /dev/null\n+++ b/lib/sched/rte_pie.h\n@@ -0,0 +1,398 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2020 Intel Corporation\n+ */\n+\n+#ifndef __RTE_PIE_H_INCLUDED__\n+#define __RTE_PIE_H_INCLUDED__\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+/**\n+ * @file\n+ * RTE Proportional Integral controller Enhanced (PIE)\n+ *\n+ *\n+ ***/\n+\n+#include <stdint.h>\n+\n+#include <rte_random.h>\n+#include <rte_debug.h>\n+#include <rte_cycles.h>\n+\n+#define RTE_DQ_THRESHOLD   16384   /**< Queue length threshold (2^14)\n+\t\t\t\t     * to start measurement cycle (bytes)\n+\t\t\t\t     */\n+#define RTE_DQ_WEIGHT      0.25    /**< Weight (RTE_DQ_THRESHOLD/2^16) to compute dequeue rate */\n+#define RTE_ALPHA          0.125   /**< Weights in drop probability calculations */\n+#define RTE_BETA           1.25    /**< Weights in drop probability calculations */\n+#define RTE_RAND_MAX      ~0LLU    /**< Max value of the random number */\n+\n+\n+/**\n+ * PIE configuration parameters passed by user\n+ *\n+ */\n+struct rte_pie_params {\n+\tuint16_t qdelay_ref;           /**< Latency Target (milliseconds) */\n+\tuint16_t dp_update_interval;   /**< Update interval for drop probability (milliseconds) */\n+\tuint16_t max_burst;            /**< Max Burst Allowance (milliseconds) */\n+\tuint16_t tailq_th;             /**< Tailq drop threshold (packet counts) */\n+};\n+\n+/**\n+ * PIE configuration parameters\n+ *\n+ */\n+struct rte_pie_config {\n+\tuint64_t qdelay_ref;           /**< Latency Target (in CPU cycles.) */\n+\tuint64_t dp_update_interval;   /**< Update interval for drop probability (in CPU cycles) */\n+\tuint64_t max_burst;            /**< Max Burst Allowance (in CPU cycles.) */\n+\tuint16_t tailq_th;             /**< Tailq drop threshold (packet counts) */\n+};\n+\n+/**\n+ * PIE run-time data\n+ */\n+struct rte_pie {\n+\tuint16_t active;               /**< Flag for activating/deactivating pie */\n+\tuint16_t in_measurement;       /**< Flag for activation of measurement cycle */\n+\tuint32_t departed_bytes_count; /**< Number of bytes departed in current measurement cycle */\n+\tuint64_t start_measurement;    /**< Time to start to measurement cycle (in cpu cycles) */\n+\tuint64_t last_measurement;     /**< Time of last measurement (in cpu cycles) */\n+\tuint64_t qlen;                 /**< Queue length (packets count) */\n+\tuint64_t qlen_bytes;           /**< Queue length (bytes count) */\n+\tuint64_t avg_dq_time;          /**< Time averaged dequeue rate (in cpu cycles) */\n+\tuint32_t burst_allowance;      /**< Current burst allowance (bytes) */\n+\tuint64_t qdelay_old;           /**< Old queue delay (bytes) */\n+\tdouble drop_prob;              /**< Current packet drop probability */\n+\tdouble accu_prob;              /**< Accumulated packet drop probability */\n+};\n+\n+/**\n+ * @brief Initialises run-time data\n+ *\n+ * @param pie [in,out] data pointer to PIE runtime data\n+ *\n+ * @return Operation status\n+ * @retval 0 success\n+ * @retval !0 error\n+ */\n+int\n+__rte_experimental\n+rte_pie_rt_data_init(struct rte_pie *pie);\n+\n+/**\n+ * @brief Configures a single PIE configuration parameter structure.\n+ *\n+ * @param pie_cfg [in,out] config pointer to a PIE configuration parameter structure\n+ * @param qdelay_ref [in]  latency target(milliseconds)\n+ * @param dp_update_interval [in] update interval for drop probability (milliseconds)\n+ * @param max_burst [in] maximum burst allowance (milliseconds)\n+ * @param tailq_th [in] tail drop threshold for the queue (number of packets)\n+ *\n+ * @return Operation status\n+ * @retval 0 success\n+ * @retval !0 error\n+ */\n+int\n+__rte_experimental\n+rte_pie_config_init(struct rte_pie_config *pie_cfg,\n+\tconst uint16_t qdelay_ref,\n+\tconst uint16_t dp_update_interval,\n+\tconst uint16_t max_burst,\n+\tconst uint16_t tailq_th);\n+\n+/**\n+ * @brief Decides packet enqueue when queue is empty\n+ *\n+ * Note: packet is never dropped in this particular case.\n+ *\n+ * @param pie_cfg [in] config pointer to a PIE configuration parameter structure\n+ * @param pie [in, out] data pointer to PIE runtime data\n+ * @param pkt_len [in] packet length in bytes\n+ *\n+ * @return Operation status\n+ * @retval 0 enqueue the packet\n+ * @retval !0 drop the packet\n+ */\n+static int\n+__rte_experimental\n+rte_pie_enqueue_empty(const struct rte_pie_config *pie_cfg,\n+\tstruct rte_pie *pie,\n+\tuint32_t pkt_len)\n+{\n+\tRTE_ASSERT(pkt_len != NULL);\n+\n+\t/* Update the PIE qlen parameter */\n+\tpie->qlen++;\n+\tpie->qlen_bytes += pkt_len;\n+\n+\t/**\n+\t * If the queue has been idle for a while, turn off PIE and Reset counters\n+\t */\n+\tif ((pie->active == 1) &&\n+\t\t(pie->qlen < (pie_cfg->tailq_th * 0.1))) {\n+\t\tpie->active =  0;\n+\t\tpie->in_measurement = 0;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * @brief make a decision to drop or enqueue a packet based on probability\n+ *        criteria\n+ *\n+ * @param pie_cfg [in] config pointer to a PIE configuration parameter structure\n+ * @param pie [in, out] data pointer to PIE runtime data\n+ * @param time [in] current time (measured in cpu cycles)\n+ */\n+static void\n+__rte_experimental\n+_calc_drop_probability(const struct rte_pie_config *pie_cfg,\n+\tstruct rte_pie *pie, uint64_t time)\n+{\n+\tuint64_t qdelay_ref = pie_cfg->qdelay_ref;\n+\n+\t/* Note: can be implemented using integer multiply.\n+\t * DQ_THRESHOLD is power of 2 value.\n+\t */\n+\tuint64_t current_qdelay = pie->qlen * (pie->avg_dq_time >> 14);\n+\n+\tdouble p = RTE_ALPHA * (current_qdelay - qdelay_ref) +\n+\t\tRTE_BETA * (current_qdelay - pie->qdelay_old);\n+\n+\tif (pie->drop_prob < 0.000001)\n+\t\tp = p * 0.00048828125;              /* (1/2048) = 0.00048828125 */\n+\telse if (pie->drop_prob < 0.00001)\n+\t\tp = p * 0.001953125;                /* (1/512) = 0.001953125  */\n+\telse if (pie->drop_prob < 0.0001)\n+\t\tp = p * 0.0078125;                  /* (1/128) = 0.0078125  */\n+\telse if (pie->drop_prob < 0.001)\n+\t\tp = p * 0.03125;                    /* (1/32) = 0.03125   */\n+\telse if (pie->drop_prob < 0.01)\n+\t\tp = p * 0.125;                      /* (1/8) = 0.125    */\n+\telse if (pie->drop_prob < 0.1)\n+\t\tp = p * 0.5;                        /* (1/2) = 0.5    */\n+\n+\tif (pie->drop_prob >= 0.1 && p > 0.02)\n+\t\tp = 0.02;\n+\n+\tpie->drop_prob += p;\n+\n+\tdouble qdelay = qdelay_ref * 0.5;\n+\n+\t/*  Exponentially decay drop prob when congestion goes away  */\n+\tif ((double)current_qdelay < qdelay && pie->qdelay_old < qdelay)\n+\t\tpie->drop_prob *= 0.98;     /* 1 - 1/64 is sufficient */\n+\n+\t/* Bound drop probability */\n+\tif (pie->drop_prob < 0)\n+\t\tpie->drop_prob = 0;\n+\tif (pie->drop_prob > 1)\n+\t\tpie->drop_prob = 1;\n+\n+\tpie->qdelay_old = current_qdelay;\n+\tpie->last_measurement = time;\n+\n+\tuint64_t burst_allowance = pie->burst_allowance - pie_cfg->dp_update_interval;\n+\n+\tpie->burst_allowance = (burst_allowance > 0) ? burst_allowance : 0;\n+}\n+\n+/**\n+ * @brief make a decision to drop or enqueue a packet based on probability\n+ *        criteria\n+ *\n+ * @param pie_cfg [in] config pointer to a PIE configuration parameter structure\n+ * @param pie [in, out] data pointer to PIE runtime data\n+ *\n+ * @return operation status\n+ * @retval 0 enqueue the packet\n+ * @retval 1 drop the packet\n+ */\n+static inline int\n+__rte_experimental\n+_rte_pie_drop(const struct rte_pie_config *pie_cfg,\n+\tstruct rte_pie *pie)\n+{\n+\tuint64_t rand_value;\n+\tdouble qdelay = pie_cfg->qdelay_ref * 0.5;\n+\n+\t/* PIE is active but the queue is not congested: return 0 */\n+\tif (((pie->qdelay_old < qdelay) && (pie->drop_prob < 0.2)) ||\n+\t\t(pie->qlen <= (pie_cfg->tailq_th * 0.1)))\n+\t\treturn 0;\n+\n+\tif (pie->drop_prob == 0)\n+\t\tpie->accu_prob = 0;\n+\n+\t/* For practical reasons, drop probability can be further scaled according\n+\t * to packet size, but one needs to set a bound to avoid unnecessary bias\n+\t * Random drop\n+\t */\n+\tpie->accu_prob += pie->drop_prob;\n+\n+\tif (pie->accu_prob < 0.85)\n+\t\treturn 0;\n+\n+\tif (pie->accu_prob >= 8.5)\n+\t\treturn 1;\n+\n+\trand_value = rte_rand()/RTE_RAND_MAX;\n+\n+\tif ((double)rand_value < pie->drop_prob) {\n+\t\tpie->accu_prob = 0;\n+\t\treturn 1;\n+\t}\n+\n+\t/* No drop */\n+\treturn 0;\n+}\n+\n+/**\n+ * @brief Decides if new packet should be enqeued or dropped for non-empty queue\n+ *\n+ * @param pie_cfg [in] config pointer to a PIE configuration parameter structure\n+ * @param pie [in,out] data pointer to PIE runtime data\n+ * @param pkt_len [in] packet length in bytes\n+ * @param time [in] current time (measured in cpu cycles)\n+ *\n+ * @return Operation status\n+ * @retval 0 enqueue the packet\n+ * @retval 1 drop the packet based on max threshold criterion\n+ * @retval 2 drop the packet based on mark probability criterion\n+ */\n+static inline int\n+__rte_experimental\n+rte_pie_enqueue_nonempty(const struct rte_pie_config *pie_cfg,\n+\tstruct rte_pie *pie,\n+\tuint32_t pkt_len,\n+\tconst uint64_t time)\n+{\n+\t/* Check queue space against the tail drop threshold */\n+\tif (pie->qlen >= pie_cfg->tailq_th) {\n+\n+\t\tpie->accu_prob = 0;\n+\t\treturn 1;\n+\t}\n+\n+\tif (pie->active) {\n+\t\t/* Update drop probability after certain interval */\n+\t\tif ((time - pie->last_measurement) >= pie_cfg->dp_update_interval)\n+\t\t\t_calc_drop_probability(pie_cfg, pie, time);\n+\n+\t\t/* Decide whether packet to be dropped or enqueued */\n+\t\tif (_rte_pie_drop(pie_cfg, pie) && pie->burst_allowance == 0)\n+\t\t\treturn 2;\n+\t}\n+\n+\t/* When queue occupancy is over a certain threshold, turn on PIE */\n+\tif ((pie->active == 0) &&\n+\t\t(pie->qlen >= (pie_cfg->tailq_th * 0.1))) {\n+\t\tpie->active = 1;\n+\t\tpie->qdelay_old = 0;\n+\t\tpie->drop_prob = 0;\n+\t\tpie->in_measurement = 1;\n+\t\tpie->departed_bytes_count = 0;\n+\t\tpie->avg_dq_time = 0;\n+\t\tpie->last_measurement = time;\n+\t\tpie->burst_allowance = pie_cfg->max_burst;\n+\t\tpie->accu_prob = 0;\n+\t\tpie->start_measurement = time;\n+\t}\n+\n+\t/* when queue has been idle for a while, turn off PIE and Reset counters */\n+\tif (pie->active == 1 &&\n+\t\tpie->qlen < (pie_cfg->tailq_th * 0.1)) {\n+\t\tpie->active =  0;\n+\t\tpie->in_measurement = 0;\n+\t}\n+\n+\t/* Update PIE qlen parameter */\n+\tpie->qlen++;\n+\tpie->qlen_bytes += pkt_len;\n+\n+\t/* No drop */\n+\treturn 0;\n+}\n+\n+/**\n+ * @brief Decides if new packet should be enqeued or dropped\n+ * Updates run time data and gives verdict whether to enqueue or drop the packet.\n+ *\n+ * @param pie_cfg [in] config pointer to a PIE configuration parameter structure\n+ * @param pie [in,out] data pointer to PIE runtime data\n+ * @param qlen [in] queue length\n+ * @param pkt_len [in] packet length in bytes\n+ * @param time [in] current time stamp (measured in cpu cycles)\n+ *\n+ * @return Operation status\n+ * @retval 0 enqueue the packet\n+ * @retval 1 drop the packet based on drop probility criteria\n+ */\n+static inline int\n+__rte_experimental\n+rte_pie_enqueue(const struct rte_pie_config *pie_cfg,\n+\tstruct rte_pie *pie,\n+\tconst unsigned int qlen,\n+\tuint32_t pkt_len,\n+\tconst uint64_t time)\n+{\n+\tRTE_ASSERT(pie_cfg != NULL);\n+\tRTE_ASSERT(pie != NULL);\n+\n+\tif (qlen != 0)\n+\t\treturn rte_pie_enqueue_nonempty(pie_cfg, pie, pkt_len, time);\n+\telse\n+\t\treturn rte_pie_enqueue_empty(pie_cfg, pie, pkt_len);\n+}\n+\n+/**\n+ * @brief PIE rate estimation method\n+ * Called on each packet departure.\n+ *\n+ * @param pie [in] data pointer to PIE runtime data\n+ * @param pkt_len [in] packet length in bytes\n+ * @param time [in] current time stamp in cpu cycles\n+ */\n+static inline void\n+__rte_experimental\n+rte_pie_dequeue(struct rte_pie *pie,\n+\tuint32_t pkt_len,\n+\tuint64_t time)\n+{\n+\t/* Dequeue rate estimation */\n+\tif (pie->in_measurement) {\n+\t\tpie->departed_bytes_count += pkt_len;\n+\n+\t\t/* Start a new measurement cycle when enough packets */\n+\t\tif (pie->departed_bytes_count >= RTE_DQ_THRESHOLD) {\n+\t\t\tuint64_t dq_time = time - pie->start_measurement;\n+\n+\t\t\tif (pie->avg_dq_time == 0)\n+\t\t\t\tpie->avg_dq_time = dq_time;\n+\t\t\telse\n+\t\t\t\tpie->avg_dq_time = dq_time * RTE_DQ_WEIGHT + pie->avg_dq_time\n+\t\t\t\t\t* (1 - RTE_DQ_WEIGHT);\n+\n+\t\t\tpie->in_measurement = 0;\n+\t\t}\n+\t}\n+\n+\t/* Start measurement cycle when enough data in the queue */\n+\tif ((pie->qlen_bytes >= RTE_DQ_THRESHOLD) && (pie->in_measurement == 0)) {\n+\t\tpie->in_measurement = 1;\n+\t\tpie->start_measurement = time;\n+\t\tpie->departed_bytes_count = 0;\n+\t}\n+}\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+\n+#endif /* __RTE_PIE_H_INCLUDED__ */\ndiff --git a/lib/sched/rte_sched.c b/lib/sched/rte_sched.c\nindex a858f61f95..807c6a4807 100644\n--- a/lib/sched/rte_sched.c\n+++ b/lib/sched/rte_sched.c\n@@ -89,8 +89,12 @@ struct rte_sched_queue {\n \n struct rte_sched_queue_extra {\n \tstruct rte_sched_queue_stats stats;\n-#ifdef RTE_SCHED_RED\n-\tstruct rte_red red;\n+#ifdef RTE_SCHED_CMAN\n+\tRTE_STD_C11\n+\tunion {\n+\t\tstruct rte_red red;\n+\t\tstruct rte_pie pie;\n+\t};\n #endif\n };\n \n@@ -183,8 +187,15 @@ struct rte_sched_subport {\n \t/* Pipe queues size */\n \tuint16_t qsize[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];\n \n-#ifdef RTE_SCHED_RED\n-\tstruct rte_red_config red_config[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE][RTE_COLORS];\n+#ifdef RTE_SCHED_CMAN\n+\tbool cman_enabled;\n+\tenum rte_sched_cman_mode cman;\n+\n+\tRTE_STD_C11\n+\tunion {\n+\t\tstruct rte_red_config red_config[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE][RTE_COLORS];\n+\t\tstruct rte_pie_config pie_config[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];\n+\t};\n #endif\n \n \t/* Scheduling loop detection */\n@@ -1078,6 +1089,90 @@ rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)\n \trte_free(port);\n }\n \n+#ifdef RTE_SCHED_CMAN\n+static int\n+rte_sched_red_config(struct rte_sched_port *port,\n+\tstruct rte_sched_subport *s,\n+\tstruct rte_sched_subport_params *params,\n+\tuint32_t n_subports)\n+{\n+\tuint32_t i;\n+\n+\tfor (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {\n+\n+\t\tuint32_t j;\n+\n+\t\tfor (j = 0; j < RTE_COLORS; j++) {\n+\t\t\t/* if min/max are both zero, then RED is disabled */\n+\t\t\tif ((params->cman_params->red_params[i][j].min_th |\n+\t\t\t\t params->cman_params->red_params[i][j].max_th) == 0) {\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\tif (rte_red_config_init(&s->red_config[i][j],\n+\t\t\t\tparams->cman_params->red_params[i][j].wq_log2,\n+\t\t\t\tparams->cman_params->red_params[i][j].min_th,\n+\t\t\t\tparams->cman_params->red_params[i][j].max_th,\n+\t\t\t\tparams->cman_params->red_params[i][j].maxp_inv) != 0) {\n+\t\t\t\trte_sched_free_memory(port, n_subports);\n+\n+\t\t\t\tRTE_LOG(NOTICE, SCHED,\n+\t\t\t\t\"%s: RED configuration init fails\\n\", __func__);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t}\n+\t}\n+\ts->cman = RTE_SCHED_CMAN_RED;\n+\treturn 0;\n+}\n+\n+static int\n+rte_sched_pie_config(struct rte_sched_port *port,\n+\tstruct rte_sched_subport *s,\n+\tstruct rte_sched_subport_params *params,\n+\tuint32_t n_subports)\n+{\n+\tuint32_t i;\n+\n+\tfor (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {\n+\t\tif (params->cman_params->pie_params[i].tailq_th > params->qsize[i]) {\n+\t\t\tRTE_LOG(NOTICE, SCHED,\n+\t\t\t\"%s: PIE tailq threshold incorrect\\n\", __func__);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tif (rte_pie_config_init(&s->pie_config[i],\n+\t\t\tparams->cman_params->pie_params[i].qdelay_ref,\n+\t\t\tparams->cman_params->pie_params[i].dp_update_interval,\n+\t\t\tparams->cman_params->pie_params[i].max_burst,\n+\t\t\tparams->cman_params->pie_params[i].tailq_th) != 0) {\n+\t\t\trte_sched_free_memory(port, n_subports);\n+\n+\t\t\tRTE_LOG(NOTICE, SCHED,\n+\t\t\t\"%s: PIE configuration init fails\\n\", __func__);\n+\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t}\n+\ts->cman = RTE_SCHED_CMAN_PIE;\n+\treturn 0;\n+}\n+\n+static int\n+rte_sched_cman_config(struct rte_sched_port *port,\n+\tstruct rte_sched_subport *s,\n+\tstruct rte_sched_subport_params *params,\n+\tuint32_t n_subports)\n+{\n+\tif (params->cman_params->cman_mode == RTE_SCHED_CMAN_RED)\n+\t\treturn rte_sched_red_config(port, s, params, n_subports);\n+\n+\telse if (params->cman_params->cman_mode == RTE_SCHED_CMAN_PIE)\n+\t\treturn rte_sched_pie_config(port, s, params, n_subports);\n+\n+\treturn -EINVAL;\n+}\n+#endif\n+\n int\n rte_sched_subport_config(struct rte_sched_port *port,\n \tuint32_t subport_id,\n@@ -1167,29 +1262,17 @@ rte_sched_subport_config(struct rte_sched_port *port,\n \t\ts->n_pipe_profiles = params->n_pipe_profiles;\n \t\ts->n_max_pipe_profiles = params->n_max_pipe_profiles;\n \n-#ifdef RTE_SCHED_RED\n-\t\tfor (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {\n-\t\t\tuint32_t j;\n-\n-\t\t\tfor (j = 0; j < RTE_COLORS; j++) {\n-\t\t\t/* if min/max are both zero, then RED is disabled */\n-\t\t\t\tif ((params->red_params[i][j].min_th |\n-\t\t\t\t     params->red_params[i][j].max_th) == 0) {\n-\t\t\t\t\tcontinue;\n-\t\t\t\t}\n-\n-\t\t\t\tif (rte_red_config_init(&s->red_config[i][j],\n-\t\t\t\t    params->red_params[i][j].wq_log2,\n-\t\t\t\t    params->red_params[i][j].min_th,\n-\t\t\t\t    params->red_params[i][j].max_th,\n-\t\t\t\t    params->red_params[i][j].maxp_inv) != 0) {\n-\t\t\t\t\tRTE_LOG(NOTICE, SCHED,\n-\t\t\t\t\t\"%s: RED configuration init fails\\n\",\n-\t\t\t\t\t__func__);\n-\t\t\t\t\tret = -EINVAL;\n-\t\t\t\t\tgoto out;\n-\t\t\t\t}\n+#ifdef RTE_SCHED_CMAN\n+\t\tif (params->cman_params != NULL) {\n+\t\t\ts->cman_enabled = true;\n+\t\t\tstatus = rte_sched_cman_config(port, s, params, n_subports);\n+\t\t\tif (status) {\n+\t\t\t\tRTE_LOG(NOTICE, SCHED,\n+\t\t\t\t\t\"%s: CMAN configuration fails\\n\", __func__);\n+\t\t\t\treturn status;\n \t\t\t}\n+\t\t} else {\n+\t\t\ts->cman_enabled = false;\n \t\t}\n #endif\n \n@@ -1718,30 +1801,19 @@ rte_sched_port_update_subport_stats(struct rte_sched_port *port,\n \tsubport->stats.n_bytes_tc[tc_index] += pkt_len;\n }\n \n-#ifdef RTE_SCHED_RED\n static inline void\n rte_sched_port_update_subport_stats_on_drop(struct rte_sched_port *port,\n \tstruct rte_sched_subport *subport,\n \tuint32_t qindex,\n \tstruct rte_mbuf *pkt,\n-\tuint32_t red)\n-#else\n-static inline void\n-rte_sched_port_update_subport_stats_on_drop(struct rte_sched_port *port,\n-\tstruct rte_sched_subport *subport,\n-\tuint32_t qindex,\n-\tstruct rte_mbuf *pkt,\n-\t__rte_unused uint32_t red)\n-#endif\n+\t__rte_unused uint32_t n_pkts_cman_dropped)\n {\n \tuint32_t tc_index = rte_sched_port_pipe_tc(port, qindex);\n \tuint32_t pkt_len = pkt->pkt_len;\n \n \tsubport->stats.n_pkts_tc_dropped[tc_index] += 1;\n \tsubport->stats.n_bytes_tc_dropped[tc_index] += pkt_len;\n-#ifdef RTE_SCHED_RED\n-\tsubport->stats.n_pkts_red_dropped[tc_index] += red;\n-#endif\n+\tsubport->stats.n_pkts_cman_dropped[tc_index] += n_pkts_cman_dropped;\n }\n \n static inline void\n@@ -1756,73 +1828,100 @@ rte_sched_port_update_queue_stats(struct rte_sched_subport *subport,\n \tqe->stats.n_bytes += pkt_len;\n }\n \n-#ifdef RTE_SCHED_RED\n-static inline void\n-rte_sched_port_update_queue_stats_on_drop(struct rte_sched_subport *subport,\n-\tuint32_t qindex,\n-\tstruct rte_mbuf *pkt,\n-\tuint32_t red)\n-#else\n static inline void\n rte_sched_port_update_queue_stats_on_drop(struct rte_sched_subport *subport,\n \tuint32_t qindex,\n \tstruct rte_mbuf *pkt,\n-\t__rte_unused uint32_t red)\n-#endif\n+\t__rte_unused uint32_t n_pkts_cman_dropped)\n {\n \tstruct rte_sched_queue_extra *qe = subport->queue_extra + qindex;\n \tuint32_t pkt_len = pkt->pkt_len;\n \n \tqe->stats.n_pkts_dropped += 1;\n \tqe->stats.n_bytes_dropped += pkt_len;\n-#ifdef RTE_SCHED_RED\n-\tqe->stats.n_pkts_red_dropped += red;\n+#ifdef RTE_SCHED_CMAN\n+\tif (subport->cman_enabled) {\n+\t\tqe->stats.n_pkts_cman_dropped += n_pkts_cman_dropped;\n+\t}\n #endif\n }\n \n #endif /* RTE_SCHED_COLLECT_STATS */\n \n-#ifdef RTE_SCHED_RED\n+#ifdef RTE_SCHED_CMAN\n \n static inline int\n-rte_sched_port_red_drop(struct rte_sched_port *port,\n+rte_sched_port_cman_drop(struct rte_sched_port *port,\n \tstruct rte_sched_subport *subport,\n \tstruct rte_mbuf *pkt,\n \tuint32_t qindex,\n \tuint16_t qlen)\n {\n+\tif (!subport->cman_enabled)\n+\t\treturn 0;\n+\n \tstruct rte_sched_queue_extra *qe;\n-\tstruct rte_red_config *red_cfg;\n-\tstruct rte_red *red;\n \tuint32_t tc_index;\n-\tenum rte_color color;\n \n \ttc_index = rte_sched_port_pipe_tc(port, qindex);\n-\tcolor = rte_sched_port_pkt_read_color(pkt);\n-\tred_cfg = &subport->red_config[tc_index][color];\n+\tqe = subport->queue_extra + qindex;\n \n-\tif ((red_cfg->min_th | red_cfg->max_th) == 0)\n-\t\treturn 0;\n+\t/* RED */\n+\tif (subport->cman == RTE_SCHED_CMAN_RED) {\n+\t\tstruct rte_red_config *red_cfg;\n+\t\tstruct rte_red *red;\n+\t\tenum rte_color color;\n \n-\tqe = subport->queue_extra + qindex;\n-\tred = &qe->red;\n+\t\tcolor = rte_sched_port_pkt_read_color(pkt);\n+\t\tred_cfg = &subport->red_config[tc_index][color];\n \n-\treturn rte_red_enqueue(red_cfg, red, qlen, port->time);\n+\t\tif ((red_cfg->min_th | red_cfg->max_th) == 0)\n+\t\t\treturn 0;\n+\n+\t\tred = &qe->red;\n+\n+\t\treturn rte_red_enqueue(red_cfg, red, qlen, port->time);\n+\t}\n+\n+\t/* PIE */\n+\tstruct rte_pie_config *pie_cfg = &subport->pie_config[tc_index];\n+\tstruct rte_pie *pie = &qe->pie;\n+\n+\treturn rte_pie_enqueue(pie_cfg, pie, qlen, pkt->pkt_len, port->time_cpu_cycles);\n }\n \n static inline void\n-rte_sched_port_set_queue_empty_timestamp(struct rte_sched_port *port,\n+rte_sched_port_red_set_queue_empty_timestamp(struct rte_sched_port *port,\n \tstruct rte_sched_subport *subport, uint32_t qindex)\n {\n-\tstruct rte_sched_queue_extra *qe = subport->queue_extra + qindex;\n-\tstruct rte_red *red = &qe->red;\n+\tif (subport->cman_enabled) {\n+\t\tstruct rte_sched_queue_extra *qe = subport->queue_extra + qindex;\n+\t\tif (subport->cman == RTE_SCHED_CMAN_RED) {\n+\t\t\tstruct rte_red *red = &qe->red;\n+\n+\t\t\trte_red_mark_queue_empty(red, port->time);\n+\t\t}\n+\t}\n+}\n \n-\trte_red_mark_queue_empty(red, port->time);\n+static inline void\n+rte_sched_port_pie_dequeue(struct rte_sched_subport *subport,\n+uint32_t qindex, uint32_t pkt_len, uint64_t time) {\n+\tif (subport->cman_enabled && subport->cman == RTE_SCHED_CMAN_PIE) {\n+\t\tstruct rte_sched_queue_extra *qe = subport->queue_extra + qindex;\n+\t\tstruct rte_pie *pie = &qe->pie;\n+\n+\t\t/* Update queue length */\n+\t\tpie->qlen -= 1;\n+\t\tpie->qlen_bytes -= pkt_len;\n+\n+\t\trte_pie_dequeue(pie, pkt_len, time);\n+\t}\n }\n \n #else\n \n-static inline int rte_sched_port_red_drop(struct rte_sched_port *port __rte_unused,\n+static inline int rte_sched_port_cman_drop(struct rte_sched_port *port __rte_unused,\n \tstruct rte_sched_subport *subport __rte_unused,\n \tstruct rte_mbuf *pkt __rte_unused,\n \tuint32_t qindex __rte_unused,\n@@ -1831,9 +1930,17 @@ static inline int rte_sched_port_red_drop(struct rte_sched_port *port __rte_unus\n \treturn 0;\n }\n \n-#define rte_sched_port_set_queue_empty_timestamp(port, subport, qindex)\n+#define rte_sched_port_red_set_queue_empty_timestamp(port, subport, qindex)\n \n-#endif /* RTE_SCHED_RED */\n+static inline void\n+rte_sched_port_pie_dequeue(struct rte_sched_subport *subport __rte_unused,\n+\tuint32_t qindex __rte_unused,\n+\tuint32_t pkt_len __rte_unused,\n+\tuint64_t time __rte_unused) {\n+\t/* do-nothing when RTE_SCHED_CMAN not defined */\n+}\n+\n+#endif /* RTE_SCHED_CMAN */\n \n #ifdef RTE_SCHED_DEBUG\n \n@@ -1929,7 +2036,7 @@ rte_sched_port_enqueue_qwa(struct rte_sched_port *port,\n \tqlen = q->qw - q->qr;\n \n \t/* Drop the packet (and update drop stats) when queue is full */\n-\tif (unlikely(rte_sched_port_red_drop(port, subport, pkt, qindex, qlen) ||\n+\tif (unlikely(rte_sched_port_cman_drop(port, subport, pkt, qindex, qlen) ||\n \t\t     (qlen >= qsize))) {\n \t\trte_pktmbuf_free(pkt);\n #ifdef RTE_SCHED_COLLECT_STATS\n@@ -2402,6 +2509,7 @@ grinder_schedule(struct rte_sched_port *port,\n {\n \tstruct rte_sched_grinder *grinder = subport->grinder + pos;\n \tstruct rte_sched_queue *queue = grinder->queue[grinder->qpos];\n+\tuint32_t qindex = grinder->qindex[grinder->qpos];\n \tstruct rte_mbuf *pkt = grinder->pkt;\n \tuint32_t pkt_len = pkt->pkt_len + port->frame_overhead;\n \tuint32_t be_tc_active;\n@@ -2421,15 +2529,16 @@ grinder_schedule(struct rte_sched_port *port,\n \t\t(pkt_len * grinder->wrr_cost[grinder->qpos]) & be_tc_active;\n \n \tif (queue->qr == queue->qw) {\n-\t\tuint32_t qindex = grinder->qindex[grinder->qpos];\n-\n \t\trte_bitmap_clear(subport->bmp, qindex);\n \t\tgrinder->qmask &= ~(1 << grinder->qpos);\n \t\tif (be_tc_active)\n \t\t\tgrinder->wrr_mask[grinder->qpos] = 0;\n-\t\trte_sched_port_set_queue_empty_timestamp(port, subport, qindex);\n+\n+\t\trte_sched_port_red_set_queue_empty_timestamp(port, subport, qindex);\n \t}\n \n+\trte_sched_port_pie_dequeue(subport, qindex, pkt_len, port->time_cpu_cycles);\n+\n \t/* Reset pipe loop detection */\n \tsubport->pipe_loop = RTE_SCHED_PIPE_INVALID;\n \tgrinder->productive = 1;\ndiff --git a/lib/sched/rte_sched.h b/lib/sched/rte_sched.h\nindex cb851301e9..9727701fe3 100644\n--- a/lib/sched/rte_sched.h\n+++ b/lib/sched/rte_sched.h\n@@ -61,10 +61,9 @@ extern \"C\" {\n #include <rte_mbuf.h>\n #include <rte_meter.h>\n \n-/** Random Early Detection (RED) */\n-#ifdef RTE_SCHED_RED\n+/** Congestion Management */\n #include \"rte_red.h\"\n-#endif\n+#include \"rte_pie.h\"\n \n /** Maximum number of queues per pipe.\n  * Note that the multiple queues (power of 2) can only be assigned to\n@@ -110,6 +109,28 @@ extern \"C\" {\n #define RTE_SCHED_FRAME_OVERHEAD_DEFAULT      24\n #endif\n \n+/**\n+ * Congestion Management (CMAN) mode\n+ *\n+ * This is used for controlling the admission of packets into a packet queue or\n+ * group of packet queues on congestion.\n+ *\n+ * The *Random Early Detection (RED)* algorithm works by proactively dropping\n+ * more and more input packets as the queue occupancy builds up. When the queue\n+ * is full or almost full, RED effectively works as *tail drop*. The *Weighted\n+ * RED* algorithm uses a separate set of RED thresholds for each packet color.\n+ *\n+ * Similar to RED, Proportional Integral Controller Enhanced (PIE) randomly\n+ * drops a packet at the onset of the congestion and tries to control the\n+ * latency around the target value. The congestion detection, however, is based\n+ * on the queueing latency instead of the queue length like RED. For more\n+ * information, refer RFC8033.\n+ */\n+enum rte_sched_cman_mode {\n+\tRTE_SCHED_CMAN_RED, /**< Random Early Detection (RED) */\n+\tRTE_SCHED_CMAN_PIE,  /**< Proportional Integral Controller Enhanced (PIE) */\n+};\n+\n /*\n  * Pipe configuration parameters. The period and credits_per_period\n  * parameters are measured in bytes, with one byte meaning the time\n@@ -139,6 +160,22 @@ struct rte_sched_pipe_params {\n \tuint8_t wrr_weights[RTE_SCHED_BE_QUEUES_PER_PIPE];\n };\n \n+/*\n+ * Congestion Management configuration parameters.\n+ */\n+struct rte_sched_cman_params {\n+\t/** Congestion Management mode */\n+\tenum rte_sched_cman_mode cman_mode;\n+\n+\tunion {\n+\t\t/** RED parameters */\n+\t\tstruct rte_red_params red_params[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE][RTE_COLORS];\n+\n+\t\t/** PIE parameters */\n+\t\tstruct rte_pie_params pie_params[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];\n+\t};\n+};\n+\n /*\n  * Subport configuration parameters. The period and credits_per_period\n  * parameters are measured in bytes, with one byte meaning the time\n@@ -174,10 +211,11 @@ struct rte_sched_subport_params {\n \t/** Max allowed profiles in the pipe profile table */\n \tuint32_t n_max_pipe_profiles;\n \n-#ifdef RTE_SCHED_RED\n-\t/** RED parameters */\n-\tstruct rte_red_params red_params[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE][RTE_COLORS];\n-#endif\n+\t/** Congestion Management parameters\n+\t * If NULL the congestion management is disabled for the subport,\n+\t * otherwise proper parameters need to be provided.\n+\t */\n+\tstruct rte_sched_cman_params *cman_params;\n };\n \n struct rte_sched_subport_profile_params {\n@@ -208,10 +246,8 @@ struct rte_sched_subport_stats {\n \t/** Number of bytes dropped for each traffic class */\n \tuint64_t n_bytes_tc_dropped[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];\n \n-#ifdef RTE_SCHED_RED\n-\t/** Number of packets dropped by red */\n-\tuint64_t n_pkts_red_dropped[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];\n-#endif\n+\t/** Number of packets dropped by congestion management scheme */\n+\tuint64_t n_pkts_cman_dropped[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];\n };\n \n /** Queue statistics */\n@@ -222,10 +258,8 @@ struct rte_sched_queue_stats {\n \t/** Packets dropped */\n \tuint64_t n_pkts_dropped;\n \n-#ifdef RTE_SCHED_RED\n-\t/** Packets dropped by RED */\n-\tuint64_t n_pkts_red_dropped;\n-#endif\n+\t/** Packets dropped by congestion management scheme */\n+\tuint64_t n_pkts_cman_dropped;\n \n \t/** Bytes successfully written */\n \tuint64_t n_bytes;\ndiff --git a/lib/sched/version.map b/lib/sched/version.map\nindex a6e505c8ac..d22c07fc9f 100644\n--- a/lib/sched/version.map\n+++ b/lib/sched/version.map\n@@ -30,4 +30,8 @@ EXPERIMENTAL {\n \n \t# added in 20.11\n \trte_sched_port_subport_profile_add;\n+\n+\t# added in 21.11\n+\trte_pie_rt_data_init;\n+\trte_pie_config_init;\n };\n",
    "prefixes": [
        "v22",
        "1/3"
    ]
}